summaryrefslogtreecommitdiffstats
path: root/src/network
diff options
context:
space:
mode:
Diffstat (limited to 'src/network')
-rw-r--r--src/network/.prev_CMakeLists.txt425
-rw-r--r--src/network/CMakeLists.txt244
-rw-r--r--src/network/access/access.pri128
-rw-r--r--src/network/access/http2/bitstreams.cpp42
-rw-r--r--src/network/access/http2/bitstreams_p.h44
-rw-r--r--src/network/access/http2/hpack.cpp89
-rw-r--r--src/network/access/http2/hpack_p.h43
-rw-r--r--src/network/access/http2/hpacktable.cpp51
-rw-r--r--src/network/access/http2/hpacktable_p.h44
-rw-r--r--src/network/access/http2/http2.pri17
-rw-r--r--src/network/access/http2/http2frames.cpp58
-rw-r--r--src/network/access/http2/http2frames_p.h59
-rw-r--r--src/network/access/http2/http2protocol.cpp141
-rw-r--r--src/network/access/http2/http2protocol_p.h53
-rw-r--r--src/network/access/http2/http2streams.cpp40
-rw-r--r--src/network/access/http2/http2streams_p.h40
-rw-r--r--src/network/access/http2/huffman.cpp47
-rw-r--r--src/network/access/http2/huffman_p.h46
-rw-r--r--src/network/access/qabstractnetworkcache.cpp63
-rw-r--r--src/network/access/qabstractnetworkcache.h42
-rw-r--r--src/network/access/qabstractnetworkcache_p.h40
-rw-r--r--src/network/access/qabstractprotocolhandler.cpp40
-rw-r--r--src/network/access/qabstractprotocolhandler_p.h40
-rw-r--r--src/network/access/qdecompresshelper.cpp304
-rw-r--r--src/network/access/qdecompresshelper_p.h58
-rw-r--r--src/network/access/qhsts.cpp104
-rw-r--r--src/network/access/qhsts_p.h46
-rw-r--r--src/network/access/qhstspolicy.cpp65
-rw-r--r--src/network/access/qhstspolicy.h55
-rw-r--r--src/network/access/qhstsstore.cpp50
-rw-r--r--src/network/access/qhstsstore_p.h40
-rw-r--r--src/network/access/qhttp1configuration.cpp154
-rw-r--r--src/network/access/qhttp1configuration.h62
-rw-r--r--src/network/access/qhttp2configuration.cpp70
-rw-r--r--src/network/access/qhttp2configuration.h60
-rw-r--r--src/network/access/qhttp2connection.cpp1752
-rw-r--r--src/network/access/qhttp2connection_p.h372
-rw-r--r--src/network/access/qhttp2protocolhandler.cpp486
-rw-r--r--src/network/access/qhttp2protocolhandler_p.h45
-rw-r--r--src/network/access/qhttpheaderparser.cpp221
-rw-r--r--src/network/access/qhttpheaderparser_p.h101
-rw-r--r--src/network/access/qhttpheaders.cpp1551
-rw-r--r--src/network/access/qhttpheaders.h281
-rw-r--r--src/network/access/qhttpmultipart.cpp85
-rw-r--r--src/network/access/qhttpmultipart.h42
-rw-r--r--src/network/access/qhttpmultipart_p.h40
-rw-r--r--src/network/access/qhttpnetworkconnection.cpp468
-rw-r--r--src/network/access/qhttpnetworkconnection_p.h86
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel.cpp178
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel_p.h47
-rw-r--r--src/network/access/qhttpnetworkheader.cpp87
-rw-r--r--src/network/access/qhttpnetworkheader_p.h55
-rw-r--r--src/network/access/qhttpnetworkreply.cpp300
-rw-r--r--src/network/access/qhttpnetworkreply_p.h86
-rw-r--r--src/network/access/qhttpnetworkrequest.cpp88
-rw-r--r--src/network/access/qhttpnetworkrequest_p.h54
-rw-r--r--src/network/access/qhttpprotocolhandler.cpp67
-rw-r--r--src/network/access/qhttpprotocolhandler_p.h42
-rw-r--r--src/network/access/qhttpthreaddelegate.cpp110
-rw-r--r--src/network/access/qhttpthreaddelegate_p.h79
-rw-r--r--src/network/access/qnetworkaccessauthenticationmanager.cpp67
-rw-r--r--src/network/access/qnetworkaccessauthenticationmanager_p.h42
-rw-r--r--src/network/access/qnetworkaccessbackend.cpp167
-rw-r--r--src/network/access/qnetworkaccessbackend_p.h41
-rw-r--r--src/network/access/qnetworkaccesscache.cpp242
-rw-r--r--src/network/access/qnetworkaccesscache_p.h51
-rw-r--r--src/network/access/qnetworkaccesscachebackend.cpp51
-rw-r--r--src/network/access/qnetworkaccesscachebackend_p.h40
-rw-r--r--src/network/access/qnetworkaccessdebugpipebackend.cpp50
-rw-r--r--src/network/access/qnetworkaccessdebugpipebackend_p.h40
-rw-r--r--src/network/access/qnetworkaccessfilebackend.cpp62
-rw-r--r--src/network/access/qnetworkaccessfilebackend_p.h40
-rw-r--r--src/network/access/qnetworkaccessmanager.cpp344
-rw-r--r--src/network/access/qnetworkaccessmanager.h64
-rw-r--r--src/network/access/qnetworkaccessmanager_p.h46
-rw-r--r--src/network/access/qnetworkcookie.cpp241
-rw-r--r--src/network/access/qnetworkcookie.h57
-rw-r--r--src/network/access/qnetworkcookie_p.h56
-rw-r--r--src/network/access/qnetworkcookiejar.cpp123
-rw-r--r--src/network/access/qnetworkcookiejar.h40
-rw-r--r--src/network/access/qnetworkcookiejar_p.h40
-rw-r--r--src/network/access/qnetworkdiskcache.cpp210
-rw-r--r--src/network/access/qnetworkdiskcache.h40
-rw-r--r--src/network/access/qnetworkdiskcache_p.h57
-rw-r--r--src/network/access/qnetworkfile.cpp42
-rw-r--r--src/network/access/qnetworkfile_p.h40
-rw-r--r--src/network/access/qnetworkreply.cpp81
-rw-r--r--src/network/access/qnetworkreply.h51
-rw-r--r--src/network/access/qnetworkreply_p.h40
-rw-r--r--src/network/access/qnetworkreplydataimpl.cpp40
-rw-r--r--src/network/access/qnetworkreplydataimpl_p.h40
-rw-r--r--src/network/access/qnetworkreplyfileimpl.cpp61
-rw-r--r--src/network/access/qnetworkreplyfileimpl_p.h54
-rw-r--r--src/network/access/qnetworkreplyhttpimpl.cpp527
-rw-r--r--src/network/access/qnetworkreplyhttpimpl_p.h65
-rw-r--r--src/network/access/qnetworkreplyimpl.cpp70
-rw-r--r--src/network/access/qnetworkreplyimpl_p.h46
-rw-r--r--src/network/access/qnetworkreplywasmimpl.cpp284
-rw-r--r--src/network/access/qnetworkreplywasmimpl_p.h55
-rw-r--r--src/network/access/qnetworkrequest.cpp475
-rw-r--r--src/network/access/qnetworkrequest.h101
-rw-r--r--src/network/access/qnetworkrequest_p.h44
-rw-r--r--src/network/access/qnetworkrequestfactory.cpp727
-rw-r--r--src/network/access/qnetworkrequestfactory.h100
-rw-r--r--src/network/access/qnetworkrequestfactory_p.h56
-rw-r--r--src/network/access/qrestaccessmanager.cpp828
-rw-r--r--src/network/access/qrestaccessmanager.h127
-rw-r--r--src/network/access/qrestaccessmanager_p.h89
-rw-r--r--src/network/access/qrestreply.cpp560
-rw-r--r--src/network/access/qrestreply.h71
-rw-r--r--src/network/access/qrestreply_p.h40
-rw-r--r--src/network/access/qsocketabstraction_p.h91
-rw-r--r--src/network/android/jar/.gitignore6
-rw-r--r--src/network/android/jar/CMakeLists.txt14
-rw-r--r--src/network/android/jar/build.gradle51
-rw-r--r--src/network/android/jar/jar.pro15
-rw-r--r--src/network/android/jar/settings.gradle1
-rw-r--r--src/network/android/jar/src/org/qtproject/qt/android/network/QtNetwork.java64
-rw-r--r--src/network/android/jar/src/org/qtproject/qt5/android/network/QtNetwork.java101
-rw-r--r--src/network/compat/removed_api.cpp67
-rw-r--r--src/network/configure.cmake223
-rw-r--r--src/network/configure.json500
-rw-r--r--src/network/configure.pri13
-rw-r--r--src/network/doc/images/network-examples.pngbin8946 -> 0 bytes
-rw-r--r--src/network/doc/images/network-examples.webpbin0 -> 8250 bytes
-rw-r--r--src/network/doc/qtnetwork.qdocconf18
-rw-r--r--src/network/doc/snippets/CMakeLists.txt9
-rw-r--r--src/network/doc/snippets/code/doc_src_qtnetwork.cpp53
-rw-r--r--src/network/doc/snippets/code/src_network_access_qhttpmultipart.cpp40
-rw-r--r--src/network/doc/snippets/code/src_network_access_qhttppart.cpp40
-rw-r--r--src/network/doc/snippets/code/src_network_access_qnetworkaccessmanager.cpp51
-rw-r--r--src/network/doc/snippets/code/src_network_access_qnetworkdiskcache.cpp60
-rw-r--r--src/network/doc/snippets/code/src_network_access_qnetworkreply.cpp55
-rw-r--r--src/network/doc/snippets/code/src_network_access_qnetworkrequest.cpp51
-rw-r--r--src/network/doc/snippets/code/src_network_access_qnetworkrequestfactory.cpp27
-rw-r--r--src/network/doc/snippets/code/src_network_access_qrestaccessmanager.cpp104
-rw-r--r--src/network/doc/snippets/code/src_network_kernel_qdnslookup.cpp54
-rw-r--r--src/network/doc/snippets/code/src_network_kernel_qhostaddress.cpp51
-rw-r--r--src/network/doc/snippets/code/src_network_kernel_qhostinfo.cpp63
-rw-r--r--src/network/doc/snippets/code/src_network_kernel_qnetworkdatagram.cpp51
-rw-r--r--src/network/doc/snippets/code/src_network_kernel_qnetworkinterface.cpp40
-rw-r--r--src/network/doc/snippets/code/src_network_kernel_qnetworkproxy.cpp51
-rw-r--r--src/network/doc/snippets/code/src_network_socket_qabstractsocket.cpp51
-rw-r--r--src/network/doc/snippets/code/src_network_socket_qlocalsocket_unix.cpp51
-rw-r--r--src/network/doc/snippets/code/src_network_socket_qnativesocketengine.cpp51
-rw-r--r--src/network/doc/snippets/code/src_network_socket_qsctpsocket.cpp51
-rw-r--r--src/network/doc/snippets/code/src_network_socket_qtcpserver.cpp51
-rw-r--r--src/network/doc/snippets/code/src_network_socket_qudpsocket.cpp51
-rw-r--r--src/network/doc/snippets/code/src_network_ssl_qdtls.cpp54
-rw-r--r--src/network/doc/snippets/code/src_network_ssl_qdtlscookie.cpp51
-rw-r--r--src/network/doc/snippets/code/src_network_ssl_qsslcertificate.cpp51
-rw-r--r--src/network/doc/snippets/code/src_network_ssl_qsslconfiguration.cpp60
-rw-r--r--src/network/doc/snippets/code/src_network_ssl_qsslpresharedkeyauthenticator.cpp40
-rw-r--r--src/network/doc/snippets/code/src_network_ssl_qsslsocket.cpp65
-rw-r--r--src/network/doc/snippets/network/CMakeLists.txt8
-rw-r--r--src/network/doc/snippets/network/network.pro9
-rw-r--r--src/network/doc/snippets/network/tcpwait.cpp59
-rw-r--r--src/network/doc/snippets/snippets.pro9
-rw-r--r--src/network/doc/src/dontdocument.qdoc28
-rw-r--r--src/network/doc/src/examples.qdoc36
-rw-r--r--src/network/doc/src/external-resources.qdoc28
-rw-r--r--src/network/doc/src/network-programming.qdoc28
-rw-r--r--src/network/doc/src/qt6-changes.qdoc197
-rw-r--r--src/network/doc/src/qtnetwork.qdoc68
-rw-r--r--src/network/doc/src/ssl.qdoc91
-rw-r--r--src/network/kernel/kernel.pri95
-rw-r--r--src/network/kernel/qauthenticator.cpp334
-rw-r--r--src/network/kernel/qauthenticator.h41
-rw-r--r--src/network/kernel/qauthenticator_p.h56
-rw-r--r--src/network/kernel/qdnslookup.cpp314
-rw-r--r--src/network/kernel/qdnslookup.h75
-rw-r--r--src/network/kernel/qdnslookup_android.cpp56
-rw-r--r--src/network/kernel/qdnslookup_dummy.cpp15
-rw-r--r--src/network/kernel/qdnslookup_p.h211
-rw-r--r--src/network/kernel/qdnslookup_unix.cpp585
-rw-r--r--src/network/kernel/qdnslookup_win.cpp190
-rw-r--r--src/network/kernel/qhostaddress.cpp214
-rw-r--r--src/network/kernel/qhostaddress.h77
-rw-r--r--src/network/kernel/qhostaddress_p.h40
-rw-r--r--src/network/kernel/qhostinfo.cpp224
-rw-r--r--src/network/kernel/qhostinfo.h111
-rw-r--r--src/network/kernel/qhostinfo_p.h75
-rw-r--r--src/network/kernel/qhostinfo_unix.cpp284
-rw-r--r--src/network/kernel/qhostinfo_win.cpp40
-rw-r--r--src/network/kernel/qnetconmonitor_darwin.mm186
-rw-r--r--src/network/kernel/qnetconmonitor_p.h85
-rw-r--r--src/network/kernel/qnetconmonitor_stub.cpp86
-rw-r--r--src/network/kernel/qnetconmonitor_win.cpp394
-rw-r--r--src/network/kernel/qnetworkdatagram.cpp44
-rw-r--r--src/network/kernel/qnetworkdatagram.h46
-rw-r--r--src/network/kernel/qnetworkdatagram_p.h40
-rw-r--r--src/network/kernel/qnetworkinformation.cpp774
-rw-r--r--src/network/kernel/qnetworkinformation.h97
-rw-r--r--src/network/kernel/qnetworkinformation_p.h156
-rw-r--r--src/network/kernel/qnetworkinterface.cpp87
-rw-r--r--src/network/kernel/qnetworkinterface.h54
-rw-r--r--src/network/kernel/qnetworkinterface_linux.cpp59
-rw-r--r--src/network/kernel/qnetworkinterface_p.h56
-rw-r--r--src/network/kernel/qnetworkinterface_uikit_p.h61
-rw-r--r--src/network/kernel/qnetworkinterface_unix.cpp109
-rw-r--r--src/network/kernel/qnetworkinterface_unix_p.h42
-rw-r--r--src/network/kernel/qnetworkinterface_win.cpp42
-rw-r--r--src/network/kernel/qnetworkproxy.cpp66
-rw-r--r--src/network/kernel/qnetworkproxy.h47
-rw-r--r--src/network/kernel/qnetworkproxy_android.cpp85
-rw-r--r--src/network/kernel/qnetworkproxy_darwin.cpp (renamed from src/network/kernel/qnetworkproxy_mac.cpp)179
-rw-r--r--src/network/kernel/qnetworkproxy_generic.cpp56
-rw-r--r--src/network/kernel/qnetworkproxy_libproxy.cpp56
-rw-r--r--src/network/kernel/qnetworkproxy_win.cpp224
-rw-r--r--src/network/kernel/qtldurl.cpp281
-rw-r--r--src/network/kernel/qtldurl_p.h43
-rw-r--r--src/network/kernel/qtnetworkglobal.h55
-rw-r--r--src/network/kernel/qtnetworkglobal_p.h51
-rw-r--r--src/network/kernel/qurltlds_p.h14540
-rw-r--r--src/network/kernel/qurltlds_p.h.INFO14
-rw-r--r--src/network/network.pro27
-rw-r--r--src/network/qt_cmdline.cmake8
-rw-r--r--src/network/socket/qabstractsocket.cpp265
-rw-r--r--src/network/socket/qabstractsocket.h70
-rw-r--r--src/network/socket/qabstractsocket_p.h86
-rw-r--r--src/network/socket/qabstractsocketengine.cpp42
-rw-r--r--src/network/socket/qabstractsocketengine_p.h60
-rw-r--r--src/network/socket/qhttpsocketengine.cpp166
-rw-r--r--src/network/socket/qhttpsocketengine_p.h61
-rw-r--r--src/network/socket/qlocalserver.cpp125
-rw-r--r--src/network/socket/qlocalserver.h55
-rw-r--r--src/network/socket/qlocalserver_p.h45
-rw-r--r--src/network/socket/qlocalserver_tcp.cpp56
-rw-r--r--src/network/socket/qlocalserver_unix.cpp178
-rw-r--r--src/network/socket/qlocalserver_win.cpp79
-rw-r--r--src/network/socket/qlocalsocket.cpp111
-rw-r--r--src/network/socket/qlocalsocket.h62
-rw-r--r--src/network/socket/qlocalsocket_p.h65
-rw-r--r--src/network/socket/qlocalsocket_tcp.cpp69
-rw-r--r--src/network/socket/qlocalsocket_unix.cpp216
-rw-r--r--src/network/socket/qlocalsocket_win.cpp393
-rw-r--r--src/network/socket/qnativesocketengine.cpp110
-rw-r--r--src/network/socket/qnativesocketengine_p.h266
-rw-r--r--src/network/socket/qnativesocketengine_p_p.h189
-rw-r--r--src/network/socket/qnativesocketengine_unix.cpp179
-rw-r--r--src/network/socket/qnativesocketengine_win.cpp178
-rw-r--r--src/network/socket/qnet_unix_p.h51
-rw-r--r--src/network/socket/qsctpserver.cpp42
-rw-r--r--src/network/socket/qsctpserver.h42
-rw-r--r--src/network/socket/qsctpserver_p.h40
-rw-r--r--src/network/socket/qsctpsocket.cpp49
-rw-r--r--src/network/socket/qsctpsocket.h42
-rw-r--r--src/network/socket/qsctpsocket_p.h40
-rw-r--r--src/network/socket/qsocks5socketengine.cpp211
-rw-r--r--src/network/socket/qsocks5socketengine_p.h65
-rw-r--r--src/network/socket/qtcpserver.cpp125
-rw-r--r--src/network/socket/qtcpserver.h44
-rw-r--r--src/network/socket/qtcpserver_p.h44
-rw-r--r--src/network/socket/qtcpsocket.cpp48
-rw-r--r--src/network/socket/qtcpsocket.h48
-rw-r--r--src/network/socket/qtcpsocket_p.h40
-rw-r--r--src/network/socket/qudpsocket.cpp48
-rw-r--r--src/network/socket/qudpsocket.h47
-rw-r--r--src/network/socket/socket.pri84
-rw-r--r--src/network/ssl/qasn1element.cpp391
-rw-r--r--src/network/ssl/qasn1element_p.h188
-rw-r--r--src/network/ssl/qdtls.cpp470
-rw-r--r--src/network/ssl/qdtls.h42
-rw-r--r--src/network/ssl/qdtls_openssl.cpp1401
-rw-r--r--src/network/ssl/qdtls_openssl_p.h212
-rw-r--r--src/network/ssl/qdtls_p.h132
-rw-r--r--src/network/ssl/qocsp_p.h40
-rw-r--r--src/network/ssl/qocspresponse.cpp75
-rw-r--r--src/network/ssl/qocspresponse.h60
-rw-r--r--src/network/ssl/qocspresponse_p.h41
-rw-r--r--src/network/ssl/qpassworddigestor.cpp144
-rw-r--r--src/network/ssl/qpassworddigestor.h44
-rw-r--r--src/network/ssl/qssl.cpp92
-rw-r--r--src/network/ssl/qssl.h92
-rw-r--r--src/network/ssl/qssl_p.h53
-rw-r--r--src/network/ssl/qsslcertificate.cpp454
-rw-r--r--src/network/ssl/qsslcertificate.h62
-rw-r--r--src/network/ssl/qsslcertificate_openssl.cpp766
-rw-r--r--src/network/ssl/qsslcertificate_p.h140
-rw-r--r--src/network/ssl/qsslcertificate_qt.cpp557
-rw-r--r--src/network/ssl/qsslcertificate_schannel.cpp62
-rw-r--r--src/network/ssl/qsslcertificateextension.cpp40
-rw-r--r--src/network/ssl/qsslcertificateextension.h42
-rw-r--r--src/network/ssl/qsslcertificateextension_p.h40
-rw-r--r--src/network/ssl/qsslcipher.cpp47
-rw-r--r--src/network/ssl/qsslcipher.h49
-rw-r--r--src/network/ssl/qsslcipher_p.h40
-rw-r--r--src/network/ssl/qsslconfiguration.cpp94
-rw-r--r--src/network/ssl/qsslconfiguration.h57
-rw-r--r--src/network/ssl/qsslconfiguration_p.h44
-rw-r--r--src/network/ssl/qsslcontext_openssl.cpp767
-rw-r--r--src/network/ssl/qsslcontext_openssl_p.h129
-rw-r--r--src/network/ssl/qssldiffiehellmanparameters.cpp99
-rw-r--r--src/network/ssl/qssldiffiehellmanparameters.h81
-rw-r--r--src/network/ssl/qssldiffiehellmanparameters_dummy.cpp57
-rw-r--r--src/network/ssl/qssldiffiehellmanparameters_openssl.cpp224
-rw-r--r--src/network/ssl/qssldiffiehellmanparameters_p.h53
-rw-r--r--src/network/ssl/qsslellipticcurve.cpp110
-rw-r--r--src/network/ssl/qsslellipticcurve.h57
-rw-r--r--src/network/ssl/qsslellipticcurve_dummy.cpp71
-rw-r--r--src/network/ssl/qsslellipticcurve_openssl.cpp177
-rw-r--r--src/network/ssl/qsslerror.cpp56
-rw-r--r--src/network/ssl/qsslerror.h49
-rw-r--r--src/network/ssl/qsslkey.h48
-rw-r--r--src/network/ssl/qsslkey_mac.cpp99
-rw-r--r--src/network/ssl/qsslkey_openssl.cpp383
-rw-r--r--src/network/ssl/qsslkey_p.cpp348
-rw-r--r--src/network/ssl/qsslkey_p.h119
-rw-r--r--src/network/ssl/qsslkey_qt.cpp785
-rw-r--r--src/network/ssl/qsslkey_schannel.cpp178
-rw-r--r--src/network/ssl/qsslpresharedkeyauthenticator.cpp78
-rw-r--r--src/network/ssl/qsslpresharedkeyauthenticator.h63
-rw-r--r--src/network/ssl/qsslpresharedkeyauthenticator_p.h40
-rw-r--r--src/network/ssl/qsslserver.cpp412
-rw-r--r--src/network/ssl/qsslserver.h61
-rw-r--r--src/network/ssl/qsslserver_p.h71
-rw-r--r--src/network/ssl/qsslsocket.cpp709
-rw-r--r--src/network/ssl/qsslsocket.h57
-rw-r--r--src/network/ssl/qsslsocket_mac.cpp1554
-rw-r--r--src/network/ssl/qsslsocket_mac_p.h138
-rw-r--r--src/network/ssl/qsslsocket_mac_shared.cpp155
-rw-r--r--src/network/ssl/qsslsocket_openssl.cpp2508
-rw-r--r--src/network/ssl/qsslsocket_openssl_android.cpp88
-rw-r--r--src/network/ssl/qsslsocket_openssl_p.h197
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols.cpp1231
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols_p.h761
-rw-r--r--src/network/ssl/qsslsocket_p.h187
-rw-r--r--src/network/ssl/qsslsocket_qt.cpp309
-rw-r--r--src/network/ssl/qsslsocket_schannel.cpp2064
-rw-r--r--src/network/ssl/qsslsocket_schannel_p.h145
-rw-r--r--src/network/ssl/qtls_utils_p.h103
-rw-r--r--src/network/ssl/qtlsbackend.cpp2357
-rw-r--r--src/network/ssl/qtlsbackend_p.h402
-rw-r--r--src/network/ssl/qwindowscarootfetcher.cpp289
-rw-r--r--src/network/ssl/qwindowscarootfetcher_p.h95
-rw-r--r--src/network/ssl/ssl.pri122
336 files changed, 21143 insertions, 48041 deletions
diff --git a/src/network/.prev_CMakeLists.txt b/src/network/.prev_CMakeLists.txt
deleted file mode 100644
index a9da13bd31..0000000000
--- a/src/network/.prev_CMakeLists.txt
+++ /dev/null
@@ -1,425 +0,0 @@
-# Generated from network.pro.
-
-#####################################################################
-## Network Module:
-#####################################################################
-
-qt_internal_add_module(Network
- PLUGIN_TYPES networkaccessbackends
- SOURCES
- access/qabstractnetworkcache.cpp access/qabstractnetworkcache.h access/qabstractnetworkcache_p.h
- access/qhsts.cpp access/qhsts_p.h
- access/qhstspolicy.cpp access/qhstspolicy.h
- access/qnetworkaccessauthenticationmanager.cpp access/qnetworkaccessauthenticationmanager_p.h
- access/qnetworkaccessbackend.cpp access/qnetworkaccessbackend_p.h
- access/qnetworkaccesscache.cpp access/qnetworkaccesscache_p.h
- access/qnetworkaccesscachebackend.cpp access/qnetworkaccesscachebackend_p.h
- access/qnetworkaccessdebugpipebackend.cpp access/qnetworkaccessdebugpipebackend_p.h
- access/qnetworkaccessfilebackend.cpp access/qnetworkaccessfilebackend_p.h
- access/qnetworkaccessmanager.cpp access/qnetworkaccessmanager.h access/qnetworkaccessmanager_p.h
- access/qnetworkcookie.cpp access/qnetworkcookie.h access/qnetworkcookie_p.h
- access/qnetworkcookiejar.cpp access/qnetworkcookiejar.h access/qnetworkcookiejar_p.h
- access/qnetworkfile.cpp access/qnetworkfile_p.h
- access/qnetworkreply.cpp access/qnetworkreply.h access/qnetworkreply_p.h
- access/qnetworkreplydataimpl.cpp access/qnetworkreplydataimpl_p.h
- access/qnetworkreplyfileimpl.cpp access/qnetworkreplyfileimpl_p.h
- access/qnetworkreplyimpl.cpp access/qnetworkreplyimpl_p.h
- access/qnetworkrequest.cpp access/qnetworkrequest.h access/qnetworkrequest_p.h
- kernel/qauthenticator.cpp kernel/qauthenticator.h kernel/qauthenticator_p.h
- kernel/qhostaddress.cpp kernel/qhostaddress.h kernel/qhostaddress_p.h
- kernel/qhostinfo.cpp kernel/qhostinfo.h kernel/qhostinfo_p.h
- kernel/qnetconmonitor_p.h
- kernel/qnetworkdatagram.cpp kernel/qnetworkdatagram.h kernel/qnetworkdatagram_p.h
- kernel/qnetworkinterface.cpp kernel/qnetworkinterface.h kernel/qnetworkinterface_p.h
- kernel/qnetworkinterface_unix_p.h
- kernel/qnetworkproxy.cpp kernel/qnetworkproxy.h
- kernel/qtnetworkglobal.h kernel/qtnetworkglobal_p.h
- socket/qabstractsocket.cpp socket/qabstractsocket.h socket/qabstractsocket_p.h
- socket/qabstractsocketengine.cpp socket/qabstractsocketengine_p.h
- socket/qnativesocketengine.cpp socket/qnativesocketengine_p.h
- socket/qtcpserver.cpp socket/qtcpserver.h socket/qtcpserver_p.h
- socket/qtcpsocket.cpp socket/qtcpsocket.h socket/qtcpsocket_p.h
- socket/qudpsocket.cpp socket/qudpsocket.h
- ssl/qasn1element.cpp ssl/qasn1element_p.h
- ssl/qpassworddigestor.cpp ssl/qpassworddigestor.h
- ssl/qssl.cpp ssl/qssl.h ssl/qssl_p.h
- ssl/qsslcertificate.cpp ssl/qsslcertificate.h ssl/qsslcertificate_p.h
- ssl/qsslcertificateextension.cpp ssl/qsslcertificateextension.h ssl/qsslcertificateextension_p.h
- ssl/qtls_utils_p.h
- DEFINES
- QT_NO_FOREACH
- QT_NO_USING_NAMESPACE
- INCLUDE_DIRECTORIES
- kernel
- LIBRARIES
- Qt::CorePrivate
- PUBLIC_LIBRARIES
- Qt::Core
- PRIVATE_MODULE_INTERFACE
- Qt::CorePrivate
- PRECOMPILED_HEADER
- "../corelib/global/qt_pch.h"
-)
-
-#### Keys ignored in scope 1:.:.:network.pro:<TRUE>:
-# QMAKE_LIBS = "$$QMAKE_LIBS_NETWORK"
-
-## Scopes:
-#####################################################################
-
-qt_internal_extend_target(Network CONDITION MSVC AND (TEST_architecture_arch STREQUAL "i386")
- LINK_OPTIONS
- "/BASE:0x64000000"
-)
-
-qt_internal_extend_target(Network CONDITION QT_FEATURE_networkdiskcache
- SOURCES
- access/qnetworkdiskcache.cpp access/qnetworkdiskcache.h access/qnetworkdiskcache_p.h
-)
-
-qt_internal_extend_target(Network CONDITION QT_FEATURE_settings
- SOURCES
- access/qhstsstore.cpp access/qhstsstore_p.h
-)
-
-qt_internal_extend_target(Network CONDITION APPLE
- LIBRARIES
- ${FWCoreFoundation}
- ${FWSecurity}
-)
-
-qt_internal_extend_target(Network CONDITION WASM
- SOURCES
- access/qhttpmultipart.cpp access/qhttpmultipart.h access/qhttpmultipart_p.h
- access/qhttpnetworkheader.cpp access/qhttpnetworkheader_p.h
- access/qnetworkreplywasmimpl.cpp access/qnetworkreplywasmimpl_p.h
-)
-
-qt_internal_extend_target(Network CONDITION QT_FEATURE_http
- SOURCES
- access/http2/bitstreams.cpp access/http2/bitstreams_p.h
- access/http2/hpack.cpp access/http2/hpack_p.h
- access/http2/hpacktable.cpp access/http2/hpacktable_p.h
- access/http2/http2frames.cpp access/http2/http2frames_p.h
- access/http2/http2protocol.cpp access/http2/http2protocol_p.h
- access/http2/http2streams.cpp access/http2/http2streams_p.h
- access/http2/huffman.cpp access/http2/huffman_p.h
- access/qabstractprotocolhandler.cpp access/qabstractprotocolhandler_p.h
- access/qdecompresshelper.cpp access/qdecompresshelper_p.h
- access/qhttp2configuration.cpp access/qhttp2configuration.h
- access/qhttp2protocolhandler.cpp access/qhttp2protocolhandler_p.h
- access/qhttpmultipart.cpp access/qhttpmultipart.h access/qhttpmultipart_p.h
- access/qhttpnetworkconnection.cpp access/qhttpnetworkconnection_p.h
- access/qhttpnetworkconnectionchannel.cpp access/qhttpnetworkconnectionchannel_p.h
- access/qhttpnetworkheader.cpp access/qhttpnetworkheader_p.h
- access/qhttpnetworkreply.cpp access/qhttpnetworkreply_p.h
- access/qhttpnetworkrequest.cpp access/qhttpnetworkrequest_p.h
- access/qhttpprotocolhandler.cpp access/qhttpprotocolhandler_p.h
- access/qhttpthreaddelegate.cpp access/qhttpthreaddelegate_p.h
- access/qnetworkreplyhttpimpl.cpp access/qnetworkreplyhttpimpl_p.h
- socket/qhttpsocketengine.cpp socket/qhttpsocketengine_p.h
-)
-
-qt_internal_extend_target(Network CONDITION QT_FEATURE_brotli AND QT_FEATURE_http
- LIBRARIES
- WrapBrotli::WrapBrotliDec
-)
-
-qt_internal_extend_target(Network CONDITION QT_FEATURE_http AND QT_FEATURE_zstd
- LIBRARIES
- ZSTD::ZSTD
-)
-
-qt_internal_extend_target(Network CONDITION QT_FEATURE_system_zlib
- LIBRARIES
- ZLIB::ZLIB
-)
-
-qt_internal_extend_target(Network CONDITION NOT QT_FEATURE_system_zlib
- INCLUDE_DIRECTORIES
- ../3rdparty/zlib/src
-)
-
-qt_internal_extend_target(Network CONDITION NOT QT_FEATURE_system_zlib AND NOT no_core_dep
- LIBRARIES
- Qt::Core
-)
-
-qt_internal_extend_target(Network CONDITION QT_FEATURE_topleveldomain
- SOURCES
- kernel/qtldurl.cpp kernel/qtldurl_p.h
- kernel/qurltlds_p.h
-)
-
-qt_internal_extend_target(Network CONDITION QT_FEATURE_dnslookup
- SOURCES
- kernel/qdnslookup.cpp kernel/qdnslookup.h kernel/qdnslookup_p.h
-)
-
-qt_internal_extend_target(Network CONDITION UNIX
- SOURCES
- kernel/qhostinfo_unix.cpp
- socket/qnativesocketengine_unix.cpp
- socket/qnet_unix_p.h
-)
-
-qt_internal_extend_target(Network CONDITION QT_FEATURE_dlopen AND UNIX
- LIBRARIES
- ${CMAKE_DL_LIBS}
-)
-
-qt_internal_extend_target(Network CONDITION QT_FEATURE_linux_netlink AND UNIX
- SOURCES
- kernel/qnetworkinterface_linux.cpp
-)
-
-qt_internal_extend_target(Network CONDITION UNIX AND NOT QT_FEATURE_linux_netlink
- SOURCES
- kernel/qnetworkinterface_unix.cpp
-)
-
-qt_internal_extend_target(Network CONDITION ANDROID AND QT_FEATURE_dnslookup
- SOURCES
- kernel/qdnslookup_android.cpp
-)
-
-qt_internal_extend_target(Network CONDITION WIN32
- SOURCES
- kernel/qhostinfo_win.cpp
- kernel/qnetworkinterface_win.cpp
- kernel/qnetworkproxy_win.cpp
- socket/qnativesocketengine_win.cpp
- LIBRARIES
- advapi32
- dnsapi
- iphlpapi
-)
-
-qt_internal_extend_target(Network CONDITION QT_FEATURE_dnslookup AND WIN32
- SOURCES
- kernel/qdnslookup_win.cpp
-)
-
-qt_internal_extend_target(Network CONDITION APPLE AND NOT UIKIT
- LIBRARIES
- ${FWCoreServices}
- ${FWSystemConfiguration}
-)
-
-qt_internal_extend_target(Network CONDITION IOS OR MACOS
- SOURCES
- kernel/qnetconmonitor_darwin.mm
- LIBRARIES
- ${FWSystemConfiguration}
-)
-
-qt_internal_extend_target(Network CONDITION QT_FEATURE_netlistmgr AND NOT IOS AND NOT MACOS
- SOURCES
- kernel/qnetconmonitor_win.cpp
-)
-
-qt_internal_extend_target(Network CONDITION NOT IOS AND NOT MACOS AND NOT QT_FEATURE_netlistmgr
- SOURCES
- kernel/qnetconmonitor_stub.cpp
-)
-
-qt_internal_extend_target(Network CONDITION QT_FEATURE_gssapi
- LIBRARIES
- GSSAPI::GSSAPI
-)
-
-qt_internal_extend_target(Network CONDITION UIKIT
- SOURCES
- kernel/qnetworkinterface_uikit_p.h
-)
-
-qt_internal_extend_target(Network CONDITION MACOS
- SOURCES
- kernel/qnetworkproxy_mac.cpp
-)
-
-qt_internal_extend_target(Network CONDITION QT_FEATURE_libproxy AND UNIX AND NOT MACOS
- SOURCES
- kernel/qnetworkproxy_libproxy.cpp
- LIBRARIES
- ${CMAKE_DL_LIBS}
- PkgConfig::Libproxy
-)
-
-qt_internal_extend_target(Network CONDITION ANDROID AND NOT QT_FEATURE_libproxy
- SOURCES
- kernel/qnetworkproxy_android.cpp
-)
-
-qt_internal_extend_target(Network CONDITION UNIX AND NOT ANDROID AND NOT MACOS AND NOT QT_FEATURE_libproxy
- SOURCES
- kernel/qnetworkproxy_generic.cpp
-)
-
-if(ANDROID AND (ANDROID))
- set_property(TARGET Network APPEND PROPERTY QT_ANDROID_BUNDLED_JAR_DEPENDENCIES
- jar/QtAndroidNetwork.jar
- )
-endif()
-
-qt_internal_extend_target(Network CONDITION QT_FEATURE_socks5
- SOURCES
- socket/qsocks5socketengine.cpp socket/qsocks5socketengine_p.h
-)
-
-qt_internal_extend_target(Network CONDITION QT_FEATURE_sctp
- SOURCES
- socket/qsctpserver.cpp socket/qsctpserver.h socket/qsctpserver_p.h
- socket/qsctpsocket.cpp socket/qsctpsocket.h socket/qsctpsocket_p.h
-)
-
-qt_internal_extend_target(Network CONDITION MSVC
- MOC_OPTIONS
- "-D_WINSOCK_DEPRECATED_NO_WARNINGS"
-)
-
-qt_internal_extend_target(Network CONDITION QT_FEATURE_localserver
- SOURCES
- socket/qlocalserver.cpp socket/qlocalserver.h socket/qlocalserver_p.h
- socket/qlocalsocket.cpp socket/qlocalsocket.h socket/qlocalsocket_p.h
-)
-
-qt_internal_extend_target(Network CONDITION INTEGRITY AND QT_FEATURE_localserver
- SOURCES
- socket/qlocalserver_tcp.cpp
- socket/qlocalsocket_tcp.cpp
- DEFINES
- QT_LOCALSOCKET_TCP
-)
-
-qt_internal_extend_target(Network CONDITION QT_FEATURE_localserver AND UNIX AND NOT INTEGRITY
- SOURCES
- socket/qlocalserver_unix.cpp
- socket/qlocalsocket_unix.cpp
-)
-
-qt_internal_extend_target(Network CONDITION QT_FEATURE_localserver AND WIN32
- SOURCES
- socket/qlocalserver_win.cpp
- socket/qlocalsocket_win.cpp
-)
-
-qt_internal_extend_target(Network CONDITION QT_FEATURE_system_proxies
- DEFINES
- QT_USE_SYSTEM_PROXIES
-)
-
-qt_internal_extend_target(Network CONDITION NOT QT_FEATURE_openssl
- SOURCES
- ssl/qsslcertificate_qt.cpp
-)
-
-qt_internal_extend_target(Network CONDITION QT_FEATURE_ssl
- SOURCES
- ssl/qocspresponse.cpp ssl/qocspresponse.h ssl/qocspresponse_p.h
- ssl/qsslcipher.cpp ssl/qsslcipher.h ssl/qsslcipher_p.h
- ssl/qsslconfiguration.cpp ssl/qsslconfiguration.h ssl/qsslconfiguration_p.h
- ssl/qssldiffiehellmanparameters.cpp ssl/qssldiffiehellmanparameters.h ssl/qssldiffiehellmanparameters_p.h
- ssl/qsslellipticcurve.cpp ssl/qsslellipticcurve.h
- ssl/qsslerror.cpp ssl/qsslerror.h
- ssl/qsslkey.h ssl/qsslkey_p.cpp ssl/qsslkey_p.h
- ssl/qsslpresharedkeyauthenticator.cpp ssl/qsslpresharedkeyauthenticator.h ssl/qsslpresharedkeyauthenticator_p.h
- ssl/qsslsocket.cpp ssl/qsslsocket.h ssl/qsslsocket_p.h
-)
-
-qt_internal_extend_target(Network CONDITION QT_FEATURE_schannel AND QT_FEATURE_ssl
- SOURCES
- ssl/qsslcertificate_schannel.cpp
- ssl/qssldiffiehellmanparameters_dummy.cpp
- ssl/qsslellipticcurve_dummy.cpp
- ssl/qsslkey_qt.cpp
- ssl/qsslkey_schannel.cpp
- ssl/qsslsocket_qt.cpp
- ssl/qsslsocket_schannel.cpp ssl/qsslsocket_schannel_p.h
- LIBRARIES
- Crypt32
- Secur32
- bcrypt
- ncrypt
-)
-
-qt_internal_extend_target(Network CONDITION QT_FEATURE_securetransport AND QT_FEATURE_ssl
- SOURCES
- ssl/qssldiffiehellmanparameters_dummy.cpp
- ssl/qsslellipticcurve_dummy.cpp
- ssl/qsslkey_mac.cpp
- ssl/qsslkey_qt.cpp
- ssl/qsslsocket_mac.cpp ssl/qsslsocket_mac_p.h
- ssl/qsslsocket_mac_shared.cpp
- ssl/qsslsocket_qt.cpp
-)
-
-qt_internal_extend_target(Network CONDITION QT_FEATURE_dtls AND QT_FEATURE_ssl
- SOURCES
- ssl/qdtls.cpp ssl/qdtls.h ssl/qdtls_p.h
-)
-
-qt_internal_extend_target(Network CONDITION QT_FEATURE_openssl AND QT_FEATURE_ssl
- SOURCES
- ssl/qsslcertificate_openssl.cpp
- ssl/qsslcontext_openssl.cpp ssl/qsslcontext_openssl_p.h
- ssl/qssldiffiehellmanparameters_openssl.cpp
- ssl/qsslellipticcurve_openssl.cpp
- ssl/qsslkey_openssl.cpp
- ssl/qsslsocket_openssl.cpp ssl/qsslsocket_openssl_p.h
- ssl/qsslsocket_openssl_symbols.cpp ssl/qsslsocket_openssl_symbols_p.h
- DEFINES
- OPENSSL_API_COMPAT=0x10100000L
-)
-
-qt_internal_extend_target(Network CONDITION QT_FEATURE_dtls AND QT_FEATURE_openssl AND QT_FEATURE_ssl
- SOURCES
- ssl/qdtls_openssl.cpp ssl/qdtls_openssl_p.h
-)
-
-qt_internal_extend_target(Network CONDITION QT_FEATURE_ocsp AND QT_FEATURE_openssl AND QT_FEATURE_ssl
- SOURCES
- ssl/qocsp_p.h
-)
-
-qt_internal_extend_target(Network CONDITION APPLE AND QT_FEATURE_openssl AND QT_FEATURE_ssl
- SOURCES
- ssl/qsslsocket_mac_shared.cpp
-)
-
-qt_internal_extend_target(Network CONDITION ANDROID AND QT_FEATURE_openssl AND QT_FEATURE_ssl AND NOT ANDROID_EMBEDDED
- SOURCES
- ssl/qsslsocket_openssl_android.cpp
-)
-
-qt_internal_extend_target(Network CONDITION ANDROID AND QT_FEATURE_openssl AND QT_FEATURE_openssl_linked AND QT_FEATURE_ssl AND (build_pass OR single_android_abi)
- LIBRARIES
- crypto_${CMAKE_SYSTEM_PROCESSOR}
- ssl_${CMAKE_SYSTEM_PROCESSOR}
-)
-
-qt_internal_extend_target(Network CONDITION QT_FEATURE_openssl AND QT_FEATURE_openssl_linked AND QT_FEATURE_ssl AND NOT ANDROID
- LIBRARIES
- WrapOpenSSL::WrapOpenSSL
-)
-
-qt_internal_extend_target(Network CONDITION QT_FEATURE_openssl AND QT_FEATURE_ssl AND NOT QT_FEATURE_openssl_linked
- LIBRARIES
- WrapOpenSSLHeaders::WrapOpenSSLHeaders
-)
-
-qt_internal_extend_target(Network CONDITION QT_FEATURE_openssl AND QT_FEATURE_ssl AND WIN32
- SOURCES
- ssl/qwindowscarootfetcher.cpp ssl/qwindowscarootfetcher_p.h
- LIBRARIES
- crypt32
-)
-
-qt_internal_extend_target(Network CONDITION QT_FEATURE_dnslookup AND UNIX AND NOT ANDROID AND NOT INTEGRITY
- SOURCES
- kernel/qdnslookup_unix.cpp
-)
-qt_internal_add_docs(Network
- doc/qtnetwork.qdocconf
-)
-
diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt
index d94fff5f7f..3f226a77dc 100644
--- a/src/network/CMakeLists.txt
+++ b/src/network/CMakeLists.txt
@@ -1,11 +1,12 @@
-# Generated from network.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## Network Module:
#####################################################################
qt_internal_add_module(Network
- PLUGIN_TYPES networkaccessbackends
+ PLUGIN_TYPES networkaccess networkinformation tls
SOURCES
access/qabstractnetworkcache.cpp access/qabstractnetworkcache.h access/qabstractnetworkcache_p.h
access/qhsts.cpp access/qhsts_p.h
@@ -14,41 +15,54 @@ qt_internal_add_module(Network
access/qnetworkaccessbackend.cpp access/qnetworkaccessbackend_p.h
access/qnetworkaccesscache.cpp access/qnetworkaccesscache_p.h
access/qnetworkaccesscachebackend.cpp access/qnetworkaccesscachebackend_p.h
- access/qnetworkaccessdebugpipebackend.cpp access/qnetworkaccessdebugpipebackend_p.h
access/qnetworkaccessfilebackend.cpp access/qnetworkaccessfilebackend_p.h
access/qnetworkaccessmanager.cpp access/qnetworkaccessmanager.h access/qnetworkaccessmanager_p.h
access/qnetworkcookie.cpp access/qnetworkcookie.h access/qnetworkcookie_p.h
access/qnetworkcookiejar.cpp access/qnetworkcookiejar.h access/qnetworkcookiejar_p.h
access/qnetworkfile.cpp access/qnetworkfile_p.h
+ access/qhttpheaders.cpp access/qhttpheaders.h
+ access/qhttpheaderparser.cpp access/qhttpheaderparser_p.h
access/qnetworkreply.cpp access/qnetworkreply.h access/qnetworkreply_p.h
access/qnetworkreplydataimpl.cpp access/qnetworkreplydataimpl_p.h
access/qnetworkreplyfileimpl.cpp access/qnetworkreplyfileimpl_p.h
access/qnetworkreplyimpl.cpp access/qnetworkreplyimpl_p.h
access/qnetworkrequest.cpp access/qnetworkrequest.h access/qnetworkrequest_p.h
+ compat/removed_api.cpp
kernel/qauthenticator.cpp kernel/qauthenticator.h kernel/qauthenticator_p.h
kernel/qhostaddress.cpp kernel/qhostaddress.h kernel/qhostaddress_p.h
kernel/qhostinfo.cpp kernel/qhostinfo.h kernel/qhostinfo_p.h
kernel/qnetconmonitor_p.h
kernel/qnetworkdatagram.cpp kernel/qnetworkdatagram.h kernel/qnetworkdatagram_p.h
+ kernel/qnetworkinformation.cpp kernel/qnetworkinformation_p.h kernel/qnetworkinformation.h
kernel/qnetworkinterface.cpp kernel/qnetworkinterface.h kernel/qnetworkinterface_p.h
kernel/qnetworkinterface_unix_p.h
kernel/qnetworkproxy.cpp kernel/qnetworkproxy.h
kernel/qtnetworkglobal.h kernel/qtnetworkglobal_p.h
socket/qabstractsocket.cpp socket/qabstractsocket.h socket/qabstractsocket_p.h
socket/qabstractsocketengine.cpp socket/qabstractsocketengine_p.h
- socket/qnativesocketengine.cpp socket/qnativesocketengine_p.h
+ socket/qnativesocketengine.cpp socket/qnativesocketengine_p.h socket/qnativesocketengine_p_p.h
socket/qtcpserver.cpp socket/qtcpserver.h socket/qtcpserver_p.h
socket/qtcpsocket.cpp socket/qtcpsocket.h socket/qtcpsocket_p.h
socket/qudpsocket.cpp socket/qudpsocket.h
- ssl/qasn1element.cpp ssl/qasn1element_p.h
ssl/qpassworddigestor.cpp ssl/qpassworddigestor.h
- ssl/qssl.cpp ssl/qssl.h ssl/qssl_p.h ssl/qtls_utils_p.h
+ ssl/qssl.cpp ssl/qssl.h ssl/qssl_p.h
ssl/qsslcertificate.cpp ssl/qsslcertificate.h ssl/qsslcertificate_p.h
ssl/qsslcertificateextension.cpp ssl/qsslcertificateextension.h ssl/qsslcertificateextension_p.h
- ssl/qtls_utils_p.h
+ ssl/qsslcipher.h
+ ssl/qsslconfiguration.h
+ ssl/qsslerror.h
+ ssl/qsslkey.h
+ ssl/qsslsocket.h
+ ssl/qtlsbackend.cpp ssl/qtlsbackend_p.h
DEFINES
+ QT_NO_CONTEXTLESS_CONNECT
QT_NO_FOREACH
QT_NO_USING_NAMESPACE
+ QT_NO_CAST_FROM_ASCII
+ QT_NO_CAST_TO_ASCII
+ QT_NO_CAST_FROM_BYTEARRAY
+ QT_NO_URL_CAST_FROM_STRING
+ QT_USE_NODISCARD_FILE_OPEN
INCLUDE_DIRECTORIES
kernel
LIBRARIES
@@ -57,16 +71,21 @@ qt_internal_add_module(Network
Qt::Core
PRIVATE_MODULE_INTERFACE
Qt::CorePrivate
+ NO_PCH_SOURCES
+ compat/removed_api.cpp
PRECOMPILED_HEADER
"../corelib/global/qt_pch.h"
+ GENERATE_CPP_EXPORTS
)
-#### Keys ignored in scope 1:.:.:network.pro:<TRUE>:
-# QMAKE_LIBS = "$$QMAKE_LIBS_NETWORK"
-
## Scopes:
#####################################################################
+qt_internal_extend_target(Network CONDITION QT_FEATURE_private_tests
+ SOURCES
+ access/qnetworkaccessdebugpipebackend.cpp access/qnetworkaccessdebugpipebackend_p.h
+)
+
qt_internal_extend_target(Network CONDITION MSVC AND (TEST_architecture_arch STREQUAL "i386")
LINK_OPTIONS
"/BASE:0x64000000"
@@ -106,7 +125,9 @@ qt_internal_extend_target(Network CONDITION QT_FEATURE_http
access/http2/huffman.cpp access/http2/huffman_p.h
access/qabstractprotocolhandler.cpp access/qabstractprotocolhandler_p.h
access/qdecompresshelper.cpp access/qdecompresshelper_p.h
+ access/qhttp1configuration.cpp access/qhttp1configuration.h
access/qhttp2configuration.cpp access/qhttp2configuration.h
+ access/qhttp2connection.cpp access/qhttp2connection_p.h
access/qhttp2protocolhandler.cpp access/qhttp2protocolhandler_p.h
access/qhttpmultipart.cpp access/qhttpmultipart.h access/qhttpmultipart_p.h
access/qhttpnetworkconnection.cpp access/qhttpnetworkconnection_p.h
@@ -117,6 +138,11 @@ qt_internal_extend_target(Network CONDITION QT_FEATURE_http
access/qhttpprotocolhandler.cpp access/qhttpprotocolhandler_p.h
access/qhttpthreaddelegate.cpp access/qhttpthreaddelegate_p.h
access/qnetworkreplyhttpimpl.cpp access/qnetworkreplyhttpimpl_p.h
+ access/qnetworkrequestfactory.cpp access/qnetworkrequestfactory_p.h
+ access/qnetworkrequestfactory.h
+ access/qrestaccessmanager.cpp access/qrestaccessmanager.h access/qrestaccessmanager_p.h
+ access/qrestreply.cpp access/qrestreply.h access/qrestreply_p.h
+ access/qsocketabstraction_p.h
socket/qhttpsocketengine.cpp socket/qhttpsocketengine_p.h
)
@@ -127,12 +153,12 @@ qt_internal_extend_target(Network CONDITION QT_FEATURE_brotli AND QT_FEATURE_htt
qt_internal_extend_target(Network CONDITION QT_FEATURE_http AND QT_FEATURE_zstd
LIBRARIES
- ZSTD::ZSTD
+ WrapZSTD::WrapZSTD
)
qt_internal_extend_target(Network CONDITION QT_FEATURE_system_zlib
LIBRARIES
- ZLIB::ZLIB
+ WrapZLIB::WrapZLIB
)
qt_internal_extend_target(Network CONDITION NOT QT_FEATURE_system_zlib
@@ -148,7 +174,9 @@ qt_internal_extend_target(Network CONDITION NOT QT_FEATURE_system_zlib AND NOT n
qt_internal_extend_target(Network CONDITION QT_FEATURE_topleveldomain
SOURCES
kernel/qtldurl.cpp kernel/qtldurl_p.h
- kernel/qurltlds_p.h
+ ../3rdparty/libpsl/src/lookup_string_in_fixed_set.c
+ INCLUDE_DIRECTORIES
+ ../3rdparty/libpsl
)
qt_internal_extend_target(Network CONDITION QT_FEATURE_dnslookup
@@ -163,11 +191,6 @@ qt_internal_extend_target(Network CONDITION UNIX
socket/qnet_unix_p.h
)
-qt_internal_extend_target(Network CONDITION QT_FEATURE_dlopen AND UNIX
- LIBRARIES
- ${CMAKE_DL_LIBS}
-)
-
qt_internal_extend_target(Network CONDITION QT_FEATURE_linux_netlink AND UNIX
SOURCES
kernel/qnetworkinterface_linux.cpp
@@ -178,11 +201,6 @@ qt_internal_extend_target(Network CONDITION UNIX AND NOT QT_FEATURE_linux_netlin
kernel/qnetworkinterface_unix.cpp
)
-qt_internal_extend_target(Network CONDITION ANDROID AND QT_FEATURE_dnslookup
- SOURCES
- kernel/qdnslookup_android.cpp
-)
-
qt_internal_extend_target(Network CONDITION WIN32
SOURCES
kernel/qhostinfo_win.cpp
@@ -193,6 +211,28 @@ qt_internal_extend_target(Network CONDITION WIN32
advapi32
dnsapi
iphlpapi
+ secur32
+ winhttp
+ DEFINES
+ NOMINMAX
+)
+
+qt_internal_extend_target(Network CONDITION APPLE AND NOT UIKIT
+ LIBRARIES
+ ${FWCoreServices}
+ ${FWSystemConfiguration}
+)
+
+qt_internal_extend_target(Network CONDITION APPLE
+ LIBRARIES
+ ${FWCFNetwork}
+)
+
+qt_internal_extend_target(Network CONDITION QT_FEATURE_dnslookup AND QT_FEATURE_libresolv
+ SOURCES
+ kernel/qdnslookup_unix.cpp
+ LIBRARIES
+ WrapResolv::WrapResolv
)
qt_internal_extend_target(Network CONDITION QT_FEATURE_dnslookup AND WIN32
@@ -200,25 +240,24 @@ qt_internal_extend_target(Network CONDITION QT_FEATURE_dnslookup AND WIN32
kernel/qdnslookup_win.cpp
)
-qt_internal_extend_target(Network CONDITION APPLE AND NOT UIKIT
- LIBRARIES
- ${FWCoreServices}
- ${FWSystemConfiguration}
+qt_internal_extend_target(Network CONDITION QT_FEATURE_dnslookup AND NOT QT_FEATURE_libresolv AND NOT WIN32
+ SOURCES
+ kernel/qdnslookup_dummy.cpp
)
-qt_internal_extend_target(Network CONDITION IOS OR MACOS
+qt_internal_extend_target(Network CONDITION APPLE
SOURCES
kernel/qnetconmonitor_darwin.mm
LIBRARIES
${FWSystemConfiguration}
)
-qt_internal_extend_target(Network CONDITION QT_FEATURE_netlistmgr AND NOT IOS AND NOT MACOS
+qt_internal_extend_target(Network CONDITION QT_FEATURE_networklistmanager AND NOT IOS AND NOT MACOS
SOURCES
kernel/qnetconmonitor_win.cpp
)
-qt_internal_extend_target(Network CONDITION NOT IOS AND NOT MACOS AND NOT QT_FEATURE_netlistmgr
+qt_internal_extend_target(Network CONDITION NOT APPLE AND NOT QT_FEATURE_networklistmanager
SOURCES
kernel/qnetconmonitor_stub.cpp
)
@@ -233,9 +272,9 @@ qt_internal_extend_target(Network CONDITION UIKIT
kernel/qnetworkinterface_uikit_p.h
)
-qt_internal_extend_target(Network CONDITION MACOS
+qt_internal_extend_target(Network CONDITION APPLE AND NOT VISIONOS
SOURCES
- kernel/qnetworkproxy_mac.cpp
+ kernel/qnetworkproxy_darwin.cpp
)
qt_internal_extend_target(Network CONDITION QT_FEATURE_libproxy AND UNIX AND NOT MACOS
@@ -246,19 +285,19 @@ qt_internal_extend_target(Network CONDITION QT_FEATURE_libproxy AND UNIX AND NOT
PkgConfig::Libproxy
)
-qt_internal_extend_target(Network CONDITION ANDROID # special case
+qt_internal_extend_target(Network CONDITION ANDROID
SOURCES
kernel/qnetworkproxy_android.cpp
)
-qt_internal_extend_target(Network CONDITION UNIX AND NOT ANDROID AND NOT MACOS AND NOT QT_FEATURE_libproxy AND (UNIX OR WINRT) # special case
+qt_internal_extend_target(Network CONDITION UNIX AND NOT ANDROID AND NOT (APPLE AND NOT VISIONOS) AND NOT QT_FEATURE_libproxy AND (UNIX OR WINRT)
SOURCES
kernel/qnetworkproxy_generic.cpp
)
if(ANDROID AND (ANDROID))
set_property(TARGET Network APPEND PROPERTY QT_ANDROID_BUNDLED_JAR_DEPENDENCIES
- jar/QtAndroidNetwork.jar
+ jar/Qt${QtBase_VERSION_MAJOR}AndroidNetwork.jar
)
endif()
@@ -304,54 +343,28 @@ qt_internal_extend_target(Network CONDITION QT_FEATURE_localserver AND WIN32
socket/qlocalsocket_win.cpp
)
+qt_internal_extend_target(Network CONDITION QT_FEATURE_openssl_linked AND QT_FEATURE_opensslv30
+ LIBRARIES
+ WrapOpenSSL::WrapOpenSSL
+)
+
qt_internal_extend_target(Network CONDITION QT_FEATURE_system_proxies
DEFINES
QT_USE_SYSTEM_PROXIES
)
-qt_internal_extend_target(Network CONDITION NOT QT_FEATURE_openssl
- SOURCES
- ssl/qsslcertificate_qt.cpp
-)
-
qt_internal_extend_target(Network CONDITION QT_FEATURE_ssl
SOURCES
ssl/qocspresponse.cpp ssl/qocspresponse.h ssl/qocspresponse_p.h
- ssl/qsslcipher.cpp ssl/qsslcipher.h ssl/qsslcipher_p.h
- ssl/qsslconfiguration.cpp ssl/qsslconfiguration.h ssl/qsslconfiguration_p.h
+ ssl/qsslcipher.cpp ssl/qsslcipher_p.h
+ ssl/qsslconfiguration.cpp ssl/qsslconfiguration_p.h
ssl/qssldiffiehellmanparameters.cpp ssl/qssldiffiehellmanparameters.h ssl/qssldiffiehellmanparameters_p.h
ssl/qsslellipticcurve.cpp ssl/qsslellipticcurve.h
- ssl/qsslerror.cpp ssl/qsslerror.h
- ssl/qsslkey.h ssl/qsslkey_p.cpp ssl/qsslkey_p.h
+ ssl/qsslerror.cpp
+ ssl/qsslkey_p.cpp ssl/qsslkey_p.h
ssl/qsslpresharedkeyauthenticator.cpp ssl/qsslpresharedkeyauthenticator.h ssl/qsslpresharedkeyauthenticator_p.h
- ssl/qsslsocket.cpp ssl/qsslsocket.h ssl/qsslsocket_p.h
-)
-
-qt_internal_extend_target(Network CONDITION QT_FEATURE_schannel AND QT_FEATURE_ssl
- SOURCES
- ssl/qsslcertificate_schannel.cpp
- ssl/qssldiffiehellmanparameters_dummy.cpp
- ssl/qsslellipticcurve_dummy.cpp
- ssl/qsslkey_qt.cpp
- ssl/qsslkey_schannel.cpp
- ssl/qsslsocket_qt.cpp
- ssl/qsslsocket_schannel.cpp ssl/qsslsocket_schannel_p.h
- LIBRARIES
- Crypt32
- Secur32
- bcrypt
- ncrypt
-)
-
-qt_internal_extend_target(Network CONDITION QT_FEATURE_securetransport AND QT_FEATURE_ssl
- SOURCES
- ssl/qssldiffiehellmanparameters_dummy.cpp
- ssl/qsslellipticcurve_dummy.cpp
- ssl/qsslkey_mac.cpp
- ssl/qsslkey_qt.cpp
- ssl/qsslsocket_mac.cpp ssl/qsslsocket_mac_p.h
- ssl/qsslsocket_mac_shared.cpp
- ssl/qsslsocket_qt.cpp
+ ssl/qsslsocket.cpp ssl/qsslsocket_p.h
+ ssl/qsslserver.cpp ssl/qsslserver.h ssl/qsslserver_p.h
)
qt_internal_extend_target(Network CONDITION QT_FEATURE_dtls AND QT_FEATURE_ssl
@@ -359,70 +372,49 @@ qt_internal_extend_target(Network CONDITION QT_FEATURE_dtls AND QT_FEATURE_ssl
ssl/qdtls.cpp ssl/qdtls.h ssl/qdtls_p.h
)
-qt_internal_extend_target(Network CONDITION QT_FEATURE_openssl AND QT_FEATURE_ssl
- SOURCES
- ssl/qsslcertificate_openssl.cpp
- ssl/qsslcontext_openssl.cpp ssl/qsslcontext_openssl_p.h
- ssl/qssldiffiehellmanparameters_openssl.cpp
- ssl/qsslellipticcurve_openssl.cpp
- ssl/qsslkey_openssl.cpp
- ssl/qsslsocket_openssl.cpp ssl/qsslsocket_openssl_p.h
- ssl/qsslsocket_openssl_symbols.cpp ssl/qsslsocket_openssl_symbols_p.h
- DEFINES
- OPENSSL_API_COMPAT=0x10100000L
-)
-
-qt_internal_extend_target(Network CONDITION QT_FEATURE_dtls AND QT_FEATURE_openssl AND QT_FEATURE_ssl
- SOURCES
- ssl/qdtls_openssl.cpp ssl/qdtls_openssl_p.h
-)
-
qt_internal_extend_target(Network CONDITION QT_FEATURE_ocsp AND QT_FEATURE_openssl AND QT_FEATURE_ssl
SOURCES
ssl/qocsp_p.h
)
-qt_internal_extend_target(Network CONDITION APPLE AND QT_FEATURE_openssl AND QT_FEATURE_ssl
- SOURCES
- ssl/qsslsocket_mac_shared.cpp
-)
-
-qt_internal_extend_target(Network CONDITION ANDROID AND QT_FEATURE_openssl AND QT_FEATURE_ssl AND NOT ANDROID_EMBEDDED
- SOURCES
- ssl/qsslsocket_openssl_android.cpp
+qt_internal_add_docs(Network
+ doc/qtnetwork.qdocconf
)
-qt_internal_extend_target(Network CONDITION ANDROID AND QT_FEATURE_openssl AND QT_FEATURE_openssl_linked AND QT_FEATURE_ssl AND (build_pass OR single_android_abi)
- LIBRARIES
- crypto_${CMAKE_SYSTEM_PROCESSOR}
- ssl_${CMAKE_SYSTEM_PROCESSOR}
-)
+# See mkspecs/common/msvc-desktop.conf
+qt_internal_extend_target(Network CONDITION WIN32 PUBLIC_LIBRARIES ws2_32)
-qt_internal_extend_target(Network CONDITION QT_FEATURE_openssl AND QT_FEATURE_openssl_linked AND QT_FEATURE_ssl AND NOT ANDROID
- LIBRARIES
- WrapOpenSSL::WrapOpenSSL
-)
+# See mkspecs/common/qcc-base-qnx.conf
+qt_internal_extend_target(Network CONDITION QNX PUBLIC_LIBRARIES socket)
-qt_internal_extend_target(Network CONDITION QT_FEATURE_openssl AND QT_FEATURE_ssl AND NOT QT_FEATURE_openssl_linked
- LIBRARIES
- WrapOpenSSLHeaders::WrapOpenSSLHeaders
-)
+qt_internal_extend_target(Network CONDITION SOLARIS PUBLIC_LIBRARIES socket nsl)
-qt_internal_extend_target(Network CONDITION QT_FEATURE_openssl AND QT_FEATURE_ssl AND WIN32
- SOURCES
- ssl/qwindowscarootfetcher.cpp ssl/qwindowscarootfetcher_p.h
- LIBRARIES
- crypt32
+qt_internal_extend_target(Network CONDITION WIN32
+ NO_UNITY_BUILD_SOURCES
+ kernel/qauthenticator.cpp
+ kernel/qdnslookup_win.cpp
+ kernel/qhostaddress.cpp
+ kernel/qhostinfo.cpp
+ kernel/qhostinfo_win.cpp
+ kernel/qnetconmonitor_win.cpp
+ kernel/qnetworkinterface_win.cpp
+ kernel/qnetworkproxy_win.cpp
+ socket/qabstractsocket.cpp
+ socket/qlocalserver.cpp
+ socket/qlocalserver_win.cpp
+ socket/qlocalsocket_win.cpp
+ socket/qnativesocketengine.cpp
+ socket/qnativesocketengine_win.cpp
)
-qt_internal_extend_target(Network CONDITION QT_FEATURE_dnslookup AND UNIX AND NOT ANDROID AND NOT INTEGRITY
- SOURCES
- kernel/qdnslookup_unix.cpp
-)
-qt_internal_add_docs(Network
- doc/qtnetwork.qdocconf
+# include the snippet projects for developer-builds
+if(QT_FEATURE_private_tests)
+ add_subdirectory(doc/snippets/network)
+endif()
+qt_internal_extend_target(Network
+ # Workaround for QTBUG-118229:
+ # Function called by inline methods taking a pointer to a private class as a parameter
+ EXTRA_LINKER_SCRIPT_EXPORTS
+ # QNetworkDatagram::destroy(QNetworkDatagramPrivate *d)
+ "_ZN*16QNetworkDatagram7destroyEP*23QNetworkDatagramPrivate*"
)
-
-qt_internal_extend_target(Network CONDITION WIN32 PUBLIC_LIBRARIES ws2_32) # special case: mkspecs/common/msvc-desktop.conf
-
-qt_internal_extend_target(Network CONDITION QNX PUBLIC_LIBRARIES socket) # special case: mkspecs/common/qcc-base-qnx.conf
diff --git a/src/network/access/access.pri b/src/network/access/access.pri
deleted file mode 100644
index d7fe0c632d..0000000000
--- a/src/network/access/access.pri
+++ /dev/null
@@ -1,128 +0,0 @@
-# Qt network access module
-
-HEADERS += \
- access/qnetworkaccessauthenticationmanager_p.h \
- access/qnetworkaccessmanager.h \
- access/qnetworkaccessmanager_p.h \
- access/qnetworkaccesscache_p.h \
- access/qnetworkaccessbackend_p.h \
- access/qnetworkaccessdebugpipebackend_p.h \
- access/qnetworkaccessfilebackend_p.h \
- access/qnetworkaccesscachebackend_p.h \
- access/qnetworkcookie.h \
- access/qnetworkcookie_p.h \
- access/qnetworkcookiejar.h \
- access/qnetworkcookiejar_p.h \
- access/qnetworkrequest.h \
- access/qnetworkrequest_p.h \
- access/qnetworkreply.h \
- access/qnetworkreply_p.h \
- access/qnetworkreplyimpl_p.h \
- access/qnetworkreplydataimpl_p.h \
- access/qnetworkreplyfileimpl_p.h \
- access/qabstractnetworkcache_p.h \
- access/qabstractnetworkcache.h \
- access/qnetworkfile_p.h \
- access/qhsts_p.h \
- access/qhstspolicy.h
-
-SOURCES += \
- access/qnetworkaccessauthenticationmanager.cpp \
- access/qnetworkaccessmanager.cpp \
- access/qnetworkaccesscache.cpp \
- access/qnetworkaccessbackend.cpp \
- access/qnetworkaccessdebugpipebackend.cpp \
- access/qnetworkaccessfilebackend.cpp \
- access/qnetworkaccesscachebackend.cpp \
- access/qnetworkcookie.cpp \
- access/qnetworkcookiejar.cpp \
- access/qnetworkrequest.cpp \
- access/qnetworkreply.cpp \
- access/qnetworkreplyimpl.cpp \
- access/qnetworkreplydataimpl.cpp \
- access/qnetworkreplyfileimpl.cpp \
- access/qabstractnetworkcache.cpp \
- access/qnetworkfile.cpp \
- access/qhsts.cpp \
- access/qhstspolicy.cpp
-
-qtConfig(networkdiskcache) {
- HEADERS += \
- access/qnetworkdiskcache_p.h \
- access/qnetworkdiskcache.h
-
- SOURCES += access/qnetworkdiskcache.cpp
-}
-
-qtConfig(settings) {
- HEADERS += \
- access/qhstsstore_p.h
-
- SOURCES += \
- access/qhstsstore.cpp
-}
-
-mac: LIBS_PRIVATE += -framework Security
-
-wasm {
- SOURCES += \
- access/qnetworkreplywasmimpl.cpp
- HEADERS += \
- access/qnetworkreplywasmimpl_p.h
-}
-
-include($$PWD/../../3rdparty/zlib_dependency.pri)
-
-qtConfig(http) {
- include($$PWD/http2/http2.pri)
-
- SOURCES += \
- access/qdecompresshelper.cpp \
- access/qabstractprotocolhandler.cpp \
- access/qhttp2protocolhandler.cpp \
- access/qhttpmultipart.cpp \
- access/qhttpnetworkconnection.cpp \
- access/qhttpnetworkconnectionchannel.cpp \
- access/qhttpnetworkheader.cpp \
- access/qhttpnetworkreply.cpp \
- access/qhttpnetworkrequest.cpp \
- access/qhttpprotocolhandler.cpp \
- access/qhttpthreaddelegate.cpp \
- access/qnetworkreplyhttpimpl.cpp \
- access/qhttp2configuration.cpp
-
- HEADERS += \
- access/qdecompresshelper_p.h \
- access/qabstractprotocolhandler_p.h \
- access/qhttp2protocolhandler_p.h \
- access/qhttpmultipart.h \
- access/qhttpmultipart_p.h \
- access/qhttpnetworkconnection_p.h \
- access/qhttpnetworkconnectionchannel_p.h \
- access/qhttpnetworkheader_p.h \
- access/qhttpnetworkreply_p.h \
- access/qhttpnetworkrequest_p.h \
- access/qhttpprotocolhandler_p.h \
- access/qhttpthreaddelegate_p.h \
- access/qnetworkreplyhttpimpl_p.h \
- access/qhttp2configuration.h
-
- qtConfig(brotli) {
- QMAKE_USE_PRIVATE += brotli
- }
-
- qtConfig(zstd) {
- QMAKE_USE_PRIVATE += zstd
- }
-}
-
-wasm: {
- SOURCES += \
- access/qhttpmultipart.cpp \
- access/qhttpnetworkheader.cpp
-
- HEADERS += \
- access/qhttpmultipart.h \
- access/qhttpmultipart_p.h \
- access/qhttpnetworkheader_p.h
-}
diff --git a/src/network/access/http2/bitstreams.cpp b/src/network/access/http2/bitstreams.cpp
index d22c7cd4ec..c35f0e3aaa 100644
--- a/src/network/access/http2/bitstreams.cpp
+++ b/src/network/access/http2/bitstreams.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "bitstreams_p.h"
#include "huffman_p.h"
@@ -99,7 +63,7 @@ void BitOStream::write(quint32 src)
}
}
-void BitOStream::write(const QByteArray &src, bool compressed)
+void BitOStream::write(QByteArrayView src, bool compressed)
{
quint32 byteLen = src.size();
if (compressed && byteLen) {
diff --git a/src/network/access/http2/bitstreams_p.h b/src/network/access/http2/bitstreams_p.h
index ca272062a6..c96adb5390 100644
--- a/src/network/access/http2/bitstreams_p.h
+++ b/src/network/access/http2/bitstreams_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef BITSTREAMS_P_H
#define BITSTREAMS_P_H
@@ -51,7 +15,7 @@
// We mean it.
//
-#include <QtCore/qglobal.h>
+#include <QtCore/private/qglobal_p.h>
#include <QtCore/qdebug.h>
#include <type_traits>
@@ -79,7 +43,7 @@ public:
// * 32-bit integers
// * strings
void write(quint32 src);
- void write(const QByteArray &src, bool compressed);
+ void write(QByteArrayView src, bool compressed);
quint64 bitLength() const;
quint64 byteLength() const;
diff --git a/src/network/access/http2/hpack.cpp b/src/network/access/http2/hpack.cpp
index 7461095f0a..9e970dda53 100644
--- a/src/network/access/http2/hpack.cpp
+++ b/src/network/access/http2/hpack.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "bitstreams_p.h"
#include "hpack_p.h"
@@ -127,7 +91,7 @@ bool read_bit_pattern(const BitPattern &pattern, BitIStream &inputStream)
return true;
}
-bool is_request_pseudo_header(const QByteArray &name)
+bool is_request_pseudo_header(QByteArrayView name)
{
return name == ":method" || name == ":scheme" ||
name == ":authority" || name == ":path";
@@ -230,8 +194,8 @@ bool Encoder::encodeRequestPseudoHeaders(BitOStream &outputStream,
using size_type = decltype(header.size());
bool methodFound = false;
- const char *headerName[] = {":authority", ":scheme", ":path"};
- const size_type nHeaders = sizeof headerName / sizeof headerName[0];
+ constexpr QByteArrayView headerName[] = {":authority", ":scheme", ":path"};
+ constexpr size_type nHeaders = std::size(headerName);
bool headerFound[nHeaders] = {};
for (const auto &field : header) {
@@ -540,6 +504,49 @@ void Decoder::handleStreamError(BitIStream &inputStream)
// HTTP2 layer will end with session error/COMPRESSION_ERROR.
}
+std::optional<QUrl> makePromiseKeyUrl(const HttpHeader &requestHeader)
+{
+ constexpr QByteArrayView names[] = { ":authority", ":method", ":path", ":scheme" };
+ enum PseudoHeaderEnum
+ {
+ Authority,
+ Method,
+ Path,
+ Scheme
+ };
+ std::array<std::optional<QByteArrayView>, std::size(names)> pseudoHeaders{};
+ for (const auto &field : requestHeader) {
+ const auto *it = std::find(std::begin(names), std::end(names), QByteArrayView(field.name));
+ if (it != std::end(names)) {
+ const auto index = std::distance(std::begin(names), it);
+ if (field.value.isEmpty() || pseudoHeaders.at(index).has_value())
+ return {};
+ pseudoHeaders[index] = field.value;
+ }
+ }
+
+ auto optionalIsSet = [](const auto &x) { return x.has_value(); };
+ if (!std::all_of(pseudoHeaders.begin(), pseudoHeaders.end(), optionalIsSet)) {
+ // All four required, HTTP/2 8.1.2.3.
+ return {};
+ }
+
+ const QByteArrayView method = pseudoHeaders[Method].value();
+ if (method.compare("get", Qt::CaseInsensitive) != 0 &&
+ method.compare("head", Qt::CaseInsensitive) != 0) {
+ return {};
+ }
+
+ QUrl url;
+ url.setScheme(QLatin1StringView(pseudoHeaders[Scheme].value()));
+ url.setAuthority(QLatin1StringView(pseudoHeaders[Authority].value()));
+ url.setPath(QLatin1StringView(pseudoHeaders[Path].value()));
+
+ if (!url.isValid())
+ return {};
+ return url;
+}
+
}
QT_END_NAMESPACE
diff --git a/src/network/access/http2/hpack_p.h b/src/network/access/http2/hpack_p.h
index 8c2701e7af..b407b81941 100644
--- a/src/network/access/http2/hpack_p.h
+++ b/src/network/access/http2/hpack_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef HPACK_P_H
#define HPACK_P_H
@@ -54,8 +18,10 @@
#include "hpacktable_p.h"
#include <QtCore/qglobal.h>
+#include <QtCore/qurl.h>
#include <vector>
+#include <optional>
QT_BEGIN_NAMESPACE
@@ -148,6 +114,7 @@ private:
FieldLookupTable lookupTable;
};
+std::optional<QUrl> makePromiseKeyUrl(const HttpHeader &requestHeader);
}
QT_END_NAMESPACE
diff --git a/src/network/access/http2/hpacktable.cpp b/src/network/access/http2/hpacktable.cpp
index d963cf261b..2c728b37e3 100644
--- a/src/network/access/http2/hpacktable.cpp
+++ b/src/network/access/http2/hpacktable.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "hpacktable_p.h"
@@ -52,7 +16,7 @@ QT_BEGIN_NAMESPACE
namespace HPack
{
-HeaderSize entry_size(const QByteArray &name, const QByteArray &value)
+HeaderSize entry_size(QByteArrayView name, QByteArrayView value)
{
// 32 comes from HPACK:
// "4.1 Calculating Table Size
@@ -62,8 +26,10 @@ HeaderSize entry_size(const QByteArray &name, const QByteArray &value)
// for counting the number of references to the name and value would have
// 32 octets of overhead."
- const unsigned sum = unsigned(name.size() + value.size());
- if (std::numeric_limits<unsigned>::max() - 32 < sum)
+ size_t sum;
+ if (qAddOverflow(size_t(name.size()), size_t(value.size()), &sum))
+ return HeaderSize();
+ if (sum > (std::numeric_limits<unsigned>::max() - 32))
return HeaderSize();
return HeaderSize(true, quint32(sum + 32));
}
@@ -382,8 +348,7 @@ quint32 FieldLookupTable::indexOfChunk(const Chunk *chunk) const
return quint32(i);
}
- Q_UNREACHABLE();
- return 0;
+ Q_UNREACHABLE_RETURN(0);
}
quint32 FieldLookupTable::keyToIndex(const SearchEntry &key) const
diff --git a/src/network/access/http2/hpacktable_p.h b/src/network/access/http2/hpacktable_p.h
index 587d86f09c..d57013150b 100644
--- a/src/network/access/http2/hpacktable_p.h
+++ b/src/network/access/http2/hpacktable_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef HPACKTABLE_P_H
#define HPACKTABLE_P_H
@@ -52,7 +16,7 @@
//
#include <QtCore/qbytearray.h>
-#include <QtCore/qglobal.h>
+#include <QtCore/private/qglobal_p.h>
#include <QtCore/qpair.h>
#include <vector>
@@ -88,7 +52,7 @@ struct Q_AUTOTEST_EXPORT HeaderField
using HeaderSize = QPair<bool, quint32>;
-HeaderSize entry_size(const QByteArray &name, const QByteArray &value);
+HeaderSize entry_size(QByteArrayView name, QByteArrayView value);
inline HeaderSize entry_size(const HeaderField &entry)
{
diff --git a/src/network/access/http2/http2.pri b/src/network/access/http2/http2.pri
deleted file mode 100644
index e9f30aeb4a..0000000000
--- a/src/network/access/http2/http2.pri
+++ /dev/null
@@ -1,17 +0,0 @@
-HEADERS += \
- access/http2/bitstreams_p.h \
- access/http2/huffman_p.h \
- access/http2/hpack_p.h \
- access/http2/hpacktable_p.h \
- access/http2/http2frames_p.h \
- access/http2/http2streams_p.h \
- access/http2/http2protocol_p.h
-
-SOURCES += \
- access/http2/bitstreams.cpp \
- access/http2/huffman.cpp \
- access/http2/hpack.cpp \
- access/http2/hpacktable.cpp \
- access/http2/http2frames.cpp \
- access/http2/http2streams.cpp \
- access/http2/http2protocol.cpp
diff --git a/src/network/access/http2/http2frames.cpp b/src/network/access/http2/http2frames.cpp
index ce33505683..e07c96b803 100644
--- a/src/network/access/http2/http2frames.cpp
+++ b/src/network/access/http2/http2frames.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "http2frames_p.h"
@@ -171,6 +135,7 @@ FrameStatus Frame::validateHeader() const
// 6.6 PUSH_PROMISE
if (framePayloadSize < 4)
return FrameStatus::sizeError;
+ break;
default:
// DATA/HEADERS/CONTINUATION will be verified
// when we have payload.
@@ -233,7 +198,8 @@ quint32 Frame::dataSize() const
Q_ASSERT(validatePayload() == FrameStatus::goodFrame);
quint32 size = payloadSize();
- if (const uchar pad = padding()) {
+ if (flags().testFlag(FrameFlag::PADDED)) {
+ const uchar pad = padding();
// + 1 one for a byte with padding number itself:
size -= pad + 1;
}
@@ -269,7 +235,7 @@ const uchar *Frame::dataBegin() const
return nullptr;
const uchar *src = &buffer[0] + frameHeaderSize;
- if (padding())
+ if (flags().testFlag(FrameFlag::PADDED))
++src;
if (priority())
@@ -293,7 +259,7 @@ const uchar *Frame::hpackBlockBegin() const
return begin;
}
-FrameStatus FrameReader::read(QAbstractSocket &socket)
+FrameStatus FrameReader::read(QIODevice &socket)
{
if (offset < frameHeaderSize) {
if (!readHeader(socket))
@@ -321,7 +287,7 @@ FrameStatus FrameReader::read(QAbstractSocket &socket)
return frame.validatePayload();
}
-bool FrameReader::readHeader(QAbstractSocket &socket)
+bool FrameReader::readHeader(QIODevice &socket)
{
Q_ASSERT(offset < frameHeaderSize);
@@ -337,7 +303,7 @@ bool FrameReader::readHeader(QAbstractSocket &socket)
return offset == frameHeaderSize;
}
-bool FrameReader::readPayload(QAbstractSocket &socket)
+bool FrameReader::readPayload(QIODevice &socket)
{
Q_ASSERT(offset < frame.buffer.size());
Q_ASSERT(frame.buffer.size() > frameHeaderSize);
@@ -428,7 +394,7 @@ void FrameWriter::updatePayloadSize()
setPayloadSize(size);
}
-bool FrameWriter::write(QAbstractSocket &socket) const
+bool FrameWriter::write(QIODevice &socket) const
{
auto &buffer = frame.buffer;
Q_ASSERT(buffer.size() >= frameHeaderSize);
@@ -442,7 +408,7 @@ bool FrameWriter::write(QAbstractSocket &socket) const
return nWritten != -1 && size_type(nWritten) == buffer.size();
}
-bool FrameWriter::writeHEADERS(QAbstractSocket &socket, quint32 sizeLimit)
+bool FrameWriter::writeHEADERS(QIODevice &socket, quint32 sizeLimit)
{
auto &buffer = frame.buffer;
Q_ASSERT(buffer.size() >= frameHeaderSize);
@@ -492,7 +458,7 @@ bool FrameWriter::writeHEADERS(QAbstractSocket &socket, quint32 sizeLimit)
return true;
}
-bool FrameWriter::writeDATA(QAbstractSocket &socket, quint32 sizeLimit,
+bool FrameWriter::writeDATA(QIODevice &socket, quint32 sizeLimit,
const uchar *src, quint32 size)
{
// With DATA frame(s) we always have:
diff --git a/src/network/access/http2/http2frames_p.h b/src/network/access/http2/http2frames_p.h
index 4bdc775806..48e3f751b7 100644
--- a/src/network/access/http2/http2frames_p.h
+++ b/src/network/access/http2/http2frames_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef HTTP2FRAMES_P_H
#define HTTP2FRAMES_P_H
@@ -63,7 +27,7 @@
QT_BEGIN_NAMESPACE
class QHttp2ProtocolHandler;
-class QAbstractSocket;
+class QIODevice;
namespace Http2
{
@@ -101,15 +65,15 @@ struct Q_AUTOTEST_EXPORT Frame
class Q_AUTOTEST_EXPORT FrameReader
{
public:
- FrameStatus read(QAbstractSocket &socket);
+ FrameStatus read(QIODevice &socket);
Frame &inboundFrame()
{
return frame;
}
private:
- bool readHeader(QAbstractSocket &socket);
- bool readPayload(QAbstractSocket &socket);
+ bool readHeader(QIODevice &socket);
+ bool readPayload(QIODevice &socket);
quint32 offset = 0;
Frame frame;
@@ -159,20 +123,25 @@ public:
{
append(&payload[0], &payload[0] + payload.size());
}
+ void append(QByteArrayView payload)
+ {
+ append(reinterpret_cast<const uchar *>(payload.begin()),
+ reinterpret_cast<const uchar *>(payload.end()));
+ }
void append(const uchar *begin, const uchar *end);
// Write as a single frame:
- bool write(QAbstractSocket &socket) const;
+ bool write(QIODevice &socket) const;
// Two types of frames we are sending are affected by frame size limits:
// HEADERS and DATA. HEADERS' payload (hpacked HTTP headers, following a
// frame header) is always in our 'buffer', we send the initial HEADERS
// frame first and then CONTINUTATION frame(s) if needed:
- bool writeHEADERS(QAbstractSocket &socket, quint32 sizeLimit);
+ bool writeHEADERS(QIODevice &socket, quint32 sizeLimit);
// With DATA frames the actual payload is never in our 'buffer', it's a
// 'readPointer' from QNonContiguousData. We split this payload as needed
// into DATA frames with correct payload size fitting into frame size limit:
- bool writeDATA(QAbstractSocket &socket, quint32 sizeLimit,
+ bool writeDATA(QIODevice &socket, quint32 sizeLimit,
const uchar *src, quint32 size);
private:
void updatePayloadSize();
diff --git a/src/network/access/http2/http2protocol.cpp b/src/network/access/http2/http2protocol.cpp
index 31da6fd616..8e7e176c41 100644
--- a/src/network/access/http2/http2protocol.cpp
+++ b/src/network/access/http2/http2protocol.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "http2protocol_p.h"
#include "http2frames_p.h"
@@ -50,6 +14,10 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
+QT_IMPL_METATYPE_EXTERN_TAGGED(Http2::Settings, Http2__Settings)
+
Q_LOGGING_CATEGORY(QT_HTTP2, "qt.network.http2")
namespace Http2
@@ -71,9 +39,12 @@ Frame configurationToSettingsFrame(const QHttp2Configuration &config)
// Server push:
builder.append(Settings::ENABLE_PUSH_ID);
builder.append(int(config.serverPushEnabled()));
- // Stream receive window size:
- builder.append(Settings::INITIAL_WINDOW_SIZE_ID);
- builder.append(config.streamReceiveWindowSize());
+
+ // Stream receive window size (if it's a default value, don't include):
+ if (config.streamReceiveWindowSize() != defaultSessionWindowSize) {
+ builder.append(Settings::INITIAL_WINDOW_SIZE_ID);
+ builder.append(config.streamReceiveWindowSize());
+ }
if (config.maxFrameSize() != minPayloadLimit) {
builder.append(Settings::MAX_FRAME_SIZE_ID);
@@ -105,12 +76,10 @@ void appendProtocolUpgradeHeaders(const QHttp2Configuration &config, QHttpNetwor
Q_ASSERT(request);
// RFC 2616, 14.10
// RFC 7540, 3.2
- QByteArray value(request->headerField("Connection"));
+ const QByteArray connectionHeader = request->headerField("Connection");
+ const auto separator = connectionHeader.isEmpty() ? QByteArrayView() : QByteArrayView(", ");
// We _append_ 'Upgrade':
- if (value.size())
- value += ", ";
-
- value += "Upgrade, HTTP2-Settings";
+ QByteArray value = connectionHeader + separator + "Upgrade, HTTP2-Settings";
request->setHeaderField("Connection", value);
// This we just (re)write.
request->setHeaderField("Upgrade", "h2c");
@@ -125,7 +94,7 @@ void qt_error(quint32 errorCode, QNetworkReply::NetworkError &error,
{
if (errorCode > quint32(HTTP_1_1_REQUIRED)) {
error = QNetworkReply::ProtocolFailure;
- errorMessage = QLatin1String("RST_STREAM with unknown error code (%1)");
+ errorMessage = "RST_STREAM with unknown error code (%1)"_L1;
errorMessage = errorMessage.arg(errorCode);
return;
}
@@ -139,61 +108,61 @@ void qt_error(quint32 errorCode, QNetworkReply::NetworkError &error,
break;
case PROTOCOL_ERROR:
error = QNetworkReply::ProtocolFailure;
- errorMessage = QLatin1String("HTTP/2 protocol error");
+ errorMessage = "HTTP/2 protocol error"_L1;
break;
case INTERNAL_ERROR:
error = QNetworkReply::InternalServerError;
- errorMessage = QLatin1String("Internal server error");
+ errorMessage = "Internal server error"_L1;
break;
case FLOW_CONTROL_ERROR:
error = QNetworkReply::ProtocolFailure;
- errorMessage = QLatin1String("Flow control error");
+ errorMessage = "Flow control error"_L1;
break;
case SETTINGS_TIMEOUT:
error = QNetworkReply::TimeoutError;
- errorMessage = QLatin1String("SETTINGS ACK timeout error");
+ errorMessage = "SETTINGS ACK timeout error"_L1;
break;
case STREAM_CLOSED:
error = QNetworkReply::ProtocolFailure;
- errorMessage = QLatin1String("Server received frame(s) on a half-closed stream");
+ errorMessage = "Server received frame(s) on a half-closed stream"_L1;
break;
case FRAME_SIZE_ERROR:
error = QNetworkReply::ProtocolFailure;
- errorMessage = QLatin1String("Server received a frame with an invalid size");
+ errorMessage = "Server received a frame with an invalid size"_L1;
break;
case REFUSE_STREAM:
error = QNetworkReply::ProtocolFailure;
- errorMessage = QLatin1String("Server refused a stream");
+ errorMessage = "Server refused a stream"_L1;
break;
case CANCEL:
error = QNetworkReply::ProtocolFailure;
- errorMessage = QLatin1String("Stream is no longer needed");
+ errorMessage = "Stream is no longer needed"_L1;
break;
case COMPRESSION_ERROR:
error = QNetworkReply::ProtocolFailure;
- errorMessage = QLatin1String("Server is unable to maintain the "
- "header compression context for the connection");
+ errorMessage = "Server is unable to maintain the "
+ "header compression context for the connection"_L1;
break;
case CONNECT_ERROR:
// TODO: in Qt6 we'll have to add more error codes in QNetworkReply.
error = QNetworkReply::UnknownNetworkError;
- errorMessage = QLatin1String("The connection established in response "
- "to a CONNECT request was reset or abnormally closed");
+ errorMessage = "The connection established in response "
+ "to a CONNECT request was reset or abnormally closed"_L1;
break;
case ENHANCE_YOUR_CALM:
error = QNetworkReply::UnknownServerError;
- errorMessage = QLatin1String("Server dislikes our behavior, excessive load detected.");
+ errorMessage = "Server dislikes our behavior, excessive load detected."_L1;
break;
case INADEQUATE_SECURITY:
error = QNetworkReply::ContentAccessDenied;
- errorMessage = QLatin1String("The underlying transport has properties "
- "that do not meet minimum security "
- "requirements");
+ errorMessage = "The underlying transport has properties "
+ "that do not meet minimum security "
+ "requirements"_L1;
break;
case HTTP_1_1_REQUIRED:
error = QNetworkReply::ProtocolFailure;
- errorMessage = QLatin1String("Server requires that HTTP/1.1 "
- "be used instead of HTTP/2.");
+ errorMessage = "Server requires that HTTP/1.1 "
+ "be used instead of HTTP/2."_L1;
}
}
@@ -215,19 +184,45 @@ QNetworkReply::NetworkError qt_error(quint32 errorCode)
bool is_protocol_upgraded(const QHttpNetworkReply &reply)
{
- if (reply.statusCode() == 101) {
- // Do some minimal checks here - we expect 'Upgrade: h2c' to be found.
- const auto &header = reply.header();
- for (const QPair<QByteArray, QByteArray> &field : header) {
- if (field.first.compare("upgrade", Qt::CaseInsensitive) == 0 &&
- field.second.compare("h2c", Qt::CaseInsensitive) == 0)
- return true;
- }
+ if (reply.statusCode() != 101)
+ return false;
+
+ // Do some minimal checks here - we expect 'Upgrade: h2c' to be found.
+ for (const auto &v : reply.header().values(QHttpHeaders::WellKnownHeader::Upgrade)) {
+ if (v.compare("h2c", Qt::CaseInsensitive) == 0)
+ return true;
}
return false;
}
+std::vector<uchar> assemble_hpack_block(const std::vector<Frame> &frames)
+{
+ std::vector<uchar> hpackBlock;
+
+ size_t total = 0;
+ for (const auto &frame : frames) {
+ if (qAddOverflow(total, size_t{frame.hpackBlockSize()}, &total))
+ return hpackBlock;
+ }
+
+ if (!total)
+ return hpackBlock;
+
+ hpackBlock.resize(total);
+ auto dst = hpackBlock.begin();
+ for (const auto &frame : frames) {
+ if (const auto hpackBlockSize = frame.hpackBlockSize()) {
+ const uchar *src = frame.hpackBlockBegin();
+ std::copy(src, src + hpackBlockSize, dst);
+ dst += hpackBlockSize;
+ }
+ }
+
+ return hpackBlock;
+}
+
+
} // namespace Http2
QT_END_NAMESPACE
diff --git a/src/network/access/http2/http2protocol_p.h b/src/network/access/http2/http2protocol_p.h
index b0af5aa919..fb5ff199c5 100644
--- a/src/network/access/http2/http2protocol_p.h
+++ b/src/network/access/http2/http2protocol_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef HTTP2PROTOCOL_P_H
#define HTTP2PROTOCOL_P_H
@@ -54,9 +18,11 @@
#include <QtNetwork/qnetworkreply.h>
#include <QtCore/qloggingcategory.h>
#include <QtCore/qmetatype.h>
-#include <QtCore/qglobal.h>
+#include <QtCore/private/qglobal_p.h>
#include <QtCore/qmap.h>
+#include <vector>
+
// Different HTTP/2 constants/values as defined by RFC 7540.
QT_BEGIN_NAMESPACE
@@ -133,9 +99,6 @@ enum Http2PredefinedParameters
maxPayloadSize = (1 << 24) - 1, // HTTP/2 6.5.2
defaultSessionWindowSize = 65535, // HTTP/2 6.5.2
- // Using 1000 (rather arbitrarily), just to
- // impose *some* upper limit:
- maxPeerConcurrentStreams = 1000,
maxConcurrentStreams = 100 // HTTP/2, 6.5.2
};
@@ -151,11 +114,13 @@ const quint32 lastValidStreamID((quint32(1) << 31) - 1); // HTTP/2, 5.1.1
// HTTP/2 servers are not afraid to immediately set it to the possible max,
// we do the same and split this window size between our concurrent streams.
const qint32 maxSessionReceiveWindowSize((quint32(1) << 31) - 1);
-const qint32 qtDefaultStreamReceiveWindowSize = maxSessionReceiveWindowSize / maxConcurrentStreams;
+// Presumably, we never use up to 100 streams so let it be 10 simultaneous:
+const qint32 qtDefaultStreamReceiveWindowSize = maxSessionReceiveWindowSize / 10;
struct Frame configurationToSettingsFrame(const QHttp2Configuration &configuration);
QByteArray settingsFrameToBase64(const Frame &settingsFrame);
void appendProtocolUpgradeHeaders(const QHttp2Configuration &configuration, QHttpNetworkRequest *request);
+std::vector<uchar> assemble_hpack_block(const std::vector<Frame> &frames);
extern const Q_AUTOTEST_EXPORT char Http2clientPreface[clientPrefaceLength];
@@ -203,6 +168,6 @@ Q_DECLARE_LOGGING_CATEGORY(QT_HTTP2)
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(Http2::Settings)
+QT_DECL_METATYPE_EXTERN_TAGGED(Http2::Settings, Http2__Settings, Q_NETWORK_EXPORT)
#endif
diff --git a/src/network/access/http2/http2streams.cpp b/src/network/access/http2/http2streams.cpp
index fa39c1d57b..3de8b946fe 100644
--- a/src/network/access/http2/http2streams.cpp
+++ b/src/network/access/http2/http2streams.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "http2streams_p.h"
diff --git a/src/network/access/http2/http2streams_p.h b/src/network/access/http2/http2streams_p.h
index 0be6b3b253..e3745cd2d4 100644
--- a/src/network/access/http2/http2streams_p.h
+++ b/src/network/access/http2/http2streams_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef HTTP2STREAMS_P_H
#define HTTP2STREAMS_P_H
diff --git a/src/network/access/http2/huffman.cpp b/src/network/access/http2/huffman.cpp
index 3cc6f9f01e..e957c3311a 100644
--- a/src/network/access/http2/huffman.cpp
+++ b/src/network/access/http2/huffman.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "bitstreams_p.h"
#include "huffman_p.h"
@@ -78,7 +42,7 @@ namespace HPack
...
[00001 | 4 remaining bits]
- All entires with indices between these two will 'point' to value 48
+ All entries with indices between these two will 'point' to value 48
with bitLength == 5 so that bit stream (for example) 000001010 will be
decoded as: 48 + "put 1010 back into bitstream".
@@ -381,7 +345,7 @@ void write_huffman_code(BitOStream &outputStream, const CodeEntry &code)
// That's from HPACK's specs - we deal with octets.
static_assert(std::numeric_limits<uchar>::digits == 8, "octets expected");
-quint64 huffman_encoded_bit_length(const QByteArray &inputData)
+quint64 huffman_encoded_bit_length(QByteArrayView inputData)
{
quint64 bitLength = 0;
for (int i = 0, e = inputData.size(); i < e; ++i)
@@ -390,7 +354,7 @@ quint64 huffman_encoded_bit_length(const QByteArray &inputData)
return bitLength;
}
-void huffman_encode_string(const QByteArray &inputData, BitOStream &outputStream)
+void huffman_encode_string(QByteArrayView inputData, BitOStream &outputStream)
{
for (int i = 0, e = inputData.size(); i < e; ++i) {
const auto value = uchar(inputData[i]);
@@ -402,6 +366,7 @@ void huffman_encode_string(const QByteArray &inputData, BitOStream &outputStream
outputStream.writeBits(0xff, 8 - outputStream.bitLength() % 8);
}
+static constexpr
bool padding_is_valid(quint32 chunk, quint32 nBits)
{
Q_ASSERT(nBits);
diff --git a/src/network/access/http2/huffman_p.h b/src/network/access/http2/huffman_p.h
index c5324d42b1..daa2b31bb3 100644
--- a/src/network/access/http2/huffman_p.h
+++ b/src/network/access/http2/huffman_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef HUFFMAN_P_H
#define HUFFMAN_P_H
@@ -51,7 +15,7 @@
// We mean it.
//
-#include <QtCore/qglobal.h>
+#include <QtCore/private/qglobal_p.h>
QT_BEGIN_NAMESPACE
@@ -69,8 +33,8 @@ struct CodeEntry
class BitOStream;
-quint64 huffman_encoded_bit_length(const QByteArray &inputData);
-void huffman_encode_string(const QByteArray &inputData, BitOStream &outputStream);
+quint64 huffman_encoded_bit_length(QByteArrayView inputData);
+void huffman_encode_string(QByteArrayView inputData, BitOStream &outputStream);
// PrefixTable:
// Huffman codes with a small bit length
diff --git a/src/network/access/qabstractnetworkcache.cpp b/src/network/access/qabstractnetworkcache.cpp
index 4e217294c4..c8b940d801 100644
--- a/src/network/access/qabstractnetworkcache.cpp
+++ b/src/network/access/qabstractnetworkcache.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qabstractnetworkcache.h"
#include "qabstractnetworkcache_p.h"
@@ -43,6 +7,7 @@
#include <qdatastream.h>
#include <qdatetime.h>
#include <qurl.h>
+#include <qhash.h>
#include <qdebug.h>
@@ -232,9 +197,10 @@ QUrl QNetworkCacheMetaData::url() const
*/
void QNetworkCacheMetaData::setUrl(const QUrl &url)
{
- d->url = url;
- d->url.setPassword(QString());
- d->url.setFragment(QString());
+ auto *p = d.data();
+ p->url = url;
+ p->url.setPassword(QString());
+ p->url.setFragment(QString());
}
/*!
@@ -395,12 +361,13 @@ static inline QDataStream &operator>>(QDataStream &in, QNetworkCacheMetaData::At
void QNetworkCacheMetaDataPrivate::load(QDataStream &in, QNetworkCacheMetaData &metaData)
{
- in >> metaData.d->url;
- in >> metaData.d->expirationDate;
- in >> metaData.d->lastModified;
- in >> metaData.d->saveToDisk;
- in >> metaData.d->attributes;
- in >> metaData.d->headers;
+ auto *p = metaData.d.data();
+ in >> p->url;
+ in >> p->expirationDate;
+ in >> p->lastModified;
+ in >> p->saveToDisk;
+ in >> p->attributes;
+ in >> p->headers;
}
/*!
@@ -542,3 +509,5 @@ QAbstractNetworkCache::~QAbstractNetworkCache()
*/
QT_END_NAMESPACE
+
+#include "moc_qabstractnetworkcache.cpp"
diff --git a/src/network/access/qabstractnetworkcache.h b/src/network/access/qabstractnetworkcache.h
index a4048c5b8f..c70dcf737c 100644
--- a/src/network/access/qabstractnetworkcache.h
+++ b/src/network/access/qabstractnetworkcache.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QABSTRACTNETWORKCACHE_H
#define QABSTRACTNETWORKCACHE_H
@@ -70,7 +34,7 @@ public:
QNetworkCacheMetaData &operator=(const QNetworkCacheMetaData &other);
void swap(QNetworkCacheMetaData &other) noexcept
- { qSwap(d, other.d); }
+ { d.swap(other.d); }
bool operator==(const QNetworkCacheMetaData &other) const;
inline bool operator!=(const QNetworkCacheMetaData &other) const
diff --git a/src/network/access/qabstractnetworkcache_p.h b/src/network/access/qabstractnetworkcache_p.h
index fee723e315..625cfcb1c3 100644
--- a/src/network/access/qabstractnetworkcache_p.h
+++ b/src/network/access/qabstractnetworkcache_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QABSTRACTNETWORKCACHE_P_H
#define QABSTRACTNETWORKCACHE_P_H
diff --git a/src/network/access/qabstractprotocolhandler.cpp b/src/network/access/qabstractprotocolhandler.cpp
index 6847816ba7..5e5019901c 100644
--- a/src/network/access/qabstractprotocolhandler.cpp
+++ b/src/network/access/qabstractprotocolhandler.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2014 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <private/qabstractprotocolhandler_p.h>
#include <private/qhttpnetworkconnectionchannel_p.h>
diff --git a/src/network/access/qabstractprotocolhandler_p.h b/src/network/access/qabstractprotocolhandler_p.h
index 04a07734dd..ad82aae66e 100644
--- a/src/network/access/qabstractprotocolhandler_p.h
+++ b/src/network/access/qabstractprotocolhandler_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2014 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QABSTRACTPROTOCOLHANDLER_H
#define QABSTRACTPROTOCOLHANDLER_H
diff --git a/src/network/access/qdecompresshelper.cpp b/src/network/access/qdecompresshelper.cpp
index 981153a852..52a0d9fc06 100644
--- a/src/network/access/qdecompresshelper.cpp
+++ b/src/network/access/qdecompresshelper.cpp
@@ -1,47 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdecompresshelper_p.h"
-#include <QtCore/private/qbytearray_p.h>
#include <QtCore/qiodevice.h>
+#include <QtCore/qcoreapplication.h>
+#include <limits>
#include <zlib.h>
#if QT_CONFIG(brotli)
@@ -58,7 +23,7 @@ QT_BEGIN_NAMESPACE
namespace {
struct ContentEncodingMapping
{
- char name[8];
+ QByteArrayView name;
QDecompressHelper::ContentEncoding encoding;
};
@@ -73,10 +38,10 @@ constexpr ContentEncodingMapping contentEncodingMapping[] {
{ "deflate", QDecompressHelper::Deflate },
};
-QDecompressHelper::ContentEncoding encodingFromByteArray(const QByteArray &ce) noexcept
+QDecompressHelper::ContentEncoding encodingFromByteArray(QByteArrayView ce) noexcept
{
for (const auto &mapping : contentEncodingMapping) {
- if (ce.compare(QByteArrayView(mapping.name, strlen(mapping.name)), Qt::CaseInsensitive) == 0)
+ if (ce.compare(mapping.name, Qt::CaseInsensitive) == 0)
return mapping.encoding;
}
return QDecompressHelper::None;
@@ -102,22 +67,19 @@ ZSTD_DStream *toZstandardPointer(void *ptr)
#endif
}
-bool QDecompressHelper::isSupportedEncoding(const QByteArray &encoding)
+bool QDecompressHelper::isSupportedEncoding(QByteArrayView encoding)
{
return encodingFromByteArray(encoding) != QDecompressHelper::None;
}
QByteArrayList QDecompressHelper::acceptedEncoding()
{
- static QByteArrayList accepted = []() {
- QByteArrayList list;
- list.reserve(sizeof(contentEncodingMapping) / sizeof(contentEncodingMapping[0]));
- for (const auto &mapping : contentEncodingMapping) {
- list << QByteArray(mapping.name);
- }
- return list;
- }();
- return accepted;
+ QByteArrayList list;
+ list.reserve(std::size(contentEncodingMapping));
+ for (const auto &mapping : contentEncodingMapping) {
+ list << mapping.name.toByteArray();
+ }
+ return list;
}
QDecompressHelper::~QDecompressHelper()
@@ -125,18 +87,21 @@ QDecompressHelper::~QDecompressHelper()
clear();
}
-bool QDecompressHelper::setEncoding(const QByteArray &encoding)
+bool QDecompressHelper::setEncoding(QByteArrayView encoding)
{
Q_ASSERT(contentEncoding == QDecompressHelper::None);
if (contentEncoding != QDecompressHelper::None) {
qWarning("Encoding is already set.");
+ // This isn't an error, so it doesn't set errorStr, it's just wrong usage.
return false;
}
ContentEncoding ce = encodingFromByteArray(encoding);
if (ce == None) {
- qWarning("An unsupported content encoding was selected: %s", encoding.data());
+ errorStr = QCoreApplication::translate("QHttp", "Unsupported content encoding: %1")
+ .arg(QLatin1String(encoding));
return false;
}
+ errorStr = QString(); // clear error
return setEncoding(ce);
}
@@ -178,7 +143,8 @@ bool QDecompressHelper::setEncoding(ContentEncoding ce)
break;
}
if (!decoderPointer) {
- qWarning("Failed to initialize the decoder.");
+ errorStr = QCoreApplication::translate("QHttp",
+ "Failed to initialize the compression decoder.");
contentEncoding = QDecompressHelper::None;
return false;
}
@@ -236,7 +202,13 @@ void QDecompressHelper::setCountingBytesEnabled(bool shouldCount)
qint64 QDecompressHelper::uncompressedSize() const
{
Q_ASSERT(countDecompressed);
- return uncompressedBytes;
+ // Use the 'totalUncompressedBytes' from the countHelper if it exceeds the amount of bytes
+ // that we know about.
+ auto totalUncompressed =
+ countHelper && countHelper->totalUncompressedBytes > totalUncompressedBytes
+ ? countHelper->totalUncompressedBytes
+ : totalUncompressedBytes;
+ return totalUncompressed - totalBytesRead;
}
/*!
@@ -261,10 +233,9 @@ void QDecompressHelper::feed(QByteArray &&data)
{
Q_ASSERT(contentEncoding != None);
totalCompressedBytes += data.size();
- if (!countInternal(data))
+ compressedDataBuffer.append(std::move(data));
+ if (!countInternal(compressedDataBuffer[compressedDataBuffer.bufferCount() - 1]))
clear(); // If our counting brother failed then so will we :|
- else
- compressedDataBuffer.append(std::move(data));
}
/*!
@@ -275,10 +246,9 @@ void QDecompressHelper::feed(const QByteDataBuffer &buffer)
{
Q_ASSERT(contentEncoding != None);
totalCompressedBytes += buffer.byteAmount();
+ compressedDataBuffer.append(buffer);
if (!countInternal(buffer))
clear(); // If our counting brother failed then so will we :|
- else
- compressedDataBuffer.append(buffer);
}
/*!
@@ -289,10 +259,10 @@ void QDecompressHelper::feed(QByteDataBuffer &&buffer)
{
Q_ASSERT(contentEncoding != None);
totalCompressedBytes += buffer.byteAmount();
- if (!countInternal(buffer))
+ const QByteDataBuffer copy(buffer);
+ compressedDataBuffer.append(std::move(buffer));
+ if (!countInternal(copy))
clear(); // If our counting brother failed then so will we :|
- else
- compressedDataBuffer.append(std::move(buffer));
}
/*!
@@ -302,19 +272,34 @@ void QDecompressHelper::feed(QByteDataBuffer &&buffer)
This lets us know the final size, unfortunately at the cost of
increased computation.
- Potential @future improvement:
- Decompress XX MiB/KiB before starting the count.
- For smaller files the extra decompression can then be avoided.
+ To save on some of the computation we will store the data until
+ we reach \c MaxDecompressedDataBufferSize stored. In this case the
+ "penalty" is completely removed from users who read the data on
+ readyRead rather than waiting for it all to be received. And
+ any file smaller than \c MaxDecompressedDataBufferSize will
+ avoid this issue as well.
*/
bool QDecompressHelper::countInternal()
{
Q_ASSERT(countDecompressed);
+ while (hasDataInternal()
+ && decompressedDataBuffer.byteAmount() < MaxDecompressedDataBufferSize) {
+ const qsizetype toRead = 256 * 1024;
+ QByteArray buffer(toRead, Qt::Uninitialized);
+ qsizetype bytesRead = readInternal(buffer.data(), buffer.size());
+ if (bytesRead == -1)
+ return false;
+ buffer.truncate(bytesRead);
+ decompressedDataBuffer.append(std::move(buffer));
+ }
+ if (!hasDataInternal())
+ return true; // handled all the data so far, just return
+
while (countHelper->hasData()) {
std::array<char, 1024> temp;
qsizetype bytesRead = countHelper->read(temp.data(), temp.size());
if (bytesRead == -1)
return false;
- uncompressedBytes += bytesRead;
}
return true;
}
@@ -328,7 +313,7 @@ bool QDecompressHelper::countInternal(const QByteArray &data)
if (countDecompressed) {
if (!countHelper) {
countHelper = std::make_unique<QDecompressHelper>();
- countHelper->setArchiveBombDetectionEnabled(archiveBombDetectionEnabled);
+ countHelper->setDecompressedSafetyCheckThreshold(archiveBombCheckThreshold);
countHelper->setEncoding(contentEncoding);
}
countHelper->feed(data);
@@ -346,7 +331,7 @@ bool QDecompressHelper::countInternal(const QByteDataBuffer &buffer)
if (countDecompressed) {
if (!countHelper) {
countHelper = std::make_unique<QDecompressHelper>();
- countHelper->setArchiveBombDetectionEnabled(archiveBombDetectionEnabled);
+ countHelper->setDecompressedSafetyCheckThreshold(archiveBombCheckThreshold);
countHelper->setEncoding(contentEncoding);
}
countHelper->feed(buffer);
@@ -357,13 +342,45 @@ bool QDecompressHelper::countInternal(const QByteDataBuffer &buffer)
qsizetype QDecompressHelper::read(char *data, qsizetype maxSize)
{
+ if (maxSize <= 0)
+ return 0;
+
if (!isValid())
return -1;
- qsizetype bytesRead = -1;
if (!hasData())
return 0;
+ qsizetype cachedRead = 0;
+ if (!decompressedDataBuffer.isEmpty()) {
+ cachedRead = decompressedDataBuffer.read(data, maxSize);
+ data += cachedRead;
+ maxSize -= cachedRead;
+ }
+
+ qsizetype bytesRead = readInternal(data, maxSize);
+ if (bytesRead == -1)
+ return -1;
+ totalBytesRead += bytesRead + cachedRead;
+ return bytesRead + cachedRead;
+}
+
+/*!
+ \internal
+ Like read() but without attempting to read the
+ cached/already-decompressed data.
+*/
+qsizetype QDecompressHelper::readInternal(char *data, qsizetype maxSize)
+{
+ Q_ASSERT(isValid());
+
+ if (maxSize <= 0)
+ return 0;
+
+ if (!hasDataInternal())
+ return 0;
+
+ qsizetype bytesRead = -1;
switch (contentEncoding) {
case None:
Q_UNREACHABLE();
@@ -381,36 +398,38 @@ qsizetype QDecompressHelper::read(char *data, qsizetype maxSize)
}
if (bytesRead == -1)
clear();
- else if (countDecompressed)
- uncompressedBytes -= bytesRead;
totalUncompressedBytes += bytesRead;
- if (isPotentialArchiveBomb())
+ if (isPotentialArchiveBomb()) {
+ errorStr = QCoreApplication::translate(
+ "QHttp",
+ "The decompressed output exceeds the limits specified by "
+ "QNetworkRequest::decompressedSafetyCheckThreshold()");
return -1;
+ }
return bytesRead;
}
/*!
\internal
- Disables or enables checking the decompression ratio of archives
- according to the value of \a enable.
- Only for enabling us to test handling of large decompressed files
- without needing to bundle large compressed files.
+ Set the \a threshold required before the archive bomb detection kicks in.
+ By default this is 10MB. Setting it to -1 is treated as disabling the
+ feature.
*/
-void QDecompressHelper::setArchiveBombDetectionEnabled(bool enable)
+void QDecompressHelper::setDecompressedSafetyCheckThreshold(qint64 threshold)
{
- archiveBombDetectionEnabled = enable;
- if (countHelper)
- countHelper->setArchiveBombDetectionEnabled(enable);
+ if (threshold == -1)
+ threshold = std::numeric_limits<qint64>::max();
+ archiveBombCheckThreshold = threshold;
}
bool QDecompressHelper::isPotentialArchiveBomb() const
{
- if (!archiveBombDetectionEnabled)
+ if (totalCompressedBytes == 0)
return false;
- if (totalCompressedBytes == 0)
+ if (totalUncompressedBytes <= archiveBombCheckThreshold)
return false;
// Some protection against malicious or corrupted compressed files that expand far more than
@@ -422,12 +441,16 @@ bool QDecompressHelper::isPotentialArchiveBomb() const
break;
case Deflate:
case GZip:
+ // This value is mentioned in docs for
+ // QNetworkRequest::setMinimumArchiveBombSize, keep synchronized
if (ratio > 40) {
return true;
}
break;
case Brotli:
case Zstandard:
+ // This value is mentioned in docs for
+ // QNetworkRequest::setMinimumArchiveBombSize, keep synchronized
if (ratio > 100) {
return true;
}
@@ -446,6 +469,16 @@ bool QDecompressHelper::isPotentialArchiveBomb() const
*/
bool QDecompressHelper::hasData() const
{
+ return hasDataInternal() || !decompressedDataBuffer.isEmpty();
+}
+
+/*!
+ \internal
+ Like hasData() but internally the buffer of decompressed data is
+ not interesting.
+*/
+bool QDecompressHelper::hasDataInternal() const
+{
return encodedBytesAvailable() || decoderHasData;
}
@@ -454,11 +487,29 @@ qint64 QDecompressHelper::encodedBytesAvailable() const
return compressedDataBuffer.byteAmount();
}
+/*!
+ \internal
+ Returns whether or not the object is valid.
+ If it becomes invalid after an operation has been performed
+ then an error has occurred.
+ \sa errorString()
+*/
bool QDecompressHelper::isValid() const
{
return contentEncoding != None;
}
+/*!
+ \internal
+ Returns a string describing the error that occurred or an empty
+ string if no error occurred.
+ \sa isValid()
+*/
+QString QDecompressHelper::errorString() const
+{
+ return errorStr;
+}
+
void QDecompressHelper::clear()
{
switch (contentEncoding) {
@@ -493,13 +544,16 @@ void QDecompressHelper::clear()
contentEncoding = None;
compressedDataBuffer.clear();
+ decompressedDataBuffer.clear();
decoderHasData = false;
countDecompressed = false;
countHelper.reset();
- uncompressedBytes = 0;
+ totalBytesRead = 0;
totalUncompressedBytes = 0;
totalCompressedBytes = 0;
+
+ errorStr.clear();
}
qsizetype QDecompressHelper::readZLib(char *data, const qsizetype maxSize)
@@ -510,16 +564,12 @@ qsizetype QDecompressHelper::readZLib(char *data, const qsizetype maxSize)
static const size_t zlibMaxSize =
size_t(std::numeric_limits<decltype(inflateStream->avail_in)>::max());
- QByteArray input;
- if (!compressedDataBuffer.isEmpty()) {
- if (zlibMaxSize < size_t(compressedDataBuffer.sizeNextBlock()))
- input = compressedDataBuffer.read(zlibMaxSize);
- else
- input = compressedDataBuffer.read();
- }
+ QByteArrayView input = compressedDataBuffer.readPointer();
+ if (size_t(input.size()) > zlibMaxSize)
+ input = input.sliced(zlibMaxSize);
inflateStream->avail_in = input.size();
- inflateStream->next_in = reinterpret_cast<Bytef *>(input.data());
+ inflateStream->next_in = reinterpret_cast<Bytef *>(const_cast<char *>(input.data()));
bool bigMaxSize = (zlibMaxSize < size_t(maxSize));
qsizetype adjustedAvailableOut = bigMaxSize ? qsizetype(zlibMaxSize) : maxSize;
@@ -547,7 +597,8 @@ qsizetype QDecompressHelper::readZLib(char *data, const qsizetype maxSize)
return -1;
} else {
inflateStream->avail_in = input.size();
- inflateStream->next_in = reinterpret_cast<Bytef *>(input.data());
+ inflateStream->next_in =
+ reinterpret_cast<Bytef *>(const_cast<char *>(input.data()));
continue;
}
} else if (ret < 0 || ret == Z_NEED_DICT) {
@@ -569,6 +620,7 @@ qsizetype QDecompressHelper::readZLib(char *data, const qsizetype maxSize)
delete inflateStream;
decoderPointer = nullptr;
// Failed to reinitialize, so we'll just return what we have
+ compressedDataBuffer.advanceReadPointer(input.size() - avail_in);
return bytesDecoded;
} else {
inflateStream->next_in = next_in;
@@ -577,6 +629,7 @@ qsizetype QDecompressHelper::readZLib(char *data, const qsizetype maxSize)
}
} else {
// No extra data, stream is at the end. We're done.
+ compressedDataBuffer.advanceReadPointer(input.size());
return bytesDecoded;
}
}
@@ -589,23 +642,19 @@ qsizetype QDecompressHelper::readZLib(char *data, const qsizetype maxSize)
inflateStream->next_out = reinterpret_cast<Bytef *>(data + bytesDecoded);
}
- if (inflateStream->avail_in == 0 && inflateStream->avail_out > 0
- && !compressedDataBuffer.isEmpty()) {
+ if (inflateStream->avail_in == 0 && inflateStream->avail_out > 0) {
// Grab the next input!
- if (zlibMaxSize < size_t(compressedDataBuffer.sizeNextBlock()))
- input = compressedDataBuffer.read(zlibMaxSize);
- else
- input = compressedDataBuffer.read();
+ compressedDataBuffer.advanceReadPointer(input.size());
+ input = compressedDataBuffer.readPointer();
+ if (size_t(input.size()) > zlibMaxSize)
+ input = input.sliced(zlibMaxSize);
inflateStream->avail_in = input.size();
- inflateStream->next_in = reinterpret_cast<Bytef *>(input.data());
+ inflateStream->next_in =
+ reinterpret_cast<Bytef *>(const_cast<char *>(input.data()));
}
} while (inflateStream->avail_out > 0 && inflateStream->avail_in > 0);
- if (inflateStream->avail_in) {
- // Some input was left unused; move back to the buffer
- input = input.right(inflateStream->avail_in);
- compressedDataBuffer.prepend(input);
- }
+ compressedDataBuffer.advanceReadPointer(input.size() - inflateStream->avail_in);
return bytesDecoded;
}
@@ -645,10 +694,8 @@ qsizetype QDecompressHelper::readBrotli(char *data, const qsizetype maxSize)
return bytesDecoded;
Q_ASSERT(bytesDecoded < maxSize);
- QByteArray input;
- if (!compressedDataBuffer.isEmpty())
- input = compressedDataBuffer.read();
- const uint8_t *encodedPtr = reinterpret_cast<const uint8_t *>(input.constData());
+ QByteArrayView input = compressedDataBuffer.readPointer();
+ const uint8_t *encodedPtr = reinterpret_cast<const uint8_t *>(input.data());
size_t encodedBytesRemaining = input.size();
uint8_t *decodedPtr = reinterpret_cast<uint8_t *>(data + bytesDecoded);
@@ -662,16 +709,19 @@ qsizetype QDecompressHelper::readBrotli(char *data, const qsizetype maxSize)
switch (result) {
case BROTLI_DECODER_RESULT_ERROR:
- qWarning("Brotli error: %s",
- BrotliDecoderErrorString(BrotliDecoderGetErrorCode(brotliDecoderState)));
+ errorStr = QLatin1String("Brotli error: %1")
+ .arg(QString::fromUtf8(BrotliDecoderErrorString(
+ BrotliDecoderGetErrorCode(brotliDecoderState))));
return -1;
case BROTLI_DECODER_RESULT_SUCCESS:
BrotliDecoderDestroyInstance(brotliDecoderState);
decoderPointer = nullptr;
+ compressedDataBuffer.clear();
return bytesDecoded;
case BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT:
- if (!compressedDataBuffer.isEmpty()) {
- input = compressedDataBuffer.read();
+ compressedDataBuffer.advanceReadPointer(input.size());
+ input = compressedDataBuffer.readPointer();
+ if (!input.isEmpty()) {
encodedPtr = reinterpret_cast<const uint8_t *>(input.constData());
encodedBytesRemaining = input.size();
break;
@@ -684,11 +734,7 @@ qsizetype QDecompressHelper::readBrotli(char *data, const qsizetype maxSize)
break;
}
}
- if (encodedBytesRemaining) {
- // Some input was left unused; move back to the buffer
- input = input.right(QByteArray::size_type(encodedBytesRemaining));
- compressedDataBuffer.prepend(input);
- }
+ compressedDataBuffer.advanceReadPointer(input.size() - encodedBytesRemaining);
return bytesDecoded;
#endif
}
@@ -702,10 +748,8 @@ qsizetype QDecompressHelper::readZstandard(char *data, const qsizetype maxSize)
#else
ZSTD_DStream *zstdStream = toZstandardPointer(decoderPointer);
- QByteArray input;
- if (!compressedDataBuffer.isEmpty())
- input = compressedDataBuffer.read();
- ZSTD_inBuffer inBuf { input.constData(), size_t(input.size()), 0 };
+ QByteArrayView input = compressedDataBuffer.readPointer();
+ ZSTD_inBuffer inBuf { input.data(), size_t(input.size()), 0 };
ZSTD_outBuffer outBuf { data, size_t(maxSize), 0 };
@@ -713,7 +757,8 @@ qsizetype QDecompressHelper::readZstandard(char *data, const qsizetype maxSize)
while (outBuf.pos < outBuf.size && (inBuf.pos < inBuf.size || decoderHasData)) {
size_t retValue = ZSTD_decompressStream(zstdStream, &outBuf, &inBuf);
if (ZSTD_isError(retValue)) {
- qWarning("ZStandard error: %s", ZSTD_getErrorName(retValue));
+ errorStr = QLatin1String("ZStandard error: %1")
+ .arg(QString::fromUtf8(ZSTD_getErrorName(retValue)));
return -1;
} else {
decoderHasData = false;
@@ -721,17 +766,14 @@ qsizetype QDecompressHelper::readZstandard(char *data, const qsizetype maxSize)
// if pos == size then there may be data left over in internal buffers
if (outBuf.pos == outBuf.size) {
decoderHasData = true;
- } else if (inBuf.pos == inBuf.size && !compressedDataBuffer.isEmpty()) {
- input = compressedDataBuffer.read();
+ } else if (inBuf.pos == inBuf.size) {
+ compressedDataBuffer.advanceReadPointer(input.size());
+ input = compressedDataBuffer.readPointer();
inBuf = { input.constData(), size_t(input.size()), 0 };
}
}
}
- if (inBuf.pos < inBuf.size) {
- // Some input was left unused; move back to the buffer
- input = input.mid(QByteArray::size_type(inBuf.pos));
- compressedDataBuffer.prepend(std::move(input));
- }
+ compressedDataBuffer.advanceReadPointer(inBuf.pos);
return bytesDecoded;
#endif
}
diff --git a/src/network/access/qdecompresshelper_p.h b/src/network/access/qdecompresshelper_p.h
index 4e66581022..c837c14521 100644
--- a/src/network/access/qdecompresshelper_p.h
+++ b/src/network/access/qdecompresshelper_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef DECOMPRESS_HELPER_P_H
#define DECOMPRESS_HELPER_P_H
@@ -73,7 +37,7 @@ public:
QDecompressHelper() = default;
~QDecompressHelper();
- bool setEncoding(const QByteArray &contentEncoding);
+ bool setEncoding(QByteArrayView contentEncoding);
bool isCountingBytes() const;
void setCountingBytesEnabled(bool shouldCount);
@@ -91,13 +55,17 @@ public:
void clear();
- void setArchiveBombDetectionEnabled(bool enable);
+ void setDecompressedSafetyCheckThreshold(qint64 threshold);
- static bool isSupportedEncoding(const QByteArray &encoding);
+ static bool isSupportedEncoding(QByteArrayView encoding);
static QByteArrayList acceptedEncoding();
+ QString errorString() const;
+
private:
bool isPotentialArchiveBomb() const;
+ bool hasDataInternal() const;
+ qsizetype readInternal(char *data, qsizetype maxSize);
bool countInternal();
bool countInternal(const QByteArray &data);
@@ -111,16 +79,20 @@ private:
qsizetype readZstandard(char *data, qsizetype maxSize);
QByteDataBuffer compressedDataBuffer;
+ QByteDataBuffer decompressedDataBuffer;
+ const qsizetype MaxDecompressedDataBufferSize = 10 * 1024 * 1024;
bool decoderHasData = false;
bool countDecompressed = false;
std::unique_ptr<QDecompressHelper> countHelper;
- qint64 uncompressedBytes = 0;
+
+ QString errorStr;
// Used for calculating the ratio
- bool archiveBombDetectionEnabled = true;
+ qint64 archiveBombCheckThreshold = 10 * 1024 * 1024;
qint64 totalUncompressedBytes = 0;
qint64 totalCompressedBytes = 0;
+ qint64 totalBytesRead = 0;
ContentEncoding contentEncoding = None;
diff --git a/src/network/access/qhsts.cpp b/src/network/access/qhsts.cpp
index 99c4c605dd..21ed08ce4a 100644
--- a/src/network/access/qhsts.cpp
+++ b/src/network/access/qhsts.cpp
@@ -1,44 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qhsts_p.h"
+#include "qhttpheaders.h"
+
#include "QtCore/private/qipaddress_p.h"
#include "QtCore/qlist.h"
@@ -76,7 +42,7 @@ static bool is_valid_domain_name(const QString &host)
return true;
}
-void QHstsCache::updateFromHeaders(const QList<QPair<QByteArray, QByteArray>> &headers,
+void QHstsCache::updateFromHeaders(const QHttpHeaders &headers,
const QUrl &url)
{
if (!url.isValid())
@@ -210,7 +176,7 @@ bool QHstsCache::isKnownHost(const QUrl &url) const
}
}
- const int dot = nameToTest.fragment.indexOf(QLatin1Char('.'));
+ const qsizetype dot = nameToTest.fragment.indexOf(u'.');
if (dot == -1)
break;
@@ -322,7 +288,7 @@ static bool isSeparator(char c)
return isLWS(c) || std::find(separators, end, c) != end;
}
-static QByteArray unescapeMaxAge(const QByteArray &value)
+static QByteArrayView unescapeMaxAge(QByteArrayView value)
{
if (value.size() < 2 || value[0] != '"')
return value;
@@ -360,27 +326,25 @@ quoted-pair = "\" CHAR
*/
-bool QHstsHeaderParser::parse(const QList<QPair<QByteArray, QByteArray>> &headers)
+bool QHstsHeaderParser::parse(const QHttpHeaders &headers)
{
- for (const auto &h : headers) {
- // We use '==' since header name was already 'trimmed' for us:
- if (h.first == "Strict-Transport-Security") {
- header = h.second;
- // RFC6797, 8.1:
- //
- // The UA MUST ignore any STS header fields not conforming to the
- // grammar specified in Section 6.1 ("Strict-Transport-Security HTTP
- // Response Header Field").
- //
- // If a UA receives more than one STS header field in an HTTP
- // response message over secure transport, then the UA MUST process
- // only the first such header field.
- //
- // We read this as: ignore all invalid headers and take the first valid:
- if (parseSTSHeader() && maxAgeFound) {
- expiry = QDateTime::currentDateTimeUtc().addSecs(maxAge);
- return true;
- }
+ for (const auto &value : headers.values(
+ QHttpHeaders::WellKnownHeader::StrictTransportSecurity)) {
+ header = value;
+ // RFC6797, 8.1:
+ //
+ // The UA MUST ignore any STS header fields not conforming to the
+ // grammar specified in Section 6.1 ("Strict-Transport-Security HTTP
+ // Response Header Field").
+ //
+ // If a UA receives more than one STS header field in an HTTP
+ // response message over secure transport, then the UA MUST process
+ // only the first such header field.
+ //
+ // We read this as: ignore all invalid headers and take the first valid:
+ if (parseSTSHeader() && maxAgeFound) {
+ expiry = QDateTime::currentDateTimeUtc().addSecs(maxAge);
+ return true;
}
}
@@ -436,7 +400,7 @@ bool QHstsHeaderParser::parseDirective()
if (token == ";") // That's a weird grammar, but that's what it is.
return true;
- if (!isTOKEN(token[0])) // Not a valid directive-name.
+ if (!isTOKEN(token.at(0))) // Not a valid directive-name.
return false;
const QByteArray directiveName = token;
@@ -481,7 +445,7 @@ bool QHstsHeaderParser::processDirective(const QByteArray &name, const QByteArra
return false;
}
- const QByteArray unescapedValue = unescapeMaxAge(value);
+ const QByteArrayView unescapedValue = unescapeMaxAge(value);
if (!unescapedValue.size())
return false;
@@ -517,13 +481,13 @@ bool QHstsHeaderParser::nextToken()
// Fortunately enough, by this point qhttpnetworkreply already got rid of
// [CRLF] parts, but we can have 1*(SP|HT) yet.
- while (tokenPos < header.size() && isLWS(header[tokenPos]))
+ while (tokenPos < header.size() && isLWS(header.at(tokenPos)))
++tokenPos;
if (tokenPos == header.size())
return true;
- const char ch = header[tokenPos];
+ const char ch = header.at(tokenPos);
if (ch == ';' || ch == '=') {
token.append(ch);
++tokenPos;
@@ -537,17 +501,17 @@ bool QHstsHeaderParser::nextToken()
if (ch == '"') {
int last = tokenPos + 1;
while (last < header.size()) {
- if (header[last] == '"') {
+ if (header.at(last) == '"') {
// The end of a quoted-string.
break;
- } else if (header[last] == '\\') {
+ } else if (header.at(last) == '\\') {
// quoted-pair = "\" CHAR
- if (last + 1 < header.size() && isCHAR(header[last + 1]))
+ if (last + 1 < header.size() && isCHAR(header.at(last + 1)))
last += 2;
else
return false;
} else {
- if (!isTEXT(header[last]))
+ if (!isTEXT(header.at(last)))
return false;
++last;
}
@@ -568,7 +532,7 @@ bool QHstsHeaderParser::nextToken()
return false;
int last = tokenPos + 1;
- while (last < header.size() && isTOKEN(header[last]))
+ while (last < header.size() && isTOKEN(header.at(last)))
++last;
token = header.mid(tokenPos, last - tokenPos);
diff --git a/src/network/access/qhsts_p.h b/src/network/access/qhsts_p.h
index ea9769ac6c..ff9378197b 100644
--- a/src/network/access/qhsts_p.h
+++ b/src/network/access/qhsts_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QHSTS_P_H
#define QHSTS_P_H
@@ -67,11 +31,13 @@
QT_BEGIN_NAMESPACE
+class QHttpHeaders;
+
class Q_AUTOTEST_EXPORT QHstsCache
{
public:
- void updateFromHeaders(const QList<QPair<QByteArray, QByteArray>> &headers,
+ void updateFromHeaders(const QHttpHeaders &headers,
const QUrl &url);
void updateFromPolicies(const QList<QHstsPolicy> &hosts);
void updateKnownHost(const QUrl &url, const QDateTime &expires,
@@ -126,7 +92,7 @@ class Q_AUTOTEST_EXPORT QHstsHeaderParser
{
public:
- bool parse(const QList<QPair<QByteArray, QByteArray>> &headers);
+ bool parse(const QHttpHeaders &headers);
QDateTime expirationDate() const { return expiry; }
bool includeSubDomains() const { return subDomainsFound; }
diff --git a/src/network/access/qhstspolicy.cpp b/src/network/access/qhstspolicy.cpp
index 46c9c22510..323e562c3c 100644
--- a/src/network/access/qhstspolicy.cpp
+++ b/src/network/access/qhstspolicy.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qhstspolicy.h"
@@ -57,8 +21,8 @@ QT_BEGIN_NAMESPACE
RFC6797.
You can set expiry time and host name for this policy, and control whether it
- applies to subdomains, either in the constructor or by calling setExpiry(),
- setHost() and setIncludesSubdomains().
+ applies to subdomains, either in the constructor or by calling \l setExpiry(),
+ \l setHost() and \l setIncludesSubDomains().
\sa QNetworkAccessManager::setStrictTransportSecurityEnabled()
*/
@@ -86,12 +50,25 @@ public:
};
/*!
- Returns \c true if the two policies have the same host and expiration date
- while agreeing on whether to include or exclude subdomains.
+ \fn bool QHstsPolicy::operator==(const QHstsPolicy &lhs, const QHstsPolicy &rhs)
+
+ Returns \c true if the two policies \a lhs and \a rhs have the same host and
+ expiration date while agreeing on whether to include or exclude subdomains.
+*/
+
+/*!
+ \fn bool QHstsPolicy::operator!=(const QHstsPolicy &lhs, const QHstsPolicy &rhs)
+
+ Returns \c true if the two policies \a lhs and \a rhs do not have the same host
+ or expiration date, or do not agree on whether to include or exclude subdomains.
+*/
+
+/*!
+ \internal
*/
-bool operator==(const QHstsPolicy &lhs, const QHstsPolicy &rhs)
+bool QHstsPolicy::isEqual(const QHstsPolicy &other) const
{
- return *lhs.d == *rhs.d;
+ return *d == *other.d;
}
/*!
diff --git a/src/network/access/qhstspolicy.h b/src/network/access/qhstspolicy.h
index f1b2ee99e5..af5841906c 100644
--- a/src/network/access/qhstspolicy.h
+++ b/src/network/access/qhstspolicy.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QHSTSPOLICY_H
#define QHSTSPOLICY_H
@@ -68,7 +32,7 @@ public:
QHstsPolicy &operator=(QHstsPolicy &&other) noexcept { swap(other); return *this; }
~QHstsPolicy();
- void swap(QHstsPolicy &other) noexcept { qSwap(d, other.d); }
+ void swap(QHstsPolicy &other) noexcept { d.swap(other.d); }
void setHost(const QString &host, QUrl::ParsingMode mode = QUrl::DecodedMode);
QString host(QUrl::ComponentFormattingOptions options = QUrl::FullyDecoded) const;
@@ -80,21 +44,18 @@ public:
bool isExpired() const;
private:
-
QSharedDataPointer<QHstsPolicyPrivate> d;
- friend Q_NETWORK_EXPORT bool operator==(const QHstsPolicy &lhs, const QHstsPolicy &rhs);
+ bool isEqual(const QHstsPolicy &other) const;
+ friend bool operator==(const QHstsPolicy &lhs, const QHstsPolicy &rhs)
+ { return lhs.isEqual(rhs); }
+ friend bool operator!=(const QHstsPolicy &lhs, const QHstsPolicy &rhs)
+ { return !lhs.isEqual(rhs); }
};
Q_DECLARE_SHARED(QHstsPolicy)
Q_DECLARE_OPERATORS_FOR_FLAGS(QHstsPolicy::PolicyFlags)
-Q_NETWORK_EXPORT bool operator==(const QHstsPolicy &lhs, const QHstsPolicy &rhs);
-
-inline bool operator!=(const QHstsPolicy &lhs, const QHstsPolicy &rhs)
-{
- return !(lhs == rhs);
-}
QT_END_NAMESPACE
diff --git a/src/network/access/qhstsstore.cpp b/src/network/access/qhstsstore.cpp
index 67be8a2de2..a972a90ee7 100644
--- a/src/network/access/qhstsstore.cpp
+++ b/src/network/access/qhstsstore.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qhstsstore_p.h"
#include "qhstspolicy.h"
@@ -52,6 +16,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
static QString host_name_to_settings_key(const QString &hostName)
{
const QByteArray hostNameAsHex(hostName.toUtf8().toHex());
@@ -114,7 +80,7 @@ void QHstsStore::synchronize()
if (observedPolicies.size()) {
beginHstsGroups();
- for (const QHstsPolicy &policy : qAsConst(observedPolicies)) {
+ for (const QHstsPolicy &policy : std::as_const(observedPolicies)) {
const QString key(host_name_to_settings_key(policy.host()));
// If we fail to write a new, updated policy, we also remove the old one.
if (policy.isExpired() || !serializePolicy(key, policy))
@@ -136,13 +102,13 @@ QString QHstsStore::absoluteFilePath(const QString &dirName)
{
const QDir dir(dirName.isEmpty() ? QStandardPaths::writableLocation(QStandardPaths::CacheLocation)
: dirName);
- return dir.absoluteFilePath(QLatin1String("hstsstore"));
+ return dir.absoluteFilePath("hstsstore"_L1);
}
void QHstsStore::beginHstsGroups()
{
- store.beginGroup(QLatin1String("StrictTransportSecurity"));
- store.beginGroup(QLatin1String("Policies"));
+ store.beginGroup("StrictTransportSecurity"_L1);
+ store.beginGroup("Policies"_L1);
}
void QHstsStore::endHstsGroups()
diff --git a/src/network/access/qhstsstore_p.h b/src/network/access/qhstsstore_p.h
index bbf7379b61..c1ec3af122 100644
--- a/src/network/access/qhstsstore_p.h
+++ b/src/network/access/qhstsstore_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QHSTSSTORE_P_H
#define QHSTSSTORE_P_H
diff --git a/src/network/access/qhttp1configuration.cpp b/src/network/access/qhttp1configuration.cpp
new file mode 100644
index 0000000000..cfa929bca5
--- /dev/null
+++ b/src/network/access/qhttp1configuration.cpp
@@ -0,0 +1,154 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qhttp1configuration.h"
+
+#include <QtCore/private/qnumeric_p.h>
+#include <QtCore/qhashfunctions.h>
+
+QT_BEGIN_NAMESPACE
+
+// QHttp1ConfigurationPrivate is unused until we need it:
+static_assert(sizeof(QHttp1Configuration) == sizeof(void*),
+ "You have added too many members to QHttp1Configuration::ShortData. "
+ "Decrease their size or switch to using a d-pointer.");
+
+/*!
+ \class QHttp1Configuration
+ \brief The QHttp1Configuration class controls HTTP/1 parameters and settings.
+ \since 6.5
+
+ \reentrant
+ \inmodule QtNetwork
+ \ingroup network
+ \ingroup shared
+
+ QHttp1Configuration controls HTTP/1 parameters and settings that
+ QNetworkAccessManager will use to send requests and process responses.
+
+ \note The configuration must be set before the first request
+ was sent to a given host (and thus an HTTP/1 session established).
+
+ \sa QNetworkRequest::setHttp1Configuration(), QNetworkRequest::http1Configuration(), QNetworkAccessManager
+*/
+
+/*!
+ Default constructs a QHttp1Configuration object.
+*/
+QHttp1Configuration::QHttp1Configuration()
+ : u(ShortData{6, {}}) // QHttpNetworkConnectionPrivate::defaultHttpChannelCount
+{
+}
+
+/*!
+ Copy-constructs this QHttp1Configuration.
+*/
+QHttp1Configuration::QHttp1Configuration(const QHttp1Configuration &)
+ = default;
+
+/*!
+ \fn QHttp1Configuration::QHttp1Configuration(QHttp1Configuration &&other)
+
+ Move-constructs this QHttp1Configuration from \a other.
+
+ \note The moved-from object \a other is placed in a
+ partially-formed state, in which the only valid operations are
+ destruction and assignment of a new value.
+*/
+
+/*!
+ Copy-assigns \a other to this QHttp1Configuration.
+*/
+QHttp1Configuration &QHttp1Configuration::operator=(const QHttp1Configuration &)
+ = default;
+
+/*!
+ \fn QHttp1Configuration &QHttp1Configuration::operator=(QHttp1Configuration &&)
+
+ Move-assigns \a other to this QHttp1Configuration.
+
+ \note The moved-from object \a other is placed in a
+ partially-formed state, in which the only valid operations are
+ destruction and assignment of a new value.
+*/
+
+/*!
+ Destructor.
+*/
+QHttp1Configuration::~QHttp1Configuration()
+ = default;
+
+/*!
+ Sets the number of connections (minimum: 1; maximum: 255)
+ used per http(s) \e{host}:\e{port} combination to \a number.
+
+ If \a number is ≤ 0, does nothing. If \a number is > 255, 255 is used.
+
+ \sa numberOfConnectionsPerHost
+*/
+void QHttp1Configuration::setNumberOfConnectionsPerHost(qsizetype number)
+{
+ auto n = qt_saturate<std::uint8_t>(number);
+ if (n == 0)
+ return;
+ u.data.numConnectionsPerHost = n;
+}
+
+/*!
+ Returns the number of connections used per http(s) \c{host}:\e{port}
+ combination. The default is six (6).
+
+ \sa setNumberOfConnectionsPerHost
+*/
+qsizetype QHttp1Configuration::numberOfConnectionsPerHost() const
+{
+ return u.data.numConnectionsPerHost;
+}
+
+/*!
+ \fn void QHttp1Configuration::swap(QHttp1Configuration &other)
+
+ Swaps this HTTP/1 configuration with \a other. This operation is very fast
+ and never fails.
+*/
+
+/*!
+ \fn bool QHttp1Configuration::operator==(const QHttp1Configuration &lhs, const QHttp1Configuration &rhs) noexcept
+ \since 6.5
+
+ Returns \c true if \a lhs and \a rhs represent the same set of HTTP/1
+ parameters.
+*/
+
+/*!
+ \fn bool QHttp1Configuration::operator!=(const QHttp1Configuration &lhs, const QHttp1Configuration &rhs) noexcept
+ \since 6.5
+
+ Returns \c true if \a lhs and \a rhs do not represent the same set of
+ HTTP/1 parameters.
+*/
+
+/*!
+ \fn size_t QHttp1Configuration::qHash(const QHttp1Configuration &key, size_t seed)
+ \since 6.5
+
+ Returns the hash value for the \a key, using \a seed to seed the calculation.
+*/
+
+/*!
+ \internal
+*/
+bool QHttp1Configuration::equals(const QHttp1Configuration &other) const noexcept
+{
+ return u.data.numConnectionsPerHost == other.u.data.numConnectionsPerHost;
+}
+
+/*!
+ \internal
+*/
+size_t QHttp1Configuration::hash(size_t seed) const noexcept
+{
+ return qHash(u.data.numConnectionsPerHost, seed);
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/access/qhttp1configuration.h b/src/network/access/qhttp1configuration.h
new file mode 100644
index 0000000000..128b8aa5aa
--- /dev/null
+++ b/src/network/access/qhttp1configuration.h
@@ -0,0 +1,62 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QHTTP1CONFIGURATION_H
+#define QHTTP1CONFIGURATION_H
+
+#include <QtNetwork/qtnetworkglobal.h>
+
+#include <utility>
+#include <cstdint>
+
+QT_REQUIRE_CONFIG(http);
+
+QT_BEGIN_NAMESPACE
+
+class QHttp1ConfigurationPrivate;
+class QHttp1Configuration
+{
+public:
+ Q_NETWORK_EXPORT QHttp1Configuration();
+ Q_NETWORK_EXPORT QHttp1Configuration(const QHttp1Configuration &other);
+ QHttp1Configuration(QHttp1Configuration &&other) noexcept
+ : u{other.u} { other.u.d = nullptr; }
+
+ Q_NETWORK_EXPORT QHttp1Configuration &operator=(const QHttp1Configuration &other);
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QHttp1Configuration)
+
+ Q_NETWORK_EXPORT ~QHttp1Configuration();
+
+ Q_NETWORK_EXPORT void setNumberOfConnectionsPerHost(qsizetype amount);
+ Q_NETWORK_EXPORT qsizetype numberOfConnectionsPerHost() const;
+
+ void swap(QHttp1Configuration &other) noexcept
+ { std::swap(u, other.u); }
+
+private:
+ struct ShortData {
+ std::uint8_t numConnectionsPerHost;
+ char reserved[sizeof(void*) - sizeof(numConnectionsPerHost)];
+ };
+ union U {
+ U(ShortData _data) : data(_data) {}
+ QHttp1ConfigurationPrivate *d;
+ ShortData data;
+ } u;
+
+ Q_NETWORK_EXPORT bool equals(const QHttp1Configuration &other) const noexcept;
+ Q_NETWORK_EXPORT size_t hash(size_t seed) const noexcept;
+
+ friend bool operator==(const QHttp1Configuration &lhs, const QHttp1Configuration &rhs) noexcept
+ { return lhs.equals(rhs); }
+ friend bool operator!=(const QHttp1Configuration &lhs, const QHttp1Configuration &rhs) noexcept
+ { return !lhs.equals(rhs); }
+
+ friend size_t qHash(const QHttp1Configuration &key, size_t seed = 0) noexcept { return key.hash(seed); }
+};
+
+Q_DECLARE_SHARED(QHttp1Configuration)
+
+QT_END_NAMESPACE
+
+#endif // QHTTP1CONFIGURATION_H
diff --git a/src/network/access/qhttp2configuration.cpp b/src/network/access/qhttp2configuration.cpp
index 408f141e77..b718ddc755 100644
--- a/src/network/access/qhttp2configuration.cpp
+++ b/src/network/access/qhttp2configuration.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qhttp2configuration.h"
@@ -98,9 +62,6 @@ class QHttp2ConfigurationPrivate : public QSharedData
{
public:
unsigned sessionWindowSize = Http2::defaultSessionWindowSize;
- // The size below is quite a limiting default value, QNetworkRequest
- // by default sets a larger number, an application can change this using
- // QNetworkRequest::setHttp2Configuration.
unsigned streamWindowSize = Http2::defaultSessionWindowSize;
unsigned maxFrameSize = Http2::minPayloadLimit; // Initial (default) value of 16Kb.
@@ -159,7 +120,7 @@ QHttp2Configuration::~QHttp2Configuration()
/*!
If \a enable is \c true, a remote server can potentially
- use server push to send reponses in advance.
+ use server push to send responses in advance.
\sa serverPushEnabled
*/
@@ -256,7 +217,7 @@ bool QHttp2Configuration::setStreamReceiveWindowSize(unsigned size)
/*!
Returns the window size for stream-level flow control.
The default value QNetworkAccessManager will be using is
- 21474836 octets.
+ 214748364 octets (see \l {https://httpwg.org/specs/rfc7540.html#SettingValues}{RFC 7540}).
*/
unsigned QHttp2Configuration::streamReceiveWindowSize() const
{
@@ -301,18 +262,29 @@ void QHttp2Configuration::swap(QHttp2Configuration &other) noexcept
}
/*!
+ \fn bool QHttp2Configuration::operator==(const QHttp2Configuration &lhs, const QHttp2Configuration &rhs) noexcept
Returns \c true if \a lhs and \a rhs have the same set of HTTP/2
parameters.
*/
-bool operator==(const QHttp2Configuration &lhs, const QHttp2Configuration &rhs)
+
+/*!
+ \fn bool QHttp2Configuration::operator!=(const QHttp2Configuration &lhs, const QHttp2Configuration &rhs) noexcept
+ Returns \c true if \a lhs and \a rhs do not have the same set of HTTP/2
+ parameters.
+*/
+
+/*!
+ \internal
+*/
+bool QHttp2Configuration::isEqual(const QHttp2Configuration &other) const noexcept
{
- if (lhs.d == rhs.d)
+ if (d == other.d)
return true;
- return lhs.d->pushEnabled == rhs.d->pushEnabled
- && lhs.d->huffmanCompressionEnabled == rhs.d->huffmanCompressionEnabled
- && lhs.d->sessionWindowSize == rhs.d->sessionWindowSize
- && lhs.d->streamWindowSize == rhs.d->streamWindowSize;
+ return d->pushEnabled == other.d->pushEnabled
+ && d->huffmanCompressionEnabled == other.d->huffmanCompressionEnabled
+ && d->sessionWindowSize == other.d->sessionWindowSize
+ && d->streamWindowSize == other.d->streamWindowSize;
}
QT_END_NAMESPACE
diff --git a/src/network/access/qhttp2configuration.h b/src/network/access/qhttp2configuration.h
index e5c235e2be..ae08b664d4 100644
--- a/src/network/access/qhttp2configuration.h
+++ b/src/network/access/qhttp2configuration.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QHTTP2CONFIGURATION_H
#define QHTTP2CONFIGURATION_H
@@ -44,17 +8,13 @@
#include <QtCore/qshareddata.h>
-#ifndef Q_CLANG_QDOC
QT_REQUIRE_CONFIG(http);
-#endif
QT_BEGIN_NAMESPACE
class QHttp2ConfigurationPrivate;
class Q_NETWORK_EXPORT QHttp2Configuration
{
- friend Q_NETWORK_EXPORT bool operator==(const QHttp2Configuration &lhs, const QHttp2Configuration &rhs);
-
public:
QHttp2Configuration();
QHttp2Configuration(const QHttp2Configuration &other);
@@ -82,18 +42,18 @@ public:
void swap(QHttp2Configuration &other) noexcept;
private:
-
QSharedDataPointer<QHttp2ConfigurationPrivate> d;
-};
-Q_DECLARE_SHARED(QHttp2Configuration)
+ bool isEqual(const QHttp2Configuration &other) const noexcept;
-Q_NETWORK_EXPORT bool operator==(const QHttp2Configuration &lhs, const QHttp2Configuration &rhs);
+ friend bool operator==(const QHttp2Configuration &lhs, const QHttp2Configuration &rhs) noexcept
+ { return lhs.isEqual(rhs); }
+ friend bool operator!=(const QHttp2Configuration &lhs, const QHttp2Configuration &rhs) noexcept
+ { return !lhs.isEqual(rhs); }
-inline bool operator!=(const QHttp2Configuration &lhs, const QHttp2Configuration &rhs)
-{
- return !(lhs == rhs);
-}
+};
+
+Q_DECLARE_SHARED(QHttp2Configuration)
QT_END_NAMESPACE
diff --git a/src/network/access/qhttp2connection.cpp b/src/network/access/qhttp2connection.cpp
new file mode 100644
index 0000000000..8560e0da38
--- /dev/null
+++ b/src/network/access/qhttp2connection.cpp
@@ -0,0 +1,1752 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qhttp2connection_p.h"
+
+#include <private/bitstreams_p.h>
+
+#include <QtCore/private/qnumeric_p.h>
+#include <QtCore/private/qiodevice_p.h>
+#include <QtCore/private/qnoncontiguousbytedevice_p.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/QRandomGenerator>
+#include <QtCore/qloggingcategory.h>
+
+#include <algorithm>
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(qHttp2ConnectionLog, "qt.network.http2.connection", QtCriticalMsg)
+
+using namespace Qt::StringLiterals;
+using namespace Http2;
+
+/*!
+ \class QHttp2Stream
+ \inmodule QtNetwork
+ \internal
+
+ The QHttp2Stream class represents a single HTTP/2 stream.
+ Must be created by QHttp2Connection.
+
+ \sa QHttp2Connection
+*/
+
+QHttp2Stream::QHttp2Stream(QHttp2Connection *connection, quint32 streamID) noexcept
+ : QObject(connection), m_streamID(streamID)
+{
+ Q_ASSERT(connection);
+ Q_ASSERT(streamID); // stream id 0 is reserved for connection control messages
+ qCDebug(qHttp2ConnectionLog, "[%p] new stream %u", connection, streamID);
+}
+
+QHttp2Stream::~QHttp2Stream() noexcept = default;
+
+/*!
+ \fn quint32 QHttp2Stream::streamID() const noexcept
+
+ Returns the stream ID of this stream.
+*/
+
+/*!
+ \fn void QHttp2Stream::headersReceived(const HPack::HttpHeader &headers, bool endStream)
+
+ This signal is emitted when the remote peer has sent a HEADERS frame, and
+ potentially some CONTINUATION frames, ending with the END_HEADERS flag
+ to this stream.
+
+ The headers are internally combined and decompressed, and are accessible
+ through the \a headers parameter. If the END_STREAM flag was set, the
+ \a endStream parameter will be \c true, indicating that the peer does not
+ intend to send any more frames on this stream.
+
+ \sa receivedHeaders()
+*/
+
+/*!
+ \fn void QHttp2Stream::headersUpdated()
+
+ This signal may be emitted if a new HEADERS frame was received after
+ already processing a previous HEADERS frame.
+
+ \sa headersReceived(), receivedHeaders()
+*/
+
+/*!
+ \fn void QHttp2Stream::errorOccurred(quint32 errorCode, const QString &errorString)
+
+ This signal is emitted when the stream has encountered an error. The
+ \a errorCode parameter is the HTTP/2 error code, and the \a errorString
+ parameter is a human-readable description of the error.
+
+ \sa https://www.rfc-editor.org/rfc/rfc7540#section-7
+*/
+
+/*!
+ \fn void QHttp2Stream::stateChanged(State newState)
+
+ This signal is emitted when the state of the stream changes. The \a newState
+ parameter is the new state of the stream.
+
+ Examples of this is sending or receiving a frame with the END_STREAM flag.
+ This will transition the stream to the HalfClosedLocal or HalfClosedRemote
+ state, respectively.
+
+ \sa state()
+*/
+
+
+/*!
+ \fn void QHttp2Stream::promisedStreamReceived(quint32 newStreamID)
+
+ This signal is emitted when the remote peer has promised a new stream with
+ the given \a newStreamID.
+
+ \sa QHttp2Connection::promisedStream()
+*/
+
+/*!
+ \fn void QHttp2Stream::uploadBlocked()
+
+ This signal is emitted when the stream is unable to send more data because
+ the remote peer's receive window is full.
+
+ This is mostly intended for diagnostics as there is no expectation that the
+ user can do anything to react to this.
+*/
+
+/*!
+ \fn void QHttp2Stream::dataReceived(const QByteArray &data, bool endStream)
+
+ This signal is emitted when the stream has received a DATA frame from the
+ remote peer. The \a data parameter contains the payload of the frame, and
+ the \a endStream parameter is \c true if the END_STREAM flag was set.
+
+ \sa downloadBuffer()
+*/
+
+/*!
+ \fn void QHttp2Stream::bytesWritten(qint64 bytesWritten)
+
+ This signal is emitted when the stream has written \a bytesWritten bytes to
+ the network.
+*/
+
+/*!
+ \fn void QHttp2Stream::uploadDeviceError(const QString &errorString)
+
+ This signal is emitted if the upload device encounters an error while
+ sending data. The \a errorString parameter is a human-readable description
+ of the error.
+*/
+
+/*!
+ \fn void QHttp2Stream::uploadFinished()
+
+ This signal is emitted when the stream has finished sending all the data
+ from the upload device.
+
+ If the END_STREAM flag was set for sendData() then the stream will be
+ closed for further writes before this signal is emitted.
+*/
+
+/*!
+ \fn bool QHttp2Stream::isUploadingDATA() const noexcept
+
+ Returns \c true if the stream is currently sending DATA frames.
+*/
+
+/*!
+ \fn State QHttp2Stream::state() const noexcept
+
+ Returns the current state of the stream.
+
+ \sa stateChanged()
+*/
+/*!
+ \fn bool QHttp2Stream::isActive() const noexcept
+
+ Returns \c true if the stream has been opened and is not yet closed.
+*/
+/*!
+ \fn bool QHttp2Stream::isPromisedStream() const noexcept
+
+ Returns \c true if the stream was promised by the remote peer.
+*/
+/*!
+ \fn bool QHttp2Stream::wasReset() const noexcept
+
+ Returns \c true if the stream was reset by the remote peer.
+*/
+/*!
+ \fn quint32 QHttp2Stream::RST_STREAM_code() const noexcept
+
+ Returns the HTTP/2 error code if the stream was reset by the remote peer.
+ If the stream was not reset, this function returns 0.
+*/
+/*!
+ \fn HPack::HttpHeader QHttp2Stream::receivedHeaders() const noexcept
+
+ Returns the headers received from the remote peer, if any.
+*/
+/*!
+ \fn QByteDataBuffer QHttp2Stream::downloadBuffer() const noexcept
+
+ Returns the buffer containing the data received from the remote peer.
+*/
+
+void QHttp2Stream::finishWithError(quint32 errorCode, const QString &message)
+{
+ qCDebug(qHttp2ConnectionLog, "[%p] stream %u finished with error: %ls (error code: %u)",
+ getConnection(), m_streamID, qUtf16Printable(message), errorCode);
+ transitionState(StateTransition::RST);
+ emit errorOccurred(errorCode, message);
+}
+
+void QHttp2Stream::finishWithError(quint32 errorCode)
+{
+ QNetworkReply::NetworkError error = QNetworkReply::NoError;
+ QString message;
+ qt_error(errorCode, error, message);
+ finishWithError(error, message);
+}
+
+/*!
+ Sends a RST_STREAM frame with the given \a errorCode.
+ This closes the stream for both sides, any further frames will be dropped.
+
+ Returns \c false if the stream is closed or idle, also if it fails to send
+ the RST_STREAM frame. Otherwise, returns \c true.
+*/
+bool QHttp2Stream::sendRST_STREAM(quint32 errorCode)
+{
+ if (m_state == State::Closed || m_state == State::Idle)
+ return false;
+ qCDebug(qHttp2ConnectionLog, "[%p] sending RST_STREAM on stream %u, code: %u", getConnection(),
+ m_streamID, errorCode);
+ transitionState(StateTransition::RST);
+
+ QHttp2Connection *connection = getConnection();
+ FrameWriter &frameWriter = connection->frameWriter;
+ frameWriter.start(FrameType::RST_STREAM, FrameFlag::EMPTY, m_streamID);
+ frameWriter.append(errorCode);
+ return frameWriter.write(*connection->getSocket());
+}
+
+/*!
+ Sends a DATA frame with the bytes obtained from \a device.
+
+ This function will send as many DATA frames as needed to send all the data
+ from \a device. If \a endStream is \c true, the END_STREAM flag will be set.
+
+ \a device must stay alive for the duration of the upload.
+ A way of doing this is to heap-allocate the \a device and parent it to the
+ QHttp2Stream.
+*/
+void QHttp2Stream::sendDATA(QIODevice *device, bool endStream)
+{
+ Q_ASSERT(!m_uploadDevice);
+ Q_ASSERT(!m_uploadByteDevice);
+ Q_ASSERT(device);
+ if (m_state != State::Open && m_state != State::HalfClosedRemote)
+ return;
+
+ auto *byteDevice = QNonContiguousByteDeviceFactory::create(device);
+ connect(this, &QHttp2Stream::uploadFinished, byteDevice, &QObject::deleteLater);
+ byteDevice->setParent(this);
+ m_uploadDevice = device;
+ qCDebug(qHttp2ConnectionLog, "[%p] starting sendDATA on stream %u, of IODevice: %p",
+ getConnection(), m_streamID, device);
+ sendDATA(byteDevice, endStream);
+}
+
+/*!
+ Sends a DATA frame with the bytes obtained from \a device.
+
+ This function will send as many DATA frames as needed to send all the data
+ from \a device. If \a endStream is \c true, the END_STREAM flag will be set.
+
+ \a device must stay alive for the duration of the upload.
+ A way of doing this is to heap-allocate the \a device and parent it to the
+ QHttp2Stream.
+*/
+void QHttp2Stream::sendDATA(QNonContiguousByteDevice *device, bool endStream)
+{
+ Q_ASSERT(!m_uploadByteDevice);
+ Q_ASSERT(device);
+ if (m_state != State::Open && m_state != State::HalfClosedRemote)
+ return;
+
+ qCDebug(qHttp2ConnectionLog, "[%p] starting sendDATA on stream %u, of device: %p",
+ getConnection(), m_streamID, device);
+
+ m_uploadByteDevice = device;
+ m_endStreamAfterDATA = endStream;
+ connect(m_uploadByteDevice, &QNonContiguousByteDevice::readyRead, this,
+ &QHttp2Stream::maybeResumeUpload);
+ connect(m_uploadByteDevice, &QObject::destroyed, this, &QHttp2Stream::uploadDeviceDestroyed);
+
+ internalSendDATA();
+}
+
+void QHttp2Stream::internalSendDATA()
+{
+ Q_ASSERT(m_uploadByteDevice);
+ QHttp2Connection *connection = getConnection();
+ Q_ASSERT(connection->maxFrameSize > frameHeaderSize);
+ QIODevice *socket = connection->getSocket();
+
+ qCDebug(qHttp2ConnectionLog,
+ "[%p] stream %u, about to write to socket, current session window size: %d, stream "
+ "window size: %d, bytes available: %lld",
+ connection, m_streamID, connection->sessionSendWindowSize, m_sendWindow,
+ m_uploadByteDevice->size() - m_uploadByteDevice->pos());
+
+ qint32 remainingWindowSize = std::min<qint32>(connection->sessionSendWindowSize, m_sendWindow);
+ FrameWriter &frameWriter = connection->frameWriter;
+ qint64 totalBytesWritten = 0;
+ const auto deviceCanRead = [this, connection] {
+ // We take advantage of knowing the internals of one of the devices used.
+ // It will request X bytes to move over to the http thread if there's
+ // not enough left, so we give it a large size. It will anyway return
+ // the size it can actually provide.
+ const qint64 requestSize = connection->maxFrameSize * 10ll;
+ qint64 tmp = 0;
+ return m_uploadByteDevice->readPointer(requestSize, tmp) != nullptr && tmp > 0;
+ };
+
+ bool sentEND_STREAM = false;
+ while (remainingWindowSize && deviceCanRead()) {
+ quint32 bytesWritten = 0;
+ qint32 remainingBytesInFrame = qint32(connection->maxFrameSize);
+ frameWriter.start(FrameType::DATA, FrameFlag::EMPTY, streamID());
+
+ while (remainingWindowSize && deviceCanRead() && remainingBytesInFrame) {
+ const qint32 maxToWrite = std::min(remainingWindowSize, remainingBytesInFrame);
+
+ qint64 outBytesAvail = 0;
+ const char *readPointer = m_uploadByteDevice->readPointer(maxToWrite, outBytesAvail);
+ if (!readPointer || outBytesAvail <= 0) {
+ qCDebug(qHttp2ConnectionLog,
+ "[%p] stream %u, cannot write data, device (%p) has %lld bytes available",
+ connection, m_streamID, m_uploadByteDevice, outBytesAvail);
+ break;
+ }
+ const qint32 bytesToWrite = qint32(std::min<qint64>(maxToWrite, outBytesAvail));
+ frameWriter.append(QByteArrayView(readPointer, bytesToWrite));
+ m_uploadByteDevice->advanceReadPointer(bytesToWrite);
+
+ bytesWritten += bytesToWrite;
+
+ m_sendWindow -= bytesToWrite;
+ Q_ASSERT(m_sendWindow >= 0);
+ connection->sessionSendWindowSize -= bytesToWrite;
+ Q_ASSERT(connection->sessionSendWindowSize >= 0);
+ remainingBytesInFrame -= bytesToWrite;
+ Q_ASSERT(remainingBytesInFrame >= 0);
+ remainingWindowSize -= bytesToWrite;
+ Q_ASSERT(remainingWindowSize >= 0);
+ }
+
+ qCDebug(qHttp2ConnectionLog, "[%p] stream %u, writing %u bytes to socket", connection,
+ m_streamID, bytesWritten);
+ if (!deviceCanRead() && m_uploadByteDevice->atEnd() && m_endStreamAfterDATA) {
+ sentEND_STREAM = true;
+ frameWriter.addFlag(FrameFlag::END_STREAM);
+ }
+ if (!frameWriter.write(*socket)) {
+ qCDebug(qHttp2ConnectionLog, "[%p] stream %u, failed to write to socket", connection,
+ m_streamID);
+ finishWithError(QNetworkReply::ProtocolFailure, "failed to write to socket"_L1);
+ return;
+ }
+
+ totalBytesWritten += bytesWritten;
+ }
+
+ qCDebug(qHttp2ConnectionLog,
+ "[%p] stream %u, wrote %lld bytes total, if the device is not exhausted, we'll write "
+ "more later. Remaining window size: %d",
+ connection, m_streamID, totalBytesWritten, remainingWindowSize);
+
+ emit bytesWritten(totalBytesWritten);
+ if (sentEND_STREAM || (!deviceCanRead() && m_uploadByteDevice->atEnd())) {
+ qCDebug(qHttp2ConnectionLog,
+ "[%p] stream %u, exhausted device %p, sent END_STREAM? %d, %ssending end stream "
+ "after DATA",
+ connection, m_streamID, m_uploadByteDevice, sentEND_STREAM,
+ m_endStreamAfterDATA ? "" : "not ");
+ if (!sentEND_STREAM && m_endStreamAfterDATA) {
+ // We need to send an empty DATA frame with END_STREAM since we
+ // have exhausted the device, but we haven't sent END_STREAM yet.
+ // This can happen if we got a final readyRead to signify no more
+ // data available, but we hadn't sent the END_STREAM flag yet.
+ frameWriter.start(FrameType::DATA, FrameFlag::END_STREAM, streamID());
+ frameWriter.write(*socket);
+ }
+ finishSendDATA();
+ } else if (isUploadBlocked()) {
+ qCDebug(qHttp2ConnectionLog, "[%p] stream %u, upload blocked", connection, m_streamID);
+ emit uploadBlocked();
+ }
+}
+
+void QHttp2Stream::finishSendDATA()
+{
+ if (m_endStreamAfterDATA)
+ transitionState(StateTransition::CloseLocal);
+
+ disconnect(m_uploadByteDevice, nullptr, this, nullptr);
+ m_uploadDevice = nullptr;
+ m_uploadByteDevice = nullptr;
+ emit uploadFinished();
+}
+
+void QHttp2Stream::maybeResumeUpload()
+{
+ qCDebug(qHttp2ConnectionLog,
+ "[%p] stream %u, maybeResumeUpload. Upload device: %p, bytes available: %lld, blocked? "
+ "%d",
+ getConnection(), m_streamID, m_uploadByteDevice,
+ !m_uploadByteDevice ? 0 : m_uploadByteDevice->size() - m_uploadByteDevice->pos(),
+ isUploadBlocked());
+ if (isUploadingDATA() && !isUploadBlocked())
+ internalSendDATA();
+}
+
+/*!
+ Returns \c true if the stream is currently unable to send more data because
+ the remote peer's receive window is full.
+*/
+bool QHttp2Stream::isUploadBlocked() const noexcept
+{
+ constexpr auto MinFrameSize = Http2::frameHeaderSize + 1; // 1 byte payload
+ return isUploadingDATA()
+ && (m_sendWindow <= MinFrameSize
+ || getConnection()->sessionSendWindowSize <= MinFrameSize);
+}
+
+void QHttp2Stream::uploadDeviceReadChannelFinished()
+{
+ maybeResumeUpload();
+}
+
+/*!
+ Sends a HEADERS frame with the given \a headers and \a priority.
+ If \a endStream is \c true, the END_STREAM flag will be set, and the stream
+ will be closed for future writes.
+ If the headers are too large, or the stream is not in the correct state,
+ this function will return \c false. Otherwise, it will return \c true.
+*/
+bool QHttp2Stream::sendHEADERS(const HPack::HttpHeader &headers, bool endStream, quint8 priority)
+{
+ using namespace HPack;
+ if (auto hs = header_size(headers);
+ !hs.first || hs.second > getConnection()->maxHeaderListSize()) {
+ return false;
+ }
+
+ transitionState(StateTransition::Open);
+
+ Q_ASSERT(m_state == State::Open || m_state == State::HalfClosedRemote);
+
+ QHttp2Connection *connection = getConnection();
+
+ qCDebug(qHttp2ConnectionLog, "[%p] stream %u, sending HEADERS frame with %u entries",
+ connection, streamID(), uint(headers.size()));
+
+ QIODevice *socket = connection->getSocket();
+ FrameWriter &frameWriter = connection->frameWriter;
+
+ frameWriter.start(FrameType::HEADERS, FrameFlag::PRIORITY | FrameFlag::END_HEADERS, streamID());
+ if (endStream)
+ frameWriter.addFlag(FrameFlag::END_STREAM);
+
+ frameWriter.append(quint32()); // No stream dependency in Qt.
+ frameWriter.append(priority);
+
+ // Compress in-place:
+ BitOStream outputStream(frameWriter.outboundFrame().buffer);
+ if (connection->m_connectionType == QHttp2Connection::Type::Client) {
+ if (!connection->encoder.encodeRequest(outputStream, headers))
+ return false;
+ } else {
+ if (!connection->encoder.encodeResponse(outputStream, headers))
+ return false;
+ }
+
+ bool result = frameWriter.writeHEADERS(*socket, connection->maxFrameSize);
+ if (endStream)
+ transitionState(StateTransition::CloseLocal);
+
+ return result;
+}
+
+/*!
+ Sends a WINDOW_UPDATE frame with the given \a delta.
+ This increases our receive window size for this stream, allowing the remote
+ peer to send more data.
+*/
+void QHttp2Stream::sendWINDOW_UPDATE(quint32 delta)
+{
+ QHttp2Connection *connection = getConnection();
+ m_recvWindow += qint32(delta);
+ connection->sendWINDOW_UPDATE(streamID(), delta);
+}
+
+void QHttp2Stream::uploadDeviceDestroyed()
+{
+ if (isUploadingDATA()) {
+ // We're in the middle of sending DATA frames, we need to abort
+ // the stream.
+ sendRST_STREAM(CANCEL);
+ emit uploadDeviceError("Upload device destroyed while uploading"_L1);
+ }
+ m_uploadDevice = nullptr;
+}
+
+void QHttp2Stream::setState(State newState)
+{
+ if (m_state == newState)
+ return;
+ qCDebug(qHttp2ConnectionLog, "[%p] stream %u, state changed from %d to %d", getConnection(),
+ streamID(), int(m_state), int(newState));
+ m_state = newState;
+ emit stateChanged(newState);
+}
+
+// Changes the state as appropriate given the current state and the transition.
+// Always call this before emitting any signals since the recipient might rely
+// on the new state!
+void QHttp2Stream::transitionState(StateTransition transition)
+{
+ switch (m_state) {
+ case State::Idle:
+ if (transition == StateTransition::Open)
+ setState(State::Open);
+ else
+ Q_UNREACHABLE(); // We should transition to Open before ever getting here
+ break;
+ case State::Open:
+ switch (transition) {
+ case StateTransition::CloseLocal:
+ setState(State::HalfClosedLocal);
+ break;
+ case StateTransition::CloseRemote:
+ setState(State::HalfClosedRemote);
+ break;
+ case StateTransition::RST:
+ setState(State::Closed);
+ break;
+ case StateTransition::Open: // no-op
+ break;
+ }
+ break;
+ case State::HalfClosedLocal:
+ if (transition == StateTransition::CloseRemote || transition == StateTransition::RST)
+ setState(State::Closed);
+ break;
+ case State::HalfClosedRemote:
+ if (transition == StateTransition::CloseLocal || transition == StateTransition::RST)
+ setState(State::Closed);
+ break;
+ case State::ReservedRemote:
+ if (transition == StateTransition::RST) {
+ setState(State::Closed);
+ } else if (transition == StateTransition::CloseLocal) { // Receiving HEADER closes local
+ setState(State::HalfClosedLocal);
+ }
+ break;
+ case State::Closed:
+ break;
+ }
+}
+
+void QHttp2Stream::handleDATA(const Frame &inboundFrame)
+{
+ QHttp2Connection *connection = getConnection();
+
+ qCDebug(qHttp2ConnectionLog, "[%p] stream %u, received DATA frame with payload of %u bytes",
+ connection, m_streamID, inboundFrame.payloadSize());
+
+ if (qint32(inboundFrame.payloadSize()) > m_recvWindow) {
+ qCDebug(qHttp2ConnectionLog,
+ "[%p] stream %u, received DATA frame with payload size %u, "
+ "but recvWindow is %d, sending FLOW_CONTROL_ERROR",
+ connection, m_streamID, inboundFrame.payloadSize(), m_recvWindow);
+ finishWithError(QNetworkReply::ProtocolFailure, "flow control error"_L1);
+ sendRST_STREAM(FLOW_CONTROL_ERROR);
+ return;
+ }
+ m_recvWindow -= qint32(inboundFrame.payloadSize());
+ const bool endStream = inboundFrame.flags().testFlag(FrameFlag::END_STREAM);
+ // Uncompress data if needed and append it ...
+ if (inboundFrame.dataSize() > 0 || endStream) {
+ QByteArray fragment(reinterpret_cast<const char *>(inboundFrame.dataBegin()),
+ inboundFrame.dataSize());
+ if (endStream)
+ transitionState(StateTransition::CloseRemote);
+ emit dataReceived(fragment, endStream);
+ m_downloadBuffer.append(std::move(fragment));
+ }
+
+ if (!endStream && m_recvWindow < connection->streamInitialReceiveWindowSize / 2) {
+ // @future[consider]: emit signal instead
+ sendWINDOW_UPDATE(quint32(connection->streamInitialReceiveWindowSize - m_recvWindow));
+ }
+}
+
+void QHttp2Stream::handleHEADERS(Http2::FrameFlags frameFlags, const HPack::HttpHeader &headers)
+{
+ if (m_state == State::Idle)
+ transitionState(StateTransition::Open);
+ const bool endStream = frameFlags.testFlag(FrameFlag::END_STREAM);
+ if (endStream)
+ transitionState(StateTransition::CloseRemote);
+ if (!headers.empty()) {
+ m_headers.insert(m_headers.end(), headers.begin(), headers.end());
+ emit headersUpdated();
+ }
+ emit headersReceived(headers, endStream);
+}
+
+void QHttp2Stream::handleRST_STREAM(const Frame &inboundFrame)
+{
+ transitionState(StateTransition::RST);
+ m_RST_STREAM_code = qFromBigEndian<quint32>(inboundFrame.dataBegin());
+ if (isUploadingDATA()) {
+ disconnect(m_uploadByteDevice, nullptr, this, nullptr);
+ m_uploadDevice = nullptr;
+ m_uploadByteDevice = nullptr;
+ }
+ finishWithError(*m_RST_STREAM_code, ""_L1);
+}
+
+void QHttp2Stream::handleWINDOW_UPDATE(const Frame &inboundFrame)
+{
+ const quint32 delta = qFromBigEndian<quint32>(inboundFrame.dataBegin());
+ const bool valid = delta && delta <= quint32(std::numeric_limits<qint32>::max());
+ qint32 sum = 0;
+ if (!valid || qAddOverflow(m_sendWindow, qint32(delta), &sum)) {
+ qCDebug(qHttp2ConnectionLog,
+ "[%p] stream %u, received WINDOW_UPDATE frame with invalid delta %u, sending "
+ "PROTOCOL_ERROR",
+ getConnection(), m_streamID, delta);
+ finishWithError(QNetworkReply::ProtocolFailure, "invalid WINDOW_UPDATE delta"_L1);
+ sendRST_STREAM(PROTOCOL_ERROR);
+ return;
+ }
+ m_sendWindow = sum;
+ // Stream may have been unblocked, so maybe try to write again
+ if (isUploadingDATA())
+ maybeResumeUpload();
+}
+
+/*!
+ \class QHttp2Connection
+ \inmodule QtNetwork
+ \internal
+
+ The QHttp2Connection class represents a HTTP/2 connection.
+ It can only be created through the static functions
+ createDirectConnection(), createUpgradedConnection(),
+ and createDirectServerConnection().
+
+ createDirectServerConnection() is used for server-side connections, and has
+ certain limitations that a client does not.
+
+ As a client you can create a QHttp2Stream with createStream().
+
+ \sa QHttp2Stream
+*/
+
+/*!
+ \fn void QHttp2Connection::newIncomingStream(QHttp2Stream *stream)
+
+ This signal is emitted when a new \a stream is received from the remote
+ peer.
+*/
+
+/*!
+ \fn void QHttp2Connection::newPromisedStream(QHttp2Stream *stream)
+
+ This signal is emitted when the remote peer has promised a new \a stream.
+*/
+
+/*!
+ \fn void QHttp2Connection::errorReceived()
+
+ This signal is emitted when the connection has received an error.
+*/
+
+/*!
+ \fn void QHttp2Connection::connectionClosed()
+
+ This signal is emitted when the connection has been closed.
+*/
+
+/*!
+ \fn void QHttp2Connection::settingsFrameReceived()
+
+ This signal is emitted when the connection has received a SETTINGS frame.
+*/
+
+/*!
+ \fn void QHttp2Connection::errorOccurred(Http2::Http2Error errorCode, const QString &errorString)
+
+ This signal is emitted when the connection has encountered an error. The
+ \a errorCode parameter is the HTTP/2 error code, and the \a errorString
+ parameter is a human-readable description of the error.
+*/
+
+/*!
+ \fn void QHttp2Connection::receivedGOAWAY(quint32 errorCode, quint32 lastStreamID)
+
+ This signal is emitted when the connection has received a GOAWAY frame. The
+ \a errorCode parameter is the HTTP/2 error code, and the \a lastStreamID
+ parameter is the last stream ID that the remote peer will process.
+
+ Any streams of a higher stream ID created by us will be ignored or reset.
+*/
+
+/*!
+ Create a new HTTP2 connection given a \a config and a \a socket.
+ This function assumes that the Upgrade headers etc. in http/1 have already
+ been sent and that the connection is already upgraded to http/2.
+
+ The object returned will be a child to the \a socket, or null on failure.
+*/
+QHttp2Connection *QHttp2Connection::createUpgradedConnection(QIODevice *socket,
+ const QHttp2Configuration &config)
+{
+ Q_ASSERT(socket);
+
+ auto connection = std::unique_ptr<QHttp2Connection>(new QHttp2Connection(socket));
+ connection->setH2Configuration(config);
+ connection->m_connectionType = QHttp2Connection::Type::Client;
+ // HTTP2 connection is already established and request was sent, so stream 1
+ // is already 'active' and is closed for any further outgoing data.
+ QHttp2Stream *stream = connection->createStreamInternal().unwrap();
+ Q_ASSERT(stream->streamID() == 1);
+ stream->setState(QHttp2Stream::State::HalfClosedLocal);
+ connection->m_upgradedConnection = true;
+
+ if (!connection->sendClientPreface()) {
+ qCWarning(qHttp2ConnectionLog, "[%p] Failed to send client preface", connection.get());
+ return nullptr;
+ }
+
+ return connection.release();
+}
+
+/*!
+ Create a new HTTP2 connection given a \a config and a \a socket.
+ This function will immediately send the client preface.
+
+ The object returned will be a child to the \a socket, or null on failure.
+*/
+QHttp2Connection *QHttp2Connection::createDirectConnection(QIODevice *socket,
+ const QHttp2Configuration &config)
+{
+ auto connection = std::unique_ptr<QHttp2Connection>(new QHttp2Connection(socket));
+ connection->setH2Configuration(config);
+ connection->m_connectionType = QHttp2Connection::Type::Client;
+
+ if (!connection->sendClientPreface()) {
+ qCWarning(qHttp2ConnectionLog, "[%p] Failed to send client preface", connection.get());
+ return nullptr;
+ }
+
+ return connection.release();
+}
+
+/*!
+ Create a new HTTP2 connection given a \a config and a \a socket.
+
+ The object returned will be a child to the \a socket, or null on failure.
+*/
+QHttp2Connection *QHttp2Connection::createDirectServerConnection(QIODevice *socket,
+ const QHttp2Configuration &config)
+{
+ auto connection = std::unique_ptr<QHttp2Connection>(new QHttp2Connection(socket));
+ connection->setH2Configuration(config);
+ connection->m_connectionType = QHttp2Connection::Type::Server;
+
+ connection->m_nextStreamID = 2; // server-initiated streams must be even
+
+ connection->m_waitingForClientPreface = true;
+
+ return connection.release();
+}
+
+/*!
+ Creates a stream on this connection.
+
+ Automatically picks the next available stream ID and returns a pointer to
+ the new stream, if possible. Otherwise returns an error.
+
+ \sa QHttp2Connection::CreateStreamError, QHttp2Stream
+*/
+QH2Expected<QHttp2Stream *, QHttp2Connection::CreateStreamError> QHttp2Connection::createStream()
+{
+ Q_ASSERT(m_connectionType == Type::Client); // This overload is just for clients
+ if (m_nextStreamID > lastValidStreamID)
+ return { QHttp2Connection::CreateStreamError::StreamIdsExhausted };
+ return createStreamInternal();
+}
+
+QH2Expected<QHttp2Stream *, QHttp2Connection::CreateStreamError>
+QHttp2Connection::createStreamInternal()
+{
+ if (m_goingAway)
+ return { QHttp2Connection::CreateStreamError::ReceivedGOAWAY };
+ const quint32 streamID = m_nextStreamID;
+ if (size_t(m_maxConcurrentStreams) <= size_t(numActiveLocalStreams()))
+ return { QHttp2Connection::CreateStreamError::MaxConcurrentStreamsReached };
+ m_nextStreamID += 2;
+ return { createStreamInternal_impl(streamID) };
+}
+
+QHttp2Stream *QHttp2Connection::createStreamInternal_impl(quint32 streamID)
+{
+ qsizetype numStreams = m_streams.size();
+ QPointer<QHttp2Stream> &stream = m_streams[streamID];
+ if (numStreams == m_streams.size()) // stream already existed
+ return nullptr;
+ stream = new QHttp2Stream(this, streamID);
+ stream->m_recvWindow = streamInitialReceiveWindowSize;
+ stream->m_sendWindow = streamInitialSendWindowSize;
+ return stream;
+}
+
+qsizetype QHttp2Connection::numActiveStreamsImpl(quint32 mask) const noexcept
+{
+ const auto shouldCount = [mask](const QPointer<QHttp2Stream> &stream) -> bool {
+ return stream && (stream->streamID() & 1) == mask;
+ };
+ return std::count_if(m_streams.cbegin(), m_streams.cend(), shouldCount);
+}
+
+/*!
+ \internal
+ The number of streams the remote peer has started that are still active.
+*/
+qsizetype QHttp2Connection::numActiveRemoteStreams() const noexcept
+{
+ const quint32 RemoteMask = m_connectionType == Type::Client ? 0 : 1;
+ return numActiveStreamsImpl(RemoteMask);
+}
+
+/*!
+ \internal
+ The number of streams we have started that are still active.
+*/
+qsizetype QHttp2Connection::numActiveLocalStreams() const noexcept
+{
+ const quint32 LocalMask = m_connectionType == Type::Client ? 1 : 0;
+ return numActiveStreamsImpl(LocalMask);
+}
+
+/*!
+ Return a pointer to a stream with the given \a streamID, or null if no such
+ stream exists or it was deleted.
+*/
+QHttp2Stream *QHttp2Connection::getStream(quint32 streamID) const
+{
+ return m_streams.value(streamID, nullptr).get();
+}
+
+
+/*!
+ \fn QHttp2Stream *QHttp2Connection::promisedStream(const QUrl &streamKey) const
+
+ Returns a pointer to the stream that was promised with the given
+ \a streamKey, if any. Otherwise, returns null.
+*/
+
+/*!
+ \fn void QHttp2Connection::close()
+
+ This sends a GOAWAY frame on the connection stream, gracefully closing the
+ connection.
+*/
+
+/*!
+ \fn bool QHttp2Connection::isGoingAway() const noexcept
+
+ Returns \c true if the connection is in the process of being closed, or
+ \c false otherwise.
+*/
+
+/*!
+ \fn quint32 QHttp2Connection::maxConcurrentStreams() const noexcept
+
+ Returns the maximum number of concurrent streams we are allowed to have
+ active at any given time. This is a directional setting, and the remote
+ peer may have a different value.
+*/
+
+/*!
+ \fn quint32 QHttp2Connection::maxHeaderListSize() const noexcept
+
+ Returns the maximum size of the header which the peer is willing to accept.
+*/
+
+/*!
+ \fn bool QHttp2Connection::isUpgradedConnection() const noexcept
+
+ Returns \c true if this connection was created as a result of an HTTP/1
+ upgrade to HTTP/2, or \c false otherwise.
+*/
+
+QHttp2Connection::QHttp2Connection(QIODevice *socket) : QObject(socket)
+{
+ Q_ASSERT(socket);
+ Q_ASSERT(socket->isOpen());
+ Q_ASSERT(socket->openMode() & QIODevice::ReadWrite);
+ // We don't make any connections directly because this is used in
+ // in the http2 protocol handler, which is used by
+ // QHttpNetworkConnectionChannel. Which in turn owns and deals with all the
+ // socket connections.
+}
+
+QHttp2Connection::~QHttp2Connection() noexcept
+{
+ // delete streams now so that any calls it might make back to this
+ // Connection will operate on a valid object.
+ for (QPointer<QHttp2Stream> &stream : std::exchange(m_streams, {}))
+ delete stream.get();
+}
+
+bool QHttp2Connection::serverCheckClientPreface()
+{
+ if (!m_waitingForClientPreface)
+ return true;
+ auto *socket = getSocket();
+ if (socket->bytesAvailable() < Http2::clientPrefaceLength)
+ return false;
+ if (!readClientPreface()) {
+ socket->close();
+ emit errorOccurred(Http2Error::PROTOCOL_ERROR, "invalid client preface"_L1);
+ qCDebug(qHttp2ConnectionLog, "[%p] Invalid client preface", this);
+ return false;
+ }
+ qCDebug(qHttp2ConnectionLog, "[%p] Peer sent valid client preface", this);
+ m_waitingForClientPreface = false;
+ if (!sendServerPreface()) {
+ connectionError(Http2::INTERNAL_ERROR, "Failed to send server preface");
+ return false;
+ }
+ return true;
+}
+
+bool QHttp2Connection::sendPing()
+{
+ std::array<char, 8> data;
+
+ QRandomGenerator gen;
+ gen.generate(data.begin(), data.end());
+ return sendPing(data);
+}
+
+bool QHttp2Connection::sendPing(QByteArrayView data)
+{
+ frameWriter.start(FrameType::PING, FrameFlag::EMPTY, connectionStreamID);
+
+ Q_ASSERT(data.length() == 8);
+ if (!m_lastPingSignature) {
+ m_lastPingSignature = data.toByteArray();
+ } else {
+ qCWarning(qHttp2ConnectionLog, "[%p] No PING is sent while waiting for the previous PING.", this);
+ return false;
+ }
+
+ frameWriter.append((uchar*)data.data(), (uchar*)data.end());
+ frameWriter.write(*getSocket());
+ return true;
+}
+
+/*!
+ This function must be called when you have received a readyRead signal
+ (or equivalent) from the QIODevice. It will read and process any incoming
+ HTTP/2 frames and emit signals as appropriate.
+*/
+void QHttp2Connection::handleReadyRead()
+{
+ /* event loop */
+ if (m_connectionType == Type::Server && !serverCheckClientPreface())
+ return;
+
+ const auto streamIsActive = [](const QPointer<QHttp2Stream> &stream) {
+ return stream && stream->isActive();
+ };
+ if (m_goingAway && std::none_of(m_streams.cbegin(), m_streams.cend(), streamIsActive)) {
+ close();
+ return;
+ }
+ QIODevice *socket = getSocket();
+
+ qCDebug(qHttp2ConnectionLog, "[%p] Receiving data, %lld bytes available", this,
+ socket->bytesAvailable());
+
+ using namespace Http2;
+ while (!m_goingAway || std::any_of(m_streams.cbegin(), m_streams.cend(), streamIsActive)) {
+ const auto result = frameReader.read(*socket);
+ if (result != FrameStatus::goodFrame)
+ qCDebug(qHttp2ConnectionLog, "[%p] Tried to read frame, got %d", this, int(result));
+ switch (result) {
+ case FrameStatus::incompleteFrame:
+ return;
+ case FrameStatus::protocolError:
+ return connectionError(PROTOCOL_ERROR, "invalid frame");
+ case FrameStatus::sizeError:
+ return connectionError(FRAME_SIZE_ERROR, "invalid frame size");
+ default:
+ break;
+ }
+
+ Q_ASSERT(result == FrameStatus::goodFrame);
+
+ inboundFrame = std::move(frameReader.inboundFrame());
+
+ const auto frameType = inboundFrame.type();
+ qCDebug(qHttp2ConnectionLog, "[%p] Successfully read a frame, with type: %d", this,
+ int(frameType));
+ if (continuationExpected && frameType != FrameType::CONTINUATION)
+ return connectionError(PROTOCOL_ERROR, "CONTINUATION expected");
+
+ switch (frameType) {
+ case FrameType::DATA:
+ handleDATA();
+ break;
+ case FrameType::HEADERS:
+ handleHEADERS();
+ break;
+ case FrameType::PRIORITY:
+ handlePRIORITY();
+ break;
+ case FrameType::RST_STREAM:
+ handleRST_STREAM();
+ break;
+ case FrameType::SETTINGS:
+ handleSETTINGS();
+ break;
+ case FrameType::PUSH_PROMISE:
+ handlePUSH_PROMISE();
+ break;
+ case FrameType::PING:
+ handlePING();
+ break;
+ case FrameType::GOAWAY:
+ handleGOAWAY();
+ break;
+ case FrameType::WINDOW_UPDATE:
+ handleWINDOW_UPDATE();
+ break;
+ case FrameType::CONTINUATION:
+ handleCONTINUATION();
+ break;
+ case FrameType::LAST_FRAME_TYPE:
+ // 5.1 - ignore unknown frames.
+ break;
+ }
+ }
+}
+
+bool QHttp2Connection::readClientPreface()
+{
+ auto *socket = getSocket();
+ Q_ASSERT(socket->bytesAvailable() >= Http2::clientPrefaceLength);
+ char buffer[Http2::clientPrefaceLength];
+ const qint64 read = socket->read(buffer, Http2::clientPrefaceLength);
+ if (read != Http2::clientPrefaceLength)
+ return false;
+ return memcmp(buffer, Http2::Http2clientPreface, Http2::clientPrefaceLength) == 0;
+}
+
+/*!
+ This function must be called when the socket has been disconnected, and will
+ end all remaining streams with an error.
+*/
+void QHttp2Connection::handleConnectionClosure()
+{
+ const auto errorString = QCoreApplication::translate("QHttp", "Connection closed");
+ for (auto it = m_streams.begin(), end = m_streams.end(); it != end; ++it) {
+ auto stream = it.value();
+ if (stream && stream->isActive())
+ stream->finishWithError(QNetworkReply::RemoteHostClosedError, errorString);
+ }
+}
+
+void QHttp2Connection::setH2Configuration(QHttp2Configuration config)
+{
+ m_config = std::move(config);
+
+ // These values comes from our own API so trust it to be sane.
+ maxSessionReceiveWindowSize = qint32(m_config.sessionReceiveWindowSize());
+ pushPromiseEnabled = m_config.serverPushEnabled();
+ streamInitialReceiveWindowSize = qint32(m_config.streamReceiveWindowSize());
+ encoder.setCompressStrings(m_config.huffmanCompressionEnabled());
+}
+
+void QHttp2Connection::connectionError(Http2Error errorCode, const char *message)
+{
+ Q_ASSERT(message);
+ if (m_goingAway)
+ return;
+
+ qCCritical(qHttp2ConnectionLog, "[%p] Connection error: %s (%d)", this, message,
+ int(errorCode));
+
+ m_goingAway = true;
+ sendGOAWAY(errorCode);
+ const auto error = qt_error(errorCode);
+ auto messageView = QLatin1StringView(message);
+
+ for (QHttp2Stream *stream : std::as_const(m_streams)) {
+ if (stream && stream->isActive())
+ stream->finishWithError(error, messageView);
+ }
+
+ closeSession();
+}
+
+void QHttp2Connection::closeSession()
+{
+ emit connectionClosed();
+}
+
+bool QHttp2Connection::streamWasReset(quint32 streamID) noexcept
+{
+ return m_resetStreamIDs.contains(streamID);
+}
+
+bool QHttp2Connection::isInvalidStream(quint32 streamID) noexcept
+{
+ auto stream = m_streams.value(streamID, nullptr);
+ return !stream && !streamWasReset(streamID);
+}
+
+bool QHttp2Connection::sendClientPreface()
+{
+ QIODevice *socket = getSocket();
+ // 3.5 HTTP/2 Connection Preface
+ const qint64 written = socket->write(Http2clientPreface, clientPrefaceLength);
+ if (written != clientPrefaceLength)
+ return false;
+
+ if (!sendSETTINGS()) {
+ qCWarning(qHttp2ConnectionLog, "[%p] Failed to send SETTINGS", this);
+ return false;
+ }
+ return true;
+}
+
+bool QHttp2Connection::sendServerPreface()
+{
+ // We send our SETTINGS frame and ACK the client's SETTINGS frame when it
+ // arrives.
+ if (!sendSETTINGS()) {
+ qCWarning(qHttp2ConnectionLog, "[%p] Failed to send SETTINGS", this);
+ return false;
+ }
+ return true;
+}
+
+bool QHttp2Connection::sendSETTINGS()
+{
+ QIODevice *socket = getSocket();
+ // 6.5 SETTINGS
+ frameWriter.setOutboundFrame(configurationToSettingsFrame(m_config));
+ qCDebug(qHttp2ConnectionLog, "[%p] Sending SETTINGS frame, %d bytes", this,
+ frameWriter.outboundFrame().payloadSize());
+ Q_ASSERT(frameWriter.outboundFrame().payloadSize());
+
+ if (!frameWriter.write(*socket))
+ return false;
+
+ sessionReceiveWindowSize = maxSessionReceiveWindowSize;
+ // We only send WINDOW_UPDATE for the connection if the size differs from the
+ // default 64 KB:
+ const auto delta = maxSessionReceiveWindowSize - defaultSessionWindowSize;
+ if (delta && !sendWINDOW_UPDATE(connectionStreamID, delta))
+ return false;
+
+ waitingForSettingsACK = true;
+ return true;
+}
+
+bool QHttp2Connection::sendWINDOW_UPDATE(quint32 streamID, quint32 delta)
+{
+ qCDebug(qHttp2ConnectionLog, "[%p] Sending WINDOW_UPDATE frame, stream %d, delta %u", this,
+ streamID, delta);
+ frameWriter.start(FrameType::WINDOW_UPDATE, FrameFlag::EMPTY, streamID);
+ frameWriter.append(delta);
+ return frameWriter.write(*getSocket());
+}
+
+bool QHttp2Connection::sendGOAWAY(quint32 errorCode)
+{
+ frameWriter.start(FrameType::GOAWAY, FrameFlag::EMPTY,
+ Http2PredefinedParameters::connectionStreamID);
+ frameWriter.append(quint32(m_lastIncomingStreamID));
+ frameWriter.append(errorCode);
+ return frameWriter.write(*getSocket());
+}
+
+bool QHttp2Connection::sendSETTINGS_ACK()
+{
+ frameWriter.start(FrameType::SETTINGS, FrameFlag::ACK, Http2::connectionStreamID);
+ return frameWriter.write(*getSocket());
+}
+
+void QHttp2Connection::handleDATA()
+{
+ Q_ASSERT(inboundFrame.type() == FrameType::DATA);
+
+ const auto streamID = inboundFrame.streamID();
+ if (streamID == connectionStreamID)
+ return connectionError(PROTOCOL_ERROR, "DATA on the connection stream");
+
+ if (isInvalidStream(streamID))
+ return connectionError(ENHANCE_YOUR_CALM, "DATA on invalid stream");
+
+ if (qint32(inboundFrame.payloadSize()) > sessionReceiveWindowSize) {
+ qCDebug(qHttp2ConnectionLog,
+ "[%p] Received DATA frame with payload size %u, "
+ "but recvWindow is %d, sending FLOW_CONTROL_ERROR",
+ this, inboundFrame.payloadSize(), sessionReceiveWindowSize);
+ return connectionError(FLOW_CONTROL_ERROR, "Flow control error");
+ }
+
+ sessionReceiveWindowSize -= inboundFrame.payloadSize();
+
+ auto it = m_streams.constFind(streamID);
+ if (it != m_streams.cend() && it.value())
+ it.value()->handleDATA(inboundFrame);
+
+ if (sessionReceiveWindowSize < maxSessionReceiveWindowSize / 2) {
+ // @future[consider]: emit signal instead
+ QMetaObject::invokeMethod(this, &QHttp2Connection::sendWINDOW_UPDATE, Qt::QueuedConnection,
+ quint32(connectionStreamID),
+ quint32(maxSessionReceiveWindowSize - sessionReceiveWindowSize));
+ sessionReceiveWindowSize = maxSessionReceiveWindowSize;
+ }
+}
+
+void QHttp2Connection::handleHEADERS()
+{
+ Q_ASSERT(inboundFrame.type() == FrameType::HEADERS);
+
+ const auto streamID = inboundFrame.streamID();
+ qCDebug(qHttp2ConnectionLog, "[%p] Received HEADERS frame on stream %d", this, streamID);
+
+ if (streamID == connectionStreamID)
+ return connectionError(PROTOCOL_ERROR, "HEADERS on 0x0 stream");
+
+ const bool isClient = m_connectionType == Type::Client;
+ const bool isClientInitiatedStream = !!(streamID & 1);
+ const bool isRemotelyInitiatedStream = isClient ^ isClientInitiatedStream;
+
+ if (isRemotelyInitiatedStream && streamID > m_lastIncomingStreamID) {
+ QHttp2Stream *newStream = createStreamInternal_impl(streamID);
+ Q_ASSERT(newStream);
+ m_lastIncomingStreamID = streamID;
+ qCDebug(qHttp2ConnectionLog, "[%p] Created new incoming stream %d", this, streamID);
+ emit newIncomingStream(newStream);
+ } else if (auto it = m_streams.constFind(streamID); it == m_streams.cend()) {
+ qCDebug(qHttp2ConnectionLog, "[%p] Received HEADERS on non-existent stream %d", this,
+ streamID);
+ return connectionError(PROTOCOL_ERROR, "HEADERS on invalid stream");
+ } else if (!*it || (*it)->wasReset()) {
+ qCDebug(qHttp2ConnectionLog, "[%p] Received HEADERS on reset stream %d", this, streamID);
+ return connectionError(ENHANCE_YOUR_CALM, "HEADERS on invalid stream");
+ }
+
+ const auto flags = inboundFrame.flags();
+ if (flags.testFlag(FrameFlag::PRIORITY)) {
+ qCDebug(qHttp2ConnectionLog, "[%p] HEADERS frame on stream %d has PRIORITY flag", this,
+ streamID);
+ handlePRIORITY();
+ if (m_goingAway)
+ return;
+ }
+
+ const bool endHeaders = flags.testFlag(FrameFlag::END_HEADERS);
+ continuedFrames.clear();
+ continuedFrames.push_back(std::move(inboundFrame));
+ if (!endHeaders) {
+ continuationExpected = true;
+ return;
+ }
+
+ handleContinuedHEADERS();
+}
+
+void QHttp2Connection::handlePRIORITY()
+{
+ Q_ASSERT(inboundFrame.type() == FrameType::PRIORITY
+ || inboundFrame.type() == FrameType::HEADERS);
+
+ const auto streamID = inboundFrame.streamID();
+ if (streamID == connectionStreamID)
+ return connectionError(PROTOCOL_ERROR, "PRIORITY on 0x0 stream");
+
+ if (isInvalidStream(streamID))
+ return connectionError(ENHANCE_YOUR_CALM, "PRIORITY on invalid stream");
+
+ quint32 streamDependency = 0;
+ uchar weight = 0;
+ const bool noErr = inboundFrame.priority(&streamDependency, &weight);
+ Q_UNUSED(noErr);
+ Q_ASSERT(noErr);
+
+ const bool exclusive = streamDependency & 0x80000000;
+ streamDependency &= ~0x80000000;
+
+ // Ignore this for now ...
+ // Can be used for streams (re)prioritization - 5.3
+ Q_UNUSED(exclusive);
+ Q_UNUSED(weight);
+}
+
+void QHttp2Connection::handleRST_STREAM()
+{
+ Q_ASSERT(inboundFrame.type() == FrameType::RST_STREAM);
+
+ // "RST_STREAM frames MUST be associated with a stream.
+ // If a RST_STREAM frame is received with a stream identifier of 0x0,
+ // the recipient MUST treat this as a connection error (Section 5.4.1)
+ // of type PROTOCOL_ERROR.
+ const auto streamID = inboundFrame.streamID();
+ if (streamID == connectionStreamID)
+ return connectionError(PROTOCOL_ERROR, "RST_STREAM on 0x0");
+
+ if (!(streamID & 0x1)) { // @future[server]: must be updated for server-side handling
+ // RST_STREAM on a promised stream:
+ // since we do not keep track of such streams,
+ // just ignore.
+ return;
+ }
+
+ // Anything greater than m_nextStreamID has not been started yet.
+ if (streamID >= m_nextStreamID) {
+ // "RST_STREAM frames MUST NOT be sent for a stream
+ // in the "idle" state. .. the recipient MUST treat this
+ // as a connection error (Section 5.4.1) of type PROTOCOL_ERROR."
+ return connectionError(PROTOCOL_ERROR, "RST_STREAM on idle stream");
+ }
+
+ Q_ASSERT(inboundFrame.dataSize() == 4);
+
+ if (QPointer<QHttp2Stream> stream = m_streams[streamID])
+ stream->handleRST_STREAM(inboundFrame);
+}
+
+void QHttp2Connection::handleSETTINGS()
+{
+ // 6.5 SETTINGS.
+ Q_ASSERT(inboundFrame.type() == FrameType::SETTINGS);
+
+ if (inboundFrame.streamID() != connectionStreamID)
+ return connectionError(PROTOCOL_ERROR, "SETTINGS on invalid stream");
+
+ if (inboundFrame.flags().testFlag(FrameFlag::ACK)) {
+ if (!waitingForSettingsACK)
+ return connectionError(PROTOCOL_ERROR, "unexpected SETTINGS ACK");
+ qCDebug(qHttp2ConnectionLog, "[%p] Received SETTINGS ACK", this);
+ waitingForSettingsACK = false;
+ return;
+ }
+ qCDebug(qHttp2ConnectionLog, "[%p] Received SETTINGS frame", this);
+
+ if (inboundFrame.dataSize()) {
+ auto src = inboundFrame.dataBegin();
+ for (const uchar *end = src + inboundFrame.dataSize(); src != end; src += 6) {
+ const Settings identifier = Settings(qFromBigEndian<quint16>(src));
+ const quint32 intVal = qFromBigEndian<quint32>(src + 2);
+ if (!acceptSetting(identifier, intVal)) {
+ // If not accepted - we finish with connectionError.
+ qCDebug(qHttp2ConnectionLog, "[%p] Received an unacceptable setting, %u, %u", this,
+ quint32(identifier), intVal);
+ return; // connectionError already called in acceptSetting.
+ }
+ }
+ }
+
+ qCDebug(qHttp2ConnectionLog, "[%p] Sending SETTINGS ACK", this);
+ emit settingsFrameReceived();
+ sendSETTINGS_ACK();
+}
+
+void QHttp2Connection::handlePUSH_PROMISE()
+{
+ // 6.6 PUSH_PROMISE.
+ Q_ASSERT(inboundFrame.type() == FrameType::PUSH_PROMISE);
+
+ if (!pushPromiseEnabled && !waitingForSettingsACK) {
+ // This means, server ACKed our 'NO PUSH',
+ // but sent us PUSH_PROMISE anyway.
+ return connectionError(PROTOCOL_ERROR, "unexpected PUSH_PROMISE frame");
+ }
+
+ const auto streamID = inboundFrame.streamID();
+ if (streamID == connectionStreamID)
+ return connectionError(PROTOCOL_ERROR, "PUSH_PROMISE with invalid associated stream (0x0)");
+
+ auto it = m_streams.constFind(streamID);
+#if 0 // Needs to be done after some timeout in case the stream has only just been reset
+ if (it != m_streams.constEnd()) {
+ QHttp2Stream *associatedStream = it->get();
+ if (associatedStream->state() != QHttp2Stream::State::Open
+ && associatedStream->state() != QHttp2Stream::State::HalfClosedLocal) {
+ // Cause us to error out below:
+ it = m_streams.constEnd();
+ }
+ }
+#endif
+ if (it == m_streams.constEnd())
+ return connectionError(ENHANCE_YOUR_CALM, "PUSH_PROMISE with invalid associated stream");
+
+ const auto reservedID = qFromBigEndian<quint32>(inboundFrame.dataBegin());
+ if ((reservedID & 1) || reservedID <= m_lastIncomingStreamID || reservedID > lastValidStreamID)
+ return connectionError(PROTOCOL_ERROR, "PUSH_PROMISE with invalid promised stream ID");
+
+ auto *stream = createStreamInternal_impl(reservedID);
+ if (!stream)
+ return connectionError(PROTOCOL_ERROR, "PUSH_PROMISE with already active stream ID");
+ m_lastIncomingStreamID = reservedID;
+ stream->setState(QHttp2Stream::State::ReservedRemote);
+
+ if (!pushPromiseEnabled) {
+ // "ignoring a PUSH_PROMISE frame causes the stream state to become
+ // indeterminate" - let's send RST_STREAM frame with REFUSE_STREAM code.
+ stream->sendRST_STREAM(REFUSE_STREAM);
+ }
+
+ const bool endHeaders = inboundFrame.flags().testFlag(FrameFlag::END_HEADERS);
+ continuedFrames.clear();
+ continuedFrames.push_back(std::move(inboundFrame));
+
+ if (!endHeaders) {
+ continuationExpected = true;
+ return;
+ }
+
+ handleContinuedHEADERS();
+}
+
+void QHttp2Connection::handlePING()
+{
+ Q_ASSERT(inboundFrame.type() == FrameType::PING);
+ Q_ASSERT(inboundFrame.dataSize() == 8);
+
+ if (inboundFrame.streamID() != connectionStreamID)
+ return connectionError(PROTOCOL_ERROR, "PING on invalid stream");
+
+ if (inboundFrame.flags() & FrameFlag::ACK) {
+ QByteArrayView pingSignature(reinterpret_cast<const char *>(inboundFrame.dataBegin()), 8);
+ if (!m_lastPingSignature.has_value()) {
+ emit pingFrameRecived(PingState::PongNoPingSent);
+ qCWarning(qHttp2ConnectionLog, "[%p] PING with ACK received but no PING was sent.", this);
+ } else if (pingSignature != m_lastPingSignature) {
+ emit pingFrameRecived(PingState::PongSignatureChanged);
+ qCWarning(qHttp2ConnectionLog, "[%p] PING signature does not match the last PING.", this);
+ } else {
+ emit pingFrameRecived(PingState::PongSignatureIdentical);
+ }
+ m_lastPingSignature.reset();
+ return;
+ } else {
+ emit pingFrameRecived(PingState::Ping);
+
+ }
+
+
+ frameWriter.start(FrameType::PING, FrameFlag::ACK, connectionStreamID);
+ frameWriter.append(inboundFrame.dataBegin(), inboundFrame.dataBegin() + 8);
+ frameWriter.write(*getSocket());
+}
+
+void QHttp2Connection::handleGOAWAY()
+{
+ // 6.8 GOAWAY
+
+ Q_ASSERT(inboundFrame.type() == FrameType::GOAWAY);
+ // "An endpoint MUST treat a GOAWAY frame with a stream identifier
+ // other than 0x0 as a connection error (Section 5.4.1) of type PROTOCOL_ERROR."
+ if (inboundFrame.streamID() != connectionStreamID)
+ return connectionError(PROTOCOL_ERROR, "GOAWAY on invalid stream");
+
+ const uchar *const src = inboundFrame.dataBegin();
+ quint32 lastStreamID = qFromBigEndian<quint32>(src);
+ const quint32 errorCode = qFromBigEndian<quint32>(src + 4);
+
+ if (!lastStreamID) {
+ // "The last stream identifier can be set to 0 if no
+ // streams were processed."
+ lastStreamID = 1;
+ } else if (!(lastStreamID & 0x1)) {
+ // 5.1.1 - we (client) use only odd numbers as stream identifiers.
+ return connectionError(PROTOCOL_ERROR, "GOAWAY with invalid last stream ID");
+ } else if (lastStreamID >= m_nextStreamID) {
+ // "A server that is attempting to gracefully shut down a connection SHOULD
+ // send an initial GOAWAY frame with the last stream identifier set to 2^31-1
+ // and a NO_ERROR code."
+ if (lastStreamID != lastValidStreamID || errorCode != HTTP2_NO_ERROR)
+ return connectionError(PROTOCOL_ERROR, "GOAWAY invalid stream/error code");
+ } else {
+ lastStreamID += 2;
+ }
+
+ m_goingAway = true;
+
+ emit receivedGOAWAY(errorCode, lastStreamID);
+
+ for (quint32 id = lastStreamID; id < m_nextStreamID; id += 2) {
+ QHttp2Stream *stream = m_streams.value(id, nullptr);
+ if (stream && stream->isActive())
+ stream->finishWithError(errorCode, "Received GOAWAY"_L1);
+ }
+
+ const auto isActive = [](const QHttp2Stream *stream) { return stream && stream->isActive(); };
+ if (std::none_of(m_streams.cbegin(), m_streams.cend(), isActive))
+ closeSession();
+}
+
+void QHttp2Connection::handleWINDOW_UPDATE()
+{
+ Q_ASSERT(inboundFrame.type() == FrameType::WINDOW_UPDATE);
+
+ const quint32 delta = qFromBigEndian<quint32>(inboundFrame.dataBegin());
+ const bool valid = delta && delta <= quint32(std::numeric_limits<qint32>::max());
+ const auto streamID = inboundFrame.streamID();
+
+ qCDebug(qHttp2ConnectionLog(), "[%p] Received WINDOW_UPDATE, stream %d, delta %d", this,
+ streamID, delta);
+ if (streamID == connectionStreamID) {
+ qint32 sum = 0;
+ if (!valid || qAddOverflow(sessionSendWindowSize, qint32(delta), &sum))
+ return connectionError(PROTOCOL_ERROR, "WINDOW_UPDATE invalid delta");
+ sessionSendWindowSize = sum;
+ for (auto &stream : m_streams) {
+ if (!stream || !stream->isActive())
+ continue;
+ // Stream may have been unblocked, so maybe try to write again
+ if (stream->isUploadingDATA() && !stream->isUploadBlocked())
+ QMetaObject::invokeMethod(stream, &QHttp2Stream::maybeResumeUpload,
+ Qt::QueuedConnection);
+ }
+ } else {
+ QHttp2Stream *stream = m_streams.value(streamID);
+ if (!stream || !stream->isActive()) {
+ // WINDOW_UPDATE on closed streams can be ignored.
+ qCDebug(qHttp2ConnectionLog, "[%p] Received WINDOW_UPDATE on closed stream %d", this,
+ streamID);
+ return;
+ }
+ stream->handleWINDOW_UPDATE(inboundFrame);
+ }
+}
+
+void QHttp2Connection::handleCONTINUATION()
+{
+ Q_ASSERT(inboundFrame.type() == FrameType::CONTINUATION);
+ if (continuedFrames.empty())
+ return connectionError(PROTOCOL_ERROR,
+ "CONTINUATION without a preceding HEADERS or PUSH_PROMISE");
+
+ if (inboundFrame.streamID() != continuedFrames.front().streamID())
+ return connectionError(PROTOCOL_ERROR, "CONTINUATION on invalid stream");
+
+ const bool endHeaders = inboundFrame.flags().testFlag(FrameFlag::END_HEADERS);
+ continuedFrames.push_back(std::move(inboundFrame));
+
+ if (!endHeaders)
+ return;
+
+ continuationExpected = false;
+ handleContinuedHEADERS();
+}
+
+void QHttp2Connection::handleContinuedHEADERS()
+{
+ // 'Continued' HEADERS can be: the initial HEADERS/PUSH_PROMISE frame
+ // with/without END_HEADERS flag set plus, if no END_HEADERS flag,
+ // a sequence of one or more CONTINUATION frames.
+ Q_ASSERT(!continuedFrames.empty());
+ const auto firstFrameType = continuedFrames[0].type();
+ Q_ASSERT(firstFrameType == FrameType::HEADERS || firstFrameType == FrameType::PUSH_PROMISE);
+
+ const auto streamID = continuedFrames[0].streamID();
+
+ const auto streamIt = m_streams.constFind(streamID);
+ if (firstFrameType == FrameType::HEADERS) {
+ if (streamIt != m_streams.cend()) {
+ QHttp2Stream *stream = streamIt.value();
+ if (stream->state() != QHttp2Stream::State::HalfClosedLocal
+ && stream->state() != QHttp2Stream::State::ReservedRemote
+ && stream->state() != QHttp2Stream::State::Idle
+ && stream->state() != QHttp2Stream::State::Open) {
+ // We can receive HEADERS on streams initiated by our requests
+ // (these streams are in halfClosedLocal or open state) or
+ // remote-reserved streams from a server's PUSH_PROMISE.
+ stream->finishWithError(QNetworkReply::ProtocolFailure,
+ "HEADERS on invalid stream"_L1);
+ stream->sendRST_STREAM(CANCEL);
+ return;
+ }
+ }
+ // Else: we cannot just ignore our peer's HEADERS frames - they change
+ // HPACK context - even though the stream was reset; apparently the peer
+ // has yet to see the reset.
+ }
+
+ std::vector<uchar> hpackBlock(assemble_hpack_block(continuedFrames));
+ const bool hasHeaderFields = !hpackBlock.empty();
+ if (hasHeaderFields) {
+ HPack::BitIStream inputStream{ hpackBlock.data(), hpackBlock.data() + hpackBlock.size() };
+ if (!decoder.decodeHeaderFields(inputStream))
+ return connectionError(COMPRESSION_ERROR, "HPACK decompression failed");
+ } else {
+ if (firstFrameType == FrameType::PUSH_PROMISE) {
+ // It could be a PRIORITY sent in HEADERS - already handled by this
+ // point in handleHEADERS. If it was PUSH_PROMISE (HTTP/2 8.2.1):
+ // "The header fields in PUSH_PROMISE and any subsequent CONTINUATION
+ // frames MUST be a valid and complete set of request header fields
+ // (Section 8.1.2.3) ... If a client receives a PUSH_PROMISE that does
+ // not include a complete and valid set of header fields or the :method
+ // pseudo-header field identifies a method that is not safe, it MUST
+ // respond with a stream error (Section 5.4.2) of type PROTOCOL_ERROR."
+ if (streamIt != m_streams.cend())
+ (*streamIt)->sendRST_STREAM(PROTOCOL_ERROR);
+ return;
+ }
+
+ // We got back an empty hpack block. Now let's figure out if there was an error.
+ constexpr auto hpackBlockHasContent = [](const auto &c) { return c.hpackBlockSize() > 0; };
+ const bool anyHpackBlock = std::any_of(continuedFrames.cbegin(), continuedFrames.cend(),
+ hpackBlockHasContent);
+ if (anyHpackBlock) // There was hpack block data, but returned empty => it overflowed.
+ return connectionError(FRAME_SIZE_ERROR, "HEADERS frame too large");
+ }
+
+ if (streamIt == m_streams.cend()) // No more processing without a stream from here on.
+ return;
+
+ switch (firstFrameType) {
+ case FrameType::HEADERS:
+ streamIt.value()->handleHEADERS(continuedFrames[0].flags(), decoder.decodedHeader());
+ break;
+ case FrameType::PUSH_PROMISE: {
+ std::optional<QUrl> promiseKey = HPack::makePromiseKeyUrl(decoder.decodedHeader());
+ if (!promiseKey)
+ return; // invalid URL/key !
+ if (m_promisedStreams.contains(*promiseKey))
+ return; // already promised!
+ const auto promiseID = qFromBigEndian<quint32>(continuedFrames[0].dataBegin());
+ QHttp2Stream *stream = m_streams.value(promiseID);
+ stream->transitionState(QHttp2Stream::StateTransition::CloseLocal);
+ stream->handleHEADERS(continuedFrames[0].flags(), decoder.decodedHeader());
+ emit newPromisedStream(stream); // @future[consider] add promise key as argument?
+ m_promisedStreams.emplace(*promiseKey, promiseID);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+bool QHttp2Connection::acceptSetting(Http2::Settings identifier, quint32 newValue)
+{
+ switch (identifier) {
+ case Settings::HEADER_TABLE_SIZE_ID: {
+ qCDebug(qHttp2ConnectionLog, "[%p] Received SETTINGS HEADER_TABLE_SIZE %d", this, newValue);
+ if (newValue > maxAcceptableTableSize) {
+ connectionError(PROTOCOL_ERROR, "SETTINGS invalid table size");
+ return false;
+ }
+ encoder.setMaxDynamicTableSize(newValue);
+ break;
+ }
+ case Settings::INITIAL_WINDOW_SIZE_ID: {
+ qCDebug(qHttp2ConnectionLog, "[%p] Received SETTINGS INITIAL_WINDOW_SIZE %d", this,
+ newValue);
+ // For every active stream - adjust its window
+ // (and handle possible overflows as errors).
+ if (newValue > quint32(std::numeric_limits<qint32>::max())) {
+ connectionError(FLOW_CONTROL_ERROR, "SETTINGS invalid initial window size");
+ return false;
+ }
+
+ const qint32 delta = qint32(newValue) - streamInitialSendWindowSize;
+ streamInitialSendWindowSize = qint32(newValue);
+
+ qCDebug(qHttp2ConnectionLog, "[%p] Adjusting initial window size for %zu streams by %d",
+ this, size_t(m_streams.size()), delta);
+ for (const QPointer<QHttp2Stream> &stream : std::as_const(m_streams)) {
+ if (!stream || !stream->isActive())
+ continue;
+ qint32 sum = 0;
+ if (qAddOverflow(stream->m_sendWindow, delta, &sum)) {
+ stream->sendRST_STREAM(PROTOCOL_ERROR);
+ stream->finishWithError(QNetworkReply::ProtocolFailure,
+ "SETTINGS window overflow"_L1);
+ continue;
+ }
+ stream->m_sendWindow = sum;
+ if (delta > 0 && stream->isUploadingDATA() && !stream->isUploadBlocked()) {
+ QMetaObject::invokeMethod(stream, &QHttp2Stream::maybeResumeUpload,
+ Qt::QueuedConnection);
+ }
+ }
+ break;
+ }
+ case Settings::MAX_CONCURRENT_STREAMS_ID: {
+ qCDebug(qHttp2ConnectionLog, "[%p] Received SETTINGS MAX_CONCURRENT_STREAMS %d", this,
+ newValue);
+ m_maxConcurrentStreams = newValue;
+ break;
+ }
+ case Settings::MAX_FRAME_SIZE_ID: {
+ qCDebug(qHttp2ConnectionLog, "[%p] Received SETTINGS MAX_FRAME_SIZE %d", this, newValue);
+ if (newValue < Http2::minPayloadLimit || newValue > Http2::maxPayloadSize) {
+ connectionError(PROTOCOL_ERROR, "SETTINGS max frame size is out of range");
+ return false;
+ }
+ maxFrameSize = newValue;
+ break;
+ }
+ case Settings::MAX_HEADER_LIST_SIZE_ID: {
+ qCDebug(qHttp2ConnectionLog, "[%p] Received SETTINGS MAX_HEADER_LIST_SIZE %d", this,
+ newValue);
+ // We just remember this value, it can later
+ // prevent us from sending any request (and this
+ // will end up in request/reply error).
+ m_maxHeaderListSize = newValue;
+ break;
+ }
+ case Http2::Settings::ENABLE_PUSH_ID:
+ qCDebug(qHttp2ConnectionLog, "[%p] Received SETTINGS ENABLE_PUSH %d", this, newValue);
+ if (newValue != 0 && newValue != 1) {
+ connectionError(PROTOCOL_ERROR, "SETTINGS peer sent illegal value for ENABLE_PUSH");
+ return false;
+ }
+ if (m_connectionType == Type::Client) {
+ if (newValue == 1) {
+ connectionError(PROTOCOL_ERROR, "SETTINGS server sent ENABLE_PUSH=1");
+ return false;
+ }
+ } else { // server-side
+ pushPromiseEnabled = newValue;
+ break;
+ }
+ }
+
+ return true;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qhttp2connection_p.cpp"
diff --git a/src/network/access/qhttp2connection_p.h b/src/network/access/qhttp2connection_p.h
new file mode 100644
index 0000000000..ca2cae58e0
--- /dev/null
+++ b/src/network/access/qhttp2connection_p.h
@@ -0,0 +1,372 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef HTTP2CONNECTION_P_H
+#define HTTP2CONNECTION_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the Network Access API. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qtnetworkglobal_p.h>
+
+#include <QtCore/qobject.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qxpfunctional.h>
+#include <QtNetwork/qhttp2configuration.h>
+#include <QtNetwork/qtcpsocket.h>
+
+#include <private/http2protocol_p.h>
+#include <private/http2streams_p.h>
+#include <private/http2frames_p.h>
+#include <private/hpack_p.h>
+
+#include <variant>
+#include <optional>
+#include <type_traits>
+#include <limits>
+
+QT_BEGIN_NAMESPACE
+
+template <typename T, typename Err>
+class QH2Expected
+{
+ static_assert(!std::is_same_v<T, Err>, "T and Err must be different types");
+public:
+ // Rule Of Zero applies
+ QH2Expected(T &&value) : m_data(std::move(value)) { }
+ QH2Expected(const T &value) : m_data(value) { }
+ QH2Expected(Err &&error) : m_data(std::move(error)) { }
+ QH2Expected(const Err &error) : m_data(error) { }
+
+ QH2Expected &operator=(T &&value)
+ {
+ m_data = std::move(value);
+ return *this;
+ }
+ QH2Expected &operator=(const T &value)
+ {
+ m_data = value;
+ return *this;
+ }
+ QH2Expected &operator=(Err &&error)
+ {
+ m_data = std::move(error);
+ return *this;
+ }
+ QH2Expected &operator=(const Err &error)
+ {
+ m_data = error;
+ return *this;
+ }
+ T unwrap() const
+ {
+ Q_ASSERT(ok());
+ return std::get<T>(m_data);
+ }
+ Err error() const
+ {
+ Q_ASSERT(has_error());
+ return std::get<Err>(m_data);
+ }
+ bool ok() const noexcept { return std::holds_alternative<T>(m_data); }
+ bool has_value() const noexcept { return ok(); }
+ bool has_error() const noexcept { return std::holds_alternative<Err>(m_data); }
+ void clear() noexcept { m_data.reset(); }
+
+private:
+ std::variant<T, Err> m_data;
+};
+
+class QHttp2Connection;
+class Q_NETWORK_EXPORT QHttp2Stream : public QObject
+{
+ Q_OBJECT
+ Q_DISABLE_COPY_MOVE(QHttp2Stream)
+
+public:
+ enum class State { Idle, ReservedRemote, Open, HalfClosedLocal, HalfClosedRemote, Closed };
+ Q_ENUM(State)
+ constexpr static quint8 DefaultPriority = 127;
+
+ ~QHttp2Stream() noexcept;
+
+ // HTTP2 things
+ quint32 streamID() const noexcept { return m_streamID; }
+
+ // Are we waiting for a larger send window before sending more data?
+ bool isUploadBlocked() const noexcept;
+ bool isUploadingDATA() const noexcept { return m_uploadByteDevice != nullptr; }
+ State state() const noexcept { return m_state; }
+ bool isActive() const noexcept { return m_state != State::Closed && m_state != State::Idle; }
+ bool isPromisedStream() const noexcept { return m_isReserved; }
+ bool wasReset() const noexcept { return m_RST_STREAM_code.has_value(); }
+ quint32 RST_STREAM_code() const noexcept { return m_RST_STREAM_code.value_or(0); }
+ // Just the list of headers, as received, may contain duplicates:
+ HPack::HttpHeader receivedHeaders() const noexcept { return m_headers; }
+
+ QByteDataBuffer downloadBuffer() const noexcept { return m_downloadBuffer; }
+
+Q_SIGNALS:
+ void headersReceived(const HPack::HttpHeader &headers, bool endStream);
+ void headersUpdated();
+ void errorOccurred(quint32 errorCode, const QString &errorString);
+ void stateChanged(QHttp2Stream::State newState);
+ void promisedStreamReceived(quint32 newStreamID);
+ void uploadBlocked();
+ void dataReceived(const QByteArray &data, bool endStream);
+
+ void bytesWritten(qint64 bytesWritten);
+ void uploadDeviceError(const QString &errorString);
+ void uploadFinished();
+
+public Q_SLOTS:
+ bool sendRST_STREAM(quint32 errorCode);
+ bool sendHEADERS(const HPack::HttpHeader &headers, bool endStream,
+ quint8 priority = DefaultPriority);
+ void sendDATA(QIODevice *device, bool endStream);
+ void sendDATA(QNonContiguousByteDevice *device, bool endStream);
+ void sendWINDOW_UPDATE(quint32 delta);
+
+private Q_SLOTS:
+ void maybeResumeUpload();
+ void uploadDeviceReadChannelFinished();
+ void uploadDeviceDestroyed();
+
+private:
+ friend class QHttp2Connection;
+ QHttp2Stream(QHttp2Connection *connection, quint32 streamID) noexcept;
+
+ [[nodiscard]] QHttp2Connection *getConnection() const
+ {
+ return qobject_cast<QHttp2Connection *>(parent());
+ }
+
+ enum class StateTransition {
+ Open,
+ CloseLocal,
+ CloseRemote,
+ RST,
+ };
+
+ void setState(State newState);
+ void transitionState(StateTransition transition);
+ void internalSendDATA();
+ void finishSendDATA();
+
+ void handleDATA(const Http2::Frame &inboundFrame);
+ void handleHEADERS(Http2::FrameFlags frameFlags, const HPack::HttpHeader &headers);
+ void handleRST_STREAM(const Http2::Frame &inboundFrame);
+ void handleWINDOW_UPDATE(const Http2::Frame &inboundFrame);
+
+ void finishWithError(quint32 errorCode, const QString &message);
+ void finishWithError(quint32 errorCode);
+
+ // Keep it const since it never changes after creation
+ const quint32 m_streamID = 0;
+ qint32 m_recvWindow = 0;
+ qint32 m_sendWindow = 0;
+ bool m_endStreamAfterDATA = false;
+ std::optional<quint32> m_RST_STREAM_code;
+
+ QIODevice *m_uploadDevice = nullptr;
+ QNonContiguousByteDevice *m_uploadByteDevice = nullptr;
+
+ QByteDataBuffer m_downloadBuffer;
+ State m_state = State::Idle;
+ HPack::HttpHeader m_headers;
+ bool m_isReserved = false;
+};
+
+class Q_NETWORK_EXPORT QHttp2Connection : public QObject
+{
+ Q_OBJECT
+ Q_DISABLE_COPY_MOVE(QHttp2Connection)
+
+public:
+ enum class CreateStreamError {
+ MaxConcurrentStreamsReached,
+ StreamIdsExhausted,
+ ReceivedGOAWAY,
+ };
+ Q_ENUM(CreateStreamError)
+
+ enum class PingState {
+ Ping,
+ PongSignatureIdentical,
+ PongSignatureChanged,
+ PongNoPingSent, // We got an ACKed ping but had not sent any
+ };
+
+ // For a pre-established connection:
+ [[nodiscard]] static QHttp2Connection *
+ createUpgradedConnection(QIODevice *socket, const QHttp2Configuration &config);
+ // For a new connection, potential TLS handshake must already be finished:
+ [[nodiscard]] static QHttp2Connection *createDirectConnection(QIODevice *socket,
+ const QHttp2Configuration &config);
+ [[nodiscard]] static QHttp2Connection *
+ createDirectServerConnection(QIODevice *socket, const QHttp2Configuration &config);
+ ~QHttp2Connection();
+
+ [[nodiscard]] QH2Expected<QHttp2Stream *, CreateStreamError> createStream();
+
+ QHttp2Stream *getStream(quint32 streamId) const;
+ QHttp2Stream *promisedStream(const QUrl &streamKey) const
+ {
+ if (quint32 id = m_promisedStreams.value(streamKey, 0); id)
+ return m_streams.value(id);
+ return nullptr;
+ }
+
+ void close() { sendGOAWAY(Http2::HTTP2_NO_ERROR); }
+
+ bool isGoingAway() const noexcept { return m_goingAway; }
+
+ quint32 maxConcurrentStreams() const noexcept { return m_maxConcurrentStreams; }
+ quint32 maxHeaderListSize() const noexcept { return m_maxHeaderListSize; }
+
+ bool isUpgradedConnection() const noexcept { return m_upgradedConnection; }
+
+Q_SIGNALS:
+ void newIncomingStream(QHttp2Stream *stream);
+ void newPromisedStream(QHttp2Stream *stream);
+ void errorReceived(/*@future: add as needed?*/); // Connection errors only, no stream-specific errors
+ void connectionClosed();
+ void settingsFrameReceived();
+ void pingFrameRecived(QHttp2Connection::PingState state);
+ void errorOccurred(Http2::Http2Error errorCode, const QString &errorString);
+ void receivedGOAWAY(quint32 errorCode, quint32 lastStreamID);
+public Q_SLOTS:
+ bool sendPing();
+ bool sendPing(QByteArrayView data);
+ void handleReadyRead();
+ void handleConnectionClosure();
+
+private:
+ friend class QHttp2Stream;
+ [[nodiscard]] QIODevice *getSocket() const { return qobject_cast<QIODevice *>(parent()); }
+
+ QH2Expected<QHttp2Stream *, QHttp2Connection::CreateStreamError> createStreamInternal();
+ QHttp2Stream *createStreamInternal_impl(quint32 streamID);
+
+ bool isInvalidStream(quint32 streamID) noexcept;
+ bool streamWasReset(quint32 streamID) noexcept;
+
+ void connectionError(Http2::Http2Error errorCode,
+ const char *message); // Connection failed to be established?
+ void setH2Configuration(QHttp2Configuration config);
+ void closeSession();
+ qsizetype numActiveStreamsImpl(quint32 mask) const noexcept;
+ qsizetype numActiveRemoteStreams() const noexcept;
+ qsizetype numActiveLocalStreams() const noexcept;
+
+ bool sendClientPreface();
+ bool sendSETTINGS();
+ bool sendServerPreface();
+ bool serverCheckClientPreface();
+ bool sendWINDOW_UPDATE(quint32 streamID, quint32 delta);
+ bool sendGOAWAY(quint32 errorCode);
+ bool sendSETTINGS_ACK();
+
+ void handleDATA();
+ void handleHEADERS();
+ void handlePRIORITY();
+ void handleRST_STREAM();
+ void handleSETTINGS();
+ void handlePUSH_PROMISE();
+ void handlePING();
+ void handleGOAWAY();
+ void handleWINDOW_UPDATE();
+ void handleCONTINUATION();
+
+ void handleContinuedHEADERS();
+
+ bool acceptSetting(Http2::Settings identifier, quint32 newValue);
+
+ bool readClientPreface();
+
+ explicit QHttp2Connection(QIODevice *socket);
+
+ enum class Type { Client, Server } m_connectionType = Type::Client;
+
+ bool waitingForSettingsACK = false;
+
+ static constexpr quint32 maxAcceptableTableSize = 16 * HPack::FieldLookupTable::DefaultSize;
+ // HTTP/2 4.3: Header compression is stateful. One compression context and
+ // one decompression context are used for the entire connection.
+ HPack::Decoder decoder = HPack::Decoder(HPack::FieldLookupTable::DefaultSize);
+ HPack::Encoder encoder = HPack::Encoder(HPack::FieldLookupTable::DefaultSize, true);
+
+ QHttp2Configuration m_config;
+ QHash<quint32, QPointer<QHttp2Stream>> m_streams;
+ QHash<QUrl, quint32> m_promisedStreams;
+ QVarLengthArray<quint32> m_resetStreamIDs;
+ std::optional<QByteArray> m_lastPingSignature = std::nullopt;
+ quint32 m_nextStreamID = 1;
+
+ // Peer's max frame size (this min is the default value
+ // we start with, that can be updated by SETTINGS frame):
+ quint32 maxFrameSize = Http2::minPayloadLimit;
+
+ Http2::FrameReader frameReader;
+ Http2::Frame inboundFrame;
+ Http2::FrameWriter frameWriter;
+
+ // Temporary storage to assemble HEADERS' block
+ // from several CONTINUATION frames ...
+ bool continuationExpected = false;
+ std::vector<Http2::Frame> continuedFrames;
+
+ // Control flow:
+
+ // This is how many concurrent streams our peer allows us, 100 is the
+ // initial value, can be updated by the server's SETTINGS frame(s):
+ quint32 m_maxConcurrentStreams = Http2::maxConcurrentStreams;
+ // While we allow sending SETTTINGS_MAX_CONCURRENT_STREAMS to limit our peer,
+ // it's just a hint and we do not actually enforce it (and we can continue
+ // sending requests and creating streams while maxConcurrentStreams allows).
+
+ // This is our (client-side) maximum possible receive window size, we set
+ // it in a ctor from QHttp2Configuration, it does not change after that.
+ // The default is 64Kb:
+ qint32 maxSessionReceiveWindowSize = Http2::defaultSessionWindowSize;
+
+ // Our session current receive window size, updated in a ctor from
+ // QHttp2Configuration. Signed integer since it can become negative
+ // (it's still a valid window size).
+ qint32 sessionReceiveWindowSize = Http2::defaultSessionWindowSize;
+ // Our per-stream receive window size, default is 64 Kb, will be updated
+ // from QHttp2Configuration. Again, signed - can become negative.
+ qint32 streamInitialReceiveWindowSize = Http2::defaultSessionWindowSize;
+
+ // These are our peer's receive window sizes, they will be updated by the
+ // peer's SETTINGS and WINDOW_UPDATE frames, defaults presumed to be 64Kb.
+ qint32 sessionSendWindowSize = Http2::defaultSessionWindowSize;
+ qint32 streamInitialSendWindowSize = Http2::defaultSessionWindowSize;
+
+ // Our peer's header size limitations. It's unlimited by default, but can
+ // be changed via peer's SETTINGS frame.
+ quint32 m_maxHeaderListSize = (std::numeric_limits<quint32>::max)();
+ // While we can send SETTINGS_MAX_HEADER_LIST_SIZE value (our limit on
+ // the headers size), we never enforce it, it's just a hint to our peer.
+
+ bool m_upgradedConnection = false;
+ bool m_goingAway = false;
+ bool pushPromiseEnabled = false;
+ quint32 m_lastIncomingStreamID = Http2::connectionStreamID;
+
+ // Server-side only:
+ bool m_waitingForClientPreface = false;
+};
+
+QT_END_NAMESPACE
+
+#endif // HTTP2CONNECTION_P_H
diff --git a/src/network/access/qhttp2protocolhandler.cpp b/src/network/access/qhttp2protocolhandler.cpp
index de6b5ac18f..d9341dc643 100644
--- a/src/network/access/qhttp2protocolhandler.cpp
+++ b/src/network/access/qhttp2protocolhandler.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qhttpnetworkconnection_p.h"
#include "qhttp2protocolhandler_p.h"
@@ -46,10 +10,12 @@
#include <private/qnoncontiguousbytedevice_p.h>
#include <QtNetwork/qabstractsocket.h>
+
#include <QtCore/qloggingcategory.h>
#include <QtCore/qendian.h>
#include <QtCore/qdebug.h>
#include <QtCore/qlist.h>
+#include <QtCore/qnumeric.h>
#include <QtCore/qurl.h>
#include <qhttp2configuration.h>
@@ -62,9 +28,12 @@
#include <algorithm>
#include <vector>
+#include <optional>
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
namespace
{
@@ -79,10 +48,10 @@ HPack::HttpHeader build_headers(const QHttpNetworkRequest &request, quint32 maxH
// 1. Before anything - mandatory fields, if they do not fit into maxHeaderList -
// then stop immediately with error.
const auto auth = request.url().authority(QUrl::FullyEncoded | QUrl::RemoveUserInfo).toLatin1();
- header.push_back(HeaderField(":authority", auth));
- header.push_back(HeaderField(":method", request.methodName()));
- header.push_back(HeaderField(":path", request.uri(useProxy)));
- header.push_back(HeaderField(":scheme", request.url().scheme().toLatin1()));
+ header.emplace_back(":authority", auth);
+ header.emplace_back(":method", request.methodName());
+ header.emplace_back(":path", request.uri(useProxy));
+ header.emplace_back(":scheme", request.url().scheme().toLatin1());
HeaderSize size = header_size(header);
if (!size.first) // Ooops!
@@ -91,9 +60,11 @@ HPack::HttpHeader build_headers(const QHttpNetworkRequest &request, quint32 maxH
if (size.second > maxHeaderListSize)
return HttpHeader(); // Bad, we cannot send this request ...
- const auto requestHeader = request.header();
- for (const auto &field : requestHeader) {
- const HeaderSize delta = entry_size(field.first, field.second);
+ const QHttpHeaders requestHeader = request.header();
+ for (qsizetype i = 0; i < requestHeader.size(); ++i) {
+ const auto name = requestHeader.nameAt(i);
+ const auto value = requestHeader.valueAt(i);
+ const HeaderSize delta = entry_size(name, value);
if (!delta.first) // Overflow???
break;
if (std::numeric_limits<quint32>::max() - delta.second < size.second)
@@ -102,73 +73,38 @@ HPack::HttpHeader build_headers(const QHttpNetworkRequest &request, quint32 maxH
if (size.second > maxHeaderListSize)
break;
- if (field.first.compare("connection", Qt::CaseInsensitive) == 0 ||
- field.first.compare("host", Qt::CaseInsensitive) == 0 ||
- field.first.compare("keep-alive", Qt::CaseInsensitive) == 0 ||
- field.first.compare("proxy-connection", Qt::CaseInsensitive) == 0 ||
- field.first.compare("transfer-encoding", Qt::CaseInsensitive) == 0)
+ if (name == "connection"_L1 || name == "host"_L1 || name == "keep-alive"_L1
+ || name == "proxy-connection"_L1 || name == "transfer-encoding"_L1) {
continue; // Those headers are not valid (section 3.2.1) - from QSpdyProtocolHandler
+ }
// TODO: verify with specs, which fields are valid to send ....
- // toLower - 8.1.2 .... "header field names MUST be converted to lowercase prior
- // to their encoding in HTTP/2.
- // A request or response containing uppercase header field names
- // MUST be treated as malformed (Section 8.1.2.6)".
- header.push_back(HeaderField(field.first.toLower(), field.second));
+ //
+ // Note: RFC 7450 8.1.2 (HTTP/2) states that header field names must be lower-cased
+ // prior to their encoding in HTTP/2; header name fields in QHttpHeaders are already
+ // lower-cased
+ header.emplace_back(QByteArray{name.data(), name.size()},
+ QByteArray{value.data(), value.size()});
}
return header;
}
-std::vector<uchar> assemble_hpack_block(const std::vector<Http2::Frame> &frames)
-{
- std::vector<uchar> hpackBlock;
-
- quint32 total = 0;
- for (const auto &frame : frames)
- total += frame.hpackBlockSize();
-
- if (!total)
- return hpackBlock;
-
- hpackBlock.resize(total);
- auto dst = hpackBlock.begin();
- for (const auto &frame : frames) {
- if (const auto hpackBlockSize = frame.hpackBlockSize()) {
- const uchar *src = frame.hpackBlockBegin();
- std::copy(src, src + hpackBlockSize, dst);
- dst += hpackBlockSize;
- }
- }
-
- return hpackBlock;
-}
-
QUrl urlkey_from_request(const QHttpNetworkRequest &request)
{
QUrl url;
url.setScheme(request.url().scheme());
url.setAuthority(request.url().authority(QUrl::FullyEncoded | QUrl::RemoveUserInfo));
- url.setPath(QLatin1String(request.uri(false)));
+ url.setPath(QLatin1StringView(request.uri(false)));
return url;
}
-bool sum_will_overflow(qint32 windowSize, qint32 delta)
-{
- if (windowSize > 0)
- return std::numeric_limits<qint32>::max() - windowSize < delta;
- return std::numeric_limits<qint32>::min() - windowSize > delta;
-}
-
}// Unnamed namespace
// Since we anyway end up having this in every function definition:
using namespace Http2;
-const std::deque<quint32>::size_type QHttp2ProtocolHandler::maxRecycledStreams = 10000;
-const quint32 QHttp2ProtocolHandler::maxAcceptableTableSize;
-
QHttp2ProtocolHandler::QHttp2ProtocolHandler(QHttpNetworkConnectionChannel *channel)
: QAbstractProtocolHandler(channel),
decoder(HPack::FieldLookupTable::DefaultSize),
@@ -239,8 +175,7 @@ void QHttp2ProtocolHandler::_q_uploadDataReadyRead()
auto &stream = activeStreams[streamID];
if (!sendDATA(stream)) {
- finishStreamWithError(stream, QNetworkReply::UnknownNetworkError,
- QLatin1String("failed to send DATA"));
+ finishStreamWithError(stream, QNetworkReply::UnknownNetworkError, "failed to send DATA"_L1);
sendRST_STREAM(streamID, INTERNAL_ERROR);
markAsReset(streamID);
deleteActiveStream(streamID);
@@ -264,7 +199,8 @@ void QHttp2ProtocolHandler::_q_uploadDataDestroyed(QObject *uploadData)
void QHttp2ProtocolHandler::_q_readyRead()
{
- _q_receiveReply();
+ if (!goingAway || activeStreams.size())
+ _q_receiveReply();
}
void QHttp2ProtocolHandler::_q_receiveReply()
@@ -272,6 +208,11 @@ void QHttp2ProtocolHandler::_q_receiveReply()
Q_ASSERT(m_socket);
Q_ASSERT(m_channel);
+ if (goingAway && activeStreams.isEmpty()) {
+ m_channel->close();
+ return;
+ }
+
while (!goingAway || activeStreams.size()) {
const auto result = frameReader.read(*m_socket);
switch (result) {
@@ -347,9 +288,7 @@ bool QHttp2ProtocolHandler::sendRequest()
auto &requests = m_channel->h2RequestsToSend;
for (auto it = requests.begin(), endIt = requests.end(); it != endIt;) {
const auto &pair = *it;
- const QString scheme(pair.first.url().scheme());
- if (scheme == QLatin1String("preconnect-http")
- || scheme == QLatin1String("preconnect-https")) {
+ if (pair.first.isPreConnect()) {
m_connection->preConnectFinished();
emit pair.second->finished();
it = requests.erase(it);
@@ -387,10 +326,13 @@ bool QHttp2ProtocolHandler::sendRequest()
initReplyFromPushPromise(message, key);
}
- const auto streamsToUse = std::min<quint32>(maxConcurrentStreams - activeStreams.size(),
- requests.size());
+ const auto isClientSide = [](const auto &pair) -> bool { return (pair.first & 1) == 1; };
+ const auto activeClientSideStreams = std::count_if(
+ activeStreams.constKeyValueBegin(), activeStreams.constKeyValueEnd(), isClientSide);
+ const qint64 streamsToUse = qBound(0, qint64(maxConcurrentStreams) - activeClientSideStreams,
+ requests.size());
auto it = requests.begin();
- for (quint32 i = 0; i < streamsToUse; ++i) {
+ for (qint64 i = 0; i < streamsToUse; ++i) {
const qint32 newStreamID = createNewStream(*it);
if (!newStreamID) {
// TODO: actually we have to open a new connection.
@@ -403,14 +345,14 @@ bool QHttp2ProtocolHandler::sendRequest()
Stream &newStream = activeStreams[newStreamID];
if (!sendHEADERS(newStream)) {
finishStreamWithError(newStream, QNetworkReply::UnknownNetworkError,
- QLatin1String("failed to send HEADERS frame(s)"));
+ "failed to send HEADERS frame(s)"_L1);
deleteActiveStream(newStreamID);
continue;
}
if (newStream.data() && !sendDATA(newStream)) {
finishStreamWithError(newStream, QNetworkReply::UnknownNetworkError,
- QLatin1String("failed to send DATA frame(s)"));
+ "failed to send DATA frame(s)"_L1);
sendRST_STREAM(newStreamID, INTERNAL_ERROR);
markAsReset(newStreamID);
deleteActiveStream(newStreamID);
@@ -489,6 +431,10 @@ bool QHttp2ProtocolHandler::sendHEADERS(Stream &stream)
#ifndef QT_NO_NETWORKPROXY
useProxy = m_connection->d_func()->networkProxy.type() != QNetworkProxy::NoProxy;
#endif
+ if (stream.request().withCredentials()) {
+ m_connection->d_func()->createAuthorization(m_socket, stream.request());
+ stream.request().d->needResendWithCredentials = false;
+ }
const auto headers = build_headers(stream.request(), maxHeaderListSize, useProxy);
if (!headers.size()) // nothing fits into maxHeaderListSize
return false;
@@ -514,7 +460,7 @@ bool QHttp2ProtocolHandler::sendDATA(Stream &stream)
Q_ASSERT(replyPrivate);
auto slot = std::min<qint32>(sessionSendWindowSize, stream.sendWindow);
- while (!stream.data()->atEnd() && slot) {
+ while (replyPrivate->totallyUploadedData < request.contentLength() && slot) {
qint64 chunkSize = 0;
const uchar *src =
reinterpret_cast<const uchar *>(stream.data()->readPointer(slot, chunkSize));
@@ -529,7 +475,7 @@ bool QHttp2ProtocolHandler::sendDATA(Stream &stream)
}
frameWriter.start(FrameType::DATA, FrameFlag::EMPTY, stream.streamID);
- const qint32 bytesWritten = std::min<qint32>(slot, chunkSize);
+ const qint32 bytesWritten = qint32(std::min<qint64>(slot, chunkSize));
if (!frameWriter.writeDATA(*m_socket, maxFrameSize, src, bytesWritten))
return false;
@@ -601,12 +547,12 @@ void QHttp2ProtocolHandler::handleDATA()
sessionReceiveWindowSize -= inboundFrame.payloadSize();
- if (activeStreams.contains(streamID)) {
- auto &stream = activeStreams[streamID];
+ auto it = activeStreams.find(streamID);
+ if (it != activeStreams.end()) {
+ Stream &stream = it.value();
if (qint32(inboundFrame.payloadSize()) > stream.recvWindow) {
- finishStreamWithError(stream, QNetworkReply::ProtocolFailure,
- QLatin1String("flow control error"));
+ finishStreamWithError(stream, QNetworkReply::ProtocolFailure, "flow control error"_L1);
sendRST_STREAM(streamID, FLOW_CONTROL_ERROR);
markAsReset(streamID);
deleteActiveStream(streamID);
@@ -880,7 +826,7 @@ void QHttp2ProtocolHandler::handleGOAWAY()
// successful completion.
if (errorCode == HTTP2_NO_ERROR) {
error = QNetworkReply::ContentReSendError;
- message = QLatin1String("Server stopped accepting new streams before this stream was established");
+ message = "Server stopped accepting new streams before this stream was established"_L1;
}
for (quint32 id = lastStreamID; id < nextID; id += 2) {
@@ -909,24 +855,27 @@ void QHttp2ProtocolHandler::handleWINDOW_UPDATE()
const auto streamID = inboundFrame.streamID();
if (streamID == Http2::connectionStreamID) {
- if (!valid || sum_will_overflow(sessionSendWindowSize, delta))
+ qint32 sum = 0;
+ if (!valid || qAddOverflow(sessionSendWindowSize, qint32(delta), &sum))
return connectionError(PROTOCOL_ERROR, "WINDOW_UPDATE invalid delta");
- sessionSendWindowSize += delta;
+ sessionSendWindowSize = sum;
} else {
- if (!activeStreams.contains(streamID)) {
+ auto it = activeStreams.find(streamID);
+ if (it == activeStreams.end()) {
// WINDOW_UPDATE on closed streams can be ignored.
return;
}
- auto &stream = activeStreams[streamID];
- if (!valid || sum_will_overflow(stream.sendWindow, delta)) {
+ Stream &stream = it.value();
+ qint32 sum = 0;
+ if (!valid || qAddOverflow(stream.sendWindow, qint32(delta), &sum)) {
finishStreamWithError(stream, QNetworkReply::ProtocolFailure,
- QLatin1String("invalid WINDOW_UPDATE delta"));
+ "invalid WINDOW_UPDATE delta"_L1);
sendRST_STREAM(streamID, PROTOCOL_ERROR);
markAsReset(streamID);
deleteActiveStream(streamID);
return;
}
- stream.sendWindow += delta;
+ stream.sendWindow = sum;
}
// Since we're in _q_receiveReply at the moment, let's first handle other
@@ -965,9 +914,10 @@ void QHttp2ProtocolHandler::handleContinuedHEADERS()
const auto streamID = continuedFrames[0].streamID();
+ const auto streamIt = activeStreams.find(streamID);
if (firstFrameType == FrameType::HEADERS) {
- if (activeStreams.contains(streamID)) {
- Stream &stream = activeStreams[streamID];
+ if (streamIt != activeStreams.end()) {
+ Stream &stream = streamIt.value();
if (stream.state != Stream::halfClosedLocal
&& stream.state != Stream::remoteReserved
&& stream.state != Stream::open) {
@@ -975,7 +925,7 @@ void QHttp2ProtocolHandler::handleContinuedHEADERS()
// (these streams are in halfClosedLocal or open state) or
// remote-reserved streams from a server's PUSH_PROMISE.
finishStreamWithError(stream, QNetworkReply::ProtocolFailure,
- QLatin1String("HEADERS on invalid stream"));
+ "HEADERS on invalid stream"_L1);
sendRST_STREAM(streamID, CANCEL);
markAsReset(streamID);
deleteActiveStream(streamID);
@@ -989,8 +939,13 @@ void QHttp2ProtocolHandler::handleContinuedHEADERS()
// has yet to see the reset.
}
- std::vector<uchar> hpackBlock(assemble_hpack_block(continuedFrames));
- if (!hpackBlock.size()) {
+ std::vector<uchar> hpackBlock(Http2::assemble_hpack_block(continuedFrames));
+ const bool hasHeaderFields = !hpackBlock.empty();
+ if (hasHeaderFields) {
+ HPack::BitIStream inputStream{&hpackBlock[0], &hpackBlock[0] + hpackBlock.size()};
+ if (!decoder.decodeHeaderFields(inputStream))
+ return connectionError(COMPRESSION_ERROR, "HPACK decompression failed");
+ } else if (firstFrameType == FrameType::PUSH_PROMISE) {
// It could be a PRIORITY sent in HEADERS - already handled by this
// point in handleHEADERS. If it was PUSH_PROMISE (HTTP/2 8.2.1):
// "The header fields in PUSH_PROMISE and any subsequent CONTINUATION
@@ -999,23 +954,20 @@ void QHttp2ProtocolHandler::handleContinuedHEADERS()
// not include a complete and valid set of header fields or the :method
// pseudo-header field identifies a method that is not safe, it MUST
// respond with a stream error (Section 5.4.2) of type PROTOCOL_ERROR."
- if (firstFrameType == FrameType::PUSH_PROMISE)
- resetPromisedStream(continuedFrames[0], Http2::PROTOCOL_ERROR);
-
+ resetPromisedStream(continuedFrames[0], Http2::PROTOCOL_ERROR);
return;
}
- HPack::BitIStream inputStream{&hpackBlock[0], &hpackBlock[0] + hpackBlock.size()};
- if (!decoder.decodeHeaderFields(inputStream))
- return connectionError(COMPRESSION_ERROR, "HPACK decompression failed");
-
switch (firstFrameType) {
case FrameType::HEADERS:
- if (activeStreams.contains(streamID)) {
- Stream &stream = activeStreams[streamID];
- updateStream(stream, decoder.decodedHeader());
- // No DATA frames.
- if (continuedFrames[0].flags() & FrameFlag::END_STREAM) {
+ if (streamIt != activeStreams.end()) {
+ Stream &stream = streamIt.value();
+ if (hasHeaderFields)
+ updateStream(stream, decoder.decodedHeader());
+ // Needs to resend the request; we should finish and delete the current stream
+ const bool needResend = stream.request().d->needResendWithCredentials;
+ // No DATA frames. Or needs to resend.
+ if (continuedFrames[0].flags() & FrameFlag::END_STREAM || needResend) {
finishStream(stream);
deleteActiveStream(stream.streamID);
}
@@ -1054,17 +1006,18 @@ bool QHttp2ProtocolHandler::acceptSetting(Http2::Settings identifier, quint32 ne
std::vector<quint32> brokenStreams;
brokenStreams.reserve(activeStreams.size());
for (auto &stream : activeStreams) {
- if (sum_will_overflow(stream.sendWindow, delta)) {
+ qint32 sum = 0;
+ if (qAddOverflow(stream.sendWindow, delta, &sum)) {
brokenStreams.push_back(stream.streamID);
continue;
}
- stream.sendWindow += delta;
+ stream.sendWindow = sum;
}
for (auto id : brokenStreams) {
auto &stream = activeStreams[id];
finishStreamWithError(stream, QNetworkReply::ProtocolFailure,
- QLatin1String("SETTINGS window overflow"));
+ "SETTINGS window overflow"_L1);
sendRST_STREAM(id, PROTOCOL_ERROR);
markAsReset(id);
deleteActiveStream(id);
@@ -1073,17 +1026,12 @@ bool QHttp2ProtocolHandler::acceptSetting(Http2::Settings identifier, quint32 ne
QMetaObject::invokeMethod(this, "resumeSuspendedStreams", Qt::QueuedConnection);
}
- if (identifier == Settings::MAX_CONCURRENT_STREAMS_ID) {
- if (newValue > maxPeerConcurrentStreams) {
- connectionError(PROTOCOL_ERROR, "SETTINGS invalid number of concurrent streams");
- return false;
- }
+ if (identifier == Settings::MAX_CONCURRENT_STREAMS_ID)
maxConcurrentStreams = newValue;
- }
if (identifier == Settings::MAX_FRAME_SIZE_ID) {
if (newValue < Http2::minPayloadLimit || newValue > Http2::maxPayloadSize) {
- connectionError(PROTOCOL_ERROR, "SETTGINGS max frame size is out of range");
+ connectionError(PROTOCOL_ERROR, "SETTINGS max frame size is out of range");
return false;
}
maxFrameSize = newValue;
@@ -1103,7 +1051,7 @@ void QHttp2ProtocolHandler::updateStream(Stream &stream, const HPack::HttpHeader
Qt::ConnectionType connectionType)
{
const auto httpReply = stream.reply();
- const auto &httpRequest = stream.request();
+ auto &httpRequest = stream.request();
Q_ASSERT(httpReply || stream.state == Stream::remoteReserved);
if (!httpReply) {
@@ -1128,11 +1076,9 @@ void QHttp2ProtocolHandler::updateStream(Stream &stream, const HPack::HttpHeader
// moment and we are probably not done yet. So we extract url and set it
// here, if needed.
int statusCode = 0;
- QUrl redirectUrl;
-
for (const auto &pair : headers) {
const auto &name = pair.name;
- auto value = pair.value;
+ const auto value = QByteArrayView(pair.value);
// TODO: part of this code copies what SPDY protocol handler does when
// processing headers. Binary nature of HTTP/2 and SPDY saves us a lot
@@ -1141,45 +1087,57 @@ void QHttp2ProtocolHandler::updateStream(Stream &stream, const HPack::HttpHeader
if (name == ":status") {
statusCode = value.left(3).toInt();
httpReply->setStatusCode(statusCode);
- httpReplyPrivate->reasonPhrase = QString::fromLatin1(value.mid(4));
+ m_channel->lastStatus = statusCode; // Mostly useless for http/2, needed for auth
+ httpReply->setReasonPhrase(QString::fromLatin1(value.mid(4)));
} else if (name == ":version") {
- httpReplyPrivate->majorVersion = value.at(5) - '0';
- httpReplyPrivate->minorVersion = value.at(7) - '0';
+ httpReply->setMajorVersion(value.at(5) - '0');
+ httpReply->setMinorVersion(value.at(7) - '0');
} else if (name == "content-length") {
bool ok = false;
const qlonglong length = value.toLongLong(&ok);
if (ok)
httpReply->setContentLength(length);
} else {
- if (name == "location")
- redirectUrl = QUrl::fromEncoded(value);
- QByteArray binder(", ");
- if (name == "set-cookie")
- binder = "\n";
- httpReplyPrivate->fields.append(qMakePair(name, value.replace('\0', binder)));
+ const auto binder = name == "set-cookie" ? QByteArrayView("\n") : QByteArrayView(", ");
+ httpReply->appendHeaderField(name, QByteArray(pair.value).replace('\0', binder));
}
}
- if (QHttpNetworkReply::isHttpRedirect(statusCode) && redirectUrl.isValid())
- httpReply->setRedirectUrl(redirectUrl);
+ // Discard all informational (1xx) replies with the exception of 101.
+ // Also see RFC 9110 (Chapter 15.2)
+ if (statusCode == 100 || (102 <= statusCode && statusCode <= 199)) {
+ httpReplyPrivate->clearHttpLayerInformation();
+ return;
+ }
+
+ if (QHttpNetworkReply::isHttpRedirect(statusCode) && httpRequest.isFollowRedirects()) {
+ QHttpNetworkConnectionPrivate::ParseRedirectResult result =
+ m_connection->d_func()->parseRedirectResponse(httpReply);
+ if (result.errorCode != QNetworkReply::NoError) {
+ auto errorString = m_connection->d_func()->errorDetail(result.errorCode, m_socket);
+ finishStreamWithError(stream, result.errorCode, errorString);
+ sendRST_STREAM(stream.streamID, INTERNAL_ERROR);
+ markAsReset(stream.streamID);
+ return;
+ }
- if (httpReplyPrivate->isCompressed() && httpRequest.d->autoDecompress) {
- httpReplyPrivate->removeAutoDecompressHeader();
- httpReplyPrivate->decompressHelper.setEncoding(
- httpReplyPrivate->headerField("content-encoding"));
- if (httpReplyPrivate->request.ignoreDecompressionRatio())
- httpReplyPrivate->decompressHelper.setArchiveBombDetectionEnabled(false);
+ if (result.redirectUrl.isValid())
+ httpReply->setRedirectUrl(result.redirectUrl);
}
- if (QHttpNetworkReply::isHttpRedirect(statusCode)
- || statusCode == 401 || statusCode == 407) {
- // These are the status codes that can trigger uploadByteDevice->reset()
- // in QHttpNetworkConnectionChannel::handleStatus. Alas, we have no
- // single request/reply, we multiplex several requests and thus we never
- // simply call 'handleStatus'. If we have byte-device - we try to reset
- // it here, we don't (and can't) handle any error during reset operation.
- if (stream.data())
+ if (httpReplyPrivate->isCompressed() && httpRequest.d->autoDecompress)
+ httpReplyPrivate->removeAutoDecompressHeader();
+
+ if (QHttpNetworkReply::isHttpRedirect(statusCode)) {
+ // Note: This status code can trigger uploadByteDevice->reset() in
+ // QHttpNetworkConnectionChannel::handleStatus. Alas, we have no single
+ // request/reply, we multiplex several requests and thus we never simply
+ // call 'handleStatus'. If we have a byte-device - we try to reset it
+ // here, we don't (and can't) handle any error during reset operation.
+ if (stream.data()) {
stream.data()->reset();
+ httpReplyPrivate->totallyUploadedData = 0;
+ }
}
if (connectionType == Qt::DirectConnection)
@@ -1205,27 +1163,11 @@ void QHttp2ProtocolHandler::updateStream(Stream &stream, const Frame &frame,
if (const auto length = frame.dataSize()) {
const char *data = reinterpret_cast<const char *>(frame.dataBegin());
- auto &httpRequest = stream.request();
auto replyPrivate = httpReply->d_func();
replyPrivate->totalProgress += length;
- const QByteArray wrapped(data, length);
- if (httpRequest.d->autoDecompress && replyPrivate->isCompressed()) {
- Q_ASSERT(replyPrivate->decompressHelper.isValid());
-
- replyPrivate->decompressHelper.feed(wrapped);
- while (replyPrivate->decompressHelper.hasData()) {
- QByteArray output(4 * 1024, Qt::Uninitialized);
- qint64 read = replyPrivate->decompressHelper.read(output.data(), output.size());
- if (read > 0) {
- output.resize(read);
- replyPrivate->responseData.append(std::move(output));
- }
- }
- } else {
- replyPrivate->responseData.append(wrapped);
- }
+ replyPrivate->responseData.append(QByteArray(data, length));
if (replyPrivate->shouldEmitSignals()) {
if (connectionType == Qt::DirectConnection) {
@@ -1242,6 +1184,91 @@ void QHttp2ProtocolHandler::updateStream(Stream &stream, const Frame &frame,
}
}
+// After calling this function, either the request will be re-sent or
+// the reply will be finishedWithError! Do not emit finished() or similar on the
+// reply after this!
+void QHttp2ProtocolHandler::handleAuthorization(Stream &stream)
+{
+ auto *httpReply = stream.reply();
+ auto *httpReplyPrivate = httpReply->d_func();
+ auto &httpRequest = stream.request();
+
+ Q_ASSERT(httpReply && (httpReply->statusCode() == 401 || httpReply->statusCode() == 407));
+
+ const auto handleAuth = [&, this](QByteArrayView authField, bool isProxy) -> bool {
+ Q_ASSERT(httpReply);
+ const QByteArrayView auth = authField.trimmed();
+ if (auth.startsWith("Negotiate") || auth.startsWith("NTLM")) {
+ // @todo: We're supposed to fall back to http/1.1:
+ // https://docs.microsoft.com/en-us/iis/get-started/whats-new-in-iis-10/http2-on-iis#when-is-http2-not-supported
+ // "Windows authentication (NTLM/Kerberos/Negotiate) is not supported with HTTP/2.
+ // In this case IIS will fall back to HTTP/1.1."
+ // Though it might be OK to ignore this. The server shouldn't let us connect with
+ // HTTP/2 if it doesn't support us using it.
+ return false;
+ }
+ // Somewhat mimics parts of QHttpNetworkConnectionChannel::handleStatus
+ bool resend = false;
+ const bool authenticateHandled = m_connection->d_func()->handleAuthenticateChallenge(
+ m_socket, httpReply, isProxy, resend);
+ if (authenticateHandled) {
+ if (resend) {
+ httpReply->d_func()->eraseData();
+ // Add the request back in queue, we'll retry later now that
+ // we've gotten some username/password set on it:
+ httpRequest.d->needResendWithCredentials = true;
+ m_channel->h2RequestsToSend.insert(httpRequest.priority(), stream.httpPair);
+ httpReply->d_func()->clearHeaders();
+ // If we have data we were uploading we need to reset it:
+ if (stream.data()) {
+ stream.data()->reset();
+ httpReplyPrivate->totallyUploadedData = 0;
+ }
+ // We automatically try to send new requests when the stream is
+ // closed, so we don't need to call sendRequest ourselves.
+ return true;
+ } // else: we're just not resending the request.
+ // @note In the http/1.x case we (at time of writing) call close()
+ // for the connectionChannel (which is a bit weird, we could surely
+ // reuse the open socket outside "connection:close"?), but in http2
+ // we only have one channel, so we won't close anything.
+ } else {
+ // No authentication header or authentication isn't supported, but
+ // we got a 401/407 so we cannot succeed. We need to emit signals
+ // for headers and data, and then finishWithError.
+ emit httpReply->headerChanged();
+ emit httpReply->readyRead();
+ QNetworkReply::NetworkError error = httpReply->statusCode() == 401
+ ? QNetworkReply::AuthenticationRequiredError
+ : QNetworkReply::ProxyAuthenticationRequiredError;
+ finishStreamWithError(stream, QNetworkReply::AuthenticationRequiredError,
+ m_connection->d_func()->errorDetail(error, m_socket));
+ }
+ return false;
+ };
+
+ // These statuses would in HTTP/1.1 be handled by
+ // QHttpNetworkConnectionChannel::handleStatus. But because h2 has
+ // multiple streams/requests in a single channel this structure does not
+ // map properly to that function.
+ bool authOk = true;
+ switch (httpReply->statusCode()) {
+ case 401:
+ authOk = handleAuth(httpReply->headerField("www-authenticate"), false);
+ break;
+ case 407:
+ authOk = handleAuth(httpReply->headerField("proxy-authenticate"), true);
+ break;
+ default:
+ Q_UNREACHABLE();
+ }
+ if (authOk) {
+ markAsReset(stream.streamID);
+ deleteActiveStream(stream.streamID);
+ } // else: errors handled inside handleAuth
+}
+
+// Called when we have received a frame with the END_STREAM flag set
void QHttp2ProtocolHandler::finishStream(Stream &stream, Qt::ConnectionType connectionType)
{
Q_ASSERT(stream.state == Stream::remoteReserved || stream.reply());
@@ -1249,14 +1276,25 @@ void QHttp2ProtocolHandler::finishStream(Stream &stream, Qt::ConnectionType conn
stream.state = Stream::closed;
auto httpReply = stream.reply();
if (httpReply) {
+ int statusCode = httpReply->statusCode();
+ if (statusCode == 401 || statusCode == 407) {
+ // handleAuthorization will either re-send the request or
+ // finishWithError. In either case we don't want to emit finished
+ // here.
+ handleAuthorization(stream);
+ return;
+ }
+
httpReply->disconnect(this);
if (stream.data())
stream.data()->disconnect(this);
- if (connectionType == Qt::DirectConnection)
- emit httpReply->finished();
- else
- QMetaObject::invokeMethod(httpReply, "finished", connectionType);
+ if (!stream.request().d->needResendWithCredentials) {
+ if (connectionType == Qt::DirectConnection)
+ emit httpReply->finished();
+ else
+ QMetaObject::invokeMethod(httpReply, "finished", connectionType);
+ }
}
qCDebug(QT_HTTP2) << "stream" << stream.streamID << "closed";
@@ -1320,6 +1358,8 @@ quint32 QHttp2ProtocolHandler::createNewStream(const HttpMessagePair &message, b
}
}
+ QMetaObject::invokeMethod(reply, "requestSent", Qt::QueuedConnection);
+
activeStreams.insert(newStreamID, newStream);
return newStreamID;
@@ -1368,9 +1408,10 @@ quint32 QHttp2ProtocolHandler::popStreamToResume()
auto &queue = suspendedStreams[rank];
auto it = queue.begin();
for (; it != queue.end(); ++it) {
- if (!activeStreams.contains(*it))
+ auto stream = activeStreams.constFind(*it);
+ if (stream == activeStreams.cend())
continue;
- if (activeStreams[*it].sendWindow > 0)
+ if (stream->sendWindow > 0)
break;
}
@@ -1393,8 +1434,8 @@ void QHttp2ProtocolHandler::removeFromSuspended(quint32 streamID)
void QHttp2ProtocolHandler::deleteActiveStream(quint32 streamID)
{
- if (activeStreams.contains(streamID)) {
- auto &stream = activeStreams[streamID];
+ if (const auto it = activeStreams.constFind(streamID); it != activeStreams.cend()) {
+ const Stream &stream = it.value();
if (stream.reply()) {
stream.reply()->disconnect(this);
streamIDs.remove(stream.reply());
@@ -1403,7 +1444,7 @@ void QHttp2ProtocolHandler::deleteActiveStream(quint32 streamID)
stream.data()->disconnect(this);
streamIDs.remove(stream.data());
}
- activeStreams.remove(streamID);
+ activeStreams.erase(it);
}
removeFromSuspended(streamID);
@@ -1426,13 +1467,14 @@ void QHttp2ProtocolHandler::resumeSuspendedStreams()
if (!streamID)
return;
- if (!activeStreams.contains(streamID))
+ auto it = activeStreams.find(streamID);
+ if (it == activeStreams.end())
continue;
+ Stream &stream = it.value();
- Stream &stream = activeStreams[streamID];
if (!sendDATA(stream)) {
finishStreamWithError(stream, QNetworkReply::UnknownNetworkError,
- QLatin1String("failed to send DATA"));
+ "failed to send DATA"_L1);
sendRST_STREAM(streamID, INTERNAL_ERROR);
markAsReset(streamID);
deleteActiveStream(streamID);
@@ -1458,42 +1500,18 @@ bool QHttp2ProtocolHandler::tryReserveStream(const Http2::Frame &pushPromiseFram
{
Q_ASSERT(pushPromiseFrame.type() == FrameType::PUSH_PROMISE);
- QMap<QByteArray, QByteArray> pseudoHeaders;
- for (const auto &field : requestHeader) {
- if (field.name == ":scheme" || field.name == ":path"
- || field.name == ":authority" || field.name == ":method") {
- if (field.value.isEmpty() || pseudoHeaders.contains(field.name))
- return false;
- pseudoHeaders[field.name] = field.value;
- }
- }
-
- if (pseudoHeaders.size() != 4) {
- // All four required, HTTP/2 8.1.2.3.
- return false;
- }
-
- const QByteArray method = pseudoHeaders[":method"];
- if (method.compare("get", Qt::CaseInsensitive) != 0 &&
- method.compare("head", Qt::CaseInsensitive) != 0)
- return false;
-
- QUrl url;
- url.setScheme(QLatin1String(pseudoHeaders[":scheme"]));
- url.setAuthority(QLatin1String(pseudoHeaders[":authority"]));
- url.setPath(QLatin1String(pseudoHeaders[":path"]));
-
- if (!url.isValid())
+ const auto url = HPack::makePromiseKeyUrl(requestHeader);
+ if (!url.has_value())
return false;
Q_ASSERT(activeStreams.contains(pushPromiseFrame.streamID()));
const Stream &associatedStream = activeStreams[pushPromiseFrame.streamID()];
const auto associatedUrl = urlkey_from_request(associatedStream.request());
- if (url.adjusted(QUrl::RemovePath) != associatedUrl.adjusted(QUrl::RemovePath))
+ if (url->adjusted(QUrl::RemovePath) != associatedUrl.adjusted(QUrl::RemovePath))
return false;
- const auto urlKey = url.toString();
+ const auto urlKey = url->toString();
if (promisedData.contains(urlKey)) // duplicate push promise
return false;
@@ -1532,8 +1550,8 @@ void QHttp2ProtocolHandler::initReplyFromPushPromise(const HttpMessagePair &mess
bool replyFinished = false;
Stream *promisedStream = nullptr;
- if (activeStreams.contains(promise.reservedID)) {
- promisedStream = &activeStreams[promise.reservedID];
+ if (auto it = activeStreams.find(promise.reservedID); it != activeStreams.end()) {
+ promisedStream = &it.value();
// Ok, we have an active (not closed yet) stream waiting for more frames,
// let's pretend we requested it:
promisedStream->httpPair = message;
@@ -1543,8 +1561,8 @@ void QHttp2ProtocolHandler::initReplyFromPushPromise(const HttpMessagePair &mess
streamInitialSendWindowSize,
streamInitialReceiveWindowSize);
closedStream.state = Stream::halfClosedLocal;
- activeStreams.insert(promise.reservedID, closedStream);
- promisedStream = &activeStreams[promise.reservedID];
+ it = activeStreams.insert(promise.reservedID, closedStream);
+ promisedStream = &it.value();
replyFinished = true;
}
@@ -1578,7 +1596,7 @@ void QHttp2ProtocolHandler::connectionError(Http2::Http2Error errorCode,
m_channel->emitFinishedWithError(error, message);
for (auto &stream: activeStreams)
- finishStreamWithError(stream, error, QLatin1String(message));
+ finishStreamWithError(stream, error, QLatin1StringView(message));
closeSession();
}
@@ -1594,3 +1612,5 @@ void QHttp2ProtocolHandler::closeSession()
}
QT_END_NAMESPACE
+
+#include "moc_qhttp2protocolhandler_p.cpp"
diff --git a/src/network/access/qhttp2protocolhandler_p.h b/src/network/access/qhttp2protocolhandler_p.h
index 14deabd70b..3b818771a6 100644
--- a/src/network/access/qhttp2protocolhandler_p.h
+++ b/src/network/access/qhttp2protocolhandler_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QHTTP2PROTOCOLHANDLER_P_H
#define QHTTP2PROTOCOLHANDLER_P_H
@@ -130,6 +94,7 @@ private:
bool acceptSetting(Http2::Settings identifier, quint32 newValue);
+ void handleAuthorization(Stream &stream);
void updateStream(Stream &stream, const HPack::HttpHeader &headers,
Qt::ConnectionType connectionType = Qt::DirectConnection);
void updateStream(Stream &stream, const Http2::Frame &dataFrame,
@@ -156,7 +121,7 @@ private:
// the client's preface 24-byte message.
bool waitingForSettingsACK = false;
- static const quint32 maxAcceptableTableSize = 16 * HPack::FieldLookupTable::DefaultSize;
+ inline static const quint32 maxAcceptableTableSize = 16 * HPack::FieldLookupTable::DefaultSize;
// HTTP/2 4.3: Header compression is stateful. One compression context and
// one decompression context are used for the entire connection.
HPack::Decoder decoder;
@@ -165,7 +130,7 @@ private:
QHash<QObject *, int> streamIDs;
QHash<quint32, Stream> activeStreams;
std::deque<quint32> suspendedStreams[3]; // 3 for priorities: High, Normal, Low.
- static const std::deque<quint32>::size_type maxRecycledStreams;
+ inline static const std::deque<quint32>::size_type maxRecycledStreams = 10000;
std::deque<quint32> recycledStreams;
// Peer's max frame size (this min is the default value
diff --git a/src/network/access/qhttpheaderparser.cpp b/src/network/access/qhttpheaderparser.cpp
new file mode 100644
index 0000000000..0b7882c18a
--- /dev/null
+++ b/src/network/access/qhttpheaderparser.cpp
@@ -0,0 +1,221 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qhttpheaderparser_p.h"
+
+#include <algorithm>
+
+QT_BEGIN_NAMESPACE
+
+QHttpHeaderParser::QHttpHeaderParser()
+ : statusCode(100) // Required by tst_QHttpNetworkConnection::ignoresslerror(failure)
+ , majorVersion(0)
+ , minorVersion(0)
+{
+}
+
+void QHttpHeaderParser::clear()
+{
+ statusCode = 100;
+ majorVersion = 0;
+ minorVersion = 0;
+ reasonPhrase.clear();
+ fields.clear();
+}
+
+static bool fieldNameCheck(QByteArrayView name)
+{
+ static constexpr QByteArrayView otherCharacters("!#$%&'*+-.^_`|~");
+ static const auto fieldNameChar = [](char c) {
+ return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9')
+ || otherCharacters.contains(c);
+ };
+
+ return !name.empty() && std::all_of(name.begin(), name.end(), fieldNameChar);
+}
+
+bool QHttpHeaderParser::parseHeaders(QByteArrayView header)
+{
+ // see rfc2616, sec 4 for information about HTTP/1.1 headers.
+ // allows relaxed parsing here, accepts both CRLF & LF line endings
+ Q_ASSERT(fields.isEmpty());
+ const auto hSpaceStart = [](QByteArrayView h) {
+ return h.startsWith(' ') || h.startsWith('\t');
+ };
+ // Headers, if non-empty, start with a non-space and end with a newline:
+ if (hSpaceStart(header) || (!header.empty() && !header.endsWith('\n')))
+ return false;
+
+ while (int tail = header.endsWith("\n\r\n") ? 2 : header.endsWith("\n\n") ? 1 : 0)
+ header.chop(tail);
+
+ if (header.size() - (header.endsWith("\r\n") ? 2 : 1) > maxTotalSize)
+ return false;
+
+ QHttpHeaders result;
+ while (!header.empty()) {
+ const qsizetype colon = header.indexOf(':');
+ if (colon == -1) // if no colon check if empty headers
+ return result.isEmpty() && (header == "\n" || header == "\r\n");
+ if (result.size() >= maxFieldCount)
+ return false;
+ QByteArrayView name = header.first(colon);
+ if (!fieldNameCheck(name))
+ return false;
+ header = header.sliced(colon + 1);
+ QByteArray value;
+ qsizetype valueSpace = maxFieldSize - name.size() - 1;
+ do {
+ const qsizetype endLine = header.indexOf('\n');
+ Q_ASSERT(endLine != -1);
+ auto line = header.first(endLine); // includes space
+ valueSpace -= line.size() - (line.endsWith('\r') ? 1 : 0);
+ if (valueSpace < 0)
+ return false;
+ line = line.trimmed();
+ if (!line.empty()) {
+ if (value.size())
+ value += ' ' + line;
+ else
+ value = line.toByteArray();
+ }
+ header = header.sliced(endLine + 1);
+ } while (hSpaceStart(header));
+ Q_ASSERT(name.size() + 1 + value.size() <= maxFieldSize);
+ result.append(name, value);
+ }
+
+ fields = result;
+ return true;
+}
+
+bool QHttpHeaderParser::parseStatus(QByteArrayView status)
+{
+ // from RFC 2616:
+ // Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
+ // HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT
+ // that makes: 'HTTP/n.n xxx Message'
+ // byte count: 0123456789012
+
+ static const int minLength = 11;
+ static const int dotPos = 6;
+ static const int spacePos = 8;
+ static const char httpMagic[] = "HTTP/";
+
+ if (status.size() < minLength
+ || !status.startsWith(httpMagic)
+ || status.at(dotPos) != '.'
+ || status.at(spacePos) != ' ') {
+ // I don't know how to parse this status line
+ return false;
+ }
+
+ // optimize for the valid case: defer checking until the end
+ majorVersion = status.at(dotPos - 1) - '0';
+ minorVersion = status.at(dotPos + 1) - '0';
+
+ int i = spacePos;
+ qsizetype j = status.indexOf(' ', i + 1);
+ const QByteArrayView code = j > i ? status.sliced(i + 1, j - i - 1)
+ : status.sliced(i + 1);
+
+ bool ok = false;
+ statusCode = code.toInt(&ok);
+
+ reasonPhrase = j > i ? QString::fromLatin1(status.sliced(j + 1))
+ : QString();
+
+ return ok && uint(majorVersion) <= 9 && uint(minorVersion) <= 9;
+}
+
+const QHttpHeaders& QHttpHeaderParser::headers() const
+{
+ return fields;
+}
+
+QByteArray QHttpHeaderParser::firstHeaderField(QByteArrayView name,
+ const QByteArray &defaultValue) const
+{
+ return fields.value(name, defaultValue).toByteArray();
+}
+
+QByteArray QHttpHeaderParser::combinedHeaderValue(QByteArrayView name, const QByteArray &defaultValue) const
+{
+ const QList<QByteArray> allValues = headerFieldValues(name);
+ if (allValues.isEmpty())
+ return defaultValue;
+ return allValues.join(", ");
+}
+
+QList<QByteArray> QHttpHeaderParser::headerFieldValues(QByteArrayView name) const
+{
+ return fields.values(name);
+}
+
+void QHttpHeaderParser::removeHeaderField(QByteArrayView name)
+{
+ fields.removeAll(name);
+}
+
+void QHttpHeaderParser::setHeaderField(const QByteArray &name, const QByteArray &data)
+{
+ removeHeaderField(name);
+ fields.append(name, data);
+}
+
+void QHttpHeaderParser::prependHeaderField(const QByteArray &name, const QByteArray &data)
+{
+ fields.insert(0, name, data);
+}
+
+void QHttpHeaderParser::appendHeaderField(const QByteArray &name, const QByteArray &data)
+{
+ fields.append(name, data);
+}
+
+void QHttpHeaderParser::clearHeaders()
+{
+ fields.clear();
+}
+
+int QHttpHeaderParser::getStatusCode() const
+{
+ return statusCode;
+}
+
+void QHttpHeaderParser::setStatusCode(int code)
+{
+ statusCode = code;
+}
+
+int QHttpHeaderParser::getMajorVersion() const
+{
+ return majorVersion;
+}
+
+void QHttpHeaderParser::setMajorVersion(int version)
+{
+ majorVersion = version;
+}
+
+int QHttpHeaderParser::getMinorVersion() const
+{
+ return minorVersion;
+}
+
+void QHttpHeaderParser::setMinorVersion(int version)
+{
+ minorVersion = version;
+}
+
+QString QHttpHeaderParser::getReasonPhrase() const
+{
+ return reasonPhrase;
+}
+
+void QHttpHeaderParser::setReasonPhrase(const QString &reason)
+{
+ reasonPhrase = reason;
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/access/qhttpheaderparser_p.h b/src/network/access/qhttpheaderparser_p.h
new file mode 100644
index 0000000000..5e8f3c8130
--- /dev/null
+++ b/src/network/access/qhttpheaderparser_p.h
@@ -0,0 +1,101 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QHTTPHEADERPARSER_H
+#define QHTTPHEADERPARSER_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the Network Access API. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtNetwork/private/qtnetworkglobal_p.h>
+#include <QtNetwork/qhttpheaders.h>
+
+#include <QByteArray>
+#include <QList>
+#include <QPair>
+#include <QString>
+
+QT_BEGIN_NAMESPACE
+
+namespace HeaderConstants {
+
+// We previously used 8K, which is common on server side, but it turned out to
+// not be enough for various uses. Historically Firefox used 10K as the limit of
+// a single field, but some Location headers and Authorization challenges can
+// get even longer. Other browsers, such as Chrome, instead have a limit on the
+// total size of all the headers (as well as extra limits on some of the
+// individual fields). We'll use 100K as our default limit, which would be a ridiculously large
+// header, with the possibility to override it where we need to.
+static constexpr int MAX_HEADER_FIELD_SIZE = 100 * 1024;
+// Taken from http://httpd.apache.org/docs/2.2/mod/core.html#limitrequestfields
+static constexpr int MAX_HEADER_FIELDS = 100;
+// Chromium has a limit on the total size of the header set to 256KB,
+// which is a reasonable default for QNetworkAccessManager.
+// https://stackoverflow.com/a/3436155
+static constexpr int MAX_TOTAL_HEADER_SIZE = 256 * 1024;
+
+}
+
+class Q_NETWORK_EXPORT QHttpHeaderParser
+{
+public:
+ QHttpHeaderParser();
+
+ void clear();
+ bool parseHeaders(QByteArrayView headers);
+ bool parseStatus(QByteArrayView status);
+
+ const QHttpHeaders& headers() const;
+ void setStatusCode(int code);
+ int getStatusCode() const;
+ int getMajorVersion() const;
+ void setMajorVersion(int version);
+ int getMinorVersion() const;
+ void setMinorVersion(int version);
+ QString getReasonPhrase() const;
+ void setReasonPhrase(const QString &reason);
+
+ QByteArray firstHeaderField(QByteArrayView name,
+ const QByteArray &defaultValue = QByteArray()) const;
+ QByteArray combinedHeaderValue(QByteArrayView name,
+ const QByteArray &defaultValue = QByteArray()) const;
+ QList<QByteArray> headerFieldValues(QByteArrayView name) const;
+ void setHeaderField(const QByteArray &name, const QByteArray &data);
+ void prependHeaderField(const QByteArray &name, const QByteArray &data);
+ void appendHeaderField(const QByteArray &name, const QByteArray &data);
+ void removeHeaderField(QByteArrayView name);
+ void clearHeaders();
+
+ void setMaxHeaderFieldSize(qsizetype size) { maxFieldSize = size; }
+ qsizetype maxHeaderFieldSize() const { return maxFieldSize; }
+
+ void setMaxTotalHeaderSize(qsizetype size) { maxTotalSize = size; }
+ qsizetype maxTotalHeaderSize() const { return maxTotalSize; }
+
+ void setMaxHeaderFields(qsizetype count) { maxFieldCount = count; }
+ qsizetype maxHeaderFields() const { return maxFieldCount; }
+
+private:
+ QHttpHeaders fields;
+ QString reasonPhrase;
+ int statusCode;
+ int majorVersion;
+ int minorVersion;
+
+ qsizetype maxFieldSize = HeaderConstants::MAX_HEADER_FIELD_SIZE;
+ qsizetype maxTotalSize = HeaderConstants::MAX_TOTAL_HEADER_SIZE;
+ qsizetype maxFieldCount = HeaderConstants::MAX_HEADER_FIELDS;
+};
+
+
+QT_END_NAMESPACE
+
+#endif // QHTTPHEADERPARSER_H
diff --git a/src/network/access/qhttpheaders.cpp b/src/network/access/qhttpheaders.cpp
new file mode 100644
index 0000000000..c63da899a8
--- /dev/null
+++ b/src/network/access/qhttpheaders.cpp
@@ -0,0 +1,1551 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qhttpheaders.h"
+
+#include <private/qoffsetstringarray_p.h>
+
+#include <QtCore/qcompare.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qmap.h>
+#include <QtCore/qset.h>
+#include <QtCore/qttypetraits.h>
+
+#include <q20algorithm.h>
+#include <string_view>
+#include <variant>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcQHttpHeaders, "qt.network.http.headers");
+
+/*!
+ \class QHttpHeaders
+ \since 6.7
+ \ingroup
+ \inmodule QtNetwork
+
+ \brief QHttpHeaders is a class for holding HTTP headers.
+
+ The class is an interface type for Qt networking APIs that
+ use or consume such headers.
+
+ \section1 Allowed field name and value characters
+
+ An HTTP header consists of \e name and \e value.
+ When setting these, QHttpHeaders validates \e name and \e value
+ to only contain characters allowed by the HTTP RFCs. For detailed
+ information see
+ \l {https://datatracker.ietf.org/doc/html/rfc9110#name-field-values}
+ {RFC 9110 Chapters 5.1 and 5.5}.
+
+ In all, this means:
+ \list
+ \li \c name must consist of visible ASCII characters, and must not be
+ empty
+ \li \c value may consist of arbitrary bytes, as long as header
+ and use case specific encoding rules are adhered to. \c value
+ may be empty
+ \endlist
+
+ The setters of this class automatically remove any leading or trailing
+ whitespaces from \e value, as they must be ignored during the
+ \e value processing.
+
+ \section1 Combining values
+
+ Most HTTP header values can be combined with a single comma \c {','}
+ plus an optional whitespace, and the semantic meaning is preserved.
+ As an example, these two should be semantically similar:
+ \badcode
+ // Values as separate header entries
+ myheadername: myheadervalue1
+ myheadername: myheadervalue2
+ // Combined value
+ myheadername: myheadervalue1, myheadervalue2
+ \endcode
+
+ However, there is a notable exception to this rule:
+ \l {https://datatracker.ietf.org/doc/html/rfc9110#name-field-order}
+ {Set-Cookie}. Due to this and the possibility of custom use cases,
+ QHttpHeaders does not automatically combine the values.
+
+ \section1 Performance
+
+ Most QHttpHeaders functions provide both
+ \l QHttpHeaders::WellKnownHeader and \l QAnyStringView overloads.
+ From a memory-usage and computation point of view it is recommended
+ to use the \l QHttpHeaders::WellKnownHeader overloads.
+*/
+
+// This list is from IANA HTTP Field Name Registry
+// https://www.iana.org/assignments/http-fields
+// It contains entries that are either "permanent"
+// or "deprecated" as of October 2023.
+// Usage relies on enum values keeping in same order.
+// ### Qt7 check if some of these headers have been obsoleted,
+// and also check if the enums benefit from reordering
+static constexpr auto headerNames = qOffsetStringArray(
+ // IANA Permanent status:
+ "a-im",
+ "accept",
+ "accept-additions",
+ "accept-ch",
+ "accept-datetime",
+ "accept-encoding",
+ "accept-features",
+ "accept-language",
+ "accept-patch",
+ "accept-post",
+ "accept-ranges",
+ "accept-signature",
+ "access-control-allow-credentials",
+ "access-control-allow-headers",
+ "access-control-allow-methods",
+ "access-control-allow-origin",
+ "access-control-expose-headers",
+ "access-control-max-age",
+ "access-control-request-headers",
+ "access-control-request-method",
+ "age",
+ "allow",
+ "alpn",
+ "alt-svc",
+ "alt-used",
+ "alternates",
+ "apply-to-redirect-ref",
+ "authentication-control",
+ "authentication-info",
+ "authorization",
+ "cache-control",
+ "cache-status",
+ "cal-managed-id",
+ "caldav-timezones",
+ "capsule-protocol",
+ "cdn-cache-control",
+ "cdn-loop",
+ "cert-not-after",
+ "cert-not-before",
+ "clear-site-data",
+ "client-cert",
+ "client-cert-chain",
+ "close",
+ "connection",
+ "content-digest",
+ "content-disposition",
+ "content-encoding",
+ "content-id",
+ "content-language",
+ "content-length",
+ "content-location",
+ "content-range",
+ "content-security-policy",
+ "content-security-policy-report-only",
+ "content-type",
+ "cookie",
+ "cross-origin-embedder-policy",
+ "cross-origin-embedder-policy-report-only",
+ "cross-origin-opener-policy",
+ "cross-origin-opener-policy-report-only",
+ "cross-origin-resource-policy",
+ "dasl",
+ "date",
+ "dav",
+ "delta-base",
+ "depth",
+ "destination",
+ "differential-id",
+ "dpop",
+ "dpop-nonce",
+ "early-data",
+ "etag",
+ "expect",
+ "expect-ct",
+ "expires",
+ "forwarded",
+ "from",
+ "hobareg",
+ "host",
+ "if",
+ "if-match",
+ "if-modified-since",
+ "if-none-match",
+ "if-range",
+ "if-schedule-tag-match",
+ "if-unmodified-since",
+ "im",
+ "include-referred-token-binding-id",
+ "keep-alive",
+ "label",
+ "last-event-id",
+ "last-modified",
+ "link",
+ "location",
+ "lock-token",
+ "max-forwards",
+ "memento-datetime",
+ "meter",
+ "mime-version",
+ "negotiate",
+ "nel",
+ "odata-entityid",
+ "odata-isolation",
+ "odata-maxversion",
+ "odata-version",
+ "optional-www-authenticate",
+ "ordering-type",
+ "origin",
+ "origin-agent-cluster",
+ "oscore",
+ "oslc-core-version",
+ "overwrite",
+ "ping-from",
+ "ping-to",
+ "position",
+ "prefer",
+ "preference-applied",
+ "priority",
+ "proxy-authenticate",
+ "proxy-authentication-info",
+ "proxy-authorization",
+ "proxy-status",
+ "public-key-pins",
+ "public-key-pins-report-only",
+ "range",
+ "redirect-ref",
+ "referer",
+ "refresh",
+ "replay-nonce",
+ "repr-digest",
+ "retry-after",
+ "schedule-reply",
+ "schedule-tag",
+ "sec-purpose",
+ "sec-token-binding",
+ "sec-websocket-accept",
+ "sec-websocket-extensions",
+ "sec-websocket-key",
+ "sec-websocket-protocol",
+ "sec-websocket-version",
+ "server",
+ "server-timing",
+ "set-cookie",
+ "signature",
+ "signature-input",
+ "slug",
+ "soapaction",
+ "status-uri",
+ "strict-transport-security",
+ "sunset",
+ "surrogate-capability",
+ "surrogate-control",
+ "tcn",
+ "te",
+ "timeout",
+ "topic",
+ "traceparent",
+ "tracestate",
+ "trailer",
+ "transfer-encoding",
+ "ttl",
+ "upgrade",
+ "urgency",
+ "user-agent",
+ "variant-vary",
+ "vary",
+ "via",
+ "want-content-digest",
+ "want-repr-digest",
+ "www-authenticate",
+ "x-content-type-options",
+ "x-frame-options",
+ // IANA Deprecated status:
+ "accept-charset",
+ "c-pep-info",
+ "pragma",
+ "protocol-info",
+ "protocol-query"
+ // If you append here, regenerate the index table
+);
+
+namespace {
+struct ByIndirectHeaderName
+{
+ constexpr bool operator()(quint8 lhs, quint8 rhs) const noexcept
+ {
+ return (*this)(map(lhs), map(rhs));
+ }
+ constexpr bool operator()(quint8 lhs, QByteArrayView rhs) const noexcept
+ {
+ return (*this)(map(lhs), rhs);
+ }
+ constexpr bool operator()(QByteArrayView lhs, quint8 rhs) const noexcept
+ {
+ return (*this)(lhs, map(rhs));
+ }
+ constexpr bool operator()(QByteArrayView lhs, QByteArrayView rhs) const noexcept
+ {
+ // ### just `lhs < rhs` when QByteArrayView relational operators are constexpr
+ return std::string_view(lhs) < std::string_view(rhs);
+ }
+private:
+ static constexpr QByteArrayView map(quint8 i) noexcept
+ {
+ return headerNames.viewAt(i);
+ }
+};
+} // unnamed namespace
+
+// This index table contains the indexes of 'headerNames' entries (above) in alphabetical order.
+// This allows a more efficient binary search for the names [O(logN)]. The 'headerNames' itself
+// cannot be guaranteed to be in alphabetical order, as it must keep the same order as the
+// WellKnownHeader enum, which may get appended over time.
+//
+// Note: when appending new enums, this must be regenerated
+static constexpr quint8 orderedHeaderNameIndexes[] = {
+ 0, // a-im
+ 1, // accept
+ 2, // accept-additions
+ 3, // accept-ch
+ 172, // accept-charset
+ 4, // accept-datetime
+ 5, // accept-encoding
+ 6, // accept-features
+ 7, // accept-language
+ 8, // accept-patch
+ 9, // accept-post
+ 10, // accept-ranges
+ 11, // accept-signature
+ 12, // access-control-allow-credentials
+ 13, // access-control-allow-headers
+ 14, // access-control-allow-methods
+ 15, // access-control-allow-origin
+ 16, // access-control-expose-headers
+ 17, // access-control-max-age
+ 18, // access-control-request-headers
+ 19, // access-control-request-method
+ 20, // age
+ 21, // allow
+ 22, // alpn
+ 23, // alt-svc
+ 24, // alt-used
+ 25, // alternates
+ 26, // apply-to-redirect-ref
+ 27, // authentication-control
+ 28, // authentication-info
+ 29, // authorization
+ 173, // c-pep-info
+ 30, // cache-control
+ 31, // cache-status
+ 32, // cal-managed-id
+ 33, // caldav-timezones
+ 34, // capsule-protocol
+ 35, // cdn-cache-control
+ 36, // cdn-loop
+ 37, // cert-not-after
+ 38, // cert-not-before
+ 39, // clear-site-data
+ 40, // client-cert
+ 41, // client-cert-chain
+ 42, // close
+ 43, // connection
+ 44, // content-digest
+ 45, // content-disposition
+ 46, // content-encoding
+ 47, // content-id
+ 48, // content-language
+ 49, // content-length
+ 50, // content-location
+ 51, // content-range
+ 52, // content-security-policy
+ 53, // content-security-policy-report-only
+ 54, // content-type
+ 55, // cookie
+ 56, // cross-origin-embedder-policy
+ 57, // cross-origin-embedder-policy-report-only
+ 58, // cross-origin-opener-policy
+ 59, // cross-origin-opener-policy-report-only
+ 60, // cross-origin-resource-policy
+ 61, // dasl
+ 62, // date
+ 63, // dav
+ 64, // delta-base
+ 65, // depth
+ 66, // destination
+ 67, // differential-id
+ 68, // dpop
+ 69, // dpop-nonce
+ 70, // early-data
+ 71, // etag
+ 72, // expect
+ 73, // expect-ct
+ 74, // expires
+ 75, // forwarded
+ 76, // from
+ 77, // hobareg
+ 78, // host
+ 79, // if
+ 80, // if-match
+ 81, // if-modified-since
+ 82, // if-none-match
+ 83, // if-range
+ 84, // if-schedule-tag-match
+ 85, // if-unmodified-since
+ 86, // im
+ 87, // include-referred-token-binding-id
+ 88, // keep-alive
+ 89, // label
+ 90, // last-event-id
+ 91, // last-modified
+ 92, // link
+ 93, // location
+ 94, // lock-token
+ 95, // max-forwards
+ 96, // memento-datetime
+ 97, // meter
+ 98, // mime-version
+ 99, // negotiate
+ 100, // nel
+ 101, // odata-entityid
+ 102, // odata-isolation
+ 103, // odata-maxversion
+ 104, // odata-version
+ 105, // optional-www-authenticate
+ 106, // ordering-type
+ 107, // origin
+ 108, // origin-agent-cluster
+ 109, // oscore
+ 110, // oslc-core-version
+ 111, // overwrite
+ 112, // ping-from
+ 113, // ping-to
+ 114, // position
+ 174, // pragma
+ 115, // prefer
+ 116, // preference-applied
+ 117, // priority
+ 175, // protocol-info
+ 176, // protocol-query
+ 118, // proxy-authenticate
+ 119, // proxy-authentication-info
+ 120, // proxy-authorization
+ 121, // proxy-status
+ 122, // public-key-pins
+ 123, // public-key-pins-report-only
+ 124, // range
+ 125, // redirect-ref
+ 126, // referer
+ 127, // refresh
+ 128, // replay-nonce
+ 129, // repr-digest
+ 130, // retry-after
+ 131, // schedule-reply
+ 132, // schedule-tag
+ 133, // sec-purpose
+ 134, // sec-token-binding
+ 135, // sec-websocket-accept
+ 136, // sec-websocket-extensions
+ 137, // sec-websocket-key
+ 138, // sec-websocket-protocol
+ 139, // sec-websocket-version
+ 140, // server
+ 141, // server-timing
+ 142, // set-cookie
+ 143, // signature
+ 144, // signature-input
+ 145, // slug
+ 146, // soapaction
+ 147, // status-uri
+ 148, // strict-transport-security
+ 149, // sunset
+ 150, // surrogate-capability
+ 151, // surrogate-control
+ 152, // tcn
+ 153, // te
+ 154, // timeout
+ 155, // topic
+ 156, // traceparent
+ 157, // tracestate
+ 158, // trailer
+ 159, // transfer-encoding
+ 160, // ttl
+ 161, // upgrade
+ 162, // urgency
+ 163, // user-agent
+ 164, // variant-vary
+ 165, // vary
+ 166, // via
+ 167, // want-content-digest
+ 168, // want-repr-digest
+ 169, // www-authenticate
+ 170, // x-content-type-options
+ 171, // x-frame-options
+};
+static_assert(std::size(orderedHeaderNameIndexes) == size_t(headerNames.count()));
+static_assert(q20::is_sorted(std::begin(orderedHeaderNameIndexes),
+ std::end(orderedHeaderNameIndexes),
+ ByIndirectHeaderName{}));
+
+/*!
+ \enum QHttpHeaders::WellKnownHeader
+
+ List of well known headers as per
+ \l {https://www.iana.org/assignments/http-fields}{IANA registry}.
+
+ \value AIM
+ \value Accept
+ \value AcceptAdditions
+ \value AcceptCH
+ \value AcceptDatetime
+ \value AcceptEncoding
+ \value AcceptFeatures
+ \value AcceptLanguage
+ \value AcceptPatch
+ \value AcceptPost
+ \value AcceptRanges
+ \value AcceptSignature
+ \value AccessControlAllowCredentials
+ \value AccessControlAllowHeaders
+ \value AccessControlAllowMethods
+ \value AccessControlAllowOrigin
+ \value AccessControlExposeHeaders
+ \value AccessControlMaxAge
+ \value AccessControlRequestHeaders
+ \value AccessControlRequestMethod
+ \value Age
+ \value Allow
+ \value ALPN
+ \value AltSvc
+ \value AltUsed
+ \value Alternates
+ \value ApplyToRedirectRef
+ \value AuthenticationControl
+ \value AuthenticationInfo
+ \value Authorization
+ \value CacheControl
+ \value CacheStatus
+ \value CalManagedID
+ \value CalDAVTimezones
+ \value CapsuleProtocol
+ \value CDNCacheControl
+ \value CDNLoop
+ \value CertNotAfter
+ \value CertNotBefore
+ \value ClearSiteData
+ \value ClientCert
+ \value ClientCertChain
+ \value Close
+ \value Connection
+ \value ContentDigest
+ \value ContentDisposition
+ \value ContentEncoding
+ \value ContentID
+ \value ContentLanguage
+ \value ContentLength
+ \value ContentLocation
+ \value ContentRange
+ \value ContentSecurityPolicy
+ \value ContentSecurityPolicyReportOnly
+ \value ContentType
+ \value Cookie
+ \value CrossOriginEmbedderPolicy
+ \value CrossOriginEmbedderPolicyReportOnly
+ \value CrossOriginOpenerPolicy
+ \value CrossOriginOpenerPolicyReportOnly
+ \value CrossOriginResourcePolicy
+ \value DASL
+ \value Date
+ \value DAV
+ \value DeltaBase
+ \value Depth
+ \value Destination
+ \value DifferentialID
+ \value DPoP
+ \value DPoPNonce
+ \value EarlyData
+ \value ETag
+ \value Expect
+ \value ExpectCT
+ \value Expires
+ \value Forwarded
+ \value From
+ \value Hobareg
+ \value Host
+ \value If
+ \value IfMatch
+ \value IfModifiedSince
+ \value IfNoneMatch
+ \value IfRange
+ \value IfScheduleTagMatch
+ \value IfUnmodifiedSince
+ \value IM
+ \value IncludeReferredTokenBindingID
+ \value KeepAlive
+ \value Label
+ \value LastEventID
+ \value LastModified
+ \value Link
+ \value Location
+ \value LockToken
+ \value MaxForwards
+ \value MementoDatetime
+ \value Meter
+ \value MIMEVersion
+ \value Negotiate
+ \value NEL
+ \value ODataEntityId
+ \value ODataIsolation
+ \value ODataMaxVersion
+ \value ODataVersion
+ \value OptionalWWWAuthenticate
+ \value OrderingType
+ \value Origin
+ \value OriginAgentCluster
+ \value OSCORE
+ \value OSLCCoreVersion
+ \value Overwrite
+ \value PingFrom
+ \value PingTo
+ \value Position
+ \value Prefer
+ \value PreferenceApplied
+ \value Priority
+ \value ProxyAuthenticate
+ \value ProxyAuthenticationInfo
+ \value ProxyAuthorization
+ \value ProxyStatus
+ \value PublicKeyPins
+ \value PublicKeyPinsReportOnly
+ \value Range
+ \value RedirectRef
+ \value Referer
+ \value Refresh
+ \value ReplayNonce
+ \value ReprDigest
+ \value RetryAfter
+ \value ScheduleReply
+ \value ScheduleTag
+ \value SecPurpose
+ \value SecTokenBinding
+ \value SecWebSocketAccept
+ \value SecWebSocketExtensions
+ \value SecWebSocketKey
+ \value SecWebSocketProtocol
+ \value SecWebSocketVersion
+ \value Server
+ \value ServerTiming
+ \value SetCookie
+ \value Signature
+ \value SignatureInput
+ \value SLUG
+ \value SoapAction
+ \value StatusURI
+ \value StrictTransportSecurity
+ \value Sunset
+ \value SurrogateCapability
+ \value SurrogateControl
+ \value TCN
+ \value TE
+ \value Timeout
+ \value Topic
+ \value Traceparent
+ \value Tracestate
+ \value Trailer
+ \value TransferEncoding
+ \value TTL
+ \value Upgrade
+ \value Urgency
+ \value UserAgent
+ \value VariantVary
+ \value Vary
+ \value Via
+ \value WantContentDigest
+ \value WantReprDigest
+ \value WWWAuthenticate
+ \value XContentTypeOptions
+ \value XFrameOptions
+ \value AcceptCharset
+ \value CPEPInfo
+ \value Pragma
+ \value ProtocolInfo
+ \value ProtocolQuery
+*/
+
+static QByteArray fieldToByteArray(QLatin1StringView s) noexcept
+{
+ return QByteArray(s.data(), s.size());
+}
+
+static QByteArray fieldToByteArray(QUtf8StringView s) noexcept
+{
+ return QByteArray(s.data(), s.size());
+}
+
+static QByteArray fieldToByteArray(QStringView s)
+{
+ return s.toLatin1();
+}
+
+static QByteArray normalizedName(QAnyStringView name)
+{
+ return name.visit([](auto name){ return fieldToByteArray(name); }).toLower();
+}
+
+struct HeaderName
+{
+ explicit HeaderName(QHttpHeaders::WellKnownHeader name) : data(name)
+ {
+ }
+
+ explicit HeaderName(QAnyStringView name)
+ {
+ auto nname = normalizedName(name);
+ if (auto h = HeaderName::toWellKnownHeader(nname))
+ data = *h;
+ else
+ data = std::move(nname);
+ }
+
+ // Returns an enum corresponding with the 'name' if possible. Uses binary search (O(logN)).
+ // The function doesn't normalize the data; needs to be done by the caller if needed
+ static std::optional<QHttpHeaders::WellKnownHeader> toWellKnownHeader(QByteArrayView name) noexcept
+ {
+ auto indexesBegin = std::cbegin(orderedHeaderNameIndexes);
+ auto indexesEnd = std::cend(orderedHeaderNameIndexes);
+
+ auto result = std::lower_bound(indexesBegin, indexesEnd, name, ByIndirectHeaderName{});
+
+ if (result != indexesEnd && name == headerNames[*result])
+ return static_cast<QHttpHeaders::WellKnownHeader>(*result);
+ return std::nullopt;
+ }
+
+ QByteArrayView asView() const noexcept
+ {
+ return std::visit([](const auto &arg) -> QByteArrayView {
+ using T = decltype(arg);
+ if constexpr (std::is_same_v<T, const QByteArray &>)
+ return arg;
+ else if constexpr (std::is_same_v<T, const QHttpHeaders::WellKnownHeader &>)
+ return headerNames.viewAt(qToUnderlying(arg));
+ else
+ static_assert(QtPrivate::type_dependent_false<T>());
+ }, data);
+ }
+
+ QByteArray asByteArray() const noexcept
+ {
+ return std::visit([](const auto &arg) -> QByteArray {
+ using T = decltype(arg);
+ if constexpr (std::is_same_v<T, const QByteArray &>) {
+ return arg;
+ } else if constexpr (std::is_same_v<T, const QHttpHeaders::WellKnownHeader &>) {
+ const auto view = headerNames.viewAt(qToUnderlying(arg));
+ return QByteArray::fromRawData(view.constData(), view.size());
+ } else {
+ static_assert(QtPrivate::type_dependent_false<T>());
+ }
+ }, data);
+ }
+
+private:
+ // Store the data as 'enum' whenever possible; more performant, and comparison relies on that
+ std::variant<QHttpHeaders::WellKnownHeader, QByteArray> data;
+
+ friend bool comparesEqual(const HeaderName &lhs, const HeaderName &rhs) noexcept
+ {
+ // Here we compare two std::variants, which will return false if the types don't match.
+ // That is beneficial here because we avoid unnecessary comparisons; but it also means
+ // we must always store the data as WellKnownHeader when possible (in other words, if
+ // we get a string that is mappable to a WellKnownHeader). To guard against accidental
+ // misuse, the 'data' is private and the constructors must be used.
+ return lhs.data == rhs.data;
+ }
+ Q_DECLARE_EQUALITY_COMPARABLE(HeaderName)
+};
+
+// A clarification on case-sensitivity:
+// - Header *names* are case-insensitive; Content-Type and content-type are considered equal
+// - Header *values* are case-sensitive
+// (In addition, the HTTP/2 and HTTP/3 standards mandate that all headers must be lower-cased when
+// encoded into transmission)
+struct Header {
+ HeaderName name;
+ QByteArray value;
+};
+
+auto headerNameMatches(const HeaderName &name)
+{
+ return [&name](const Header &header) { return header.name == name; };
+}
+
+class QHttpHeadersPrivate : public QSharedData
+{
+public:
+ QHttpHeadersPrivate() = default;
+
+ // The 'Self' is supplied as parameter to static functions so that
+ // we can define common methods which 'detach()' the private itself.
+ using Self = QExplicitlySharedDataPointer<QHttpHeadersPrivate>;
+ static void removeAll(Self &d, const HeaderName &name);
+ static void replaceOrAppend(Self &d, const HeaderName &name, const QByteArray &value);
+
+ void combinedValue(const HeaderName &name, QByteArray &result) const;
+ void values(const HeaderName &name, QList<QByteArray> &result) const;
+ QByteArrayView value(const HeaderName &name, QByteArrayView defaultValue) const noexcept;
+
+ QList<Header> headers;
+};
+
+QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QHttpHeadersPrivate)
+template <> void QExplicitlySharedDataPointer<QHttpHeadersPrivate>::detach()
+{
+ if (!d) {
+ d = new QHttpHeadersPrivate();
+ d->ref.ref();
+ } else if (d->ref.loadRelaxed() != 1) {
+ detach_helper();
+ }
+}
+
+void QHttpHeadersPrivate::removeAll(Self &d, const HeaderName &name)
+{
+ const auto it = std::find_if(d->headers.cbegin(), d->headers.cend(), headerNameMatches(name));
+
+ if (it != d->headers.cend()) {
+ // Found something to remove, calculate offset so we can proceed from the match-location
+ const auto matchOffset = it - d->headers.cbegin();
+ d.detach();
+ // Rearrange all matches to the end and erase them
+ d->headers.erase(std::remove_if(d->headers.begin() + matchOffset, d->headers.end(),
+ headerNameMatches(name)),
+ d->headers.end());
+ }
+}
+
+void QHttpHeadersPrivate::combinedValue(const HeaderName &name, QByteArray &result) const
+{
+ const char* separator = "";
+ for (const auto &h : std::as_const(headers)) {
+ if (h.name == name) {
+ result.append(separator);
+ result.append(h.value);
+ separator = ", ";
+ }
+ }
+}
+
+void QHttpHeadersPrivate::values(const HeaderName &name, QList<QByteArray> &result) const
+{
+ for (const auto &h : std::as_const(headers)) {
+ if (h.name == name)
+ result.append(h.value);
+ }
+}
+
+QByteArrayView QHttpHeadersPrivate::value(const HeaderName &name, QByteArrayView defaultValue) const noexcept
+{
+ for (const auto &h : std::as_const(headers)) {
+ if (h.name == name)
+ return h.value;
+ }
+ return defaultValue;
+}
+
+void QHttpHeadersPrivate::replaceOrAppend(Self &d, const HeaderName &name, const QByteArray &value)
+{
+ d.detach();
+ auto it = std::find_if(d->headers.begin(), d->headers.end(), headerNameMatches(name));
+ if (it != d->headers.end()) {
+ // Found something to replace => replace, and then rearrange any remaining
+ // matches to the end and erase them
+ it->value = value;
+ d->headers.erase(
+ std::remove_if(it + 1, d->headers.end(), headerNameMatches(name)),
+ d->headers.end());
+ } else {
+ // Found nothing to replace => append
+ d->headers.append(Header{name, value});
+ }
+}
+
+/*!
+ Creates a new QHttpHeaders object.
+*/
+QHttpHeaders::QHttpHeaders() noexcept : d()
+{
+}
+
+/*!
+ Creates a new QHttpHeaders object that is populated with
+ \a headers.
+
+ \sa {Allowed field name and value characters}
+*/
+QHttpHeaders QHttpHeaders::fromListOfPairs(const QList<std::pair<QByteArray, QByteArray>> &headers)
+{
+ QHttpHeaders h;
+ h.reserve(headers.size());
+ for (const auto &header : headers)
+ h.append(header.first, header.second);
+ return h;
+}
+
+/*!
+ Creates a new QHttpHeaders object that is populated with
+ \a headers.
+
+ \sa {Allowed field name and value characters}
+*/
+QHttpHeaders QHttpHeaders::fromMultiMap(const QMultiMap<QByteArray, QByteArray> &headers)
+{
+ QHttpHeaders h;
+ h.reserve(headers.size());
+ for (const auto &[name,value] : headers.asKeyValueRange())
+ h.append(name, value);
+ return h;
+}
+
+/*!
+ Creates a new QHttpHeaders object that is populated with
+ \a headers.
+
+ \sa {Allowed field name and value characters}
+*/
+QHttpHeaders QHttpHeaders::fromMultiHash(const QMultiHash<QByteArray, QByteArray> &headers)
+{
+ QHttpHeaders h;
+ h.reserve(headers.size());
+ for (const auto &[name,value] : headers.asKeyValueRange())
+ h.append(name, value);
+ return h;
+}
+
+/*!
+ Disposes of the headers object.
+*/
+QHttpHeaders::~QHttpHeaders()
+ = default;
+
+/*!
+ Creates a copy of \a other.
+*/
+QHttpHeaders::QHttpHeaders(const QHttpHeaders &other)
+ = default;
+
+/*!
+ Assigns the contents of \a other and returns a reference to this object.
+*/
+QHttpHeaders &QHttpHeaders::operator=(const QHttpHeaders &other)
+ = default;
+
+/*!
+ \fn QHttpHeaders::QHttpHeaders(QHttpHeaders &&other) noexcept
+
+ Move-constructs the object from \a other, which will be left
+ \l{isEmpty()}{empty}.
+*/
+
+/*!
+ \fn QHttpHeaders &QHttpHeaders::operator=(QHttpHeaders &&other) noexcept
+
+ Move-assigns \a other and returns a reference to this object.
+
+ \a other will be left \l{isEmpty()}{empty}.
+*/
+
+/*!
+ \fn void QHttpHeaders::swap(QHttpHeaders &other)
+
+ Swaps this QHttpHeaders with \a other. This function is very fast and
+ never fails.
+*/
+
+#ifndef QT_NO_DEBUG_STREAM
+/*!
+ \fn QDebug QHttpHeaders::operator<<(QDebug debug,
+ const QHttpHeaders &headers)
+
+ Writes \a headers into \a debug stream.
+*/
+QDebug operator<<(QDebug debug, const QHttpHeaders &headers)
+{
+ const QDebugStateSaver saver(debug);
+ debug.resetFormat().nospace();
+
+ debug << "QHttpHeaders(";
+ if (headers.d) {
+ debug << "headers = ";
+ const char *separator = "";
+ for (const auto &h : headers.d->headers) {
+ debug << separator << h.name.asView() << ':' << h.value;
+ separator = " | ";
+ }
+ }
+ debug << ")";
+ return debug;
+}
+#endif
+
+// A clarification on string encoding:
+// Setters and getters only accept names and values that are Latin-1 representable:
+// Either they are directly ASCII/Latin-1, or if they are UTF-X, they only use first 256
+// of the unicode points. For example using a '€' (U+20AC) in value would yield a warning
+// and the call is ignored.
+// Furthermore the 'name' has more strict rules than the 'value'
+
+// TODO FIXME REMOVEME once this is merged:
+// https://codereview.qt-project.org/c/qt/qtbase/+/508829
+static bool isUtf8Latin1Representable(QUtf8StringView s) noexcept
+{
+ // L1 encoded in UTF8 has at most the form
+ // - 0b0XXX'XXXX - US-ASCII
+ // - 0b1100'00XX 0b10XX'XXXX - at most 8 non-zero LSB bits allowed in L1
+ bool inMultibyte = false;
+ for (unsigned char c : s) {
+ if (c < 128) { // US-ASCII
+ if (inMultibyte)
+ return false; // invalid sequence
+ } else {
+ // decode as UTF-8:
+ if ((c & 0b1110'0000) == 0b1100'0000) { // two-octet UTF-8 leader
+ if (inMultibyte)
+ return false; // invalid sequence
+ inMultibyte = true;
+ const auto bits_7_to_11 = c & 0b0001'1111;
+ if (bits_7_to_11 < 0b10)
+ return false; // invalid sequence (US-ASCII encoded in two octets)
+ if (bits_7_to_11 > 0b11) // more than the two LSB
+ return false; // outside L1
+ } else if ((c & 0b1100'0000) == 0b1000'0000) { // trailing UTF-8 octet
+ if (!inMultibyte)
+ return false; // invalid sequence
+ inMultibyte = false; // only one continuation allowed
+ } else {
+ return false; // invalid sequence or outside of L1
+ }
+ }
+ }
+ if (inMultibyte)
+ return false; // invalid sequence: premature end
+ return true;
+}
+
+static constexpr auto isValidHttpHeaderNameChar = [](uchar c) noexcept
+{
+ // RFC 9110 Chapters "5.1 Field Names" and "5.6.2 Tokens"
+ // field-name = token
+ // token = 1*tchar
+ // tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" /
+ // "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
+ // / DIGIT / ALPHA
+ // ; any VCHAR, except delimiters
+ // (for explanation on VCHAR see isValidHttpHeaderValueChar)
+ return (('A' <= c && c <= 'Z')
+ || ('a' <= c && c <= 'z')
+ || ('0' <= c && c <= '9')
+ || ('#' <= c && c <= '\'')
+ || ('^' <= c && c <= '`')
+ || c == '|' || c == '~' || c == '!' || c == '*' || c == '+' || c == '-' || c == '.');
+};
+
+static bool headerNameValidImpl(QLatin1StringView name) noexcept
+{
+ return std::all_of(name.begin(), name.end(), isValidHttpHeaderNameChar);
+}
+
+static bool headerNameValidImpl(QUtf8StringView name) noexcept
+{
+ // Traversing the UTF-8 string char-by-char is fine in this case as
+ // the isValidHttpHeaderNameChar rejects any value above 0x7E. UTF-8
+ // only has bytes <= 0x7F if they truly represent that ASCII character.
+ return headerNameValidImpl(QLatin1StringView(QByteArrayView(name)));
+}
+
+static bool headerNameValidImpl(QStringView name) noexcept
+{
+ return std::all_of(name.begin(), name.end(), [](QChar c) {
+ return isValidHttpHeaderNameChar(c.toLatin1());
+ });
+}
+
+static bool isValidHttpHeaderNameField(QAnyStringView name) noexcept
+{
+ if (name.isEmpty()) {
+ qCWarning(lcQHttpHeaders, "HTTP header name cannot be empty");
+ return false;
+ }
+ const bool valid = name.visit([](auto name){ return headerNameValidImpl(name); });
+ if (!valid)
+ qCWarning(lcQHttpHeaders, "HTTP header name contained illegal character(s)");
+ return valid;
+}
+
+static constexpr auto isValidHttpHeaderValueChar = [](uchar c) noexcept
+{
+ // RFC 9110 Chapter 5.5, Field Values
+ // field-value = *field-content
+ // field-content = field-vchar
+ // [ 1*( SP / HTAB / field-vchar ) field-vchar ]
+ // field-vchar = VCHAR / obs-text
+ // obs-text = %x80-FF
+ // VCHAR is defined as "any visible US-ASCII character", and RFC 5234 B.1.
+ // defines it as %x21-7E
+ // Note: The ABNF above states that field-content and thus field-value cannot
+ // start or end with SP/HTAB. The caller should handle this.
+ return (c >= 0x80 // obs-text (extended ASCII)
+ || (0x20 <= c && c <= 0x7E) // SP (0x20) + VCHAR
+ || (c == 0x09)); // HTAB
+};
+
+static bool headerValueValidImpl(QLatin1StringView value) noexcept
+{
+ return std::all_of(value.begin(), value.end(), isValidHttpHeaderValueChar);
+}
+
+static bool headerValueValidImpl(QUtf8StringView value) noexcept
+{
+ if (!isUtf8Latin1Representable(value)) // TODO FIXME see the function
+ return false;
+ return std::all_of(value.begin(), value.end(), isValidHttpHeaderValueChar);
+}
+
+static bool headerValueValidImpl(QStringView value) noexcept
+{
+ return std::all_of(value.begin(), value.end(), [](QChar c) {
+ return isValidHttpHeaderValueChar(c.toLatin1());
+ });
+}
+
+static bool isValidHttpHeaderValueField(QAnyStringView value) noexcept
+{
+ const bool valid = value.visit([](auto value){ return headerValueValidImpl(value); });
+ if (!valid)
+ qCWarning(lcQHttpHeaders, "HTTP header value contained illegal character(s)");
+ return valid;
+}
+
+static QByteArray normalizedValue(QAnyStringView value)
+{
+ // Note on trimming away any leading or trailing whitespace of 'value':
+ // RFC 9110 (HTTP 1.1, 2022, Chapter 5.5) does not allow leading or trailing whitespace
+ // RFC 7230 (HTTP 1.1, 2014, Chapter 3.2) allows them optionally, but also mandates that
+ // they are ignored during processing
+ // RFC 7540 (HTTP/2) does not seem explicit about it
+ // => for maximum compatibility, trim away any leading or trailing whitespace
+ return value.visit([](auto value){ return fieldToByteArray(value); }).trimmed();
+}
+
+/*!
+ Appends a header entry with \a name and \a value and returns \c true
+ if successful.
+
+ \sa append(QHttpHeaders::WellKnownHeader, QAnyStringView)
+ \sa {Allowed field name and value characters}
+*/
+bool QHttpHeaders::append(QAnyStringView name, QAnyStringView value)
+{
+ if (!isValidHttpHeaderNameField(name) || !isValidHttpHeaderValueField(value))
+ return false;
+
+ d.detach();
+ d->headers.push_back({HeaderName{name}, normalizedValue(value)});
+ return true;
+}
+
+/*!
+ \overload append(QAnyStringView, QAnyStringView)
+*/
+bool QHttpHeaders::append(WellKnownHeader name, QAnyStringView value)
+{
+ if (!isValidHttpHeaderValueField(value))
+ return false;
+
+ d.detach();
+ d->headers.push_back({HeaderName{name}, normalizedValue(value)});
+ return true;
+}
+
+/*!
+ Inserts a header entry at index \a i, with \a name and \a value. The index
+ must be valid (see \l size()). Returns whether the insert succeeded.
+
+ \sa append(),
+ insert(qsizetype, QHttpHeaders::WellKnownHeader, QAnyStringView), size()
+ \sa {Allowed field name and value characters}
+*/
+bool QHttpHeaders::insert(qsizetype i, QAnyStringView name, QAnyStringView value)
+{
+ verify(i, 0);
+ if (!isValidHttpHeaderNameField(name) || !isValidHttpHeaderValueField(value))
+ return false;
+
+ d.detach();
+ d->headers.insert(i, {HeaderName{name}, normalizedValue(value)});
+ return true;
+}
+
+/*!
+ \overload insert(qsizetype, QAnyStringView, QAnyStringView)
+*/
+bool QHttpHeaders::insert(qsizetype i, WellKnownHeader name, QAnyStringView value)
+{
+ verify(i, 0);
+ if (!isValidHttpHeaderValueField(value))
+ return false;
+
+ d.detach();
+ d->headers.insert(i, {HeaderName{name}, normalizedValue(value)});
+ return true;
+}
+
+/*!
+ Replaces the header entry at index \a i, with \a name and \a newValue.
+ The index must be valid (see \l size()). Returns whether the replace
+ succeeded.
+
+ \sa append(),
+ replace(qsizetype, QHttpHeaders::WellKnownHeader, QAnyStringView), size()
+ \sa {Allowed field name and value characters}
+*/
+bool QHttpHeaders::replace(qsizetype i, QAnyStringView name, QAnyStringView newValue)
+{
+ verify(i);
+ if (!isValidHttpHeaderNameField(name) || !isValidHttpHeaderValueField(newValue))
+ return false;
+
+ d.detach();
+ d->headers.replace(i, {HeaderName{name}, normalizedValue(newValue)});
+ return true;
+}
+
+/*!
+ \overload replace(qsizetype, QAnyStringView, QAnyStringView)
+*/
+bool QHttpHeaders::replace(qsizetype i, WellKnownHeader name, QAnyStringView newValue)
+{
+ verify(i);
+ if (!isValidHttpHeaderValueField(newValue))
+ return false;
+
+ d.detach();
+ d->headers.replace(i, {HeaderName{name}, normalizedValue(newValue)});
+ return true;
+}
+
+/*!
+ \since 6.8
+
+ If QHttpHeaders already contains \a name, replaces its value with
+ \a newValue and removes possible additional \a name entries.
+ If \a name didn't exist, appends a new entry. Returns \c true
+ if successful.
+
+ This function is a convenience method for setting a unique
+ \a name : \a newValue header. For most headers the relative order does not
+ matter, which allows reusing an existing entry if one exists.
+
+ \sa replaceOrAppend(QAnyStringView, QAnyStringView)
+*/
+bool QHttpHeaders::replaceOrAppend(WellKnownHeader name, QAnyStringView newValue)
+{
+ if (isEmpty())
+ return append(name, newValue);
+
+ if (!isValidHttpHeaderValueField(newValue))
+ return false;
+
+ QHttpHeadersPrivate::replaceOrAppend(d, HeaderName{name}, normalizedValue(newValue));
+ return true;
+}
+
+/*!
+ \overload replaceOrAppend(WellKnownHeader, QAnyStringView)
+*/
+bool QHttpHeaders::replaceOrAppend(QAnyStringView name, QAnyStringView newValue)
+{
+ if (isEmpty())
+ return append(name, newValue);
+
+ if (!isValidHttpHeaderNameField(name) || !isValidHttpHeaderValueField(newValue))
+ return false;
+
+ QHttpHeadersPrivate::replaceOrAppend(d, HeaderName{name}, normalizedValue(newValue));
+ return true;
+}
+
+/*!
+ Returns whether the headers contain header with \a name.
+
+ \sa contains(QHttpHeaders::WellKnownHeader)
+*/
+bool QHttpHeaders::contains(QAnyStringView name) const
+{
+ if (isEmpty())
+ return false;
+
+ return std::any_of(d->headers.cbegin(), d->headers.cend(), headerNameMatches(HeaderName{name}));
+}
+
+/*!
+ \overload has(QAnyStringView)
+*/
+bool QHttpHeaders::contains(WellKnownHeader name) const
+{
+ if (isEmpty())
+ return false;
+
+ return std::any_of(d->headers.cbegin(), d->headers.cend(), headerNameMatches(HeaderName{name}));
+}
+
+/*!
+ Removes the header \a name.
+
+ \sa removeAt(), removeAll(QHttpHeaders::WellKnownHeader)
+*/
+void QHttpHeaders::removeAll(QAnyStringView name)
+{
+ if (isEmpty())
+ return;
+
+ return QHttpHeadersPrivate::removeAll(d, HeaderName(name));
+}
+
+/*!
+ \overload removeAll(QAnyStringView)
+*/
+void QHttpHeaders::removeAll(WellKnownHeader name)
+{
+ if (isEmpty())
+ return;
+
+ return QHttpHeadersPrivate::removeAll(d, HeaderName(name));
+}
+
+/*!
+ Removes the header at index \a i. The index \a i must be valid
+ (see \l size()).
+
+ \sa removeAll(QHttpHeaders::WellKnownHeader),
+ removeAll(QAnyStringView), size()
+*/
+void QHttpHeaders::removeAt(qsizetype i)
+{
+ verify(i);
+ d.detach();
+ d->headers.removeAt(i);
+}
+
+/*!
+ Returns the value of the (first) header \a name, or \a defaultValue if it
+ doesn't exist.
+
+ \sa value(QHttpHeaders::WellKnownHeader, QByteArrayView)
+*/
+QByteArrayView QHttpHeaders::value(QAnyStringView name, QByteArrayView defaultValue) const noexcept
+{
+ if (isEmpty())
+ return defaultValue;
+
+ return d->value(HeaderName{name}, defaultValue);
+}
+
+/*!
+ \overload value(QAnyStringView, QByteArrayView)
+*/
+QByteArrayView QHttpHeaders::value(WellKnownHeader name, QByteArrayView defaultValue) const noexcept
+{
+ if (isEmpty())
+ return defaultValue;
+
+ return d->value(HeaderName{name}, defaultValue);
+}
+
+/*!
+ Returns the values of header \a name in a list. Returns an empty
+ list if header with \a name doesn't exist.
+
+ \sa values(QHttpHeaders::WellKnownHeader)
+*/
+QList<QByteArray> QHttpHeaders::values(QAnyStringView name) const
+{
+ QList<QByteArray> result;
+ if (isEmpty())
+ return result;
+
+ d->values(HeaderName{name}, result);
+ return result;
+}
+
+/*!
+ \overload values(QAnyStringView)
+*/
+QList<QByteArray> QHttpHeaders::values(WellKnownHeader name) const
+{
+ QList<QByteArray> result;
+ if (isEmpty())
+ return result;
+
+ d->values(HeaderName{name}, result);
+ return result;
+}
+
+/*!
+ Returns the header value at index \a i. The index \a i must be valid
+ (see \l size()).
+
+ \sa size(), value(), values(), combinedValue(), nameAt()
+*/
+QByteArrayView QHttpHeaders::valueAt(qsizetype i) const noexcept
+{
+ verify(i);
+ return d->headers.at(i).value;
+}
+
+/*!
+ Returns the header name at index \a i. The index \a i must be valid
+ (see \l size()).
+
+ Header names are case-insensitive, and the returned names are lower-cased.
+
+ \sa size(), valueAt()
+*/
+QLatin1StringView QHttpHeaders::nameAt(qsizetype i) const noexcept
+{
+ verify(i);
+ return QLatin1StringView{d->headers.at(i).name.asView()};
+}
+
+/*!
+ Returns the values of header \a name in a comma-combined string.
+ Returns a \c null QByteArray if the header with \a name doesn't
+ exist.
+
+ \note Accessing the value(s) of 'Set-Cookie' header this way may not work
+ as intended. It is a notable exception in the
+ \l {https://datatracker.ietf.org/doc/html/rfc9110#name-field-order}{HTTP RFC}
+ in that its values cannot be combined this way. Prefer \l values() instead.
+
+ \sa values(QAnyStringView)
+*/
+QByteArray QHttpHeaders::combinedValue(QAnyStringView name) const
+{
+ QByteArray result;
+ if (isEmpty())
+ return result;
+
+ d->combinedValue(HeaderName{name}, result);
+ return result;
+}
+
+/*!
+ \overload combinedValue(QAnyStringView)
+*/
+QByteArray QHttpHeaders::combinedValue(WellKnownHeader name) const
+{
+ QByteArray result;
+ if (isEmpty())
+ return result;
+
+ d->combinedValue(HeaderName{name}, result);
+ return result;
+}
+
+/*!
+ Returns the number of header entries.
+*/
+qsizetype QHttpHeaders::size() const noexcept
+{
+ if (!d)
+ return 0;
+ return d->headers.size();
+}
+
+/*!
+ Attempts to allocate memory for at least \a size header entries.
+
+ If you know in advance how how many header entries there will
+ be, you may call this function to prevent reallocations
+ and memory fragmentation.
+*/
+void QHttpHeaders::reserve(qsizetype size)
+{
+ d.detach();
+ d->headers.reserve(size);
+}
+
+/*!
+ \fn bool QHttpHeaders::isEmpty() const noexcept
+
+ Returns \c true if the headers have size 0; otherwise returns \c false.
+
+ \sa size()
+*/
+
+/*!
+ Returns a header name corresponding to the provided \a name as a view.
+*/
+QByteArrayView QHttpHeaders::wellKnownHeaderName(WellKnownHeader name) noexcept
+{
+ return headerNames[qToUnderlying(name)];
+}
+
+/*!
+ Returns the header entries as a list of (name, value) pairs.
+ Header names are case-insensitive, and the returned names are lower-cased.
+*/
+QList<std::pair<QByteArray, QByteArray>> QHttpHeaders::toListOfPairs() const
+{
+ QList<std::pair<QByteArray, QByteArray>> list;
+ if (isEmpty())
+ return list;
+ list.reserve(size());
+ for (const auto & h : std::as_const(d->headers))
+ list.append({h.name.asByteArray(), h.value});
+ return list;
+}
+
+/*!
+ Returns the header entries as a map from name to value(s).
+ Header names are case-insensitive, and the returned names are lower-cased.
+*/
+QMultiMap<QByteArray, QByteArray> QHttpHeaders::toMultiMap() const
+{
+ QMultiMap<QByteArray, QByteArray> map;
+ if (isEmpty())
+ return map;
+ for (const auto &h : std::as_const(d->headers))
+ map.insert(h.name.asByteArray(), h.value);
+ return map;
+}
+
+/*!
+ Returns the header entries as a hash from name to value(s).
+ Header names are case-insensitive, and the returned names are lower-cased.
+*/
+QMultiHash<QByteArray, QByteArray> QHttpHeaders::toMultiHash() const
+{
+ QMultiHash<QByteArray, QByteArray> hash;
+ if (isEmpty())
+ return hash;
+ hash.reserve(size());
+ for (const auto &h : std::as_const(d->headers))
+ hash.insert(h.name.asByteArray(), h.value);
+ return hash;
+}
+
+/*!
+ Clears all header entries.
+
+ \sa size()
+*/
+void QHttpHeaders::clear()
+{
+ if (isEmpty())
+ return;
+ d.detach();
+ d->headers.clear();
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/access/qhttpheaders.h b/src/network/access/qhttpheaders.h
new file mode 100644
index 0000000000..97dc415e55
--- /dev/null
+++ b/src/network/access/qhttpheaders.h
@@ -0,0 +1,281 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QHTTPHEADERS_H
+#define QHTTPHEADERS_H
+
+#include <QtNetwork/qnetworkrequest.h>
+#include <QtCore/qshareddata.h>
+#include <QtCore/qcontainerfwd.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDebug;
+
+class QHttpHeadersPrivate;
+QT_DECLARE_QESDP_SPECIALIZATION_DTOR_WITH_EXPORT(QHttpHeadersPrivate, Q_NETWORK_EXPORT)
+class QHttpHeaders
+{
+ Q_GADGET_EXPORT(Q_NETWORK_EXPORT)
+public:
+ enum class WellKnownHeader {
+ // IANA Permanent status:
+ AIM,
+ Accept,
+ AcceptAdditions,
+ AcceptCH,
+ AcceptDatetime,
+ AcceptEncoding,
+ AcceptFeatures,
+ AcceptLanguage,
+ AcceptPatch,
+ AcceptPost,
+ AcceptRanges,
+ AcceptSignature,
+ AccessControlAllowCredentials,
+ AccessControlAllowHeaders,
+ AccessControlAllowMethods,
+ AccessControlAllowOrigin,
+ AccessControlExposeHeaders,
+ AccessControlMaxAge,
+ AccessControlRequestHeaders,
+ AccessControlRequestMethod,
+ Age,
+ Allow,
+ ALPN,
+ AltSvc,
+ AltUsed,
+ Alternates,
+ ApplyToRedirectRef,
+ AuthenticationControl,
+ AuthenticationInfo,
+ Authorization,
+ CacheControl,
+ CacheStatus,
+ CalManagedID,
+ CalDAVTimezones,
+ CapsuleProtocol,
+ CDNCacheControl,
+ CDNLoop,
+ CertNotAfter,
+ CertNotBefore,
+ ClearSiteData,
+ ClientCert,
+ ClientCertChain,
+ Close,
+ Connection,
+ ContentDigest,
+ ContentDisposition,
+ ContentEncoding,
+ ContentID,
+ ContentLanguage,
+ ContentLength,
+ ContentLocation,
+ ContentRange,
+ ContentSecurityPolicy,
+ ContentSecurityPolicyReportOnly,
+ ContentType,
+ Cookie,
+ CrossOriginEmbedderPolicy,
+ CrossOriginEmbedderPolicyReportOnly,
+ CrossOriginOpenerPolicy,
+ CrossOriginOpenerPolicyReportOnly,
+ CrossOriginResourcePolicy,
+ DASL,
+ Date,
+ DAV,
+ DeltaBase,
+ Depth,
+ Destination,
+ DifferentialID,
+ DPoP,
+ DPoPNonce,
+ EarlyData,
+ ETag,
+ Expect,
+ ExpectCT,
+ Expires,
+ Forwarded,
+ From,
+ Hobareg,
+ Host,
+ If,
+ IfMatch,
+ IfModifiedSince,
+ IfNoneMatch,
+ IfRange,
+ IfScheduleTagMatch,
+ IfUnmodifiedSince,
+ IM,
+ IncludeReferredTokenBindingID,
+ KeepAlive,
+ Label,
+ LastEventID,
+ LastModified,
+ Link,
+ Location,
+ LockToken,
+ MaxForwards,
+ MementoDatetime,
+ Meter,
+ MIMEVersion,
+ Negotiate,
+ NEL,
+ ODataEntityId,
+ ODataIsolation,
+ ODataMaxVersion,
+ ODataVersion,
+ OptionalWWWAuthenticate,
+ OrderingType,
+ Origin,
+ OriginAgentCluster,
+ OSCORE,
+ OSLCCoreVersion,
+ Overwrite,
+ PingFrom,
+ PingTo,
+ Position,
+ Prefer,
+ PreferenceApplied,
+ Priority,
+ ProxyAuthenticate,
+ ProxyAuthenticationInfo,
+ ProxyAuthorization,
+ ProxyStatus,
+ PublicKeyPins,
+ PublicKeyPinsReportOnly,
+ Range,
+ RedirectRef,
+ Referer,
+ Refresh,
+ ReplayNonce,
+ ReprDigest,
+ RetryAfter,
+ ScheduleReply,
+ ScheduleTag,
+ SecPurpose,
+ SecTokenBinding,
+ SecWebSocketAccept,
+ SecWebSocketExtensions,
+ SecWebSocketKey,
+ SecWebSocketProtocol,
+ SecWebSocketVersion,
+ Server,
+ ServerTiming,
+ SetCookie,
+ Signature,
+ SignatureInput,
+ SLUG,
+ SoapAction,
+ StatusURI,
+ StrictTransportSecurity,
+ Sunset,
+ SurrogateCapability,
+ SurrogateControl,
+ TCN,
+ TE,
+ Timeout,
+ Topic,
+ Traceparent,
+ Tracestate,
+ Trailer,
+ TransferEncoding,
+ TTL,
+ Upgrade,
+ Urgency,
+ UserAgent,
+ VariantVary,
+ Vary,
+ Via,
+ WantContentDigest,
+ WantReprDigest,
+ WWWAuthenticate,
+ XContentTypeOptions,
+ XFrameOptions,
+ // IANA Deprecated status:
+ AcceptCharset,
+ CPEPInfo,
+ Pragma,
+ ProtocolInfo,
+ ProtocolQuery,
+ };
+ Q_ENUM(WellKnownHeader)
+
+ Q_NETWORK_EXPORT QHttpHeaders() noexcept;
+ Q_NETWORK_EXPORT ~QHttpHeaders();
+
+ Q_NETWORK_EXPORT QHttpHeaders(const QHttpHeaders &other);
+ QHttpHeaders(QHttpHeaders &&other) noexcept = default;
+ Q_NETWORK_EXPORT QHttpHeaders &operator=(const QHttpHeaders &other);
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QHttpHeaders)
+ void swap(QHttpHeaders &other) noexcept { d.swap(other.d); }
+
+ Q_NETWORK_EXPORT bool append(QAnyStringView name, QAnyStringView value);
+ Q_NETWORK_EXPORT bool append(WellKnownHeader name, QAnyStringView value);
+
+ Q_NETWORK_EXPORT bool insert(qsizetype i, QAnyStringView name, QAnyStringView value);
+ Q_NETWORK_EXPORT bool insert(qsizetype i, WellKnownHeader name, QAnyStringView value);
+
+ Q_NETWORK_EXPORT bool replace(qsizetype i, QAnyStringView name, QAnyStringView newValue);
+ Q_NETWORK_EXPORT bool replace(qsizetype i, WellKnownHeader name, QAnyStringView newValue);
+
+ Q_NETWORK_EXPORT bool replaceOrAppend(QAnyStringView name, QAnyStringView newValue);
+ Q_NETWORK_EXPORT bool replaceOrAppend(WellKnownHeader name, QAnyStringView newValue);
+
+ Q_NETWORK_EXPORT bool contains(QAnyStringView name) const;
+ Q_NETWORK_EXPORT bool contains(WellKnownHeader name) const;
+
+ Q_NETWORK_EXPORT void clear();
+ Q_NETWORK_EXPORT void removeAll(QAnyStringView name);
+ Q_NETWORK_EXPORT void removeAll(WellKnownHeader name);
+ Q_NETWORK_EXPORT void removeAt(qsizetype i);
+
+ Q_NETWORK_EXPORT QByteArrayView value(QAnyStringView name, QByteArrayView defaultValue = {}) const noexcept;
+ Q_NETWORK_EXPORT QByteArrayView value(WellKnownHeader name, QByteArrayView defaultValue = {}) const noexcept;
+
+ Q_NETWORK_EXPORT QList<QByteArray> values(QAnyStringView name) const;
+ Q_NETWORK_EXPORT QList<QByteArray> values(WellKnownHeader name) const;
+
+ Q_NETWORK_EXPORT QByteArrayView valueAt(qsizetype i) const noexcept;
+ Q_NETWORK_EXPORT QLatin1StringView nameAt(qsizetype i) const noexcept;
+
+ Q_NETWORK_EXPORT QByteArray combinedValue(QAnyStringView name) const;
+ Q_NETWORK_EXPORT QByteArray combinedValue(WellKnownHeader name) const;
+
+ Q_NETWORK_EXPORT qsizetype size() const noexcept;
+ Q_NETWORK_EXPORT void reserve(qsizetype size);
+ bool isEmpty() const noexcept { return size() == 0; }
+
+ Q_NETWORK_EXPORT static QByteArrayView wellKnownHeaderName(WellKnownHeader name) noexcept;
+
+ Q_NETWORK_EXPORT static QHttpHeaders
+ fromListOfPairs(const QList<std::pair<QByteArray, QByteArray>> &headers);
+ Q_NETWORK_EXPORT static QHttpHeaders
+ fromMultiMap(const QMultiMap<QByteArray, QByteArray> &headers);
+ Q_NETWORK_EXPORT static QHttpHeaders
+ fromMultiHash(const QMultiHash<QByteArray, QByteArray> &headers);
+
+ Q_NETWORK_EXPORT QList<std::pair<QByteArray, QByteArray>> toListOfPairs() const;
+ Q_NETWORK_EXPORT QMultiMap<QByteArray, QByteArray> toMultiMap() const;
+ Q_NETWORK_EXPORT QMultiHash<QByteArray, QByteArray> toMultiHash() const;
+
+private:
+#ifndef QT_NO_DEBUG_STREAM
+ friend Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, const QHttpHeaders &headers);
+#endif
+ Q_ALWAYS_INLINE void verify([[maybe_unused]] qsizetype pos = 0,
+ [[maybe_unused]] qsizetype n = 1) const
+ {
+ Q_ASSERT(pos >= 0);
+ Q_ASSERT(pos <= size());
+ Q_ASSERT(n >= 0);
+ Q_ASSERT(n <= size() - pos);
+ }
+ QExplicitlySharedDataPointer<QHttpHeadersPrivate> d;
+};
+
+Q_DECLARE_SHARED(QHttpHeaders)
+
+QT_END_NAMESPACE
+
+#endif // QHTTPHEADERS_H
diff --git a/src/network/access/qhttpmultipart.cpp b/src/network/access/qhttpmultipart.cpp
index d6fefc4314..6d81f1b957 100644
--- a/src/network/access/qhttpmultipart.cpp
+++ b/src/network/access/qhttpmultipart.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qhttpmultipart.h"
#include "qhttpmultipart_p.h"
@@ -353,11 +317,11 @@ void QHttpMultiPart::setBoundary(const QByteArray &boundary)
qint64 QHttpPartPrivate::bytesAvailable() const
{
checkHeaderCreated();
- qint64 bytesAvailable = header.count();
+ qint64 bytesAvailable = header.size();
if (bodyDevice) {
bytesAvailable += bodyDevice->bytesAvailable() - readPointer;
} else {
- bytesAvailable += body.count() - readPointer;
+ bytesAvailable += body.size() - readPointer;
}
// the device might have closed etc., so make sure we do not return a negative value
return qMax(bytesAvailable, (qint64) 0);
@@ -367,7 +331,7 @@ qint64 QHttpPartPrivate::readData(char *data, qint64 maxSize)
{
checkHeaderCreated();
qint64 bytesRead = 0;
- qint64 headerDataCount = header.count();
+ qint64 headerDataCount = header.size();
// read header if it has not been read yet
if (readPointer < headerDataCount) {
@@ -385,7 +349,7 @@ qint64 QHttpPartPrivate::readData(char *data, qint64 maxSize)
bytesRead += dataBytesRead;
readPointer += dataBytesRead;
} else {
- qint64 contentBytesRead = qMin(body.count() - readPointer + headerDataCount, maxSize - bytesRead);
+ qint64 contentBytesRead = qMin(body.size() - readPointer + headerDataCount, maxSize - bytesRead);
const char *contentData = body.constData();
// if this method is called several times, we need to find the
// right offset in the content ourselves:
@@ -400,11 +364,11 @@ qint64 QHttpPartPrivate::readData(char *data, qint64 maxSize)
qint64 QHttpPartPrivate::size() const
{
checkHeaderCreated();
- qint64 size = header.count();
+ qint64 size = header.size();
if (bodyDevice) {
size += bodyDevice->size();
} else {
- size += body.count();
+ size += body.size();
}
return size;
}
@@ -422,10 +386,9 @@ void QHttpPartPrivate::checkHeaderCreated() const
{
if (!headerCreated) {
// copied from QHttpNetworkRequestPrivate::header() and adapted
- QList<QPair<QByteArray, QByteArray> > fields = allRawHeaders();
- QList<QPair<QByteArray, QByteArray> >::const_iterator it = fields.constBegin();
- for (; it != fields.constEnd(); ++it)
- header += it->first + ": " + it->second + "\r\n";
+ const auto fields = allRawHeaders();
+ for (const auto &[name, value] : fields)
+ header += name + ": " + value + "\r\n";
header += "\r\n";
headerCreated = true;
}
@@ -440,7 +403,7 @@ QHttpMultiPartPrivate::QHttpMultiPartPrivate() : contentType(QHttpMultiPart::Mix
+ QByteArray::fromRawData(reinterpret_cast<char *>(random), sizeof(random)).toBase64();
// boundary must not be longer than 70 characters, see RFC 2046, section 5.1.1
- Q_ASSERT(boundary.count() <= 70);
+ Q_ASSERT(boundary.size() <= 70);
}
qint64 QHttpMultiPartIODevice::size() const
@@ -449,8 +412,8 @@ qint64 QHttpMultiPartIODevice::size() const
// including boundary (needed later in readData)
if (deviceSize == -1) {
qint64 currentSize = 0;
- qint64 boundaryCount = multiPart->boundary.count();
- for (int a = 0; a < multiPart->parts.count(); a++) {
+ qint64 boundaryCount = multiPart->boundary.size();
+ for (int a = 0; a < multiPart->parts.size(); a++) {
partOffsets.append(currentSize);
// 4 additional bytes for the "--" before and the "\r\n" after the boundary,
// and 2 bytes for the "\r\n" after the content
@@ -464,7 +427,7 @@ qint64 QHttpMultiPartIODevice::size() const
bool QHttpMultiPartIODevice::isSequential() const
{
- for (int a = 0; a < multiPart->parts.count(); a++) {
+ for (int a = 0; a < multiPart->parts.size(); a++) {
QIODevice *device = multiPart->parts.at(a).d->bodyDevice;
// we are sequential if any of the bodyDevices of our parts are sequential;
// when reading from a byte array, we are not sequential
@@ -478,7 +441,7 @@ bool QHttpMultiPartIODevice::reset()
{
// Reset QIODevice's data
QIODevice::reset();
- for (int a = 0; a < multiPart->parts.count(); a++)
+ for (int a = 0; a < multiPart->parts.size(); a++)
if (!multiPart->parts[a].d->reset())
return false;
readPointer = 0;
@@ -489,17 +452,17 @@ qint64 QHttpMultiPartIODevice::readData(char *data, qint64 maxSize)
qint64 bytesRead = 0, index = 0;
// skip the parts we have already read
- while (index < multiPart->parts.count() &&
+ while (index < multiPart->parts.size() &&
readPointer >= partOffsets.at(index) + multiPart->parts.at(index).d->size()
- + multiPart->boundary.count() + 6) // 6 == 2 boundary dashes, \r\n after boundary, \r\n after multipart
+ + multiPart->boundary.size() + 6) // 6 == 2 boundary dashes, \r\n after boundary, \r\n after multipart
index++;
// read the data
- while (bytesRead < maxSize && index < multiPart->parts.count()) {
+ while (bytesRead < maxSize && index < multiPart->parts.size()) {
// check whether we need to read the boundary of the current part
QByteArray boundaryData = "--" + multiPart->boundary + "\r\n";
- qint64 boundaryCount = boundaryData.count();
+ qint64 boundaryCount = boundaryData.size();
qint64 partIndex = readPointer - partOffsets.at(index);
if (partIndex < boundaryCount) {
qint64 boundaryBytesRead = qMin(boundaryCount - partIndex, maxSize - bytesRead);
@@ -530,10 +493,10 @@ qint64 QHttpMultiPartIODevice::readData(char *data, qint64 maxSize)
}
}
// check whether we need to return the final boundary
- if (bytesRead < maxSize && index == multiPart->parts.count()) {
+ if (bytesRead < maxSize && index == multiPart->parts.size()) {
QByteArray finalBoundary = "--" + multiPart->boundary + "--\r\n";
- qint64 boundaryIndex = readPointer + finalBoundary.count() - size();
- qint64 lastBoundaryBytesRead = qMin(finalBoundary.count() - boundaryIndex, maxSize - bytesRead);
+ qint64 boundaryIndex = readPointer + finalBoundary.size() - size();
+ qint64 lastBoundaryBytesRead = qMin(finalBoundary.size() - boundaryIndex, maxSize - bytesRead);
memcpy(data + bytesRead, finalBoundary.constData() + boundaryIndex, lastBoundaryBytesRead);
bytesRead += lastBoundaryBytesRead;
readPointer += lastBoundaryBytesRead;
@@ -550,3 +513,5 @@ qint64 QHttpMultiPartIODevice::writeData(const char *data, qint64 maxSize)
QT_END_NAMESPACE
+
+#include "moc_qhttpmultipart.cpp"
diff --git a/src/network/access/qhttpmultipart.h b/src/network/access/qhttpmultipart.h
index 7f07008c0f..26e5fafdf2 100644
--- a/src/network/access/qhttpmultipart.h
+++ b/src/network/access/qhttpmultipart.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QHTTPMULTIPART_H
#define QHTTPMULTIPART_H
@@ -65,7 +29,7 @@ public:
QHttpPart &operator=(QHttpPart &&other) noexcept { swap(other); return *this; }
QHttpPart &operator=(const QHttpPart &other);
- void swap(QHttpPart &other) noexcept { qSwap(d, other.d); }
+ void swap(QHttpPart &other) noexcept { d.swap(other.d); }
bool operator==(const QHttpPart &other) const;
inline bool operator!=(const QHttpPart &other) const
diff --git a/src/network/access/qhttpmultipart_p.h b/src/network/access/qhttpmultipart_p.h
index e7fd2d6d3d..d485fcf5cd 100644
--- a/src/network/access/qhttpmultipart_p.h
+++ b/src/network/access/qhttpmultipart_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QHTTPMULTIPART_P_H
#define QHTTPMULTIPART_P_H
diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp
index c133a09044..1897380e0e 100644
--- a/src/network/access/qhttpnetworkconnection.cpp
+++ b/src/network/access/qhttpnetworkconnection.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qhttpnetworkconnection_p.h"
#include <private/qabstractsocket_p.h>
@@ -48,10 +12,13 @@
#include <qnetworkproxy.h>
#include <qauthenticator.h>
#include <qcoreapplication.h>
+#include <private/qdecompresshelper_p.h>
#include <qbuffer.h>
#include <qpair.h>
#include <qdebug.h>
+#include <qspan.h>
+#include <qvarlengtharray.h>
#ifndef QT_NO_SSL
# include <private/qsslsocket_p.h>
@@ -65,7 +32,7 @@
QT_BEGIN_NAMESPACE
-const int QHttpNetworkConnectionPrivate::defaultHttpChannelCount = 6;
+using namespace Qt::StringLiterals;
// The pipeline length. So there will be 4 requests in flight.
const int QHttpNetworkConnectionPrivate::defaultPipelineLength = 3;
@@ -73,43 +40,33 @@ const int QHttpNetworkConnectionPrivate::defaultPipelineLength = 3;
// This means that there are 2 requests in flight and 2 slots free that will be re-filled.
const int QHttpNetworkConnectionPrivate::defaultRePipelineLength = 2;
-
-QHttpNetworkConnectionPrivate::QHttpNetworkConnectionPrivate(const QString &hostName,
- quint16 port, bool encrypt,
- QHttpNetworkConnection::ConnectionType type)
-: state(RunningState),
- networkLayerState(Unknown),
- hostName(hostName), port(port), encrypt(encrypt), delayIpv4(true)
- , activeChannelCount(type == QHttpNetworkConnection::ConnectionTypeHTTP2
- || type == QHttpNetworkConnection::ConnectionTypeHTTP2Direct
- ? 1 : defaultHttpChannelCount)
- , channelCount(defaultHttpChannelCount)
-#ifndef QT_NO_NETWORKPROXY
- , networkProxy(QNetworkProxy::NoProxy)
-#endif
- , preConnectRequests(0)
- , connectionType(type)
+static int getPreferredActiveChannelCount(QHttpNetworkConnection::ConnectionType type,
+ int defaultValue)
{
- // We allocate all 6 channels even if it's HTTP/2 enabled connection:
- // in case the protocol negotiation via NPN/ALPN fails, we will have
- // normally working HTTP/1.1.
- Q_ASSERT(channelCount >= activeChannelCount);
- channels = new QHttpNetworkConnectionChannel[channelCount];
+ return (type == QHttpNetworkConnection::ConnectionTypeHTTP2
+ || type == QHttpNetworkConnection::ConnectionTypeHTTP2Direct)
+ ? 1
+ : defaultValue;
}
-QHttpNetworkConnectionPrivate::QHttpNetworkConnectionPrivate(quint16 connectionCount, const QString &hostName,
- quint16 port, bool encrypt,
- QHttpNetworkConnection::ConnectionType type)
-: state(RunningState), networkLayerState(Unknown),
- hostName(hostName), port(port), encrypt(encrypt), delayIpv4(true),
- activeChannelCount(connectionCount), channelCount(connectionCount)
+QHttpNetworkConnectionPrivate::QHttpNetworkConnectionPrivate(
+ quint16 connectionCount, const QString &hostName, quint16 port, bool encrypt,
+ QHttpNetworkConnection::ConnectionType type)
+ : hostName(hostName),
+ port(port),
+ encrypt(encrypt),
+ activeChannelCount(getPreferredActiveChannelCount(type, connectionCount)),
+ channelCount(connectionCount),
+ channels(new QHttpNetworkConnectionChannel[channelCount]),
#ifndef QT_NO_NETWORKPROXY
- , networkProxy(QNetworkProxy::NoProxy)
+ networkProxy(QNetworkProxy::NoProxy),
#endif
- , preConnectRequests(0)
- , connectionType(type)
+ connectionType(type)
{
- channels = new QHttpNetworkConnectionChannel[channelCount];
+ // We allocate all 6 channels even if it's an HTTP/2-enabled
+ // connection: in case the protocol negotiation via NPN/ALPN fails,
+ // we will have normally working HTTP/1.1.
+ Q_ASSERT(channelCount >= activeChannelCount);
}
@@ -178,7 +135,7 @@ void QHttpNetworkConnectionPrivate::resumeConnection()
QMetaObject::invokeMethod(this->q_func(), "_q_startNextRequest", Qt::QueuedConnection);
}
-int QHttpNetworkConnectionPrivate::indexOf(QAbstractSocket *socket) const
+int QHttpNetworkConnectionPrivate::indexOf(QIODevice *socket) const
{
for (int i = 0; i < activeChannelCount; ++i)
if (channels[i].socket == socket)
@@ -192,7 +149,7 @@ int QHttpNetworkConnectionPrivate::indexOf(QAbstractSocket *socket) const
// emitted. This function will check the status of the connection channels if we
// have not decided the networkLayerState and will return true if the channel error
// should be emitted by the channel.
-bool QHttpNetworkConnectionPrivate::shouldEmitChannelError(QAbstractSocket *socket)
+bool QHttpNetworkConnectionPrivate::shouldEmitChannelError(QIODevice *socket)
{
Q_Q(QHttpNetworkConnection);
@@ -250,6 +207,17 @@ qint64 QHttpNetworkConnectionPrivate::uncompressedBytesAvailableNextBlock(const
return reply.d_func()->responseData.sizeNextBlock();
}
+static QByteArray makeAcceptLanguage()
+{
+ QString systemLocale = QLocale::system().name();
+ if (systemLocale == "C"_L1)
+ return "en,*"_ba;
+ systemLocale.replace('_'_L1, '-'_L1);
+ if (systemLocale.startsWith("en-"_L1))
+ return (systemLocale + ",*"_L1).toLatin1();
+ return (systemLocale + ",en,*"_L1).toLatin1();
+}
+
void QHttpNetworkConnectionPrivate::prepareRequest(HttpMessagePair &messagePair)
{
QHttpNetworkRequest &request = messagePair.first;
@@ -257,15 +225,16 @@ void QHttpNetworkConnectionPrivate::prepareRequest(HttpMessagePair &messagePair)
// add missing fields for the request
QByteArray value;
+#ifndef Q_OS_WASM
// check if Content-Length is provided
QNonContiguousByteDevice* uploadByteDevice = request.uploadByteDevice();
-#ifndef Q_OS_WASM
if (uploadByteDevice) {
const qint64 contentLength = request.contentLength();
const qint64 uploadDeviceSize = uploadByteDevice->size();
if (contentLength != -1 && uploadDeviceSize != -1) {
- // both values known, take the smaller one.
- request.setContentLength(qMin(uploadDeviceSize, contentLength));
+ // Both values known: use the smaller one.
+ if (uploadDeviceSize < contentLength)
+ request.setContentLength(uploadDeviceSize);
} else if (contentLength == -1 && uploadDeviceSize != -1) {
// content length not supplied by user, but the upload device knows it
request.setContentLength(uploadDeviceSize);
@@ -299,8 +268,8 @@ void QHttpNetworkConnectionPrivate::prepareRequest(HttpMessagePair &messagePair)
value = request.headerField("accept-encoding");
if (value.isEmpty()) {
#ifndef QT_NO_COMPRESS
- const QByteArrayList &acceptedEncoding = QDecompressHelper::acceptedEncoding();
- request.setHeaderField("Accept-Encoding", acceptedEncoding.join(", "));
+ const static QByteArray acceptedEncoding = QDecompressHelper::acceptedEncoding().join(", ");
+ request.setHeaderField("Accept-Encoding", acceptedEncoding);
request.d->autoDecompress = true;
#else
// if zlib is not available set this to false always
@@ -313,17 +282,8 @@ void QHttpNetworkConnectionPrivate::prepareRequest(HttpMessagePair &messagePair)
// not with us, but we work around this by setting
// one always.
value = request.headerField("accept-language");
- if (value.isEmpty()) {
- QString systemLocale = QLocale::system().name().replace(QChar::fromLatin1('_'),QChar::fromLatin1('-'));
- QString acceptLanguage;
- if (systemLocale == QLatin1String("C"))
- acceptLanguage = QString::fromLatin1("en,*");
- else if (systemLocale.startsWith(QLatin1String("en-")))
- acceptLanguage = systemLocale + QLatin1String(",*");
- else
- acceptLanguage = systemLocale + QLatin1String(",en,*");
- request.setHeaderField("Accept-Language", std::move(acceptLanguage).toLatin1());
- }
+ if (value.isEmpty())
+ request.setHeaderField("Accept-Language", makeAcceptLanguage());
// set the User Agent
value = request.headerField("user-agent");
@@ -336,7 +296,7 @@ void QHttpNetworkConnectionPrivate::prepareRequest(HttpMessagePair &messagePair)
QByteArray host;
if (add.setAddress(hostName)) {
if (add.protocol() == QAbstractSocket::IPv6Protocol)
- host = '[' + hostName.toLatin1() + ']'; //format the ipv6 in the standard way
+ host = (u'[' + hostName + u']').toLatin1(); //format the ipv6 in the standard way
else
host = hostName.toLatin1();
@@ -397,10 +357,12 @@ void QHttpNetworkConnectionPrivate::copyCredentials(int fromChannel, QAuthentica
// NTLM and Negotiate do multi-phase authentication.
// Copying credentialsbetween authenticators would mess things up.
if (fromChannel >= 0) {
- const QHttpNetworkConnectionChannel &channel = channels[fromChannel];
- const QAuthenticatorPrivate::Method method = isProxy ? channel.proxyAuthMethod : channel.authMethod;
- if (method == QAuthenticatorPrivate::Ntlm || method == QAuthenticatorPrivate::Negotiate)
+ QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(*auth);
+ if (priv
+ && (priv->method == QAuthenticatorPrivate::Ntlm
+ || priv->method == QAuthenticatorPrivate::Negotiate)) {
return;
+ }
}
// select another channel
@@ -430,35 +392,34 @@ bool QHttpNetworkConnectionPrivate::handleAuthenticateChallenge(QAbstractSocket
resend = false;
//create the response header to be used with QAuthenticatorPrivate.
- QList<QPair<QByteArray, QByteArray> > fields = reply->header();
-
- //find out the type of authentication protocol requested.
- QAuthenticatorPrivate::Method authMethod = reply->d_func()->authenticationMethod(isProxy);
- if (authMethod != QAuthenticatorPrivate::None) {
+ const auto headers = reply->header();
+
+ // Check that any of the proposed authenticate methods are supported
+ const QByteArray header = isProxy ? "proxy-authenticate" : "www-authenticate";
+ const QByteArrayList &authenticationMethods = reply->d_func()->headerFieldValues(header);
+ const bool isSupported = std::any_of(authenticationMethods.begin(), authenticationMethods.end(),
+ QAuthenticatorPrivate::isMethodSupported);
+ if (isSupported) {
int i = indexOf(socket);
//Use a single authenticator for all domains. ### change later to use domain/realm
- QAuthenticator* auth = nullptr;
- if (isProxy) {
- auth = &channels[i].proxyAuthenticator;
- channels[i].proxyAuthMethod = authMethod;
- } else {
- auth = &channels[i].authenticator;
- channels[i].authMethod = authMethod;
- }
+ QAuthenticator *auth = isProxy ? &channels[i].proxyAuthenticator
+ : &channels[i].authenticator;
//proceed with the authentication.
if (auth->isNull())
auth->detach();
QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(*auth);
- priv->parseHttpResponse(fields, isProxy, reply->url().host());
+ priv->parseHttpResponse(headers, isProxy, reply->url().host());
// Update method in case it changed
if (priv->method == QAuthenticatorPrivate::None)
return false;
- if (isProxy)
- channels[i].proxyAuthMethod = priv->method;
- else
- channels[i].authMethod = priv->method;
- if (priv->phase == QAuthenticatorPrivate::Done) {
+ if (priv->phase == QAuthenticatorPrivate::Done ||
+ (priv->phase == QAuthenticatorPrivate::Start
+ && (priv->method == QAuthenticatorPrivate::Ntlm
+ || priv->method == QAuthenticatorPrivate::Negotiate))) {
+ if (priv->phase == QAuthenticatorPrivate::Start)
+ priv->phase = QAuthenticatorPrivate::Phase1;
+
pauseConnection();
if (!isProxy) {
if (channels[i].authenticationCredentialsSent) {
@@ -506,8 +467,8 @@ bool QHttpNetworkConnectionPrivate::handleAuthenticateChallenge(QAbstractSocket
channels[i].authenticator = QAuthenticator();
// authentication is cancelled, send the current contents to the user.
- emit channels[i].reply->headerChanged();
- emit channels[i].reply->readyRead();
+ emit reply->headerChanged();
+ emit reply->readyRead();
QNetworkReply::NetworkError errorCode =
isProxy
? QNetworkReply::ProxyAuthenticationRequiredError
@@ -524,31 +485,37 @@ bool QHttpNetworkConnectionPrivate::handleAuthenticateChallenge(QAbstractSocket
return false;
}
-QUrl QHttpNetworkConnectionPrivate::parseRedirectResponse(QAbstractSocket *socket, QHttpNetworkReply *reply)
+// Used by the HTTP1 code-path
+QUrl QHttpNetworkConnectionPrivate::parseRedirectResponse(QAbstractSocket *socket,
+ QHttpNetworkReply *reply)
+{
+ ParseRedirectResult result = parseRedirectResponse(reply);
+ if (result.errorCode != QNetworkReply::NoError) {
+ emitReplyError(socket, reply, result.errorCode);
+ return {};
+ }
+ return std::move(result.redirectUrl);
+}
+
+QHttpNetworkConnectionPrivate::ParseRedirectResult
+QHttpNetworkConnectionPrivate::parseRedirectResponse(QHttpNetworkReply *reply)
{
if (!reply->request().isFollowRedirects())
- return QUrl();
+ return {{}, QNetworkReply::NoError};
QUrl redirectUrl;
- const QList<QPair<QByteArray, QByteArray> > fields = reply->header();
- for (const QNetworkReply::RawHeaderPair &header : fields) {
- if (header.first.compare("location", Qt::CaseInsensitive) == 0) {
- redirectUrl = QUrl::fromEncoded(header.second);
- break;
- }
+ const QHttpHeaders fields = reply->header();
+ if (const auto h = fields.values(QHttpHeaders::WellKnownHeader::Location); !h.empty()) {
+ redirectUrl = QUrl::fromEncoded(h.first());
}
- // If the location url is invalid/empty, we emit ProtocolUnknownError
- if (!redirectUrl.isValid()) {
- emitReplyError(socket, reply, QNetworkReply::ProtocolUnknownError);
- return QUrl();
- }
+ // If the location url is invalid/empty, we return ProtocolUnknownError
+ if (!redirectUrl.isValid())
+ return {{}, QNetworkReply::ProtocolUnknownError};
// Check if we have exceeded max redirects allowed
- if (reply->request().redirectCount() <= 0) {
- emitReplyError(socket, reply, QNetworkReply::TooManyRedirectsError);
- return QUrl();
- }
+ if (reply->request().redirectCount() <= 0)
+ return {{}, QNetworkReply::TooManyRedirectsError};
// Resolve the URL if it's relative
if (redirectUrl.isRelative())
@@ -556,7 +523,7 @@ QUrl QHttpNetworkConnectionPrivate::parseRedirectResponse(QAbstractSocket *socke
// Check redirect url protocol
const QUrl priorUrl(reply->request().url());
- if (redirectUrl.scheme() == QLatin1String("http") || redirectUrl.scheme() == QLatin1String("https")) {
+ if (redirectUrl.scheme() == "http"_L1 || redirectUrl.scheme() == "https"_L1) {
switch (reply->request().redirectPolicy()) {
case QNetworkRequest::NoLessSafeRedirectPolicy:
// Here we could handle https->http redirects as InsecureProtocolError.
@@ -569,8 +536,7 @@ QUrl QHttpNetworkConnectionPrivate::parseRedirectResponse(QAbstractSocket *socke
if (priorUrl.host() != redirectUrl.host()
|| priorUrl.scheme() != redirectUrl.scheme()
|| priorUrl.port() != redirectUrl.port()) {
- emitReplyError(socket, reply, QNetworkReply::InsecureRedirectError);
- return QUrl();
+ return {{}, QNetworkReply::InsecureRedirectError};
}
break;
case QNetworkRequest::UserVerifiedRedirectPolicy:
@@ -579,40 +545,53 @@ QUrl QHttpNetworkConnectionPrivate::parseRedirectResponse(QAbstractSocket *socke
Q_ASSERT(!"Unexpected redirect policy");
}
} else {
- emitReplyError(socket, reply, QNetworkReply::ProtocolUnknownError);
- return QUrl();
+ return {{}, QNetworkReply::ProtocolUnknownError};
}
- return redirectUrl;
+ return {std::move(redirectUrl), QNetworkReply::NoError};
}
-void QHttpNetworkConnectionPrivate::createAuthorization(QAbstractSocket *socket, QHttpNetworkRequest &request)
+void QHttpNetworkConnectionPrivate::createAuthorization(QIODevice *socket, QHttpNetworkRequest &request)
{
Q_ASSERT(socket);
- int i = indexOf(socket);
+ QHttpNetworkConnectionChannel &channel = channels[indexOf(socket)];
+ QAuthenticator *authenticator = &channel.authenticator;
+ QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(*authenticator);
// Send "Authorization" header, but not if it's NTLM and the socket is already authenticated.
- if (channels[i].authMethod != QAuthenticatorPrivate::None) {
- if ((channels[i].authMethod != QAuthenticatorPrivate::Ntlm && request.headerField("Authorization").isEmpty()) || channels[i].lastStatus == 401) {
- QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(channels[i].authenticator);
- if (priv && priv->method != QAuthenticatorPrivate::None) {
- QByteArray response = priv->calculateResponse(request.methodName(), request.uri(false), request.url().host());
- request.setHeaderField("Authorization", response);
- channels[i].authenticationCredentialsSent = true;
- }
+ if (priv && priv->method != QAuthenticatorPrivate::None) {
+ const bool ntlmNego = priv->method == QAuthenticatorPrivate::Ntlm
+ || priv->method == QAuthenticatorPrivate::Negotiate;
+ const bool authNeeded = channel.lastStatus == 401;
+ const bool ntlmNegoOk = ntlmNego && authNeeded
+ && (priv->phase != QAuthenticatorPrivate::Done
+ || !channel.authenticationCredentialsSent);
+ const bool otherOk =
+ !ntlmNego && (authNeeded || request.headerField("Authorization").isEmpty());
+ if (ntlmNegoOk || otherOk) {
+ QByteArray response = priv->calculateResponse(request.methodName(), request.uri(false),
+ request.url().host());
+ request.setHeaderField("Authorization", response);
+ channel.authenticationCredentialsSent = true;
}
}
#if QT_CONFIG(networkproxy)
+ authenticator = &channel.proxyAuthenticator;
+ priv = QAuthenticatorPrivate::getPrivate(*authenticator);
// Send "Proxy-Authorization" header, but not if it's NTLM and the socket is already authenticated.
- if (channels[i].proxyAuthMethod != QAuthenticatorPrivate::None) {
- if (!(channels[i].proxyAuthMethod == QAuthenticatorPrivate::Ntlm && channels[i].lastStatus != 407)) {
- QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(channels[i].proxyAuthenticator);
- if (priv && priv->method != QAuthenticatorPrivate::None) {
- QByteArray response = priv->calculateResponse(request.methodName(), request.uri(false), networkProxy.hostName());
- request.setHeaderField("Proxy-Authorization", response);
- channels[i].proxyCredentialsSent = true;
- }
+ if (priv && priv->method != QAuthenticatorPrivate::None) {
+ const bool ntlmNego = priv->method == QAuthenticatorPrivate::Ntlm
+ || priv->method == QAuthenticatorPrivate::Negotiate;
+ const bool proxyAuthNeeded = channel.lastStatus == 407;
+ const bool ntlmNegoOk = ntlmNego && proxyAuthNeeded
+ && (priv->phase != QAuthenticatorPrivate::Done || !channel.proxyCredentialsSent);
+ const bool otherOk = !ntlmNego;
+ if (ntlmNegoOk || otherOk) {
+ QByteArray response = priv->calculateResponse(request.methodName(), request.uri(false),
+ networkProxy.hostName());
+ request.setHeaderField("Proxy-Authorization", response);
+ channel.proxyCredentialsSent = true;
}
}
#endif // QT_CONFIG(networkproxy)
@@ -707,7 +686,7 @@ void QHttpNetworkConnectionPrivate::requeueRequest(const HttpMessagePair &pair)
QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection);
}
-bool QHttpNetworkConnectionPrivate::dequeueRequest(QAbstractSocket *socket)
+bool QHttpNetworkConnectionPrivate::dequeueRequest(QIODevice *socket)
{
int i = 0;
if (socket)
@@ -751,6 +730,15 @@ QHttpNetworkRequest QHttpNetworkConnectionPrivate::predictNextRequest() const
return QHttpNetworkRequest();
}
+QHttpNetworkReply* QHttpNetworkConnectionPrivate::predictNextRequestsReply() const
+{
+ if (!highPriorityQueue.isEmpty())
+ return highPriorityQueue.last().second;
+ if (!lowPriorityQueue.isEmpty())
+ return lowPriorityQueue.last().second;
+ return nullptr;
+}
+
// this is called from _q_startNextRequest and when a request has been sent down a socket from the channel
void QHttpNetworkConnectionPrivate::fillPipeline(QAbstractSocket *socket)
{
@@ -764,7 +752,7 @@ void QHttpNetworkConnectionPrivate::fillPipeline(QAbstractSocket *socket)
if (channels[i].reply == nullptr)
return;
- if (! (defaultPipelineLength - channels[i].alreadyPipelinedRequests.length() >= defaultRePipelineLength)) {
+ if (! (defaultPipelineLength - channels[i].alreadyPipelinedRequests.size() >= defaultRePipelineLength)) {
return;
}
@@ -805,28 +793,28 @@ void QHttpNetworkConnectionPrivate::fillPipeline(QAbstractSocket *socket)
int lengthBefore;
while (!highPriorityQueue.isEmpty()) {
- lengthBefore = channels[i].alreadyPipelinedRequests.length();
+ lengthBefore = channels[i].alreadyPipelinedRequests.size();
fillPipeline(highPriorityQueue, channels[i]);
- if (channels[i].alreadyPipelinedRequests.length() >= defaultPipelineLength) {
+ if (channels[i].alreadyPipelinedRequests.size() >= defaultPipelineLength) {
channels[i].pipelineFlush();
return;
}
- if (lengthBefore == channels[i].alreadyPipelinedRequests.length())
+ if (lengthBefore == channels[i].alreadyPipelinedRequests.size())
break; // did not process anything, now do the low prio queue
}
while (!lowPriorityQueue.isEmpty()) {
- lengthBefore = channels[i].alreadyPipelinedRequests.length();
+ lengthBefore = channels[i].alreadyPipelinedRequests.size();
fillPipeline(lowPriorityQueue, channels[i]);
- if (channels[i].alreadyPipelinedRequests.length() >= defaultPipelineLength) {
+ if (channels[i].alreadyPipelinedRequests.size() >= defaultPipelineLength) {
channels[i].pipelineFlush();
return;
}
- if (lengthBefore == channels[i].alreadyPipelinedRequests.length())
+ if (lengthBefore == channels[i].alreadyPipelinedRequests.size())
break; // did not process anything
}
@@ -840,7 +828,7 @@ bool QHttpNetworkConnectionPrivate::fillPipeline(QList<HttpMessagePair> &queue,
if (queue.isEmpty())
return true;
- for (int i = queue.count() - 1; i >= 0; --i) {
+ for (int i = queue.size() - 1; i >= 0; --i) {
HttpMessagePair messagePair = queue.at(i);
const QHttpNetworkRequest &request = messagePair.first;
@@ -907,6 +895,8 @@ QString QHttpNetworkConnectionPrivate::errorDetail(QNetworkReply::NetworkError e
break;
case QNetworkReply::SslHandshakeFailedError:
errorString = QCoreApplication::translate("QHttp", "SSL handshake failed");
+ if (socket)
+ errorString += ": "_L1 + socket->errorString();
break;
case QNetworkReply::TooManyRedirectsError:
errorString = QCoreApplication::translate("QHttp", "Too many redirects");
@@ -960,7 +950,7 @@ void QHttpNetworkConnectionPrivate::removeReply(QHttpNetworkReply *reply)
}
// is the reply inside the pipeline of this channel already?
- for (int j = 0; j < channels[i].alreadyPipelinedRequests.length(); j++) {
+ for (int j = 0; j < channels[i].alreadyPipelinedRequests.size(); j++) {
if (channels[i].alreadyPipelinedRequests.at(j).second == reply) {
// Remove that HttpMessagePair
channels[i].alreadyPipelinedRequests.removeAt(j);
@@ -978,23 +968,22 @@ void QHttpNetworkConnectionPrivate::removeReply(QHttpNetworkReply *reply)
return;
}
}
-#ifndef QT_NO_SSL
// is the reply inside the H2 pipeline of this channel already?
- QMultiMap<int, HttpMessagePair>::iterator it = channels[i].h2RequestsToSend.begin();
- QMultiMap<int, HttpMessagePair>::iterator end = channels[i].h2RequestsToSend.end();
- for (; it != end; ++it) {
- if (it.value().second == reply) {
- channels[i].h2RequestsToSend.remove(it.key());
-
- QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection);
- return;
- }
+ const auto foundReply = [reply](const HttpMessagePair &pair) {
+ return pair.second == reply;
+ };
+ auto &seq = channels[i].h2RequestsToSend;
+ const auto end = seq.cend();
+ auto it = std::find_if(seq.cbegin(), end, foundReply);
+ if (it != end) {
+ seq.erase(it);
+ QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection);
+ return;
}
-#endif
}
// remove from the high priority queue
if (!highPriorityQueue.isEmpty()) {
- for (int j = highPriorityQueue.count() - 1; j >= 0; --j) {
+ for (int j = highPriorityQueue.size() - 1; j >= 0; --j) {
HttpMessagePair messagePair = highPriorityQueue.at(j);
if (messagePair.second == reply) {
highPriorityQueue.removeAt(j);
@@ -1005,7 +994,7 @@ void QHttpNetworkConnectionPrivate::removeReply(QHttpNetworkReply *reply)
}
// remove from the low priority queue
if (!lowPriorityQueue.isEmpty()) {
- for (int j = lowPriorityQueue.count() - 1; j >= 0; --j) {
+ for (int j = lowPriorityQueue.size() - 1; j >= 0; --j) {
HttpMessagePair messagePair = lowPriorityQueue.at(j);
if (messagePair.second == reply) {
lowPriorityQueue.removeAt(j);
@@ -1034,6 +1023,11 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
//resend the necessary ones.
for (int i = 0; i < activeChannelCount; ++i) {
if (channels[i].resendCurrent && (channels[i].state != QHttpNetworkConnectionChannel::ClosingState)) {
+ if (!channels[i].socket
+ || channels[i].socket->state() == QAbstractSocket::UnconnectedState) {
+ if (!channels[i].ensureConnection())
+ continue;
+ }
channels[i].resendCurrent = false;
// if this is not possible, error will be emitted and connection terminated
@@ -1064,8 +1058,10 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
}
case QHttpNetworkConnection::ConnectionTypeHTTP2Direct:
case QHttpNetworkConnection::ConnectionTypeHTTP2: {
- if (channels[0].h2RequestsToSend.isEmpty() && channels[0].switchedToHttp2)
+ if (channels[0].h2RequestsToSend.isEmpty() && !channels[0].reply
+ && highPriorityQueue.isEmpty() && lowPriorityQueue.isEmpty()) {
return;
+ }
if (networkLayerState == IPv4)
channels[0].networkLayerPreference = QAbstractSocket::IPv4Protocol;
@@ -1106,7 +1102,7 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
// If there is not already any connected channels we need to connect a new one.
// We do not pair the channel with the request until we know if it is
// connected or not. This is to reuse connected channels before we connect new once.
- int queuedRequests = highPriorityQueue.count() + lowPriorityQueue.count();
+ int queuedRequests = highPriorityQueue.size() + lowPriorityQueue.size();
// in case we have in-flight preconnect requests and normal requests,
// we only need one socket for each (preconnect, normal request) pair
@@ -1115,31 +1111,52 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
int normalRequests = queuedRequests - preConnectRequests;
neededOpenChannels = qMax(normalRequests, preConnectRequests);
}
+
+ if (neededOpenChannels <= 0)
+ return;
+
+ QVarLengthArray<int> channelsToConnect;
+
+ // use previously used channels first
for (int i = 0; i < activeChannelCount && neededOpenChannels > 0; ++i) {
- bool connectChannel = false;
- if (channels[i].socket) {
- if ((channels[i].socket->state() == QAbstractSocket::ConnectingState)
- || (channels[i].socket->state() == QAbstractSocket::HostLookupState)
- || channels[i].pendingEncrypt) // pendingEncrypt == "EncryptingState"
- neededOpenChannels--;
-
- if (neededOpenChannels <= 0)
- break;
- if (!channels[i].reply && !channels[i].isSocketBusy() && (channels[i].socket->state() == QAbstractSocket::UnconnectedState))
- connectChannel = true;
- } else { // not previously used channel
- connectChannel = true;
+ if (!channels[i].socket)
+ continue;
+
+ if ((channels[i].socket->state() == QAbstractSocket::ConnectingState)
+ || (channels[i].socket->state() == QAbstractSocket::HostLookupState)
+ || channels[i].pendingEncrypt) { // pendingEncrypt == "EncryptingState"
+ neededOpenChannels--;
+ continue;
}
- if (connectChannel) {
- if (networkLayerState == IPv4)
- channels[i].networkLayerPreference = QAbstractSocket::IPv4Protocol;
- else if (networkLayerState == IPv6)
- channels[i].networkLayerPreference = QAbstractSocket::IPv6Protocol;
- channels[i].ensureConnection();
+ if (!channels[i].reply && !channels[i].isSocketBusy()
+ && (channels[i].socket->state() == QAbstractSocket::UnconnectedState)) {
+ channelsToConnect.push_back(i);
neededOpenChannels--;
}
}
+
+ // use other channels
+ for (int i = 0; i < activeChannelCount && neededOpenChannels > 0; ++i) {
+ if (channels[i].socket)
+ continue;
+
+ channelsToConnect.push_back(i);
+ neededOpenChannels--;
+ }
+
+ auto channelToConnectSpan = QSpan{channelsToConnect};
+ while (!channelToConnectSpan.isEmpty()) {
+ const int channel = channelToConnectSpan.front();
+ channelToConnectSpan = channelToConnectSpan.sliced(1);
+
+ if (networkLayerState == IPv4)
+ channels[channel].networkLayerPreference = QAbstractSocket::IPv4Protocol;
+ else if (networkLayerState == IPv6)
+ channels[channel].networkLayerPreference = QAbstractSocket::IPv6Protocol;
+
+ channels[channel].ensureConnection();
+ }
}
@@ -1235,23 +1252,30 @@ void QHttpNetworkConnectionPrivate::_q_hostLookupFinished(const QHostInfo &info)
networkLayerState = QHttpNetworkConnectionPrivate::IPv6;
QMetaObject::invokeMethod(this->q_func(), "_q_startNextRequest", Qt::QueuedConnection);
} else {
+ auto lookupError = QNetworkReply::HostNotFoundError;
+#ifndef QT_NO_NETWORKPROXY
+ // if the proxy can lookup hostnames, all hostname lookups except for the lookup of the
+ // proxy hostname are delegated to the proxy.
+ auto proxyCapabilities = networkProxy.capabilities() | channels[0].proxy.capabilities();
+ if (proxyCapabilities & QNetworkProxy::HostNameLookupCapability)
+ lookupError = QNetworkReply::ProxyNotFoundError;
+#endif
if (dequeueRequest(channels[0].socket)) {
- emitReplyError(channels[0].socket, channels[0].reply, QNetworkReply::HostNotFoundError);
+ emitReplyError(channels[0].socket, channels[0].reply, lookupError);
networkLayerState = QHttpNetworkConnectionPrivate::Unknown;
} else if (connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2
|| connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) {
- for (const HttpMessagePair &h2Pair : qAsConst(channels[0].h2RequestsToSend)) {
+ for (const HttpMessagePair &h2Pair : std::as_const(channels[0].h2RequestsToSend)) {
// emit error for all replies
QHttpNetworkReply *currentReply = h2Pair.second;
Q_ASSERT(currentReply);
- emitReplyError(channels[0].socket, currentReply, QNetworkReply::HostNotFoundError);
+ emitReplyError(channels[0].socket, currentReply, lookupError);
}
} else {
- // Should not happen: we start a host lookup before sending a request,
- // so it's natural to have requests either in HTTP/2 queue, or in low/high
- // priority queues.
- qWarning("QHttpNetworkConnectionPrivate::_q_hostLookupFinished"
- " could not de-queue request, failed to report HostNotFoundError");
+ // We can end up here if a request has been aborted or otherwise failed (e.g. timeout)
+ // before the host lookup was finished.
+ qDebug("QHttpNetworkConnectionPrivate::_q_hostLookupFinished"
+ " could not de-queue request, failed to report HostNotFoundError");
networkLayerState = QHttpNetworkConnectionPrivate::Unknown;
}
}
@@ -1304,18 +1328,6 @@ void QHttpNetworkConnectionPrivate::_q_connectDelayedChannel()
channels[1].ensureConnection();
}
-QHttpNetworkConnection::QHttpNetworkConnection(const QString &hostName, quint16 port, bool encrypt,
- QHttpNetworkConnection::ConnectionType connectionType, QObject *parent)
- : QObject(*(new QHttpNetworkConnectionPrivate(hostName, port, encrypt , connectionType)), parent)
-{
- Q_D(QHttpNetworkConnection);
- d->init();
- if (QNetworkStatusMonitor::isEnabled()) {
- connect(&d->connectionMonitor, &QNetworkConnectionMonitor::reachabilityChanged,
- this, &QHttpNetworkConnection::onlineStateChanged, Qt::QueuedConnection);
- }
-}
-
QHttpNetworkConnection::QHttpNetworkConnection(quint16 connectionCount, const QString &hostName,
quint16 port, bool encrypt, QObject *parent,
QHttpNetworkConnection::ConnectionType connectionType)
@@ -1324,7 +1336,7 @@ QHttpNetworkConnection::QHttpNetworkConnection(quint16 connectionCount, const QS
{
Q_D(QHttpNetworkConnection);
d->init();
- if (QNetworkStatusMonitor::isEnabled()) {
+ if (QNetworkConnectionMonitor::isEnabled()) {
connect(&d->connectionMonitor, &QNetworkConnectionMonitor::reachabilityChanged,
this, &QHttpNetworkConnection::onlineStateChanged, Qt::QueuedConnection);
}
@@ -1376,7 +1388,7 @@ void QHttpNetworkConnection::setCacheProxy(const QNetworkProxy &networkProxy)
d->networkProxy = networkProxy;
// update the authenticator
if (!d->networkProxy.user().isEmpty()) {
- for (int i = 0; i < d->activeChannelCount; ++i) {
+ for (int i = 0; i < d->channelCount; ++i) {
d->channels[i].proxyAuthenticator.setUser(d->networkProxy.user());
d->channels[i].proxyAuthenticator.setPassword(d->networkProxy.password());
}
@@ -1392,7 +1404,7 @@ QNetworkProxy QHttpNetworkConnection::cacheProxy() const
void QHttpNetworkConnection::setTransparentProxy(const QNetworkProxy &networkProxy)
{
Q_D(QHttpNetworkConnection);
- for (int i = 0; i < d->activeChannelCount; ++i)
+ for (int i = 0; i < d->channelCount; ++i)
d->channels[i].setProxy(networkProxy);
}
@@ -1403,9 +1415,9 @@ QNetworkProxy QHttpNetworkConnection::transparentProxy() const
}
#endif
-QHttpNetworkConnection::ConnectionType QHttpNetworkConnection::connectionType()
+QHttpNetworkConnection::ConnectionType QHttpNetworkConnection::connectionType() const
{
- Q_D(QHttpNetworkConnection);
+ Q_D(const QHttpNetworkConnection);
return d->connectionType;
}
@@ -1440,13 +1452,13 @@ void QHttpNetworkConnection::setSslConfiguration(const QSslConfiguration &config
d->channels[i].setSslConfiguration(config);
}
-QSharedPointer<QSslContext> QHttpNetworkConnection::sslContext()
+std::shared_ptr<QSslContext> QHttpNetworkConnection::sslContext() const
{
- Q_D(QHttpNetworkConnection);
+ Q_D(const QHttpNetworkConnection);
return d->sslContext;
}
-void QHttpNetworkConnection::setSslContext(QSharedPointer<QSslContext> context)
+void QHttpNetworkConnection::setSslContext(std::shared_ptr<QSslContext> context)
{
Q_D(QHttpNetworkConnection);
d->sslContext = std::move(context);
@@ -1538,12 +1550,12 @@ void QHttpNetworkConnectionPrivate::emitProxyAuthenticationRequired(const QHttpN
pauseConnection();
QHttpNetworkReply *reply;
if ((connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2
- && (chan->switchedToHttp2 || chan->h2RequestsToSend.count() > 0))
+ && (chan->switchedToHttp2 || chan->h2RequestsToSend.size() > 0))
|| connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) {
// we choose the reply to emit the proxyAuth signal from somewhat arbitrarily,
// but that does not matter because the signal will ultimately be emitted
// by the QNetworkAccessManager.
- Q_ASSERT(chan->h2RequestsToSend.count() > 0);
+ Q_ASSERT(chan->h2RequestsToSend.size() > 0);
reply = chan->h2RequestsToSend.cbegin().value().second;
} else { // HTTP
reply = chan->reply;
diff --git a/src/network/access/qhttpnetworkconnection_p.h b/src/network/access/qhttpnetworkconnection_p.h
index 5bda507920..9cd4d75bbc 100644
--- a/src/network/access/qhttpnetworkconnection_p.h
+++ b/src/network/access/qhttpnetworkconnection_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QHTTPNETWORKCONNECTION_H
#define QHTTPNETWORKCONNECTION_H
@@ -88,7 +52,7 @@ class QSslContext;
#endif // !QT_NO_SSL
class QHttpNetworkConnectionPrivate;
-class Q_AUTOTEST_EXPORT QHttpNetworkConnection : public QObject
+class Q_NETWORK_EXPORT QHttpNetworkConnection : public QObject
{
Q_OBJECT
public:
@@ -99,9 +63,6 @@ public:
ConnectionTypeHTTP2Direct
};
- explicit QHttpNetworkConnection(const QString &hostName, quint16 port = 80, bool encrypt = false,
- ConnectionType connectionType = ConnectionTypeHTTP,
- QObject *parent = nullptr);
QHttpNetworkConnection(quint16 channelCount, const QString &hostName, quint16 port = 80,
bool encrypt = false, QObject *parent = nullptr,
ConnectionType connectionType = ConnectionTypeHTTP);
@@ -128,7 +89,7 @@ public:
QHttpNetworkConnectionChannel *channels() const;
- ConnectionType connectionType();
+ ConnectionType connectionType() const;
void setConnectionType(ConnectionType type);
QHttp2Configuration http2Parameters() const;
@@ -138,8 +99,8 @@ public:
void setSslConfiguration(const QSslConfiguration &config);
void ignoreSslErrors(int channel = -1);
void ignoreSslErrors(const QList<QSslError> &errors, int channel = -1);
- QSharedPointer<QSslContext> sslContext();
- void setSslContext(QSharedPointer<QSslContext> context);
+ std::shared_ptr<QSslContext> sslContext() const;
+ void setSslContext(std::shared_ptr<QSslContext> context);
#endif
void preConnectFinished();
@@ -173,8 +134,10 @@ typedef QPair<QHttpNetworkRequest, QHttpNetworkReply*> HttpMessagePair;
class QHttpNetworkConnectionPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QHttpNetworkConnection)
+ Q_DISABLE_COPY_MOVE(QHttpNetworkConnectionPrivate)
public:
- static const int defaultHttpChannelCount;
+ // Note: Only used from auto tests, normal usage is via QHttp1Configuration
+ static constexpr int defaultHttpChannelCount = 6;
static const int defaultPipelineLength;
static const int defaultRePipelineLength;
@@ -191,29 +154,28 @@ public:
IPv4or6
};
- QHttpNetworkConnectionPrivate(const QString &hostName, quint16 port, bool encrypt,
- QHttpNetworkConnection::ConnectionType type);
- QHttpNetworkConnectionPrivate(quint16 channelCount, const QString &hostName, quint16 port, bool encrypt,
- QHttpNetworkConnection::ConnectionType type);
+ QHttpNetworkConnectionPrivate(quint16 connectionCount, const QString &hostName, quint16 port,
+ bool encrypt, QHttpNetworkConnection::ConnectionType type);
~QHttpNetworkConnectionPrivate();
void init();
void pauseConnection();
void resumeConnection();
- ConnectionState state;
- NetworkLayerPreferenceState networkLayerState;
+ ConnectionState state = RunningState;
+ NetworkLayerPreferenceState networkLayerState = Unknown;
enum { ChunkSize = 4096 };
- int indexOf(QAbstractSocket *socket) const;
+ int indexOf(QIODevice *socket) const;
QHttpNetworkReply *queueRequest(const QHttpNetworkRequest &request);
void requeueRequest(const HttpMessagePair &pair); // e.g. after pipeline broke
void fillHttp2Queue();
- bool dequeueRequest(QAbstractSocket *socket);
+ bool dequeueRequest(QIODevice *socket);
void prepareRequest(HttpMessagePair &request);
void updateChannel(int i, const HttpMessagePair &messagePair);
QHttpNetworkRequest predictNextRequest() const;
+ QHttpNetworkReply* predictNextRequestsReply() const;
void fillPipeline(QAbstractSocket *socket);
bool fillPipeline(QList<HttpMessagePair> &queue, QHttpNetworkConnectionChannel &channel);
@@ -233,7 +195,7 @@ public:
void _q_hostLookupFinished(const QHostInfo &info);
void _q_connectDelayedChannel();
- void createAuthorization(QAbstractSocket *socket, QHttpNetworkRequest &request);
+ void createAuthorization(QIODevice *socket, QHttpNetworkRequest &request);
QString errorDetail(QNetworkReply::NetworkError errorCode, QAbstractSocket *socket,
const QString &extraDetail = QString());
@@ -243,7 +205,7 @@ public:
QString hostName;
quint16 port;
bool encrypt;
- bool delayIpv4;
+ bool delayIpv4 = true;
// Number of channels we are trying to use at the moment:
int activeChannelCount;
@@ -251,7 +213,7 @@ public:
const int channelCount;
QTimer delayedConnectionTimer;
QHttpNetworkConnectionChannel *channels; // parallel connections to the server
- bool shouldEmitChannelError(QAbstractSocket *socket);
+ bool shouldEmitChannelError(QIODevice *socket);
qint64 uncompressedBytesAvailable(const QHttpNetworkReply &reply) const;
qint64 uncompressedBytesAvailableNextBlock(const QHttpNetworkReply &reply) const;
@@ -259,6 +221,12 @@ public:
void emitReplyError(QAbstractSocket *socket, QHttpNetworkReply *reply, QNetworkReply::NetworkError errorCode);
bool handleAuthenticateChallenge(QAbstractSocket *socket, QHttpNetworkReply *reply, bool isProxy, bool &resend);
+ struct ParseRedirectResult {
+ QUrl redirectUrl;
+ QNetworkReply::NetworkError errorCode;
+ };
+ static ParseRedirectResult parseRedirectResponse(QHttpNetworkReply *reply);
+ // Used by the HTTP1 code-path
QUrl parseRedirectResponse(QAbstractSocket *socket, QHttpNetworkReply *reply);
#ifndef QT_NO_NETWORKPROXY
@@ -270,12 +238,12 @@ public:
QList<HttpMessagePair> highPriorityQueue;
QList<HttpMessagePair> lowPriorityQueue;
- int preConnectRequests;
+ int preConnectRequests = 0;
QHttpNetworkConnection::ConnectionType connectionType;
#ifndef QT_NO_SSL
- QSharedPointer<QSslContext> sslContext;
+ std::shared_ptr<QSslContext> sslContext;
#endif
QHttp2Configuration http2Parameters;
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
index edbaa7efce..6766989690 100644
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
@@ -1,49 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2014 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qhttpnetworkconnectionchannel_p.h"
#include "qhttpnetworkconnection_p.h"
#include "qhttp2configuration.h"
#include "private/qnoncontiguousbytedevice_p.h"
-#include <qpair.h>
#include <qdebug.h>
#include <private/qhttp2protocolhandler_p.h>
@@ -58,6 +21,9 @@
#include "private/qnetconmonitor_p.h"
+#include <memory>
+#include <utility>
+
QT_BEGIN_NAMESPACE
namespace
@@ -74,7 +40,7 @@ private:
}
-// TODO: Put channel specific stuff here so it does not polute qhttpnetworkconnection.cpp
+// TODO: Put channel specific stuff here so it does not pollute qhttpnetworkconnection.cpp
// Because in-flight when sending a request, the server might close our connection (because the persistent HTTP
// connection times out)
@@ -93,8 +59,6 @@ QHttpNetworkConnectionChannel::QHttpNetworkConnectionChannel()
, lastStatus(0)
, pendingEncrypt(false)
, reconnectAttempts(reconnectAttemptsDefault)
- , authMethod(QAuthenticatorPrivate::None)
- , proxyAuthMethod(QAuthenticatorPrivate::None)
, authenticationCredentialsSent(false)
, proxyCredentialsSent(false)
, protocolHandler(nullptr)
@@ -244,7 +208,7 @@ void QHttpNetworkConnectionChannel::abort()
bool QHttpNetworkConnectionChannel::sendRequest()
{
- Q_ASSERT(!protocolHandler.isNull());
+ Q_ASSERT(protocolHandler);
return protocolHandler->sendRequest();
}
@@ -257,7 +221,7 @@ bool QHttpNetworkConnectionChannel::sendRequest()
void QHttpNetworkConnectionChannel::sendRequestDelayed()
{
QMetaObject::invokeMethod(this, [this] {
- Q_ASSERT(!protocolHandler.isNull());
+ Q_ASSERT(protocolHandler);
if (reply)
protocolHandler->sendRequest();
}, Qt::ConnectionType::QueuedConnection);
@@ -265,13 +229,13 @@ void QHttpNetworkConnectionChannel::sendRequestDelayed()
void QHttpNetworkConnectionChannel::_q_receiveReply()
{
- Q_ASSERT(!protocolHandler.isNull());
+ Q_ASSERT(protocolHandler);
protocolHandler->_q_receiveReply();
}
void QHttpNetworkConnectionChannel::_q_readyRead()
{
- Q_ASSERT(!protocolHandler.isNull());
+ Q_ASSERT(protocolHandler);
protocolHandler->_q_readyRead();
}
@@ -358,6 +322,13 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
QString connectHost = connection->d_func()->hostName;
quint16 connectPort = connection->d_func()->port;
+ QHttpNetworkReply *potentialReply = connection->d_func()->predictNextRequestsReply();
+ if (potentialReply) {
+ QMetaObject::invokeMethod(potentialReply, "socketStartedConnecting", Qt::QueuedConnection);
+ } else if (!h2RequestsToSend.isEmpty()) {
+ QMetaObject::invokeMethod(std::as_const(h2RequestsToSend).first().second, "socketStartedConnecting", Qt::QueuedConnection);
+ }
+
#ifndef QT_NO_NETWORKPROXY
// HTTPS always use transparent proxy.
if (connection->d_func()->networkProxy.type() != QNetworkProxy::NoProxy && !ssl) {
@@ -373,8 +344,8 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
if (connection->connectionType()
== QHttpNetworkConnection::ConnectionTypeHTTP2Direct
|| (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2
- && h2RequestsToSend.count() > 0)) {
- value = h2RequestsToSend.first().first.headerField("user-agent");
+ && !h2RequestsToSend.isEmpty())) {
+ value = std::as_const(h2RequestsToSend).first().first.headerField("user-agent");
} else {
value = connection->d_func()->predictNextRequest().headerField("user-agent");
}
@@ -395,8 +366,8 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
// check whether we can re-use an existing SSL session
// (meaning another socket in this connection has already
// performed a full handshake)
- if (!connection->sslContext().isNull())
- QSslSocketPrivate::checkSettingSslContext(sslSocket, connection->sslContext());
+ if (auto ctx = connection->sslContext())
+ QSslSocketPrivate::checkSettingSslContext(sslSocket, std::move(ctx));
sslSocket->setPeerVerifyName(connection->d_func()->peerVerifyName);
sslSocket->connectToHostEncrypted(connectHost, connectPort, QIODevice::ReadWrite, networkLayerPreference);
@@ -473,18 +444,18 @@ void QHttpNetworkConnectionChannel::allDone()
// trick with ProtocolHandlerDeleter, a QObject-derived class.
// These dances below just make it somewhat exception-safe.
// 1. Create a new owner:
- QAbstractProtocolHandler *oldHandler = protocolHandler.data();
- QScopedPointer<ProtocolHandlerDeleter> deleter(new ProtocolHandlerDeleter(oldHandler));
+ QAbstractProtocolHandler *oldHandler = protocolHandler.get();
+ auto deleter = std::make_unique<ProtocolHandlerDeleter>(oldHandler);
// 2. Retire the old one:
- protocolHandler.take();
+ Q_UNUSED(protocolHandler.release());
// 3. Call 'deleteLater':
deleter->deleteLater();
// 3. Give up the ownerthip:
- deleter.take();
+ Q_UNUSED(deleter.release());
connection->fillHttp2Queue();
protocolHandler.reset(new QHttp2ProtocolHandler(this));
- QHttp2ProtocolHandler *h2c = static_cast<QHttp2ProtocolHandler *>(protocolHandler.data());
+ QHttp2ProtocolHandler *h2c = static_cast<QHttp2ProtocolHandler *>(protocolHandler.get());
QMetaObject::invokeMethod(h2c, "_q_receiveReply", Qt::QueuedConnection);
QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
// If we only had one request sent with H2 allowed, we may fail to send
@@ -579,7 +550,7 @@ void QHttpNetworkConnectionChannel::detectPipeliningSupport()
QByteArray serverHeaderField;
if (
// check for HTTP/1.1
- (reply->d_func()->majorVersion == 1 && reply->d_func()->minorVersion == 1)
+ (reply->majorVersion() == 1 && reply->minorVersion() == 1)
// check for not having connection close
&& (!reply->d_func()->isConnectionCloseEnabled())
// check if it is still connected
@@ -602,7 +573,7 @@ void QHttpNetworkConnectionChannel::detectPipeliningSupport()
// called when the connection broke and we need to queue some pipelined requests again
void QHttpNetworkConnectionChannel::requeueCurrentlyPipelinedRequests()
{
- for (int i = 0; i < alreadyPipelinedRequests.length(); i++)
+ for (int i = 0; i < alreadyPipelinedRequests.size(); i++)
connection->d_func()->requeueRequest(alreadyPipelinedRequests.at(i));
alreadyPipelinedRequests.clear();
@@ -687,17 +658,19 @@ bool QHttpNetworkConnectionChannel::resetUploadData()
//this happens if server closes connection while QHttpNetworkConnectionPrivate::_q_startNextRequest is pending
return false;
}
- QNonContiguousByteDevice* uploadByteDevice = request.uploadByteDevice();
- if (!uploadByteDevice)
- return true;
-
- if (uploadByteDevice->reset()) {
+ if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct
+ || switchedToHttp2) {
+ // The else branch doesn't make any sense for HTTP/2, since 1 channel is multiplexed into
+ // many streams. And having one stream fail to reset upload data should not completely close
+ // the channel. Handled in the http2 protocol handler.
+ } else if (QNonContiguousByteDevice *uploadByteDevice = request.uploadByteDevice()) {
+ if (!uploadByteDevice->reset()) {
+ connection->d_func()->emitReplyError(socket, reply, QNetworkReply::ContentReSendError);
+ return false;
+ }
written = 0;
- return true;
- } else {
- connection->d_func()->emitReplyError(socket, reply, QNetworkReply::ContentReSendError);
- return false;
}
+ return true;
}
#ifndef QT_NO_NETWORKPROXY
@@ -856,7 +829,7 @@ void QHttpNetworkConnectionChannel::_q_disconnected()
QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
}
state = QHttpNetworkConnectionChannel::IdleState;
- if (alreadyPipelinedRequests.length()) {
+ if (alreadyPipelinedRequests.size()) {
// If nothing was in a pipeline, no need in calling
// _q_startNextRequest (which it does):
requeueCurrentlyPipelinedRequests();
@@ -883,6 +856,8 @@ void QHttpNetworkConnectionChannel::_q_connected()
connection->d_func()->networkLayerState = QHttpNetworkConnectionPrivate::IPv6;
}
connection->d_func()->networkLayerDetected(networkLayerPreference);
+ if (connection->d_func()->activeChannelCount > 1 && !connection->d_func()->encrypt)
+ QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
} else {
bool anyProtocol = networkLayerPreference == QAbstractSocket::AnyIPProtocol;
if (((connection->d_func()->networkLayerState == QHttpNetworkConnectionPrivate::IPv4)
@@ -911,7 +886,7 @@ void QHttpNetworkConnectionChannel::_q_connected()
pipeliningSupported = QHttpNetworkConnectionChannel::PipeliningSupportUnknown;
- if (QNetworkStatusMonitor::isEnabled()) {
+ if (QNetworkConnectionMonitor::isEnabled()) {
auto connectionPrivate = connection->d_func();
if (!connectionPrivate->connectionMonitor.isMonitoring()) {
// Now that we have a pair of addresses, we can start monitoring the
@@ -925,18 +900,17 @@ void QHttpNetworkConnectionChannel::_q_connected()
//channels[i].reconnectAttempts = 2;
if (ssl || pendingEncrypt) { // FIXME: Didn't work properly with pendingEncrypt only, we should refactor this into an EncrypingState
#ifndef QT_NO_SSL
- if (connection->sslContext().isNull()) {
+ if (!connection->sslContext()) {
// this socket is making the 1st handshake for this connection,
// we need to set the SSL context so new sockets can reuse it
- QSharedPointer<QSslContext> socketSslContext = QSslSocketPrivate::sslContext(static_cast<QSslSocket*>(socket));
- if (!socketSslContext.isNull())
- connection->setSslContext(socketSslContext);
+ if (auto socketSslContext = QSslSocketPrivate::sslContext(static_cast<QSslSocket*>(socket)))
+ connection->setSslContext(std::move(socketSslContext));
}
#endif
} else if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) {
state = QHttpNetworkConnectionChannel::IdleState;
protocolHandler.reset(new QHttp2ProtocolHandler(this));
- if (h2RequestsToSend.count() > 0) {
+ if (h2RequestsToSend.size() > 0) {
// In case our peer has sent us its settings (window size, max concurrent streams etc.)
// let's give _q_receiveReply a chance to read them first ('invokeMethod', QueuedConnection).
QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
@@ -977,6 +951,10 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
break;
case QAbstractSocket::ConnectionRefusedError:
errorCode = QNetworkReply::ConnectionRefusedError;
+#ifndef QT_NO_NETWORKPROXY
+ if (connection->d_func()->networkProxy.type() != QNetworkProxy::NoProxy && !ssl)
+ errorCode = QNetworkReply::ProxyConnectionRefusedError;
+#endif
break;
case QAbstractSocket::RemoteHostClosedError:
// This error for SSL comes twice in a row, first from SSL layer ("The TLS/SSL connection has been closed") then from TCP layer.
@@ -989,13 +967,12 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
// we do not resend, but must report errors if any request is in progress (note, while
// not in its sendRequest(), protocol handler switches the channel to IdleState, thus
// this check is under this condition in 'if'):
- if (protocolHandler.data()) {
+ if (protocolHandler) {
if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct
|| (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2
&& switchedToHttp2)) {
- auto h2Handler = static_cast<QHttp2ProtocolHandler *>(protocolHandler.data());
+ auto h2Handler = static_cast<QHttp2ProtocolHandler *>(protocolHandler.get());
h2Handler->handleConnectionClosure();
- protocolHandler.reset();
}
}
return;
@@ -1059,6 +1036,9 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
}
errorCode = QNetworkReply::TimeoutError;
break;
+ case QAbstractSocket::ProxyConnectionRefusedError:
+ errorCode = QNetworkReply::ProxyConnectionRefusedError;
+ break;
case QAbstractSocket::ProxyAuthenticationRequiredError:
errorCode = QNetworkReply::ProxyAuthenticationRequiredError;
break;
@@ -1116,10 +1096,12 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2
|| connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) {
- QList<HttpMessagePair> h2Pairs = h2RequestsToSend.values();
- for (int a = 0; a < h2Pairs.count(); ++a) {
+ const auto h2RequestsToSendCopy = std::exchange(h2RequestsToSend, {});
+ for (const auto &httpMessagePair : h2RequestsToSendCopy) {
// emit error for all replies
- QHttpNetworkReply *currentReply = h2Pairs.at(a).second;
+ QHttpNetworkReply *currentReply = httpMessagePair.second;
+ currentReply->d_func()->errorString = errorString;
+ currentReply->d_func()->httpErrorCode = errorCode;
Q_ASSERT(currentReply);
emit currentReply->finishedWithError(errorCode, errorString);
}
@@ -1146,9 +1128,9 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
void QHttpNetworkConnectionChannel::_q_proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator* auth)
{
if ((connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2
- && (switchedToHttp2 || h2RequestsToSend.count() > 0))
+ && (switchedToHttp2 || h2RequestsToSend.size() > 0))
|| connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) {
- if (h2RequestsToSend.count() > 0)
+ if (h2RequestsToSend.size() > 0)
connection->d_func()->emitProxyAuthenticationRequired(this, proxy, auth);
} else { // HTTP
// Need to dequeue the request before we can emit the error.
@@ -1171,9 +1153,9 @@ void QHttpNetworkConnectionChannel::emitFinishedWithError(QNetworkReply::Network
{
if (reply)
emit reply->finishedWithError(error, QHttpNetworkConnectionChannel::tr(message));
- QList<HttpMessagePair> h2Pairs = h2RequestsToSend.values();
- for (int a = 0; a < h2Pairs.count(); ++a) {
- QHttpNetworkReply *currentReply = h2Pairs.at(a).second;
+ const auto h2RequestsToSendCopy = h2RequestsToSend;
+ for (const auto &httpMessagePair : h2RequestsToSendCopy) {
+ QHttpNetworkReply *currentReply = httpMessagePair.second;
Q_ASSERT(currentReply);
emit currentReply->finishedWithError(error, QHttpNetworkConnectionChannel::tr(message));
}
@@ -1254,10 +1236,12 @@ void QHttpNetworkConnectionChannel::_q_encrypted()
if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2 ||
connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) {
- if (h2RequestsToSend.count() > 0) {
+ if (!h2RequestsToSend.isEmpty()) {
+ // Similar to HTTP/1.1 counterpart below:
+ const auto &pair = std::as_const(h2RequestsToSend).first();
+ emit pair.second->encrypted();
// In case our peer has sent us its settings (window size, max concurrent streams etc.)
// let's give _q_receiveReply a chance to read them first ('invokeMethod', QueuedConnection).
- QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
}
} else { // HTTP
if (!reply)
@@ -1270,14 +1254,14 @@ void QHttpNetworkConnectionChannel::_q_encrypted()
if (reply)
sendRequestDelayed();
}
+ QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
}
void QHttpNetworkConnectionChannel::requeueHttp2Requests()
{
- QList<HttpMessagePair> h2Pairs = h2RequestsToSend.values();
- for (int a = 0; a < h2Pairs.count(); ++a)
- connection->d_func()->requeueRequest(h2Pairs.at(a));
- h2RequestsToSend.clear();
+ const auto h2RequestsToSendCopy = std::exchange(h2RequestsToSend, {});
+ for (const auto &httpMessagePair : h2RequestsToSendCopy)
+ connection->d_func()->requeueRequest(httpMessagePair);
}
void QHttpNetworkConnectionChannel::_q_sslErrors(const QList<QSslError> &errors)
@@ -1296,10 +1280,10 @@ void QHttpNetworkConnectionChannel::_q_sslErrors(const QList<QSslError> &errors)
}
#ifndef QT_NO_SSL
else { // HTTP/2
- QList<HttpMessagePair> h2Pairs = h2RequestsToSend.values();
- for (int a = 0; a < h2Pairs.count(); ++a) {
+ const auto h2RequestsToSendCopy = h2RequestsToSend;
+ for (const auto &httpMessagePair : h2RequestsToSendCopy) {
// emit SSL errors for all replies
- QHttpNetworkReply *currentReply = h2Pairs.at(a).second;
+ QHttpNetworkReply *currentReply = httpMessagePair.second;
Q_ASSERT(currentReply);
emit currentReply->sslErrors(errors);
}
@@ -1319,10 +1303,10 @@ void QHttpNetworkConnectionChannel::_q_preSharedKeyAuthenticationRequired(QSslPr
if (reply)
emit reply->preSharedKeyAuthenticationRequired(authenticator);
} else {
- QList<HttpMessagePair> h2Pairs = h2RequestsToSend.values();
- for (int a = 0; a < h2Pairs.count(); ++a) {
+ const auto h2RequestsToSendCopy = h2RequestsToSend;
+ for (const auto &httpMessagePair : h2RequestsToSendCopy) {
// emit SSL errors for all replies
- QHttpNetworkReply *currentReply = h2Pairs.at(a).second;
+ QHttpNetworkReply *currentReply = httpMessagePair.second;
Q_ASSERT(currentReply);
emit currentReply->preSharedKeyAuthenticationRequired(authenticator);
}
diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h
index a0f25a6430..c42290feca 100644
--- a/src/network/access/qhttpnetworkconnectionchannel_p.h
+++ b/src/network/access/qhttpnetworkconnectionchannel_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QHTTPNETWORKCONNECTIONCHANNEL_H
#define QHTTPNETWORKCONNECTIONCHANNEL_H
@@ -76,8 +40,11 @@
# include <QtNetwork/qtcpsocket.h>
#endif
+#include <QtCore/qpointer.h>
#include <QtCore/qscopedpointer.h>
+#include <memory>
+
QT_REQUIRE_CONFIG(http);
QT_BEGIN_NAMESPACE
@@ -116,13 +83,11 @@ public:
int lastStatus; // last status received on this channel
bool pendingEncrypt; // for https (send after encrypted)
int reconnectAttempts; // maximum 2 reconnection attempts
- QAuthenticatorPrivate::Method authMethod;
- QAuthenticatorPrivate::Method proxyAuthMethod;
QAuthenticator authenticator;
QAuthenticator proxyAuthenticator;
bool authenticationCredentialsSent;
bool proxyCredentialsSent;
- QScopedPointer<QAbstractProtocolHandler> protocolHandler;
+ std::unique_ptr<QAbstractProtocolHandler> protocolHandler;
QMultiMap<int, HttpMessagePair> h2RequestsToSend;
bool switchedToHttp2 = false;
#ifndef QT_NO_SSL
diff --git a/src/network/access/qhttpnetworkheader.cpp b/src/network/access/qhttpnetworkheader.cpp
index 98d7dcafe2..7f9c94dc9c 100644
--- a/src/network/access/qhttpnetworkheader.cpp
+++ b/src/network/access/qhttpnetworkheader.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qhttpnetworkheader_p.h"
@@ -48,27 +12,12 @@ QHttpNetworkHeaderPrivate::QHttpNetworkHeaderPrivate(const QUrl &newUrl)
{
}
-QHttpNetworkHeaderPrivate::QHttpNetworkHeaderPrivate(const QHttpNetworkHeaderPrivate &other)
- :QSharedData(other)
-{
- url = other.url;
- fields = other.fields;
-}
-
qint64 QHttpNetworkHeaderPrivate::contentLength() const
{
bool ok = false;
// We are not using the headerField() method here because servers might send us multiple content-length
// headers which is crap (see QTBUG-15311). Therefore just take the first content-length header field.
- QByteArray value;
- QList<QPair<QByteArray, QByteArray> >::ConstIterator it = fields.constBegin(),
- end = fields.constEnd();
- for ( ; it != end; ++it)
- if (it->first.compare("content-length", Qt::CaseInsensitive) == 0) {
- value = it->second;
- break;
- }
-
+ QByteArray value = parser.firstHeaderField("content-length");
qint64 length = value.toULongLong(&ok);
if (ok)
return length;
@@ -80,7 +29,7 @@ void QHttpNetworkHeaderPrivate::setContentLength(qint64 length)
setHeaderField("Content-Length", QByteArray::number(length));
}
-QByteArray QHttpNetworkHeaderPrivate::headerField(const QByteArray &name, const QByteArray &defaultValue) const
+QByteArray QHttpNetworkHeaderPrivate::headerField(QByteArrayView name, const QByteArray &defaultValue) const
{
QList<QByteArray> allValues = headerFieldValues(name);
if (allValues.isEmpty())
@@ -89,37 +38,29 @@ QByteArray QHttpNetworkHeaderPrivate::headerField(const QByteArray &name, const
return allValues.join(", ");
}
-QList<QByteArray> QHttpNetworkHeaderPrivate::headerFieldValues(const QByteArray &name) const
+QList<QByteArray> QHttpNetworkHeaderPrivate::headerFieldValues(QByteArrayView name) const
{
- QList<QByteArray> result;
- QList<QPair<QByteArray, QByteArray> >::ConstIterator it = fields.constBegin(),
- end = fields.constEnd();
- for ( ; it != end; ++it)
- if (name.compare(it->first, Qt::CaseInsensitive) == 0)
- result += it->second;
-
- return result;
+ return parser.headerFieldValues(name);
}
void QHttpNetworkHeaderPrivate::setHeaderField(const QByteArray &name, const QByteArray &data)
{
- auto firstEqualsName = [&name](const QPair<QByteArray, QByteArray> &header) {
- return name.compare(header.first, Qt::CaseInsensitive) == 0;
- };
- fields.erase(std::remove_if(fields.begin(), fields.end(),
- firstEqualsName),
- fields.end());
- fields.append(qMakePair(name, data));
+ parser.setHeaderField(name, data);
}
void QHttpNetworkHeaderPrivate::prependHeaderField(const QByteArray &name, const QByteArray &data)
{
- fields.prepend(qMakePair(name, data));
+ parser.prependHeaderField(name, data);
+}
+
+QHttpHeaders QHttpNetworkHeaderPrivate::headers() const
+{
+ return parser.headers();
}
void QHttpNetworkHeaderPrivate::clearHeaders()
{
- fields.clear();
+ parser.clearHeaders();
}
bool QHttpNetworkHeaderPrivate::operator==(const QHttpNetworkHeaderPrivate &other) const
diff --git a/src/network/access/qhttpnetworkheader_p.h b/src/network/access/qhttpnetworkheader_p.h
index c8186eeda0..afbc6cb6fe 100644
--- a/src/network/access/qhttpnetworkheader_p.h
+++ b/src/network/access/qhttpnetworkheader_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QHTTPNETWORKHEADER_H
#define QHTTPNETWORKHEADER_H
@@ -52,6 +16,8 @@
//
#include <QtNetwork/private/qtnetworkglobal_p.h>
+#include <QtNetwork/private/qhttpheaderparser_p.h>
+#include <QtNetwork/qhttpheaders.h>
#include <qshareddata.h>
#include <qurl.h>
@@ -75,8 +41,8 @@ public:
virtual qint64 contentLength() const = 0;
virtual void setContentLength(qint64 length) = 0;
- virtual QList<QPair<QByteArray, QByteArray> > header() const = 0;
- virtual QByteArray headerField(const QByteArray &name, const QByteArray &defaultValue = QByteArray()) const = 0;
+ virtual QHttpHeaders header() const = 0;
+ virtual QByteArray headerField(QByteArrayView name, const QByteArray &defaultValue = QByteArray()) const = 0;
virtual void setHeaderField(const QByteArray &name, const QByteArray &data) = 0;
};
@@ -84,18 +50,19 @@ class Q_AUTOTEST_EXPORT QHttpNetworkHeaderPrivate : public QSharedData
{
public:
QUrl url;
- QList<QPair<QByteArray, QByteArray> > fields;
+ QHttpHeaderParser parser;
QHttpNetworkHeaderPrivate(const QUrl &newUrl = QUrl());
- QHttpNetworkHeaderPrivate(const QHttpNetworkHeaderPrivate &other);
+ QHttpNetworkHeaderPrivate(const QHttpNetworkHeaderPrivate &other) = default;
qint64 contentLength() const;
void setContentLength(qint64 length);
- QByteArray headerField(const QByteArray &name, const QByteArray &defaultValue = QByteArray()) const;
- QList<QByteArray> headerFieldValues(const QByteArray &name) const;
+ QByteArray headerField(QByteArrayView name, const QByteArray &defaultValue = QByteArray()) const;
+ QList<QByteArray> headerFieldValues(QByteArrayView name) const;
void setHeaderField(const QByteArray &name, const QByteArray &data);
void prependHeaderField(const QByteArray &name, const QByteArray &data);
void clearHeaders();
+ QHttpHeaders headers() const;
bool operator==(const QHttpNetworkHeaderPrivate &other) const;
};
diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp
index 29aef59369..5711c96b18 100644
--- a/src/network/access/qhttpnetworkreply.cpp
+++ b/src/network/access/qhttpnetworkreply.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qhttpnetworkreply_p.h"
#include "qhttpnetworkconnection_p.h"
@@ -46,8 +10,12 @@
# include <QtNetwork/qsslconfiguration.h>
#endif
+#include <private/qdecompresshelper_p.h>
+
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
QHttpNetworkReply::QHttpNetworkReply(const QUrl &url, QObject *parent)
: QObject(*new QHttpNetworkReplyPrivate(url), parent)
{
@@ -99,12 +67,12 @@ void QHttpNetworkReply::setContentLength(qint64 length)
d->setContentLength(length);
}
-QList<QPair<QByteArray, QByteArray> > QHttpNetworkReply::header() const
+QHttpHeaders QHttpNetworkReply::header() const
{
- return d_func()->fields;
+ return d_func()->parser.headers();
}
-QByteArray QHttpNetworkReply::headerField(const QByteArray &name, const QByteArray &defaultValue) const
+QByteArray QHttpNetworkReply::headerField(QByteArrayView name, const QByteArray &defaultValue) const
{
return d_func()->headerField(name, defaultValue);
}
@@ -115,7 +83,13 @@ void QHttpNetworkReply::setHeaderField(const QByteArray &name, const QByteArray
d->setHeaderField(name, data);
}
-void QHttpNetworkReply::parseHeader(const QByteArray &header)
+void QHttpNetworkReply::appendHeaderField(const QByteArray &name, const QByteArray &data)
+{
+ Q_D(QHttpNetworkReply);
+ d->appendHeaderField(name, data);
+}
+
+void QHttpNetworkReply::parseHeader(QByteArrayView header)
{
Q_D(QHttpNetworkReply);
d->parseHeader(header);
@@ -135,13 +109,13 @@ void QHttpNetworkReply::setRequest(const QHttpNetworkRequest &request)
int QHttpNetworkReply::statusCode() const
{
- return d_func()->statusCode;
+ return d_func()->parser.getStatusCode();
}
void QHttpNetworkReply::setStatusCode(int code)
{
Q_D(QHttpNetworkReply);
- d->statusCode = code;
+ d->parser.setStatusCode(code);
}
QString QHttpNetworkReply::errorString() const
@@ -156,7 +130,12 @@ QNetworkReply::NetworkError QHttpNetworkReply::errorCode() const
QString QHttpNetworkReply::reasonPhrase() const
{
- return d_func()->reasonPhrase;
+ return d_func()->parser.getReasonPhrase();
+}
+
+void QHttpNetworkReply::setReasonPhrase(const QString &reason)
+{
+ d_func()->parser.setReasonPhrase(reason);
}
void QHttpNetworkReply::setErrorString(const QString &error)
@@ -167,12 +146,22 @@ void QHttpNetworkReply::setErrorString(const QString &error)
int QHttpNetworkReply::majorVersion() const
{
- return d_func()->majorVersion;
+ return d_func()->parser.getMajorVersion();
}
int QHttpNetworkReply::minorVersion() const
{
- return d_func()->minorVersion;
+ return d_func()->parser.getMinorVersion();
+}
+
+void QHttpNetworkReply::setMajorVersion(int version)
+{
+ d_func()->parser.setMajorVersion(version);
+}
+
+void QHttpNetworkReply::setMinorVersion(int version)
+{
+ d_func()->parser.setMinorVersion(version);
}
qint64 QHttpNetworkReply::bytesAvailable() const
@@ -246,7 +235,8 @@ void QHttpNetworkReply::setReadBufferSize(qint64 size)
bool QHttpNetworkReply::supportsUserProvidedDownloadBuffer()
{
Q_D(QHttpNetworkReply);
- return (!d->isChunked() && !d->autoDecompress && d->bodyLength > 0 && d->statusCode == 200);
+ return !d->isChunked() && !d->autoDecompress &&
+ d->bodyLength > 0 && d->parser.getStatusCode() == 200;
}
void QHttpNetworkReply::setUserProvidedDownloadBuffer(char* b)
@@ -312,9 +302,8 @@ QHttpNetworkConnection* QHttpNetworkReply::connection()
QHttpNetworkReplyPrivate::QHttpNetworkReplyPrivate(const QUrl &newUrl)
: QHttpNetworkHeaderPrivate(newUrl)
, state(NothingDoneState)
- , ssl(false)
- , statusCode(100),
- majorVersion(0), minorVersion(0), bodyLength(0), contentRead(0), totalProgress(0),
+ , ssl(false),
+ bodyLength(0), contentRead(0), totalProgress(0),
chunkedTransferEncoding(false),
connectionCloseEnabled(true),
forceConnectionCloseEnabled(false),
@@ -329,8 +318,7 @@ QHttpNetworkReplyPrivate::QHttpNetworkReplyPrivate(const QUrl &newUrl)
{
QString scheme = newUrl.scheme();
- if (scheme == QLatin1String("preconnect-http")
- || scheme == QLatin1String("preconnect-https"))
+ if (scheme == "preconnect-http"_L1 || scheme == "preconnect-https"_L1)
// make sure we do not close the socket after preconnecting
connectionCloseEnabled = false;
}
@@ -340,7 +328,6 @@ QHttpNetworkReplyPrivate::~QHttpNetworkReplyPrivate() = default;
void QHttpNetworkReplyPrivate::clearHttpLayerInformation()
{
state = NothingDoneState;
- statusCode = 100;
bodyLength = 0;
contentRead = 0;
totalProgress = 0;
@@ -348,8 +335,7 @@ void QHttpNetworkReplyPrivate::clearHttpLayerInformation()
currentChunkRead = 0;
lastChunkRead = false;
connectionCloseEnabled = true;
- decompressHelper.clear();
- fields.clear();
+ parser.clear();
}
// TODO: Isn't everything HTTP layer related? We don't need to set connection and connectionChannel to 0 at all
@@ -382,61 +368,17 @@ void QHttpNetworkReplyPrivate::removeAutoDecompressHeader()
{
// The header "Content-Encoding = gzip" is retained.
// Content-Length is removed since the actual one sent by the server is for compressed data
- QByteArray name("content-length");
- QList<QPair<QByteArray, QByteArray> >::Iterator it = fields.begin(),
- end = fields.end();
- while (it != end) {
- if (name.compare(it->first, Qt::CaseInsensitive) == 0) {
- removedContentLength = strtoull(it->second.constData(), nullptr, 0);
- fields.erase(it);
- break;
- }
- ++it;
- }
-}
-
-bool QHttpNetworkReplyPrivate::findChallenge(bool forProxy, QByteArray &challenge) const
-{
- challenge.clear();
- // find out the type of authentication protocol requested.
- QByteArray header = forProxy ? "proxy-authenticate" : "www-authenticate";
- // pick the best protocol (has to match parsing in QAuthenticatorPrivate)
- QList<QByteArray> challenges = headerFieldValues(header);
- for (int i = 0; i<challenges.size(); i++) {
- QByteArray line = challenges.at(i);
- // todo use qstrincmp
- if (!line.toLower().startsWith("negotiate"))
- challenge = line;
- }
- return !challenge.isEmpty();
-}
-
-QAuthenticatorPrivate::Method QHttpNetworkReplyPrivate::authenticationMethod(bool isProxy) const
-{
- // The logic is same as the one used in void QAuthenticatorPrivate::parseHttpResponse()
- QAuthenticatorPrivate::Method method = QAuthenticatorPrivate::None;
- QByteArray header = isProxy ? "proxy-authenticate" : "www-authenticate";
- QList<QByteArray> challenges = headerFieldValues(header);
- for (int i = 0; i<challenges.size(); i++) {
- QByteArray line = challenges.at(i).trimmed().toLower();
- if (method < QAuthenticatorPrivate::Basic
- && line.startsWith("basic")) {
- method = QAuthenticatorPrivate::Basic;
- } else if (method < QAuthenticatorPrivate::Ntlm
- && line.startsWith("ntlm")) {
- method = QAuthenticatorPrivate::Ntlm;
- } else if (method < QAuthenticatorPrivate::DigestMd5
- && line.startsWith("digest")) {
- method = QAuthenticatorPrivate::DigestMd5;
- } else if (method < QAuthenticatorPrivate::Negotiate
- && line.startsWith("negotiate")) {
- method = QAuthenticatorPrivate::Negotiate;
- }
+ constexpr auto name = QByteArrayView("content-length");
+ QByteArray contentLength = parser.firstHeaderField(name);
+ bool parseOk = false;
+ qint64 value = contentLength.toLongLong(&parseOk);
+ if (parseOk) {
+ removedContentLength = value;
+ parser.removeHeaderField(name);
}
- return method;
}
-qint64 QHttpNetworkReplyPrivate::readStatus(QAbstractSocket *socket)
+qint64 QHttpNetworkReplyPrivate::readStatus(QIODevice *socket)
{
if (fragment.isEmpty()) {
// reserve bytes for the status line. This is better than always append() which reallocs the byte array
@@ -462,7 +404,7 @@ qint64 QHttpNetworkReplyPrivate::readStatus(QAbstractSocket *socket)
if (c == '\n') {
// remove the CR at the end
if (fragment.endsWith('\r')) {
- fragment.truncate(fragment.length()-1);
+ fragment.truncate(fragment.size()-1);
}
bool ok = parseStatus(fragment);
state = ReadingHeaderState;
@@ -476,7 +418,7 @@ qint64 QHttpNetworkReplyPrivate::readStatus(QAbstractSocket *socket)
}
// is this a valid reply?
- if (fragment.length() == 5 && !fragment.startsWith("HTTP/")) {
+ if (fragment.size() == 5 && !fragment.startsWith("HTTP/")) {
fragment.clear();
return -1;
}
@@ -485,43 +427,12 @@ qint64 QHttpNetworkReplyPrivate::readStatus(QAbstractSocket *socket)
return bytes;
}
-bool QHttpNetworkReplyPrivate::parseStatus(const QByteArray &status)
+bool QHttpNetworkReplyPrivate::parseStatus(QByteArrayView status)
{
- // from RFC 2616:
- // Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
- // HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT
- // that makes: 'HTTP/n.n xxx Message'
- // byte count: 0123456789012
-
- static const int minLength = 11;
- static const int dotPos = 6;
- static const int spacePos = 8;
- static const char httpMagic[] = "HTTP/";
-
- if (status.length() < minLength
- || !status.startsWith(httpMagic)
- || status.at(dotPos) != '.'
- || status.at(spacePos) != ' ') {
- // I don't know how to parse this status line
- return false;
- }
-
- // optimize for the valid case: defer checking until the end
- majorVersion = status.at(dotPos - 1) - '0';
- minorVersion = status.at(dotPos + 1) - '0';
-
- int i = spacePos;
- int j = status.indexOf(' ', i + 1); // j == -1 || at(j) == ' ' so j+1 == 0 && j+1 <= length()
- const QByteArray code = status.mid(i + 1, j - i - 1);
-
- bool ok;
- statusCode = code.toInt(&ok);
- reasonPhrase = QString::fromLatin1(status.constData() + j + 1);
-
- return ok && uint(majorVersion) <= 9 && uint(minorVersion) <= 9;
+ return parser.parseStatus(status);
}
-qint64 QHttpNetworkReplyPrivate::readHeader(QAbstractSocket *socket)
+qint64 QHttpNetworkReplyPrivate::readHeader(QIODevice *socket)
{
if (fragment.isEmpty()) {
// according to http://dev.opera.com/articles/view/mama-http-headers/ the average size of the header
@@ -555,8 +466,8 @@ qint64 QHttpNetworkReplyPrivate::readHeader(QAbstractSocket *socket)
allHeaders = true;
// there is another case: We have no headers. Then the fragment equals just the line ending
- if ((fragment.length() == 2 && fragment.endsWith("\r\n"))
- || (fragment.length() == 1 && fragment.endsWith("\n")))
+ if ((fragment.size() == 2 && fragment.endsWith("\r\n"))
+ || (fragment.size() == 1 && fragment.endsWith("\n")))
allHeaders = true;
}
}
@@ -577,48 +488,20 @@ qint64 QHttpNetworkReplyPrivate::readHeader(QAbstractSocket *socket)
// check for explicit indication of close or the implicit connection close of HTTP/1.0
connectionCloseEnabled = (connectionHeaderField.toLower().contains("close") ||
headerField("proxy-connection").toLower().contains("close")) ||
- (majorVersion == 1 && minorVersion == 0 &&
+ (parser.getMajorVersion() == 1 && parser.getMinorVersion() == 0 &&
(connectionHeaderField.isEmpty() && !headerField("proxy-connection").toLower().contains("keep-alive")));
- if (autoDecompress && isCompressed()) {
- if (!decompressHelper.setEncoding(headerField("content-encoding")))
- return -1; // Either the encoding was unsupported or the decoder could not be set up
- if (request.ignoreDecompressionRatio())
- decompressHelper.setArchiveBombDetectionEnabled(false);
- }
}
return bytes;
}
-void QHttpNetworkReplyPrivate::parseHeader(const QByteArray &header)
+void QHttpNetworkReplyPrivate::parseHeader(QByteArrayView header)
{
- // see rfc2616, sec 4 for information about HTTP/1.1 headers.
- // allows relaxed parsing here, accepts both CRLF & LF line endings
- int i = 0;
- while (i < header.count()) {
- int j = header.indexOf(':', i); // field-name
- if (j == -1)
- break;
- const QByteArray field = header.mid(i, j - i).trimmed();
- j++;
- // any number of LWS is allowed before and after the value
- QByteArray value;
- do {
- i = header.indexOf('\n', j);
- if (i == -1)
- break;
- if (!value.isEmpty())
- value += ' ';
- // check if we have CRLF or only LF
- bool hasCR = (i && header[i-1] == '\r');
- int length = i -(hasCR ? 1: 0) - j;
- value += header.mid(j, length).trimmed();
- j = ++i;
- } while (i < header.count() && (header.at(i) == ' ' || header.at(i) == '\t'));
- if (i == -1)
- break; // something is wrong
-
- fields.append(qMakePair(field, value));
- }
+ parser.parseHeaders(header);
+}
+
+void QHttpNetworkReplyPrivate::appendHeaderField(const QByteArray &name, const QByteArray &data)
+{
+ parser.appendHeaderField(name, data);
}
bool QHttpNetworkReplyPrivate::isChunked()
@@ -633,7 +516,7 @@ bool QHttpNetworkReplyPrivate::isConnectionCloseEnabled()
// note this function can only be used for non-chunked, non-compressed with
// known content length
-qint64 QHttpNetworkReplyPrivate::readBodyVeryFast(QAbstractSocket *socket, char *b)
+qint64 QHttpNetworkReplyPrivate::readBodyVeryFast(QIODevice *socket, char *b)
{
// This first read is to flush the buffer inside the socket
qint64 haveRead = 0;
@@ -652,7 +535,7 @@ qint64 QHttpNetworkReplyPrivate::readBodyVeryFast(QAbstractSocket *socket, char
// note this function can only be used for non-chunked, non-compressed with
// known content length
-qint64 QHttpNetworkReplyPrivate::readBodyFast(QAbstractSocket *socket, QByteDataBuffer *rb)
+qint64 QHttpNetworkReplyPrivate::readBodyFast(QIODevice *socket, QByteDataBuffer *rb)
{
qint64 toBeRead = qMin(socket->bytesAvailable(), bodyLength - contentRead);
@@ -682,51 +565,27 @@ qint64 QHttpNetworkReplyPrivate::readBodyFast(QAbstractSocket *socket, QByteData
}
-qint64 QHttpNetworkReplyPrivate::readBody(QAbstractSocket *socket, QByteDataBuffer *out)
+qint64 QHttpNetworkReplyPrivate::readBody(QIODevice *socket, QByteDataBuffer *out)
{
qint64 bytes = 0;
- // for compressed data we'll allocate a temporary one that we then decompress
- QByteDataBuffer *tempOutDataBuffer = (autoDecompress ? new QByteDataBuffer : out);
-
-
if (isChunked()) {
// chunked transfer encoding (rfc 2616, sec 3.6)
- bytes += readReplyBodyChunked(socket, tempOutDataBuffer);
+ bytes += readReplyBodyChunked(socket, out);
} else if (bodyLength > 0) {
// we have a Content-Length
- bytes += readReplyBodyRaw(socket, tempOutDataBuffer, bodyLength - contentRead);
+ bytes += readReplyBodyRaw(socket, out, bodyLength - contentRead);
if (contentRead + bytes == bodyLength)
state = AllDoneState;
} else {
// no content length. just read what's possible
- bytes += readReplyBodyRaw(socket, tempOutDataBuffer, socket->bytesAvailable());
- }
-
- // This is true if there is compressed encoding and we're supposed to use it.
- if (autoDecompress) {
- QScopedPointer holder(tempOutDataBuffer);
- if (!decompressHelper.isValid())
- return -1;
-
- decompressHelper.feed(std::move(*tempOutDataBuffer));
- while (decompressHelper.hasData()) {
- QByteArray output(4 * 1024, Qt::Uninitialized);
- qint64 read = decompressHelper.read(output.data(), output.size());
- if (read < 0) {
- return -1;
- } else if (read > 0) {
- output.resize(read);
- out->append(std::move(output));
- }
- }
+ bytes += readReplyBodyRaw(socket, out, socket->bytesAvailable());
}
-
contentRead += bytes;
return bytes;
}
-qint64 QHttpNetworkReplyPrivate::readReplyBodyRaw(QAbstractSocket *socket, QByteDataBuffer *out, qint64 size)
+qint64 QHttpNetworkReplyPrivate::readReplyBodyRaw(QIODevice *socket, QByteDataBuffer *out, qint64 size)
{
// FIXME get rid of this function and just use readBodyFast and give it socket->bytesAvailable()
qint64 bytes = 0;
@@ -759,7 +618,7 @@ qint64 QHttpNetworkReplyPrivate::readReplyBodyRaw(QAbstractSocket *socket, QByte
}
-qint64 QHttpNetworkReplyPrivate::readReplyBodyChunked(QAbstractSocket *socket, QByteDataBuffer *out)
+qint64 QHttpNetworkReplyPrivate::readReplyBodyChunked(QIODevice *socket, QByteDataBuffer *out)
{
qint64 bytes = 0;
while (socket->bytesAvailable()) {
@@ -821,7 +680,7 @@ qint64 QHttpNetworkReplyPrivate::readReplyBodyChunked(QAbstractSocket *socket, Q
return bytes;
}
-qint64 QHttpNetworkReplyPrivate::getChunkSize(QAbstractSocket *socket, qint64 *chunkSize)
+qint64 QHttpNetworkReplyPrivate::getChunkSize(QIODevice *socket, qint64 *chunkSize)
{
qint64 bytes = 0;
char crlf[2];
@@ -842,8 +701,8 @@ qint64 QHttpNetworkReplyPrivate::getChunkSize(QAbstractSocket *socket, qint64 *c
bytes += socket->read(crlf, 1); // read the \n
bool ok = false;
// ignore the chunk-extension
- fragment = fragment.mid(0, fragment.indexOf(';')).trimmed();
- *chunkSize = fragment.toLong(&ok, 16);
+ const auto fragmentView = QByteArrayView(fragment).mid(0, fragment.indexOf(';')).trimmed();
+ *chunkSize = fragmentView.toLong(&ok, 16);
fragment.clear();
break; // size done
} else {
@@ -865,7 +724,7 @@ bool QHttpNetworkReplyPrivate::isRedirecting() const
{
// We're in the process of redirecting - if the HTTP status code says so and
// followRedirect is switched on
- return (QHttpNetworkReply::isHttpRedirect(statusCode)
+ return (QHttpNetworkReply::isHttpRedirect(parser.getStatusCode())
&& request.isFollowRedirects());
}
@@ -873,11 +732,12 @@ bool QHttpNetworkReplyPrivate::shouldEmitSignals()
{
// for 401 & 407 don't emit the data signals. Content along with these
// responses are sent only if the authentication fails.
- return (statusCode != 401 && statusCode != 407);
+ return parser.getStatusCode() != 401 && parser.getStatusCode() != 407;
}
bool QHttpNetworkReplyPrivate::expectContent()
{
+ int statusCode = parser.getStatusCode();
// check whether we can expect content after the headers (rfc 2616, sec4.4)
if ((statusCode >= 100 && statusCode < 200)
|| statusCode == 204 || statusCode == 304)
@@ -944,3 +804,5 @@ void QHttpNetworkReply::ignoreSslErrors(const QList<QSslError> &errors)
QT_END_NAMESPACE
+
+#include "moc_qhttpnetworkreply_p.cpp"
diff --git a/src/network/access/qhttpnetworkreply_p.h b/src/network/access/qhttpnetworkreply_p.h
index 7a23d310cc..caec82bd7e 100644
--- a/src/network/access/qhttpnetworkreply_p.h
+++ b/src/network/access/qhttpnetworkreply_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QHTTPNETWORKREPLY_H
#define QHTTPNETWORKREPLY_H
@@ -77,6 +41,9 @@ Q_MOC_INCLUDE(<QtNetwork/QNetworkProxy>)
Q_MOC_INCLUDE(<QtNetwork/QAuthenticator>)
#include <private/qdecompresshelper_p.h>
+#include <QtNetwork/qhttpheaders.h>
+
+#include <QtCore/qpointer.h>
QT_REQUIRE_CONFIG(http);
@@ -87,7 +54,7 @@ class QHttpNetworkConnectionChannel;
class QHttpNetworkRequest;
class QHttpNetworkConnectionPrivate;
class QHttpNetworkReplyPrivate;
-class Q_AUTOTEST_EXPORT QHttpNetworkReply : public QObject, public QHttpNetworkHeader
+class Q_NETWORK_EXPORT QHttpNetworkReply : public QObject, public QHttpNetworkHeader
{
Q_OBJECT
public:
@@ -100,14 +67,17 @@ public:
int majorVersion() const override;
int minorVersion() const override;
+ void setMajorVersion(int version);
+ void setMinorVersion(int version);
qint64 contentLength() const override;
void setContentLength(qint64 length) override;
- QList<QPair<QByteArray, QByteArray> > header() const override;
- QByteArray headerField(const QByteArray &name, const QByteArray &defaultValue = QByteArray()) const override;
+ QHttpHeaders header() const override;
+ QByteArray headerField(QByteArrayView name, const QByteArray &defaultValue = QByteArray()) const override;
void setHeaderField(const QByteArray &name, const QByteArray &data) override;
- void parseHeader(const QByteArray &header); // mainly for testing
+ void appendHeaderField(const QByteArray &name, const QByteArray &data);
+ void parseHeader(QByteArrayView header); // used for testing
QHttpNetworkRequest request() const;
void setRequest(const QHttpNetworkRequest &request);
@@ -121,6 +91,7 @@ public:
QNetworkReply::NetworkError errorCode() const;
QString reasonPhrase() const;
+ void setReasonPhrase(const QString &reason);
qint64 bytesAvailable() const;
qint64 bytesAvailableNextBlock() const;
@@ -170,6 +141,8 @@ Q_SIGNALS:
#endif
Q_SIGNALS:
+ void socketStartedConnecting();
+ void requestSent();
void readyRead();
void finished();
void finishedWithError(QNetworkReply::NetworkError errorCode, const QString &detail = QString());
@@ -199,21 +172,20 @@ class Q_AUTOTEST_EXPORT QHttpNetworkReplyPrivate : public QObjectPrivate, public
public:
QHttpNetworkReplyPrivate(const QUrl &newUrl = QUrl());
~QHttpNetworkReplyPrivate();
- qint64 readStatus(QAbstractSocket *socket);
- bool parseStatus(const QByteArray &status);
- qint64 readHeader(QAbstractSocket *socket);
- void parseHeader(const QByteArray &header);
- qint64 readBody(QAbstractSocket *socket, QByteDataBuffer *out);
- qint64 readBodyVeryFast(QAbstractSocket *socket, char *b);
- qint64 readBodyFast(QAbstractSocket *socket, QByteDataBuffer *rb);
- bool findChallenge(bool forProxy, QByteArray &challenge) const;
- QAuthenticatorPrivate::Method authenticationMethod(bool isProxy) const;
+ qint64 readStatus(QIODevice *socket);
+ bool parseStatus(QByteArrayView status);
+ qint64 readHeader(QIODevice *socket);
+ void parseHeader(QByteArrayView header);
+ void appendHeaderField(const QByteArray &name, const QByteArray &data);
+ qint64 readBody(QIODevice *socket, QByteDataBuffer *out);
+ qint64 readBodyVeryFast(QIODevice *socket, char *b);
+ qint64 readBodyFast(QIODevice *socket, QByteDataBuffer *rb);
void clear();
void clearHttpLayerInformation();
- qint64 readReplyBodyRaw(QAbstractSocket *in, QByteDataBuffer *out, qint64 size);
- qint64 readReplyBodyChunked(QAbstractSocket *in, QByteDataBuffer *out);
- qint64 getChunkSize(QAbstractSocket *in, qint64 *chunkSize);
+ qint64 readReplyBodyRaw(QIODevice *in, QByteDataBuffer *out, qint64 size);
+ qint64 readReplyBodyChunked(QIODevice *in, QByteDataBuffer *out);
+ qint64 getChunkSize(QIODevice *in, qint64 *chunkSize);
bool isRedirecting() const;
bool shouldEmitSignals();
@@ -242,11 +214,7 @@ public:
QHttpNetworkRequest request;
bool ssl;
- int statusCode;
- int majorVersion;
- int minorVersion;
QString errorString;
- QString reasonPhrase;
qint64 bodyLength;
qint64 contentRead;
qint64 totalProgress;
@@ -275,8 +243,6 @@ public:
char* userProvidedDownloadBuffer;
QUrl redirectUrl;
-
- QDecompressHelper decompressHelper;
};
diff --git a/src/network/access/qhttpnetworkrequest.cpp b/src/network/access/qhttpnetworkrequest.cpp
index c0b2167d15..7a4ffb1684 100644
--- a/src/network/access/qhttpnetworkrequest.cpp
+++ b/src/network/access/qhttpnetworkrequest.cpp
@@ -1,47 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qhttpnetworkrequest_p.h"
#include "private/qnoncontiguousbytedevice_p.h"
QT_BEGIN_NAMESPACE
+QT_IMPL_METATYPE_EXTERN(QHttpNetworkRequest)
+
QHttpNetworkRequestPrivate::QHttpNetworkRequestPrivate(QHttpNetworkRequest::Operation op,
QHttpNetworkRequest::Priority pri, const QUrl &newUrl)
: QHttpNetworkHeaderPrivate(newUrl), operation(op), priority(pri), uploadByteDevice(nullptr),
@@ -61,10 +27,11 @@ QHttpNetworkRequestPrivate::QHttpNetworkRequestPrivate(const QHttpNetworkRequest
pipeliningAllowed(other.pipeliningAllowed),
http2Allowed(other.http2Allowed),
http2Direct(other.http2Direct),
+ h2cAllowed(other.h2cAllowed),
withCredentials(other.withCredentials),
ssl(other.ssl),
preConnect(other.preConnect),
- ignoreDecompressionRatio(other.ignoreDecompressionRatio),
+ needResendWithCredentials(other.needResendWithCredentials),
redirectCount(other.redirectCount),
redirectPolicy(other.redirectPolicy),
peerVerifyName(other.peerVerifyName)
@@ -85,13 +52,16 @@ bool QHttpNetworkRequestPrivate::operator==(const QHttpNetworkRequestPrivate &ot
&& (pipeliningAllowed == other.pipeliningAllowed)
&& (http2Allowed == other.http2Allowed)
&& (http2Direct == other.http2Direct)
+ && (h2cAllowed == other.h2cAllowed)
// we do not clear the customVerb in setOperation
&& (operation != QHttpNetworkRequest::Custom || (customVerb == other.customVerb))
&& (withCredentials == other.withCredentials)
&& (ssl == other.ssl)
&& (preConnect == other.preConnect)
&& (redirectPolicy == other.redirectPolicy)
- && (peerVerifyName == other.peerVerifyName);
+ && (peerVerifyName == other.peerVerifyName)
+ && (needResendWithCredentials == other.needResendWithCredentials)
+ ;
}
QByteArray QHttpNetworkRequest::methodName() const
@@ -142,9 +112,9 @@ QByteArray QHttpNetworkRequest::uri(bool throughProxy) const
QByteArray QHttpNetworkRequestPrivate::header(const QHttpNetworkRequest &request, bool throughProxy)
{
- QList<QPair<QByteArray, QByteArray> > fields = request.header();
+ const QHttpHeaders headers = request.header();
QByteArray ba;
- ba.reserve(40 + fields.length()*25); // very rough lower bound estimation
+ ba.reserve(40 + headers.size() * 25); // very rough lower bound estimation
ba += request.methodName();
ba += ' ';
@@ -156,12 +126,10 @@ QByteArray QHttpNetworkRequestPrivate::header(const QHttpNetworkRequest &request
ba += QByteArray::number(request.minorVersion());
ba += "\r\n";
- QList<QPair<QByteArray, QByteArray> >::const_iterator it = fields.constBegin();
- QList<QPair<QByteArray, QByteArray> >::const_iterator endIt = fields.constEnd();
- for (; it != endIt; ++it) {
- ba += it->first;
+ for (qsizetype i = 0; i < headers.size(); ++i) {
+ ba += headers.nameAt(i);
ba += ": ";
- ba += it->second;
+ ba += headers.valueAt(i);
ba += "\r\n";
}
if (request.d->operation == QHttpNetworkRequest::Post) {
@@ -267,12 +235,12 @@ void QHttpNetworkRequest::setContentLength(qint64 length)
d->setContentLength(length);
}
-QList<QPair<QByteArray, QByteArray> > QHttpNetworkRequest::header() const
+QHttpHeaders QHttpNetworkRequest::header() const
{
- return d->fields;
+ return d->parser.headers();
}
-QByteArray QHttpNetworkRequest::headerField(const QByteArray &name, const QByteArray &defaultValue) const
+QByteArray QHttpNetworkRequest::headerField(QByteArrayView name, const QByteArray &defaultValue) const
{
return d->headerField(name, defaultValue);
}
@@ -363,6 +331,16 @@ void QHttpNetworkRequest::setHTTP2Direct(bool b)
d->http2Direct = b;
}
+bool QHttpNetworkRequest::isH2cAllowed() const
+{
+ return d->h2cAllowed;
+}
+
+void QHttpNetworkRequest::setH2cAllowed(bool b)
+{
+ d->h2cAllowed = b;
+}
+
bool QHttpNetworkRequest::withCredentials() const
{
return d->withCredentials;
@@ -403,15 +381,5 @@ void QHttpNetworkRequest::setPeerVerifyName(const QString &peerName)
d->peerVerifyName = peerName;
}
-bool QHttpNetworkRequest::ignoreDecompressionRatio()
-{
- return d->ignoreDecompressionRatio;
-}
-
-void QHttpNetworkRequest::setIgnoreDecompressionRatio(bool enabled)
-{
- d->ignoreDecompressionRatio = enabled;
-}
-
QT_END_NAMESPACE
diff --git a/src/network/access/qhttpnetworkrequest_p.h b/src/network/access/qhttpnetworkrequest_p.h
index 1a38b24a8a..131885f6d2 100644
--- a/src/network/access/qhttpnetworkrequest_p.h
+++ b/src/network/access/qhttpnetworkrequest_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QHTTPNETWORKREQUEST_H
#define QHTTPNETWORKREQUEST_H
@@ -101,8 +65,8 @@ public:
qint64 contentLength() const override;
void setContentLength(qint64 length) override;
- QList<QPair<QByteArray, QByteArray> > header() const override;
- QByteArray headerField(const QByteArray &name, const QByteArray &defaultValue = QByteArray()) const override;
+ QHttpHeaders header() const override;
+ QByteArray headerField(QByteArrayView name, const QByteArray &defaultValue = QByteArray()) const override;
void setHeaderField(const QByteArray &name, const QByteArray &data) override;
void prependHeaderField(const QByteArray &name, const QByteArray &data);
void clearHeaders();
@@ -125,6 +89,9 @@ public:
bool isHTTP2Direct() const;
void setHTTP2Direct(bool b);
+ bool isH2cAllowed() const;
+ void setH2cAllowed(bool b);
+
bool withCredentials() const;
void setWithCredentials(bool b);
@@ -150,8 +117,6 @@ public:
QString peerVerifyName() const;
void setPeerVerifyName(const QString &peerName);
- bool ignoreDecompressionRatio();
- void setIgnoreDecompressionRatio(bool enabled);
private:
QSharedDataPointer<QHttpNetworkRequestPrivate> d;
friend class QHttpNetworkRequestPrivate;
@@ -181,10 +146,11 @@ public:
bool pipeliningAllowed;
bool http2Allowed;
bool http2Direct;
+ bool h2cAllowed = false;
bool withCredentials;
bool ssl;
bool preConnect;
- bool ignoreDecompressionRatio = false;
+ bool needResendWithCredentials = false;
int redirectCount;
QNetworkRequest::RedirectPolicy redirectPolicy;
QString peerVerifyName;
@@ -193,6 +159,6 @@ public:
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QHttpNetworkRequest)
+QT_DECL_METATYPE_EXTERN(QHttpNetworkRequest, Q_AUTOTEST_EXPORT)
#endif // QHTTPNETWORKREQUEST_H
diff --git a/src/network/access/qhttpprotocolhandler.cpp b/src/network/access/qhttpprotocolhandler.cpp
index 69afd35b57..28eab03890 100644
--- a/src/network/access/qhttpprotocolhandler.cpp
+++ b/src/network/access/qhttpprotocolhandler.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2014 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <private/qhttpprotocolhandler_p.h>
#include <private/qnoncontiguousbytedevice_p.h>
@@ -44,6 +8,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
QHttpProtocolHandler::QHttpProtocolHandler(QHttpNetworkConnectionChannel *channel)
: QAbstractProtocolHandler(channel)
{
@@ -107,7 +73,7 @@ void QHttpProtocolHandler::_q_receiveReply()
return;
}
bytes += statusBytes;
- m_channel->lastStatus = m_reply->d_func()->statusCode;
+ m_channel->lastStatus = m_reply->statusCode();
break;
}
case QHttpNetworkReplyPrivate::ReadingHeaderState: {
@@ -127,7 +93,8 @@ void QHttpProtocolHandler::_q_receiveReply()
} else {
replyPrivate->autoDecompress = false;
}
- if (replyPrivate->statusCode == 100) {
+ const int statusCode = m_reply->statusCode();
+ if (statusCode == 100 || (102 <= statusCode && statusCode <= 199)) {
replyPrivate->clearHttpLayerInformation();
replyPrivate->state = QHttpNetworkReplyPrivate::ReadingStatusState;
break; // ignore
@@ -177,8 +144,7 @@ void QHttpProtocolHandler::_q_receiveReply()
m_connection->d_func()->emitReplyError(m_socket, m_reply, QNetworkReply::RemoteHostClosedError);
break;
}
- } else if (!replyPrivate->isChunked() && !replyPrivate->autoDecompress
- && replyPrivate->bodyLength > 0) {
+ } else if (!replyPrivate->isChunked() && replyPrivate->bodyLength > 0) {
// bulk files like images should fulfill these properties and
// we can therefore save on memory copying
qint64 haveRead = replyPrivate->readBodyFast(m_socket, &replyPrivate->responseData);
@@ -216,6 +182,8 @@ void QHttpProtocolHandler::_q_receiveReply()
}
case QHttpNetworkReplyPrivate::AllDoneState:
m_channel->allDone();
+ if (state == QHttpNetworkReplyPrivate::AllDoneState)
+ lastBytes = bytes; // No need to loop more just to call m_channel->allDone again.
break;
default:
break;
@@ -271,9 +239,7 @@ bool QHttpProtocolHandler::sendRequest()
// _q_connected or _q_encrypted
return false;
}
- QString scheme = m_channel->request.url().scheme();
- if (scheme == QLatin1String("preconnect-http")
- || scheme == QLatin1String("preconnect-https")) {
+ if (m_channel->request.isPreConnect()) {
m_channel->state = QHttpNetworkConnectionChannel::IdleState;
m_reply->d_func()->state = QHttpNetworkReplyPrivate::AllDoneState;
m_channel->allDone();
@@ -318,6 +284,7 @@ bool QHttpProtocolHandler::sendRequest()
#else
m_header = QHttpNetworkRequestPrivate::header(m_channel->request, false);
#endif
+
// flushing is dangerous (QSslSocket calls transmit which might read or error)
// m_socket->flush();
QNonContiguousByteDevice* uploadByteDevice = m_channel->request.uploadByteDevice();
@@ -331,7 +298,8 @@ bool QHttpProtocolHandler::sendRequest()
sendRequest(); //recurse
} else {
// no data to send: just send the HTTP headers
- m_socket->write(qExchange(m_header, {}));
+ m_socket->write(std::exchange(m_header, {}));
+ QMetaObject::invokeMethod(m_reply, "requestSent", Qt::QueuedConnection);
m_channel->state = QHttpNetworkConnectionChannel::WaitingState; // now wait for response
sendRequest(); //recurse
}
@@ -346,7 +314,7 @@ bool QHttpProtocolHandler::sendRequest()
// the upload device might have no data to send, but we still have to send the headers,
// do it now.
if (!m_header.isEmpty())
- m_socket->write(qExchange(m_header, {}));
+ m_socket->write(std::exchange(m_header, {}));
if (uploadByteDevice)
emit m_reply->dataSendProgress(m_channel->written, m_channel->bytesTotal);
m_channel->state = QHttpNetworkConnectionChannel::WaitingState; // now wait for response
@@ -403,9 +371,10 @@ bool QHttpProtocolHandler::sendRequest()
// assemble header and data and send them together
const qint64 headerSize = m_header.size();
m_header.append(readPointer, currentReadSize);
- currentWriteSize = m_socket->write(qExchange(m_header, {}));
+ currentWriteSize = m_socket->write(std::exchange(m_header, {}));
if (currentWriteSize != -1)
currentWriteSize -= headerSize;
+ QMetaObject::invokeMethod(m_reply, "requestSent", Qt::QueuedConnection);
}
if (currentWriteSize == -1 || currentWriteSize != currentReadSize) {
// socket broke down
diff --git a/src/network/access/qhttpprotocolhandler_p.h b/src/network/access/qhttpprotocolhandler_p.h
index f2da21d3b6..221e98d538 100644
--- a/src/network/access/qhttpprotocolhandler_p.h
+++ b/src/network/access/qhttpprotocolhandler_p.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2014 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QHTTPPROTOCOLHANDLER_H
#define QHTTPPROTOCOLHANDLER_H
diff --git a/src/network/access/qhttpthreaddelegate.cpp b/src/network/access/qhttpthreaddelegate.cpp
index 05b720c4df..b0ae0dcf44 100644
--- a/src/network/access/qhttpthreaddelegate.cpp
+++ b/src/network/access/qhttpthreaddelegate.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//#define QHTTPTHREADDELEGATE_DEBUG
#include "qhttpthreaddelegate_p.h"
@@ -52,6 +16,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
static QNetworkReply::NetworkError statusCodeFromHttp(int httpStatusCode, const QUrl &url)
{
QNetworkReply::NetworkError code;
@@ -128,14 +94,12 @@ static QByteArray makeCacheKey(QUrl &url, QNetworkProxy *proxy, const QString &p
QString result;
QUrl copy = url;
QString scheme = copy.scheme();
- bool isEncrypted = scheme == QLatin1String("https")
- || scheme == QLatin1String("preconnect-https");
+ bool isEncrypted = scheme == "https"_L1 || scheme == "preconnect-https"_L1;
copy.setPort(copy.port(isEncrypted ? 443 : 80));
- if (scheme == QLatin1String("preconnect-http")) {
- copy.setScheme(QLatin1String("http"));
- } else if (scheme == QLatin1String("preconnect-https")) {
- copy.setScheme(QLatin1String("https"));
- }
+ if (scheme == "preconnect-http"_L1)
+ copy.setScheme("http"_L1);
+ else if (scheme == "preconnect-https"_L1)
+ copy.setScheme("https"_L1);
result = copy.toString(QUrl::RemoveUserInfo | QUrl::RemovePath |
QUrl::RemoveQuery | QUrl::RemoveFragment | QUrl::FullyEncoded);
@@ -145,12 +109,12 @@ static QByteArray makeCacheKey(QUrl &url, QNetworkProxy *proxy, const QString &p
switch (proxy->type()) {
case QNetworkProxy::Socks5Proxy:
- key.setScheme(QLatin1String("proxy-socks5"));
+ key.setScheme("proxy-socks5"_L1);
break;
case QNetworkProxy::HttpProxy:
case QNetworkProxy::HttpCachingProxy:
- key.setScheme(QLatin1String("proxy-http"));
+ key.setScheme("proxy-http"_L1);
break;
default:
@@ -172,7 +136,7 @@ static QByteArray makeCacheKey(QUrl &url, QNetworkProxy *proxy, const QString &p
Q_UNUSED(proxy);
#endif
if (!peerVerifyName.isEmpty())
- result += QLatin1Char(':') + peerVerifyName;
+ result += u':' + peerVerifyName;
return "http-connection:" + std::move(result).toLatin1();
}
@@ -181,9 +145,9 @@ class QNetworkAccessCachedHttpConnection: public QHttpNetworkConnection,
{
// Q_OBJECT
public:
- QNetworkAccessCachedHttpConnection(const QString &hostName, quint16 port, bool encrypt,
+ QNetworkAccessCachedHttpConnection(quint16 connectionCount, const QString &hostName, quint16 port, bool encrypt,
QHttpNetworkConnection::ConnectionType connectionType)
- : QHttpNetworkConnection(hostName, port, encrypt, connectionType)
+ : QHttpNetworkConnection(connectionCount, hostName, port, encrypt, /*parent=*/nullptr, connectionType)
{
setExpires(true);
setShareable(true);
@@ -226,6 +190,7 @@ QHttpThreadDelegate::QHttpThreadDelegate(QObject *parent) :
, pendingDownloadData()
, pendingDownloadProgress()
, synchronous(false)
+ , connectionCacheExpiryTimeoutSeconds(-1)
, incomingStatusCode(0)
, isPipeliningUsed(false)
, isHttp2Used(false)
@@ -289,6 +254,12 @@ void QHttpThreadDelegate::startRequest()
connectionType = QHttpNetworkConnection::ConnectionTypeHTTP2Direct;
}
+ // Use HTTP/1.1 if h2c is not allowed and we would otherwise choose to use it
+ if (!ssl && connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2
+ && !httpRequest.isH2cAllowed()) {
+ connectionType = QHttpNetworkConnection::ConnectionTypeHTTP;
+ }
+
#if QT_CONFIG(ssl)
// See qnetworkreplyhttpimpl, delegate's initialization code.
Q_ASSERT(!ssl || incomingSslConfiguration.data());
@@ -326,7 +297,7 @@ void QHttpThreadDelegate::startRequest()
if (!httpConnection) {
// no entry in cache; create an object
// the http object is actually a QHttpNetworkConnection
- httpConnection = new QNetworkAccessCachedHttpConnection(urlCopy.host(), urlCopy.port(), ssl,
+ httpConnection = new QNetworkAccessCachedHttpConnection(http1Parameters.numberOfConnectionsPerHost(), urlCopy.host(), urlCopy.port(), ssl,
connectionType);
if (connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2
|| connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) {
@@ -344,7 +315,7 @@ void QHttpThreadDelegate::startRequest()
#endif
httpConnection->setPeerVerifyName(httpRequest.peerVerifyName());
// cache the QHttpNetworkConnection corresponding to this cache key
- connections.localData()->addEntry(cacheKey, httpConnection);
+ connections.localData()->addEntry(cacheKey, httpConnection, connectionCacheExpiryTimeoutSeconds);
} else {
if (httpRequest.withCredentials()) {
QNetworkAuthenticationCredential credential = authenticationManager->fetchCachedCredentials(httpRequest.url(), nullptr);
@@ -377,6 +348,8 @@ void QHttpThreadDelegate::startRequest()
// Don't care about ignored SSL errors for now in the synchronous HTTP case.
} else if (!synchronous) {
+ connect(httpReply,SIGNAL(socketStartedConnecting()), this, SIGNAL(socketStartedConnecting()));
+ connect(httpReply,SIGNAL(requestSent()), this, SIGNAL(requestSent()));
connect(httpReply,SIGNAL(headerChanged()), this, SLOT(headerChangedSlot()));
connect(httpReply,SIGNAL(finished()), this, SLOT(finishedSlot()));
connect(httpReply,SIGNAL(finishedWithError(QNetworkReply::NetworkError,QString)),
@@ -513,8 +486,8 @@ void QHttpThreadDelegate::finishedSlot()
if (httpReply->statusCode() >= 400) {
// it's an error reply
- QString msg = QLatin1String(QT_TRANSLATE_NOOP("QNetworkReply",
- "Error transferring %1 - server replied: %2"));
+ QString msg = QLatin1StringView(QT_TRANSLATE_NOOP("QNetworkReply",
+ "Error transferring %1 - server replied: %2"));
msg = msg.arg(httpRequest.url().toString(), httpReply->reasonPhrase());
emit error(statusCodeFromHttp(httpReply->statusCode(), httpRequest.url()), msg);
}
@@ -539,12 +512,13 @@ void QHttpThreadDelegate::synchronousFinishedSlot()
#endif
if (httpReply->statusCode() >= 400) {
// it's an error reply
- QString msg = QLatin1String(QT_TRANSLATE_NOOP("QNetworkReply",
- "Error transferring %1 - server replied: %2"));
+ QString msg = QLatin1StringView(QT_TRANSLATE_NOOP("QNetworkReply",
+ "Error transferring %1 - server replied: %2"));
incomingErrorDetail = msg.arg(httpRequest.url().toString(), httpReply->reasonPhrase());
incomingErrorCode = statusCodeFromHttp(httpReply->statusCode(), httpRequest.url());
}
+ isCompressed = httpReply->isCompressed();
synchronousDownloadData = httpReply->readAll();
QMetaObject::invokeMethod(httpReply, "deleteLater", Qt::QueuedConnection);
@@ -593,11 +567,6 @@ void QHttpThreadDelegate::synchronousFinishedWithErrorSlot(QNetworkReply::Networ
httpReply = nullptr;
}
-static void downloadBufferDeleter(char *ptr)
-{
- delete[] ptr;
-}
-
void QHttpThreadDelegate::headerChangedSlot()
{
if (!httpReply)
@@ -615,14 +584,11 @@ void QHttpThreadDelegate::headerChangedSlot()
// Is using a zerocopy buffer allowed by user and possible with this reply?
if (httpReply->supportsUserProvidedDownloadBuffer()
&& (downloadBufferMaximumSize > 0) && (httpReply->contentLength() <= downloadBufferMaximumSize)) {
- QT_TRY {
- char *buf = new char[httpReply->contentLength()]; // throws if allocation fails
- if (buf) {
- downloadBuffer = QSharedPointer<char>(buf, downloadBufferDeleter);
- httpReply->setUserProvidedDownloadBuffer(buf);
- }
- } QT_CATCH(const std::bad_alloc &) {
- // in out of memory situations, don't use downloadbuffer.
+ char *buf = new (std::nothrow) char[httpReply->contentLength()];
+ // in out of memory situations, don't use downloadBuffer.
+ if (buf) {
+ downloadBuffer = QSharedPointer<char>(buf, [](auto p) { delete[] p; });
+ httpReply->setUserProvidedDownloadBuffer(buf);
}
}
@@ -634,6 +600,7 @@ void QHttpThreadDelegate::headerChangedSlot()
incomingContentLength = httpReply->contentLength();
removedContentLength = httpReply->removedContentLength();
isHttp2Used = httpReply->isHttp2Used();
+ isCompressed = httpReply->isCompressed();
emit downloadMetaData(incomingHeaders,
incomingStatusCode,
@@ -642,7 +609,8 @@ void QHttpThreadDelegate::headerChangedSlot()
downloadBuffer,
incomingContentLength,
removedContentLength,
- isHttp2Used);
+ isHttp2Used,
+ isCompressed);
}
void QHttpThreadDelegate::synchronousHeaderChangedSlot()
@@ -763,3 +731,5 @@ void QHttpThreadDelegate::synchronousProxyAuthenticationRequiredSlot(const QNet
#endif
QT_END_NAMESPACE
+
+#include "moc_qhttpthreaddelegate_p.cpp"
diff --git a/src/network/access/qhttpthreaddelegate_p.h b/src/network/access/qhttpthreaddelegate_p.h
index 5849d3427f..38e9fb4d78 100644
--- a/src/network/access/qhttpthreaddelegate_p.h
+++ b/src/network/access/qhttpthreaddelegate_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QHTTPTHREADDELEGATE_H
#define QHTTPTHREADDELEGATE_H
@@ -62,12 +26,14 @@
#include <QNetworkReply>
#include "qhttpnetworkrequest_p.h"
#include "qhttpnetworkconnection_p.h"
+#include "qhttp1configuration.h"
#include "qhttp2configuration.h"
#include <QSharedPointer>
#include <QScopedPointer>
#include "private/qnoncontiguousbytedevice_p.h"
#include "qnetworkaccessauthenticationmanager_p.h"
#include <QtNetwork/private/http2protocol_p.h>
+#include <QtNetwork/qhttpheaders.h>
QT_REQUIRE_CONFIG(http);
@@ -97,18 +63,19 @@ public:
qint64 readBufferMaxSize;
qint64 bytesEmitted;
// From backend, modified by us for signal compression
- QSharedPointer<QAtomicInt> pendingDownloadData;
- QSharedPointer<QAtomicInt> pendingDownloadProgress;
+ std::shared_ptr<QAtomicInt> pendingDownloadData;
+ std::shared_ptr<QAtomicInt> pendingDownloadProgress;
#ifndef QT_NO_NETWORKPROXY
QNetworkProxy cacheProxy;
QNetworkProxy transparentProxy;
#endif
- QSharedPointer<QNetworkAccessAuthenticationManager> authenticationManager;
+ std::shared_ptr<QNetworkAccessAuthenticationManager> authenticationManager;
bool synchronous;
+ qint64 connectionCacheExpiryTimeoutSeconds;
// outgoing, Retrieved in the synchronous HTTP case
QByteArray synchronousDownloadData;
- QList<QPair<QByteArray,QByteArray> > incomingHeaders;
+ QHttpHeaders incomingHeaders;
int incomingStatusCode;
QString incomingReasonPhrase;
bool isPipeliningUsed;
@@ -117,8 +84,11 @@ public:
qint64 removedContentLength;
QNetworkReply::NetworkError incomingErrorCode;
QString incomingErrorDetail;
+ QHttp1Configuration http1Parameters;
QHttp2Configuration http2Parameters;
+ bool isCompressed;
+
protected:
// The zerocopy download buffer, if used:
QSharedPointer<char> downloadBuffer;
@@ -141,8 +111,10 @@ signals:
void sslConfigurationChanged(const QSslConfiguration &);
void preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator *);
#endif
- void downloadMetaData(const QList<QPair<QByteArray,QByteArray> > &, int, const QString &, bool,
- QSharedPointer<char>, qint64, qint64, bool);
+ void socketStartedConnecting();
+ void requestSent();
+ void downloadMetaData(const QHttpHeaders &, int, const QString &, bool,
+ QSharedPointer<char>, qint64, qint64, bool, bool);
void downloadProgress(qint64, qint64);
void downloadData(const QByteArray &);
void error(QNetworkReply::NetworkError, const QString &);
@@ -193,22 +165,18 @@ class QNonContiguousByteDeviceThreadForwardImpl : public QNonContiguousByteDevic
{
Q_OBJECT
protected:
- bool wantDataPending;
- qint64 m_amount;
- char *m_data;
+ bool wantDataPending = false;
+ qint64 m_amount = 0;
+ char *m_data = nullptr;
QByteArray m_dataArray;
- bool m_atEnd;
- qint64 m_size;
- qint64 m_pos; // to match calls of haveDataSlot with the expected position
+ bool m_atEnd = false;
+ qint64 m_size = 0;
+ qint64 m_pos = 0; // to match calls of haveDataSlot with the expected position
public:
QNonContiguousByteDeviceThreadForwardImpl(bool aE, qint64 s)
: QNonContiguousByteDevice(),
- wantDataPending(false),
- m_amount(0),
- m_data(nullptr),
m_atEnd(aE),
- m_size(s),
- m_pos(0)
+ m_size(s)
{
}
@@ -281,6 +249,7 @@ public:
if (b) {
// the reset succeeded, we're at pos 0 again
m_pos = 0;
+ m_atEnd = false;
// the HTTP code will anyway abort the request if !b.
}
return b;
diff --git a/src/network/access/qnetworkaccessauthenticationmanager.cpp b/src/network/access/qnetworkaccessauthenticationmanager.cpp
index 4899273aa8..ab7c27b885 100644
--- a/src/network/access/qnetworkaccessauthenticationmanager.cpp
+++ b/src/network/access/qnetworkaccessauthenticationmanager.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qnetworkaccessauthenticationmanager_p.h"
#include "qnetworkaccessmanager.h"
@@ -51,6 +15,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
class QNetworkAuthenticationCache : private QList<QNetworkAuthenticationCredential>,
public QNetworkAccessCache::CacheableObject
{
@@ -62,20 +28,23 @@ public:
reserve(1);
}
- QNetworkAuthenticationCredential *findClosestMatch(const QString &domain)
+ using QList<QNetworkAuthenticationCredential>::begin;
+ using QList<QNetworkAuthenticationCredential>::end;
+
+ iterator findClosestMatch(const QString &domain)
{
iterator it = std::lower_bound(begin(), end(), domain);
if (it == end() && !isEmpty())
--it;
if (it == end() || !domain.startsWith(it->domain))
- return nullptr;
- return &*it;
+ return end();
+ return it;
}
void insert(const QString &domain, const QString &user, const QString &password)
{
- QNetworkAuthenticationCredential *closestMatch = findClosestMatch(domain);
- if (closestMatch && closestMatch->domain == domain) {
+ iterator closestMatch = findClosestMatch(domain);
+ if (closestMatch != end() && closestMatch->domain == domain) {
// we're overriding the current credentials
closestMatch->user = user;
closestMatch->password = password;
@@ -85,7 +54,7 @@ public:
newCredential.user = user;
newCredential.password = password;
- if (closestMatch)
+ if (closestMatch != end())
QList<QNetworkAuthenticationCredential>::insert(++closestMatch, newCredential);
else
QList<QNetworkAuthenticationCredential>::insert(end(), newCredential);
@@ -102,16 +71,16 @@ static QByteArray proxyAuthenticationKey(const QNetworkProxy &proxy, const QStri
switch (proxy.type()) {
case QNetworkProxy::Socks5Proxy:
- key.setScheme(QLatin1String("proxy-socks5"));
+ key.setScheme("proxy-socks5"_L1);
break;
case QNetworkProxy::HttpProxy:
case QNetworkProxy::HttpCachingProxy:
- key.setScheme(QLatin1String("proxy-http"));
+ key.setScheme("proxy-http"_L1);
break;
case QNetworkProxy::FtpCachingProxy:
- key.setScheme(QLatin1String("proxy-ftp"));
+ key.setScheme("proxy-ftp"_L1);
break;
case QNetworkProxy::DefaultProxy:
@@ -287,9 +256,9 @@ QNetworkAccessAuthenticationManager::fetchCachedCredentials(const QUrl &url,
QNetworkAuthenticationCache *auth =
static_cast<QNetworkAuthenticationCache *>(authenticationCache.requestEntryNow(cacheKey));
- QNetworkAuthenticationCredential *cred = auth->findClosestMatch(url.path());
+ auto cred = auth->findClosestMatch(url.path());
QNetworkAuthenticationCredential ret;
- if (cred)
+ if (cred != auth->end())
ret = *cred;
authenticationCache.releaseEntry(cacheKey);
return ret;
diff --git a/src/network/access/qnetworkaccessauthenticationmanager_p.h b/src/network/access/qnetworkaccessauthenticationmanager_p.h
index bf57dffbb0..f88360f1c1 100644
--- a/src/network/access/qnetworkaccessauthenticationmanager_p.h
+++ b/src/network/access/qnetworkaccessauthenticationmanager_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNETWORKACCESSAUTHENTICATIONMANAGER_P_H
#define QNETWORKACCESSAUTHENTICATIONMANAGER_P_H
@@ -74,7 +38,7 @@ public:
return domain.isNull() && user.isNull() && password.isNull();
}
};
-Q_DECLARE_TYPEINFO(QNetworkAuthenticationCredential, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QNetworkAuthenticationCredential, Q_RELOCATABLE_TYPE);
inline bool operator<(const QNetworkAuthenticationCredential &t1, const QString &t2)
{ return t1.domain < t2; }
inline bool operator<(const QString &t1, const QNetworkAuthenticationCredential &t2)
diff --git a/src/network/access/qnetworkaccessbackend.cpp b/src/network/access/qnetworkaccessbackend.cpp
index f7e29340d9..5dbcef4bbe 100644
--- a/src/network/access/qnetworkaccessbackend.cpp
+++ b/src/network/access/qnetworkaccessbackend.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qnetworkaccessbackend_p.h"
#include "qnetworkreplyimpl_p.h"
@@ -72,7 +36,7 @@ public:
static QBasicAtomicInt valid;
};
Q_GLOBAL_STATIC(QNetworkAccessBackendFactoryData, factoryData)
-QBasicAtomicInt QNetworkAccessBackendFactoryData::valid = Q_BASIC_ATOMIC_INITIALIZER(0);
+Q_CONSTINIT QBasicAtomicInt QNetworkAccessBackendFactoryData::valid = Q_BASIC_ATOMIC_INITIALIZER(0);
class QNetworkAccessBackendPrivate : public QObjectPrivate
{
@@ -80,7 +44,7 @@ public:
QNetworkAccessBackend::TargetTypes m_targetTypes;
QNetworkAccessBackend::SecurityFeatures m_securityFeatures;
QNetworkAccessBackend::IOFeatures m_ioFeatures;
- QSharedPointer<QNonContiguousByteDevice> uploadByteDevice;
+ std::shared_ptr<QNonContiguousByteDevice> uploadByteDevice;
QIODevice *wrappedUploadByteDevice;
QNetworkReplyImplPrivate *m_reply = nullptr;
QNetworkAccessManagerPrivate *m_manager = nullptr;
@@ -126,6 +90,76 @@ QStringList QNetworkAccessManagerPrivate::backendSupportedSchemes() const
}
/*!
+ \class QNetworkAccessBackendFactory
+ \brief QNetworkAccessBackendFactory is the base class to inherit
+ from for Qt to instantiate and query your QNetworkAccessBackend
+ plugin.
+ \since 6.0
+ \internal
+
+//! [semi-private-notice]
+ The class is considered semi-private and as such requires linking
+ to "NetworkPrivate" to access the header. Furthermore it means
+ the class is not under the same binary compatibility restrictions
+ as the rest of Qt. While we still try to avoid breakage it may
+ still occur. The class is primarily meant to be used by plugins
+ which would be recompiled every time Qt is updated.
+//! [semi-private-notice]
+
+ This class acts as the primary interface to the plugin and must
+ be derived from. It deals with both querying supported schemes
+ and the creation of QNetworkAccessBackend
+
+ Since they are both abstract function you are required to
+ implement supportedSchemes() and create().
+*/
+
+/*!
+ \fn QStringList QNetworkAccessBackendFactory::supportedSchemes() const
+
+ Override this method in your own derived class to let Qt know
+ what schemes your class can handle.
+*/
+
+/*!
+ \fn QNetworkAccessBackendFactory::create(QNetworkAccessManager::Operation op, const QNetworkRequest &request) const
+
+ Override this method in your own class and return a
+ heap-allocated instance of your class derived from
+ QNetworkAccessBackend.
+
+ If \a op or a property of \a request is not supported (for
+ example the URL's scheme) then you must return \nullptr.
+
+ \sa QNetworkRequest::attribute(), QNetworkRequest::url(), QUrl::scheme()
+*/
+
+/*!
+ \class QNetworkAccessBackend
+ \brief QNetworkAccessBackend is the base class for implementing
+ support for schemes used by QNetworkAccessManager.
+ \since 6.0
+ \internal
+
+ \include access/qnetworkaccessbackend.cpp semi-private-notice
+
+ This class can be derived from to add support for further schemes
+ in QNetworkAccessManager.
+
+ The design of QNetworkAccessBackend makes it possible to specialize
+ behavior as needed for certain backends.
+ This was done using the (currently) 3 enums TargetType,
+ SecurityFeatures and IOFeatures. For example while only open()
+ and close() are abstract functions you are also required to
+ implement either read() or readPointer() and advanceReadPointer()
+ depending on whether you enable IOFeature::ZeroCopy or not.
+ Read more about it in the documentation for each of the
+ enumerators.
+
+ \sa TargetType, SecurityFeatures, IOFeatures
+*/
+
+/*!
\enum QNetworkAccessBackend::TargetType
Use the values in this enum to specify what type of target
@@ -276,6 +310,47 @@ bool QNetworkAccessBackend::start()
return true;
}
+/*!
+ \fn void QNetworkAccessBackend::open() = 0
+
+ You must implement this in your derived class.
+ During this call you must open the connection and begin the request
+ (see: request()).
+
+ As the connection progresses you must call the various public and
+ protected slots on QNetworkAccessBackend. As an example, when you have
+ received some data you must call readyRead(). And when all the data has been
+ received you must call finished(). This could, for example, be done by
+ binding signals inside your own implementation to the slots, or by calling
+ them directly.
+
+ \sa close()
+*/
+
+/*!
+ \fn void QNetworkAccessBackend::close() = 0
+
+ You must implement this function in your derived class.
+ This function gets called when the QNetworkReply is closed or aborted.
+
+ You should not emit an error or call finished() during this call since
+ QtNetwork will set and emit the \c{QNetworkReply::OperationCanceledError}
+ error by itself after control flow returns from this function.
+*/
+
+/*!
+ \fn qint64 QNetworkAccessBackend::bytesAvailable() const = 0
+
+ You must implement this function in your derived class.
+ This function is called at various times. It may be called because the user
+ called QNetworkReply::bytesAvailable(), and it may be called before an
+ attempt to read is made.
+
+ While this function doesn't technically need to return an accurate number,
+ it may result in reduced performance if it does not. This function must
+ return zero if there are no bytes available.
+*/
+
#if QT_CONFIG(ssl)
/*!
Passes a \a configuration with the user's desired TLS
@@ -566,7 +641,7 @@ QIODevice *QNetworkAccessBackend::createUploadByteDevice()
// We want signal emissions only for normal asynchronous uploads
if (!isSynchronous()) {
- connect(d->uploadByteDevice.data(), &QNonContiguousByteDevice::readProgress, this,
+ connect(d->uploadByteDevice.get(), &QNonContiguousByteDevice::readProgress, this,
[this](qint64 a, qint64 b) {
Q_D(QNetworkAccessBackend);
if (!d->m_reply->isFinished)
@@ -574,7 +649,7 @@ QIODevice *QNetworkAccessBackend::createUploadByteDevice()
});
}
- d->wrappedUploadByteDevice = QNonContiguousByteDeviceFactory::wrap(d->uploadByteDevice.data());
+ d->wrappedUploadByteDevice = QNonContiguousByteDeviceFactory::wrap(d->uploadByteDevice.get());
return d->wrappedUploadByteDevice;
}
@@ -738,6 +813,12 @@ QNetworkAccessBackendFactory::QNetworkAccessBackendFactory()
/*!
Destructs QNetworkAccessBackendFactory
*/
-QNetworkAccessBackendFactory::~QNetworkAccessBackendFactory() = default;
+QNetworkAccessBackendFactory::~QNetworkAccessBackendFactory()
+{
+ if (factoryData.exists())
+ factoryData->removeAll(this);
+};
QT_END_NAMESPACE
+
+#include "moc_qnetworkaccessbackend_p.cpp"
diff --git a/src/network/access/qnetworkaccessbackend_p.h b/src/network/access/qnetworkaccessbackend_p.h
index d2742c180c..799ae3faad 100644
--- a/src/network/access/qnetworkaccessbackend_p.h
+++ b/src/network/access/qnetworkaccessbackend_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNETWORKACCESSBACKEND_P_H
#define QNETWORKACCESSBACKEND_P_H
@@ -60,6 +24,7 @@
#include <QtCore/qobject.h>
#include <QtCore/qflags.h>
#include <QtCore/qbytearrayview.h>
+#include <QtCore/private/qglobal_p.h>
#if QT_CONFIG(ssl)
#include <QtNetwork/qsslconfiguration.h>
diff --git a/src/network/access/qnetworkaccesscache.cpp b/src/network/access/qnetworkaccesscache.cpp
index 4d65761a0b..2bc0e8fb70 100644
--- a/src/network/access/qnetworkaccesscache.cpp
+++ b/src/network/access/qnetworkaccesscache.cpp
@@ -1,51 +1,17 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qnetworkaccesscache_p.h"
#include "QtCore/qpointer.h"
-#include "QtCore/qdatetime.h"
+#include "QtCore/qdeadlinetimer.h"
#include "qnetworkaccessmanager_p.h"
#include "qnetworkreply_p.h"
#include "qnetworkrequest.h"
#include <vector>
+//#define DEBUG_ACCESSCACHE
+
QT_BEGIN_NAMESPACE
enum ExpiryTimeEnum {
@@ -63,18 +29,14 @@ namespace {
// idea copied from qcache.h
struct QNetworkAccessCache::Node
{
- QDateTime timestamp;
- std::vector<Receiver> receiverQueue;
+ QDeadlineTimer timer;
QByteArray key;
- Node *older, *newer;
- CacheableObject *object;
-
- int useCount;
+ Node *previous = nullptr; // "previous" nodes expire "previous"ly (before us)
+ Node *next = nullptr; // "next" nodes expire "next" (after us)
+ CacheableObject *object = nullptr;
- Node()
- : older(nullptr), newer(nullptr), object(nullptr), useCount(0)
- { }
+ int useCount = 0;
};
QNetworkAccessCache::CacheableObject::CacheableObject()
@@ -102,11 +64,6 @@ void QNetworkAccessCache::CacheableObject::setShareable(bool enable)
shareable = enable;
}
-QNetworkAccessCache::QNetworkAccessCache()
- : oldest(nullptr), newest(nullptr)
-{
-}
-
QNetworkAccessCache::~QNetworkAccessCache()
{
clear();
@@ -131,7 +88,7 @@ void QNetworkAccessCache::clear()
timer.stop();
- oldest = newest = nullptr;
+ firstExpiringNode = lastExpiringNode = nullptr;
}
/*!
@@ -144,27 +101,60 @@ void QNetworkAccessCache::linkEntry(const QByteArray &key)
if (!node)
return;
- Q_ASSERT(node != oldest && node != newest);
- Q_ASSERT(node->older == nullptr && node->newer == nullptr);
+ Q_ASSERT(node != firstExpiringNode && node != lastExpiringNode);
+ Q_ASSERT(node->previous == nullptr && node->next == nullptr);
Q_ASSERT(node->useCount == 0);
- if (newest) {
- Q_ASSERT(newest->newer == nullptr);
- newest->newer = node;
- node->older = newest;
- }
- if (!oldest) {
- // there are no entries, so this is the oldest one too
- oldest = node;
+
+ node->timer.setPreciseRemainingTime(node->object->expiryTimeoutSeconds);
+#ifdef DEBUG_ACCESSCACHE
+ qDebug() << "QNetworkAccessCache case trying to insert=" << QString::fromUtf8(key)
+ << node->timer.remainingTime() << "milliseconds";
+ Node *current = lastExpiringNode;
+ while (current) {
+ qDebug() << "QNetworkAccessCache item=" << QString::fromUtf8(current->key)
+ << current->timer.remainingTime() << "milliseconds"
+ << (current == lastExpiringNode ? "[last to expire]" : "")
+ << (current == firstExpiringNode ? "[first to expire]" : "");
+ current = current->previous;
}
+#endif
- node->timestamp = QDateTime::currentDateTimeUtc().addSecs(ExpiryTime);
- newest = node;
+ if (lastExpiringNode) {
+ Q_ASSERT(lastExpiringNode->next == nullptr);
+ if (lastExpiringNode->timer < node->timer) {
+ // Insert as new last-to-expire node.
+ node->previous = lastExpiringNode;
+ lastExpiringNode->next = node;
+ lastExpiringNode = node;
+ } else {
+ // Insert in a sorted way, as different nodes might have had different expiryTimeoutSeconds set.
+ Node *current = lastExpiringNode;
+ while (current->previous != nullptr && current->previous->timer >= node->timer)
+ current = current->previous;
+ node->previous = current->previous;
+ if (node->previous)
+ node->previous->next = node;
+ node->next = current;
+ current->previous = node;
+ if (node->previous == nullptr)
+ firstExpiringNode = node;
+ }
+ } else {
+ // no current last-to-expire node
+ lastExpiringNode = node;
+ }
+ if (!firstExpiringNode) {
+ // there are no entries, so this is the next-to-expire too
+ firstExpiringNode = node;
+ }
+ Q_ASSERT(firstExpiringNode->previous == nullptr);
+ Q_ASSERT(lastExpiringNode->next == nullptr);
}
/*!
Removes the entry pointed by \a key from the linked list.
- Returns \c true if the entry removed was the oldest one.
+ Returns \c true if the entry removed was the next to expire.
*/
bool QNetworkAccessCache::unlinkEntry(const QByteArray &key)
{
@@ -172,38 +162,39 @@ bool QNetworkAccessCache::unlinkEntry(const QByteArray &key)
if (!node)
return false;
- bool wasOldest = false;
- if (node == oldest) {
- oldest = node->newer;
- wasOldest = true;
+ bool wasFirst = false;
+ if (node == firstExpiringNode) {
+ firstExpiringNode = node->next;
+ wasFirst = true;
}
- if (node == newest)
- newest = node->older;
- if (node->older)
- node->older->newer = node->newer;
- if (node->newer)
- node->newer->older = node->older;
-
- node->newer = node->older = nullptr;
- return wasOldest;
+ if (node == lastExpiringNode)
+ lastExpiringNode = node->previous;
+ if (node->previous)
+ node->previous->next = node->next;
+ if (node->next)
+ node->next->previous = node->previous;
+
+ node->next = node->previous = nullptr;
+ return wasFirst;
}
void QNetworkAccessCache::updateTimer()
{
timer.stop();
- if (!oldest)
+ if (!firstExpiringNode)
return;
- int interval = QDateTime::currentDateTimeUtc().secsTo(oldest->timestamp);
+ qint64 interval = firstExpiringNode->timer.remainingTime();
if (interval <= 0) {
interval = 0;
- } else {
- // round up the interval
- interval = (interval + 15) & ~16;
}
- timer.start(interval * 1000, this);
+ // Plus 10 msec so we don't spam timer events if date comparisons are too fuzzy.
+ // This code used to do (broken) rounding, but for ConnectionCacheExpiryTimeoutSecondsAttribute
+ // to work we cannot do this.
+ // See discussion in https://codereview.qt-project.org/c/qt/qtbase/+/337464
+ timer.start(interval + 10, this);
}
bool QNetworkAccessCache::emitEntryReady(Node *node, QObject *target, const char *member)
@@ -220,28 +211,24 @@ bool QNetworkAccessCache::emitEntryReady(Node *node, QObject *target, const char
void QNetworkAccessCache::timerEvent(QTimerEvent *)
{
- // expire old items
- const QDateTime now = QDateTime::currentDateTimeUtc();
-
- while (oldest && oldest->timestamp < now) {
- Node *next = oldest->newer;
- oldest->object->dispose();
-
- hash.remove(oldest->key); // oldest gets deleted
- delete oldest;
- oldest = next;
+ while (firstExpiringNode && firstExpiringNode->timer.hasExpired()) {
+ Node *next = firstExpiringNode->next;
+ firstExpiringNode->object->dispose();
+ hash.remove(firstExpiringNode->key); // `firstExpiringNode` gets deleted
+ delete firstExpiringNode;
+ firstExpiringNode = next;
}
// fixup the list
- if (oldest)
- oldest->older = nullptr;
+ if (firstExpiringNode)
+ firstExpiringNode->previous = nullptr;
else
- newest = nullptr;
+ lastExpiringNode = nullptr;
updateTimer();
}
-void QNetworkAccessCache::addEntry(const QByteArray &key, CacheableObject *entry)
+void QNetworkAccessCache::addEntry(const QByteArray &key, CacheableObject *entry, qint64 connectionCacheExpiryTimeoutSeconds)
{
Q_ASSERT(!key.isEmpty());
@@ -260,8 +247,15 @@ void QNetworkAccessCache::addEntry(const QByteArray &key, CacheableObject *entry
node->object->dispose();
node->object = entry;
node->object->key = key;
+ if (connectionCacheExpiryTimeoutSeconds > -1) {
+ node->object->expiryTimeoutSeconds = connectionCacheExpiryTimeoutSeconds; // via ConnectionCacheExpiryTimeoutSecondsAttribute
+ } else {
+ node->object->expiryTimeoutSeconds = ExpiryTime;
+ }
node->key = key;
node->useCount = 1;
+
+ // It gets only put into the expiry list in linkEntry (from releaseEntry), when it is not used anymore.
}
bool QNetworkAccessCache::hasEntry(const QByteArray &key) const
@@ -269,30 +263,6 @@ bool QNetworkAccessCache::hasEntry(const QByteArray &key) const
return hash.contains(key);
}
-bool QNetworkAccessCache::requestEntry(const QByteArray &key, QObject *target, const char *member)
-{
- Node *node = hash.value(key);
- if (!node)
- return false;
-
- if (node->useCount > 0 && !node->object->shareable) {
- // object is not shareable and is in use
- // queue for later use
- Q_ASSERT(node->older == nullptr && node->newer == nullptr);
- node->receiverQueue.push_back({target, member});
-
- // request queued
- return true;
- } else {
- // node not in use or is shareable
- if (unlinkEntry(key))
- updateTimer();
-
- ++node->useCount;
- return emitEntryReady(node, target, member);
- }
-}
-
QNetworkAccessCache::CacheableObject *QNetworkAccessCache::requestEntryNow(const QByteArray &key)
{
Node *node = hash.value(key);
@@ -310,10 +280,10 @@ QNetworkAccessCache::CacheableObject *QNetworkAccessCache::requestEntryNow(const
}
// entry not in use, let the caller have it
- bool wasOldest = unlinkEntry(key);
+ bool wasNext = unlinkEntry(key);
++node->useCount;
- if (wasOldest)
+ if (wasNext)
updateTimer();
return node->object;
}
@@ -328,28 +298,12 @@ void QNetworkAccessCache::releaseEntry(const QByteArray &key)
Q_ASSERT(node->useCount > 0);
- // are there other objects waiting?
- const auto objectStillExists = [](const Receiver &r) { return !r.object.isNull(); };
-
- auto &queue = node->receiverQueue;
- auto qit = std::find_if(queue.begin(), queue.end(), objectStillExists);
-
- const Receiver receiver = qit == queue.end() ? Receiver{} : std::move(*qit++) ;
-
- queue.erase(queue.begin(), qit);
-
- if (receiver.object) {
- // queue another activation
- emitEntryReady(node, receiver.object, receiver.member);
- return;
- }
-
if (!--node->useCount) {
// no objects waiting; add it back to the expiry list
if (node->object->expires)
linkEntry(key);
- if (oldest == node)
+ if (firstExpiringNode == node)
updateTimer();
}
}
@@ -374,3 +328,5 @@ void QNetworkAccessCache::removeEntry(const QByteArray &key)
}
QT_END_NAMESPACE
+
+#include "moc_qnetworkaccesscache_p.cpp"
diff --git a/src/network/access/qnetworkaccesscache_p.h b/src/network/access/qnetworkaccesscache_p.h
index 9f7001d044..3be7967ca1 100644
--- a/src/network/access/qnetworkaccesscache_p.h
+++ b/src/network/access/qnetworkaccesscache_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNETWORKACCESSCACHE_P_H
#define QNETWORKACCESSCACHE_P_H
@@ -79,6 +43,7 @@ public:
QByteArray key;
bool expires;
bool shareable;
+ qint64 expiryTimeoutSeconds;
public:
CacheableObject();
virtual ~CacheableObject();
@@ -90,14 +55,12 @@ public:
void setShareable(bool enable);
};
- QNetworkAccessCache();
~QNetworkAccessCache();
void clear();
- void addEntry(const QByteArray &key, CacheableObject *entry);
+ void addEntry(const QByteArray &key, CacheableObject *entry, qint64 connectionCacheExpiryTimeoutSeconds = -1);
bool hasEntry(const QByteArray &key) const;
- bool requestEntry(const QByteArray &key, QObject *target, const char *member);
CacheableObject *requestEntryNow(const QByteArray &key);
void releaseEntry(const QByteArray &key);
void removeEntry(const QByteArray &key);
@@ -111,8 +74,8 @@ protected:
private:
// idea copied from qcache.h
NodeHash hash;
- Node *oldest;
- Node *newest;
+ Node *firstExpiringNode = nullptr;
+ Node *lastExpiringNode = nullptr;
QBasicTimer timer;
@@ -124,6 +87,4 @@ private:
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QNetworkAccessCache::CacheableObject*)
-
#endif
diff --git a/src/network/access/qnetworkaccesscachebackend.cpp b/src/network/access/qnetworkaccesscachebackend.cpp
index 9ed951751a..fd8174c143 100644
--- a/src/network/access/qnetworkaccesscachebackend.cpp
+++ b/src/network/access/qnetworkaccesscachebackend.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//#define QNETWORKACCESSCACHEBACKEND_DEBUG
@@ -44,9 +8,12 @@
#include "qfileinfo.h"
#include "qdir.h"
#include "qcoreapplication.h"
+#include "qhash.h"
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
QNetworkAccessCacheBackend::QNetworkAccessCacheBackend()
: QNetworkAccessBackend(QNetworkAccessBackend::TargetType::Local)
{
@@ -86,10 +53,10 @@ bool QNetworkAccessCacheBackend::sendCacheContents()
// set the raw headers
const QNetworkCacheMetaData::RawHeaderList rawHeaders = item.rawHeaders();
for (const auto &header : rawHeaders) {
- if (header.first.toLower() == "cache-control") {
- const QByteArray cacheControlValue = header.second.toLower();
- if (cacheControlValue.contains("must-revalidate")
- || cacheControlValue.contains("no-cache")) {
+ if (header.first.compare("cache-control", Qt::CaseInsensitive) == 0) {
+ const QLatin1StringView cacheControlValue(header.second);
+ if (cacheControlValue.contains("must-revalidate"_L1, Qt::CaseInsensitive)
+ || cacheControlValue.contains("no-cache"_L1, Qt::CaseInsensitive)) {
return false;
}
}
diff --git a/src/network/access/qnetworkaccesscachebackend_p.h b/src/network/access/qnetworkaccesscachebackend_p.h
index fc26dda454..80ec1535de 100644
--- a/src/network/access/qnetworkaccesscachebackend_p.h
+++ b/src/network/access/qnetworkaccesscachebackend_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNETWORKACCESSCACHEBACKEND_P_H
#define QNETWORKACCESSCACHEBACKEND_P_H
diff --git a/src/network/access/qnetworkaccessdebugpipebackend.cpp b/src/network/access/qnetworkaccessdebugpipebackend.cpp
index 51c13b7241..4b12f9fe31 100644
--- a/src/network/access/qnetworkaccessdebugpipebackend.cpp
+++ b/src/network/access/qnetworkaccessdebugpipebackend.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qnetworkaccessdebugpipebackend_p.h"
#include "QtCore/qdatastream.h"
@@ -46,6 +10,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
#ifdef QT_BUILD_INTERNAL
enum {
@@ -74,7 +40,7 @@ QNetworkAccessDebugPipeBackendFactory::create(QNetworkAccessManager::Operation o
}
QUrl url = request.url();
- if (url.scheme() == QLatin1String("debugpipe"))
+ if (url.scheme() == "debugpipe"_L1)
return new QNetworkAccessDebugPipeBackend;
return nullptr;
}
@@ -109,7 +75,7 @@ void QNetworkAccessDebugPipeBackend::open()
// socket bytes written -> we can push more from upstream to socket
connect(&socket, SIGNAL(bytesWritten(qint64)), SLOT(socketBytesWritten(qint64)));
- bareProtocol = QUrlQuery(url()).queryItemValue(QLatin1String("bare")) == QLatin1String("1");
+ bareProtocol = QUrlQuery(url()).queryItemValue("bare"_L1) == "1"_L1;
if (operation() == QNetworkAccessManager::PutOperation) {
createUploadByteDevice();
@@ -218,7 +184,7 @@ void QNetworkAccessDebugPipeBackend::possiblyFinish()
void QNetworkAccessDebugPipeBackend::close()
{
- qWarning("QNetworkAccessDebugPipeBackend::closeDownstreamChannel() %d",operation());;
+ qWarning("QNetworkAccessDebugPipeBackend::closeDownstreamChannel() %d",operation());
//if (operation() == QNetworkAccessManager::GetOperation)
// socket.disconnectFromHost();
}
@@ -270,3 +236,5 @@ void QNetworkAccessDebugPipeBackend::socketConnected()
#endif
QT_END_NAMESPACE
+
+#include "moc_qnetworkaccessdebugpipebackend_p.cpp"
diff --git a/src/network/access/qnetworkaccessdebugpipebackend_p.h b/src/network/access/qnetworkaccessdebugpipebackend_p.h
index 50ef5cea7d..b3e9e1d40b 100644
--- a/src/network/access/qnetworkaccessdebugpipebackend_p.h
+++ b/src/network/access/qnetworkaccessdebugpipebackend_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNETWORKACCESSDEBUGPIPEBACKEND_P_H
#define QNETWORKACCESSDEBUGPIPEBACKEND_P_H
diff --git a/src/network/access/qnetworkaccessfilebackend.cpp b/src/network/access/qnetworkaccessfilebackend.cpp
index c5f1826203..2100c188a5 100644
--- a/src/network/access/qnetworkaccessfilebackend.cpp
+++ b/src/network/access/qnetworkaccessfilebackend.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qnetworkaccessfilebackend_p.h"
#include "qfileinfo.h"
@@ -47,6 +11,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
QStringList QNetworkAccessFileBackendFactory::supportedSchemes() const
{
QStringList schemes;
@@ -74,13 +40,13 @@ QNetworkAccessFileBackendFactory::create(QNetworkAccessManager::Operation op,
}
QUrl url = request.url();
- if (url.scheme().compare(QLatin1String("qrc"), Qt::CaseInsensitive) == 0
+ if (url.scheme().compare("qrc"_L1, Qt::CaseInsensitive) == 0
#if defined(Q_OS_ANDROID)
- || url.scheme().compare(QLatin1String("assets"), Qt::CaseInsensitive) == 0
+ || url.scheme().compare("assets"_L1, Qt::CaseInsensitive) == 0
#endif
|| url.isLocalFile()) {
return new QNetworkAccessFileBackend;
- } else if (!url.scheme().isEmpty() && url.authority().isEmpty() && (url.scheme().length() > 1)) {
+ } else if (!url.scheme().isEmpty() && url.authority().isEmpty() && (url.scheme().size() > 1)) {
// check if QFile could, in theory, open this URL via the file engines
// it has to be in the format:
// prefix:path/to/file
@@ -112,7 +78,7 @@ void QNetworkAccessFileBackend::open()
{
QUrl url = this->url();
- if (url.host() == QLatin1String("localhost"))
+ if (url.host() == "localhost"_L1)
url.setHost(QString());
#if !defined(Q_OS_WIN)
// do not allow UNC paths on Unix
@@ -125,17 +91,17 @@ void QNetworkAccessFileBackend::open()
}
#endif // !defined(Q_OS_WIN)
if (url.path().isEmpty())
- url.setPath(QLatin1String("/"));
+ url.setPath("/"_L1);
setUrl(url);
QString fileName = url.toLocalFile();
if (fileName.isEmpty()) {
- if (url.scheme() == QLatin1String("qrc")) {
- fileName = QLatin1Char(':') + url.path();
+ if (url.scheme() == "qrc"_L1) {
+ fileName = u':' + url.path();
} else {
#if defined(Q_OS_ANDROID)
- if (url.scheme() == QLatin1String("assets"))
- fileName = QLatin1String("assets:") + url.path();
+ if (url.scheme() == "assets"_L1)
+ fileName = "assets:"_L1 + url.path();
else
#endif
fileName = url.toString(QUrl::RemoveAuthority | QUrl::RemoveFragment | QUrl::RemoveQuery);
@@ -286,3 +252,5 @@ qint64 QNetworkAccessFileBackend::read(char *data, qint64 maxlen)
}
QT_END_NAMESPACE
+
+#include "moc_qnetworkaccessfilebackend_p.cpp"
diff --git a/src/network/access/qnetworkaccessfilebackend_p.h b/src/network/access/qnetworkaccessfilebackend_p.h
index 716869e50d..2c3a106f2a 100644
--- a/src/network/access/qnetworkaccessfilebackend_p.h
+++ b/src/network/access/qnetworkaccessfilebackend_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNETWORKACCESSFILEBACKEND_P_H
#define QNETWORKACCESSFILEBACKEND_P_H
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp
index bb90e89305..4e13c9924b 100644
--- a/src/network/access/qnetworkaccessmanager.cpp
+++ b/src/network/access/qnetworkaccessmanager.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtNetwork/private/qtnetworkglobal_p.h>
@@ -68,9 +32,9 @@
#include "QtCore/qurl.h"
#include "QtNetwork/private/qauthenticator_p.h"
#include "QtNetwork/qsslconfiguration.h"
-#include "QtNetwork/private/http2protocol_p.h"
#if QT_CONFIG(http)
+#include "QtNetwork/private/http2protocol_p.h"
#include "qhttpmultipart.h"
#include "qhttpmultipart_p.h"
#include "qnetworkreplyhttpimpl_p.h"
@@ -80,12 +44,16 @@
#include <QHostInfo>
+#include "QtCore/qapplicationstatic.h"
+#include "QtCore/qloggingcategory.h"
#include <QtCore/private/qfactoryloader_p.h>
#if defined(Q_OS_MACOS)
+#include <QtCore/private/qcore_mac_p.h>
+
#include <CoreServices/CoreServices.h>
#include <SystemConfiguration/SystemConfiguration.h>
-#include <Security/SecKeychain.h>
+#include <Security/Security.h>
#endif
#ifdef Q_OS_WASM
#include "qnetworkreplywasmimpl_p.h"
@@ -95,75 +63,98 @@
#include "qnetconmonitor_p.h"
+#include <mutex>
+
QT_BEGIN_NAMESPACE
-Q_GLOBAL_STATIC(QNetworkAccessFileBackendFactory, fileBackend)
+using namespace Qt::StringLiterals;
+using namespace std::chrono_literals;
+
+Q_LOGGING_CATEGORY(lcQnam, "qt.network.access.manager")
+
+Q_APPLICATION_STATIC(QNetworkAccessFileBackendFactory, fileBackend)
-#ifdef QT_BUILD_INTERNAL
+#if QT_CONFIG(private_tests)
Q_GLOBAL_STATIC(QNetworkAccessDebugPipeBackendFactory, debugpipeBackend)
#endif
-Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
- (QNetworkAccessBackendFactory_iid,
- QLatin1String("/networkaccessbackends")))
+Q_APPLICATION_STATIC(QFactoryLoader, qnabfLoader, QNetworkAccessBackendFactory_iid, "/networkaccess"_L1)
+
#if defined(Q_OS_MACOS)
bool getProxyAuth(const QString& proxyHostname, const QString &scheme, QString& username, QString& password)
{
- OSStatus err;
- SecKeychainItemRef itemRef;
- bool retValue = false;
- SecProtocolType protocolType = kSecProtocolTypeAny;
- if (scheme.compare(QLatin1String("ftp"),Qt::CaseInsensitive)==0) {
- protocolType = kSecProtocolTypeFTPProxy;
- } else if (scheme.compare(QLatin1String("http"),Qt::CaseInsensitive)==0
- || scheme.compare(QLatin1String("preconnect-http"),Qt::CaseInsensitive)==0) {
- protocolType = kSecProtocolTypeHTTPProxy;
- } else if (scheme.compare(QLatin1String("https"),Qt::CaseInsensitive)==0
- || scheme.compare(QLatin1String("preconnect-https"),Qt::CaseInsensitive)==0) {
- protocolType = kSecProtocolTypeHTTPSProxy;
+ CFStringRef protocolType = nullptr;
+ if (scheme.compare("ftp"_L1, Qt::CaseInsensitive) == 0) {
+ protocolType = kSecAttrProtocolFTPProxy;
+ } else if (scheme.compare("http"_L1, Qt::CaseInsensitive) == 0
+ || scheme.compare("preconnect-http"_L1, Qt::CaseInsensitive) == 0) {
+ protocolType = kSecAttrProtocolHTTPProxy;
+ } else if (scheme.compare("https"_L1,Qt::CaseInsensitive)==0
+ || scheme.compare("preconnect-https"_L1, Qt::CaseInsensitive) == 0) {
+ protocolType = kSecAttrProtocolHTTPSProxy;
+ } else {
+ qCWarning(lcQnam) << "Cannot query user name and password for a proxy, unnknown protocol:"
+ << scheme;
+ return false;
}
- QByteArray proxyHostnameUtf8(proxyHostname.toUtf8());
- err = SecKeychainFindInternetPassword(NULL,
- proxyHostnameUtf8.length(), proxyHostnameUtf8.constData(),
- 0,NULL,
- 0, NULL,
- 0, NULL,
- 0,
- protocolType,
- kSecAuthenticationTypeAny,
- 0, NULL,
- &itemRef);
- if (err == noErr) {
-
- SecKeychainAttribute attr;
- SecKeychainAttributeList attrList;
- UInt32 length;
- void *outData;
-
- attr.tag = kSecAccountItemAttr;
- attr.length = 0;
- attr.data = NULL;
-
- attrList.count = 1;
- attrList.attr = &attr;
-
- if (SecKeychainItemCopyContent(itemRef, NULL, &attrList, &length, &outData) == noErr) {
- username = QString::fromUtf8((const char*)attr.data, attr.length);
- password = QString::fromUtf8((const char*)outData, length);
- SecKeychainItemFreeContent(&attrList,outData);
- retValue = true;
- }
- CFRelease(itemRef);
+
+ QCFType<CFMutableDictionaryRef> query(CFDictionaryCreateMutable(kCFAllocatorDefault,
+ 0, nullptr, nullptr));
+ Q_ASSERT(query);
+
+ CFDictionaryAddValue(query, kSecClass, kSecClassInternetPassword);
+ CFDictionaryAddValue(query, kSecAttrProtocol, protocolType);
+
+ QCFType<CFStringRef> serverName; // Note the scope.
+ if (proxyHostname.size()) {
+ serverName = proxyHostname.toCFString();
+ CFDictionaryAddValue(query, kSecAttrServer, serverName);
+ }
+
+ // This is to get the user name in the result:
+ CFDictionaryAddValue(query, kSecReturnAttributes, kCFBooleanTrue);
+ // This one to get the password:
+ CFDictionaryAddValue(query, kSecReturnData, kCFBooleanTrue);
+
+ // The default for kSecMatchLimit key is 1 (the first match only), which is fine,
+ // so don't set this value explicitly.
+
+ QCFType<CFTypeRef> replyData;
+ if (SecItemCopyMatching(query, &replyData) != errSecSuccess) {
+ qCWarning(lcQnam, "Failed to extract user name and password from the keychain.");
+ return false;
+ }
+
+ if (!replyData || CFDictionaryGetTypeID() != CFGetTypeID(replyData)) {
+ qCWarning(lcQnam, "Query returned data in unexpected format.");
+ return false;
+ }
+
+ CFDictionaryRef accountData = replyData.as<CFDictionaryRef>();
+ const void *value = CFDictionaryGetValue(accountData, kSecAttrAccount);
+ if (!value || CFGetTypeID(value) != CFStringGetTypeID()) {
+ qCWarning(lcQnam, "Cannot find user name or its format is unknown.");
+ return false;
+ }
+ username = QString::fromCFString(static_cast<CFStringRef>(value));
+
+ value = CFDictionaryGetValue(accountData, kSecValueData);
+ if (!value || CFGetTypeID(value) != CFDataGetTypeID()) {
+ qCWarning(lcQnam, "Cannot find password or its format is unknown.");
+ return false;
}
- return retValue;
+ const CFDataRef passData = static_cast<const CFDataRef>(value);
+ password = QString::fromLocal8Bit(reinterpret_cast<const char *>(CFDataGetBytePtr(passData)),
+ qsizetype(CFDataGetLength(passData)));
+ return true;
}
-#endif
+#endif // Q_OS_MACOS
static void ensureInitialized()
{
-#ifdef QT_BUILD_INTERNAL
+#if QT_CONFIG(private_tests)
(void) debugpipeBackend();
#endif
@@ -253,7 +244,7 @@ static void ensureInitialized()
\fn void QNetworkAccessManager::networkSessionConnected()
\since 4.7
- \obsolete
+ \deprecated
\internal
@@ -683,7 +674,7 @@ bool QNetworkAccessManager::isStrictTransportSecurityEnabled() const
store is enabled, these policies will be preserved in the store. In case both
cache and store contain the same known hosts, policies from cache are considered
to be more up-to-date (and thus will overwrite the previous values in the store).
- If this behavior is undesired, enable HSTS store before enabling Strict Tranport
+ If this behavior is undesired, enable HSTS store before enabling Strict Transport
Security. By default, the persistent store of HSTS policies is disabled.
\sa isStrictTransportSecurityStoreEnabled(), setStrictTransportSecurityEnabled(),
@@ -790,6 +781,46 @@ QNetworkReply *QNetworkAccessManager::get(const QNetworkRequest &request)
}
/*!
+ \since 6.7
+
+ \overload
+
+ \note A GET request with a message body is not cached.
+
+ \note If the request is redirected, the message body will be kept only if the status code is
+ 307 or 308.
+*/
+
+QNetworkReply *QNetworkAccessManager::get(const QNetworkRequest &request, QIODevice *data)
+{
+ QNetworkRequest newRequest(request);
+ return d_func()->postProcess(
+ createRequest(QNetworkAccessManager::GetOperation, newRequest, data));
+}
+
+/*!
+ \since 6.7
+
+ \overload
+
+ \note A GET request with a message body is not cached.
+
+ \note If the request is redirected, the message body will be kept only if the status code is
+ 307 or 308.
+*/
+
+QNetworkReply *QNetworkAccessManager::get(const QNetworkRequest &request, const QByteArray &data)
+{
+ QBuffer *buffer = new QBuffer;
+ buffer->setData(data);
+ buffer->open(QIODevice::ReadOnly);
+
+ QNetworkReply *reply = get(request, buffer);
+ buffer->setParent(reply);
+ return reply;
+}
+
+/*!
Sends an HTTP POST request to the destination specified by \a request
and returns a new QNetworkReply object opened for reading that will
contain the reply sent by the server. The contents of the \a data
@@ -825,6 +856,24 @@ QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, const
return reply;
}
+/*!
+ \overload
+
+ \since 6.8
+
+ Sends the POST request specified by \a request without a body and returns
+ a new QNetworkReply object.
+*/
+QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, std::nullptr_t nptr)
+{
+ Q_UNUSED(nptr);
+ QIODevice *dev = nullptr;
+
+ return d_func()->postProcess(createRequest(QNetworkAccessManager::PostOperation,
+ request,
+ dev));
+}
+
#if QT_CONFIG(http) || defined(Q_OS_WASM)
/*!
\since 4.8
@@ -909,6 +958,23 @@ QNetworkReply *QNetworkAccessManager::put(const QNetworkRequest &request, const
}
/*!
+ \overload
+
+ \since 6.8
+
+ Sends the PUT request specified by \a request without a body and returns
+ a new QNetworkReply object.
+*/
+
+QNetworkReply *QNetworkAccessManager::put(const QNetworkRequest &request, std::nullptr_t nptr)
+{
+ Q_UNUSED(nptr);
+ QIODevice *dev = nullptr;
+
+ return d_func()->postProcess(createRequest(QNetworkAccessManager::PutOperation, request, dev));
+}
+
+/*!
\since 4.6
Sends a request to delete the resource identified by the URL of \a request.
@@ -975,7 +1041,7 @@ void QNetworkAccessManager::connectToHostEncrypted(const QString &hostName, quin
QUrl url;
url.setHost(hostName);
url.setPort(port);
- url.setScheme(QLatin1String("preconnect-https"));
+ url.setScheme("preconnect-https"_L1);
QNetworkRequest request(url);
if (sslConfiguration != QSslConfiguration::defaultConfiguration())
request.setSslConfiguration(sslConfiguration);
@@ -1006,7 +1072,7 @@ void QNetworkAccessManager::connectToHost(const QString &hostName, quint16 port)
QUrl url;
url.setHost(hostName);
url.setPort(port);
- url.setScheme(QLatin1String("preconnect-http"));
+ url.setScheme("preconnect-http"_L1);
QNetworkRequest request(url);
get(request);
}
@@ -1142,8 +1208,8 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
}
#if QT_CONFIG(http) || defined (Q_OS_WASM)
- if (!req.transferTimeout())
- req.setTransferTimeout(transferTimeout());
+ if (req.transferTimeoutAsDuration() == 0ms)
+ req.setTransferTimeout(transferTimeoutAsDuration());
#endif
if (autoDeleteReplies()
@@ -1154,7 +1220,6 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
bool isLocalFile = req.url().isLocalFile();
QString scheme = req.url().scheme();
-#ifndef Q_OS_WASM
// fast path for GET on file:// URLs
// The QNetworkAccessFileBackend will right now only be used for PUT
@@ -1162,13 +1227,13 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
|| op == QNetworkAccessManager::HeadOperation) {
if (isLocalFile
#ifdef Q_OS_ANDROID
- || scheme == QLatin1String("assets")
+ || scheme == "assets"_L1
#endif
- || scheme == QLatin1String("qrc")) {
+ || scheme == "qrc"_L1) {
return new QNetworkReplyFileImpl(this, req, op);
}
- if (scheme == QLatin1String("data"))
+ if (scheme == "data"_L1)
return new QNetworkReplyDataImpl(this, req, op);
// A request with QNetworkRequest::AlwaysCache does not need any bearer management
@@ -1189,7 +1254,6 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
return reply;
}
}
-#endif
QNetworkRequest request = req;
#ifndef Q_OS_WASM // Content-length header is not allowed to be set by user in wasm
if (!request.header(QNetworkRequest::ContentLengthHeader).isValid() &&
@@ -1209,8 +1273,9 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
}
}
#ifdef Q_OS_WASM
+ Q_UNUSED(isLocalFile);
// Support http, https, and relative urls
- if (scheme == QLatin1String("http") || scheme == QLatin1String("https") || scheme.isEmpty()) {
+ if (scheme == "http"_L1 || scheme == "https"_L1 || scheme.isEmpty()) {
QNetworkReplyWasmImpl *reply = new QNetworkReplyWasmImpl(this);
QNetworkReplyWasmImplPrivate *priv = reply->d_func();
priv->manager = this;
@@ -1220,12 +1285,16 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
#endif
#if QT_CONFIG(http)
- // Since Qt 5 we use the new QNetworkReplyHttpImpl
- if (scheme == QLatin1String("http") || scheme == QLatin1String("preconnect-http")
+ constexpr char16_t httpSchemes[][17] = {
+ u"http",
+ u"preconnect-http",
#ifndef QT_NO_SSL
- || scheme == QLatin1String("https") || scheme == QLatin1String("preconnect-https")
+ u"https",
+ u"preconnect-https",
#endif
- ) {
+ };
+ // Since Qt 5 we use the new QNetworkReplyHttpImpl
+ if (std::find(std::begin(httpSchemes), std::end(httpSchemes), scheme) != std::end(httpSchemes)) {
#ifndef QT_NO_SSL
if (isStrictTransportSecurityEnabled() && d->stsCache.isKnownHost(request.url())) {
QUrl stsUrl(request.url());
@@ -1240,7 +1309,7 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
// MUST NOT add one.
if (stsUrl.port() == 80)
stsUrl.setPort(443);
- stsUrl.setScheme(QLatin1String("https"));
+ stsUrl.setScheme("https"_L1);
request.setUrl(stsUrl);
}
#endif
@@ -1297,7 +1366,7 @@ QStringList QNetworkAccessManager::supportedSchemes() const
/*!
\since 5.2
- \obsolete
+ \deprecated
Lists all the URL schemes supported by the access manager.
@@ -1391,38 +1460,59 @@ void QNetworkAccessManager::setAutoDeleteReplies(bool shouldAutoDelete)
}
/*!
+ \fn int QNetworkAccessManager::transferTimeout() const
\since 5.15
Returns the timeout used for transfers, in milliseconds.
- This timeout is zero if setTransferTimeout() hasn't been
- called, which means that the timeout is not used.
+ \sa setTransferTimeout()
*/
-int QNetworkAccessManager::transferTimeout() const
+
+/*!
+ \fn void QNetworkAccessManager::setTransferTimeout(int timeout)
+ \since 5.15
+
+ Sets \a timeout as the transfer timeout in milliseconds.
+
+ \sa setTransferTimeout(std::chrono::milliseconds),
+ transferTimeout(), transferTimeoutAsDuration()
+*/
+
+/*!
+ \since 6.7
+
+ Returns the timeout duration after which the transfer is aborted if no
+ data is exchanged.
+
+ The default duration is zero, which means that the timeout is not used.
+
+ \sa setTransferTimeout(std::chrono::milliseconds)
+ */
+std::chrono::milliseconds QNetworkAccessManager::transferTimeoutAsDuration() const
{
return d_func()->transferTimeout;
}
/*!
- \since 5.15
+ \since 6.7
- Sets \a timeout as the transfer timeout in milliseconds.
+ Sets the timeout \a duration to abort the transfer if no data is exchanged.
Transfers are aborted if no bytes are transferred before
the timeout expires. Zero means no timer is set. If no
argument is provided, the timeout is
- QNetworkRequest::DefaultTransferTimeoutConstant. If this function
+ QNetworkRequest::DefaultTransferTimeout. If this function
is not called, the timeout is disabled and has the
value zero. The request-specific non-zero timeouts set for
the requests that are executed override this value. This means
that if QNetworkAccessManager has an enabled timeout, it needs
to be disabled to execute a request without a timeout.
- \sa transferTimeout()
-*/
-void QNetworkAccessManager::setTransferTimeout(int timeout)
+ \sa transferTimeoutAsDuration()
+ */
+void QNetworkAccessManager::setTransferTimeout(std::chrono::milliseconds duration)
{
- d_func()->transferTimeout = timeout;
+ d_func()->transferTimeout = duration;
}
void QNetworkAccessManagerPrivate::_q_replyFinished(QNetworkReply *reply)
@@ -1660,7 +1750,7 @@ QNetworkRequest QNetworkAccessManagerPrivate::prepareMultipart(const QNetworkReq
// add Content-Type header if not there already
if (!request.header(QNetworkRequest::ContentTypeHeader).isValid()) {
QByteArray contentType;
- contentType.reserve(34 + multiPart->d_func()->boundary.count());
+ contentType.reserve(34 + multiPart->d_func()->boundary.size());
contentType += "multipart/";
switch (multiPart->d_func()->contentType) {
case QHttpMultiPart::RelatedType:
@@ -1683,9 +1773,9 @@ QNetworkRequest QNetworkAccessManagerPrivate::prepareMultipart(const QNetworkReq
// add MIME-Version header if not there already (we must include the header
// if the message conforms to RFC 2045, see section 4 of that RFC)
- QByteArray mimeHeader("MIME-Version");
+ auto mimeHeader = "MIME-Version"_ba;
if (!request.hasRawHeader(mimeHeader))
- newRequest.setRawHeader(mimeHeader, QByteArray("1.0"));
+ newRequest.setRawHeader(mimeHeader, "1.0"_ba);
QIODevice *device = multiPart->d_func()->device;
if (!device->isReadable()) {
@@ -1708,15 +1798,15 @@ QNetworkRequest QNetworkAccessManagerPrivate::prepareMultipart(const QNetworkReq
*/
void QNetworkAccessManagerPrivate::ensureBackendPluginsLoaded()
{
- static QBasicMutex mutex;
+ Q_CONSTINIT static QBasicMutex mutex;
std::unique_lock locker(mutex);
- if (!loader())
+ if (!qnabfLoader())
return;
#if QT_CONFIG(library)
- loader->update();
+ qnabfLoader->update();
#endif
int index = 0;
- while (loader->instance(index))
+ while (qnabfLoader->instance(index))
++index;
}
diff --git a/src/network/access/qnetworkaccessmanager.h b/src/network/access/qnetworkaccessmanager.h
index b03191505b..0d069b2a9b 100644
--- a/src/network/access/qnetworkaccessmanager.h
+++ b/src/network/access/qnetworkaccessmanager.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNETWORKACCESSMANAGER_H
#define QNETWORKACCESSMANAGER_H
@@ -116,10 +80,14 @@ public:
QNetworkReply *head(const QNetworkRequest &request);
QNetworkReply *get(const QNetworkRequest &request);
+ QNetworkReply *get(const QNetworkRequest &request, QIODevice *data);
+ QNetworkReply *get(const QNetworkRequest &request, const QByteArray &data);
QNetworkReply *post(const QNetworkRequest &request, QIODevice *data);
QNetworkReply *post(const QNetworkRequest &request, const QByteArray &data);
+ QNetworkReply *post(const QNetworkRequest &request, std::nullptr_t nptr);
QNetworkReply *put(const QNetworkRequest &request, QIODevice *data);
QNetworkReply *put(const QNetworkRequest &request, const QByteArray &data);
+ QNetworkReply *put(const QNetworkRequest &request, std::nullptr_t nptr);
QNetworkReply *deleteResource(const QNetworkRequest &request);
QNetworkReply *sendCustomRequest(const QNetworkRequest &request, const QByteArray &verb, QIODevice *data = nullptr);
QNetworkReply *sendCustomRequest(const QNetworkRequest &request, const QByteArray &verb, const QByteArray &data);
@@ -145,8 +113,14 @@ public:
bool autoDeleteReplies() const;
void setAutoDeleteReplies(bool autoDelete);
+ QT_NETWORK_INLINE_SINCE(6, 8)
int transferTimeout() const;
- void setTransferTimeout(int timeout = QNetworkRequest::DefaultTransferTimeoutConstant);
+ QT_NETWORK_INLINE_SINCE(6, 8)
+ void setTransferTimeout(int timeout);
+
+ std::chrono::milliseconds transferTimeoutAsDuration() const;
+ void setTransferTimeout(std::chrono::milliseconds duration =
+ QNetworkRequest::DefaultTransferTimeout);
Q_SIGNALS:
#ifndef QT_NO_NETWORKPROXY
@@ -183,6 +157,18 @@ private:
#endif
};
+#if QT_NETWORK_INLINE_IMPL_SINCE(6, 8)
+int QNetworkAccessManager::transferTimeout() const
+{
+ return int(transferTimeoutAsDuration().count());
+}
+
+void QNetworkAccessManager::setTransferTimeout(int timeout)
+{
+ setTransferTimeout(std::chrono::milliseconds(timeout));
+}
+#endif // INLINE_SINCE 6.8
+
QT_END_NAMESPACE
#endif
diff --git a/src/network/access/qnetworkaccessmanager_p.h b/src/network/access/qnetworkaccessmanager_p.h
index 3d5d7231b4..491a5acaa4 100644
--- a/src/network/access/qnetworkaccessmanager_p.h
+++ b/src/network/access/qnetworkaccessmanager_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNETWORKACCESSMANAGER_P_H
#define QNETWORKACCESSMANAGER_P_H
@@ -86,7 +50,7 @@ public:
cookieJarCreated(false),
defaultAccessControl(true),
redirectPolicy(QNetworkRequest::NoLessSafeRedirectPolicy),
- authenticationManager(QSharedPointer<QNetworkAccessAuthenticationManager>::create())
+ authenticationManager(std::make_shared<QNetworkAccessAuthenticationManager>())
{
}
~QNetworkAccessManagerPrivate();
@@ -150,7 +114,7 @@ public:
QNetworkRequest::RedirectPolicy redirectPolicy = QNetworkRequest::NoLessSafeRedirectPolicy;
// The cache with authorization data:
- QSharedPointer<QNetworkAccessAuthenticationManager> authenticationManager;
+ std::shared_ptr<QNetworkAccessAuthenticationManager> authenticationManager;
// this cache can be used by individual backends to cache e.g. their TCP connections to a server
// and use the connections for multiple requests.
@@ -167,7 +131,7 @@ public:
bool autoDeleteReplies = false;
- int transferTimeout = 0;
+ std::chrono::milliseconds transferTimeout{0};
Q_DECLARE_PUBLIC(QNetworkAccessManager)
};
diff --git a/src/network/access/qnetworkcookie.cpp b/src/network/access/qnetworkcookie.cpp
index 16c38d89ab..8ea5fdbe57 100644
--- a/src/network/access/qnetworkcookie.cpp
+++ b/src/network/access/qnetworkcookie.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qnetworkcookie.h"
#include "qnetworkcookie_p.h"
@@ -43,18 +7,24 @@
#include "qnetworkrequest.h"
#include "qnetworkreply.h"
#include "QtCore/qbytearray.h"
+#include "QtCore/qdatetime.h"
#include "QtCore/qdebug.h"
#include "QtCore/qlist.h"
#include "QtCore/qlocale.h"
#include <QtCore/qregularexpression.h>
#include "QtCore/qstring.h"
#include "QtCore/qstringlist.h"
+#include "QtCore/qtimezone.h"
#include "QtCore/qurl.h"
#include "QtNetwork/qhostaddress.h"
#include "private/qobject_p.h"
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
+QT_IMPL_METATYPE_EXTERN(QNetworkCookie)
+
/*!
\class QNetworkCookie
\since 4.4
@@ -180,7 +150,8 @@ bool QNetworkCookie::operator==(const QNetworkCookie &other) const
d->domain == other.d->domain &&
d->path == other.d->path &&
d->secure == other.d->secure &&
- d->comment == other.d->comment;
+ d->comment == other.d->comment &&
+ d->sameSite == other.d->sameSite;
}
/*!
@@ -222,6 +193,29 @@ void QNetworkCookie::setSecure(bool enable)
}
/*!
+ Returns the "SameSite" option if specified in the cookie
+ string, \c SameSite::Default if not present.
+
+ \since 6.1
+ \sa setSameSitePolicy()
+*/
+QNetworkCookie::SameSite QNetworkCookie::sameSitePolicy() const
+{
+ return d->sameSite;
+}
+
+/*!
+ Sets the "SameSite" option of this cookie to \a sameSite.
+
+ \since 6.1
+ \sa sameSitePolicy()
+*/
+void QNetworkCookie::setSameSitePolicy(QNetworkCookie::SameSite sameSite)
+{
+ d->sameSite = sameSite;
+}
+
+/*!
\since 4.5
Returns \c true if the "HttpOnly" flag is enabled for this cookie.
@@ -382,13 +376,13 @@ void QNetworkCookie::setValue(const QByteArray &value)
}
// ### move this to qnetworkcookie_p.h and share with qnetworkaccesshttpbackend
-static QPair<QByteArray, QByteArray> nextField(const QByteArray &text, int &position, bool isNameValue)
+static QPair<QByteArray, QByteArray> nextField(QByteArrayView text, int &position, bool isNameValue)
{
// format is one of:
// (1) token
// (2) token = token
// (3) token = quoted-string
- const int length = text.length();
+ const int length = text.size();
position = nextNonWhitespace(text, position);
int semiColonPosition = text.indexOf(';', position);
@@ -402,11 +396,11 @@ static QPair<QByteArray, QByteArray> nextField(const QByteArray &text, int &posi
equalsPosition = semiColonPosition; //no '=' means there is an attribute-name but no attribute-value
}
- QByteArray first = text.mid(position, equalsPosition - position).trimmed();
+ QByteArray first = text.mid(position, equalsPosition - position).trimmed().toByteArray();
QByteArray second;
int secondLength = semiColonPosition - equalsPosition - 1;
if (secondLength > 0)
- second = text.mid(equalsPosition + 1, secondLength).trimmed();
+ second = text.mid(equalsPosition + 1, secondLength).trimmed().toByteArray();
position = semiColonPosition;
return qMakePair(first, second);
@@ -435,6 +429,53 @@ static QPair<QByteArray, QByteArray> nextField(const QByteArray &text, int &posi
*/
/*!
+ \enum QNetworkCookie::SameSite
+ \since 6.1
+
+ \value Default SameSite is not set. Can be interpreted as None or Lax by the browser.
+ \value None Cookies can be sent in all contexts. This used to be default, but
+ recent browsers made Lax default, and will now require the cookie to be both secure and to set SameSite=None.
+ \value Lax Cookies are sent on first party requests and GET requests initiated by third party website.
+ This is the default in modern browsers (since mid 2020).
+ \value Strict Cookies will only be sent in a first-party context.
+
+ \sa setSameSitePolicy(), sameSitePolicy()
+*/
+
+namespace {
+
+constexpr QByteArrayView sameSiteNone() noexcept { return "None"; }
+constexpr QByteArrayView sameSiteLax() noexcept { return "Lax"; }
+constexpr QByteArrayView sameSiteStrict() noexcept { return "Strict"; }
+
+QByteArrayView sameSiteToRawString(QNetworkCookie::SameSite samesite) noexcept
+{
+ switch (samesite) {
+ case QNetworkCookie::SameSite::None:
+ return sameSiteNone();
+ case QNetworkCookie::SameSite::Lax:
+ return sameSiteLax();
+ case QNetworkCookie::SameSite::Strict:
+ return sameSiteStrict();
+ case QNetworkCookie::SameSite::Default:
+ break;
+ }
+ return QByteArrayView();
+}
+
+QNetworkCookie::SameSite sameSiteFromRawString(QByteArrayView str) noexcept
+{
+ if (str.compare(sameSiteNone(), Qt::CaseInsensitive) == 0)
+ return QNetworkCookie::SameSite::None;
+ if (str.compare(sameSiteLax(), Qt::CaseInsensitive) == 0)
+ return QNetworkCookie::SameSite::Lax;
+ if (str.compare(sameSiteStrict(), Qt::CaseInsensitive) == 0)
+ return QNetworkCookie::SameSite::Strict;
+ return QNetworkCookie::SameSite::Default;
+}
+} // namespace
+
+/*!
Returns the raw form of this QNetworkCookie. The QByteArray
returned by this function is suitable for an HTTP header, either
in a server response (the Set-Cookie header) or the client request
@@ -459,14 +500,18 @@ QByteArray QNetworkCookie::toRawForm(RawForm form) const
result += "; secure";
if (isHttpOnly())
result += "; HttpOnly";
+ if (d->sameSite != SameSite::Default) {
+ result += "; SameSite=";
+ result += sameSiteToRawString(d->sameSite);
+ }
if (!isSessionCookie()) {
result += "; expires=";
result += QLocale::c().toString(d->expirationDate.toUTC(),
- QLatin1String("ddd, dd-MMM-yyyy hh:mm:ss 'GMT")).toLatin1();
+ "ddd, dd-MMM-yyyy hh:mm:ss 'GMT"_L1).toLatin1();
}
if (!d->domain.isEmpty()) {
result += "; domain=";
- if (d->domain.startsWith(QLatin1Char('.'))) {
+ if (d->domain.startsWith(u'.')) {
result += '.';
result += QUrl::toAce(d->domain.mid(1));
} else {
@@ -535,11 +580,11 @@ static inline bool isValueSeparator(char c)
static inline bool isWhitespace(char c)
{ return c == ' ' || c == '\t'; }
-static bool checkStaticArray(int &val, const QByteArray &dateString, int at, const char *array, int size)
+static bool checkStaticArray(int &val, QByteArrayView dateString, int at, const char *array, int size)
{
if (dateString[at] < 'a' || dateString[at] > 'z')
return false;
- if (val == -1 && dateString.length() >= at + 3) {
+ if (val == -1 && dateString.size() >= at + 3) {
int j = 0;
int i = 0;
while (i <= size) {
@@ -582,7 +627,7 @@ static bool checkStaticArray(int &val, const QByteArray &dateString, int at, con
Or in their own words:
"} // else what the hell is this."
*/
-static QDateTime parseDateString(const QByteArray &dateString)
+static QDateTime parseDateString(QByteArrayView dateString)
{
QTime time;
// placeholders for values when we are not sure it is a year, month or day
@@ -593,10 +638,11 @@ static QDateTime parseDateString(const QByteArray &dateString)
int zoneOffset = -1;
// hour:minute:second.ms pm
- QRegularExpression timeRx(QLatin1String("(\\d{1,2}):(\\d{1,2})(:(\\d{1,2})|)(\\.(\\d{1,3})|)((\\s{0,}(am|pm))|)"));
+ static const QRegularExpression timeRx(
+ u"(\\d\\d?):(\\d\\d?)(?::(\\d\\d?)(?:\\.(\\d{1,3}))?)?(?:\\s*(am|pm))?"_s);
int at = 0;
- while (at < dateString.length()) {
+ while (at < dateString.size()) {
#ifdef PARSEDATESTRINGDEBUG
qDebug() << dateString.mid(at);
#endif
@@ -637,20 +683,20 @@ static QDateTime parseDateString(const QByteArray &dateString)
&& (dateString[at - 1] == 't')))) {
int end = 1;
- while (end < 5 && dateString.length() > at+end
+ while (end < 5 && dateString.size() > at+end
&& dateString[at + end] >= '0' && dateString[at + end] <= '9')
++end;
int minutes = 0;
int hours = 0;
switch (end - 1) {
case 4:
- minutes = atoi(dateString.mid(at + 3, 2).constData());
+ minutes = dateString.mid(at + 3, 2).toInt();
Q_FALLTHROUGH();
case 2:
- hours = atoi(dateString.mid(at + 1, 2).constData());
+ hours = dateString.mid(at + 1, 2).toInt();
break;
case 1:
- hours = atoi(dateString.mid(at + 1, 1).constData());
+ hours = dateString.mid(at + 1, 1).toInt();
break;
default:
at += end;
@@ -669,25 +715,25 @@ static QDateTime parseDateString(const QByteArray &dateString)
// Time
if (isNum && time.isNull()
- && dateString.length() >= at + 3
+ && dateString.size() >= at + 3
&& (dateString[at + 2] == ':' || dateString[at + 1] == ':')) {
// While the date can be found all over the string the format
// for the time is set and a nice regexp can be used.
- QRegularExpressionMatch match;
- int pos = QString::fromLatin1(dateString).indexOf(timeRx, at, &match);
- if (pos != -1) {
- QStringList list = match.capturedTexts();
- int h = match.captured(1).toInt();
- int m = match.captured(2).toInt();
- int s = match.captured(4).toInt();
- int ms = match.captured(6).toInt();
- QString ampm = match.captured(9);
+ // This string needs to stay for as long as the QRegularExpressionMatch is used,
+ // or else we get use-after-free issues:
+ QString dateToString = QString::fromLatin1(dateString);
+ if (auto match = timeRx.match(dateToString, at); match.hasMatch()) {
+ int h = match.capturedView(1).toInt();
+ int m = match.capturedView(2).toInt();
+ int s = match.capturedView(3).toInt();
+ int ms = match.capturedView(4).toInt();
+ QStringView ampm = match.capturedView(5);
if (h < 12 && !ampm.isEmpty())
- if (ampm == QLatin1String("pm"))
+ if (ampm == "pm"_L1)
h += 12;
time = QTime(h, m, s, ms);
#ifdef PARSEDATESTRINGDEBUG
- qDebug() << "Time:" << list << timeRx.matchedLength();
+ qDebug() << "Time:" << match.capturedTexts() << match.capturedLength();
#endif
at += match.capturedLength();
continue;
@@ -697,11 +743,11 @@ static QDateTime parseDateString(const QByteArray &dateString)
// 4 digit Year
if (isNum
&& year == -1
- && dateString.length() > at + 3) {
+ && dateString.size() > at + 3) {
if (isNumber(dateString[at + 1])
&& isNumber(dateString[at + 2])
&& isNumber(dateString[at + 3])) {
- year = atoi(dateString.mid(at, 4).constData());
+ year = dateString.mid(at, 4).toInt();
at += 4;
#ifdef PARSEDATESTRINGDEBUG
qDebug() << "Year:" << year;
@@ -714,10 +760,10 @@ static QDateTime parseDateString(const QByteArray &dateString)
// Could be month, day or year
if (isNum) {
int length = 1;
- if (dateString.length() > at + 1
+ if (dateString.size() > at + 1
&& isNumber(dateString[at + 1]))
++length;
- int x = atoi(dateString.mid(at, length).constData());
+ int x = dateString.mid(at, length).toInt();
if (year == -1 && (x > 31 || x == 0)) {
year = x;
} else {
@@ -866,11 +912,11 @@ static QDateTime parseDateString(const QByteArray &dateString)
if (!date.isValid())
date = QDate(day + y2k, month, year);
- QDateTime dateTime(date, time, Qt::UTC);
+ QDateTime dateTime(date, time, QTimeZone::UTC);
- if (zoneOffset != -1) {
+ if (zoneOffset != -1)
dateTime = dateTime.addSecs(zoneOffset);
- }
+
if (!dateTime.isValid())
return QDateTime();
return dateTime;
@@ -886,19 +932,19 @@ static QDateTime parseDateString(const QByteArray &dateString)
cookie that is parsed.
\sa toRawForm()
+ \note In Qt versions prior to 6.7, this function took QByteArray only.
*/
-QList<QNetworkCookie> QNetworkCookie::parseCookies(const QByteArray &cookieString)
+QList<QNetworkCookie> QNetworkCookie::parseCookies(QByteArrayView cookieString)
{
// cookieString can be a number of set-cookie header strings joined together
// by \n, parse each line separately.
QList<QNetworkCookie> cookies;
- QList<QByteArray> list = cookieString.split('\n');
- for (int a = 0; a < list.size(); a++)
- cookies += QNetworkCookiePrivate::parseSetCookieHeaderLine(list.at(a));
+ for (auto s : QLatin1StringView(cookieString).tokenize('\n'_L1))
+ cookies += QNetworkCookiePrivate::parseSetCookieHeaderLine(s);
return cookies;
}
-QList<QNetworkCookie> QNetworkCookiePrivate::parseSetCookieHeaderLine(const QByteArray &cookieString)
+QList<QNetworkCookie> QNetworkCookiePrivate::parseSetCookieHeaderLine(QByteArrayView cookieString)
{
// According to http://wp.netscape.com/newsref/std/cookie_spec.html,<
// the Set-Cookie response header is of the format:
@@ -913,7 +959,7 @@ QList<QNetworkCookie> QNetworkCookiePrivate::parseSetCookieHeaderLine(const QByt
const QDateTime now = QDateTime::currentDateTimeUtc();
int position = 0;
- const int length = cookieString.length();
+ const int length = cookieString.size();
while (position < length) {
QNetworkCookie cookie;
@@ -931,28 +977,27 @@ QList<QNetworkCookie> QNetworkCookiePrivate::parseSetCookieHeaderLine(const QByt
case ';':
// new field in the cookie
field = nextField(cookieString, position, false);
- field.first = field.first.toLower(); // everything but the NAME=VALUE is case-insensitive
- if (field.first == "expires") {
- position -= field.second.length();
+ if (field.first.compare("expires", Qt::CaseInsensitive) == 0) {
+ position -= field.second.size();
int end;
for (end = position; end < length; ++end)
if (isValueSeparator(cookieString.at(end)))
break;
- QByteArray dateString = cookieString.mid(position, end - position).trimmed();
+ QByteArray dateString = cookieString.mid(position, end - position).trimmed().toByteArray().toLower();
position = end;
- QDateTime dt = parseDateString(dateString.toLower());
+ QDateTime dt = parseDateString(dateString);
if (dt.isValid())
cookie.setExpirationDate(dt);
//if unparsed, ignore the attribute but not the whole cookie (RFC6265 section 5.2.1)
- } else if (field.first == "domain") {
- QByteArray rawDomain = field.second;
+ } else if (field.first.compare("domain", Qt::CaseInsensitive) == 0) {
+ QByteArrayView rawDomain = field.second;
//empty domain should be ignored (RFC6265 section 5.2.3)
if (!rawDomain.isEmpty()) {
- QString maybeLeadingDot;
+ QLatin1StringView maybeLeadingDot;
if (rawDomain.startsWith('.')) {
- maybeLeadingDot = QLatin1Char('.');
+ maybeLeadingDot = "."_L1;
rawDomain = rawDomain.mid(1);
}
@@ -967,7 +1012,7 @@ QList<QNetworkCookie> QNetworkCookiePrivate::parseSetCookieHeaderLine(const QByt
return result;
}
}
- } else if (field.first == "max-age") {
+ } else if (field.first.compare("max-age", Qt::CaseInsensitive) == 0) {
bool ok = false;
int secs = field.second.toInt(&ok);
if (ok) {
@@ -979,7 +1024,7 @@ QList<QNetworkCookie> QNetworkCookiePrivate::parseSetCookieHeaderLine(const QByt
}
}
//if unparsed, ignore the attribute but not the whole cookie (RFC6265 section 5.2.2)
- } else if (field.first == "path") {
+ } else if (field.first.compare("path", Qt::CaseInsensitive) == 0) {
if (field.second.startsWith('/')) {
// ### we should treat cookie paths as an octet sequence internally
// However RFC6265 says we should assume UTF-8 for presentation as a string
@@ -989,10 +1034,12 @@ QList<QNetworkCookie> QNetworkCookiePrivate::parseSetCookieHeaderLine(const QByt
// and also IETF test case path0030 which has valid and empty path in the same cookie
cookie.setPath(QString());
}
- } else if (field.first == "secure") {
+ } else if (field.first.compare("secure", Qt::CaseInsensitive) == 0) {
cookie.setSecure(true);
- } else if (field.first == "httponly") {
+ } else if (field.first.compare("httponly", Qt::CaseInsensitive) == 0) {
cookie.setHttpOnly(true);
+ } else if (field.first.compare("samesite", Qt::CaseInsensitive) == 0) {
+ cookie.setSameSitePolicy(sameSiteFromRawString(field.second));
} else {
// ignore unknown fields in the cookie (RFC6265 section 5.2, rule 6)
}
@@ -1018,9 +1065,9 @@ void QNetworkCookie::normalize(const QUrl &url)
// don't do path checking. See QTBUG-5815
if (d->path.isEmpty()) {
QString pathAndFileName = url.path();
- QString defaultPath = pathAndFileName.left(pathAndFileName.lastIndexOf(QLatin1Char('/'))+1);
+ QString defaultPath = pathAndFileName.left(pathAndFileName.lastIndexOf(u'/') + 1);
if (defaultPath.isEmpty())
- defaultPath = QLatin1Char('/');
+ defaultPath = u'/';
d->path = defaultPath;
}
@@ -1030,12 +1077,12 @@ void QNetworkCookie::normalize(const QUrl &url)
QHostAddress hostAddress(d->domain);
if (hostAddress.protocol() != QAbstractSocket::IPv4Protocol
&& hostAddress.protocol() != QAbstractSocket::IPv6Protocol
- && !d->domain.startsWith(QLatin1Char('.'))) {
+ && !d->domain.startsWith(u'.')) {
// Ensure the domain starts with a dot if its field was not empty
// in the HTTP header. There are some servers that forget the
// leading dot and this is actually forbidden according to RFC 2109,
// but all browsers accept it anyway so we do that as well.
- d->domain.prepend(QLatin1Char('.'));
+ d->domain.prepend(u'.');
}
}
}
@@ -1051,3 +1098,5 @@ QDebug operator<<(QDebug s, const QNetworkCookie &cookie)
#endif
QT_END_NAMESPACE
+
+#include "moc_qnetworkcookie.cpp"
diff --git a/src/network/access/qnetworkcookie.h b/src/network/access/qnetworkcookie.h
index b712b63849..aed9c8af12 100644
--- a/src/network/access/qnetworkcookie.h
+++ b/src/network/access/qnetworkcookie.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNETWORKCOOKIE_H
#define QNETWORKCOOKIE_H
@@ -57,11 +21,19 @@ class QUrl;
class QNetworkCookiePrivate;
class Q_NETWORK_EXPORT QNetworkCookie
{
+ Q_GADGET
public:
enum RawForm {
NameAndValueOnly,
Full
};
+ enum class SameSite {
+ Default,
+ None,
+ Lax,
+ Strict
+ };
+ Q_ENUM(SameSite)
explicit QNetworkCookie(const QByteArray &name = QByteArray(), const QByteArray &value = QByteArray());
QNetworkCookie(const QNetworkCookie &other);
@@ -69,7 +41,7 @@ public:
QNetworkCookie &operator=(QNetworkCookie &&other) noexcept { swap(other); return *this; }
QNetworkCookie &operator=(const QNetworkCookie &other);
- void swap(QNetworkCookie &other) noexcept { qSwap(d, other.d); }
+ void swap(QNetworkCookie &other) noexcept { d.swap(other.d); }
bool operator==(const QNetworkCookie &other) const;
inline bool operator!=(const QNetworkCookie &other) const
@@ -79,6 +51,8 @@ public:
void setSecure(bool enable);
bool isHttpOnly() const;
void setHttpOnly(bool enable);
+ SameSite sameSitePolicy() const;
+ void setSameSitePolicy(SameSite sameSite);
bool isSessionCookie() const;
QDateTime expirationDate() const;
@@ -101,7 +75,10 @@ public:
bool hasSameIdentifier(const QNetworkCookie &other) const;
void normalize(const QUrl &url);
+#if QT_NETWORK_REMOVED_SINCE(6, 7)
static QList<QNetworkCookie> parseCookies(const QByteArray &cookieString);
+#endif
+ static QList<QNetworkCookie> parseCookies(QByteArrayView cookieString);
private:
QSharedDataPointer<QNetworkCookiePrivate> d;
@@ -117,6 +94,6 @@ Q_NETWORK_EXPORT QDebug operator<<(QDebug, const QNetworkCookie &);
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QNetworkCookie)
+QT_DECL_METATYPE_EXTERN(QNetworkCookie, Q_NETWORK_EXPORT)
#endif
diff --git a/src/network/access/qnetworkcookie_p.h b/src/network/access/qnetworkcookie_p.h
index 13538ad243..ce4378fd64 100644
--- a/src/network/access/qnetworkcookie_p.h
+++ b/src/network/access/qnetworkcookie_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNETWORKCOOKIE_P_H
#define QNETWORKCOOKIE_P_H
@@ -53,14 +17,15 @@
#include <QtNetwork/private/qtnetworkglobal_p.h>
#include "QtCore/qdatetime.h"
+#include "QtNetwork/qnetworkcookie.h"
QT_BEGIN_NAMESPACE
class QNetworkCookiePrivate: public QSharedData
{
public:
- inline QNetworkCookiePrivate() : secure(false), httpOnly(false) { }
- static QList<QNetworkCookie> parseSetCookieHeaderLine(const QByteArray &cookieString);
+ QNetworkCookiePrivate() = default;
+ static QList<QNetworkCookie> parseSetCookieHeaderLine(QByteArrayView cookieString);
QDateTime expirationDate;
QString domain;
@@ -68,8 +33,9 @@ public:
QString comment;
QByteArray name;
QByteArray value;
- bool secure;
- bool httpOnly;
+ QNetworkCookie::SameSite sameSite = QNetworkCookie::SameSite::Default;
+ bool secure = false;
+ bool httpOnly = false;
};
static inline bool isLWS(char c)
@@ -77,13 +43,13 @@ static inline bool isLWS(char c)
return c == ' ' || c == '\t' || c == '\r' || c == '\n';
}
-static int nextNonWhitespace(const QByteArray &text, int from)
+static int nextNonWhitespace(QByteArrayView text, int from)
{
// RFC 2616 defines linear whitespace as:
// LWS = [CRLF] 1*( SP | HT )
// We ignore the fact that CRLF must come as a pair at this point
// It's an invalid HTTP header if that happens.
- while (from < text.length()) {
+ while (from < text.size()) {
if (isLWS(text.at(from)))
++from;
else
@@ -91,7 +57,7 @@ static int nextNonWhitespace(const QByteArray &text, int from)
}
// reached the end
- return text.length();
+ return text.size();
}
QT_END_NAMESPACE
diff --git a/src/network/access/qnetworkcookiejar.cpp b/src/network/access/qnetworkcookiejar.cpp
index c01bd339ca..82746f91b1 100644
--- a/src/network/access/qnetworkcookiejar.cpp
+++ b/src/network/access/qnetworkcookiejar.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qnetworkcookiejar.h"
#include "qnetworkcookiejar_p.h"
@@ -50,13 +14,15 @@ QT_BEGIN_NAMESPACE
static bool qIsEffectiveTLD(QStringView domain)
{
// provide minimal checking by not accepting cookies on real TLDs
- return !domain.contains(QLatin1Char('.'));
+ return !domain.contains(u'.');
}
QT_END_NAMESPACE
#endif
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
/*!
\class QNetworkCookieJar
\since 4.4
@@ -146,11 +112,11 @@ void QNetworkCookieJar::setAllCookies(const QList<QNetworkCookie> &cookieList)
d->allCookies = cookieList;
}
-static inline bool isParentPath(const QString &path, const QString &reference)
+static inline bool isParentPath(QStringView path, QStringView reference)
{
- if ((path.isEmpty() && reference == QLatin1String("/")) || path.startsWith(reference)) {
+ if ((path.isEmpty() && reference == "/"_L1) || path.startsWith(reference)) {
//The cookie-path and the request-path are identical.
- if (path.length() == reference.length())
+ if (path.size() == reference.size())
return true;
//The cookie-path is a prefix of the request-path, and the last
//character of the cookie-path is %x2F ("/").
@@ -159,18 +125,18 @@ static inline bool isParentPath(const QString &path, const QString &reference)
//The cookie-path is a prefix of the request-path, and the first
//character of the request-path that is not included in the cookie-
//path is a %x2F ("/") character.
- if (path.at(reference.length()) == u'/')
+ if (path.at(reference.size()) == u'/')
return true;
}
return false;
}
-static inline bool isParentDomain(const QString &domain, const QString &reference)
+static inline bool isParentDomain(QStringView domain, QStringView reference)
{
- if (!reference.startsWith(QLatin1Char('.')))
+ if (!reference.startsWith(u'.'))
return domain == reference;
- return domain.endsWith(reference) || domain == QStringView{reference}.mid(1);
+ return domain.endsWith(reference) || domain == reference.mid(1);
}
/*!
@@ -234,49 +200,38 @@ QList<QNetworkCookie> QNetworkCookieJar::cookiesForUrl(const QUrl &url) const
Q_D(const QNetworkCookieJar);
const QDateTime now = QDateTime::currentDateTimeUtc();
QList<QNetworkCookie> result;
- bool isEncrypted = url.scheme() == QLatin1String("https");
+ const bool isEncrypted = url.scheme() == "https"_L1;
// scan our cookies for something that matches
- QList<QNetworkCookie>::ConstIterator it = d->allCookies.constBegin(),
- end = d->allCookies.constEnd();
- for ( ; it != end; ++it) {
- if (!isParentDomain(url.host(), it->domain()))
+ for (const auto &cookie : std::as_const(d->allCookies)) {
+ if (!isEncrypted && cookie.isSecure())
continue;
- if (!isParentPath(url.path(), it->path()))
+ if (!cookie.isSessionCookie() && cookie.expirationDate() < now)
continue;
- if (!(*it).isSessionCookie() && (*it).expirationDate() < now)
+ const QString urlHost = url.host();
+ const QString cookieDomain = cookie.domain();
+ if (!isParentDomain(urlHost, cookieDomain))
continue;
- if ((*it).isSecure() && !isEncrypted)
+ if (!isParentPath(url.path(), cookie.path()))
continue;
- QString domain = it->domain();
- if (domain.startsWith(QLatin1Char('.'))) /// Qt6?: remove when compliant with RFC6265
- domain = domain.mid(1);
+ QStringView domain = cookieDomain;
+ if (domain.startsWith(u'.')) /// Qt6?: remove when compliant with RFC6265
+ domain = domain.sliced(1);
#if QT_CONFIG(topleveldomain)
- if (qIsEffectiveTLD(domain) && url.host() != domain)
+ if (urlHost != domain && qIsEffectiveTLD(domain))
continue;
#else
- if (!domain.contains(QLatin1Char('.')) && url.host() != domain)
+ if (!domain.contains(u'.') && urlHost != domain)
continue;
#endif // topleveldomain
- // insert this cookie into result, sorted by path
- QList<QNetworkCookie>::Iterator insertIt = result.begin();
- while (insertIt != result.end()) {
- if (insertIt->path().length() < it->path().length()) {
- // insert here
- insertIt = result.insert(insertIt, *it);
- break;
- } else {
- ++insertIt;
- }
- }
-
- // this is the shortest path yet, just append
- if (insertIt == result.end())
- result += *it;
+ result += cookie;
}
+ auto longerPath = [](const auto &c1, const auto &c2)
+ { return c1.path().size() > c2.path().size(); };
+ std::sort(result.begin(), result.end(), longerPath);
return result;
}
@@ -333,12 +288,11 @@ bool QNetworkCookieJar::updateCookie(const QNetworkCookie &cookie)
bool QNetworkCookieJar::deleteCookie(const QNetworkCookie &cookie)
{
Q_D(QNetworkCookieJar);
- QList<QNetworkCookie>::Iterator it;
- for (it = d->allCookies.begin(); it != d->allCookies.end(); ++it) {
- if (it->hasSameIdentifier(cookie)) {
- d->allCookies.erase(it);
- return true;
- }
+ const auto it = std::find_if(d->allCookies.cbegin(), d->allCookies.cend(),
+ [&cookie](const auto &c) { return c.hasSameIdentifier(cookie); });
+ if (it != d->allCookies.cend()) {
+ d->allCookies.erase(it);
+ return true;
}
return false;
}
@@ -351,13 +305,14 @@ bool QNetworkCookieJar::deleteCookie(const QNetworkCookie &cookie)
*/
bool QNetworkCookieJar::validateCookie(const QNetworkCookie &cookie, const QUrl &url) const
{
- QString domain = cookie.domain();
+ const QString cookieDomain = cookie.domain();
+ QStringView domain = cookieDomain;
const QString host = url.host();
if (!isParentDomain(domain, host) && !isParentDomain(host, domain))
return false; // not accepted
- if (domain.startsWith(QLatin1Char('.')))
- domain = domain.mid(1);
+ if (domain.startsWith(u'.'))
+ domain = domain.sliced(1);
// We shouldn't reject if:
// "[...] the domain-attribute is identical to the canonicalized request-host"
@@ -373,3 +328,5 @@ bool QNetworkCookieJar::validateCookie(const QNetworkCookie &cookie, const QUrl
}
QT_END_NAMESPACE
+
+#include "moc_qnetworkcookiejar.cpp"
diff --git a/src/network/access/qnetworkcookiejar.h b/src/network/access/qnetworkcookiejar.h
index c3b2200443..71f2884a28 100644
--- a/src/network/access/qnetworkcookiejar.h
+++ b/src/network/access/qnetworkcookiejar.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNETWORKCOOKIEJAR_H
#define QNETWORKCOOKIEJAR_H
diff --git a/src/network/access/qnetworkcookiejar_p.h b/src/network/access/qnetworkcookiejar_p.h
index 43f189a40c..f2837ab83d 100644
--- a/src/network/access/qnetworkcookiejar_p.h
+++ b/src/network/access/qnetworkcookiejar_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNETWORKCOOKIEJAR_P_H
#define QNETWORKCOOKIEJAR_P_H
diff --git a/src/network/access/qnetworkdiskcache.cpp b/src/network/access/qnetworkdiskcache.cpp
index 1ee075cb71..c883a61886 100644
--- a/src/network/access/qnetworkdiskcache.cpp
+++ b/src/network/access/qnetworkdiskcache.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//#define QNETWORKDISKCACHE_DEBUG
@@ -48,20 +12,23 @@
#include <qdir.h>
#include <qdatastream.h>
#include <qdatetime.h>
-#include <qdiriterator.h>
+#include <qdirlisting.h>
#include <qurl.h>
#include <qcryptographichash.h>
#include <qdebug.h>
-#define CACHE_POSTFIX QLatin1String(".d")
-#define PREPARED_SLASH QLatin1String("prepared/")
+#include <memory>
+
+#define CACHE_POSTFIX ".d"_L1
#define CACHE_VERSION 8
-#define DATA_DIR QLatin1String("data")
+#define DATA_DIR "data"_L1
#define MAX_COMPRESSION_SIZE (1024 * 1024 * 3)
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
/*!
\class QNetworkDiskCache
\since 4.5
@@ -145,10 +112,10 @@ void QNetworkDiskCache::setCacheDirectory(const QString &cacheDir)
d->cacheDirectory = cacheDir;
QDir dir(d->cacheDirectory);
d->cacheDirectory = dir.absolutePath();
- if (!d->cacheDirectory.endsWith(QLatin1Char('/')))
- d->cacheDirectory += QLatin1Char('/');
+ if (!d->cacheDirectory.endsWith(u'/'))
+ d->cacheDirectory += u'/';
- d->dataDirectory = d->cacheDirectory + DATA_DIR + QString::number(CACHE_VERSION) + QLatin1Char('/');
+ d->dataDirectory = d->cacheDirectory + DATA_DIR + QString::number(CACHE_VERSION) + u'/';
d->prepareLayout();
}
@@ -196,7 +163,7 @@ QIODevice *QNetworkDiskCache::prepare(const QNetworkCacheMetaData &metaData)
break;
}
}
- QScopedPointer<QCacheItem> cacheItem(new QCacheItem);
+ std::unique_ptr<QCacheItem> cacheItem = std::make_unique<QCacheItem>();
cacheItem->metaData = metaData;
QIODevice *device = nullptr;
@@ -204,13 +171,9 @@ QIODevice *QNetworkDiskCache::prepare(const QNetworkCacheMetaData &metaData)
cacheItem->data.open(QBuffer::ReadWrite);
device = &(cacheItem->data);
} else {
- QString templateName = d->tmpCacheFileName();
- QT_TRY {
- cacheItem->file = new QTemporaryFile(templateName, &cacheItem->data);
- } QT_CATCH(...) {
- cacheItem->file = nullptr;
- }
- if (!cacheItem->file || !cacheItem->file->open()) {
+ QString fileName = d->cacheFileName(cacheItem->metaData.url());
+ cacheItem->file = new(std::nothrow) QSaveFile(fileName, &cacheItem->data);
+ if (!cacheItem->file || !cacheItem->file->open(QFileDevice::WriteOnly)) {
qWarning("QNetworkDiskCache::prepare() unable to open temporary file");
cacheItem.reset();
return nullptr;
@@ -218,7 +181,7 @@ QIODevice *QNetworkDiskCache::prepare(const QNetworkCacheMetaData &metaData)
cacheItem->writeHeader(cacheItem->file);
device = cacheItem->file;
}
- d->inserting[device] = cacheItem.take();
+ d->inserting[device] = cacheItem.release();
return device;
}
@@ -250,7 +213,6 @@ void QNetworkDiskCache::insert(QIODevice *device)
void QNetworkDiskCachePrivate::prepareLayout()
{
QDir helper;
- helper.mkpath(cacheDirectory + PREPARED_SLASH);
//Create directory and subdirectories 0-F
helper.mkpath(dataDirectory);
@@ -271,19 +233,16 @@ void QNetworkDiskCachePrivate::storeItem(QCacheItem *cacheItem)
Q_ASSERT(!fileName.isEmpty());
if (QFile::exists(fileName)) {
- if (!QFile::remove(fileName)) {
+ if (!removeFile(fileName)) {
qWarning() << "QNetworkDiskCache: couldn't remove the cache file " << fileName;
return;
}
}
- if (currentCacheSize > 0)
- currentCacheSize += 1024 + cacheItem->size();
currentCacheSize = q->expire();
if (!cacheItem->file) {
- QString templateName = tmpCacheFileName();
- cacheItem->file = new QTemporaryFile(templateName, &cacheItem->data);
- if (cacheItem->file->open()) {
+ cacheItem->file = new QSaveFile(fileName, &cacheItem->data);
+ if (cacheItem->file->open(QFileDevice::WriteOnly)) {
cacheItem->writeHeader(cacheItem->file);
cacheItem->writeCompressedData(cacheItem->file);
}
@@ -291,13 +250,15 @@ void QNetworkDiskCachePrivate::storeItem(QCacheItem *cacheItem)
if (cacheItem->file
&& cacheItem->file->isOpen()
- && cacheItem->file->error() == QFile::NoError) {
- cacheItem->file->setAutoRemove(false);
- // ### use atomic rename rather then remove & rename
- if (cacheItem->file->rename(fileName))
- currentCacheSize += cacheItem->file->size();
- else
- cacheItem->file->setAutoRemove(true);
+ && cacheItem->file->error() == QFileDevice::NoError) {
+ // We have to call size() here instead of inside the if-body because
+ // commit() invalidates the file-engine, and size() will create a new
+ // one, pointing at an empty filename.
+ qint64 size = cacheItem->file->size();
+ if (cacheItem->file->commit())
+ currentCacheSize += size;
+ // Delete and unset the QSaveFile, it's invalid now.
+ delete std::exchange(cacheItem->file, nullptr);
}
if (cacheItem->metaData.url() == lastItem.metaData.url())
lastItem.reset();
@@ -395,7 +356,7 @@ QIODevice *QNetworkDiskCache::data(const QUrl &url)
qDebug() << "QNetworkDiskCache::data()" << url;
#endif
Q_D(QNetworkDiskCache);
- QScopedPointer<QBuffer> buffer;
+ std::unique_ptr<QBuffer> buffer;
if (!url.isValid())
return nullptr;
if (d->lastItem.metaData.url() == url && d->lastItem.data.isOpen()) {
@@ -417,22 +378,11 @@ QIODevice *QNetworkDiskCache::data(const QUrl &url)
buffer->setData(d->lastItem.data.data());
} else {
buffer.reset(new QBuffer);
- // ### verify that QFile uses the fd size and not the file name
- qint64 size = file->size() - file->pos();
- const uchar *p = nullptr;
-#if !defined(Q_OS_INTEGRITY)
- p = file->map(file->pos(), size);
-#endif
- if (p) {
- buffer->setData((const char *)p, size);
- file.take()->setParent(buffer.data());
- } else {
- buffer->setData(file->readAll());
- }
+ buffer->setData(file->readAll());
}
}
buffer->open(QBuffer::ReadOnly);
- return buffer.take();
+ return buffer.release();
}
/*!
@@ -527,47 +477,45 @@ qint64 QNetworkDiskCache::expire()
// close file handle to prevent "in use" error when QFile::remove() is called
d->lastItem.reset();
- QDir::Filters filters = QDir::AllDirs | QDir:: Files | QDir::NoDotAndDotDot;
- QDirIterator it(cacheDirectory(), filters, QDirIterator::Subdirectories);
+ const QDir::Filters filters = QDir::AllDirs | QDir:: Files | QDir::NoDotAndDotDot;
- QMultiMap<QDateTime, QString> cacheItems;
+ struct CacheItem
+ {
+ std::chrono::milliseconds msecs;
+ QString path;
+ qint64 size = 0;
+ };
+ std::vector<CacheItem> cacheItems;
qint64 totalSize = 0;
- while (it.hasNext()) {
- QString path = it.next();
- QFileInfo info = it.fileInfo();
- QString fileName = info.fileName();
- if (fileName.endsWith(CACHE_POSTFIX)) {
- const QDateTime birthTime = info.fileTime(QFile::FileBirthTime);
- cacheItems.insert(birthTime.isValid() ? birthTime
- : info.fileTime(QFile::FileMetadataChangeTime), path);
- totalSize += info.size();
- }
+ using F = QDirListing::IteratorFlag;
+ for (const auto &dirEntry : QDirListing(cacheDirectory(), filters, F::Recursive)) {
+ if (!dirEntry.fileName().endsWith(CACHE_POSTFIX))
+ continue;
+
+ const QFileInfo &info = dirEntry.fileInfo();
+ QDateTime fileTime = info.birthTime(QTimeZone::UTC);
+ if (!fileTime.isValid())
+ fileTime = info.metadataChangeTime(QTimeZone::UTC);
+ const std::chrono::milliseconds msecs{fileTime.toMSecsSinceEpoch()};
+ const qint64 size = info.size();
+ cacheItems.push_back(CacheItem{msecs, info.filePath(), size});
+ totalSize += size;
}
- int removedFiles = 0;
- qint64 goal = (maximumCacheSize() * 9) / 10;
- QMultiMap<QDateTime, QString>::const_iterator i = cacheItems.constBegin();
- while (i != cacheItems.constEnd()) {
- if (totalSize < goal)
- break;
- QString name = i.value();
- QFile file(name);
-
- if (name.contains(PREPARED_SLASH)) {
- for (QCacheItem *item : qAsConst(d->inserting)) {
- if (item && item->file && item->file->fileName() == name) {
- delete item->file;
- item->file = nullptr;
- break;
- }
- }
- }
+ const qint64 goal = (maximumCacheSize() * 9) / 10;
+ if (totalSize < goal)
+ return totalSize; // Nothing to do
- qint64 size = file.size();
- file.remove();
- totalSize -= size;
+ auto byFileTime = [&](const auto &a, const auto &b) { return a.msecs < b.msecs; };
+ std::sort(cacheItems.begin(), cacheItems.end(), byFileTime);
+
+ [[maybe_unused]] int removedFiles = 0; // used under QNETWORKDISKCACHE_DEBUG
+ for (const CacheItem &cached : cacheItems) {
+ QFile::remove(cached.path);
++removedFiles;
- ++i;
+ totalSize -= cached.size;
+ if (totalSize < goal)
+ break;
}
#if defined(QNETWORKDISKCACHE_DEBUG)
if (removedFiles > 0) {
@@ -603,24 +551,16 @@ QString QNetworkDiskCachePrivate::uniqueFileName(const QUrl &url)
cleanUrl.setPassword(QString());
cleanUrl.setFragment(QString());
- QCryptographicHash hash(QCryptographicHash::Sha1);
- hash.addData(cleanUrl.toEncoded());
+ const QByteArray hash = QCryptographicHash::hash(cleanUrl.toEncoded(), QCryptographicHash::Sha1);
// convert sha1 to base36 form and return first 8 bytes for use as string
- const QByteArray id = QByteArray::number(*(qlonglong*)hash.result().constData(), 36).left(8);
- // generates <one-char subdir>/<8-char filname.d>
- uint code = (uint)id.at(id.length()-1) % 16;
- QString pathFragment = QString::number(code, 16) + QLatin1Char('/')
- + QLatin1String(id) + CACHE_POSTFIX;
+ const QByteArray id = QByteArray::number(*(qlonglong*)hash.data(), 36).left(8);
+ // generates <one-char subdir>/<8-char filename.d>
+ uint code = (uint)id.at(id.size()-1) % 16;
+ QString pathFragment = QString::number(code, 16) + u'/' + QLatin1StringView(id) + CACHE_POSTFIX;
return pathFragment;
}
-QString QNetworkDiskCachePrivate::tmpCacheFileName() const
-{
- //The subdirectory is presumed to be already read for use.
- return cacheDirectory + PREPARED_SLASH + QLatin1String("XXXXXX") + CACHE_POSTFIX;
-}
-
/*!
Generates fully qualified path of cached resource from a URL.
*/
@@ -671,7 +611,7 @@ enum
CurrentCacheVersion = CACHE_VERSION
};
-void QCacheItem::writeHeader(QFile *device) const
+void QCacheItem::writeHeader(QFileDevice *device) const
{
QDataStream out(device);
@@ -683,7 +623,7 @@ void QCacheItem::writeHeader(QFile *device) const
out << compressed;
}
-void QCacheItem::writeCompressedData(QFile *device) const
+void QCacheItem::writeCompressedData(QFileDevice *device) const
{
QDataStream out(device);
@@ -694,7 +634,7 @@ void QCacheItem::writeCompressedData(QFile *device) const
Returns \c false if the file is a cache file,
but is an older version and should be removed otherwise true.
*/
-bool QCacheItem::read(QFile *device, bool readData)
+bool QCacheItem::read(QFileDevice *device, bool readData)
{
reset();
@@ -733,7 +673,9 @@ bool QCacheItem::read(QFile *device, bool readData)
if (!device->fileName().endsWith(expectedFilename))
return false;
- return metaData.isValid();
+ return metaData.isValid() && !metaData.rawHeaders().isEmpty();
}
QT_END_NAMESPACE
+
+#include "moc_qnetworkdiskcache.cpp"
diff --git a/src/network/access/qnetworkdiskcache.h b/src/network/access/qnetworkdiskcache.h
index ff7d3192e8..370f3d2b26 100644
--- a/src/network/access/qnetworkdiskcache.h
+++ b/src/network/access/qnetworkdiskcache.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNETWORKDISKCACHE_H
#define QNETWORKDISKCACHE_H
diff --git a/src/network/access/qnetworkdiskcache_p.h b/src/network/access/qnetworkdiskcache_p.h
index c797e63830..826f0a1d7d 100644
--- a/src/network/access/qnetworkdiskcache_p.h
+++ b/src/network/access/qnetworkdiskcache_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNETWORKDISKCACHE_P_H
#define QNETWORKDISKCACHE_P_H
@@ -56,20 +20,16 @@
#include <qbuffer.h>
#include <qhash.h>
-#include <qtemporaryfile.h>
+#include <qsavefile.h>
QT_REQUIRE_CONFIG(networkdiskcache);
QT_BEGIN_NAMESPACE
-class QFile;
-
class QCacheItem
{
public:
- QCacheItem() : file(nullptr)
- {
- }
+ QCacheItem() = default;
~QCacheItem()
{
reset();
@@ -77,7 +37,7 @@ public:
QNetworkCacheMetaData metaData;
QBuffer data;
- QTemporaryFile *file;
+ QSaveFile *file = nullptr;
inline qint64 size() const
{ return file ? file->size() : data.size(); }
@@ -87,9 +47,9 @@ public:
delete file;
file = nullptr;
}
- void writeHeader(QFile *device) const;
- void writeCompressedData(QFile *device) const;
- bool read(QFile *device, bool readData);
+ void writeHeader(QFileDevice *device) const;
+ void writeCompressedData(QFileDevice *device) const;
+ bool read(QFileDevice *device, bool readData);
bool canCompress() const;
};
@@ -105,7 +65,6 @@ public:
static QString uniqueFileName(const QUrl &url);
QString cacheFileName(const QUrl &url) const;
- QString tmpCacheFileName() const;
bool removeFile(const QString &file);
void storeItem(QCacheItem *item);
void prepareLayout();
diff --git a/src/network/access/qnetworkfile.cpp b/src/network/access/qnetworkfile.cpp
index b7c91f28d8..bfedf044de 100644
--- a/src/network/access/qnetworkfile.cpp
+++ b/src/network/access/qnetworkfile.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qnetworkfile_p.h"
@@ -90,3 +54,5 @@ void QNetworkFile::close()
}
QT_END_NAMESPACE
+
+#include "moc_qnetworkfile_p.cpp"
diff --git a/src/network/access/qnetworkfile_p.h b/src/network/access/qnetworkfile_p.h
index e788308d82..df772251b4 100644
--- a/src/network/access/qnetworkfile_p.h
+++ b/src/network/access/qnetworkfile_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNETWORKFILE_H
#define QNETWORKFILE_H
diff --git a/src/network/access/qnetworkreply.cpp b/src/network/access/qnetworkreply.cpp
index c69bcc951e..9334b01de6 100644
--- a/src/network/access/qnetworkreply.cpp
+++ b/src/network/access/qnetworkreply.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtNetwork/private/qtnetworkglobal_p.h>
@@ -45,6 +9,8 @@
QT_BEGIN_NAMESPACE
+QT_IMPL_METATYPE_EXTERN_TAGGED(QNetworkReply::NetworkError, QNetworkReply__NetworkError)
+
const int QNetworkReplyPrivate::progressSignalInterval = 100;
QNetworkReplyPrivate::QNetworkReplyPrivate()
@@ -76,7 +42,7 @@ QNetworkReplyPrivate::QNetworkReplyPrivate()
itself.
QNetworkReply is a sequential-access QIODevice, which means that
- once data is read from the object, it no longer kept by the
+ once data is read from the object, it is no longer kept by the
device. It is therefore the application's responsibility to keep
this data if it needs to. Whenever more data is received from the
network and processed, the readyRead() signal is emitted.
@@ -298,7 +264,7 @@ QNetworkReplyPrivate::QNetworkReplyPrivate()
\fn void QNetworkReply::redirected(const QUrl &url)
\since 5.6
- This signal is emitted if the QNetworkRequest::ManualRedirectPolicy was
+ This signal is emitted if the QNetworkRequest::ManualRedirectPolicy was not
set in the request and the server responded with a 3xx status (specifically
301, 302, 303, 305, 307 or 308 status code) with a valid url in the location
header, indicating a HTTP redirect. The \a url parameter contains the new
@@ -322,6 +288,27 @@ QNetworkReplyPrivate::QNetworkReplyPrivate()
*/
/*!
+ \fn void QNetworkReply::socketStartedConnecting()
+ \since 6.3
+
+ This signal is emitted 0 or more times, when the socket
+ is connecting, before sending the request. Useful for
+ custom progress or timeout handling.
+
+ \sa metaDataChanged(), requestSent()
+*/
+
+/*!
+ \fn void QNetworkReply::requestSent()
+ \since 6.3
+
+ This signal is emitted 1 or more times when the request was
+ sent. Useful for custom progress or timeout handling.
+
+ \sa metaDataChanged(), socketStartedConnecting()
+*/
+
+/*!
\fn void QNetworkReply::metaDataChanged()
\omit FIXME: Update name? \endomit
@@ -344,7 +331,7 @@ QNetworkReplyPrivate::QNetworkReplyPrivate()
processing. After this signal is emitted, there will be no more
updates to the reply's data or metadata.
- Unless close() or abort() have been called, the reply will be still be opened
+ Unless close() or abort() have been called, the reply will still be opened
for reading, so the data can be retrieved by calls to read() or
readAll(). In particular, if no calls to read() were made as a
result of readyRead(), a call to readAll() will retrieve the full
@@ -625,8 +612,9 @@ QVariant QNetworkReply::header(QNetworkRequest::KnownHeaders header) const
the remote server
\sa rawHeader()
+ \note In Qt versions prior to 6.7, this function took QByteArray only.
*/
-bool QNetworkReply::hasRawHeader(const QByteArray &headerName) const
+bool QNetworkReply::hasRawHeader(QAnyStringView headerName) const
{
Q_D(const QNetworkReply);
return d->findRawHeader(headerName) != d->rawHeaders.constEnd();
@@ -640,13 +628,12 @@ bool QNetworkReply::hasRawHeader(const QByteArray &headerName) const
header field.
\sa setRawHeader(), hasRawHeader(), header()
+ \note In Qt versions prior to 6.7, this function took QByteArray only.
*/
-QByteArray QNetworkReply::rawHeader(const QByteArray &headerName) const
+QByteArray QNetworkReply::rawHeader(QAnyStringView headerName) const
{
Q_D(const QNetworkReply);
- QNetworkHeadersPrivate::RawHeadersList::ConstIterator it =
- d->findRawHeader(headerName);
- if (it != d->rawHeaders.constEnd())
+ if (const auto it = d->findRawHeader(headerName); it != d->rawHeaders.constEnd())
return it->second;
return QByteArray();
}
@@ -946,3 +933,5 @@ void QNetworkReply::setAttribute(QNetworkRequest::Attribute code, const QVariant
}
QT_END_NAMESPACE
+
+#include "moc_qnetworkreply.cpp"
diff --git a/src/network/access/qnetworkreply.h b/src/network/access/qnetworkreply.h
index 2587696715..390a6f2f51 100644
--- a/src/network/access/qnetworkreply.h
+++ b/src/network/access/qnetworkreply.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNETWORKREPLY_H
#define QNETWORKREPLY_H
@@ -133,9 +97,15 @@ public:
QVariant header(QNetworkRequest::KnownHeaders header) const;
// raw headers:
+#if QT_NETWORK_REMOVED_SINCE(6, 7)
bool hasRawHeader(const QByteArray &headerName) const;
+#endif
+ bool hasRawHeader(QAnyStringView headerName) const;
QList<QByteArray> rawHeaderList() const;
+#if QT_NETWORK_REMOVED_SINCE(6, 7)
QByteArray rawHeader(const QByteArray &headerName) const;
+#endif
+ QByteArray rawHeader(QAnyStringView headerName) const;
typedef QPair<QByteArray, QByteArray> RawHeaderPair;
const QList<RawHeaderPair>& rawHeaderPairs() const;
@@ -154,6 +124,8 @@ public Q_SLOTS:
virtual void ignoreSslErrors();
Q_SIGNALS:
+ void socketStartedConnecting();
+ void requestSent();
void metaDataChanged();
void finished();
void errorOccurred(QNetworkReply::NetworkError);
@@ -194,6 +166,7 @@ private:
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QNetworkReply::NetworkError)
+QT_DECL_METATYPE_EXTERN_TAGGED(QNetworkReply::NetworkError,
+ QNetworkReply__NetworkError, Q_NETWORK_EXPORT)
#endif
diff --git a/src/network/access/qnetworkreply_p.h b/src/network/access/qnetworkreply_p.h
index 3b3bb3dfa4..f9bbfcbc6b 100644
--- a/src/network/access/qnetworkreply_p.h
+++ b/src/network/access/qnetworkreply_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNETWORKREPLY_P_H
#define QNETWORKREPLY_P_H
diff --git a/src/network/access/qnetworkreplydataimpl.cpp b/src/network/access/qnetworkreplydataimpl.cpp
index 2f75020446..7cb7621bca 100644
--- a/src/network/access/qnetworkreplydataimpl.cpp
+++ b/src/network/access/qnetworkreplydataimpl.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qnetworkreplydataimpl_p.h"
#include "private/qdataurl_p.h"
diff --git a/src/network/access/qnetworkreplydataimpl_p.h b/src/network/access/qnetworkreplydataimpl_p.h
index 81d2110d69..35fd38aece 100644
--- a/src/network/access/qnetworkreplydataimpl_p.h
+++ b/src/network/access/qnetworkreplydataimpl_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNETWORKREPLYDATAIMPL_H
#define QNETWORKREPLYDATAIMPL_H
diff --git a/src/network/access/qnetworkreplyfileimpl.cpp b/src/network/access/qnetworkreplyfileimpl.cpp
index b6be93147a..e6208a5c85 100644
--- a/src/network/access/qnetworkreplyfileimpl.cpp
+++ b/src/network/access/qnetworkreplyfileimpl.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qnetworkreplyfileimpl_p.h"
@@ -49,6 +13,10 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
+QT_IMPL_METATYPE_EXTERN_TAGGED(QNetworkRequest::KnownHeaders, QNetworkRequest__KnownHeaders)
+
QNetworkReplyFileImplPrivate::QNetworkReplyFileImplPrivate()
: QNetworkReplyPrivate(), managerPrivate(nullptr), realFile(nullptr)
{
@@ -80,7 +48,7 @@ QNetworkReplyFileImpl::QNetworkReplyFileImpl(QNetworkAccessManager *manager, con
d->managerPrivate = manager->d_func();
QUrl url = req.url();
- if (url.host() == QLatin1String("localhost"))
+ if (url.host() == "localhost"_L1)
url.setHost(QString());
#if !defined(Q_OS_WIN)
@@ -89,25 +57,26 @@ QNetworkReplyFileImpl::QNetworkReplyFileImpl(QNetworkAccessManager *manager, con
// we handle only local files
QString msg = QCoreApplication::translate("QNetworkAccessFileBackend", "Request for opening non-local file %1").arg(url.toString());
setError(QNetworkReply::ProtocolInvalidOperationError, msg);
+ setFinished(true); // We're finished, will emit finished() after ctor is done.
QMetaObject::invokeMethod(this, "errorOccurred", Qt::QueuedConnection,
Q_ARG(QNetworkReply::NetworkError, QNetworkReply::ProtocolInvalidOperationError));
- fileOpenFinished(false);
+ QMetaObject::invokeMethod(this, &QNetworkReplyFileImpl::fileOpenFinished, Qt::QueuedConnection, false);
return;
}
#endif
if (url.path().isEmpty())
- url.setPath(QLatin1String("/"));
+ url.setPath("/"_L1);
setUrl(url);
QString fileName = url.toLocalFile();
if (fileName.isEmpty()) {
const QString scheme = url.scheme();
- if (scheme == QLatin1String("qrc")) {
- fileName = QLatin1Char(':') + url.path();
+ if (scheme == "qrc"_L1) {
+ fileName = u':' + url.path();
} else {
#if defined(Q_OS_ANDROID)
- if (scheme == QLatin1String("assets"))
- fileName = QLatin1String("assets:") + url.path();
+ if (scheme == "assets"_L1)
+ fileName = "assets:"_L1 + url.path();
else
#endif
fileName = url.toString(QUrl::RemoveAuthority | QUrl::RemoveFragment | QUrl::RemoveQuery);
@@ -222,7 +191,7 @@ qint64 QNetworkReplyFileImpl::readData(char *data, qint64 maxlen)
return -1;
else {
setAttribute(QNetworkRequest::HttpStatusCodeAttribute, 200);
- setAttribute(QNetworkRequest::HttpReasonPhraseAttribute, QLatin1String("OK"));
+ setAttribute(QNetworkRequest::HttpReasonPhraseAttribute, "OK"_L1);
return ret;
}
}
diff --git a/src/network/access/qnetworkreplyfileimpl_p.h b/src/network/access/qnetworkreplyfileimpl_p.h
index 48d82abd3f..6413903d8f 100644
--- a/src/network/access/qnetworkreplyfileimpl_p.h
+++ b/src/network/access/qnetworkreplyfileimpl_p.h
@@ -1,44 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QNETWORKREPLYFILEIMPL_H
-#define QNETWORKREPLYFILEIMPL_H
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QNETWORKREPLYFILEIMPL_P_H
+#define QNETWORKREPLYFILEIMPL_P_H
//
// W A R N I N G
@@ -55,7 +19,9 @@
#include "qnetworkreply.h"
#include "qnetworkreply_p.h"
#include "qnetworkaccessmanager.h"
+
#include <QFile>
+#include <QtCore/qpointer.h>
#include <private/qabstractfileengine_p.h>
QT_BEGIN_NAMESPACE
@@ -97,6 +63,8 @@ public:
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QNetworkRequest::KnownHeaders)
+// ### move to qnetworkrequest.h
+QT_DECL_METATYPE_EXTERN_TAGGED(QNetworkRequest::KnownHeaders,
+ QNetworkRequest__KnownHeaders, Q_NETWORK_EXPORT)
-#endif // QNETWORKREPLYFILEIMPL_H
+#endif // QNETWORKREPLYFILEIMPL_P_H
diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp
index 921b482d10..1eee98f834 100644
--- a/src/network/access/qnetworkreplyhttpimpl.cpp
+++ b/src/network/access/qnetworkreplyhttpimpl.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//#define QNETWORKACCESSHTTPBACKEND_DEBUG
@@ -57,6 +21,7 @@
#include "QtCore/qcoreapplication.h"
#include <QtCore/private/qthread_p.h>
+#include <QtCore/private/qtools_p.h>
#include "qnetworkcookiejar.h"
#include "qnetconmonitor_p.h"
@@ -67,16 +32,18 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+using namespace QtMiscUtils;
+using namespace std::chrono_literals;
+
class QNetworkProxy;
-static inline bool isSeparator(char c)
-{
- static const char separators[] = "()<>@,;:\\\"/[]?={}";
- return isLWS(c) || strchr(separators, c) != nullptr;
-}
+static inline QByteArray rangeName() { return "Range"_ba; }
+static inline QByteArray cacheControlName() { return "Cache-Control"_ba; }
+static constexpr QByteArrayView bytesEqualPrefix() noexcept { return "bytes="; }
// ### merge with nextField in cookiejar.cpp
-static QHash<QByteArray, QByteArray> parseHttpOptionHeader(const QByteArray &header)
+static QHash<QByteArray, QByteArray> parseHttpOptionHeader(QByteArrayView header)
{
// The HTTP header is of the form:
// header = #1(directives)
@@ -88,7 +55,7 @@ static QHash<QByteArray, QByteArray> parseHttpOptionHeader(const QByteArray &hea
while (true) {
// skip spaces
pos = nextNonWhitespace(header, pos);
- if (pos == header.length())
+ if (pos == header.size())
return result; // end of parsing
// pos points to a non-whitespace
@@ -102,36 +69,36 @@ static QHash<QByteArray, QByteArray> parseHttpOptionHeader(const QByteArray &hea
// of the header, whichever comes first
int end = comma;
if (end == -1)
- end = header.length();
+ end = header.size();
if (equal != -1 && end > equal)
end = equal; // equal sign comes before comma/end
- QByteArray key = QByteArray(header.constData() + pos, end - pos).trimmed().toLower();
+ const auto key = header.sliced(pos, end - pos).trimmed();
pos = end + 1;
if (uint(equal) < uint(comma)) {
// case: token "=" (token | quoted-string)
// skip spaces
pos = nextNonWhitespace(header, pos);
- if (pos == header.length())
+ if (pos == header.size())
// huh? Broken header
return result;
QByteArray value;
- value.reserve(header.length() - pos);
+ value.reserve(header.size() - pos);
if (header.at(pos) == '"') {
// case: quoted-string
// quoted-string = ( <"> *(qdtext | quoted-pair ) <"> )
// qdtext = <any TEXT except <">>
// quoted-pair = "\" CHAR
++pos;
- while (pos < header.length()) {
+ while (pos < header.size()) {
char c = header.at(pos);
if (c == '"') {
// end of quoted text
break;
} else if (c == '\\') {
++pos;
- if (pos >= header.length())
+ if (pos >= header.size())
// broken header
return result;
c = header.at(pos);
@@ -141,8 +108,13 @@ static QHash<QByteArray, QByteArray> parseHttpOptionHeader(const QByteArray &hea
++pos;
}
} else {
+ const auto isSeparator = [](char c) {
+ static const char separators[] = "()<>@,;:\\\"/[]?={}";
+ return isLWS(c) || strchr(separators, c) != nullptr;
+ };
+
// case: token
- while (pos < header.length()) {
+ while (pos < header.size()) {
char c = header.at(pos);
if (isSeparator(c))
break;
@@ -151,7 +123,7 @@ static QHash<QByteArray, QByteArray> parseHttpOptionHeader(const QByteArray &hea
}
}
- result.insert(key, value);
+ result.insert(key.toByteArray().toLower(), value);
// find the comma now:
comma = header.indexOf(',', pos);
@@ -161,7 +133,7 @@ static QHash<QByteArray, QByteArray> parseHttpOptionHeader(const QByteArray &hea
} else {
// case: token
// key is already set
- result.insert(key, QByteArray());
+ result.insert(key.toByteArray().toLower(), QByteArray());
}
}
}
@@ -182,10 +154,13 @@ QNetworkReplyHttpImpl::QNetworkReplyHttpImpl(QNetworkAccessManager* const manage
d->outgoingData = outgoingData;
d->url = request.url();
#ifndef QT_NO_SSL
- if (request.url().scheme() == QLatin1String("https"))
+ if (request.url().scheme() == "https"_L1)
d->sslConfiguration.reset(new QSslConfiguration(request.sslConfiguration()));
#endif
+ QObjectPrivate::connect(this, &QNetworkReplyHttpImpl::redirectAllowed, d,
+ &QNetworkReplyHttpImplPrivate::followRedirect, Qt::QueuedConnection);
+
// FIXME Later maybe set to Unbuffered, especially if it is zerocopy or from cache?
QIODevice::open(QIODevice::ReadOnly);
@@ -199,7 +174,7 @@ QNetworkReplyHttpImpl::QNetworkReplyHttpImpl(QNetworkAccessManager* const manage
if (d->synchronous && outgoingData) {
// The synchronous HTTP is a corner case, we will put all upload data in one big QByteArray in the outgoingDataBuffer.
// Yes, this is not the most efficient thing to do, but on the other hand synchronous XHR needs to die anyway.
- d->outgoingDataBuffer = QSharedPointer<QRingBuffer>::create();
+ d->outgoingDataBuffer = std::make_shared<QRingBuffer>();
qint64 previousDataSize = 0;
do {
previousDataSize = d->outgoingDataBuffer->size();
@@ -305,6 +280,13 @@ qint64 QNetworkReplyHttpImpl::bytesAvailable() const
return QNetworkReply::bytesAvailable() + d->downloadBufferCurrentSize - d->downloadBufferReadPosition;
}
+ if (d->decompressHelper.isValid()) {
+ if (d->decompressHelper.isCountingBytes())
+ return QNetworkReply::bytesAvailable() + d->decompressHelper.uncompressedSize();
+ if (d->decompressHelper.hasData())
+ return QNetworkReply::bytesAvailable() + 1;
+ }
+
// normal buffer
return QNetworkReply::bytesAvailable();
}
@@ -345,6 +327,32 @@ qint64 QNetworkReplyHttpImpl::readData(char* data, qint64 maxlen)
}
+ if (d->decompressHelper.isValid() && (d->decompressHelper.hasData() || !isFinished())) {
+ if (maxlen == 0 || !d->decompressHelper.hasData())
+ return 0;
+ const qint64 bytesRead = d->decompressHelper.read(data, maxlen);
+ if (!d->decompressHelper.isValid()) {
+ d->error(QNetworkReplyImpl::NetworkError::UnknownContentError,
+ QCoreApplication::translate("QHttp", "Decompression failed: %1")
+ .arg(d->decompressHelper.errorString()));
+ d->decompressHelper.clear();
+ return -1;
+ }
+ if (d->cacheSaveDevice) {
+ // Need to write to the cache now that we have the data
+ d->cacheSaveDevice->write(data, bytesRead);
+ // ... and if we've read everything then the cache can be closed.
+ if (isFinished() && !d->decompressHelper.hasData())
+ d->completeCacheSave();
+ }
+ // In case of buffer size restriction we need to emit that it has been emptied
+ qint64 wasBuffered = d->bytesBuffered;
+ d->bytesBuffered = 0;
+ if (readBufferSize())
+ emit readBufferFreed(wasBuffered);
+ return bytesRead;
+ }
+
// normal buffer
if (d->state == d->Finished || d->state == d->Aborted)
return -1;
@@ -447,8 +455,8 @@ QNetworkReplyHttpImplPrivate::QNetworkReplyHttpImplPrivate()
, downloadBufferReadPosition(0)
, downloadBufferCurrentSize(0)
, downloadZerocopyBuffer(nullptr)
- , pendingDownloadDataEmissions(QSharedPointer<QAtomicInt>::create())
- , pendingDownloadProgressEmissions(QSharedPointer<QAtomicInt>::create())
+ , pendingDownloadDataEmissions(std::make_shared<QAtomicInt>())
+ , pendingDownloadProgressEmissions(std::make_shared<QAtomicInt>())
#ifndef QT_NO_SSL
, pendingIgnoreAllSslErrors(false)
#endif
@@ -473,16 +481,17 @@ bool QNetworkReplyHttpImplPrivate::loadFromCacheIfAllowed(QHttpNetworkRequest &h
if (CacheLoadControlAttribute == QNetworkRequest::AlwaysNetwork) {
// If the request does not already specify preferred cache-control
// force reload from the network and tell any caching proxy servers to reload too
- if (!request.rawHeaderList().contains("Cache-Control")) {
- httpRequest.setHeaderField("Cache-Control", "no-cache");
- httpRequest.setHeaderField("Pragma", "no-cache");
+ if (!request.rawHeaderList().contains(cacheControlName())) {
+ const auto noCache = "no-cache"_ba;
+ httpRequest.setHeaderField(cacheControlName(), noCache);
+ httpRequest.setHeaderField("Pragma"_ba, noCache);
}
return false;
}
// The disk cache API does not currently support partial content retrieval.
// That is why we don't use the disk cache for any such requests.
- if (request.hasRawHeader("Range"))
+ if (request.hasRawHeader(rangeName()))
return false;
QAbstractNetworkCache *nc = managerPrivate->networkCache;
@@ -500,20 +509,27 @@ bool QNetworkReplyHttpImplPrivate::loadFromCacheIfAllowed(QHttpNetworkRequest &h
QNetworkHeadersPrivate::RawHeadersList::ConstIterator it;
cacheHeaders.setAllRawHeaders(metaData.rawHeaders());
+ it = cacheHeaders.findRawHeader("content-length");
+ if (it != cacheHeaders.rawHeaders.constEnd()) {
+ std::unique_ptr<QIODevice> data(nc->data(httpRequest.url()));
+ if (!data || data->size() < it->second.toLongLong())
+ return false; // The data is smaller than the content-length specified
+ }
+
it = cacheHeaders.findRawHeader("etag");
if (it != cacheHeaders.rawHeaders.constEnd())
- httpRequest.setHeaderField("If-None-Match", it->second);
+ httpRequest.setHeaderField("If-None-Match"_ba, it->second);
QDateTime lastModified = metaData.lastModified();
if (lastModified.isValid())
- httpRequest.setHeaderField("If-Modified-Since", QNetworkHeadersPrivate::toHttpDate(lastModified));
+ httpRequest.setHeaderField("If-Modified-Since"_ba, QNetworkHeadersPrivate::toHttpDate(lastModified));
- it = cacheHeaders.findRawHeader("Cache-Control");
+ it = cacheHeaders.findRawHeader(cacheControlName());
if (it != cacheHeaders.rawHeaders.constEnd()) {
QHash<QByteArray, QByteArray> cacheControl = parseHttpOptionHeader(it->second);
- if (cacheControl.contains("must-revalidate"))
+ if (cacheControl.contains("must-revalidate"_ba))
return false;
- if (cacheControl.contains("no-cache"))
+ if (cacheControl.contains("no-cache"_ba))
return false;
}
@@ -568,10 +584,11 @@ bool QNetworkReplyHttpImplPrivate::loadFromCacheIfAllowed(QHttpNetworkRequest &h
if (lastModified.isValid() && dateHeader.isValid()) {
qint64 diff = lastModified.secsTo(dateHeader);
freshness_lifetime = diff / 10;
- if (httpRequest.headerField("Warning").isEmpty()) {
+ const auto warningHeader = "Warning"_ba;
+ if (httpRequest.headerField(warningHeader).isEmpty()) {
QDateTime dt = currentDateTime.addSecs(current_age);
if (currentDateTime.daysTo(dt) > 1)
- httpRequest.setHeaderField("Warning", "113");
+ httpRequest.setHeaderField(warningHeader, "113"_ba);
}
}
@@ -627,13 +644,11 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq
httpRequest.setRedirectCount(newHttpRequest.maximumRedirectsAllowed());
QString scheme = url.scheme();
- bool ssl = (scheme == QLatin1String("https")
- || scheme == QLatin1String("preconnect-https"));
+ bool ssl = (scheme == "https"_L1 || scheme == "preconnect-https"_L1);
q->setAttribute(QNetworkRequest::ConnectionEncryptedAttribute, ssl);
httpRequest.setSsl(ssl);
- bool preConnect = (scheme == QLatin1String("preconnect-http")
- || scheme == QLatin1String("preconnect-https"));
+ bool preConnect = (scheme == "preconnect-http"_L1 || scheme == "preconnect-https"_L1);
httpRequest.setPreConnect(preConnect);
#ifndef QT_NO_NETWORKPROXY
@@ -680,12 +695,18 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq
httpRequest.setRedirectPolicy(redirectPolicy);
httpRequest.setPriority(convert(newHttpRequest.priority()));
+ loadingFromCache = false;
switch (operation) {
case QNetworkAccessManager::GetOperation:
httpRequest.setOperation(QHttpNetworkRequest::Get);
- if (loadFromCacheIfAllowed(httpRequest))
+ // If the request has a body, createUploadByteDevice() and don't use caching
+ if (outgoingData) {
+ invalidateCache();
+ createUploadByteDevice();
+ } else if (loadFromCacheIfAllowed(httpRequest)) {
return; // no need to send the request! :)
+ }
break;
case QNetworkAccessManager::HeadOperation:
@@ -725,14 +746,15 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq
QList<QByteArray> headers = newHttpRequest.rawHeaderList();
if (resumeOffset != 0) {
- const int rangeIndex = headers.indexOf("Range");
+ const int rangeIndex = headers.indexOf(rangeName());
if (rangeIndex != -1) {
// Need to adjust resume offset for user specified range
headers.removeAt(rangeIndex);
// We've already verified that requestRange starts with "bytes=", see canResume.
- QByteArray requestRange = newHttpRequest.rawHeader("Range").mid(6);
+ const auto rangeHeader = newHttpRequest.rawHeader(rangeName());
+ const auto requestRange = QByteArrayView(rangeHeader).mid(bytesEqualPrefix().size());
int index = requestRange.indexOf('-');
@@ -740,16 +762,16 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq
quint64 requestEndOffset = requestRange.mid(index + 1).toULongLong();
// In case an end offset is not given it is skipped from the request range
- requestRange = "bytes=" + QByteArray::number(resumeOffset + requestStartOffset) +
+ QByteArray newRange = bytesEqualPrefix() + QByteArray::number(resumeOffset + requestStartOffset) +
'-' + (requestEndOffset ? QByteArray::number(requestEndOffset) : QByteArray());
- httpRequest.setHeaderField("Range", requestRange);
+ httpRequest.setHeaderField(rangeName(), newRange);
} else {
- httpRequest.setHeaderField("Range", "bytes=" + QByteArray::number(resumeOffset) + '-');
+ httpRequest.setHeaderField(rangeName(), bytesEqualPrefix() + QByteArray::number(resumeOffset) + '-');
}
}
- for (const QByteArray &header : qAsConst(headers))
+ for (const QByteArray &header : std::as_const(headers))
httpRequest.setHeaderField(header, newHttpRequest.rawHeader(header));
if (newHttpRequest.attribute(QNetworkRequest::HttpPipeliningAllowedAttribute).toBool())
@@ -759,6 +781,12 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq
allowed.isValid() && allowed.canConvert<bool>()) {
httpRequest.setHTTP2Allowed(allowed.value<bool>());
}
+ auto h2cAttribute = request.attribute(QNetworkRequest::Http2CleartextAllowedAttribute);
+ // ### Qt7: Stop checking the environment variable
+ if (h2cAttribute.toBool()
+ || (!h2cAttribute.isValid() && qEnvironmentVariableIsSet("QT_NETWORK_H2C_ALLOWED"))) {
+ httpRequest.setH2cAllowed(true);
+ }
if (request.attribute(QNetworkRequest::Http2DirectAttribute).toBool()) {
// Intentionally mutually exclusive - cannot be both direct and 'allowed'
@@ -774,24 +802,30 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq
if (request.attribute(QNetworkRequest::EmitAllUploadProgressSignalsAttribute).toBool())
emitAllUploadProgressSignals = true;
- // For internal use/testing
- auto ignoreDownloadRatio =
- request.attribute(QNetworkRequest::Attribute(QNetworkRequest::User - 1));
- if (!ignoreDownloadRatio.isNull() && ignoreDownloadRatio.canConvert<QByteArray>()
- && ignoreDownloadRatio.toByteArray() == "__qdecompresshelper_ignore_download_ratio") {
- httpRequest.setIgnoreDecompressionRatio(true);
- }
-
httpRequest.setPeerVerifyName(newHttpRequest.peerVerifyName());
// Create the HTTP thread delegate
QHttpThreadDelegate *delegate = new QHttpThreadDelegate;
// Propagate Http/2 settings:
delegate->http2Parameters = request.http2Configuration();
+ delegate->http1Parameters = request.http1Configuration();
+
+ if (request.attribute(QNetworkRequest::ConnectionCacheExpiryTimeoutSecondsAttribute).isValid())
+ delegate->connectionCacheExpiryTimeoutSeconds = request.attribute(QNetworkRequest::ConnectionCacheExpiryTimeoutSecondsAttribute).toInt();
// For the synchronous HTTP, this is the normal way the delegate gets deleted
// For the asynchronous HTTP this is a safety measure, the delegate deletes itself when HTTP is finished
- QObject::connect(thread, SIGNAL(finished()), delegate, SLOT(deleteLater()));
+ QMetaObject::Connection threadFinishedConnection =
+ QObject::connect(thread, SIGNAL(finished()), delegate, SLOT(deleteLater()));
+
+ // QTBUG-88063: When 'delegate' is deleted the connection will be added to 'thread''s orphaned
+ // connections list. This orphaned list will be cleaned up next time 'thread' emits a signal,
+ // unfortunately that's the finished signal. It leads to a soft-leak so we do this to disconnect
+ // it on deletion so that it cleans up the orphan immediately.
+ QObject::connect(delegate, &QObject::destroyed, delegate, [threadFinishedConnection]() {
+ if (bool(threadFinishedConnection))
+ QObject::disconnect(threadFinishedConnection);
+ });
// Set the properties it needs
delegate->httpRequest = httpRequest;
@@ -836,14 +870,12 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq
QObject::connect(delegate, SIGNAL(downloadFinished()),
q, SLOT(replyFinished()),
Qt::QueuedConnection);
- QObject::connect(delegate, SIGNAL(downloadMetaData(QList<QPair<QByteArray,QByteArray> >,
- int, QString, bool,
- QSharedPointer<char>, qint64, qint64,
- bool)),
- q, SLOT(replyDownloadMetaData(QList<QPair<QByteArray,QByteArray> >,
- int, QString, bool,
- QSharedPointer<char>, qint64, qint64, bool)),
- Qt::QueuedConnection);
+ QObject::connect(delegate, &QHttpThreadDelegate::socketStartedConnecting,
+ q, &QNetworkReply::socketStartedConnecting, Qt::QueuedConnection);
+ QObject::connect(delegate, &QHttpThreadDelegate::requestSent,
+ q, &QNetworkReply::requestSent, Qt::QueuedConnection);
+ connect(delegate, &QHttpThreadDelegate::downloadMetaData, this,
+ &QNetworkReplyHttpImplPrivate::replyDownloadMetaData, Qt::QueuedConnection);
QObject::connect(delegate, SIGNAL(downloadProgress(qint64,qint64)),
q, SLOT(replyDownloadProgressSlot(qint64,qint64)),
Qt::QueuedConnection);
@@ -854,9 +886,6 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq
q, SLOT(onRedirected(QUrl,int,int)),
Qt::QueuedConnection);
- QObject::connect(q, SIGNAL(redirectAllowed()), q, SLOT(followRedirect()),
- Qt::QueuedConnection);
-
#ifndef QT_NO_SSL
QObject::connect(delegate, SIGNAL(sslConfigurationChanged(QSslConfiguration)),
q, SLOT(replySslConfigurationChanged(QSslConfiguration)),
@@ -896,14 +925,14 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq
delegate->httpRequest.setUploadByteDevice(forwardUploadDevice);
// If the device in the user thread claims it has more data, keep the flow to HTTP thread going
- QObject::connect(uploadByteDevice.data(), SIGNAL(readyRead()),
+ QObject::connect(uploadByteDevice.get(), SIGNAL(readyRead()),
q, SLOT(uploadByteDeviceReadyReadSlot()),
Qt::QueuedConnection);
// From user thread to http thread:
QObject::connect(q, SIGNAL(haveUploadData(qint64,QByteArray,bool,qint64)),
forwardUploadDevice, SLOT(haveDataSlot(qint64,QByteArray,bool,qint64)), Qt::QueuedConnection);
- QObject::connect(uploadByteDevice.data(), SIGNAL(readyRead()),
+ QObject::connect(uploadByteDevice.get(), SIGNAL(readyRead()),
forwardUploadDevice, SIGNAL(readyRead()),
Qt::QueuedConnection);
@@ -926,7 +955,7 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq
// use the uploadByteDevice provided to us by the QNetworkReplyImpl.
// The code that is in start() makes sure it is safe to use from a thread
// since it only wraps a QRingBuffer
- delegate->httpRequest.setUploadByteDevice(uploadByteDevice.data());
+ delegate->httpRequest.setUploadByteDevice(uploadByteDevice.get());
}
}
@@ -943,30 +972,20 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq
if (synchronous) {
emit q->startHttpRequestSynchronously(); // This one is BlockingQueuedConnection, so it will return when all work is done
- if (delegate->incomingErrorCode != QNetworkReply::NoError) {
- replyDownloadMetaData
- (delegate->incomingHeaders,
- delegate->incomingStatusCode,
- delegate->incomingReasonPhrase,
- delegate->isPipeliningUsed,
- QSharedPointer<char>(),
- delegate->incomingContentLength,
- delegate->removedContentLength,
- delegate->isHttp2Used);
- replyDownloadData(delegate->synchronousDownloadData);
+ replyDownloadMetaData
+ (delegate->incomingHeaders,
+ delegate->incomingStatusCode,
+ delegate->incomingReasonPhrase,
+ delegate->isPipeliningUsed,
+ QSharedPointer<char>(),
+ delegate->incomingContentLength,
+ delegate->removedContentLength,
+ delegate->isHttp2Used,
+ delegate->isCompressed);
+ replyDownloadData(delegate->synchronousDownloadData);
+
+ if (delegate->incomingErrorCode != QNetworkReply::NoError)
httpError(delegate->incomingErrorCode, delegate->incomingErrorDetail);
- } else {
- replyDownloadMetaData
- (delegate->incomingHeaders,
- delegate->incomingStatusCode,
- delegate->incomingReasonPhrase,
- delegate->isPipeliningUsed,
- QSharedPointer<char>(),
- delegate->incomingContentLength,
- delegate->removedContentLength,
- delegate->isHttp2Used);
- replyDownloadData(delegate->synchronousDownloadData);
- }
thread->quit();
thread->wait(QDeadlineTimer(5000));
@@ -1037,23 +1056,79 @@ void QNetworkReplyHttpImplPrivate::replyDownloadData(QByteArray d)
if (!q->isOpen())
return;
+ // cache this, we need it later and it's invalidated when dealing with compressed data
+ auto dataSize = d.size();
+
if (cacheEnabled && isCachingAllowed() && !cacheSaveDevice)
initCacheSaveDevice();
+ if (decompressHelper.isValid()) {
+ qint64 uncompressedBefore = -1;
+ if (decompressHelper.isCountingBytes())
+ uncompressedBefore = decompressHelper.uncompressedSize();
+
+ decompressHelper.feed(std::move(d));
+
+ if (!decompressHelper.isValid()) {
+ error(QNetworkReplyImpl::NetworkError::UnknownContentError,
+ QCoreApplication::translate("QHttp", "Decompression failed: %1")
+ .arg(decompressHelper.errorString()));
+ decompressHelper.clear();
+ return;
+ }
+
+ if (!isHttpRedirectResponse()) {
+ if (decompressHelper.isCountingBytes())
+ bytesDownloaded += (decompressHelper.uncompressedSize() - uncompressedBefore);
+ setupTransferTimeout();
+ }
+
+ if (synchronous) {
+ d = QByteArray();
+ const qsizetype increments = 16 * 1024;
+ qint64 bytesRead = 0;
+ while (decompressHelper.hasData()) {
+ quint64 nextSize = quint64(d.size()) + quint64(increments);
+ if (nextSize > quint64(std::numeric_limits<QByteArray::size_type>::max())) {
+ error(QNetworkReplyImpl::NetworkError::UnknownContentError,
+ QCoreApplication::translate("QHttp",
+ "Data downloaded is too large to store"));
+ decompressHelper.clear();
+ return;
+ }
+ d.resize(nextSize);
+ bytesRead += decompressHelper.read(d.data() + bytesRead, increments);
+ if (!decompressHelper.isValid()) {
+ error(QNetworkReplyImpl::NetworkError::UnknownContentError,
+ QCoreApplication::translate("QHttp", "Decompression failed: %1")
+ .arg(decompressHelper.errorString()));
+ decompressHelper.clear();
+ return;
+ }
+ }
+ d.resize(bytesRead);
+ // we're synchronous so we're not calling this function again; reset the decompressHelper
+ decompressHelper.clear();
+ }
+ }
+
// This is going to look a little strange. When downloading data while a
// HTTP redirect is happening (and enabled), we write the redirect
// response to the cache. However, we do not append it to our internal
// buffer as that will contain the response data only for the final
// response
- if (cacheSaveDevice)
+ // Note: For compressed data this is done in readData()
+ if (cacheSaveDevice && !decompressHelper.isValid()) {
cacheSaveDevice->write(d);
+ }
- if (!isHttpRedirectResponse()) {
+ // if decompressHelper is valid then we have compressed data, and this is handled above
+ if (!decompressHelper.isValid() && !isHttpRedirectResponse()) {
buffer.append(d);
- bytesDownloaded += d.size();
+ bytesDownloaded += dataSize;
setupTransferTimeout();
}
- bytesBuffered += d.size();
+ bytesBuffered += dataSize;
int pendingSignals = pendingDownloadDataEmissions->fetchAndSubAcquire(1) - 1;
if (pendingSignals > 0) {
@@ -1067,17 +1142,26 @@ void QNetworkReplyHttpImplPrivate::replyDownloadData(QByteArray d)
if (isHttpRedirectResponse())
return;
+ // This can occur when downloading compressed data as some of the data may be the content
+ // encoding's header. Don't emit anything for this.
+ if (lastReadyReadEmittedSize == bytesDownloaded) {
+ if (readBufferMaxSize)
+ emit q->readBufferFreed(dataSize);
+ return;
+ }
+ lastReadyReadEmittedSize = bytesDownloaded;
+
QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader);
emit q->readyRead();
- // emit readyRead before downloadProgress incase this will cause events to be
+ // emit readyRead before downloadProgress in case this will cause events to be
// processed and we get into a recursive call (as in QProgressDialog).
- if (downloadProgressSignalChoke.elapsed() >= progressSignalInterval) {
+ if (downloadProgressSignalChoke.elapsed() >= progressSignalInterval
+ && (!decompressHelper.isValid() || decompressHelper.isCountingBytes())) {
downloadProgressSignalChoke.restart();
emit q->downloadProgress(bytesDownloaded,
totalSize.isNull() ? Q_INT64_C(-1) : totalSize.toLongLong());
}
-
}
void QNetworkReplyHttpImplPrivate::replyFinished()
@@ -1148,13 +1232,12 @@ void QNetworkReplyHttpImplPrivate::onRedirected(const QUrl &redirectUrl, int htt
// equal to "80", the port component value MUST be preserved;
// otherwise, if the URI does not contain an explicit port
// component, the UA MUST NOT add one.
- url.setScheme(QLatin1String("https"));
+ url.setScheme("https"_L1);
if (url.port() == 80)
url.setPort(443);
}
- const bool isLessSafe = schemeBefore == QLatin1String("https")
- && url.scheme() == QLatin1String("http");
+ const bool isLessSafe = schemeBefore == "https"_L1 && url.scheme() == "http"_L1;
if (httpRequest.redirectPolicy() == QNetworkRequest::NoLessSafeRedirectPolicy
&& isLessSafe) {
error(QNetworkReply::InsecureRedirectError,
@@ -1162,13 +1245,18 @@ void QNetworkReplyHttpImplPrivate::onRedirected(const QUrl &redirectUrl, int htt
return;
}
+ // If the original operation was a GET with a body and the status code is either
+ // 307 or 308 then keep the message body
+ const bool getOperationKeepsBody = (operation == QNetworkAccessManager::GetOperation)
+ && (httpStatus == 307 || httpStatus == 308);
+
redirectRequest = createRedirectRequest(originalRequest, url, maxRedirectsRemaining);
operation = getRedirectOperation(operation, httpStatus);
// Clear stale headers, the relevant ones get set again later
httpRequest.clearHeaders();
- if (operation == QNetworkAccessManager::GetOperation
- || operation == QNetworkAccessManager::HeadOperation) {
+ if ((operation == QNetworkAccessManager::GetOperation
+ || operation == QNetworkAccessManager::HeadOperation) && !getOperationKeepsBody) {
// possibly changed from not-GET/HEAD to GET/HEAD, make sure to get rid of upload device
uploadByteDevice.reset();
uploadByteDevicePosition = 0;
@@ -1204,6 +1292,7 @@ void QNetworkReplyHttpImplPrivate::followRedirect()
Q_Q(QNetworkReplyHttpImpl);
Q_ASSERT(managerPrivate);
+ decompressHelper.clear();
rawHeaders.clear();
cookedHeaders.clear();
@@ -1214,6 +1303,8 @@ void QNetworkReplyHttpImplPrivate::followRedirect()
q, [this]() { postRequest(redirectRequest); }, Qt::QueuedConnection);
}
+static constexpr QLatin1StringView locationHeader() noexcept { return "location"_L1; }
+
void QNetworkReplyHttpImplPrivate::checkForRedirect(const int statusCode)
{
Q_Q(QNetworkReplyHttpImpl);
@@ -1226,20 +1317,20 @@ void QNetworkReplyHttpImplPrivate::checkForRedirect(const int statusCode)
// What do we do about the caching of the HTML note?
// The response to a 303 MUST NOT be cached, while the response to
// all of the others is cacheable if the headers indicate it to be
- QByteArray header = q->rawHeader("location");
+ QByteArray header = q->rawHeader(locationHeader());
QUrl url = QUrl(QString::fromUtf8(header));
if (!url.isValid())
- url = QUrl(QLatin1String(header));
+ url = QUrl(QLatin1StringView(header));
q->setAttribute(QNetworkRequest::RedirectionTargetAttribute, url);
}
}
-void QNetworkReplyHttpImplPrivate::replyDownloadMetaData(const QList<QPair<QByteArray,QByteArray> > &hm,
+void QNetworkReplyHttpImplPrivate::replyDownloadMetaData(const QHttpHeaders &hm,
int sc, const QString &rp, bool pu,
QSharedPointer<char> db,
qint64 contentLength,
qint64 removedContentLength,
- bool h2Used)
+ bool h2Used, bool isCompressed)
{
Q_Q(QNetworkReplyHttpImpl);
Q_UNUSED(contentLength);
@@ -1253,7 +1344,7 @@ void QNetworkReplyHttpImplPrivate::replyDownloadMetaData(const QList<QPair<QByte
// RFC6797, 8.1
// If an HTTP response is received over insecure transport, the UA MUST
// ignore any present STS header field(s).
- if (url.scheme() == QLatin1String("https") && managerPrivate->stsEnabled)
+ if (url.scheme() == "https"_L1 && managerPrivate->stsEnabled)
managerPrivate->stsCache.updateFromHeaders(hm, url);
#endif
// Download buffer
@@ -1267,29 +1358,48 @@ void QNetworkReplyHttpImplPrivate::replyDownloadMetaData(const QList<QPair<QByte
q->setAttribute(QNetworkRequest::HttpPipeliningWasUsedAttribute, pu);
q->setAttribute(QNetworkRequest::Http2WasUsedAttribute, h2Used);
+ // A user having manually defined which encodings they accept is, for
+ // somwehat unknown (presumed legacy compatibility) reasons treated as
+ // disabling our decompression:
+ const bool autoDecompress = request.rawHeader("accept-encoding").isEmpty();
+ const bool shouldDecompress = isCompressed && autoDecompress;
// reconstruct the HTTP header
- QList<QPair<QByteArray, QByteArray> > headerMap = hm;
- QList<QPair<QByteArray, QByteArray> >::ConstIterator it = headerMap.constBegin(),
- end = headerMap.constEnd();
- for (; it != end; ++it) {
- QByteArray value = q->rawHeader(it->first);
+ for (qsizetype i = 0; i < hm.size(); ++i) {
+ const auto key = hm.nameAt(i);
+ const auto originValue = hm.valueAt(i);
+
+ QByteArray value = q->rawHeader(key);
// Reset any previous "location" header set in the reply. In case of
// redirects, we don't want to 'append' multiple location header values,
// rather we keep only the latest one
- if (it->first.toLower() == "location")
+ if (key == locationHeader())
value.clear();
+ if (shouldDecompress && !decompressHelper.isValid() && key == "content-encoding"_L1) {
+ if (!synchronous) // with synchronous all the data is expected to be handled at once
+ decompressHelper.setCountingBytesEnabled(true);
+
+ if (!decompressHelper.setEncoding(originValue)) {
+ error(QNetworkReplyImpl::NetworkError::UnknownContentError,
+ QCoreApplication::translate("QHttp", "Failed to initialize decompression: %1")
+ .arg(decompressHelper.errorString()));
+ return;
+ }
+ decompressHelper.setDecompressedSafetyCheckThreshold(
+ request.decompressedSafetyCheckThreshold());
+ }
+
if (!value.isEmpty()) {
// Why are we appending values for headers which are already
// present?
- if (it->first.compare("set-cookie", Qt::CaseInsensitive) == 0)
+ if (key == "set-cookie"_L1)
value += '\n';
else
value += ", ";
}
- value += it->second;
- q->setRawHeader(it->first, value);
+ value += originValue;
+ q->setRawHeader({key.data(), key.size()}, value);
}
q->setAttribute(QNetworkRequest::HttpStatusCodeAttribute, statusCode);
@@ -1308,11 +1418,11 @@ void QNetworkReplyHttpImplPrivate::replyDownloadMetaData(const QList<QPair<QByte
QNetworkHeadersPrivate cacheHeaders;
cacheHeaders.setAllRawHeaders(metaData.rawHeaders());
QNetworkHeadersPrivate::RawHeadersList::ConstIterator it;
- it = cacheHeaders.findRawHeader("Cache-Control");
+ it = cacheHeaders.findRawHeader(cacheControlName());
bool mustReValidate = false;
if (it != cacheHeaders.rawHeaders.constEnd()) {
QHash<QByteArray, QByteArray> cacheControl = parseHttpOptionHeader(it->second);
- if (cacheControl.contains("must-revalidate"))
+ if (cacheControl.contains("must-revalidate"_ba))
mustReValidate = true;
}
if (!mustReValidate && sendCacheContents(metaData))
@@ -1382,7 +1492,7 @@ void QNetworkReplyHttpImplPrivate::replyDownloadProgressSlot(qint64 bytesReceive
downloadBufferCurrentSize = bytesReceived;
// Only emit readyRead when actual data is there
- // emit readyRead before downloadProgress incase this will cause events to be
+ // emit readyRead before downloadProgress in case this will cause events to be
// processed and we get into a recursive call (as in QProgressDialog).
if (bytesDownloaded > 0)
emit q->readyRead();
@@ -1556,7 +1666,7 @@ bool QNetworkReplyHttpImplPrivate::sendCacheContents(const QNetworkCacheMetaData
QUrl redirectUrl;
for ( ; it != end; ++it) {
if (httpRequest.isFollowRedirects() &&
- !it->first.compare("location", Qt::CaseInsensitive))
+ !it->first.compare(locationHeader(), Qt::CaseInsensitive))
redirectUrl = QUrl::fromEncoded(it->second);
setRawHeader(it->first, it->second);
}
@@ -1593,6 +1703,27 @@ bool QNetworkReplyHttpImplPrivate::sendCacheContents(const QNetworkCacheMetaData
return true;
}
+static auto caseInsensitiveCompare(QByteArrayView value)
+{
+ return [value](QByteArrayView element)
+ {
+ return value.compare(element, Qt::CaseInsensitive) == 0;
+ };
+}
+
+static bool isHopByHop(QByteArrayView header)
+{
+ constexpr QByteArrayView headers[] = { "connection",
+ "keep-alive",
+ "proxy-authenticate",
+ "proxy-authorization",
+ "te",
+ "trailers",
+ "transfer-encoding",
+ "upgrade"};
+ return std::any_of(std::begin(headers), std::end(headers), caseInsensitiveCompare(header));
+}
+
QNetworkCacheMetaData QNetworkReplyHttpImplPrivate::fetchCacheMetaData(const QNetworkCacheMetaData &oldMetaData) const
{
Q_Q(const QNetworkReplyHttpImpl);
@@ -1604,22 +1735,11 @@ QNetworkCacheMetaData QNetworkReplyHttpImplPrivate::fetchCacheMetaData(const QNe
QNetworkHeadersPrivate::RawHeadersList::ConstIterator it;
const QList<QByteArray> newHeaders = q->rawHeaderList();
- for (QByteArray header : newHeaders) {
- QByteArray originalHeader = header;
- header = header.toLower();
- bool hop_by_hop =
- (header == "connection"
- || header == "keep-alive"
- || header == "proxy-authenticate"
- || header == "proxy-authorization"
- || header == "te"
- || header == "trailers"
- || header == "transfer-encoding"
- || header == "upgrade");
- if (hop_by_hop)
+ for (const QByteArray& header : newHeaders) {
+ if (isHopByHop(header))
continue;
- if (header == "set-cookie")
+ if (header.compare("set-cookie", Qt::CaseInsensitive) == 0)
continue;
// for 4.6.0, we were planning to not store the date header in the
@@ -1632,27 +1752,27 @@ QNetworkCacheMetaData QNetworkReplyHttpImplPrivate::fetchCacheMetaData(const QNe
//continue;
// Don't store Warning 1xx headers
- if (header == "warning") {
- QByteArray v = q->rawHeader(header);
- if (v.length() == 3
+ if (header.compare("warning", Qt::CaseInsensitive) == 0) {
+ const QByteArray v = q->rawHeader(header);
+ if (v.size() == 3
&& v[0] == '1'
- && v[1] >= '0' && v[1] <= '9'
- && v[2] >= '0' && v[2] <= '9')
+ && isAsciiDigit(v[1])
+ && isAsciiDigit(v[2]))
continue;
}
it = cacheHeaders.findRawHeader(header);
if (it != cacheHeaders.rawHeaders.constEnd()) {
// Match the behavior of Firefox and assume Cache-Control: "no-transform"
- if (header == "content-encoding"
- || header == "content-range"
- || header == "content-type")
+ constexpr QByteArrayView headers[]=
+ {"content-encoding", "content-range", "content-type"};
+ if (std::any_of(std::begin(headers), std::end(headers), caseInsensitiveCompare(header)))
continue;
}
// IIS has been known to send "Content-Length: 0" on 304 responses, so
// ignore this too
- if (header == "content-length" && statusCode == 304)
+ if (statusCode == 304 && header.compare("content-length", Qt::CaseInsensitive) == 0)
continue;
#if defined(QNETWORKACCESSHTTPBACKEND_DEBUG)
@@ -1660,23 +1780,23 @@ QNetworkCacheMetaData QNetworkReplyHttpImplPrivate::fetchCacheMetaData(const QNe
QByteArray o;
if (it != cacheHeaders.rawHeaders.constEnd())
o = (*it).second;
- if (n != o && header != "date") {
+ if (n != o && headerheader.compare("date", Qt::CaseInsensitive) != 0) {
qDebug() << "replacing" << header;
qDebug() << "new" << n;
qDebug() << "old" << o;
}
#endif
- cacheHeaders.setRawHeader(originalHeader, q->rawHeader(header));
+ cacheHeaders.setRawHeader(header, q->rawHeader(header));
}
metaData.setRawHeaders(cacheHeaders.rawHeaders);
bool checkExpired = true;
QHash<QByteArray, QByteArray> cacheControl;
- it = cacheHeaders.findRawHeader("Cache-Control");
+ it = cacheHeaders.findRawHeader(cacheControlName());
if (it != cacheHeaders.rawHeaders.constEnd()) {
cacheControl = parseHttpOptionHeader(it->second);
- QByteArray maxAge = cacheControl.value("max-age");
+ QByteArray maxAge = cacheControl.value("max-age"_ba);
if (!maxAge.isEmpty()) {
checkExpired = false;
QDateTime dt = QDateTime::currentDateTimeUtc();
@@ -1703,7 +1823,7 @@ QNetworkCacheMetaData QNetworkReplyHttpImplPrivate::fetchCacheMetaData(const QNe
canDiskCache = true;
// HTTP/1.1. Check the Cache-Control header
- if (cacheControl.contains("no-store"))
+ if (cacheControl.contains("no-store"_ba))
canDiskCache = false;
// responses to POST might be cacheable
@@ -1712,7 +1832,7 @@ QNetworkCacheMetaData QNetworkReplyHttpImplPrivate::fetchCacheMetaData(const QNe
canDiskCache = false;
// some pages contain "expires:" and "cache-control: no-cache" field,
// so we only might cache POST requests if we get "cache-control: max-age ..."
- if (cacheControl.contains("max-age"))
+ if (cacheControl.contains("max-age"_ba))
canDiskCache = true;
// responses to PUT and DELETE are not cacheable
@@ -1743,14 +1863,14 @@ bool QNetworkReplyHttpImplPrivate::canResume() const
return false;
// Can only resume if server/resource supports Range header.
- QByteArray acceptRangesheaderName("Accept-Ranges");
+ constexpr auto acceptRangesheaderName = QByteArrayView("Accept-Ranges");
if (!q->hasRawHeader(acceptRangesheaderName) || q->rawHeader(acceptRangesheaderName) == "none")
return false;
// We only support resuming for byte ranges.
- if (request.hasRawHeader("Range")) {
- QByteArray range = request.rawHeader("Range");
- if (!range.startsWith("bytes="))
+ if (request.hasRawHeader(rangeName())) {
+ QByteArray range = request.rawHeader(rangeName());
+ if (!range.startsWith(bytesEqualPrefix()))
return false;
}
@@ -1769,7 +1889,9 @@ void QNetworkReplyHttpImplPrivate::setResumeOffset(quint64 offset)
void QNetworkReplyHttpImplPrivate::_q_startOperation()
{
- if (state == Working) // ensure this function is only being called once
+ // Ensure this function is only being called once, and not at all if we were
+ // cancelled
+ if (state >= Working)
return;
state = Working;
@@ -1799,7 +1921,7 @@ void QNetworkReplyHttpImplPrivate::_q_cacheLoadReadyRead()
QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader);
- // emit readyRead before downloadProgress incase this will cause events to be
+ // emit readyRead before downloadProgress in case this will cause events to be
// processed and we get into a recursive call (as in QProgressDialog).
if (!(isHttpRedirectResponse())) {
@@ -1876,7 +1998,7 @@ void QNetworkReplyHttpImplPrivate::_q_bufferOutgoingData()
if (!outgoingDataBuffer) {
// first call, create our buffer
- outgoingDataBuffer = QSharedPointer<QRingBuffer>::create();
+ outgoingDataBuffer = std::make_shared<QRingBuffer>();
QObject::connect(outgoingData, SIGNAL(readyRead()), q, SLOT(_q_bufferOutgoingData()));
QObject::connect(outgoingData, SIGNAL(readChannelFinished()), q, SLOT(_q_bufferOutgoingDataFinished()));
@@ -1929,9 +2051,9 @@ void QNetworkReplyHttpImplPrivate::setupTransferTimeout()
Qt::QueuedConnection);
}
transferTimeout->stop();
- if (request.transferTimeout()) {
+ if (request.transferTimeoutAsDuration() > 0ms) {
transferTimeout->setSingleShot(true);
- transferTimeout->setInterval(request.transferTimeout());
+ transferTimeout->setInterval(request.transferTimeoutAsDuration());
QMetaObject::invokeMethod(transferTimeout, "start",
Qt::QueuedConnection);
@@ -1976,10 +2098,10 @@ QNonContiguousByteDevice* QNetworkReplyHttpImplPrivate::createUploadByteDevice()
// We want signal emissions only for normal asynchronous uploads
if (!synchronous)
- QObject::connect(uploadByteDevice.data(), SIGNAL(readProgress(qint64,qint64)),
+ QObject::connect(uploadByteDevice.get(), SIGNAL(readProgress(qint64,qint64)),
q, SLOT(emitReplyUploadProgress(qint64,qint64)));
- return uploadByteDevice.data();
+ return uploadByteDevice.get();
}
void QNetworkReplyHttpImplPrivate::_q_finished()
@@ -1998,9 +2120,12 @@ void QNetworkReplyHttpImplPrivate::finished()
QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader);
- // if we don't know the total size of or we received everything save the cache
- if (totalSize.isNull() || totalSize == -1 || bytesDownloaded == totalSize)
+ // if we don't know the total size of or we received everything save the cache.
+ // If the data is compressed then this is done in readData()
+ if ((totalSize.isNull() || totalSize == -1 || bytesDownloaded == totalSize)
+ && !decompressHelper.isValid()) {
completeCacheSave();
+ }
// We check for errorCode too as in case of SSL handshake failure, we still
// get the HTTP redirect status code (301, 303 etc)
@@ -2034,7 +2159,9 @@ void QNetworkReplyHttpImplPrivate::error(QNetworkReplyImpl::NetworkError code, c
Q_Q(QNetworkReplyHttpImpl);
// Can't set and emit multiple errors.
if (errorCode != QNetworkReply::NoError) {
- qWarning("QNetworkReplyImplPrivate::error: Internal problem, this method must only be called once.");
+ // But somewhat unavoidable if we have cancelled the request:
+ if (errorCode != QNetworkReply::OperationCanceledError)
+ qWarning("QNetworkReplyImplPrivate::error: Internal problem, this method must only be called once.");
return;
}
@@ -2126,3 +2253,5 @@ void QNetworkReplyHttpImplPrivate::completeCacheSave()
}
QT_END_NAMESPACE
+
+#include "moc_qnetworkreplyhttpimpl_p.cpp"
diff --git a/src/network/access/qnetworkreplyhttpimpl_p.h b/src/network/access/qnetworkreplyhttpimpl_p.h
index 2bd6072c21..e00c43bdb3 100644
--- a/src/network/access/qnetworkreplyhttpimpl_p.h
+++ b/src/network/access/qnetworkreplyhttpimpl_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNETWORKREPLYHTTPIMPL_P_H
#define QNETWORKREPLYHTTPIMPL_P_H
@@ -73,6 +37,10 @@
Q_MOC_INCLUDE(<QtNetwork/QAuthenticator>)
+#include <private/qdecompresshelper_p.h>
+
+#include <memory>
+
QT_REQUIRE_CONFIG(http);
QT_BEGIN_NAMESPACE
@@ -108,9 +76,6 @@ public:
// From reply
Q_PRIVATE_SLOT(d_func(), void replyDownloadData(QByteArray))
Q_PRIVATE_SLOT(d_func(), void replyFinished())
- Q_PRIVATE_SLOT(d_func(), void replyDownloadMetaData(QList<QPair<QByteArray,QByteArray> >,
- int, QString, bool, QSharedPointer<char>,
- qint64, qint64, bool))
Q_PRIVATE_SLOT(d_func(), void replyDownloadProgressSlot(qint64,qint64))
Q_PRIVATE_SLOT(d_func(), void httpAuthenticationRequired(const QHttpNetworkRequest &, QAuthenticator *))
Q_PRIVATE_SLOT(d_func(), void httpError(QNetworkReply::NetworkError, const QString &))
@@ -198,11 +163,11 @@ public:
// upload
QNonContiguousByteDevice* createUploadByteDevice();
- QSharedPointer<QNonContiguousByteDevice> uploadByteDevice;
+ std::shared_ptr<QNonContiguousByteDevice> uploadByteDevice;
qint64 uploadByteDevicePosition;
bool uploadDeviceChoking; // if we couldn't readPointer() any data at the moment
QIODevice *outgoingData;
- QSharedPointer<QRingBuffer> outgoingDataBuffer;
+ std::shared_ptr<QRingBuffer> outgoingDataBuffer;
void emitReplyUploadProgress(qint64 bytesSent, qint64 bytesTotal); // dup?
void onRedirected(const QUrl &redirectUrl, int httpStatus, int maxRedirectsRemainig);
void followRedirect();
@@ -235,6 +200,10 @@ public:
qint64 bytesDownloaded;
qint64 bytesBuffered;
+ // We use this to keep track of whether or not we need to emit readyRead
+ // when we deal with signal compression (delaying emission) + decompressing
+ // data (potentially receiving bytes that don't end up in the final output):
+ qint64 lastReadyReadEmittedSize = 0;
QTimer *transferTimeout;
@@ -246,8 +215,8 @@ public:
char* downloadZerocopyBuffer;
// Will be increased by HTTP thread:
- QSharedPointer<QAtomicInt> pendingDownloadDataEmissions;
- QSharedPointer<QAtomicInt> pendingDownloadProgressEmissions;
+ std::shared_ptr<QAtomicInt> pendingDownloadDataEmissions;
+ std::shared_ptr<QAtomicInt> pendingDownloadProgressEmissions;
#ifndef QT_NO_SSL
@@ -258,6 +227,8 @@ public:
QNetworkRequest redirectRequest;
+ QDecompressHelper decompressHelper;
+
bool loadFromCacheIfAllowed(QHttpNetworkRequest &httpRequest);
void invalidateCache();
bool sendCacheContents(const QNetworkCacheMetaData &metaData);
@@ -273,8 +244,8 @@ public:
// From HTTP thread:
void replyDownloadData(QByteArray);
void replyFinished();
- void replyDownloadMetaData(const QList<QPair<QByteArray,QByteArray> > &, int, const QString &,
- bool, QSharedPointer<char>, qint64, qint64, bool);
+ void replyDownloadMetaData(const QHttpHeaders &, int, const QString &,
+ bool, QSharedPointer<char>, qint64, qint64, bool, bool);
void replyDownloadProgressSlot(qint64,qint64);
void httpAuthenticationRequired(const QHttpNetworkRequest &request, QAuthenticator *auth);
void httpError(QNetworkReply::NetworkError error, const QString &errorString);
diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp
index 61745155f5..8b2acfdb4e 100644
--- a/src/network/access/qnetworkreplyimpl.cpp
+++ b/src/network/access/qnetworkreplyimpl.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qnetworkreplyimpl_p.h"
#include "qnetworkaccessbackend_p.h"
@@ -51,6 +15,8 @@
QT_BEGIN_NAMESPACE
+QT_IMPL_METATYPE_EXTERN_TAGGED(QSharedPointer<char>, QSharedPointer_char)
+
inline QNetworkReplyImplPrivate::QNetworkReplyImplPrivate()
: backend(nullptr), outgoingData(nullptr),
copyDevice(nullptr),
@@ -154,7 +120,7 @@ void QNetworkReplyImplPrivate::_q_copyReadyRead()
QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader);
pauseNotificationHandling();
- // emit readyRead before downloadProgress incase this will cause events to be
+ // emit readyRead before downloadProgress in case this will cause events to be
// processed and we get into a recursive call (as in QProgressDialog).
emit q->readyRead();
if (downloadProgressSignalChoke.elapsed() >= progressSignalInterval) {
@@ -193,7 +159,7 @@ void QNetworkReplyImplPrivate::_q_bufferOutgoingData()
if (!outgoingDataBuffer) {
// first call, create our buffer
- outgoingDataBuffer = QSharedPointer<QRingBuffer>::create();
+ outgoingDataBuffer = std::make_shared<QRingBuffer>();
QObject::connect(outgoingData, SIGNAL(readyRead()), q, SLOT(_q_bufferOutgoingData()));
QObject::connect(outgoingData, SIGNAL(readChannelFinished()), q, SLOT(_q_bufferOutgoingDataFinished()));
@@ -249,7 +215,7 @@ void QNetworkReplyImplPrivate::setup(QNetworkAccessManager::Operation op, const
// The synchronous HTTP is a corner case, we will put all upload data in one big QByteArray in the outgoingDataBuffer.
// Yes, this is not the most efficient thing to do, but on the other hand synchronous XHR needs to die anyway.
if (synchronousHttpAttribute.toBool() && outgoingData) {
- outgoingDataBuffer = QSharedPointer<QRingBuffer>::create();
+ outgoingDataBuffer = std::make_shared<QRingBuffer>();
qint64 previousDataSize = 0;
do {
previousDataSize = outgoingDataBuffer->size();
@@ -315,7 +281,7 @@ void QNetworkReplyImplPrivate::handleNotifications()
if (notificationHandlingPaused)
return;
- for (InternalNotifications notification : qExchange(pendingNotifications, {})) {
+ for (InternalNotifications notification : std::exchange(pendingNotifications, {})) {
if (state != Working)
return;
switch (notification) {
@@ -492,7 +458,7 @@ void QNetworkReplyImplPrivate::appendDownstreamData(QByteDataBuffer &data)
}
qint64 bytesWritten = 0;
- for (int i = 0; i < data.bufferCount(); i++) {
+ for (qsizetype i = 0; i < data.bufferCount(); ++i) {
QByteArray const &item = data[i];
if (cacheSaveDevice)
@@ -517,7 +483,7 @@ void QNetworkReplyImplPrivate::appendDownstreamDataSignalEmissions()
// important: At the point of this readyRead(), the data parameter list must be empty,
// else implicit sharing will trigger memcpy when the user is reading data!
emit q->readyRead();
- // emit readyRead before downloadProgress incase this will cause events to be
+ // emit readyRead before downloadProgress in case this will cause events to be
// processed and we get into a recursive call (as in QProgressDialog).
if (downloadProgressSignalChoke.elapsed() >= progressSignalInterval) {
downloadProgressSignalChoke.restart();
@@ -541,7 +507,7 @@ void QNetworkReplyImplPrivate::appendDownstreamData(QIODevice *data)
// read until EOF from data
if (Q_UNLIKELY(copyDevice)) {
qCritical("QNetworkReplyImpl: copy from QIODevice already in progress -- "
- "backend probly needs to be fixed");
+ "backend probably needs to be fixed");
return;
}
@@ -553,11 +519,6 @@ void QNetworkReplyImplPrivate::appendDownstreamData(QIODevice *data)
_q_copyReadyRead();
}
-static void downloadBufferDeleter(char *ptr)
-{
- delete[] ptr;
-}
-
char* QNetworkReplyImplPrivate::getDownloadBuffer(qint64 size)
{
Q_Q(QNetworkReplyImpl);
@@ -570,7 +531,7 @@ char* QNetworkReplyImplPrivate::getDownloadBuffer(qint64 size)
downloadBufferCurrentSize = 0;
downloadBufferMaximumSize = size;
downloadBuffer = new char[downloadBufferMaximumSize]; // throws if allocation fails
- downloadBufferPointer = QSharedPointer<char>(downloadBuffer, downloadBufferDeleter);
+ downloadBufferPointer = QSharedPointer<char>(downloadBuffer, [](auto p) { delete[] p; });
q->setAttribute(QNetworkRequest::DownloadBufferAttribute, QVariant::fromValue<QSharedPointer<char> > (downloadBufferPointer));
}
@@ -610,7 +571,7 @@ void QNetworkReplyImplPrivate::appendDownstreamDataDownloadBuffer(qint64 bytesRe
downloadBufferCurrentSize = bytesReceived;
// Only emit readyRead when actual data is there
- // emit readyRead before downloadProgress incase this will cause events to be
+ // emit readyRead before downloadProgress in case this will cause events to be
// processed and we get into a recursive call (as in QProgressDialog).
if (bytesDownloaded > 0)
emit q->readyRead();
@@ -734,6 +695,7 @@ void QNetworkReplyImplPrivate::readFromBackend()
if (backend->bytesAvailable())
emit q->readyRead();
} else {
+ bool anyBytesRead = false;
while (backend->bytesAvailable()
&& (!readBufferMaxSize || buffer.size() < readBufferMaxSize)) {
qint64 toRead = qMin(nextDownstreamBlockSize(), backend->bytesAvailable());
@@ -743,8 +705,10 @@ void QNetworkReplyImplPrivate::readFromBackend()
qint64 bytesRead = backend->read(data, toRead);
Q_ASSERT(bytesRead <= toRead);
buffer.chop(toRead - bytesRead);
- emit q->readyRead();
+ anyBytesRead |= bytesRead > 0;
}
+ if (anyBytesRead)
+ emit q->readyRead();
}
}
diff --git a/src/network/access/qnetworkreplyimpl_p.h b/src/network/access/qnetworkreplyimpl_p.h
index 7d014f9173..9648b8b57a 100644
--- a/src/network/access/qnetworkreplyimpl_p.h
+++ b/src/network/access/qnetworkreplyimpl_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNETWORKREPLYIMPL_P_H
#define QNETWORKREPLYIMPL_P_H
@@ -63,6 +27,8 @@
#include "private/qbytedata_p.h"
#include <QSharedPointer>
+#include <memory>
+
QT_BEGIN_NAMESPACE
class QAbstractNetworkCache;
@@ -153,7 +119,7 @@ public:
QNetworkAccessBackend *backend;
QIODevice *outgoingData;
- QSharedPointer<QRingBuffer> outgoingDataBuffer;
+ std::shared_ptr<QRingBuffer> outgoingDataBuffer;
QIODevice *copyDevice;
QAbstractNetworkCache *networkCache() const;
@@ -191,6 +157,4 @@ Q_DECLARE_TYPEINFO(QNetworkReplyImplPrivate::InternalNotifications, Q_PRIMITIVE_
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QSharedPointer<char>)
-
#endif
diff --git a/src/network/access/qnetworkreplywasmimpl.cpp b/src/network/access/qnetworkreplywasmimpl.cpp
index 0fc5bbf5a8..c02f0b4e61 100644
--- a/src/network/access/qnetworkreplywasmimpl.cpp
+++ b/src/network/access/qnetworkreplywasmimpl.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qnetworkreplywasmimpl_p.h"
#include "qnetworkrequest.h"
@@ -45,6 +9,8 @@
#include <QtCore/qcoreapplication.h>
#include <QtCore/qfileinfo.h>
#include <QtCore/qthread.h>
+#include <QtCore/private/qoffsetstringarray_p.h>
+#include <QtCore/private/qtools_p.h>
#include <private/qnetworkaccessmanager_p.h>
#include <private/qnetworkfile_p.h>
@@ -54,6 +20,41 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
+namespace {
+
+static constexpr auto BannedHeaders = qOffsetStringArray(
+ "accept-charset",
+ "accept-encoding",
+ "access-control-request-headers",
+ "access-control-request-method",
+ "connection",
+ "content-length",
+ "cookie",
+ "cookie2",
+ "date",
+ "dnt",
+ "expect",
+ "host",
+ "keep-alive",
+ "origin",
+ "referer",
+ "te",
+ "trailer",
+ "transfer-encoding",
+ "upgrade",
+ "via"
+);
+
+bool isUnsafeHeader(QLatin1StringView header) noexcept
+{
+ return header.startsWith("proxy-"_L1, Qt::CaseInsensitive)
+ || header.startsWith("sec-"_L1, Qt::CaseInsensitive)
+ || BannedHeaders.contains(header, Qt::CaseInsensitive);
+}
+} // namespace
+
QNetworkReplyWasmImplPrivate::QNetworkReplyWasmImplPrivate()
: QNetworkReplyPrivate()
, managerPrivate(0)
@@ -61,16 +62,12 @@ QNetworkReplyWasmImplPrivate::QNetworkReplyWasmImplPrivate()
, downloadBufferCurrentSize(0)
, totalDownloadSize(0)
, percentFinished(0)
- , m_fetch(0)
+ , m_fetch(nullptr)
{
}
QNetworkReplyWasmImplPrivate::~QNetworkReplyWasmImplPrivate()
{
- if (m_fetch) {
- emscripten_fetch_close(m_fetch);
- m_fetch = 0;
- }
}
QNetworkReplyWasmImpl::QNetworkReplyWasmImpl(QObject *parent)
@@ -82,6 +79,9 @@ QNetworkReplyWasmImpl::QNetworkReplyWasmImpl(QObject *parent)
QNetworkReplyWasmImpl::~QNetworkReplyWasmImpl()
{
+ if (isRunning())
+ abort();
+ close();
}
QByteArray QNetworkReplyWasmImpl::methodName() const
@@ -108,20 +108,38 @@ QByteArray QNetworkReplyWasmImpl::methodName() const
void QNetworkReplyWasmImpl::close()
{
+ Q_D(QNetworkReplyWasmImpl);
+
+ if (d->state != QNetworkReplyPrivate::Aborted &&
+ d->state != QNetworkReplyPrivate::Finished &&
+ d->state != QNetworkReplyPrivate::Idle) {
+ d->state = QNetworkReplyPrivate::Finished;
+ d->setCanceled();
+ }
+
QNetworkReply::close();
- setFinished(true);
- emit finished();
}
void QNetworkReplyWasmImpl::abort()
{
- Q_D( QNetworkReplyWasmImpl);
+ Q_D(QNetworkReplyWasmImpl);
+
if (d->state == QNetworkReplyPrivate::Finished || d->state == QNetworkReplyPrivate::Aborted)
return;
d->state = QNetworkReplyPrivate::Aborted;
- d->doAbort();
- close();
+ d->setCanceled();
+}
+
+void QNetworkReplyWasmImplPrivate::setCanceled()
+{
+ Q_Q(QNetworkReplyWasmImpl);
+ if (m_fetch)
+ m_fetch->userData = nullptr;
+
+ emitReplyError(QNetworkReply::OperationCanceledError, QStringLiteral("Operation canceled"));
+ q->setFinished(true);
+ emit q->finished();
}
qint64 QNetworkReplyWasmImpl::bytesAvailable() const
@@ -198,11 +216,6 @@ void QNetworkReplyWasmImplPrivate::setReplyAttributes(quintptr data, int statusC
handler->q_func()->setAttribute(QNetworkRequest::HttpReasonPhraseAttribute, statusReason);
}
-void QNetworkReplyWasmImplPrivate::doAbort() const
-{
- emscripten_fetch_close(m_fetch);
-}
-
constexpr int getArraySize (int factor) {
return 2 * factor + 1;
}
@@ -218,15 +231,22 @@ void QNetworkReplyWasmImplPrivate::doSendRequest()
QList<QByteArray> headersData = request.rawHeaderList();
int arrayLength = getArraySize(headersData.count());
- const char* customHeaders[arrayLength];
+ const char *customHeaders[arrayLength];
+ QStringList trimmedHeaders;
if (headersData.count() > 0) {
int i = 0;
- for (int j = 0; j < headersData.count(); j++) {
- customHeaders[i] = headersData[j].constData();
- i += 1;
- customHeaders[i] = request.rawHeader(headersData[j]).constData();
- i += 1;
+ for (const auto &headerName : headersData) {
+ if (isUnsafeHeader(QLatin1StringView(headerName.constData()))) {
+ trimmedHeaders.push_back(QString::fromLatin1(headerName));
+ } else {
+ customHeaders[i++] = headerName.constData();
+ customHeaders[i++] = request.rawHeader(headerName).constData();
+ }
+ }
+ if (!trimmedHeaders.isEmpty()) {
+ qWarning() << "Qt has trimmed the following forbidden headers from the request:"
+ << trimmedHeaders.join(QLatin1StringView(", "));
}
customHeaders[i] = nullptr;
attr.requestHeaders = customHeaders;
@@ -241,10 +261,13 @@ void QNetworkReplyWasmImplPrivate::doSendRequest()
}
}
+ QByteArray userName, password;
// username & password
if (!request.url().userInfo().isEmpty()) {
- attr.userName = request.url().userName().toUtf8();
- attr.password = request.url().password().toUtf8();
+ userName = request.url().userName().toUtf8();
+ password = request.url().password().toUtf8();
+ attr.userName = userName.constData();
+ attr.password = password.constData();
}
attr.attributes = EMSCRIPTEN_FETCH_LOAD_TO_MEMORY;
@@ -264,6 +287,7 @@ void QNetworkReplyWasmImplPrivate::doSendRequest()
attr.attributes -= EMSCRIPTEN_FETCH_PERSIST_FILE;
}
+ attr.withCredentials = request.attribute(QNetworkRequest::UseCredentialsAttribute, false).toBool();
attr.onsuccess = QNetworkReplyWasmImplPrivate::downloadSucceeded;
attr.onerror = QNetworkReplyWasmImplPrivate::downloadFailed;
attr.onprogress = QNetworkReplyWasmImplPrivate::downloadProgress;
@@ -271,10 +295,12 @@ void QNetworkReplyWasmImplPrivate::doSendRequest()
attr.timeoutMSecs = request.transferTimeout();
attr.userData = reinterpret_cast<void *>(this);
- QString dPath = QStringLiteral("/home/web_user/") + request.url().fileName();
- attr.destinationPath = dPath.toUtf8();
+ QString dPath = "/home/web_user/"_L1 + request.url().fileName();
+ QByteArray destinationPath = dPath.toUtf8();
+ attr.destinationPath = destinationPath.constData();
- m_fetch = emscripten_fetch(&attr, request.url().toString().toUtf8());
+ m_fetch = emscripten_fetch(&attr, request.url().toString().toUtf8().constData());
+ state = Working;
}
void QNetworkReplyWasmImplPrivate::emitReplyError(QNetworkReply::NetworkError errorCode, const QString &errorString)
@@ -283,7 +309,6 @@ void QNetworkReplyWasmImplPrivate::emitReplyError(QNetworkReply::NetworkError er
q->setError(errorCode, errorString);
emit q->errorOccurred(errorCode);
- emit q->finished();
}
void QNetworkReplyWasmImplPrivate::emitDataReadProgress(qint64 bytesReceived, qint64 bytesTotal)
@@ -292,15 +317,16 @@ void QNetworkReplyWasmImplPrivate::emitDataReadProgress(qint64 bytesReceived, qi
totalDownloadSize = bytesTotal;
- percentFinished = (bytesReceived / bytesTotal) * 100;
+ percentFinished = bytesTotal ? (bytesReceived / bytesTotal) * 100 : 100;
emit q->downloadProgress(bytesReceived, bytesTotal);
}
-void QNetworkReplyWasmImplPrivate::dataReceived(const QByteArray &buffer, int bufferSize)
+void QNetworkReplyWasmImplPrivate::dataReceived(const QByteArray &buffer)
{
Q_Q(QNetworkReplyWasmImpl);
+ const qsizetype bufferSize = buffer.size();
if (bufferSize > 0)
q->setReadBufferSize(bufferSize);
@@ -313,7 +339,7 @@ void QNetworkReplyWasmImplPrivate::dataReceived(const QByteArray &buffer, int bu
totalDownloadSize = downloadBufferCurrentSize;
- downloadBuffer.append(buffer, bufferSize);
+ downloadBuffer.append(buffer);
emit q->readyRead();
}
@@ -324,32 +350,36 @@ static int parseHeaderName(const QByteArray &headerName)
if (headerName.isEmpty())
return -1;
- switch (tolower(headerName.at(0))) {
+ auto is = [&](const char *what) {
+ return qstrnicmp(headerName.data(), headerName.size(), what) == 0;
+ };
+
+ switch (QtMiscUtils::toAsciiLower(headerName.front())) {
case 'c':
- if (qstricmp(headerName.constData(), "content-type") == 0)
+ if (is("content-type"))
return QNetworkRequest::ContentTypeHeader;
- else if (qstricmp(headerName.constData(), "content-length") == 0)
+ else if (is("content-length"))
return QNetworkRequest::ContentLengthHeader;
- else if (qstricmp(headerName.constData(), "cookie") == 0)
+ else if (is("cookie"))
return QNetworkRequest::CookieHeader;
break;
case 'l':
- if (qstricmp(headerName.constData(), "location") == 0)
+ if (is("location"))
return QNetworkRequest::LocationHeader;
- else if (qstricmp(headerName.constData(), "last-modified") == 0)
+ else if (is("last-modified"))
return QNetworkRequest::LastModifiedHeader;
break;
case 's':
- if (qstricmp(headerName.constData(), "set-cookie") == 0)
+ if (is("set-cookie"))
return QNetworkRequest::SetCookieHeader;
- else if (qstricmp(headerName.constData(), "server") == 0)
+ else if (is("server"))
return QNetworkRequest::ServerHeader;
break;
case 'u':
- if (qstricmp(headerName.constData(), "user-agent") == 0)
+ if (is("user-agent"))
return QNetworkRequest::UserAgentHeader;
break;
}
@@ -408,7 +438,7 @@ void QNetworkReplyWasmImplPrivate::_q_bufferOutgoingData()
if (!outgoingDataBuffer) {
// first call, create our buffer
- outgoingDataBuffer = QSharedPointer<QRingBuffer>::create();
+ outgoingDataBuffer = std::make_shared<QRingBuffer>();
QObject::connect(outgoingData, SIGNAL(readyRead()), q, SLOT(_q_bufferOutgoingData()));
QObject::connect(outgoingData, SIGNAL(readChannelFinished()), q, SLOT(_q_bufferOutgoingDataFinished()));
@@ -447,77 +477,83 @@ void QNetworkReplyWasmImplPrivate::_q_bufferOutgoingData()
void QNetworkReplyWasmImplPrivate::downloadSucceeded(emscripten_fetch_t *fetch)
{
- QNetworkReplyWasmImplPrivate *reply =
- reinterpret_cast<QNetworkReplyWasmImplPrivate*>(fetch->userData);
+ auto reply = reinterpret_cast<QNetworkReplyWasmImplPrivate*>(fetch->userData);
if (reply) {
- QByteArray buffer(fetch->data, fetch->numBytes);
- reply->dataReceived(buffer, buffer.size());
-
- QByteArray statusText(fetch->statusText);
- reply->setStatusCode(fetch->status, statusText);
- reply->setReplyFinished();
+ if (reply->state != QNetworkReplyPrivate::Aborted) {
+ QByteArray buffer(fetch->data, fetch->numBytes);
+ reply->dataReceived(buffer);
+ QByteArray statusText(fetch->statusText);
+ reply->setStatusCode(fetch->status, statusText);
+ reply->setReplyFinished();
+ }
+ reply->m_fetch = nullptr;
}
-}
-
-void QNetworkReplyWasmImplPrivate::setStatusCode(int status, const QByteArray &statusText)
-{
- Q_Q(QNetworkReplyWasmImpl);
- q->setAttribute(QNetworkRequest::HttpStatusCodeAttribute, status);
- q->setAttribute(QNetworkRequest::HttpReasonPhraseAttribute, statusText);
+ emscripten_fetch_close(fetch);
}
void QNetworkReplyWasmImplPrivate::setReplyFinished()
{
Q_Q(QNetworkReplyWasmImpl);
+ state = QNetworkReplyPrivate::Finished;
q->setFinished(true);
emit q->readChannelFinished();
emit q->finished();
}
+void QNetworkReplyWasmImplPrivate::setStatusCode(int status, const QByteArray &statusText)
+{
+ Q_Q(QNetworkReplyWasmImpl);
+ q->setAttribute(QNetworkRequest::HttpStatusCodeAttribute, status);
+ q->setAttribute(QNetworkRequest::HttpReasonPhraseAttribute, statusText);
+}
+
void QNetworkReplyWasmImplPrivate::stateChange(emscripten_fetch_t *fetch)
{
- if (fetch->readyState == /*HEADERS_RECEIVED*/ 2) {
- size_t headerLength = emscripten_fetch_get_response_headers_length(fetch);
- QByteArray str(headerLength, Qt::Uninitialized);
- emscripten_fetch_get_response_headers(fetch, str.data(), str.size());
- QNetworkReplyWasmImplPrivate *reply =
- reinterpret_cast<QNetworkReplyWasmImplPrivate*>(fetch->userData);
- reply->headersReceived(str);
+ auto reply = reinterpret_cast<QNetworkReplyWasmImplPrivate*>(fetch->userData);
+ if (reply && reply->state != QNetworkReplyPrivate::Aborted) {
+ if (fetch->readyState == /*HEADERS_RECEIVED*/ 2) {
+ size_t headerLength = emscripten_fetch_get_response_headers_length(fetch);
+ QByteArray str(headerLength, Qt::Uninitialized);
+ emscripten_fetch_get_response_headers(fetch, str.data(), str.size());
+ reply->headersReceived(str);
+ }
}
}
void QNetworkReplyWasmImplPrivate::downloadProgress(emscripten_fetch_t *fetch)
{
- QNetworkReplyWasmImplPrivate *reply =
- reinterpret_cast<QNetworkReplyWasmImplPrivate*>(fetch->userData);
- Q_ASSERT(reply);
-
- if (fetch->status < 400) {
- uint64_t bytes = fetch->dataOffset + fetch->numBytes;
- uint64_t tBytes = fetch->totalBytes; // totalBytes can be 0 if server not reporting content length
- if (tBytes == 0)
- tBytes = bytes;
- reply->emitDataReadProgress(bytes, tBytes);
+ auto reply = reinterpret_cast<QNetworkReplyWasmImplPrivate*>(fetch->userData);
+ if (reply && reply->state != QNetworkReplyPrivate::Aborted) {
+ if (fetch->status < 400) {
+ uint64_t bytes = fetch->dataOffset + fetch->numBytes;
+ uint64_t tBytes = fetch->totalBytes; // totalBytes can be 0 if server not reporting content length
+ if (tBytes == 0)
+ tBytes = bytes;
+ reply->emitDataReadProgress(bytes, tBytes);
+ }
}
}
void QNetworkReplyWasmImplPrivate::downloadFailed(emscripten_fetch_t *fetch)
{
- QNetworkReplyWasmImplPrivate *reply = reinterpret_cast<QNetworkReplyWasmImplPrivate*>(fetch->userData);
+ auto reply = reinterpret_cast<QNetworkReplyWasmImplPrivate*>(fetch->userData);
if (reply) {
- QString reasonStr;
- if (fetch->status > 600 || reply->state == QNetworkReplyPrivate::Aborted)
- reasonStr = QStringLiteral("Operation canceled");
- else
- reasonStr = QString::fromUtf8(fetch->statusText);
-
- QByteArray statusText(fetch->statusText);
- reply->setStatusCode(fetch->status, statusText);
- reply->emitReplyError(reply->statusCodeFromHttp(fetch->status, reply->request.url()), reasonStr);
+ if (reply->state != QNetworkReplyPrivate::Aborted) {
+ QString reasonStr;
+ if (fetch->status > 600)
+ reasonStr = QStringLiteral("Operation canceled");
+ else
+ reasonStr = QString::fromUtf8(fetch->statusText);
+ QByteArray buffer(fetch->data, fetch->numBytes);
+ reply->dataReceived(buffer);
+ QByteArray statusText(fetch->statusText);
+ reply->setStatusCode(fetch->status, statusText);
+ reply->emitReplyError(reply->statusCodeFromHttp(fetch->status, reply->request.url()), reasonStr);
+ reply->setReplyFinished();
+ }
+ reply->m_fetch = nullptr;
}
-
- if (fetch->status >= 400)
- emscripten_fetch_close(fetch); // Also free data on failure.
+ emscripten_fetch_close(fetch);
}
//taken from qhttpthreaddelegate.cpp
@@ -595,3 +631,5 @@ QNetworkReply::NetworkError QNetworkReplyWasmImplPrivate::statusCodeFromHttp(int
}
QT_END_NAMESPACE
+
+#include "moc_qnetworkreplywasmimpl_p.cpp"
diff --git a/src/network/access/qnetworkreplywasmimpl_p.h b/src/network/access/qnetworkreplywasmimpl_p.h
index 53e9bc3375..ae167799d7 100644
--- a/src/network/access/qnetworkreplywasmimpl_p.h
+++ b/src/network/access/qnetworkreplywasmimpl_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNETWORKREPLYWASMIMPL_H
#define QNETWORKREPLYWASMIMPL_H
@@ -63,6 +27,8 @@
#include <emscripten.h>
#include <emscripten/fetch.h>
+#include <memory>
+
QT_BEGIN_NAMESPACE
class QIODevice;
@@ -91,7 +57,7 @@ public:
Q_PRIVATE_SLOT(d_func(), void emitReplyError(QNetworkReply::NetworkError errorCode, const QString &errorString))
Q_PRIVATE_SLOT(d_func(), void emitDataReadProgress(qint64 done, qint64 total))
- Q_PRIVATE_SLOT(d_func(), void dataReceived(char *buffer, int bufferSize))
+ Q_PRIVATE_SLOT(d_func(), void dataReceived(const QByteArray &buffer))
private:
QByteArray methodName() const;
@@ -109,7 +75,7 @@ public:
void emitReplyError(QNetworkReply::NetworkError errorCode, const QString &);
void emitDataReadProgress(qint64 done, qint64 total);
- void dataReceived(const QByteArray &buffer, int bufferSize);
+ void dataReceived(const QByteArray &buffer);
void headersReceived(const QByteArray &buffer);
void setStatusCode(int status, const QByteArray &statusText);
@@ -121,8 +87,8 @@ public:
void _q_bufferOutgoingData();
void _q_bufferOutgoingDataFinished();
- QSharedPointer<QAtomicInt> pendingDownloadData;
- QSharedPointer<QAtomicInt> pendingDownloadProgress;
+ std::shared_ptr<QAtomicInt> pendingDownloadData;
+ std::shared_ptr<QAtomicInt> pendingDownloadProgress;
qint64 bytesDownloaded;
qint64 bytesBuffered;
@@ -134,11 +100,9 @@ public:
QByteArray downloadBuffer;
QIODevice *outgoingData;
- QSharedPointer<QRingBuffer> outgoingDataBuffer;
+ std::shared_ptr<QRingBuffer> outgoingDataBuffer;
QByteArray requestData;
- void doAbort() const;
-
static void downloadProgress(emscripten_fetch_t *fetch);
static void downloadFailed(emscripten_fetch_t *fetch);
static void downloadSucceeded(emscripten_fetch_t *fetch);
@@ -148,6 +112,7 @@ public:
emscripten_fetch_t *m_fetch;
void setReplyFinished();
+ void setCanceled();
Q_DECLARE_PUBLIC(QNetworkReplyWasmImpl)
};
diff --git a/src/network/access/qnetworkrequest.cpp b/src/network/access/qnetworkrequest.cpp
index a02b1fb912..6f5a7ff19a 100644
--- a/src/network/access/qnetworkrequest.cpp
+++ b/src/network/access/qnetworkrequest.cpp
@@ -1,54 +1,22 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qnetworkrequest.h"
#include "qnetworkrequest_p.h"
#include "qplatformdefs.h"
#include "qnetworkcookie.h"
#include "qsslconfiguration.h"
-#if QT_CONFIG(http) || defined(Q_CLANG_QDOC)
+#if QT_CONFIG(http)
+#include "qhttp1configuration.h"
#include "qhttp2configuration.h"
#include "private/http2protocol_p.h"
#endif
-#include "QtCore/qshareddata.h"
-#include "QtCore/qlocale.h"
+
#include "QtCore/qdatetime.h"
+#include "QtCore/qlocale.h"
+#include "QtCore/qshareddata.h"
+#include "QtCore/qtimezone.h"
+#include "QtCore/private/qtools_p.h"
#include <ctype.h>
#if QT_CONFIG(datestring)
@@ -59,6 +27,14 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+using namespace std::chrono_literals;
+
+constexpr std::chrono::milliseconds QNetworkRequest::DefaultTransferTimeout;
+
+QT_IMPL_METATYPE_EXTERN(QNetworkRequest)
+QT_IMPL_METATYPE_EXTERN_TAGGED(QNetworkRequest::RedirectPolicy, QNetworkRequest__RedirectPolicy)
+
/*!
\class QNetworkRequest
\since 4.4
@@ -169,10 +145,10 @@ QT_BEGIN_NAMESPACE
Replies only, type: QMetaType::QUrl (no default)
If present, it indicates that the server is redirecting the
request to a different URL. The Network Access API does follow
- redirections by default, but if
- QNetworkRequest::ManualRedirectPolicy is enabled and
- the redirect was not handled in redirected() then this
- attribute will be present.
+ redirections by default, unless
+ QNetworkRequest::ManualRedirectPolicy is used. Additionally, if
+ QNetworkRequest::UserVerifiedRedirectPolicy is used, then this
+ attribute will be set if the redirect was not followed.
The returned URL might be relative. Use QUrl::resolved()
to create an absolute URL out of it.
@@ -248,7 +224,7 @@ QT_BEGIN_NAMESPACE
Requests only, type: QMetaType::Int (default: QNetworkRequest::Automatic)
Indicates whether to use cached authorization credentials in the request,
if available. If this is set to QNetworkRequest::Manual and the authentication
- mechanism is 'Basic' or 'Digest', Qt will not send an an 'Authorization' HTTP
+ mechanism is 'Basic' or 'Digest', Qt will not send an 'Authorization' HTTP
header with any cached credentials it may have for the request's URL.
This attribute is set to QNetworkRequest::Manual by Qt WebKit when creating a cross-origin
XMLHttpRequest where withCredentials has not been set explicitly to true by the
@@ -272,7 +248,8 @@ QT_BEGIN_NAMESPACE
Requests only, type: QMetaType::Bool (default: true)
Indicates whether the QNetworkAccessManager code is
allowed to use HTTP/2 with this request. This applies
- to SSL requests or 'cleartext' HTTP/2.
+ to SSL requests or 'cleartext' HTTP/2 if Http2CleartextAllowedAttribute
+ is set.
\value Http2WasUsedAttribute
Replies only, type: QMetaType::Bool (default: false)
@@ -304,8 +281,9 @@ QT_BEGIN_NAMESPACE
If set, this attribute will force QNetworkAccessManager to use
HTTP/2 protocol without initial HTTP/2 protocol negotiation.
Use of this attribute implies prior knowledge that a particular
- server supports HTTP/2. The attribute works with SSL or 'cleartext'
- HTTP/2. If a server turns out to not support HTTP/2, when HTTP/2 direct
+ server supports HTTP/2. The attribute works with SSL or with 'cleartext'
+ HTTP/2 if Http2CleartextAllowedAttribute is set.
+ If a server turns out to not support HTTP/2, when HTTP/2 direct
was specified, QNetworkAccessManager gives up, without attempting to
fall back to HTTP/1.1. If both Http2AllowedAttribute and
Http2DirectAttribute are set, Http2DirectAttribute takes priority.
@@ -319,6 +297,28 @@ QT_BEGIN_NAMESPACE
the QNetworkReply after having emitted "finished".
(This value was introduced in 5.14.)
+ \value ConnectionCacheExpiryTimeoutSecondsAttribute
+ Requests only, type: QMetaType::Int
+ To set when the TCP connections to a server (HTTP1 and HTTP2) should
+ be closed after the last pending request had been processed.
+ (This value was introduced in 6.3.)
+
+ \value Http2CleartextAllowedAttribute
+ Requests only, type: QMetaType::Bool (default: false)
+ If set, this attribute will tell QNetworkAccessManager to attempt
+ an upgrade to HTTP/2 over cleartext (also known as h2c).
+ Until Qt 7 the default value for this attribute can be overridden
+ to true by setting the QT_NETWORK_H2C_ALLOWED environment variable.
+ This attribute is ignored if the Http2AllowedAttribute is not set.
+ (This value was introduced in 6.3.)
+
+ \value UseCredentialsAttribute
+ Requests only, type: QMetaType::Bool (default: false)
+ Indicates if the underlying XMLHttpRequest cross-site Access-Control
+ requests should be made using credentials. Has no effect on
+ same-origin requests. This only affects the WebAssembly platform.
+ (This value was introduced in 6.5.)
+
\value User
Special type. Additional information can be passed in
QVariants with types ranging from User to UserMax. The default
@@ -393,6 +393,11 @@ QT_BEGIN_NAMESPACE
for example, to ask the user whether to
accept the redirect, or to decide
based on some app-specific configuration.
+
+ \note When Qt handles redirects it will, for legacy and compatibility
+ reasons, issue the redirected request using GET when the server returns
+ a 301 or 302 response, regardless of the original method used, unless it was
+ HEAD.
*/
/*!
@@ -405,6 +410,16 @@ QT_BEGIN_NAMESPACE
\value DefaultTransferTimeoutConstant The transfer timeout in milliseconds.
Used if setTimeout() is called
without an argument.
+
+ \sa QNetworkRequest::DefaultTransferTimeout
+ */
+
+/*!
+ \variable QNetworkRequest::DefaultTransferTimeout
+
+ The transfer timeout with \l {QNetworkRequest::TransferTimeoutConstant}
+ milliseconds. Used if setTransferTimeout() is called without an
+ argument.
*/
class QNetworkRequestPrivate: public QSharedData, public QNetworkHeadersPrivate
@@ -417,7 +432,6 @@ public:
, sslConfiguration(nullptr)
#endif
, maxRedirectsAllowed(maxRedirectCount)
- , transferTimeout(0)
{ qRegisterMetaType<QNetworkRequest>(); }
~QNetworkRequestPrivate()
{
@@ -440,7 +454,9 @@ public:
#endif
peerVerifyName = other.peerVerifyName;
#if QT_CONFIG(http)
+ h1Configuration = other.h1Configuration;
h2Configuration = other.h2Configuration;
+ decompressedSafetyCheckThreshold = other.decompressedSafetyCheckThreshold;
#endif
transferTimeout = other.transferTimeout;
}
@@ -454,7 +470,9 @@ public:
maxRedirectsAllowed == other.maxRedirectsAllowed &&
peerVerifyName == other.peerVerifyName
#if QT_CONFIG(http)
+ && h1Configuration == other.h1Configuration
&& h2Configuration == other.h2Configuration
+ && decompressedSafetyCheckThreshold == other.decompressedSafetyCheckThreshold
#endif
&& transferTimeout == other.transferTimeout
;
@@ -469,9 +487,11 @@ public:
int maxRedirectsAllowed;
QString peerVerifyName;
#if QT_CONFIG(http)
+ QHttp1Configuration h1Configuration;
QHttp2Configuration h2Configuration;
+ qint64 decompressedSafetyCheckThreshold = 10ll * 1024ll * 1024ll;
#endif
- int transferTimeout;
+ std::chrono::milliseconds transferTimeout = 0ms;
};
/*!
@@ -483,12 +503,12 @@ public:
QNetworkRequest::QNetworkRequest()
: d(new QNetworkRequestPrivate)
{
-
#if QT_CONFIG(http)
- // Initial values proposed by RFC 7540 are quite draconian,
- // so unless an application will set its own parameters, we
- // make stream window size larger and increase (via WINDOW_UPDATE)
- // the session window size. These are our 'defaults':
+ // Initial values proposed by RFC 7540 are quite draconian, but we
+ // know about servers configured with this value as maximum possible,
+ // rejecting our SETTINGS frame and sending us a GOAWAY frame with the
+ // flow control error set. If this causes a problem - the app should
+ // set a proper configuration. We'll use our defaults, as documented.
d->h2Configuration.setStreamReceiveWindowSize(Http2::qtDefaultStreamReceiveWindowSize);
d->h2Configuration.setSessionReceiveWindowSize(Http2::maxSessionReceiveWindowSize);
d->h2Configuration.setServerPushEnabled(false);
@@ -609,8 +629,9 @@ void QNetworkRequest::setHeader(KnownHeaders header, const QVariant &value)
network request.
\sa rawHeader(), setRawHeader()
+ \note In Qt versions prior to 6.7, this function took QByteArray only.
*/
-bool QNetworkRequest::hasRawHeader(const QByteArray &headerName) const
+bool QNetworkRequest::hasRawHeader(QAnyStringView headerName) const
{
return d->findRawHeader(headerName) != d->rawHeaders.constEnd();
}
@@ -624,12 +645,11 @@ bool QNetworkRequest::hasRawHeader(const QByteArray &headerName) const
Raw headers can be set with setRawHeader() or with setHeader().
\sa header(), setRawHeader()
+ \note In Qt versions prior to 6.7, this function took QByteArray only.
*/
-QByteArray QNetworkRequest::rawHeader(const QByteArray &headerName) const
+QByteArray QNetworkRequest::rawHeader(QAnyStringView headerName) const
{
- QNetworkHeadersPrivate::RawHeadersList::ConstIterator it =
- d->findRawHeader(headerName);
- if (it != d->rawHeaders.constEnd())
+ if (const auto it = d->findRawHeader(headerName); it != d->rawHeaders.constEnd())
return it->second;
return QByteArray();
}
@@ -716,9 +736,8 @@ QSslConfiguration QNetworkRequest::sslConfiguration() const
/*!
Sets this network request's SSL configuration to be \a config. The
settings that apply are the private key, the local certificate,
- the SSL protocol (SSLv2, SSLv3, TLSv1.0 where applicable), the CA
- certificates and the ciphers that the SSL backend is allowed to
- use.
+ the TLS protocol (e.g. TLS 1.3), the CA certificates and the ciphers that
+ the SSL backend is allowed to use.
\sa sslConfiguration(), QSslConfiguration::defaultConfiguration()
*/
@@ -852,7 +871,31 @@ void QNetworkRequest::setPeerVerifyName(const QString &peerName)
d->peerVerifyName = peerName;
}
-#if QT_CONFIG(http) || defined(Q_CLANG_QDOC)
+#if QT_CONFIG(http)
+/*!
+ \since 6.5
+
+ Returns the current parameters that QNetworkAccessManager is
+ using for the underlying HTTP/1 connection of this request.
+
+ \sa setHttp1Configuration
+*/
+QHttp1Configuration QNetworkRequest::http1Configuration() const
+{
+ return d->h1Configuration;
+}
+/*!
+ \since 6.5
+
+ Sets request's HTTP/1 parameters from \a configuration.
+
+ \sa http1Configuration, QNetworkAccessManager, QHttp1Configuration
+*/
+void QNetworkRequest::setHttp1Configuration(const QHttp1Configuration &configuration)
+{
+ d->h1Configuration = configuration;
+}
+
/*!
\since 5.14
@@ -865,7 +908,7 @@ void QNetworkRequest::setPeerVerifyName(const QString &peerName)
\list
\li Window size for connection-level flowcontrol is 2147483647 octets
- \li Window size for stream-level flowcontrol is 21474836 octets
+ \li Window size for stream-level flowcontrol is 214748364 octets
\li Max frame size is 16384
\endlist
@@ -896,84 +939,146 @@ void QNetworkRequest::setHttp2Configuration(const QHttp2Configuration &configura
{
d->h2Configuration = configuration;
}
-#endif // QT_CONFIG(http) || defined(Q_CLANG_QDOC)
-#if QT_CONFIG(http) || defined(Q_CLANG_QDOC) || defined (Q_OS_WASM)
+
/*!
+ \since 6.2
+
+ Returns the threshold for archive bomb checks.
+
+ If the decompressed size of a reply is smaller than this, Qt will simply
+ decompress it, without further checking.
+
+ \sa setDecompressedSafetyCheckThreshold()
+*/
+qint64 QNetworkRequest::decompressedSafetyCheckThreshold() const
+{
+ return d->decompressedSafetyCheckThreshold;
+}
+
+/*!
+ \since 6.2
+
+ Sets the \a threshold for archive bomb checks.
+
+ Some supported compression algorithms can, in a tiny compressed file, encode
+ a spectacularly huge decompressed file. This is only possible if the
+ decompressed content is extremely monotonous, which is seldom the case for
+ real files being transmitted in good faith: files exercising such insanely
+ high compression ratios are typically payloads of buffer-overrun attacks, or
+ denial-of-service (by using up too much memory) attacks. Consequently, files
+ that decompress to huge sizes, particularly from tiny compressed forms, are
+ best rejected as suspected malware.
+
+ If a reply's decompressed size is bigger than this threshold (by default,
+ 10 MiB, i.e. 10 * 1024 * 1024), Qt will check the compression ratio: if that
+ is unreasonably large (40:1 for GZip and Deflate, or 100:1 for Brotli and
+ ZStandard), the reply will be treated as an error. Setting the threshold
+ to \c{-1} disables this check.
+
+ \sa decompressedSafetyCheckThreshold()
+*/
+void QNetworkRequest::setDecompressedSafetyCheckThreshold(qint64 threshold)
+{
+ d->decompressedSafetyCheckThreshold = threshold;
+}
+#endif // QT_CONFIG(http)
+
+#if QT_CONFIG(http) || defined (Q_OS_WASM)
+/*!
+ \fn int QNetworkRequest::transferTimeout() const
\since 5.15
Returns the timeout used for transfers, in milliseconds.
- This timeout is zero if setTransferTimeout hasn't been
- called, which means that the timeout is not used.
+ \sa setTransferTimeout()
+*/
+
+/*!
+ \fn void QNetworkRequest::setTransferTimeout(int timeout)
+ \since 5.15
+
+ Sets \a timeout as the transfer timeout in milliseconds.
- \sa setTransferTimeout
+ \sa setTransferTimeout(std::chrono::milliseconds),
+ transferTimeout(), transferTimeoutAsDuration()
*/
-int QNetworkRequest::transferTimeout() const
+
+/*!
+ \since 6.7
+
+ Returns the timeout duration after which the transfer is aborted if no
+ data is exchanged.
+
+ The default duration is zero, which means that the timeout is not used.
+
+ \sa setTransferTimeout(std::chrono::milliseconds)
+*/
+std::chrono::milliseconds QNetworkRequest::transferTimeoutAsDuration() const
{
return d->transferTimeout;
}
/*!
- \since 5.15
+ \since 6.7
- Sets \a timeout as the transfer timeout in milliseconds.
+ Sets the timeout \a duration to abort the transfer if no data is exchanged.
Transfers are aborted if no bytes are transferred before
the timeout expires. Zero means no timer is set. If no
argument is provided, the timeout is
- QNetworkRequest::DefaultTransferTimeoutConstant. If this function
+ QNetworkRequest::DefaultTransferTimeout. If this function
is not called, the timeout is disabled and has the
value zero.
- \sa transferTimeout
+ \sa transferTimeoutAsDuration()
*/
-void QNetworkRequest::setTransferTimeout(int timeout)
+void QNetworkRequest::setTransferTimeout(std::chrono::milliseconds duration)
{
- d->transferTimeout = timeout;
+ d->transferTimeout = duration;
}
-#endif // QT_CONFIG(http) || defined(Q_CLANG_QDOC) || defined (Q_OS_WASM)
+#endif // QT_CONFIG(http) || defined (Q_OS_WASM)
static QByteArray headerName(QNetworkRequest::KnownHeaders header)
{
switch (header) {
case QNetworkRequest::ContentTypeHeader:
- return "Content-Type";
+ return "Content-Type"_ba;
case QNetworkRequest::ContentLengthHeader:
- return "Content-Length";
+ return "Content-Length"_ba;
case QNetworkRequest::LocationHeader:
- return "Location";
+ return "Location"_ba;
case QNetworkRequest::LastModifiedHeader:
- return "Last-Modified";
+ return "Last-Modified"_ba;
case QNetworkRequest::IfModifiedSinceHeader:
- return "If-Modified-Since";
+ return "If-Modified-Since"_ba;
case QNetworkRequest::ETagHeader:
- return "ETag";
+ return "ETag"_ba;
case QNetworkRequest::IfMatchHeader:
- return "If-Match";
+ return "If-Match"_ba;
case QNetworkRequest::IfNoneMatchHeader:
- return "If-None-Match";
+ return "If-None-Match"_ba;
case QNetworkRequest::CookieHeader:
- return "Cookie";
+ return "Cookie"_ba;
case QNetworkRequest::SetCookieHeader:
- return "Set-Cookie";
+ return "Set-Cookie"_ba;
case QNetworkRequest::ContentDispositionHeader:
- return "Content-Disposition";
+ return "Content-Disposition"_ba;
case QNetworkRequest::UserAgentHeader:
- return "User-Agent";
+ return "User-Agent"_ba;
case QNetworkRequest::ServerHeader:
- return "Server";
+ return "Server"_ba;
// no default:
// if new values are added, this will generate a compiler warning
@@ -982,6 +1087,22 @@ static QByteArray headerName(QNetworkRequest::KnownHeaders header)
return QByteArray();
}
+static QByteArray makeCookieHeader(const QVariant &value, QNetworkCookie::RawForm type, QByteArrayView separator)
+{
+ QList<QNetworkCookie> cookies = qvariant_cast<QList<QNetworkCookie> >(value);
+ if (cookies.isEmpty() && value.userType() == qMetaTypeId<QNetworkCookie>())
+ cookies << qvariant_cast<QNetworkCookie>(value);
+
+ QByteArray result;
+ for (const QNetworkCookie &cookie : std::as_const(cookies)) {
+ result += cookie.toRawForm(type);
+ result += separator;
+ }
+ if (!result.isEmpty())
+ result.chop(separator.size());
+ return result;
+}
+
static QByteArray headerValue(QNetworkRequest::KnownHeaders header, const QVariant &value)
{
switch (header) {
@@ -1007,98 +1128,77 @@ static QByteArray headerValue(QNetworkRequest::KnownHeaders header, const QVaria
case QNetworkRequest::LastModifiedHeader:
case QNetworkRequest::IfModifiedSinceHeader:
switch (value.userType()) {
+ // Generate RFC 1123/822 dates:
case QMetaType::QDate:
+ return QNetworkHeadersPrivate::toHttpDate(value.toDate().startOfDay(QTimeZone::UTC));
case QMetaType::QDateTime:
- // generate RFC 1123/822 dates:
return QNetworkHeadersPrivate::toHttpDate(value.toDateTime());
default:
return value.toByteArray();
}
- case QNetworkRequest::CookieHeader: {
- QList<QNetworkCookie> cookies = qvariant_cast<QList<QNetworkCookie> >(value);
- if (cookies.isEmpty() && value.userType() == qMetaTypeId<QNetworkCookie>())
- cookies << qvariant_cast<QNetworkCookie>(value);
-
- QByteArray result;
- bool first = true;
- for (const QNetworkCookie &cookie : qAsConst(cookies)) {
- if (!first)
- result += "; ";
- first = false;
- result += cookie.toRawForm(QNetworkCookie::NameAndValueOnly);
- }
- return result;
- }
+ case QNetworkRequest::CookieHeader:
+ return makeCookieHeader(value, QNetworkCookie::NameAndValueOnly, "; ");
- case QNetworkRequest::SetCookieHeader: {
- QList<QNetworkCookie> cookies = qvariant_cast<QList<QNetworkCookie> >(value);
- if (cookies.isEmpty() && value.userType() == qMetaTypeId<QNetworkCookie>())
- cookies << qvariant_cast<QNetworkCookie>(value);
-
- QByteArray result;
- bool first = true;
- for (const QNetworkCookie &cookie : qAsConst(cookies)) {
- if (!first)
- result += ", ";
- first = false;
- result += cookie.toRawForm(QNetworkCookie::Full);
- }
- return result;
- }
+ case QNetworkRequest::SetCookieHeader:
+ return makeCookieHeader(value, QNetworkCookie::Full, ", ");
}
return QByteArray();
}
-static int parseHeaderName(const QByteArray &headerName)
+static int parseHeaderName(QByteArrayView headerName)
{
if (headerName.isEmpty())
return -1;
- switch (tolower(headerName.at(0))) {
+ auto is = [headerName](QByteArrayView what) {
+ return headerName.compare(what, Qt::CaseInsensitive) == 0;
+ };
+
+ switch (QtMiscUtils::toAsciiLower(headerName.front())) {
case 'c':
- if (headerName.compare("content-type", Qt::CaseInsensitive) == 0)
+ if (is("content-type"))
return QNetworkRequest::ContentTypeHeader;
- else if (headerName.compare("content-length", Qt::CaseInsensitive) == 0)
+ else if (is("content-length"))
return QNetworkRequest::ContentLengthHeader;
- else if (headerName.compare("cookie", Qt::CaseInsensitive) == 0)
+ else if (is("cookie"))
return QNetworkRequest::CookieHeader;
- else if (qstricmp(headerName.constData(), "content-disposition") == 0)
+ else if (is("content-disposition"))
return QNetworkRequest::ContentDispositionHeader;
break;
case 'e':
- if (qstricmp(headerName.constData(), "etag") == 0)
+ if (is("etag"))
return QNetworkRequest::ETagHeader;
break;
case 'i':
- if (qstricmp(headerName.constData(), "if-modified-since") == 0)
+ if (is("if-modified-since"))
return QNetworkRequest::IfModifiedSinceHeader;
- if (qstricmp(headerName.constData(), "if-match") == 0)
+ if (is("if-match"))
return QNetworkRequest::IfMatchHeader;
- if (qstricmp(headerName.constData(), "if-none-match") == 0)
+ if (is("if-none-match"))
return QNetworkRequest::IfNoneMatchHeader;
break;
case 'l':
- if (headerName.compare("location", Qt::CaseInsensitive) == 0)
+ if (is("location"))
return QNetworkRequest::LocationHeader;
- else if (headerName.compare("last-modified", Qt::CaseInsensitive) == 0)
+ else if (is("last-modified"))
return QNetworkRequest::LastModifiedHeader;
break;
case 's':
- if (headerName.compare("set-cookie", Qt::CaseInsensitive) == 0)
+ if (is("set-cookie"))
return QNetworkRequest::SetCookieHeader;
- else if (headerName.compare("server", Qt::CaseInsensitive) == 0)
+ else if (is("server"))
return QNetworkRequest::ServerHeader;
break;
case 'u':
- if (headerName.compare("user-agent", Qt::CaseInsensitive) == 0)
+ if (is("user-agent"))
return QNetworkRequest::UserAgentHeader;
break;
}
@@ -1114,13 +1214,12 @@ static QVariant parseHttpDate(const QByteArray &raw)
return QVariant(); // transform an invalid QDateTime into a null QVariant
}
-static QVariant parseCookieHeader(const QByteArray &raw)
+static QVariant parseCookieHeader(QByteArrayView raw)
{
QList<QNetworkCookie> result;
- const QList<QByteArray> cookieList = raw.split(';');
- for (const QByteArray &cookie : cookieList) {
+ for (auto cookie : QLatin1StringView(raw).tokenize(';'_L1)) {
QList<QNetworkCookie> parsed = QNetworkCookie::parseCookies(cookie.trimmed());
- if (parsed.count() != 1)
+ if (parsed.size() != 1)
return QVariant(); // invalid Cookie: header
result += parsed;
@@ -1129,9 +1228,9 @@ static QVariant parseCookieHeader(const QByteArray &raw)
return QVariant::fromValue(result);
}
-static QVariant parseETag(const QByteArray &raw)
+static QVariant parseETag(QByteArrayView raw)
{
- const QByteArray trimmed = raw.trimmed();
+ const QByteArrayView trimmed = raw.trimmed();
if (!trimmed.startsWith('"') && !trimmed.startsWith(R"(W/")"))
return QVariant();
@@ -1141,46 +1240,34 @@ static QVariant parseETag(const QByteArray &raw)
return QString::fromLatin1(trimmed);
}
-static QVariant parseIfMatch(const QByteArray &raw)
+template<typename T>
+static QVariant parseMatchImpl(QByteArrayView raw, T op)
{
- const QByteArray trimmedRaw = raw.trimmed();
+ const QByteArrayView trimmedRaw = raw.trimmed();
if (trimmedRaw == "*")
return QStringList(QStringLiteral("*"));
QStringList tags;
- const QList<QByteArray> split = trimmedRaw.split(',');
- for (const QByteArray &element : split) {
- const QByteArray trimmed = element.trimmed();
- if (!trimmed.startsWith('"'))
- continue;
-
- if (!trimmed.endsWith('"'))
- continue;
-
- tags += QString::fromLatin1(trimmed);
+ for (auto &element : QLatin1StringView(trimmedRaw).tokenize(','_L1)) {
+ if (const auto trimmed = element.trimmed(); op(trimmed))
+ tags += QString::fromLatin1(trimmed);
}
return tags;
}
-static QVariant parseIfNoneMatch(const QByteArray &raw)
-{
- const QByteArray trimmedRaw = raw.trimmed();
- if (trimmedRaw == "*")
- return QStringList(QStringLiteral("*"));
- QStringList tags;
- const QList<QByteArray> split = trimmedRaw.split(',');
- for (const QByteArray &element : split) {
- const QByteArray trimmed = element.trimmed();
- if (!trimmed.startsWith('"') && !trimmed.startsWith(R"(W/")"))
- continue;
-
- if (!trimmed.endsWith('"'))
- continue;
+static QVariant parseIfMatch(QByteArrayView raw)
+{
+ return parseMatchImpl(raw, [](QByteArrayView element) {
+ return element.startsWith('"') && element.endsWith('"');
+ });
+}
- tags += QString::fromLatin1(trimmed);
- }
- return tags;
+static QVariant parseIfNoneMatch(QByteArrayView raw)
+{
+ return parseMatchImpl(raw, [](QByteArrayView element) {
+ return (element.startsWith('"') || element.startsWith(R"(W/")")) && element.endsWith('"');
+ });
}
@@ -1197,7 +1284,7 @@ static QVariant parseHeaderValue(QNetworkRequest::KnownHeaders header, const QBy
case QNetworkRequest::ContentLengthHeader: {
bool ok;
- qint64 result = value.trimmed().toLongLong(&ok);
+ qint64 result = QByteArrayView(value).trimmed().toLongLong(&ok);
if (ok)
return result;
return QVariant();
@@ -1236,15 +1323,14 @@ static QVariant parseHeaderValue(QNetworkRequest::KnownHeaders header, const QBy
}
QNetworkHeadersPrivate::RawHeadersList::ConstIterator
-QNetworkHeadersPrivate::findRawHeader(const QByteArray &key) const
+QNetworkHeadersPrivate::findRawHeader(QAnyStringView key) const
{
- RawHeadersList::ConstIterator it = rawHeaders.constBegin();
- RawHeadersList::ConstIterator end = rawHeaders.constEnd();
- for ( ; it != end; ++it)
- if (it->first.compare(key, Qt::CaseInsensitive) == 0)
- return it;
-
- return end; // not found
+ auto isKeyEqual = [key](const auto &headerPair)
+ {
+ QLatin1StringView name{headerPair.first};
+ return QAnyStringView::compare(name, key, Qt::CaseInsensitive) == 0;
+ };
+ return std::find_if(rawHeaders.begin(), rawHeaders.end(), isKeyEqual);
}
QNetworkHeadersPrivate::RawHeadersList QNetworkHeadersPrivate::allRawHeaders() const
@@ -1256,10 +1342,8 @@ QList<QByteArray> QNetworkHeadersPrivate::rawHeadersKeys() const
{
QList<QByteArray> result;
result.reserve(rawHeaders.size());
- RawHeadersList::ConstIterator it = rawHeaders.constBegin(),
- end = rawHeaders.constEnd();
- for ( ; it != end; ++it)
- result << it->first;
+ for (const auto &pair : rawHeaders)
+ result << pair.first;
return result;
}
@@ -1287,10 +1371,8 @@ void QNetworkHeadersPrivate::setAllRawHeaders(const RawHeadersList &list)
cookedHeaders.clear();
rawHeaders = list;
- RawHeadersList::ConstIterator it = rawHeaders.constBegin();
- RawHeadersList::ConstIterator end = rawHeaders.constEnd();
- for ( ; it != end; ++it)
- parseAndSetHeader(it->first, it->second);
+ for (const auto &[key, value] : std::as_const(rawHeaders))
+ parseAndSetHeader(key, value);
}
void QNetworkHeadersPrivate::setCookedHeader(QNetworkRequest::KnownHeaders header,
@@ -1324,9 +1406,7 @@ void QNetworkHeadersPrivate::setRawHeaderInternal(const QByteArray &key, const Q
auto firstEqualsKey = [&key](const RawHeaderPair &header) {
return header.first.compare(key, Qt::CaseInsensitive) == 0;
};
- rawHeaders.erase(std::remove_if(rawHeaders.begin(), rawHeaders.end(),
- firstEqualsKey),
- rawHeaders.end());
+ rawHeaders.removeIf(firstEqualsKey);
if (value.isNull())
return; // only wanted to erase key
@@ -1441,20 +1521,21 @@ QDateTime QNetworkHeadersPrivate::fromHttpDate(const QByteArray &value)
// eat the weekday, the comma and the space following it
QString sansWeekday = QString::fromLatin1(value.constData() + pos + 2);
// must be RFC 850 date
- dt = c.toDateTime(sansWeekday, QLatin1String("dd-MMM-yy hh:mm:ss 'GMT'"));
+ dt = c.toDateTime(sansWeekday, "dd-MMM-yy hh:mm:ss 'GMT'"_L1);
}
}
#endif // datestring
if (dt.isValid())
- dt.setTimeSpec(Qt::UTC);
+ dt.setTimeZone(QTimeZone::UTC);
return dt;
}
QByteArray QNetworkHeadersPrivate::toHttpDate(const QDateTime &dt)
{
- return QLocale::c().toString(dt, u"ddd, dd MMM yyyy hh:mm:ss 'GMT'")
- .toLatin1();
+ return QLocale::c().toString(dt.toUTC(), u"ddd, dd MMM yyyy hh:mm:ss 'GMT'").toLatin1();
}
QT_END_NAMESPACE
+
+#include "moc_qnetworkrequest.cpp"
diff --git a/src/network/access/qnetworkrequest.h b/src/network/access/qnetworkrequest.h
index e4dd5870cf..3ca61a2ee3 100644
--- a/src/network/access/qnetworkrequest.h
+++ b/src/network/access/qnetworkrequest.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNETWORKREQUEST_H
#define QNETWORKREQUEST_H
@@ -50,10 +14,12 @@ QT_BEGIN_NAMESPACE
class QSslConfiguration;
class QHttp2Configuration;
+class QHttp1Configuration;
class QNetworkRequestPrivate;
class Q_NETWORK_EXPORT QNetworkRequest
{
+ Q_GADGET
public:
enum KnownHeaders {
ContentTypeHeader,
@@ -70,6 +36,8 @@ public:
IfMatchHeader,
IfNoneMatchHeader
};
+ Q_ENUM(KnownHeaders)
+
enum Attribute {
HttpStatusCodeAttribute,
HttpReasonPhraseAttribute,
@@ -89,7 +57,7 @@ public:
DownloadBufferAttribute, // internal
SynchronousRequestAttribute, // internal
BackgroundRequestAttribute,
- EmitAllUploadProgressSignalsAttribute = BackgroundRequestAttribute + 3,
+ EmitAllUploadProgressSignalsAttribute,
Http2AllowedAttribute,
Http2WasUsedAttribute,
OriginalContentLengthAttribute,
@@ -97,6 +65,9 @@ public:
Http2DirectAttribute,
ResourceTypeAttribute, // internal
AutoDeleteReplyOnFinishAttribute,
+ ConnectionCacheExpiryTimeoutSecondsAttribute,
+ Http2CleartextAllowedAttribute,
+ UseCredentialsAttribute,
User = 1000,
UserMax = 32767
@@ -129,6 +100,9 @@ public:
DefaultTransferTimeoutConstant = 30000
};
+ static constexpr auto DefaultTransferTimeout =
+ std::chrono::milliseconds(DefaultTransferTimeoutConstant);
+
QNetworkRequest();
explicit QNetworkRequest(const QUrl &url);
QNetworkRequest(const QNetworkRequest &other);
@@ -136,7 +110,7 @@ public:
QNetworkRequest &operator=(QNetworkRequest &&other) noexcept { swap(other); return *this; }
QNetworkRequest &operator=(const QNetworkRequest &other);
- void swap(QNetworkRequest &other) noexcept { qSwap(d, other.d); }
+ void swap(QNetworkRequest &other) noexcept { d.swap(other.d); }
bool operator==(const QNetworkRequest &other) const;
inline bool operator!=(const QNetworkRequest &other) const
@@ -150,9 +124,15 @@ public:
void setHeader(KnownHeaders header, const QVariant &value);
// raw headers:
+#if QT_NETWORK_REMOVED_SINCE(6, 7)
bool hasRawHeader(const QByteArray &headerName) const;
+#endif
+ bool hasRawHeader(QAnyStringView headerName) const;
QList<QByteArray> rawHeaderList() const;
+#if QT_NETWORK_REMOVED_SINCE(6, 7)
QByteArray rawHeader(const QByteArray &headerName) const;
+#endif
+ QByteArray rawHeader(QAnyStringView headerName) const;
void setRawHeader(const QByteArray &headerName, const QByteArray &value);
// attributes
@@ -176,14 +156,26 @@ public:
QString peerVerifyName() const;
void setPeerVerifyName(const QString &peerName);
-#if QT_CONFIG(http) || defined(Q_CLANG_QDOC)
+#if QT_CONFIG(http)
+ QHttp1Configuration http1Configuration() const;
+ void setHttp1Configuration(const QHttp1Configuration &configuration);
+
QHttp2Configuration http2Configuration() const;
void setHttp2Configuration(const QHttp2Configuration &configuration);
-#endif // QT_CONFIG(http) || defined(Q_CLANG_QDOC)
-#if QT_CONFIG(http) || defined(Q_CLANG_QDOC) || defined (Q_OS_WASM)
+
+ qint64 decompressedSafetyCheckThreshold() const;
+ void setDecompressedSafetyCheckThreshold(qint64 threshold);
+#endif // QT_CONFIG(http)
+
+#if QT_CONFIG(http) || defined (Q_OS_WASM)
+ QT_NETWORK_INLINE_SINCE(6, 8)
int transferTimeout() const;
- void setTransferTimeout(int timeout = DefaultTransferTimeoutConstant);
-#endif // QT_CONFIG(http) || defined(Q_CLANG_QDOC) || defined (Q_OS_WASM)
+ QT_NETWORK_INLINE_SINCE(6, 8)
+ void setTransferTimeout(int timeout);
+
+ std::chrono::milliseconds transferTimeoutAsDuration() const;
+ void setTransferTimeout(std::chrono::milliseconds duration = DefaultTransferTimeout);
+#endif // QT_CONFIG(http) || defined (Q_OS_WASM)
private:
QSharedDataPointer<QNetworkRequestPrivate> d;
friend class QNetworkRequestPrivate;
@@ -191,9 +183,24 @@ private:
Q_DECLARE_SHARED(QNetworkRequest)
+#if QT_NETWORK_INLINE_IMPL_SINCE(6, 8)
+#if QT_CONFIG(http) || defined (Q_OS_WASM)
+int QNetworkRequest::transferTimeout() const
+{
+ return int(transferTimeoutAsDuration().count());
+}
+
+void QNetworkRequest::setTransferTimeout(int timeout)
+{
+ setTransferTimeout(std::chrono::milliseconds(timeout));
+}
+#endif // QT_CONFIG(http) || defined (Q_OS_WASM)
+#endif // INLINE_SINCE 6.8
+
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QNetworkRequest)
-Q_DECLARE_METATYPE(QNetworkRequest::RedirectPolicy)
+QT_DECL_METATYPE_EXTERN(QNetworkRequest, Q_NETWORK_EXPORT)
+QT_DECL_METATYPE_EXTERN_TAGGED(QNetworkRequest::RedirectPolicy,
+ QNetworkRequest__RedirectPolicy, Q_NETWORK_EXPORT)
#endif
diff --git a/src/network/access/qnetworkrequest_p.h b/src/network/access/qnetworkrequest_p.h
index 5e18da6d55..48fcdcf1ed 100644
--- a/src/network/access/qnetworkrequest_p.h
+++ b/src/network/access/qnetworkrequest_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNETWORKREQUEST_P_H
#define QNETWORKREQUEST_P_H
@@ -76,7 +40,7 @@ public:
AttributesMap attributes;
QPointer<QObject> originatingObject;
- RawHeadersList::ConstIterator findRawHeader(const QByteArray &key) const;
+ RawHeadersList::ConstIterator findRawHeader(QAnyStringView key) const;
RawHeadersList allRawHeaders() const;
QList<QByteArray> rawHeadersKeys() const;
void setRawHeader(const QByteArray &key, const QByteArray &value);
@@ -91,7 +55,7 @@ private:
void parseAndSetHeader(const QByteArray &key, const QByteArray &value);
};
-Q_DECLARE_TYPEINFO(QNetworkHeadersPrivate::RawHeaderPair, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QNetworkHeadersPrivate::RawHeaderPair, Q_RELOCATABLE_TYPE);
QT_END_NAMESPACE
diff --git a/src/network/access/qnetworkrequestfactory.cpp b/src/network/access/qnetworkrequestfactory.cpp
new file mode 100644
index 0000000000..87738d9086
--- /dev/null
+++ b/src/network/access/qnetworkrequestfactory.cpp
@@ -0,0 +1,727 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qnetworkrequestfactory.h"
+#include "qnetworkrequestfactory_p.h"
+
+#if QT_CONFIG(ssl)
+#include <QtNetwork/qsslconfiguration.h>
+#endif
+
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qmap.h>
+
+QT_BEGIN_NAMESPACE
+
+QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QNetworkRequestFactoryPrivate)
+
+using namespace Qt::StringLiterals;
+
+Q_LOGGING_CATEGORY(lcQrequestfactory, "qt.network.access.request.factory")
+
+/*!
+ \class QNetworkRequestFactory
+ \since 6.7
+ \ingroup shared
+ \inmodule QtNetwork
+
+ \brief Convenience class for grouping remote server endpoints that share
+ common network request properties.
+
+ \preliminary
+
+ REST servers often have endpoints that require the same headers and other data.
+ Grouping such endpoints with a QNetworkRequestFactory makes it more
+ convenient to issue requests to these endpoints; only the typically
+ varying parts such as \e path and \e query parameters are provided
+ when creating a new request.
+
+ Basic usage steps of QNetworkRequestFactory are as follows:
+ \list
+ \li Instantiation
+ \li Setting the data common to all requests
+ \li Issuing requests
+ \endlist
+
+ An example of usage:
+
+ \snippet code/src_network_access_qnetworkrequestfactory.cpp 0
+*/
+
+/*!
+ Creates a new QNetworkRequestFactory object.
+ Use setBaseUrl() to set a valid base URL for the requests.
+
+ \sa QNetworkRequestFactory(const QUrl &baseUrl), setBaseUrl()
+*/
+
+QNetworkRequestFactory::QNetworkRequestFactory()
+ : d(new QNetworkRequestFactoryPrivate)
+{
+}
+
+/*!
+ Creates a new QNetworkRequestFactory object, initializing the base URL to
+ \a baseUrl. The base URL is used to populate subsequent network
+ requests.
+
+ If the URL contains a \e path component, it will be extracted and used
+ as a base path in subsequent network requests. This means that any
+ paths provided when requesting individual requests will be appended
+ to this base path, as illustrated below:
+
+ \snippet code/src_network_access_qnetworkrequestfactory.cpp 1
+ */
+QNetworkRequestFactory::QNetworkRequestFactory(const QUrl &baseUrl)
+ : d(new QNetworkRequestFactoryPrivate(baseUrl))
+{
+}
+
+/*!
+ Destroys this QNetworkRequestFactory object.
+ */
+QNetworkRequestFactory::~QNetworkRequestFactory()
+ = default;
+
+/*!
+ Creates a copy of \a other.
+ */
+QNetworkRequestFactory::QNetworkRequestFactory(const QNetworkRequestFactory &other)
+ = default;
+
+/*!
+ Creates a copy of \a other and returns a reference to this factory.
+ */
+QNetworkRequestFactory &QNetworkRequestFactory::operator=(const QNetworkRequestFactory &other)
+ = default;
+
+/*!
+ \fn QNetworkRequestFactory::QNetworkRequestFactory(QNetworkRequestFactory &&other) noexcept
+
+ Move-constructs the factory from \a other.
+
+ \note The moved-from object \a other is placed in a
+ partially-formed state, in which the only valid operations are
+ destruction and assignment of a new value.
+*/
+
+/*!
+ \fn QNetworkRequestFactory &QNetworkRequestFactory::operator=(QNetworkRequestFactory &&other) noexcept
+
+ Move-assigns \a other and returns a reference to this factory.
+
+ \note The moved-from object \a other is placed in a
+ partially-formed state, in which the only valid operations are
+ destruction and assignment of a new value.
+ */
+
+/*!
+ \fn void QNetworkRequestFactory::swap(QNetworkRequestFactory &other)
+
+ Swaps this factory with \a other. This operation is
+ very fast and never fails.
+ */
+
+/*!
+ Returns the base URL used for the individual requests.
+
+ The base URL may contain a path component. This path is used
+ as path "prefix" for the paths that are provided when generating
+ individual requests.
+
+ \sa setBaseUrl()
+ */
+QUrl QNetworkRequestFactory::baseUrl() const
+{
+ return d->baseUrl;
+}
+
+/*!
+ Sets the base URL used in individual requests to \a url.
+
+ \sa baseUrl()
+ */
+void QNetworkRequestFactory::setBaseUrl(const QUrl &url)
+{
+ if (d->baseUrl == url)
+ return;
+
+ d.detach();
+ d->baseUrl = url;
+}
+
+#if QT_CONFIG(ssl)
+/*!
+ Returns the SSL configuration set to this factory. The SSL configuration
+ is set to each individual request.
+
+ \sa setSslConfiguration()
+ */
+QSslConfiguration QNetworkRequestFactory::sslConfiguration() const
+{
+ return d->sslConfig;
+}
+
+/*!
+ Sets the SSL configuration to \a configuration.
+
+ \sa sslConfiguration()
+ */
+void QNetworkRequestFactory::setSslConfiguration(const QSslConfiguration &configuration)
+{
+ if (d->sslConfig == configuration)
+ return;
+
+ d.detach();
+ d->sslConfig = configuration;
+}
+#endif
+
+/*!
+ Returns a QNetworkRequest.
+
+ The returned request is filled with the data that this factory
+ has been configured with.
+
+ \sa createRequest(const QUrlQuery&), createRequest(const QString&, const QUrlQuery&)
+*/
+
+QNetworkRequest QNetworkRequestFactory::createRequest() const
+{
+ return d->newRequest(d->requestUrl());
+}
+
+/*!
+ Returns a QNetworkRequest.
+
+ The returned request's URL is formed by appending the provided \a path
+ to the baseUrl (which may itself have a path component).
+
+ \sa createRequest(const QString &, const QUrlQuery &), createRequest(), baseUrl()
+*/
+QNetworkRequest QNetworkRequestFactory::createRequest(const QString &path) const
+{
+ return d->newRequest(d->requestUrl(&path));
+}
+
+/*!
+ Returns a QNetworkRequest.
+
+ The returned request's URL is formed by appending the provided \a query
+ to the baseUrl.
+
+ \sa createRequest(const QString &, const QUrlQuery &), createRequest(), baseUrl()
+*/
+QNetworkRequest QNetworkRequestFactory::createRequest(const QUrlQuery &query) const
+{
+ return d->newRequest(d->requestUrl(nullptr, &query));
+}
+
+/*!
+ Returns a QNetworkRequest.
+
+ The returned requests URL is formed by appending the provided \a path
+ and \a query to the baseUrl (which may have a path component).
+
+ If the provided \a path contains query items, they will be combined
+ with the items in \a query.
+
+ \sa createRequest(const QUrlQuery&), createRequest(), baseUrl()
+ */
+QNetworkRequest QNetworkRequestFactory::createRequest(const QString &path, const QUrlQuery &query) const
+{
+ return d->newRequest(d->requestUrl(&path, &query));
+}
+
+/*!
+ Sets \a headers that are common to all requests.
+
+ These headers are added to individual requests' headers.
+ This is a convenience mechanism for setting headers that
+ repeat across requests.
+
+ \sa commonHeaders(), clearCommonHeaders(), createRequest()
+ */
+void QNetworkRequestFactory::setCommonHeaders(const QHttpHeaders &headers)
+{
+ d.detach();
+ d->headers = headers;
+}
+
+/*!
+ Returns the currently set headers.
+
+ \sa setCommonHeaders(), clearCommonHeaders()
+ */
+QHttpHeaders QNetworkRequestFactory::commonHeaders() const
+{
+ return d->headers;
+}
+
+/*!
+ Clears current headers.
+
+ \sa commonHeaders(), setCommonHeaders()
+*/
+void QNetworkRequestFactory::clearCommonHeaders()
+{
+ if (d->headers.isEmpty())
+ return;
+ d.detach();
+ d->headers.clear();
+}
+
+/*!
+ Returns the bearer token that has been set.
+
+ The bearer token, if present, is used to set the
+ \c {Authorization: Bearer my_token} header for requests. This is a common
+ authorization convention and is provided as an additional convenience.
+
+ The means to acquire the bearer token vary. Standard methods include \c OAuth2
+ and the service provider's website/dashboard. It is expected that the bearer
+ token changes over time. For example, when updated with a refresh token,
+ always setting the new token again ensures that subsequent requests have
+ the latest, valid token.
+
+ The presence of the bearer token does not impact the \l commonHeaders()
+ listing. If the \l commonHeaders() also lists \c Authorization header, it
+ will be overwritten.
+
+ \sa setBearerToken(), commonHeaders()
+ */
+QByteArray QNetworkRequestFactory::bearerToken() const
+{
+ return d->bearerToken;
+}
+
+/*!
+ Sets the bearer token to \a token.
+
+ \sa bearerToken(), clearBearerToken()
+*/
+void QNetworkRequestFactory::setBearerToken(const QByteArray &token)
+{
+ if (d->bearerToken == token)
+ return;
+
+ d.detach();
+ d->bearerToken = token;
+}
+
+/*!
+ Clears the bearer token.
+
+ \sa bearerToken()
+*/
+void QNetworkRequestFactory::clearBearerToken()
+{
+ if (d->bearerToken.isEmpty())
+ return;
+
+ d.detach();
+ d->bearerToken.clear();
+}
+
+/*!
+ Returns the username set to this factory.
+
+ \sa setUserName(), clearUserName(), password()
+*/
+QString QNetworkRequestFactory::userName() const
+{
+ return d->userName;
+}
+
+/*!
+ Sets the username of this factory to \a userName.
+
+ The username is set in the request URL when \l createRequest() is called.
+ The QRestAccessManager / QNetworkAccessManager will attempt to use
+ these credentials when the server indicates that authentication
+ is required.
+
+ \sa userName(), clearUserName(), password()
+*/
+void QNetworkRequestFactory::setUserName(const QString &userName)
+{
+ if (d->userName == userName)
+ return;
+ d.detach();
+ d->userName = userName;
+}
+
+/*!
+ Clears the username set to this factory.
+*/
+void QNetworkRequestFactory::clearUserName()
+{
+ if (d->userName.isEmpty())
+ return;
+ d.detach();
+ d->userName.clear();
+}
+
+/*!
+ Returns the password set to this factory.
+
+ \sa password(), clearPassword(), userName()
+*/
+QString QNetworkRequestFactory::password() const
+{
+ return d->password;
+}
+
+/*!
+ Sets the password of this factory to \a password.
+
+ The password is set in the request URL when \l createRequest() is called.
+ The QRestAccessManager / QNetworkAccessManager will attempt to use
+ these credentials when the server indicates that authentication
+ is required.
+
+ \sa password(), clearPassword(), userName()
+*/
+void QNetworkRequestFactory::setPassword(const QString &password)
+{
+ if (d->password == password)
+ return;
+ d.detach();
+ d->password = password;
+}
+
+/*!
+ Clears the password set to this factory.
+
+ \sa password(), setPassword(), userName()
+*/
+void QNetworkRequestFactory::clearPassword()
+{
+ if (d->password.isEmpty())
+ return;
+ d.detach();
+ d->password.clear();
+}
+
+/*!
+ Sets \a timeout used for transfers.
+
+ \sa transferTimeout(), QNetworkRequest::setTransferTimeout(),
+ QNetworkAccessManager::setTransferTimeout()
+*/
+void QNetworkRequestFactory::setTransferTimeout(std::chrono::milliseconds timeout)
+{
+ if (d->transferTimeout == timeout)
+ return;
+
+ d.detach();
+ d->transferTimeout = timeout;
+}
+
+/*!
+ Returns the timeout used for transfers.
+
+ \sa setTransferTimeout(), QNetworkRequest::transferTimeout(),
+ QNetworkAccessManager::transferTimeout()
+*/
+std::chrono::milliseconds QNetworkRequestFactory::transferTimeout() const
+{
+ return d->transferTimeout;
+}
+
+/*!
+ Returns query parameters that are added to individual requests' query
+ parameters. The query parameters are added to any potential query
+ parameters provided with the individual \l createRequest() calls.
+
+ Use cases for using repeating query parameters are server dependent,
+ but typical examples include language setting \c {?lang=en}, format
+ specification \c {?format=json}, API version specification
+ \c {?version=1.0} and API key authentication.
+
+ \sa setQueryParameters(), clearQueryParameters(), createRequest()
+*/
+QUrlQuery QNetworkRequestFactory::queryParameters() const
+{
+ return d->queryParameters;
+}
+
+/*!
+ Sets \a query parameters that are added to individual requests' query
+ parameters.
+
+ \sa queryParameters(), clearQueryParameters()
+ */
+void QNetworkRequestFactory::setQueryParameters(const QUrlQuery &query)
+{
+ if (d->queryParameters == query)
+ return;
+
+ d.detach();
+ d->queryParameters = query;
+}
+
+/*!
+ Clears the query parameters.
+
+ \sa queryParameters()
+*/
+void QNetworkRequestFactory::clearQueryParameters()
+{
+ if (d->queryParameters.isEmpty())
+ return;
+
+ d.detach();
+ d->queryParameters.clear();
+}
+
+/*!
+ \since 6.8
+
+ Sets the priority for any future requests created by this factory to
+ \a priority.
+
+ The default priority is \l QNetworkRequest::NormalPriority.
+
+ \sa priority(), QNetworkRequest::setPriority()
+*/
+void QNetworkRequestFactory::setPriority(QNetworkRequest::Priority priority)
+{
+ if (d->priority == priority)
+ return;
+ d.detach();
+ d->priority = priority;
+}
+
+/*!
+ \since 6.8
+
+ Returns the priority assigned to any future requests created by this
+ factory.
+
+ \sa setPriority(), QNetworkRequest::priority()
+*/
+QNetworkRequest::Priority QNetworkRequestFactory::priority() const
+{
+ return d->priority;
+}
+
+/*!
+ \since 6.8
+
+ Sets the value associated with \a attribute to \a value.
+ If the attribute is already set, the previous value is
+ replaced. The attributes are set to any future requests
+ created by this factory.
+
+ \sa attribute(), clearAttribute(), clearAttributes(),
+ QNetworkRequest::Attribute
+*/
+void QNetworkRequestFactory::setAttribute(QNetworkRequest::Attribute attribute,
+ const QVariant &value)
+{
+ if (attribute == QNetworkRequest::HttpStatusCodeAttribute
+ || attribute == QNetworkRequest::HttpReasonPhraseAttribute
+ || attribute == QNetworkRequest::RedirectionTargetAttribute
+ || attribute == QNetworkRequest::ConnectionEncryptedAttribute
+ || attribute == QNetworkRequest::SourceIsFromCacheAttribute
+ || attribute == QNetworkRequest::HttpPipeliningWasUsedAttribute
+ || attribute == QNetworkRequest::Http2WasUsedAttribute
+ || attribute == QNetworkRequest::OriginalContentLengthAttribute)
+ {
+ qCWarning(lcQrequestfactory, "%i is a reply-only attribute, ignoring.", attribute);
+ return;
+ }
+ d.detach();
+ d->attributes.insert(attribute, value);
+}
+
+/*!
+ \since 6.8
+
+ Returns the value associated with \a attribute. If the
+ attribute has not been set, returns a default-constructed \l QVariant.
+
+ \sa attribute(QNetworkRequest::Attribute, const QVariant &),
+ setAttribute(), clearAttributes(), QNetworkRequest::Attribute
+
+*/
+QVariant QNetworkRequestFactory::attribute(QNetworkRequest::Attribute attribute) const
+{
+ return d->attributes.value(attribute);
+}
+
+/*!
+ \since 6.8
+
+ Returns the value associated with \a attribute. If the
+ attribute has not been set, returns \a defaultValue.
+
+ \sa attribute(), setAttribute(), clearAttributes(),
+ QNetworkRequest::Attribute
+*/
+QVariant QNetworkRequestFactory::attribute(QNetworkRequest::Attribute attribute,
+ const QVariant &defaultValue) const
+{
+ return d->attributes.value(attribute, defaultValue);
+}
+
+/*!
+ \since 6.8
+
+ Clears \a attribute set to this factory.
+
+ \sa attribute(), setAttribute()
+*/
+void QNetworkRequestFactory::clearAttribute(QNetworkRequest::Attribute attribute)
+{
+ if (!d->attributes.contains(attribute))
+ return;
+ d.detach();
+ d->attributes.remove(attribute);
+}
+
+/*!
+ \since 6.8
+
+ Clears any attributes set to this factory.
+
+ \sa attribute(), setAttribute()
+*/
+void QNetworkRequestFactory::clearAttributes()
+{
+ if (d->attributes.isEmpty())
+ return;
+ d.detach();
+ d->attributes.clear();
+}
+
+QNetworkRequestFactoryPrivate::QNetworkRequestFactoryPrivate()
+ = default;
+
+QNetworkRequestFactoryPrivate::QNetworkRequestFactoryPrivate(const QUrl &baseUrl)
+ : baseUrl(baseUrl)
+{
+}
+
+QNetworkRequestFactoryPrivate::~QNetworkRequestFactoryPrivate()
+ = default;
+
+QNetworkRequest QNetworkRequestFactoryPrivate::newRequest(const QUrl &url) const
+{
+ QNetworkRequest request;
+ request.setUrl(url);
+#if QT_CONFIG(ssl)
+ if (!sslConfig.isNull())
+ request.setSslConfiguration(sslConfig);
+#endif
+ // Set the header entries to the request. Combine values as there
+ // may be multiple values per name. Note: this would not necessarily
+ // produce right result for 'Set-Cookie' header if it has multiple values,
+ // but since it is a purely server-side (response) header, not relevant here.
+ const auto headerNames = headers.toMultiMap().uniqueKeys(); // ### fixme: port QNR to QHH
+ for (const auto &name : headerNames)
+ request.setRawHeader(name, headers.combinedValue(name));
+
+ constexpr char Bearer[] = "Bearer ";
+ if (!bearerToken.isEmpty())
+ request.setRawHeader("Authorization"_ba, Bearer + bearerToken);
+
+ request.setTransferTimeout(transferTimeout);
+ request.setPriority(priority);
+
+ for (const auto &[attribute, value] : attributes.asKeyValueRange())
+ request.setAttribute(attribute, value);
+
+ return request;
+}
+
+QUrl QNetworkRequestFactoryPrivate::requestUrl(const QString *path,
+ const QUrlQuery *query) const
+{
+ const QUrl providedPath = path ? QUrl(*path) : QUrl{};
+ const QUrlQuery providedQuery = query ? *query : QUrlQuery();
+
+ if (!providedPath.scheme().isEmpty() || !providedPath.host().isEmpty()) {
+ qCWarning(lcQrequestfactory, "The provided path %ls may only contain path and query item "
+ "components, and other parts will be ignored. Set the baseUrl instead",
+ qUtf16Printable(providedPath.toDisplayString()));
+ }
+
+ QUrl resultUrl = baseUrl;
+ QUrlQuery resultQuery(providedQuery);
+ QString basePath = baseUrl.path();
+
+ resultUrl.setUserName(userName);
+ resultUrl.setPassword(password);
+
+ // Separate the path and query parameters components on the application-provided path
+ const QString requestPath{providedPath.path()};
+ const QUrlQuery pathQueryItems{providedPath};
+
+ if (!pathQueryItems.isEmpty()) {
+ // Add any query items provided as part of the path
+ const auto items = pathQueryItems.queryItems(QUrl::ComponentFormattingOption::FullyEncoded);
+ for (const auto &[key, value]: items)
+ resultQuery.addQueryItem(key, value);
+ }
+
+ if (!queryParameters.isEmpty()) {
+ // Add any query items set to this factory
+ const QList<std::pair<QString,QString>> items =
+ queryParameters.queryItems(QUrl::ComponentFormattingOption::FullyEncoded);
+ for (const auto &item: items)
+ resultQuery.addQueryItem(item.first, item.second);
+ }
+
+ if (!resultQuery.isEmpty())
+ resultUrl.setQuery(resultQuery);
+
+ if (requestPath.isEmpty())
+ return resultUrl;
+
+ // Ensure that the "base path" (the path that may be present
+ // in the baseUrl), and the request path are joined with one '/'
+ // If both have it, remove one, if neither has it, add one
+ if (basePath.endsWith(u'/') && requestPath.startsWith(u'/'))
+ basePath.chop(1);
+ else if (!requestPath.startsWith(u'/') && !basePath.endsWith(u'/'))
+ basePath.append(u'/');
+
+ resultUrl.setPath(basePath.append(requestPath));
+ return resultUrl;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+/*!
+ \fn QDebug QNetworkRequestFactory::operator<<(QDebug debug,
+ const QNetworkRequestFactory &factory)
+
+ Writes \a factory into \a debug stream.
+
+ \sa {Debugging Techniques}
+*/
+QDebug operator<<(QDebug debug, const QNetworkRequestFactory &factory)
+{
+ const QDebugStateSaver saver(debug);
+ debug.resetFormat().nospace();
+
+ debug << "QNetworkRequestFactory(baseUrl = " << factory.baseUrl()
+ << ", headers = " << factory.commonHeaders()
+ << ", queryParameters = " << factory.queryParameters().queryItems()
+ << ", bearerToken = " << (factory.bearerToken().isEmpty() ? "(empty)" : "(is set)")
+ << ", transferTimeout = " << factory.transferTimeout()
+ << ", userName = " << (factory.userName().isEmpty() ? "(empty)" : "(is set)")
+ << ", password = " << (factory.password().isEmpty() ? "(empty)" : "(is set)")
+#if QT_CONFIG(ssl)
+ << ", SSL configuration"
+ << (factory.sslConfiguration().isNull() ? " is not set (default)" : " is set")
+#else
+ << ", no SSL support"
+#endif
+ << ")";
+ return debug;
+}
+#endif // QT_NO_DEBUG_STREAM
+
+QT_END_NAMESPACE
diff --git a/src/network/access/qnetworkrequestfactory.h b/src/network/access/qnetworkrequestfactory.h
new file mode 100644
index 0000000000..9d955a51e7
--- /dev/null
+++ b/src/network/access/qnetworkrequestfactory.h
@@ -0,0 +1,100 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QNETWORKREQUESTFACTORY_H
+#define QNETWORKREQUESTFACTORY_H
+
+#include <QtNetwork/qnetworkrequest.h>
+#include <QtNetwork/qhttpheaders.h>
+
+#include <QtCore/qcompare.h>
+#include <QtCore/qshareddata.h>
+#include <QtCore/qurlquery.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qvariant.h>
+
+#include <chrono>
+
+QT_BEGIN_NAMESPACE
+
+class QDebug;
+#if QT_CONFIG(ssl)
+class QSslConfiguration;
+#endif
+
+class QNetworkRequestFactoryPrivate;
+QT_DECLARE_QESDP_SPECIALIZATION_DTOR_WITH_EXPORT(QNetworkRequestFactoryPrivate, Q_NETWORK_EXPORT)
+
+class QT_TECH_PREVIEW_API QNetworkRequestFactory
+{
+public:
+ Q_NETWORK_EXPORT QNetworkRequestFactory();
+ Q_NETWORK_EXPORT explicit QNetworkRequestFactory(const QUrl &baseUrl);
+ Q_NETWORK_EXPORT ~QNetworkRequestFactory();
+
+ Q_NETWORK_EXPORT QNetworkRequestFactory(const QNetworkRequestFactory &other);
+ QNetworkRequestFactory(QNetworkRequestFactory &&other) noexcept = default;
+ Q_NETWORK_EXPORT QNetworkRequestFactory &operator=(const QNetworkRequestFactory &other);
+
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QNetworkRequestFactory)
+ void swap(QNetworkRequestFactory &other) noexcept { d.swap(other.d); }
+
+ Q_NETWORK_EXPORT QUrl baseUrl() const;
+ Q_NETWORK_EXPORT void setBaseUrl(const QUrl &url);
+
+#if QT_CONFIG(ssl)
+ Q_NETWORK_EXPORT QSslConfiguration sslConfiguration() const;
+ Q_NETWORK_EXPORT void setSslConfiguration(const QSslConfiguration &configuration);
+#endif
+
+ Q_NETWORK_EXPORT QNetworkRequest createRequest() const;
+ Q_NETWORK_EXPORT QNetworkRequest createRequest(const QUrlQuery &query) const;
+ Q_NETWORK_EXPORT QNetworkRequest createRequest(const QString &path) const;
+ Q_NETWORK_EXPORT QNetworkRequest createRequest(const QString &path, const QUrlQuery &query) const;
+
+ Q_NETWORK_EXPORT void setCommonHeaders(const QHttpHeaders &headers);
+ Q_NETWORK_EXPORT QHttpHeaders commonHeaders() const;
+ Q_NETWORK_EXPORT void clearCommonHeaders();
+
+ Q_NETWORK_EXPORT QByteArray bearerToken() const;
+ Q_NETWORK_EXPORT void setBearerToken(const QByteArray &token);
+ Q_NETWORK_EXPORT void clearBearerToken();
+
+ Q_NETWORK_EXPORT QString userName() const;
+ Q_NETWORK_EXPORT void setUserName(const QString &userName);
+ Q_NETWORK_EXPORT void clearUserName();
+
+ Q_NETWORK_EXPORT QString password() const;
+ Q_NETWORK_EXPORT void setPassword(const QString &password);
+ Q_NETWORK_EXPORT void clearPassword();
+
+ Q_NETWORK_EXPORT void setTransferTimeout(std::chrono::milliseconds timeout);
+ Q_NETWORK_EXPORT std::chrono::milliseconds transferTimeout() const;
+
+ Q_NETWORK_EXPORT QUrlQuery queryParameters() const;
+ Q_NETWORK_EXPORT void setQueryParameters(const QUrlQuery &query);
+ Q_NETWORK_EXPORT void clearQueryParameters();
+
+ Q_NETWORK_EXPORT void setPriority(QNetworkRequest::Priority priority);
+ Q_NETWORK_EXPORT QNetworkRequest::Priority priority() const;
+
+ Q_NETWORK_EXPORT QVariant attribute(QNetworkRequest::Attribute attribute) const;
+ Q_NETWORK_EXPORT QVariant attribute(QNetworkRequest::Attribute attribute,
+ const QVariant &defaultValue) const;
+ Q_NETWORK_EXPORT void setAttribute(QNetworkRequest::Attribute attribute, const QVariant &value);
+ Q_NETWORK_EXPORT void clearAttribute(QNetworkRequest::Attribute attribute);
+ Q_NETWORK_EXPORT void clearAttributes();
+
+private:
+#ifndef QT_NO_DEBUG_STREAM
+ friend Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, const QNetworkRequestFactory &reply);
+#endif
+
+ QExplicitlySharedDataPointer<QNetworkRequestFactoryPrivate> d;
+};
+
+Q_DECLARE_SHARED(QNetworkRequestFactory)
+
+QT_END_NAMESPACE
+
+#endif // QNETWORKREQUESTFACTORY_H
diff --git a/src/network/access/qnetworkrequestfactory_p.h b/src/network/access/qnetworkrequestfactory_p.h
new file mode 100644
index 0000000000..4116669f21
--- /dev/null
+++ b/src/network/access/qnetworkrequestfactory_p.h
@@ -0,0 +1,56 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QNETWORKREQUESTFACTORY_P_H
+#define QNETWORKREQUESTFACTORY_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the Network Access framework. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtNetwork/qhttpheaders.h>
+#include <QtNetwork/qnetworkrequest.h>
+#if QT_CONFIG(ssl)
+#include <QtNetwork/qsslconfiguration.h>
+#endif
+#include <QtCore/qhash.h>
+#include <QtCore/qshareddata.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qurlquery.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_NAMESPACE
+
+class QNetworkRequestFactoryPrivate : public QSharedData
+{
+public:
+ QNetworkRequestFactoryPrivate();
+ explicit QNetworkRequestFactoryPrivate(const QUrl &baseUrl);
+ ~QNetworkRequestFactoryPrivate();
+ QNetworkRequest newRequest(const QUrl &url) const;
+ QUrl requestUrl(const QString *path = nullptr, const QUrlQuery *query = nullptr) const;
+
+#if QT_CONFIG(ssl)
+ QSslConfiguration sslConfig;
+#endif
+ QUrl baseUrl;
+ QHttpHeaders headers;
+ QByteArray bearerToken;
+ QString userName;
+ QString password;
+ QUrlQuery queryParameters;
+ QNetworkRequest::Priority priority = QNetworkRequest::NormalPriority;
+ std::chrono::milliseconds transferTimeout{0};
+ QHash<QNetworkRequest::Attribute, QVariant> attributes;
+};
+
+QT_END_NAMESPACE
+
+#endif // QNETWORKREQUESTFACTORY_P_H
diff --git a/src/network/access/qrestaccessmanager.cpp b/src/network/access/qrestaccessmanager.cpp
new file mode 100644
index 0000000000..7ef682e955
--- /dev/null
+++ b/src/network/access/qrestaccessmanager.cpp
@@ -0,0 +1,828 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qrestaccessmanager.h"
+#include "qrestaccessmanager_p.h"
+#include "qrestreply.h"
+
+#include <QtNetwork/qhttpmultipart.h>
+#include <QtNetwork/qnetworkaccessmanager.h>
+#include <QtNetwork/qnetworkreply.h>
+
+#include <QtCore/qjsondocument.h>
+#include <QtCore/qjsonobject.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qthread.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+Q_LOGGING_CATEGORY(lcQrest, "qt.network.access.rest")
+
+/*!
+
+ \class QRestAccessManager
+ \brief The QRestAccessManager is a convenience wrapper for
+ QNetworkAccessManager.
+ \since 6.7
+
+ \ingroup network
+ \inmodule QtNetwork
+ \reentrant
+
+ \preliminary
+
+ QRestAccessManager is a convenience wrapper on top of
+ QNetworkAccessManager. It amends datatypes and HTTP methods
+ that are useful for typical RESTful client applications.
+
+ The usual Qt networking features are accessible by configuring the
+ wrapped QNetworkAccessManager directly. QRestAccessManager does not
+ take ownership of the wrapped QNetworkAccessManager.
+
+ QRestAccessManager and related QRestReply classes can only be used in the
+ thread they live in. See \l {QObject#Thread Affinity}{QObject thread affinity}
+ for more information.
+
+ \section1 Issuing Network Requests and Handling Replies
+
+ Network requests are initiated with a function call corresponding to
+ the desired HTTP method, such as \c get() and \c post().
+
+ \section2 Using Signals and Slots
+
+ The function returns a QNetworkReply* object, whose signals can be used
+ to follow up on the completion of the request in a traditional
+ Qt-signals-and-slots way.
+
+ Here's an example of how you could send a GET request and handle the
+ response:
+
+ \snippet code/src_network_access_qrestaccessmanager.cpp 0
+
+ \section2 Using Callbacks and Context Objects
+
+ The functions also take a context object of QObject (subclass) type
+ and a callback function as parameters. The callback takes one QRestReply&
+ as a parameter. The callback can be any callable, including a
+ pointer-to-member-function.
+
+ These callbacks are invoked when the reply has finished processing
+ (also in the case the processing finished due to an error).
+
+ The context object can be \c nullptr, although, generally speaking,
+ this is discouraged. Using a valid context object ensures that if the
+ context object is destroyed during request processing, the callback will
+ not be called. Stray callbacks which access a destroyed context is a source
+ of application misbehavior.
+
+ Here's an example of how you could send a GET request and check the
+ response:
+
+ \snippet code/src_network_access_qrestaccessmanager.cpp 1
+
+ Many of the functions take in data for sending to a server. The data is
+ supplied as the second parameter after the request.
+
+ Here's an example of how you could send a POST request and check the
+ response:
+
+ \snippet code/src_network_access_qrestaccessmanager.cpp 2
+
+ The provided QRestReply& is valid only while the callback
+ executes. If you need it for longer, you can either move it
+ to another QRestReply, or construct a new one and initialize
+ it with the QNetworkReply (see QRestReply::networkReply()).
+
+ \section2 Supported data types
+
+ The following table summarizes the methods and the supported data types.
+ \c X means support.
+
+ \table
+ \header
+ \li Data type
+ \li \c get()
+ \li \c post()
+ \li \c put()
+ \li \c head()
+ \li \c patch()
+ \li \c deleteResource()
+ \li \c sendCustomRequest()
+ \row
+ \li No data
+ \li X
+ \li -
+ \li -
+ \li X
+ \li -
+ \li X
+ \li -
+ \row
+ \li QByteArray
+ \li X
+ \li X
+ \li X
+ \li -
+ \li X
+ \li -
+ \li X
+ \row
+ \li QJsonDocument *)
+ \li X
+ \li X
+ \li X
+ \li -
+ \li X
+ \li -
+ \li -
+ \row
+ \li QVariantMap **)
+ \li -
+ \li X
+ \li X
+ \li -
+ \li X
+ \li -
+ \li -
+ \row
+ \li QHttpMultiPart
+ \li -
+ \li X
+ \li X
+ \li -
+ \li -
+ \li -
+ \li X
+ \row
+ \li QIODevice
+ \li X
+ \li X
+ \li X
+ \li -
+ \li X
+ \li -
+ \li X
+ \endtable
+
+ *) QJsonDocument is sent in \l QJsonDocument::Compact format,
+ and the \c Content-Type header is set to \c {application/json} if the
+ \c Content-Type header was not set
+
+ **) QVariantMap is converted to and treated as a QJsonObject
+
+ \sa QRestReply, QNetworkRequestFactory, QNetworkAccessManager
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::get(
+ const QNetworkRequest &request,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ Issues an \c {HTTP GET} based on \a request.
+
+ The optional \a callback and \a context object can be provided for
+ handling the request completion as illustrated below:
+
+ \snippet code/src_network_access_qrestaccessmanager.cpp 3
+
+ Alternatively the signals of the returned QNetworkReply* object can be
+ used. For further information see
+ \l {Issuing Network Requests and Handling Replies}.
+
+ \sa QRestReply
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::get(
+ const QNetworkRequest &request, const QByteArray &data,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ Issues an \c {HTTP GET} based on \a request and provided \a data.
+
+ The optional \a callback and \a context object can be provided for
+ handling the request completion as illustrated below:
+
+ \snippet code/src_network_access_qrestaccessmanager.cpp 4
+
+ Alternatively the signals of the returned QNetworkReply* object can be
+ used. For further information see
+ \l {Issuing Network Requests and Handling Replies}.
+
+ \sa QRestReply
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::get(
+ const QNetworkRequest &request, const QJsonDocument &data,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ \overload
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::get(
+ const QNetworkRequest &request, QIODevice *data,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ \overload
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::post(
+ const QNetworkRequest &request, const QJsonDocument &data,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ Issues an \c {HTTP POST} based on \a request.
+
+ The optional \a callback and \a context object can be provided for
+ handling the request completion as illustrated below:
+
+ \snippet code/src_network_access_qrestaccessmanager.cpp 5
+
+ Alternatively, the signals of the returned QNetworkReply* object can be
+ used. For further information see
+ \l {Issuing Network Requests and Handling Replies}.
+
+ The \c post() method always requires \a data parameter. The following
+ data types are supported:
+ \list
+ \li QByteArray
+ \li QJsonDocument *)
+ \li QVariantMap **)
+ \li QHttpMultiPart*
+ \li QIODevice*
+ \endlist
+
+ *) Sent in \l QJsonDocument::Compact format, and the
+ \c Content-Type header is set to \c {application/json} if the
+ \c Content-Type header was not set
+ **) QVariantMap is converted to and treated as a QJsonObject
+
+ \sa QRestReply
+*/
+
+/*!
+
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::post(
+ const QNetworkRequest &request, const QVariantMap &data,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ \overload
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::post(
+ const QNetworkRequest &request, const QByteArray &data,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ \overload
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::post(
+ const QNetworkRequest &request, QHttpMultiPart *data,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ \overload
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::post(
+ const QNetworkRequest &request, QIODevice *data,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ \overload
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::put(
+ const QNetworkRequest &request, const QJsonDocument &data,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ Issues an \c {HTTP PUT} based on \a request.
+
+ The optional \a callback and \a context object can be provided for
+ handling the request completion as illustrated below:
+
+ \snippet code/src_network_access_qrestaccessmanager.cpp 6
+
+ Alternatively the signals of the returned QNetworkReply* object can be
+ used. For further information see
+ \l {Issuing Network Requests and Handling Replies}.
+
+ The \c put() method always requires \a data parameter. The following
+ data types are supported:
+ \list
+ \li QByteArray
+ \li QJsonDocument *)
+ \li QVariantMap **)
+ \li QHttpMultiPart*
+ \li QIODevice*
+ \endlist
+
+ *) Sent in \l QJsonDocument::Compact format, and the
+ \c Content-Type header is set to \c {application/json} if the
+ \c Content-Type header was not set
+ **) QVariantMap is converted to and treated as a QJsonObject
+
+ \sa QRestReply
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::put(
+ const QNetworkRequest &request, const QVariantMap &data,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ \overload
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::put(
+ const QNetworkRequest &request, const QByteArray &data,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ \overload
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::put(
+ const QNetworkRequest &request, QHttpMultiPart *data,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ \overload
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::put(
+ const QNetworkRequest &request, QIODevice *data,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ \overload
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::patch(
+ const QNetworkRequest &request, const QJsonDocument &data,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ Issues an \c {HTTP PATCH} based on \a request.
+
+ The optional \a callback and \a context object can be provided for
+ handling the request completion as illustrated below:
+
+ \snippet code/src_network_access_qrestaccessmanager.cpp 10
+
+ Alternatively the signals of the returned QNetworkReply* object can be
+ used. For further information see
+ \l {Issuing Network Requests and Handling Replies}.
+
+ The \c patch() method always requires \a data parameter. The following
+ data types are supported:
+ \list
+ \li QByteArray
+ \li QJsonDocument *)
+ \li QVariantMap **)
+ \li QIODevice*
+ \endlist
+
+ *) Sent in \l QJsonDocument::Compact format, and the
+ \c Content-Type header is set to \c {application/json} if the
+ \c Content-Type header was not set
+ **) QVariantMap is converted to and treated as a QJsonObject
+
+ \sa QRestReply
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::patch(
+ const QNetworkRequest &request, const QVariantMap &data,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ \overload
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::patch(
+ const QNetworkRequest &request, const QByteArray &data,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ \overload
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::patch(
+ const QNetworkRequest &request, QIODevice *data,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ \overload
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::head(
+ const QNetworkRequest &request,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ Issues an \c {HTTP HEAD} based on \a request.
+
+ The optional \a callback and \a context object can be provided for
+ handling the request completion as illustrated below:
+
+ \snippet code/src_network_access_qrestaccessmanager.cpp 7
+
+ Alternatively the signals of the returned QNetworkReply* object can be
+ used. For further information see
+ \l {Issuing Network Requests and Handling Replies}.
+
+ \c head() request does not support providing data.
+
+ \sa QRestReply
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::deleteResource(
+ const QNetworkRequest &request,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ Issues an \c {HTTP DELETE} based on \a request.
+
+ The optional \a callback and \a context object can be provided for
+ handling the request completion as illustrated below:
+
+ \snippet code/src_network_access_qrestaccessmanager.cpp 8
+
+ Alternatively the signals of the returned QNetworkReply* object can be
+ used. For further information see
+ \l {Issuing Network Requests and Handling Replies}.
+
+ \c deleteResource() request does not support providing data.
+
+ \sa QRestReply
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::sendCustomRequest(
+ const QNetworkRequest& request, const QByteArray &method, const QByteArray &data,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ Issues \a request based HTTP request with custom \a method and the
+ provided \a data.
+
+ The optional \a callback and \a context object can be provided for
+ handling the request completion as illustrated below:
+
+ \snippet code/src_network_access_qrestaccessmanager.cpp 9
+
+ Alternatively the signals of the returned QNetworkReply* object can be
+ used. For further information see
+ \l {Issuing Network Requests and Handling Replies}.
+
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::sendCustomRequest(
+ const QNetworkRequest& request, const QByteArray &method, QIODevice *data,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ \overload
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::sendCustomRequest(
+ const QNetworkRequest& request, const QByteArray &method, QHttpMultiPart *data,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ \overload
+*/
+
+/*!
+ Constructs a QRestAccessManager object and sets \a parent as the parent
+ object, and \a manager as the underlying QNetworkAccessManager which
+ is used for communication.
+
+ \sa networkAccessManager()
+*/
+
+QRestAccessManager::QRestAccessManager(QNetworkAccessManager *manager, QObject *parent)
+ : QObject(*new QRestAccessManagerPrivate, parent)
+{
+ Q_D(QRestAccessManager);
+ d->qnam = manager;
+ if (!d->qnam)
+ qCWarning(lcQrest, "QRestAccessManager: QNetworkAccesManager is nullptr");
+}
+
+/*!
+ Destroys the QRestAccessManager object.
+*/
+QRestAccessManager::~QRestAccessManager()
+ = default;
+
+/*!
+ Returns the underlying QNetworkAccessManager instance.
+
+ \sa QNetworkAccessManager
+*/
+QNetworkAccessManager *QRestAccessManager::networkAccessManager() const
+{
+ Q_D(const QRestAccessManager);
+ return d->qnam;
+}
+
+QRestAccessManagerPrivate::QRestAccessManagerPrivate()
+ = default;
+
+QRestAccessManagerPrivate::~QRestAccessManagerPrivate()
+{
+ if (!activeRequests.isEmpty()) {
+ qCWarning(lcQrest, "Access manager destroyed while %lld requests were still in progress",
+ qlonglong(activeRequests.size()));
+ }
+}
+
+QNetworkReply *QRestAccessManager::postWithDataImpl(const QNetworkRequest &request,
+ const QJsonDocument &data, const QObject *context,
+ QtPrivate::QSlotObjectBase *slot)
+{
+ Q_D(QRestAccessManager);
+ return d->executeRequest([](auto qnam, auto req, auto data) { return qnam->post(req, data); },
+ data, request, context, slot);
+}
+
+QNetworkReply *QRestAccessManager::postWithDataImpl(const QNetworkRequest &request,
+ const QVariantMap &data, const QObject *context,
+ QtPrivate::QSlotObjectBase *slot)
+{
+ return postWithDataImpl(request, QJsonDocument::fromVariant(data), context, slot);
+}
+
+QNetworkReply *QRestAccessManager::postWithDataImpl(const QNetworkRequest &request,
+ const QByteArray &data, const QObject *context,
+ QtPrivate::QSlotObjectBase *slot)
+{
+ Q_D(QRestAccessManager);
+ return d->executeRequest([&](auto qnam) { return qnam->post(request, data); }, context, slot);
+}
+
+QNetworkReply *QRestAccessManager::postWithDataImpl(const QNetworkRequest &request,
+ QHttpMultiPart *data, const QObject *context,
+ QtPrivate::QSlotObjectBase *slot)
+{
+ Q_D(QRestAccessManager);
+ return d->executeRequest([&](auto qnam) { return qnam->post(request, data); }, context, slot);
+}
+
+QNetworkReply *QRestAccessManager::postWithDataImpl(const QNetworkRequest &request,
+ QIODevice *data, const QObject *context,
+ QtPrivate::QSlotObjectBase *slot)
+{
+ Q_D(QRestAccessManager);
+ return d->executeRequest([&](auto qnam) { return qnam->post(request, data); }, context, slot);
+}
+
+QNetworkReply *QRestAccessManager::getNoDataImpl(const QNetworkRequest &request,
+ const QObject *context, QtPrivate::QSlotObjectBase *slot)
+{
+ Q_D(QRestAccessManager);
+ return d->executeRequest([&](auto qnam) { return qnam->get(request); }, context, slot);
+}
+
+QNetworkReply *QRestAccessManager::getWithDataImpl(const QNetworkRequest &request,
+ const QByteArray &data, const QObject *context,
+ QtPrivate::QSlotObjectBase *slot)
+{
+ Q_D(QRestAccessManager);
+ return d->executeRequest([&](auto qnam) { return qnam->get(request, data); }, context, slot);
+}
+
+QNetworkReply *QRestAccessManager::getWithDataImpl(const QNetworkRequest &request,
+ const QJsonDocument &data, const QObject *context,
+ QtPrivate::QSlotObjectBase *slot)
+{
+ Q_D(QRestAccessManager);
+ return d->executeRequest([](auto qnam, auto req, auto data) { return qnam->get(req, data); },
+ data, request, context, slot);
+}
+
+QNetworkReply *QRestAccessManager::getWithDataImpl(const QNetworkRequest &request,
+ QIODevice *data, const QObject *context,
+ QtPrivate::QSlotObjectBase *slot)
+{
+ Q_D(QRestAccessManager);
+ return d->executeRequest([&](auto qnam) { return qnam->get(request, data); }, context, slot);
+}
+
+QNetworkReply *QRestAccessManager::deleteResourceNoDataImpl(const QNetworkRequest &request,
+ const QObject *context, QtPrivate::QSlotObjectBase *slot)
+{
+ Q_D(QRestAccessManager);
+ return d->executeRequest([&](auto qnam) { return qnam->deleteResource(request); }, context, slot);
+}
+
+QNetworkReply *QRestAccessManager::headNoDataImpl(const QNetworkRequest &request,
+ const QObject *context, QtPrivate::QSlotObjectBase *slot)
+{
+ Q_D(QRestAccessManager);
+ return d->executeRequest([&](auto qnam) { return qnam->head(request); }, context, slot);
+}
+
+QNetworkReply *QRestAccessManager::putWithDataImpl(const QNetworkRequest &request,
+ const QJsonDocument &data, const QObject *context,
+ QtPrivate::QSlotObjectBase *slot)
+{
+ Q_D(QRestAccessManager);
+ return d->executeRequest([](auto qnam, auto req, auto data) { return qnam->put(req, data); },
+ data, request, context, slot);
+}
+
+QNetworkReply *QRestAccessManager::putWithDataImpl(const QNetworkRequest &request,
+ const QVariantMap &data, const QObject *context,
+ QtPrivate::QSlotObjectBase *slot)
+{
+ return putWithDataImpl(request, QJsonDocument::fromVariant(data), context, slot);
+}
+
+QNetworkReply *QRestAccessManager::putWithDataImpl(const QNetworkRequest &request,
+ const QByteArray &data, const QObject *context,
+ QtPrivate::QSlotObjectBase *slot)
+{
+ Q_D(QRestAccessManager);
+ return d->executeRequest([&](auto qnam) { return qnam->put(request, data); }, context, slot);
+}
+
+QNetworkReply *QRestAccessManager::putWithDataImpl(const QNetworkRequest &request,
+ QHttpMultiPart *data, const QObject *context,
+ QtPrivate::QSlotObjectBase *slot)
+{
+ Q_D(QRestAccessManager);
+ return d->executeRequest([&](auto qnam) { return qnam->put(request, data); }, context, slot);
+}
+
+QNetworkReply *QRestAccessManager::putWithDataImpl(const QNetworkRequest &request, QIODevice *data,
+ const QObject *context, QtPrivate::QSlotObjectBase *slot)
+{
+ Q_D(QRestAccessManager);
+ return d->executeRequest([&](auto qnam) { return qnam->put(request, data); }, context, slot);
+}
+
+static const auto PATCH = "PATCH"_ba;
+
+QNetworkReply *QRestAccessManager::patchWithDataImpl(const QNetworkRequest &request,
+ const QJsonDocument &data, const QObject *context,
+ QtPrivate::QSlotObjectBase *slot)
+{
+ Q_D(QRestAccessManager);
+ return d->executeRequest(
+ [](auto qnam, auto req, auto data) { return qnam->sendCustomRequest(req, PATCH, data); },
+ data, request, context, slot);
+}
+
+QNetworkReply *QRestAccessManager::patchWithDataImpl(const QNetworkRequest &request,
+ const QVariantMap &data, const QObject *context,
+ QtPrivate::QSlotObjectBase *slot)
+{
+ return patchWithDataImpl(request, QJsonDocument::fromVariant(data), context, slot);
+}
+
+QNetworkReply *QRestAccessManager::patchWithDataImpl(const QNetworkRequest &request,
+ const QByteArray &data, const QObject *context,
+ QtPrivate::QSlotObjectBase *slot)
+{
+ Q_D(QRestAccessManager);
+ return d->executeRequest([&](auto qnam) { return qnam->sendCustomRequest(request, PATCH, data); },
+ context, slot);
+}
+
+QNetworkReply *QRestAccessManager::patchWithDataImpl(const QNetworkRequest &request, QIODevice *data,
+ const QObject *context, QtPrivate::QSlotObjectBase *slot)
+{
+ Q_D(QRestAccessManager);
+ return d->executeRequest([&](auto qnam) { return qnam->sendCustomRequest(request, PATCH, data); },
+ context, slot);
+}
+
+QNetworkReply *QRestAccessManager::customWithDataImpl(const QNetworkRequest &request,
+ const QByteArray& method, const QByteArray &data,
+ const QObject *context,
+ QtPrivate::QSlotObjectBase *slot)
+{
+ Q_D(QRestAccessManager);
+ return d->executeRequest([&](auto qnam) { return qnam->sendCustomRequest(request, method, data); },
+ context, slot);
+}
+
+QNetworkReply *QRestAccessManager::customWithDataImpl(const QNetworkRequest &request,
+ const QByteArray& method, QIODevice *data,
+ const QObject *context,
+ QtPrivate::QSlotObjectBase *slot)
+{
+ Q_D(QRestAccessManager);
+ return d->executeRequest([&](auto qnam) { return qnam->sendCustomRequest(request, method, data); },
+ context, slot);
+}
+
+QNetworkReply *QRestAccessManager::customWithDataImpl(const QNetworkRequest &request,
+ const QByteArray& method, QHttpMultiPart *data,
+ const QObject *context,
+ QtPrivate::QSlotObjectBase *slot)
+{
+ Q_D(QRestAccessManager);
+ return d->executeRequest([&](auto qnam) { return qnam->sendCustomRequest(request, method, data); },
+ context, slot);
+}
+
+QNetworkReply *QRestAccessManagerPrivate::createActiveRequest(QNetworkReply *reply,
+ const QObject *contextObject,
+ QtPrivate::QSlotObjectBase *slot)
+{
+ Q_Q(QRestAccessManager);
+ Q_ASSERT(reply);
+ QtPrivate::SlotObjSharedPtr slotPtr(QtPrivate::SlotObjUniquePtr{slot}); // adopts
+ activeRequests.insert(reply, CallerInfo{contextObject, slotPtr});
+ // The signal connections below are made to 'q' to avoid stray signal
+ // handling upon its destruction while requests were still in progress
+
+ QObject::connect(reply, &QNetworkReply::finished, q, [reply, this]() {
+ handleReplyFinished(reply);
+ });
+ // Safe guard in case reply is destroyed before it's finished
+ QObject::connect(reply, &QObject::destroyed, q, [reply, this]() {
+ activeRequests.remove(reply);
+ });
+ // If context object is destroyed, clean up any possible replies it had associated with it
+ if (contextObject) {
+ QObject::connect(contextObject, &QObject::destroyed, q, [reply, this]() {
+ activeRequests.remove(reply);
+ });
+ }
+ return reply;
+}
+
+void QRestAccessManagerPrivate::verifyThreadAffinity(const QObject *contextObject)
+{
+ Q_Q(QRestAccessManager);
+ if (QThread::currentThread() != q->thread()) {
+ qCWarning(lcQrest, "QRestAccessManager can only be called in the thread it belongs to");
+ Q_ASSERT(false);
+ }
+ if (contextObject && (contextObject->thread() != q->thread())) {
+ qCWarning(lcQrest, "QRestAccessManager: the context object must reside in the same thread");
+ Q_ASSERT(false);
+ }
+}
+
+QNetworkReply* QRestAccessManagerPrivate::warnNoAccessManager()
+{
+ qCWarning(lcQrest, "QRestAccessManager: QNetworkAccessManager not set");
+ return nullptr;
+}
+
+void QRestAccessManagerPrivate::handleReplyFinished(QNetworkReply *reply)
+{
+ auto request = activeRequests.find(reply);
+ if (request == activeRequests.end()) {
+ qCDebug(lcQrest, "QRestAccessManager: Unexpected reply received, ignoring");
+ return;
+ }
+
+ CallerInfo caller = request.value();
+ activeRequests.erase(request);
+
+ if (caller.slot) {
+ // Callback was provided
+ QRestReply restReply(reply);
+ void *argv[] = { nullptr, &restReply };
+ // If we have context object, use it
+ QObject *context = caller.contextObject
+ ? const_cast<QObject*>(caller.contextObject.get()) : nullptr;
+ caller.slot->call(context, argv);
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qrestaccessmanager.cpp"
diff --git a/src/network/access/qrestaccessmanager.h b/src/network/access/qrestaccessmanager.h
new file mode 100644
index 0000000000..3245b41785
--- /dev/null
+++ b/src/network/access/qrestaccessmanager.h
@@ -0,0 +1,127 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QRESTACCESSMANAGER_H
+#define QRESTACCESSMANAGER_H
+
+#if 0
+#pragma qt_class(QRestAccessManager)
+#endif
+
+#include <QtNetwork/qnetworkaccessmanager.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDebug;
+class QRestReply;
+
+#define QREST_METHOD_WITH_DATA(METHOD, DATA) \
+public: \
+template <typename Functor, if_compatible_callback<Functor> = true> \
+QNetworkReply *METHOD(const QNetworkRequest &request, DATA data, \
+ const ContextTypeForFunctor<Functor> *context, \
+ Functor &&callback) \
+{ \
+ return METHOD##WithDataImpl(request, data, context, \
+ QtPrivate::makeCallableObject<CallbackPrototype>(std::forward<Functor>(callback))); \
+} \
+QNetworkReply *METHOD(const QNetworkRequest &request, DATA data) \
+{ \
+ return METHOD##WithDataImpl(request, data, nullptr, nullptr); \
+} \
+private: \
+QNetworkReply *METHOD##WithDataImpl(const QNetworkRequest &request, DATA data, \
+ const QObject *context, QtPrivate::QSlotObjectBase *slot); \
+/* end */
+
+#define QREST_METHOD_NO_DATA(METHOD) \
+public: \
+template <typename Functor, if_compatible_callback<Functor> = true> \
+QNetworkReply *METHOD(const QNetworkRequest &request, \
+ const ContextTypeForFunctor<Functor> *context, \
+ Functor &&callback) \
+{ \
+ return METHOD##NoDataImpl(request, context, \
+ QtPrivate::makeCallableObject<CallbackPrototype>(std::forward<Functor>(callback))); \
+} \
+QNetworkReply *METHOD(const QNetworkRequest &request) \
+{ \
+ return METHOD##NoDataImpl(request, nullptr, nullptr); \
+} \
+private: \
+QNetworkReply *METHOD##NoDataImpl(const QNetworkRequest &request, \
+ const QObject *context, QtPrivate::QSlotObjectBase *slot); \
+/* end */
+
+#define QREST_METHOD_CUSTOM_WITH_DATA(DATA) \
+public: \
+template <typename Functor, if_compatible_callback<Functor> = true> \
+QNetworkReply *sendCustomRequest(const QNetworkRequest& request, const QByteArray &method, DATA data, \
+ const ContextTypeForFunctor<Functor> *context, \
+ Functor &&callback) \
+{ \
+ return customWithDataImpl(request, method, data, context, \
+ QtPrivate::makeCallableObject<CallbackPrototype>(std::forward<Functor>(callback))); \
+} \
+QNetworkReply *sendCustomRequest(const QNetworkRequest& request, const QByteArray &method, DATA data) \
+{ \
+ return customWithDataImpl(request, method, data, nullptr, nullptr); \
+} \
+private: \
+QNetworkReply *customWithDataImpl(const QNetworkRequest& request, const QByteArray &method, \
+ DATA data, const QObject* context, \
+ QtPrivate::QSlotObjectBase *slot); \
+/* end */
+
+class QRestAccessManagerPrivate;
+class QT_TECH_PREVIEW_API Q_NETWORK_EXPORT QRestAccessManager : public QObject
+{
+ Q_OBJECT
+ using CallbackPrototype = void(*)(QRestReply&);
+ template <typename Functor>
+ using ContextTypeForFunctor = typename QtPrivate::ContextTypeForFunctor<Functor>::ContextType;
+ template <typename Functor>
+ using if_compatible_callback = std::enable_if_t<
+ QtPrivate::AreFunctionsCompatible<CallbackPrototype, Functor>::value, bool>;
+public:
+ explicit QRestAccessManager(QNetworkAccessManager *manager, QObject *parent = nullptr);
+ ~QRestAccessManager() override;
+
+ QNetworkAccessManager *networkAccessManager() const;
+
+ QREST_METHOD_NO_DATA(deleteResource)
+ QREST_METHOD_NO_DATA(head)
+ QREST_METHOD_NO_DATA(get)
+ QREST_METHOD_WITH_DATA(get, const QByteArray &)
+ QREST_METHOD_WITH_DATA(get, const QJsonDocument &)
+ QREST_METHOD_WITH_DATA(get, QIODevice *)
+ QREST_METHOD_WITH_DATA(post, const QJsonDocument &)
+ QREST_METHOD_WITH_DATA(post, const QVariantMap &)
+ QREST_METHOD_WITH_DATA(post, const QByteArray &)
+ QREST_METHOD_WITH_DATA(post, QHttpMultiPart *)
+ QREST_METHOD_WITH_DATA(post, QIODevice *)
+ QREST_METHOD_WITH_DATA(put, const QJsonDocument &)
+ QREST_METHOD_WITH_DATA(put, const QVariantMap &)
+ QREST_METHOD_WITH_DATA(put, const QByteArray &)
+ QREST_METHOD_WITH_DATA(put, QHttpMultiPart *)
+ QREST_METHOD_WITH_DATA(put, QIODevice *)
+ QREST_METHOD_WITH_DATA(patch, const QJsonDocument &)
+ QREST_METHOD_WITH_DATA(patch, const QVariantMap &)
+ QREST_METHOD_WITH_DATA(patch, const QByteArray &)
+ QREST_METHOD_WITH_DATA(patch, QIODevice *)
+ QREST_METHOD_CUSTOM_WITH_DATA(const QByteArray &)
+ QREST_METHOD_CUSTOM_WITH_DATA(QIODevice *)
+ QREST_METHOD_CUSTOM_WITH_DATA(QHttpMultiPart *)
+
+private:
+ Q_DECLARE_PRIVATE(QRestAccessManager)
+ Q_DISABLE_COPY(QRestAccessManager)
+};
+
+#undef QREST_METHOD_NO_DATA
+#undef QREST_METHOD_WITH_DATA
+#undef QREST_METHOD_CUSTOM_WITH_DATA
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/network/access/qrestaccessmanager_p.h b/src/network/access/qrestaccessmanager_p.h
new file mode 100644
index 0000000000..51af299f5c
--- /dev/null
+++ b/src/network/access/qrestaccessmanager_p.h
@@ -0,0 +1,89 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QRESTACCESSMANAGER_P_H
+#define QRESTACCESSMANAGER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the Network Access API. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qrestaccessmanager.h"
+#include "private/qobject_p.h"
+
+#include <QtNetwork/qnetworkaccessmanager.h>
+
+#include <QtCore/qjsonarray.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qjsondocument.h>
+#include <QtCore/qjsonobject.h>
+#include <QtCore/qxpfunctional.h>
+
+QT_BEGIN_NAMESPACE
+
+class QRestReply;
+class QRestAccessManagerPrivate : public QObjectPrivate
+{
+public:
+ QRestAccessManagerPrivate();
+ ~QRestAccessManagerPrivate() override;
+
+ QNetworkReply* createActiveRequest(QNetworkReply *reply, const QObject *contextObject,
+ QtPrivate::QSlotObjectBase *slot);
+ void handleReplyFinished(QNetworkReply *reply);
+
+ using ReqOpRef = qxp::function_ref<QNetworkReply*(QNetworkAccessManager*) const>;
+ QNetworkReply *executeRequest(ReqOpRef requestOperation,
+ const QObject *context, QtPrivate::QSlotObjectBase *slot)
+ {
+ if (!qnam)
+ return warnNoAccessManager();
+ verifyThreadAffinity(context);
+ QNetworkReply *reply = requestOperation(qnam);
+ return createActiveRequest(reply, context, slot);
+ }
+
+ using ReqOpRefJson = qxp::function_ref<QNetworkReply*(QNetworkAccessManager*,
+ const QNetworkRequest &,
+ const QByteArray &) const>;
+ QNetworkReply *executeRequest(ReqOpRefJson requestOperation, const QJsonDocument &jsonDoc,
+ const QNetworkRequest &request,
+ const QObject *context, QtPrivate::QSlotObjectBase *slot)
+ {
+ if (!qnam)
+ return warnNoAccessManager();
+ verifyThreadAffinity(context);
+ QNetworkRequest req(request);
+ if (!request.header(QNetworkRequest::ContentTypeHeader).isValid()) {
+ req.setHeader(QNetworkRequest::ContentTypeHeader,
+ QLatin1StringView{"application/json"});
+ }
+ QNetworkReply *reply = requestOperation(qnam, req, jsonDoc.toJson(QJsonDocument::Compact));
+ return createActiveRequest(reply, context, slot);
+ }
+
+ void verifyThreadAffinity(const QObject *contextObject);
+ Q_DECL_COLD_FUNCTION
+ QNetworkReply* warnNoAccessManager();
+
+ struct CallerInfo {
+ QPointer<const QObject> contextObject = nullptr;
+ QtPrivate::SlotObjSharedPtr slot;
+ };
+ QHash<QNetworkReply*, CallerInfo> activeRequests;
+
+ QNetworkAccessManager *qnam = nullptr;
+ bool deletesRepliesOnFinished = true;
+ Q_DECLARE_PUBLIC(QRestAccessManager)
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/network/access/qrestreply.cpp b/src/network/access/qrestreply.cpp
new file mode 100644
index 0000000000..155e5877fd
--- /dev/null
+++ b/src/network/access/qrestreply.cpp
@@ -0,0 +1,560 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qrestreply.h"
+#include "qrestreply_p.h"
+
+#include <QtNetwork/private/qnetworkreply_p.h>
+
+#include <QtCore/qbytearrayview.h>
+#include <QtCore/qjsondocument.h>
+#include <QtCore/qlatin1stringmatcher.h>
+#include <QtCore/qlatin1stringview.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qstringconverter.h>
+
+#include <QtCore/qxpfunctional.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+Q_DECLARE_LOGGING_CATEGORY(lcQrest)
+
+/*!
+ \class QRestReply
+ \since 6.7
+ \brief QRestReply is a convenience wrapper for QNetworkReply.
+
+ \reentrant
+ \ingroup network
+ \inmodule QtNetwork
+
+ \preliminary
+
+ QRestReply wraps a QNetworkReply and provides convenience methods for data
+ and status handling. The methods provide convenience for typical RESTful
+ client applications.
+
+ QRestReply doesn't take ownership of the wrapped QNetworkReply, and the
+ lifetime and ownership of the reply is as defined by QNetworkAccessManager
+ documentation.
+
+ QRestReply object is not copyable, but is movable.
+
+ \sa QRestAccessManager, QNetworkReply, QNetworkAccessManager,
+ QNetworkAccessManager::setAutoDeleteReplies()
+*/
+
+/*!
+ Creates a QRestReply and initializes the wrapped QNetworkReply to \a reply.
+*/
+QRestReply::QRestReply(QNetworkReply *reply)
+ : wrapped(reply)
+{
+ if (!wrapped)
+ qCWarning(lcQrest, "QRestReply: QNetworkReply is nullptr");
+}
+
+/*!
+ Destroys this QRestReply object.
+*/
+QRestReply::~QRestReply()
+{
+ delete d;
+}
+
+/*!
+ \fn QRestReply::QRestReply(QRestReply &&other) noexcept
+
+ Move-constructs the reply from \a other.
+
+ \note The moved-from object \a other is placed in a
+ partially-formed state, in which the only valid operations are
+ destruction and assignment of a new value.
+*/
+
+/*!
+ \fn QRestReply &QRestReply::operator=(QRestReply &&other) noexcept
+
+ Move-assigns \a other and returns a reference to this reply.
+
+ \note The moved-from object \a other is placed in a
+ partially-formed state, in which the only valid operations are
+ destruction and assignment of a new value.
+*/
+
+/*!
+ Returns a pointer to the underlying QNetworkReply wrapped by this object.
+*/
+QNetworkReply *QRestReply::networkReply() const
+{
+ return wrapped;
+}
+
+/*!
+ Returns the received data as a QJsonDocument.
+
+ The returned value is wrapped in \c std::optional. If the conversion
+ from the received data fails (empty data or JSON parsing error),
+ \c std::nullopt is returned, and \a error is filled with details.
+
+ Calling this function consumes the received data, and any further calls
+ to get response data will return empty.
+
+ This function returns \c {std::nullopt} and will not consume
+ any data if the reply is not finished. If \a error is passed, it will be
+ set to QJsonParseError::NoError to distinguish this case from an actual
+ error.
+
+ \sa readBody(), readText()
+*/
+std::optional<QJsonDocument> QRestReply::readJson(QJsonParseError *error)
+{
+ if (!wrapped) {
+ if (error)
+ *error = {0, QJsonParseError::ParseError::NoError};
+ return std::nullopt;
+ }
+
+ if (!wrapped->isFinished()) {
+ qCWarning(lcQrest, "readJson() called on an unfinished reply, ignoring");
+ if (error)
+ *error = {0, QJsonParseError::ParseError::NoError};
+ return std::nullopt;
+ }
+ QJsonParseError parseError;
+ const QByteArray data = wrapped->readAll();
+ const QJsonDocument doc = QJsonDocument::fromJson(data, &parseError);
+ if (error)
+ *error = parseError;
+ if (parseError.error)
+ return std::nullopt;
+ return doc;
+}
+
+/*!
+ Returns the received data as a QByteArray.
+
+ Calling this function consumes the data received so far, and any further
+ calls to get response data will return empty until further data has been
+ received.
+
+ \sa readJson(), readText(), QNetworkReply::bytesAvailable(),
+ QNetworkReply::readyRead()
+*/
+QByteArray QRestReply::readBody()
+{
+ return wrapped ? wrapped->readAll() : QByteArray{};
+}
+
+/*!
+ Returns the received data as a QString.
+
+ The received data is decoded into a QString (UTF-16). If available, the decoding
+ uses the \e Content-Type header's \e charset parameter to determine the
+ source encoding. If the encoding information is not available or not supported
+ by \l QStringConverter, UTF-8 is used by default.
+
+ Calling this function consumes the data received so far. Returns
+ a default constructed value if no new data is available, or if the
+ decoding is not supported by \l QStringConverter, or if the decoding
+ has errors (for example invalid characters).
+
+ \sa readJson(), readBody(), QNetworkReply::readyRead()
+*/
+QString QRestReply::readText()
+{
+ QString result;
+ if (!wrapped)
+ return result;
+
+ QByteArray data = wrapped->readAll();
+ if (data.isEmpty())
+ return result;
+
+ // Text decoding needs to persist decoding state across calls to this function,
+ // so allocate decoder if not yet allocated.
+ if (!d)
+ d = new QRestReplyPrivate;
+
+ if (!d->decoder) {
+ const QByteArray charset = QRestReplyPrivate::contentCharset(wrapped);
+ d->decoder.emplace(charset.constData());
+ if (!d->decoder->isValid()) { // the decoder may not support the mimetype's charset
+ qCWarning(lcQrest, "readText(): Charset \"%s\" is not supported", charset.constData());
+ return result;
+ }
+ }
+ // Check if the decoder already had an error, or has errors after decoding current data chunk
+ if (d->decoder->hasError() || (result = (*d->decoder)(data), d->decoder->hasError())) {
+ qCWarning(lcQrest, "readText(): Decoding error occurred");
+ return {};
+ }
+ return result;
+}
+
+/*!
+ Returns the HTTP status received in the server response.
+ The value is \e 0 if not available (the status line has not been received,
+ yet).
+
+ \note The HTTP status is reported as indicated by the received HTTP
+ response. An error() may occur after receiving the status, for instance
+ due to network disconnection while receiving a long response.
+ These potential subsequent errors are not represented by the reported
+ HTTP status.
+
+ \sa isSuccess(), hasError(), error()
+*/
+int QRestReply::httpStatus() const
+{
+ return wrapped ? wrapped->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() : 0;
+}
+
+/*!
+ \fn bool QRestReply::isSuccess() const
+
+ Returns whether the HTTP status is between 200..299 and no
+ further errors have occurred while receiving the response (for example,
+ abrupt disconnection while receiving the body data). This function
+ is a convenient way to check whether the response is considered successful.
+
+ \sa httpStatus(), hasError(), error()
+*/
+
+/*!
+ Returns whether the HTTP status is between 200..299.
+
+ \sa isSuccess(), httpStatus(), hasError(), error()
+*/
+bool QRestReply::isHttpStatusSuccess() const
+{
+ const int status = httpStatus();
+ return status >= 200 && status < 300;
+}
+
+/*!
+ Returns whether an error has occurred. This includes errors such as
+ network and protocol errors, but excludes cases where the server
+ successfully responded with an HTTP error status (for example
+ \c {500 Internal Server Error}). Use \l httpStatus() or
+ \l isHttpStatusSuccess() to get the HTTP status information.
+
+ \sa httpStatus(), isSuccess(), error(), errorString()
+*/
+bool QRestReply::hasError() const
+{
+ if (!wrapped)
+ return false;
+
+ const int status = httpStatus();
+ if (status > 0) {
+ // The HTTP status is set upon receiving the response headers, but the
+ // connection might still fail later while receiving the body data.
+ return wrapped->error() == QNetworkReply::RemoteHostClosedError;
+ }
+ return wrapped->error() != QNetworkReply::NoError;
+}
+
+/*!
+ Returns the last error, if any. The errors include
+ errors such as network and protocol errors, but exclude
+ cases when the server successfully responded with an HTTP status.
+
+ \sa httpStatus(), isSuccess(), hasError(), errorString()
+*/
+QNetworkReply::NetworkError QRestReply::error() const
+{
+ if (!hasError())
+ return QNetworkReply::NetworkError::NoError;
+ return wrapped->error();
+}
+
+/*!
+ Returns a human-readable description of the last network error.
+
+ \sa httpStatus(), isSuccess(), hasError(), error()
+*/
+QString QRestReply::errorString() const
+{
+ if (hasError())
+ return wrapped->errorString();
+ return {};
+}
+
+QRestReplyPrivate::QRestReplyPrivate()
+ = default;
+
+QRestReplyPrivate::~QRestReplyPrivate()
+ = default;
+
+#ifndef QT_NO_DEBUG_STREAM
+static QLatin1StringView operationName(QNetworkAccessManager::Operation operation)
+{
+ switch (operation) {
+ case QNetworkAccessManager::Operation::GetOperation:
+ return "GET"_L1;
+ case QNetworkAccessManager::Operation::HeadOperation:
+ return "HEAD"_L1;
+ case QNetworkAccessManager::Operation::PostOperation:
+ return "POST"_L1;
+ case QNetworkAccessManager::Operation::PutOperation:
+ return "PUT"_L1;
+ case QNetworkAccessManager::Operation::DeleteOperation:
+ return "DELETE"_L1;
+ case QNetworkAccessManager::Operation::CustomOperation:
+ return "CUSTOM"_L1;
+ case QNetworkAccessManager::Operation::UnknownOperation:
+ return "UNKNOWN"_L1;
+ }
+ Q_UNREACHABLE_RETURN({});
+}
+
+/*!
+ \fn QDebug QRestReply::operator<<(QDebug debug, const QRestReply &reply)
+
+ Writes the \a reply into the \a debug object for debugging purposes.
+
+ \sa {Debugging Techniques}
+*/
+QDebug operator<<(QDebug debug, const QRestReply &reply)
+{
+ const QDebugStateSaver saver(debug);
+ debug.resetFormat().nospace();
+ if (!reply.networkReply()) {
+ debug << "QRestReply(no network reply)";
+ return debug;
+ }
+ debug << "QRestReply(isSuccess = " << reply.isSuccess()
+ << ", httpStatus = " << reply.httpStatus()
+ << ", isHttpStatusSuccess = " << reply.isHttpStatusSuccess()
+ << ", hasError = " << reply.hasError()
+ << ", errorString = " << reply.errorString()
+ << ", error = " << reply.error()
+ << ", isFinished = " << reply.networkReply()->isFinished()
+ << ", bytesAvailable = " << reply.networkReply()->bytesAvailable()
+ << ", url " << reply.networkReply()->url()
+ << ", operation = " << operationName(reply.networkReply()->operation())
+ << ", reply headers = " << reply.networkReply()->rawHeaderPairs()
+ << ")";
+ return debug;
+}
+#endif // QT_NO_DEBUG_STREAM
+
+static constexpr auto parse_OWS(QByteArrayView data) noexcept
+{
+ struct R {
+ QByteArrayView ows, tail;
+ };
+
+ constexpr auto is_OWS_char = [](auto ch) { return ch == ' ' || ch == '\t'; };
+
+ qsizetype i = 0;
+ while (i < data.size() && is_OWS_char(data[i]))
+ ++i;
+
+ return R{data.first(i), data.sliced(i)};
+}
+
+static constexpr void eat_OWS(QByteArrayView &data) noexcept
+{
+ data = parse_OWS(data).tail;
+}
+
+static constexpr auto parse_quoted_string(QByteArrayView data, qxp::function_ref<void(char) const> yield)
+{
+ struct R {
+ QByteArrayView quotedString, tail;
+ constexpr explicit operator bool() const noexcept { return !quotedString.isEmpty(); }
+ };
+
+ if (!data.startsWith('"'))
+ return R{{}, data};
+
+ qsizetype i = 1; // one past initial DQUOTE
+ while (i < data.size()) {
+ switch (auto ch = data[i++]) {
+ case '"': // final DQUOTE -> end of string
+ return R{data.first(i), data.sliced(i)};
+ case '\\': // quoted-pair
+ // https://www.rfc-editor.org/rfc/rfc9110.html#section-5.6.4-3:
+ // Recipients that process the value of a quoted-string MUST handle a
+ // quoted-pair as if it were replaced by the octet following the backslash.
+ if (i == data.size())
+ break; // premature end
+ ch = data[i++]; // eat '\\'
+ [[fallthrough]];
+ default:
+ // we don't validate quoted-string octets to be only qdtext (Postel's Law)
+ yield(ch);
+ }
+ }
+
+ return R{{}, data}; // premature end
+}
+
+static constexpr bool is_tchar(char ch) noexcept
+{
+ // ### optimize
+ switch (ch) {
+ case '!':
+ case '#':
+ case '$':
+ case '%':
+ case '&':
+ case '\'':
+ case '*':
+ case '+':
+ case '-':
+ case '.':
+ case '^':
+ case '_':
+ case '`':
+ case '|':
+ case '~':
+ return true;
+ default:
+ return (ch >= 'a' && ch <= 'z')
+ || (ch >= '0' && ch <= '9')
+ || (ch >= 'A' && ch <= 'Z');
+ }
+}
+
+static constexpr auto parse_token(QByteArrayView data) noexcept
+{
+ struct R {
+ QByteArrayView token, tail;
+ constexpr explicit operator bool() const noexcept { return !token.isEmpty(); }
+ };
+
+ qsizetype i = 0;
+ while (i < data.size() && is_tchar(data[i]))
+ ++i;
+
+ return R{data.first(i), data.sliced(i)};
+}
+
+static constexpr auto parse_parameter(QByteArrayView data, qxp::function_ref<void(char) const> yield)
+{
+ struct R {
+ QLatin1StringView name; QByteArrayView value; QByteArrayView tail;
+ constexpr explicit operator bool() const noexcept { return !name.isEmpty(); }
+ };
+
+ const auto invalid = R{{}, {}, data}; // preserves original `data`
+
+ // parameter = parameter-name "=" parameter-value
+ // parameter-name = token
+ // parameter-value = ( token / quoted-string )
+
+ const auto name = parse_token(data);
+ if (!name)
+ return invalid;
+ data = name.tail;
+
+ eat_OWS(data); // not in the grammar, but accepted under Postel's Law
+
+ if (!data.startsWith('='))
+ return invalid;
+ data = data.sliced(1);
+
+ eat_OWS(data); // not in the grammar, but accepted under Postel's Law
+
+ if (Q_UNLIKELY(data.startsWith('"'))) { // value is a quoted-string
+
+ const auto value = parse_quoted_string(data, yield);
+ if (!value)
+ return invalid;
+ data = value.tail;
+
+ return R{QLatin1StringView{name.token}, value.quotedString, data};
+
+ } else { // value is a token
+
+ const auto value = parse_token(data);
+ if (!value)
+ return invalid;
+ data = value.tail;
+
+ return R{QLatin1StringView{name.token}, value.token, data};
+ }
+}
+
+static auto parse_content_type(QByteArrayView data)
+{
+ struct R {
+ QLatin1StringView type, subtype;
+ std::string charset;
+ constexpr explicit operator bool() const noexcept { return !type.isEmpty(); }
+ };
+
+ eat_OWS(data); // not in the grammar, but accepted under Postel's Law
+
+ const auto type = parse_token(data);
+ if (!type)
+ return R{};
+ data = type.tail;
+
+ eat_OWS(data); // not in the grammar, but accepted under Postel's Law
+
+ if (!data.startsWith('/'))
+ return R{};
+ data = data.sliced(1);
+
+ eat_OWS(data); // not in the grammar, but accepted under Postel's Law
+
+ const auto subtype = parse_token(data);
+ if (!subtype)
+ return R{};
+ data = subtype.tail;
+
+ eat_OWS(data);
+
+ auto r = R{QLatin1StringView{type.token}, QLatin1StringView{subtype.token}, {}};
+
+ while (data.startsWith(';')) {
+
+ data = data.sliced(1); // eat ';'
+
+ eat_OWS(data);
+
+ const auto param = parse_parameter(data, [&](char ch) { r.charset.append(1, ch); });
+ if (param.name.compare("charset"_L1, Qt::CaseInsensitive) == 0) {
+ if (r.charset.empty() && !param.value.startsWith('"')) // wasn't a quoted-string
+ r.charset.assign(param.value.begin(), param.value.end());
+ return r; // charset found
+ }
+ r.charset.clear(); // wasn't an actual charset
+ if (param.tail.size() == data.size()) // no progress was made
+ break; // returns {type, subtype}
+ // otherwise, continue (accepting e.g. `;;`)
+ data = param.tail;
+
+ eat_OWS(data);
+ }
+
+ return r; // no charset found
+}
+
+QByteArray QRestReplyPrivate::contentCharset(const QNetworkReply* reply)
+{
+ // Content-type consists of mimetype and optional parameters, of which one may be 'charset'
+ // Example values and their combinations below are all valid, see RFC 7231 section 3.1.1.5
+ // and RFC 2045 section 5.1
+ //
+ // text/plain; charset=utf-8
+ // text/plain; charset=utf-8;version=1.7
+ // text/plain; charset = utf-8
+ // text/plain; charset ="utf-8"
+
+ const QByteArray contentTypeValue =
+ reply->header(QNetworkRequest::KnownHeaders::ContentTypeHeader).toByteArray();
+
+ const auto r = parse_content_type(contentTypeValue);
+ if (r && !r.charset.empty())
+ return QByteArrayView(r.charset).toByteArray();
+ else
+ return "UTF-8"_ba; // Default to the most commonly used UTF-8.
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/access/qrestreply.h b/src/network/access/qrestreply.h
new file mode 100644
index 0000000000..c32fff1d4e
--- /dev/null
+++ b/src/network/access/qrestreply.h
@@ -0,0 +1,71 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QRESTREPLY_H
+#define QRESTREPLY_H
+
+#include <QtNetwork/qnetworkreply.h>
+
+#include <QtCore/qpointer.h>
+
+#include <optional>
+#include <utility>
+
+QT_BEGIN_NAMESPACE
+
+class QByteArray;
+class QDebug;
+struct QJsonParseError;
+class QJsonDocument;
+class QString;
+
+class QRestReplyPrivate;
+class QT_TECH_PREVIEW_API QRestReply
+{
+public:
+ Q_NETWORK_EXPORT explicit QRestReply(QNetworkReply *reply);
+ Q_NETWORK_EXPORT ~QRestReply();
+
+ QRestReply(QRestReply &&other) noexcept
+ : wrapped(std::move(other.wrapped)),
+ d(std::exchange(other.d, nullptr))
+ {
+ }
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QRestReply)
+ void swap(QRestReply &other) noexcept
+ {
+ wrapped.swap(other.wrapped);
+ qt_ptr_swap(d, other.d);
+ }
+
+ Q_NETWORK_EXPORT QNetworkReply *networkReply() const;
+
+ Q_NETWORK_EXPORT std::optional<QJsonDocument> readJson(QJsonParseError *error = nullptr);
+ Q_NETWORK_EXPORT QByteArray readBody();
+ Q_NETWORK_EXPORT QString readText();
+
+ bool isSuccess() const
+ {
+ return !hasError() && isHttpStatusSuccess();
+ }
+ Q_NETWORK_EXPORT int httpStatus() const;
+ Q_NETWORK_EXPORT bool isHttpStatusSuccess() const;
+
+ Q_NETWORK_EXPORT bool hasError() const;
+ Q_NETWORK_EXPORT QNetworkReply::NetworkError error() const;
+ Q_NETWORK_EXPORT QString errorString() const;
+
+private:
+#ifndef QT_NO_DEBUG_STREAM
+ friend Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, const QRestReply &reply);
+#endif
+ QPointer<QNetworkReply> wrapped;
+ QRestReplyPrivate *d = nullptr;
+ Q_DISABLE_COPY(QRestReply)
+};
+
+Q_DECLARE_SHARED(QRestReply)
+
+QT_END_NAMESPACE
+
+#endif // QRESTREPLY_H
diff --git a/src/network/access/qrestreply_p.h b/src/network/access/qrestreply_p.h
new file mode 100644
index 0000000000..ec963cf168
--- /dev/null
+++ b/src/network/access/qrestreply_p.h
@@ -0,0 +1,40 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QRESTREPLY_P_H
+#define QRESTREPLY_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the Network Access API. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/private/qstringconverter_p.h>
+
+#include <optional>
+
+QT_BEGIN_NAMESPACE
+
+class QByteArray;
+class QNetworkReply;
+
+class QRestReplyPrivate
+{
+public:
+ QRestReplyPrivate();
+ ~QRestReplyPrivate();
+
+ std::optional<QStringDecoder> decoder;
+
+ static QByteArray contentCharset(const QNetworkReply *reply);
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/network/access/qsocketabstraction_p.h b/src/network/access/qsocketabstraction_p.h
new file mode 100644
index 0000000000..2b40b80244
--- /dev/null
+++ b/src/network/access/qsocketabstraction_p.h
@@ -0,0 +1,91 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QSOCKETABSTRACTION_P_H
+#define QSOCKETABSTRACTION_P_H
+
+#include <private/qtnetworkglobal_p.h>
+
+#include <QtNetwork/qabstractsocket.h>
+#include <QtNetwork/qlocalsocket.h>
+
+#include <QtCore/qxpfunctional.h>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the Network Access API. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+// Helper functions to deal with a QIODevice that is either a socket or a local
+// socket.
+namespace QSocketAbstraction {
+template <typename Fn, typename... Args>
+auto visit(Fn &&fn, QIODevice *socket, Args &&...args)
+{
+ if (auto *s = qobject_cast<QAbstractSocket *>(socket))
+ return std::forward<Fn>(fn)(s, std::forward<Args>(args)...);
+ if (auto *s = qobject_cast<QLocalSocket *>(socket))
+ return std::forward<Fn>(fn)(s, std::forward<Args>(args)...);
+ Q_UNREACHABLE();
+}
+
+// Since QLocalSocket's LocalSocketState's values are defined as being equal
+// to some of QAbstractSocket's SocketState's values, we can use the superset
+// of the two as the return type.
+inline QAbstractSocket::SocketState socketState(QIODevice *device)
+{
+ auto getState = [](auto *s) {
+ using T = std::remove_pointer_t<decltype(s)>;
+ if constexpr (std::is_same_v<T, QAbstractSocket>) {
+ return s->state();
+ } else if constexpr (std::is_same_v<T, QLocalSocket>) {
+ QLocalSocket::LocalSocketState st = s->state();
+ return static_cast<QAbstractSocket::SocketState>(st);
+ }
+ Q_UNREACHABLE();
+ };
+ return visit(getState, device);
+}
+
+// Same as for socketState(), but for the errors
+inline QAbstractSocket::SocketError socketError(QIODevice *device)
+{
+ auto getError = [](auto *s) {
+ using T = std::remove_pointer_t<decltype(s)>;
+ if constexpr (std::is_same_v<T, QAbstractSocket>) {
+ return s->error();
+ } else if constexpr (std::is_same_v<T, QLocalSocket>) {
+ QLocalSocket::LocalSocketError st = s->error();
+ return static_cast<QAbstractSocket::SocketError>(st);
+ }
+ Q_UNREACHABLE();
+ };
+ return visit(getError, device);
+}
+
+inline QString socketPeerName(QIODevice *device)
+{
+ auto getPeerName = [](auto *s) {
+ using T = std::remove_pointer_t<decltype(s)>;
+ if constexpr (std::is_same_v<T, QAbstractSocket>) {
+ return s->peerName();
+ } else if constexpr (std::is_same_v<T, QLocalSocket>) {
+ return s->serverName();
+ }
+ Q_UNREACHABLE();
+ };
+ return visit(getPeerName, device);
+}
+} // namespace QSocketAbstraction
+
+QT_END_NAMESPACE
+
+#endif // QSOCKETABSTRACTION_P_H
diff --git a/src/network/android/jar/.gitignore b/src/network/android/jar/.gitignore
new file mode 100644
index 0000000000..364420a59a
--- /dev/null
+++ b/src/network/android/jar/.gitignore
@@ -0,0 +1,6 @@
+.gradle/
+build/
+gradle/
+gradlew
+gradlew.bat
+local.properties
diff --git a/src/network/android/jar/CMakeLists.txt b/src/network/android/jar/CMakeLists.txt
index c2635ec666..b5172b6aba 100644
--- a/src/network/android/jar/CMakeLists.txt
+++ b/src/network/android/jar/CMakeLists.txt
@@ -1,17 +1,19 @@
-# Generated from jar.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
set(java_sources
- src/org/qtproject/qt5/android/network/QtNetwork.java
+ src/org/qtproject/qt/android/network/QtNetwork.java
)
-qt_internal_add_jar(QtAndroidNetwork
+qt_internal_add_jar(Qt${QtBase_VERSION_MAJOR}AndroidNetwork
INCLUDE_JARS ${QT_ANDROID_JAR}
SOURCES ${java_sources}
OUTPUT_DIR "${QT_BUILD_DIR}/jar"
)
-install_jar(QtAndroidNetwork
- DESTINATION jar
+qt_path_join(destination ${INSTALL_DATADIR} "jar")
+
+install_jar(Qt${QtBase_VERSION_MAJOR}AndroidNetwork
+ DESTINATION ${destination}
COMPONENT Devel
)
-
diff --git a/src/network/android/jar/build.gradle b/src/network/android/jar/build.gradle
new file mode 100644
index 0000000000..68a9381ad2
--- /dev/null
+++ b/src/network/android/jar/build.gradle
@@ -0,0 +1,51 @@
+// This is mainly used to allow Android Studio to easily read this folder as an android project.
+
+buildscript {
+ repositories {
+ google()
+ mavenCentral()
+ }
+
+ dependencies {
+ classpath 'com.android.tools.build:gradle:8.0.2'
+ }
+}
+
+apply plugin: 'com.android.library'
+
+dependencies {
+ implementation fileTree(dir: "libs", include: ["*.jar"])
+}
+
+repositories {
+ google()
+ mavenCentral()
+}
+
+android {
+ compileSdk 34
+
+ defaultConfig {
+ minSdkVersion 23
+ }
+
+ sourceSets {
+ main {
+ java.srcDir 'src/'
+ resources.srcDir 'libs/'
+ manifest.srcFile 'AndroidManifest.xml'
+ res.srcDirs = ['res/']
+ }
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
+ android {
+ lintOptions {
+ abortOnError true
+ }
+ }
+}
diff --git a/src/network/android/jar/jar.pro b/src/network/android/jar/jar.pro
deleted file mode 100644
index 4af1012c1c..0000000000
--- a/src/network/android/jar/jar.pro
+++ /dev/null
@@ -1,15 +0,0 @@
-CONFIG += single_arch
-
-TARGET = QtAndroidNetwork
-
-load(qt_build_paths)
-CONFIG += java
-DESTDIR = $$MODULE_BASE_OUTDIR/jar
-
-JAVACLASSPATH += $$PWD/src
-
-JAVASOURCES += $$PWD/src/org/qtproject/qt5/android/network/QtNetwork.java
-
-# install
-target.path = $$[QT_INSTALL_PREFIX]/jar
-INSTALLS += target
diff --git a/src/network/android/jar/settings.gradle b/src/network/android/jar/settings.gradle
new file mode 100644
index 0000000000..a5d909ed33
--- /dev/null
+++ b/src/network/android/jar/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = "QtAndroidNetwork"
diff --git a/src/network/android/jar/src/org/qtproject/qt/android/network/QtNetwork.java b/src/network/android/jar/src/org/qtproject/qt/android/network/QtNetwork.java
new file mode 100644
index 0000000000..eb6a16d5b7
--- /dev/null
+++ b/src/network/android/jar/src/org/qtproject/qt/android/network/QtNetwork.java
@@ -0,0 +1,64 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android.network;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.net.Proxy;
+import android.net.ProxyInfo;
+
+public class QtNetwork
+{
+ private static final String LOG_TAG = "QtNetwork";
+ private static ProxyReceiver m_proxyReceiver = null;
+ private static final Object m_lock = new Object();
+ private static ProxyInfo m_proxyInfo = null;
+
+ private static class ProxyReceiver extends BroadcastReceiver
+ {
+ @Override
+ public void onReceive(Context context, Intent intent)
+ {
+ m_proxyInfo = null;
+ }
+ }
+
+ private QtNetwork() {}
+
+ public static void registerReceiver(final Context context)
+ {
+ synchronized (m_lock) {
+ if (m_proxyReceiver == null) {
+ m_proxyReceiver = new ProxyReceiver();
+ IntentFilter intentFilter = new IntentFilter(Proxy.PROXY_CHANGE_ACTION);
+ context.registerReceiver(m_proxyReceiver, intentFilter);
+ }
+ }
+ }
+
+ public static void unregisterReceiver(final Context context)
+ {
+ synchronized (m_lock) {
+ if (m_proxyReceiver == null)
+ return;
+
+ context.unregisterReceiver(m_proxyReceiver);
+ }
+ }
+
+ public static ConnectivityManager getConnectivityManager(final Context context)
+ {
+ return (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ }
+
+ public static ProxyInfo getProxyInfo(final Context context)
+ {
+ if (m_proxyInfo == null)
+ m_proxyInfo = (ProxyInfo)getConnectivityManager(context).getDefaultProxy();
+ return m_proxyInfo;
+ }
+}
diff --git a/src/network/android/jar/src/org/qtproject/qt5/android/network/QtNetwork.java b/src/network/android/jar/src/org/qtproject/qt5/android/network/QtNetwork.java
deleted file mode 100644
index 249ffe61a5..0000000000
--- a/src/network/android/jar/src/org/qtproject/qt5/android/network/QtNetwork.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-package org.qtproject.qt5.android.network;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.util.Log;
-import android.net.ConnectivityManager;
-import android.net.Proxy;
-import android.net.ProxyInfo;
-
-public class QtNetwork
-{
- private static final String LOG_TAG = "QtNetwork";
- private static ProxyReceiver m_proxyReceiver = null;
- private static final Object m_lock = new Object();
- private static ProxyInfo m_proxyInfo = null;
-
- private static class ProxyReceiver extends BroadcastReceiver
- {
- @Override
- public void onReceive(Context context, Intent intent)
- {
- m_proxyInfo = null;
- }
- }
-
- private QtNetwork() {}
-
- public static void registerReceiver(final Context context)
- {
- synchronized (m_lock) {
- if (m_proxyReceiver == null) {
- m_proxyReceiver = new ProxyReceiver();
- IntentFilter intentFilter = new IntentFilter(Proxy.PROXY_CHANGE_ACTION);
- context.registerReceiver(m_proxyReceiver, intentFilter);
- }
- }
- }
-
- public static void unregisterReceiver(final Context context)
- {
- synchronized (m_lock) {
- if (m_proxyReceiver == null)
- return;
-
- context.unregisterReceiver(m_proxyReceiver);
- }
- }
-
- public static ConnectivityManager getConnectivityManager(final Context context)
- {
- return (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
- }
-
- public static ProxyInfo getProxyInfo(final Context context)
- {
- if (m_proxyInfo == null)
- m_proxyInfo = (ProxyInfo)getConnectivityManager(context).getDefaultProxy();
- return m_proxyInfo;
- }
-}
diff --git a/src/network/compat/removed_api.cpp b/src/network/compat/removed_api.cpp
new file mode 100644
index 0000000000..86951d9222
--- /dev/null
+++ b/src/network/compat/removed_api.cpp
@@ -0,0 +1,67 @@
+// Copyright (c) 2023 LLC «V Kontakte»
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#define QT_NETWORK_BUILD_REMOVED_API
+
+#include "qtnetworkglobal.h"
+
+QT_USE_NAMESPACE
+
+#if QT_NETWORK_REMOVED_SINCE(6, 7)
+
+#include "qhostinfo.h"
+
+// static
+int QHostInfo::lookupHost(const QString &name, QObject *receiver, const char *member)
+{
+ const auto *r = receiver;
+ return lookupHost(name, r, member);
+}
+
+
+#include "qnetworkreply.h"
+
+QByteArray QNetworkReply::rawHeader(const QByteArray &headerName) const
+{
+ return rawHeader(qToByteArrayViewIgnoringNull(headerName));
+}
+
+bool QNetworkReply::hasRawHeader(const QByteArray &headerName) const
+{
+ return hasRawHeader(qToByteArrayViewIgnoringNull(headerName));
+}
+
+#include "qnetworkrequest.h"
+
+QByteArray QNetworkRequest::rawHeader(const QByteArray &headerName) const
+{
+ return rawHeader(qToByteArrayViewIgnoringNull(headerName));
+}
+
+bool QNetworkRequest::hasRawHeader(const QByteArray &headerName) const
+{
+ return hasRawHeader(qToByteArrayViewIgnoringNull(headerName));
+}
+
+#include "qnetworkcookie.h"
+
+QList<QNetworkCookie> QNetworkCookie::parseCookies(const QByteArray &cookieString)
+{
+ return parseCookies(qToByteArrayViewIgnoringNull(cookieString));
+}
+
+// #include "qotherheader.h"
+// // implement removed functions from qotherheader.h
+// order sections alphabetically
+
+#endif // QT_NETWORK_REMOVED_SINCE(6, 7)
+
+#if QT_NETWORK_REMOVED_SINCE(6, 8)
+
+#include "qnetworkrequest.h" // inlined API
+
+// #include "qotherheader.h"
+// // implement removed functions from qotherheader.h
+// order sections alphabetically
+
+#endif // QT_NETWORK_REMOVED_SINCE(6, 8)
diff --git a/src/network/configure.cmake b/src/network/configure.cmake
index 6f3dac9faa..cda444b873 100644
--- a/src/network/configure.cmake
+++ b/src/network/configure.cmake
@@ -1,4 +1,5 @@
-
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#### Inputs
@@ -8,58 +9,10 @@
qt_find_package(WrapBrotli PROVIDED_TARGETS WrapBrotli::WrapBrotliDec MODULE_NAME network QMAKE_LIB brotli)
qt_find_package(Libproxy PROVIDED_TARGETS PkgConfig::Libproxy MODULE_NAME network QMAKE_LIB libproxy)
-qt_find_package(WrapOpenSSLHeaders PROVIDED_TARGETS WrapOpenSSLHeaders::WrapOpenSSLHeaders MODULE_NAME network QMAKE_LIB openssl_headers)
-# openssl_headers
-qt_config_compile_test(openssl_headers
- LIBRARIES
- WrapOpenSSLHeaders::WrapOpenSSLHeaders
- CODE
-"
-#include <openssl/ssl.h>
-#include <openssl/opensslv.h>
-#if !defined(OPENSSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER-0 < 0x10101000L
-# error OpenSSL >= 1.1.1 is required
-#endif
-#if !defined(OPENSSL_NO_EC) && !defined(SSL_CTRL_SET_CURVES)
-# error OpenSSL was reported as >= 1.1.1 but is missing required features, possibly it is libressl which is unsupported
-#endif
-int main(int argc, char **argv)
-{
- (void)argc; (void)argv;
- /* BEGIN TEST: */
-
- /* END TEST: */
- return 0;
-}
-")
-
-qt_find_package(WrapOpenSSL PROVIDED_TARGETS WrapOpenSSL::WrapOpenSSL MODULE_NAME network QMAKE_LIB openssl)
-# openssl
-qt_config_compile_test(openssl
- LIBRARIES
- WrapOpenSSL::WrapOpenSSL
- CODE
-"
-#include <openssl/ssl.h>
-#include <openssl/opensslv.h>
-#if !defined(OPENSSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER-0 < 0x10101000L
-# error OpenSSL >= 1.1.1 is required
-#endif
-#if !defined(OPENSSL_NO_EC) && !defined(SSL_CTRL_SET_CURVES)
-# error OpenSSL was reported as >= 1.1.1 but is missing required features, possibly it is libressl which is unsupported
-#endif
-int main(int argc, char **argv)
-{
- (void)argc; (void)argv;
- /* BEGIN TEST: */
-SSL_free(SSL_new(0));
- /* END TEST: */
- return 0;
-}
-")
-
qt_find_package(GSSAPI PROVIDED_TARGETS GSSAPI::GSSAPI MODULE_NAME network QMAKE_LIB gssapi)
-
+qt_find_package(GLIB2 OPTIONAL_COMPONENTS GOBJECT PROVIDED_TARGETS GLIB2::GOBJECT MODULE_NAME core QMAKE_LIB gobject)
+qt_find_package(GLIB2 OPTIONAL_COMPONENTS GIO PROVIDED_TARGETS GLIB2::GIO MODULE_NAME core QMAKE_LIB gio)
+qt_find_package(WrapResolv PROVIDED_TARGETS WrapResolv::WrapResolv MODULE_NAME network QMAKE_LIB libresolv)
#### Tests
@@ -67,15 +20,13 @@ qt_find_package(GSSAPI PROVIDED_TARGETS GSSAPI::GSSAPI MODULE_NAME network QMAKE
qt_config_compile_test(getifaddrs
LABEL "getifaddrs()"
CODE
-"
-#include <sys/types.h>
+"#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <ifaddrs.h>
-int main(int argc, char **argv)
+int main(void)
{
- (void)argc; (void)argv;
/* BEGIN TEST: */
ifaddrs *list;
getifaddrs(&list);
@@ -90,14 +41,12 @@ freeifaddrs(list);
qt_config_compile_test(ipv6ifname
LABEL "IPv6 ifname"
CODE
-"
-#include <sys/types.h>
+"#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
-int main(int argc, char **argv)
+int main(void)
{
- (void)argc; (void)argv;
/* BEGIN TEST: */
char buf[IFNAMSIZ];
if_nametoindex(\"eth0\");
@@ -113,15 +62,13 @@ if_freenameindex(if_nameindex());
qt_config_compile_test(linux_netlink
LABEL "Linux AF_NETLINK sockets"
CODE
-"
-#include <asm/types.h>
+"#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <sys/socket.h>
-int main(int argc, char **argv)
+int main(void)
{
- (void)argc; (void)argv;
/* BEGIN TEST: */
struct rtattr rta = { };
struct ifinfomsg ifi = {};
@@ -137,19 +84,36 @@ ci.ifa_prefered = ci.ifa_valid = 0;
}
")
+# res_setserver
+qt_config_compile_test(res_setservers
+ LABEL "res_setservers()"
+ LIBRARIES
+ WrapResolv::WrapResolv
+ CODE
+"#include <sys/types.h>
+#include <netinet/in.h>
+#include <resolv.h>
+int main()
+{
+ union res_sockaddr_union sa;
+ res_state s = nullptr;
+ res_setservers(s, &sa, 1);
+ return 0;
+}
+"
+)
+
# sctp
qt_config_compile_test(sctp
LABEL "SCTP support"
CODE
-"
-#include <sys/types.h>
+"#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/sctp.h>
-int main(int argc, char **argv)
+int main(void)
{
- (void)argc; (void)argv;
/* BEGIN TEST: */
sctp_initmsg sctpInitMsg;
socklen_t sctpInitMsgSize = sizeof(sctpInitMsg);
@@ -167,16 +131,14 @@ qt_config_compile_test(dtls
LIBRARIES
WrapOpenSSLHeaders::WrapOpenSSLHeaders
CODE
-"
-#include <openssl/ssl.h>
+"#include <openssl/ssl.h>
#if defined(OPENSSL_NO_DTLS) || !defined(DTLS1_2_VERSION)
# error OpenSSL without DTLS support
#endif
-int main(int argc, char **argv)
+
+int main(void)
{
- (void)argc; (void)argv;
/* BEGIN TEST: */
-
/* END TEST: */
return 0;
}
@@ -188,33 +150,30 @@ qt_config_compile_test(ocsp
LIBRARIES
WrapOpenSSLHeaders::WrapOpenSSLHeaders
CODE
-"
-#include <openssl/ssl.h>
+"#include <openssl/ssl.h>
#include <openssl/ocsp.h>
#if defined(OPENSSL_NO_OCSP) || defined(OPENSSL_NO_TLSEXT)
# error OpenSSL without OCSP stapling
#endif
-int main(int argc, char **argv)
+
+int main(void)
{
- (void)argc; (void)argv;
/* BEGIN TEST: */
-
/* END TEST: */
return 0;
}
")
-# netlistmgr
-qt_config_compile_test(netlistmgr
+# networklistmanager
+qt_config_compile_test(networklistmanager
LABEL "Network List Manager"
CODE
-"
-#include <netlistmgr.h>
+"#include <netlistmgr.h>
+#include <ocidl.h>
#include <wrl/client.h>
-int main(int argc, char **argv)
+int main(void)
{
- (void)argc; (void)argv;
/* BEGIN TEST: */
using namespace Microsoft::WRL;
ComPtr<INetworkListManager> networkListManager;
@@ -232,22 +191,21 @@ connectionPointContainer->FindConnectionPoint(IID_INetworkConnectionEvents, &con
#### Features
-qt_feature("corewlan" PUBLIC PRIVATE
- LABEL "CoreWLan"
- CONDITION libs.corewlan OR FIXME
- EMIT_IF APPLE
-)
-qt_feature_definition("corewlan" "QT_NO_COREWLAN" NEGATE VALUE "1")
qt_feature("getifaddrs" PUBLIC
LABEL "getifaddrs()"
- CONDITION TEST_getifaddrs
+ CONDITION VXWORKS OR UNIX AND NOT QT_FEATURE_linux_netlink AND TEST_getifaddrs
)
qt_feature_definition("getifaddrs" "QT_NO_GETIFADDRS" NEGATE VALUE "1")
qt_feature("ipv6ifname" PUBLIC
LABEL "IPv6 ifname"
- CONDITION TEST_ipv6ifname
+ CONDITION VXWORKS OR UNIX AND NOT QT_FEATURE_linux_netlink AND TEST_ipv6ifname
)
qt_feature_definition("ipv6ifname" "QT_NO_IPV6IFNAME" NEGATE VALUE "1")
+qt_feature("libresolv" PRIVATE
+ LABEL "libresolv"
+ CONDITION WrapResolv_FOUND
+ AUTODETECT UNIX
+)
qt_feature("libproxy" PRIVATE
LABEL "libproxy"
AUTODETECT OFF
@@ -257,36 +215,20 @@ qt_feature("linux-netlink" PRIVATE
LABEL "Linux AF_NETLINK"
CONDITION LINUX AND NOT ANDROID AND TEST_linux_netlink
)
-qt_feature("openssl" PRIVATE
- LABEL "OpenSSL"
- CONDITION QT_FEATURE_openssl_runtime OR QT_FEATURE_openssl_linked
- ENABLE false
+qt_feature("res_setservers" PRIVATE
+ LABEL "res_setservers()"
+ CONDITION QT_FEATURE_libresolv AND TEST_res_setservers
)
-qt_feature_definition("openssl" "QT_NO_OPENSSL" NEGATE)
-qt_feature_config("openssl" QMAKE_PUBLIC_QT_CONFIG)
-qt_feature("openssl-runtime"
- AUTODETECT NOT WASM
- CONDITION NOT QT_FEATURE_securetransport AND NOT QT_FEATURE_schannel AND TEST_openssl_headers
- ENABLE INPUT_openssl STREQUAL 'yes' OR INPUT_openssl STREQUAL 'runtime'
- DISABLE INPUT_openssl STREQUAL 'no' OR INPUT_openssl STREQUAL 'linked' OR INPUT_ssl STREQUAL 'no'
-)
-qt_feature("openssl-linked" PRIVATE
- LABEL " Qt directly linked to OpenSSL"
- AUTODETECT OFF
- CONDITION NOT QT_FEATURE_securetransport AND NOT QT_FEATURE_schannel AND TEST_openssl
- ENABLE INPUT_openssl STREQUAL 'linked'
-)
-qt_feature_definition("openssl-linked" "QT_LINKED_OPENSSL")
qt_feature("securetransport" PUBLIC
LABEL "SecureTransport"
- CONDITION APPLE AND ( INPUT_openssl STREQUAL '' OR INPUT_openssl STREQUAL 'no' )
- DISABLE INPUT_securetransport STREQUAL 'no' OR INPUT_ssl STREQUAL 'no'
+ CONDITION APPLE
+ DISABLE INPUT_ssl STREQUAL 'no'
)
qt_feature_definition("securetransport" "QT_SECURETRANSPORT")
qt_feature("schannel" PUBLIC
LABEL "Schannel"
- CONDITION INPUT_schannel STREQUAL 'yes' AND WIN32 AND ( INPUT_openssl STREQUAL '' OR INPUT_openssl STREQUAL 'no' )
- DISABLE INPUT_schannel STREQUAL 'no' OR INPUT_ssl STREQUAL 'no'
+ CONDITION WIN32
+ DISABLE INPUT_ssl STREQUAL 'no'
)
qt_feature_definition("schannel" "QT_SCHANNEL")
qt_feature("ssl" PUBLIC
@@ -304,11 +246,7 @@ qt_feature("ocsp" PUBLIC
SECTION "Networking"
LABEL "OCSP-stapling"
PURPOSE "Provides OCSP stapling support"
- CONDITION QT_FEATURE_opensslv11 AND TEST_ocsp
-)
-qt_feature("opensslv11" PUBLIC
- LABEL "OpenSSL 1.1"
- CONDITION QT_FEATURE_openssl
+ CONDITION QT_FEATURE_openssl AND TEST_ocsp
)
qt_feature("sctp" PUBLIC
LABEL "SCTP"
@@ -377,6 +315,7 @@ qt_feature("dnslookup" PUBLIC
SECTION "Networking"
LABEL "QDnsLookup"
PURPOSE "Provides API for DNS lookups."
+ CONDITION QT_FEATURE_thread AND NOT INTEGRITY
)
qt_feature("gssapi" PUBLIC
SECTION "Networking"
@@ -392,22 +331,34 @@ qt_feature("sspi" PUBLIC
CONDITION WIN32
)
qt_feature_definition("sspi" "QT_NO_SSPI" NEGATE VALUE "1")
-qt_feature("netlistmgr" PRIVATE
+qt_feature("networklistmanager" PRIVATE
SECTION "Networking"
LABEL "Network List Manager"
PURPOSE "Use Network List Manager to keep track of network connectivity"
- CONDITION WIN32 AND TEST_netlistmgr
+ CONDITION WIN32 AND TEST_networklistmanager
)
qt_feature("topleveldomain" PUBLIC
SECTION "Networking"
- LABEL "qTopLevelDomain()"
- PURPOSE "Provides support for extracting the top level domain from URLs. If enabled, a binary dump of the Public Suffix List (http://www.publicsuffix.org, Mozilla License) is included. The data is then also used in QNetworkCookieJar::validateCookie."
+ LABEL "qIsEffectiveTLD()"
+ PURPOSE "Provides support for checking if a domain is a top level domain. If enabled, a binary dump of the Public Suffix List (http://www.publicsuffix.org, Mozilla License) is included. The data is used in QNetworkCookieJar."
+ AUTODETECT NOT WASM
+ DISABLE INPUT_publicsuffix STREQUAL "no"
)
-qt_configure_add_summary_section(NAME "Qt Network")
-qt_configure_add_summary_entry(
- ARGS "corewlan"
- CONDITION APPLE
+qt_feature("publicsuffix-qt" PRIVATE
+ LABEL " Built-in publicsuffix database"
+ CONDITION QT_FEATURE_topleveldomain
+ ENABLE INPUT_publicsuffix STREQUAL "qt" OR INPUT_publicsuffix STREQUAL "all"
+ DISABLE INPUT_publicsuffix STREQUAL "system"
+)
+qt_feature("publicsuffix-system" PRIVATE
+ LABEL " System publicsuffix database"
+ CONDITION QT_FEATURE_topleveldomain
+ AUTODETECT LINUX
+ ENABLE INPUT_publicsuffix STREQUAL "system" OR INPUT_publicsuffix STREQUAL "all"
+ DISABLE INPUT_publicsuffix STREQUAL "qt"
)
+
+qt_configure_add_summary_section(NAME "Qt Network")
qt_configure_add_summary_entry(ARGS "getifaddrs")
qt_configure_add_summary_entry(ARGS "ipv6ifname")
qt_configure_add_summary_entry(ARGS "libproxy")
@@ -423,23 +374,13 @@ qt_configure_add_summary_entry(
ARGS "schannel"
CONDITION WIN32
)
-qt_configure_add_summary_entry(ARGS "openssl")
-qt_configure_add_summary_entry(ARGS "openssl-linked")
-qt_configure_add_summary_entry(ARGS "opensslv11")
qt_configure_add_summary_entry(ARGS "dtls")
qt_configure_add_summary_entry(ARGS "ocsp")
qt_configure_add_summary_entry(ARGS "sctp")
qt_configure_add_summary_entry(ARGS "system-proxies")
qt_configure_add_summary_entry(ARGS "gssapi")
qt_configure_add_summary_entry(ARGS "brotli")
+qt_configure_add_summary_entry(ARGS "topleveldomain")
+qt_configure_add_summary_entry(ARGS "publicsuffix-qt")
+qt_configure_add_summary_entry(ARGS "publicsuffix-system")
qt_configure_end_summary_section() # end of "Qt Network" section
-qt_configure_add_report_entry(
- TYPE NOTE
- MESSAGE "When linking against OpenSSL, you can override the default library names through OPENSSL_LIBS. For example: OPENSSL_LIBS='-L/opt/ssl/lib -lssl -lcrypto' ./configure -openssl-linked"
- CONDITION NOT ANDROID AND QT_FEATURE_openssl_linked AND ( NOT TEST_openssl.source EQUAL 0 ) AND INPUT_openssl.prefix STREQUAL '' AND INPUT_openssl.libs STREQUAL '' AND INPUT_openssl.libs.debug STREQUAL '' OR FIXME
-)
-qt_configure_add_report_entry(
- TYPE WARNING
- MESSAGE "Some of libproxy's plugins may use incompatible Qt versions. Some platforms and distributions ship libproxy with plugins, such as config_kde4.so, that are linked against old versions of Qt, and libproxy loads these plugins automatically when initialized. If Qt is not in a namespace, that loading causes a crash. Even if the systems on which you build and test have no such plugins, your users' systems may have them. We therefore recommend that you combine -libproxy with -qtnamespace when configuring Qt."
- CONDITION QT_FEATURE_libproxy AND INPUT_qt_namespace STREQUAL ''
-)
diff --git a/src/network/configure.json b/src/network/configure.json
deleted file mode 100644
index 9a09d3f2e1..0000000000
--- a/src/network/configure.json
+++ /dev/null
@@ -1,500 +0,0 @@
-{
- "module": "network",
- "depends": [
- "core"
- ],
- "testDir": "../../config.tests",
-
- "commandline": {
- "assignments": {
- "OPENSSL_PATH": "openssl.prefix"
- },
- "options": {
- "libproxy": "boolean",
- "openssl": { "type": "optionalString", "values": [ "no", "yes", "linked", "runtime" ] },
- "openssl-linked": { "type": "void", "name": "openssl", "value": "linked" },
- "openssl-runtime": { "type": "void", "name": "openssl", "value": "runtime" },
- "dtls": "boolean",
- "ocsp": "boolean",
- "sctp": "boolean",
- "securetransport": "boolean",
- "schannel": "boolean",
- "ssl": "boolean",
- "system-proxies": "boolean"
- }
- },
-
- "libraries": {
- "brotli": {
- "label": "Brotli Decompression",
- "test": {
- "main": [
- "BrotliDecoderState *state = BrotliDecoderCreateInstance(nullptr, nullptr, nullptr);"
- ]
- },
- "headers": [
- "brotli/decode.h"
- ],
- "sources": [
- { "type": "pkgConfig", "args": "libbrotlidec" },
- "-lbrotlidec"
- ]
- },
- "corewlan": {
- "label": "CoreWLan",
- "export": "",
- "test": {
- "lang": "objc++",
- "include": [ "CoreWLAN/CoreWLAN.h", "CoreWLAN/CWInterface.h" ],
- "main": "[CWInterface interfaceWithName:@\"en2\"];"
- },
- "sources": [
- "-framework CoreWLAN -framework Foundation"
- ]
- },
- "network": {
- "sources": [
- { "type": "makeSpec", "spec": "NETWORK" }
- ]
- },
- "libproxy": {
- "label": "libproxy",
- "test": {
- "main": [
- "pxProxyFactory *factory = px_proxy_factory_new();",
- "px_proxy_factory_get_proxies(factory, \"http://qt-project.org\");",
- "px_proxy_factory_free(factory);"
- ]
- },
- "headers": "proxy.h",
- "sources": [
- "-lproxy"
- ]
- },
- "openssl_headers": {
- "label": "OpenSSL Headers",
- "export": "openssl",
- "test": {
- "tail": [
- "#if !defined(OPENSSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER-0 < 0x10101000L",
- "# error OpenSSL >= 1.1.1 is required",
- "#endif",
- "#if !defined(OPENSSL_NO_EC) && !defined(SSL_CTRL_SET_CURVES)",
- "# error OpenSSL was reported as >= 1.1.1 but is missing required features, possibly it is libressl which is unsupported",
- "#endif"
- ]
- },
- "headers": [ "openssl/ssl.h", "openssl/opensslv.h" ],
- "sources": [
- {
- "comment": "placeholder for OPENSSL_PATH",
- "libs": ""
- }
- ]
- },
- "openssl": {
- "label": "OpenSSL",
- "test": {
- "inherit": "openssl_headers",
- "main": "SSL_free(SSL_new(0));"
- },
- "sources": [
- { "type": "openssl" },
- {
- "libs": "-lssleay32 -llibeay32 -lUser32 -lWs2_32 -lAdvapi32 -lGdi32",
- "condition": "config.win32"
- },
- {
- "libs": "-llibssl -llibcrypto -lUser32 -lWs2_32 -lAdvapi32 -lCrypt32",
- "condition": "config.msvc"
- },
- {
- "libs": "-lssl_arm64-v8a -lcrypto_arm64-v8a",
- "condition": "config.android"
- },
- {
- "libs": "-lssl -lcrypto",
- "condition": "!config.msvc"
- }
- ]
- },
- "gssapi": {
- "label": "KRB5 GSSAPI Support",
- "test": {
- "head": [
- "#if defined(__APPLE__) && (defined(__GNUC__) || defined(__xlC__) || defined(__xlc__))",
- "# include <TargetConditionals.h>",
- "# if defined(TARGET_OS_MAC) && TARGET_OS_MAC",
- "# include <GSS/GSS.h>",
- "# endif",
- "#else",
- "# include <gssapi/gssapi.h>",
- "#endif"
- ],
- "main": [
- "gss_ctx_id_t ctx;",
- "gss_context_time(nullptr, ctx, nullptr);"
- ]
- },
- "sources": [
- { "libs": "-framework GSS", "condition": "config.darwin" },
- { "type": "pkgConfig", "args": "krb5-gssapi" },
- "-lgssapi_krb5"
- ]
- }
- },
-
- "tests": {
- "getifaddrs": {
- "label": "getifaddrs()",
- "type": "compile",
- "test": {
- "include": [ "sys/types.h", "sys/socket.h", "net/if.h", "ifaddrs.h" ],
- "main": [
- "ifaddrs *list;",
- "getifaddrs(&list);",
- "freeifaddrs(list);"
- ]
- },
- "use": "network"
- },
- "ipv6ifname": {
- "label": "IPv6 ifname",
- "type": "compile",
- "test": {
- "include": [ "sys/types.h", "sys/socket.h", "net/if.h" ],
- "main": [
- "char buf[IFNAMSIZ];",
- "if_nametoindex(\"eth0\");",
- "if_indextoname(1, buf);",
- "if_freenameindex(if_nameindex());"
- ]
- },
- "use": "network"
- },
- "linux-netlink": {
- "label": "Linux AF_NETLINK sockets",
- "type": "compile",
- "test": {
- "include": [ "asm/types.h", "linux/netlink.h", "linux/rtnetlink.h", "sys/socket.h" ],
- "main": [
- "struct rtattr rta = { };",
- "struct ifinfomsg ifi = {};",
- "struct ifaddrmsg ifa = {};",
- "struct ifa_cacheinfo ci;",
- "ci.ifa_prefered = ci.ifa_valid = 0;",
- "(void)RTM_NEWLINK; (void)RTM_NEWADDR;",
- "(void)IFLA_ADDRESS; (void)IFLA_IFNAME;",
- "(void)IFA_ADDRESS; (void)IFA_LABEL; (void)IFA_CACHEINFO;",
- "(void)(IFA_F_SECONDARY | IFA_F_DEPRECATED | IFA_F_PERMANENT | IFA_F_MANAGETEMPADDR);"
- ]
- }
- },
- "sctp": {
- "label": "SCTP support",
- "type": "compile",
- "test": {
- "include": [ "sys/types.h", "sys/socket.h", "netinet/in.h", "netinet/sctp.h" ],
- "main": [
- "sctp_initmsg sctpInitMsg;",
- "socklen_t sctpInitMsgSize = sizeof(sctpInitMsg);",
- "(void) socket(PF_INET, SOCK_STREAM, IPPROTO_SCTP);",
- "(void) getsockopt(-1, SOL_SCTP, SCTP_INITMSG, &sctpInitMsg, &sctpInitMsgSize);"
- ]
- },
- "use": "network"
- },
- "dtls": {
- "label": "DTLS support in OpenSSL",
- "type": "compile",
- "test": {
- "include": "openssl/ssl.h",
- "tail": [
- "#if defined(OPENSSL_NO_DTLS) || !defined(DTLS1_2_VERSION)",
- "# error OpenSSL without DTLS support",
- "#endif"
- ]
- },
- "use": "openssl"
- },
- "ocsp": {
- "label": "OCSP stapling support in OpenSSL",
- "type": "compile",
- "test": {
- "include": ["openssl/ssl.h", "openssl/ocsp.h"],
- "tail": [
- "#if defined(OPENSSL_NO_OCSP) || defined(OPENSSL_NO_TLSEXT)",
- "# error OpenSSL without OCSP stapling",
- "#endif"
- ]
- },
- "use": "openssl"
- },
- "netlistmgr": {
- "label": "Network List Manager",
- "type": "compile",
- "test": {
- "include": [ "netlistmgr.h", "wrl/client.h" ],
- "main": [
- "using namespace Microsoft::WRL;",
- "ComPtr<INetworkListManager> networkListManager;",
- "ComPtr<IConnectionPoint> connectionPoint;",
- "ComPtr<IConnectionPointContainer> connectionPointContainer;",
- "networkListManager.As(&connectionPointContainer);",
- "connectionPointContainer->FindConnectionPoint(IID_INetworkConnectionEvents, &connectionPoint);"
- ],
- "qmake": "LIBS += -lOle32"
- }
- }
- },
-
- "features": {
- "corewlan": {
- "label": "CoreWLan",
- "condition": "libs.corewlan",
- "emitIf": "config.darwin",
- "output": [ "feature", "privateFeature" ]
- },
- "getifaddrs": {
- "label": "getifaddrs()",
- "condition": "tests.getifaddrs",
- "output": [ "feature" ]
- },
- "ipv6ifname": {
- "label": "IPv6 ifname",
- "condition": "tests.ipv6ifname",
- "output": [ "feature" ]
- },
- "libproxy": {
- "label": "libproxy",
- "autoDetect": false,
- "condition": "libs.libproxy",
- "output": [ "privateFeature" ]
- },
- "linux-netlink": {
- "label": "Linux AF_NETLINK",
- "condition": "config.linux && !config.android && tests.linux-netlink",
- "output": [ "privateFeature" ]
- },
- "openssl": {
- "label": "OpenSSL",
- "enable": "false",
- "condition": "features.openssl-runtime || features.openssl-linked",
- "output": [
- "privateFeature",
- { "type": "publicQtConfig", "condition": "!features.openssl-linked" },
- { "type": "define", "negative": true, "name": "QT_NO_OPENSSL" }
- ]
- },
- "openssl-runtime": {
- "autoDetect": "!config.wasm",
- "enable": "input.openssl == 'yes' || input.openssl == 'runtime'",
- "disable": "input.openssl == 'no' || input.openssl == 'linked' || input.ssl == 'no'",
- "condition": "!features.securetransport && !features.schannel && libs.openssl_headers"
- },
- "openssl-linked": {
- "label": " Qt directly linked to OpenSSL",
- "autoDetect": false,
- "enable": "input.openssl == 'linked'",
- "condition": "!features.securetransport && !features.schannel && libs.openssl",
- "output": [
- "privateFeature",
- { "type": "define", "name": "QT_LINKED_OPENSSL" }
- ]
- },
- "securetransport": {
- "label": "SecureTransport",
- "disable": "input.securetransport == 'no' || input.ssl == 'no'",
- "condition": "config.darwin && (input.openssl == '' || input.openssl == 'no')",
- "output": [
- "publicFeature",
- { "type": "define", "name": "QT_SECURETRANSPORT" }
- ]
- },
- "schannel": {
- "label": "Schannel",
- "disable": "input.schannel == 'no' || input.ssl == 'no'",
- "condition": "input.schannel == 'yes' && config.win32 && (input.openssl == '' || input.openssl == 'no')",
- "output": [
- "publicFeature",
- { "type": "define", "name": "QT_SCHANNEL" }
- ]
- },
- "ssl": {
- "label": "SSL",
- "condition": "features.securetransport || features.openssl || features.schannel",
- "output": [ "publicFeature", "feature" ]
- },
- "dtls": {
- "label": "DTLS",
- "purpose": "Provides a DTLS implementation",
- "section": "Networking",
- "condition": "features.openssl && features.udpsocket && tests.dtls",
- "output": [ "publicFeature" ]
- },
- "ocsp": {
- "label": "OCSP-stapling",
- "purpose": "Provides OCSP stapling support",
- "section": "Networking",
- "condition": "features.opensslv11 && tests.ocsp",
- "output": [ "publicFeature" ]
- },
- "opensslv11": {
- "label": "OpenSSL 1.1",
- "condition": "features.openssl",
- "output": [ "publicFeature" ]
- },
- "sctp": {
- "label": "SCTP",
- "autoDetect": false,
- "condition": "tests.sctp",
- "output": [ "publicFeature", "feature" ]
- },
- "system-proxies": {
- "label": "Use system proxies",
- "output": [ "privateFeature" ]
- },
- "http": {
- "label": "HTTP",
- "purpose": "Provides support for the Hypertext Transfer Protocol in QNetworkAccessManager.",
- "section": "Networking",
- "condition": "features.thread",
- "output": [ "publicFeature", "feature" ]
- },
- "udpsocket": {
- "label": "QUdpSocket",
- "purpose": "Provides access to UDP sockets.",
- "section": "Networking",
- "output": [ "publicFeature", "feature" ]
- },
- "networkproxy": {
- "label": "QNetworkProxy",
- "purpose": "Provides network proxy support.",
- "section": "Networking",
- "output": [ "publicFeature", "feature" ]
- },
- "socks5": {
- "label": "SOCKS5",
- "purpose": "Provides SOCKS5 support in QNetworkProxy.",
- "section": "Networking",
- "condition": "features.networkproxy",
- "output": [ "publicFeature", "feature" ]
- },
- "networkinterface": {
- "label": "QNetworkInterface",
- "purpose": "Supports enumerating a host's IP addresses and network interfaces.",
- "condition": "!config.wasm",
- "section": "Networking",
- "output": [ "publicFeature", "feature" ]
- },
- "networkdiskcache": {
- "label": "QNetworkDiskCache",
- "purpose": "Provides a disk cache for network resources.",
- "section": "Networking",
- "condition": "features.temporaryfile",
- "output": [ "publicFeature", "feature" ]
- },
- "brotli": {
- "label": "Brotli Decompression Support",
- "purpose": "Support for downloading and decompressing resources compressed with Brotli through QNetworkAccessManager.",
- "section": "Networking",
- "condition": "libs.brotli",
- "output": [ "publicFeature", "feature" ]
- },
- "localserver": {
- "label": "QLocalServer",
- "purpose": "Provides a local socket based server.",
- "section": "Networking",
- "condition": "features.temporaryfile",
- "output": [ "publicFeature", "feature" ]
- },
- "dnslookup": {
- "label": "QDnsLookup",
- "purpose": "Provides API for DNS lookups.",
- "section": "Networking",
- "output": [ "publicFeature" ]
- },
- "gssapi": {
- "label": "GSSAPI",
- "purpose": "Enable SPNEGO authentication through GSSAPI",
- "section": "Networking",
- "condition": "!config.win32 && libs.gssapi",
- "output": [ "publicFeature", "feature" ]
- },
- "sspi": {
- "label": "SSPI",
- "purpose": "Enable NTLM/SPNEGO authentication through SSPI",
- "section": "Networking",
- "condition": "config.win32",
- "output": [ "publicFeature", "feature" ]
- },
- "netlistmgr": {
- "label": "Network List Manager",
- "purpose": "Use Network List Manager to keep track of network connectivity",
- "section": "Networking",
- "condition": "config.win32 && tests.netlistmgr",
- "output": [ "privateFeature" ]
- },
- "topleveldomain": {
- "label": "qTopLevelDomain()",
- "purpose": "Provides support for extracting the top level domain from URLs. If enabled, a binary dump of the Public Suffix List (http://www.publicsuffix.org, Mozilla License) is included. The data is then also used in QNetworkCookieJar::validateCookie.",
- "section": "Networking",
- "output": [ "publicFeature" ]
- }
- },
-
- "report": [
- {
- "type": "note",
- "condition": "!config.android && features.openssl-linked && libs.openssl.source != 0
- && input.openssl.prefix == '' && input.openssl.libs == '' && input.openssl.libs.debug == ''",
- "message": "When linking against OpenSSL, you can override the default
-library names through OPENSSL_LIBS.
-For example:
- OPENSSL_LIBS='-L/opt/ssl/lib -lssl -lcrypto' ./configure -openssl-linked"
- },
- {
- "type": "warning",
- "condition": "features.libproxy && input.qt_namespace == ''",
- "message": "Some of libproxy's plugins may use incompatible Qt versions. Some platforms and distributions ship libproxy with plugins, such as config_kde4.so, that are linked against old versions of Qt; and libproxy loads these plugins automatically when initialized. If Qt is not in a namespace, that loading causes a crash. Even if the systems on which you build and test have no such plugins, your users' systems may have them. We therefore recommend that you combine -libproxy with -qtnamespace when configuring Qt."
- }
- ],
-
- "summary": [
- {
- "section": "Qt Network",
- "entries": [
- {
- "type": "feature",
- "args": "corewlan",
- "condition": "config.darwin"
- },
- "getifaddrs", "ipv6ifname", "libproxy",
- {
- "type": "feature",
- "args": "linux-netlink",
- "condition": "config.linux"
- },
- {
- "type": "feature",
- "args": "securetransport",
- "condition": "config.darwin"
- },
- {
- "type": "feature",
- "args": "schannel",
- "condition": "config.win32"
- },
- "openssl",
- "openssl-linked",
- "opensslv11",
- "dtls",
- "ocsp",
- "sctp",
- "system-proxies",
- "gssapi",
- "brotli"
- ]
- }
- ]
-}
diff --git a/src/network/configure.pri b/src/network/configure.pri
deleted file mode 100644
index ad4d711cba..0000000000
--- a/src/network/configure.pri
+++ /dev/null
@@ -1,13 +0,0 @@
-# custom tests
-
-defineTest(qtConfLibrary_openssl) {
- eval(libs = $$getenv("OPENSSL_LIBS"))
- !isEmpty(libs) {
- !qtConfResolveLibs($${1}.libs, $$libs): \
- return(false)
- return(true)
- }
- qtLog("$OPENSSL_LIBS is not set.")
- return(false)
-}
-
diff --git a/src/network/doc/images/network-examples.png b/src/network/doc/images/network-examples.png
deleted file mode 100644
index 15dfba850a..0000000000
--- a/src/network/doc/images/network-examples.png
+++ /dev/null
Binary files differ
diff --git a/src/network/doc/images/network-examples.webp b/src/network/doc/images/network-examples.webp
new file mode 100644
index 0000000000..4f6269ec8b
--- /dev/null
+++ b/src/network/doc/images/network-examples.webp
Binary files differ
diff --git a/src/network/doc/qtnetwork.qdocconf b/src/network/doc/qtnetwork.qdocconf
index 8c7f3fc912..1e1162bdac 100644
--- a/src/network/doc/qtnetwork.qdocconf
+++ b/src/network/doc/qtnetwork.qdocconf
@@ -15,10 +15,6 @@ qhp.QtNetwork.virtualFolder = qtnetwork
qhp.QtNetwork.indexTitle = Qt Network
qhp.QtNetwork.indexRoot =
-qhp.QtNetwork.filterAttributes = qtnetwork $QT_VERSION qtrefdoc
-qhp.QtNetwork.customFilters.Qt.name = QtNetwork $QT_VERSION
-qhp.QtNetwork.customFilters.Qt.filterAttributes = qtnetwork $QT_VERSION
-
qhp.QtNetwork.subprojects = classes
qhp.QtNetwork.subprojects.classes.title = C++ Classes
qhp.QtNetwork.subprojects.classes.indexTitle = Qt Network C++ Classes
@@ -27,7 +23,7 @@ qhp.QtNetwork.subprojects.classes.sortPages = true
tagfile = ../../../doc/qtnetwork/qtnetwork.tags
-depends += qtcore qtgui qtdoc qmake qtcmake
+depends += qtcore qtgui qtdoc qmake qtcmake qtwidgets
headerdirs += ..
@@ -41,7 +37,15 @@ exampledirs += ../../../examples/network \
imagedirs += images \
../../../examples/network/doc/images
-manifestmeta.highlighted.names = "QtNetwork/HTTP Example"
-
navigation.landingpage = "Qt Network"
navigation.cppclassespage = "Qt Network C++ Classes"
+
+manifestmeta.highlighted.names = \
+ "QtNetwork/Fortune Client" \
+ "QtNetwork/Fortune Server" \
+ "QtNetwork/HTTP Client" \
+ "QtNetwork/Secure Socket Client" \
+ "QtNetwork/Torrent Example"
+
+# Enforce zero documentation warnings
+warninglimit = 0
diff --git a/src/network/doc/snippets/CMakeLists.txt b/src/network/doc/snippets/CMakeLists.txt
index 0921774224..05e5668e24 100644
--- a/src/network/doc/snippets/CMakeLists.txt
+++ b/src/network/doc/snippets/CMakeLists.txt
@@ -1,4 +1,7 @@
-cmake_minimum_required(VERSION 3.1.0)
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
project(network_cppsnippets)
@@ -7,6 +10,6 @@ add_executable(mytarget
)
# ![0]
-find_package(Qt6 COMPONENTS Network REQUIRED)
-target_link_libraries(mytarget Qt::Network)
+find_package(Qt6 REQUIRED COMPONENTS Network)
+target_link_libraries(mytarget PRIVATE Qt6::Network)
# ![0]
diff --git a/src/network/doc/snippets/code/doc_src_qtnetwork.cpp b/src/network/doc/snippets/code/doc_src_qtnetwork.cpp
deleted file mode 100644
index a74a1fce41..0000000000
--- a/src/network/doc/snippets/code/doc_src_qtnetwork.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** 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.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//! [1]
-#include <QtNetwork>
-//! [1]
diff --git a/src/network/doc/snippets/code/src_network_access_qhttpmultipart.cpp b/src/network/doc/snippets/code/src_network_access_qhttpmultipart.cpp
index 4166adef23..73308b5547 100644
--- a/src/network/doc/snippets/code/src_network_access_qhttpmultipart.cpp
+++ b/src/network/doc/snippets/code/src_network_access_qhttpmultipart.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [0]
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
diff --git a/src/network/doc/snippets/code/src_network_access_qhttppart.cpp b/src/network/doc/snippets/code/src_network_access_qhttppart.cpp
index e2a280fe22..059a4c60e9 100644
--- a/src/network/doc/snippets/code/src_network_access_qhttppart.cpp
+++ b/src/network/doc/snippets/code/src_network_access_qhttppart.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [0]
Content-Type: text/plain
diff --git a/src/network/doc/snippets/code/src_network_access_qnetworkaccessmanager.cpp b/src/network/doc/snippets/code/src_network_access_qnetworkaccessmanager.cpp
index a4e5230b2d..14eed532cb 100644
--- a/src/network/doc/snippets/code/src_network_access_qnetworkaccessmanager.cpp
+++ b/src/network/doc/snippets/code/src_network_access_qnetworkaccessmanager.cpp
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** 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.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [0]
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
diff --git a/src/network/doc/snippets/code/src_network_access_qnetworkdiskcache.cpp b/src/network/doc/snippets/code/src_network_access_qnetworkdiskcache.cpp
index f5791abd41..1087f52035 100644
--- a/src/network/doc/snippets/code/src_network_access_qnetworkdiskcache.cpp
+++ b/src/network/doc/snippets/code/src_network_access_qnetworkdiskcache.cpp
@@ -1,67 +1,23 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** 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.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [0]
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
QNetworkDiskCache *diskCache = new QNetworkDiskCache(this);
-diskCache->setCacheDirectory("cacheDir");
+QString directory = QStandardPaths::writableLocation(QStandardPaths::CacheLocation)
+ + QLatin1StringView("/cacheDir/");
+diskCache->setCacheDirectory(directory);
manager->setCache(diskCache);
//! [0]
//! [1]
+using namespace Qt::StringLiterals;
// do a normal request (preferred from network, as this is the default)
-QNetworkRequest request(QUrl(QString("http://qt-project.org")));
+QNetworkRequest request(QUrl(u"http://qt-project.org"_s));
manager->get(request);
// do a request preferred from cache
-QNetworkRequest request2(QUrl(QString("http://qt-project.org")));
+QNetworkRequest request2(QUrl(u"http://qt-project.org"_s));
request2.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache);
manager->get(request2);
//! [1]
diff --git a/src/network/doc/snippets/code/src_network_access_qnetworkreply.cpp b/src/network/doc/snippets/code/src_network_access_qnetworkreply.cpp
index 3ac98302b6..4915b18f1e 100644
--- a/src/network/doc/snippets/code/src_network_access_qnetworkreply.cpp
+++ b/src/network/doc/snippets/code/src_network_access_qnetworkreply.cpp
@@ -1,55 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** 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.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+using namespace Qt::StringLiterals;
//! [0]
-QList<QSslCertificate> cert = QSslCertificate::fromPath(QLatin1String("server-certificate.pem"));
+QList<QSslCertificate> cert = QSslCertificate::fromPath("server-certificate.pem"_L1);
QSslError error(QSslError::SelfSignedCertificate, cert.at(0));
QList<QSslError> expectedSslErrors;
expectedSslErrors.append(error);
diff --git a/src/network/doc/snippets/code/src_network_access_qnetworkrequest.cpp b/src/network/doc/snippets/code/src_network_access_qnetworkrequest.cpp
index 7b3efa812e..045e65dc05 100644
--- a/src/network/doc/snippets/code/src_network_access_qnetworkrequest.cpp
+++ b/src/network/doc/snippets/code/src_network_access_qnetworkrequest.cpp
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** 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.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [0]
request.setRawHeader(QByteArray("Last-Modified"), QByteArray("Sun, 06 Nov 1994 08:49:37 GMT"));
diff --git a/src/network/doc/snippets/code/src_network_access_qnetworkrequestfactory.cpp b/src/network/doc/snippets/code/src_network_access_qnetworkrequestfactory.cpp
new file mode 100644
index 0000000000..f7994d442c
--- /dev/null
+++ b/src/network/doc/snippets/code/src_network_access_qnetworkrequestfactory.cpp
@@ -0,0 +1,27 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+using namespace Qt::StringLiterals;
+
+//! [0]
+// Instantiate a factory somewhere suitable in the application
+QNetworkRequestFactory api{{"https://example.com/v1"_L1}};
+
+// Set bearer token
+api.setBearerToken("my_token");
+
+// Issue requests (reply handling omitted for brevity)
+manager.get(api.createRequest("models"_L1)); // https://example.com/v1/models
+// The conventional leading '/' for the path can be used as well
+manager.get(api.createRequest("/models"_L1)); // https://example.com/v1/models
+//! [0]
+
+
+//! [1]
+// Here the API version v2 is used as the base path:
+QNetworkRequestFactory api{{"https://example.com/v2"_L1}};
+// ...
+manager.get(api.createRequest("models"_L1)); // https://example.com/v2/models
+// Equivalent with a leading '/'
+manager.get(api.createRequest("/models"_L1)); // https://example.com/v2/models
+//! [1]
+
diff --git a/src/network/doc/snippets/code/src_network_access_qrestaccessmanager.cpp b/src/network/doc/snippets/code/src_network_access_qrestaccessmanager.cpp
new file mode 100644
index 0000000000..8f9e00f4b6
--- /dev/null
+++ b/src/network/doc/snippets/code/src_network_access_qrestaccessmanager.cpp
@@ -0,0 +1,104 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+//! [0]
+QNetworkReply *reply = manager->get(request);
+QObject::connect(reply, &QNetworkReply::finished, this, [reply]() {
+ // The reply may be wrapped in the finish handler:
+ QRestReply restReply(reply);
+ if (restReply.isSuccess())
+ // ...
+});
+//! [0]
+
+
+//! [1]
+// With lambda
+manager->get(request, this, [this](QRestReply &reply) {
+ if (reply.isSuccess()) {
+ // ...
+ }
+});
+// With member function
+manager->get(request, this, &MyClass::handleFinished);
+//! [1]
+
+
+//! [2]
+QJsonDocument myJson;
+// ...
+manager->post(request, myJson, this, [this](QRestReply &reply) {
+ if (!reply.isSuccess()) {
+ // ...
+ }
+ if (std::optional json = reply.readJson()) {
+ // use *json
+ }
+});
+//! [2]
+
+
+//! [3]
+manager->get(request, this, [this](QRestReply &reply) {
+ if (!reply.isSuccess())
+ // handle error
+ if (std::optional json = reply.readJson())
+ // use *json
+});
+//! [3]
+
+
+//! [4]
+manager->get(request, myData, this, [this](QRestReply &reply) {
+ if (reply.isSuccess())
+ // ...
+});
+//! [4]
+
+
+//! [5]
+manager->post(request, myData, this, [this](QRestReply &reply) {
+ if (reply.isSuccess())
+ // ...
+});
+//! [5]
+
+
+//! [6]
+manager->put(request, myData, this, [this](QRestReply &reply) {
+ if (reply.isSuccess())
+ // ...
+});
+//! [6]
+
+
+//! [7]
+manager->head(request, this, [this](QRestReply &reply) {
+ if (reply.isSuccess())
+ // ...
+});
+//! [7]
+
+
+//! [8]
+manager->deleteResource(request, this, [this](QRestReply &reply) {
+ if (reply.isSuccess())
+ // ...
+});
+//! [8]
+
+
+//! [9]
+manager->sendCustomRequest(request, "MYMETHOD", myData, this, [this](QRestReply &reply) {
+ if (reply.isSuccess())
+ // ...
+});
+//! [9]
+
+
+//! [10]
+manager->patch(request, myData, this, [this](QRestReply &reply) {
+ if (reply.isSuccess())
+ // ...
+});
+//! [10]
diff --git a/src/network/doc/snippets/code/src_network_kernel_qdnslookup.cpp b/src/network/doc/snippets/code/src_network_kernel_qdnslookup.cpp
index 76a0d61427..ce976001bb 100644
--- a/src/network/doc/snippets/code/src_network_kernel_qdnslookup.cpp
+++ b/src/network/doc/snippets/code/src_network_kernel_qdnslookup.cpp
@@ -1,60 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Jeremy Lainé <jeremy.laine@m4x.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** 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.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Jeremy Lainé <jeremy.laine@m4x.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [0]
void MyObject::lookupServers()
{
// Create a DNS lookup.
dns = new QDnsLookup(this);
- connect(dns, SIGNAL(finished()),
- this, SLOT(handleServers()));
+ connect(dns, &QDnsLookup::finished, this, &MyObject::handleServers);
// Find the XMPP servers for gmail.com
dns->setType(QDnsLookup::SRV);
diff --git a/src/network/doc/snippets/code/src_network_kernel_qhostaddress.cpp b/src/network/doc/snippets/code/src_network_kernel_qhostaddress.cpp
index 60e2a8125d..1497fbd734 100644
--- a/src/network/doc/snippets/code/src_network_kernel_qhostaddress.cpp
+++ b/src/network/doc/snippets/code/src_network_kernel_qhostaddress.cpp
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** 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.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [0]
Q_IPV6ADDR addr = hostAddr.toIPv6Address();
diff --git a/src/network/doc/snippets/code/src_network_kernel_qhostinfo.cpp b/src/network/doc/snippets/code/src_network_kernel_qhostinfo.cpp
index b7939bb1c0..7c39827b94 100644
--- a/src/network/doc/snippets/code/src_network_kernel_qhostinfo.cpp
+++ b/src/network/doc/snippets/code/src_network_kernel_qhostinfo.cpp
@@ -1,61 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** 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.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [0]
// To find the IP address of qt-project.org
-QHostInfo::lookupHost("qt-project.org",
- this, SLOT(printResults(QHostInfo)));
+QHostInfo::lookupHost("qt-project.org", this, &MyWidget::printResults);
// To find the host name for 4.2.2.1
-QHostInfo::lookupHost("4.2.2.1",
- this, SLOT(printResults(QHostInfo)));
+QHostInfo::lookupHost("4.2.2.1", this, &MyWidget::printResults);
//! [0]
@@ -65,8 +16,7 @@ QHostInfo info = QHostInfo::fromName("qt-project.org");
//! [2]
-QHostInfo::lookupHost("www.kde.org",
- this, SLOT(lookedUp(QHostInfo)));
+QHostInfo::lookupHost("www.kde.org", this, &MyWidget::lookedUp);
//! [2]
@@ -86,8 +36,7 @@ void MyWidget::lookedUp(const QHostInfo &host)
//! [4]
-QHostInfo::lookupHost("4.2.2.1",
- this, SLOT(lookedUp(QHostInfo)));
+QHostInfo::lookupHost("4.2.2.1", this, &MyWidget::lookedUp);
//! [4]
diff --git a/src/network/doc/snippets/code/src_network_kernel_qnetworkdatagram.cpp b/src/network/doc/snippets/code/src_network_kernel_qnetworkdatagram.cpp
index f81ca97681..c0db73340d 100644
--- a/src/network/doc/snippets/code/src_network_kernel_qnetworkdatagram.cpp
+++ b/src/network/doc/snippets/code/src_network_kernel_qnetworkdatagram.cpp
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** 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.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [0]
void Server::readPendingDatagrams()
diff --git a/src/network/doc/snippets/code/src_network_kernel_qnetworkinterface.cpp b/src/network/doc/snippets/code/src_network_kernel_qnetworkinterface.cpp
index fc7fd7814a..d34750aaaf 100644
--- a/src/network/doc/snippets/code/src_network_kernel_qnetworkinterface.cpp
+++ b/src/network/doc/snippets/code/src_network_kernel_qnetworkinterface.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [0]
QNetworkInterface::interfaceFromName(name).index()
diff --git a/src/network/doc/snippets/code/src_network_kernel_qnetworkproxy.cpp b/src/network/doc/snippets/code/src_network_kernel_qnetworkproxy.cpp
index dd51fb1e5f..8e3e42f9ac 100644
--- a/src/network/doc/snippets/code/src_network_kernel_qnetworkproxy.cpp
+++ b/src/network/doc/snippets/code/src_network_kernel_qnetworkproxy.cpp
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** 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.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [0]
QNetworkProxy proxy;
diff --git a/src/network/doc/snippets/code/src_network_socket_qabstractsocket.cpp b/src/network/doc/snippets/code/src_network_socket_qabstractsocket.cpp
index e03d8ca7be..2a568ff69f 100644
--- a/src/network/doc/snippets/code/src_network_socket_qabstractsocket.cpp
+++ b/src/network/doc/snippets/code/src_network_socket_qabstractsocket.cpp
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** 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.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [0]
socket->connectToHost("imap", 143);
diff --git a/src/network/doc/snippets/code/src_network_socket_qlocalsocket_unix.cpp b/src/network/doc/snippets/code/src_network_socket_qlocalsocket_unix.cpp
index deafca831d..e6459a02d2 100644
--- a/src/network/doc/snippets/code/src_network_socket_qlocalsocket_unix.cpp
+++ b/src/network/doc/snippets/code/src_network_socket_qlocalsocket_unix.cpp
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** 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.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [0]
socket->connectToServer("market");
diff --git a/src/network/doc/snippets/code/src_network_socket_qnativesocketengine.cpp b/src/network/doc/snippets/code/src_network_socket_qnativesocketengine.cpp
index 8f7ff3bee4..4817ace4b1 100644
--- a/src/network/doc/snippets/code/src_network_socket_qnativesocketengine.cpp
+++ b/src/network/doc/snippets/code/src_network_socket_qnativesocketengine.cpp
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** 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.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [0]
QNativeSocketEngine socketLayer;
diff --git a/src/network/doc/snippets/code/src_network_socket_qsctpsocket.cpp b/src/network/doc/snippets/code/src_network_socket_qsctpsocket.cpp
index ac181f950c..8ab04c3acd 100644
--- a/src/network/doc/snippets/code/src_network_socket_qsctpsocket.cpp
+++ b/src/network/doc/snippets/code/src_network_socket_qsctpsocket.cpp
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** 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.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [0]
QSctpSocket *socket = new QSctpSocket(this);
diff --git a/src/network/doc/snippets/code/src_network_socket_qtcpserver.cpp b/src/network/doc/snippets/code/src_network_socket_qtcpserver.cpp
index a19c44c986..8c28cabf94 100644
--- a/src/network/doc/snippets/code/src_network_socket_qtcpserver.cpp
+++ b/src/network/doc/snippets/code/src_network_socket_qtcpserver.cpp
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** 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.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [0]
server->setProxy(QNetworkProxy::NoProxy);
diff --git a/src/network/doc/snippets/code/src_network_socket_qudpsocket.cpp b/src/network/doc/snippets/code/src_network_socket_qudpsocket.cpp
index f6a28ce46c..4666e28536 100644
--- a/src/network/doc/snippets/code/src_network_socket_qudpsocket.cpp
+++ b/src/network/doc/snippets/code/src_network_socket_qudpsocket.cpp
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** 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.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [0]
void Server::initSocket()
diff --git a/src/network/doc/snippets/code/src_network_ssl_qdtls.cpp b/src/network/doc/snippets/code/src_network_ssl_qdtls.cpp
index 2132b48338..cfdebec463 100644
--- a/src/network/doc/snippets/code/src_network_ssl_qdtls.cpp
+++ b/src/network/doc/snippets/code/src_network_ssl_qdtls.cpp
@@ -1,53 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** 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.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+using namespace Qt::StringLiterals;
//! [0]
// A client initiates a handshake:
QUdpSocket clientSocket;
@@ -126,7 +80,7 @@ if (!dtls.doHandshake(&socket, dgram)) {
//! [5]
//! [6]
-QList<QSslCertificate> cert = QSslCertificate::fromPath(QLatin1String("server-certificate.pem"));
+QList<QSslCertificate> cert = QSslCertificate::fromPath("server-certificate.pem"_L1);
QSslError error(QSslError::SelfSignedCertificate, cert.at(0));
QList<QSslError> expectedSslErrors;
expectedSslErrors.append(error);
diff --git a/src/network/doc/snippets/code/src_network_ssl_qdtlscookie.cpp b/src/network/doc/snippets/code/src_network_ssl_qdtlscookie.cpp
index a9e596eca5..3cf7baf390 100644
--- a/src/network/doc/snippets/code/src_network_ssl_qdtlscookie.cpp
+++ b/src/network/doc/snippets/code/src_network_ssl_qdtlscookie.cpp
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** 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.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [0]
class DtlsServer : public QObject
diff --git a/src/network/doc/snippets/code/src_network_ssl_qsslcertificate.cpp b/src/network/doc/snippets/code/src_network_ssl_qsslcertificate.cpp
index 62502afe61..e80f014b4e 100644
--- a/src/network/doc/snippets/code/src_network_ssl_qsslcertificate.cpp
+++ b/src/network/doc/snippets/code/src_network_ssl_qsslcertificate.cpp
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** 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.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [1]
const auto certs = QSslCertificate::fromPath("C:/ssl/certificate.*.pem",
diff --git a/src/network/doc/snippets/code/src_network_ssl_qsslconfiguration.cpp b/src/network/doc/snippets/code/src_network_ssl_qsslconfiguration.cpp
index b857a57a63..d9a493d1ce 100644
--- a/src/network/doc/snippets/code/src_network_ssl_qsslconfiguration.cpp
+++ b/src/network/doc/snippets/code/src_network_ssl_qsslconfiguration.cpp
@@ -1,62 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** 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.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [0]
QSslConfiguration config = sslSocket.sslConfiguration();
-config.setProtocol(QSsl::TlsV1_0);
+config.setProtocol(QSsl::TlsV1_2);
sslSocket.setSslConfiguration(config);
//! [0]
-
-
-//! [1]
-QSslConfiguration tlsConfig = QSslConfiguration::defaultConfiguration();
-tlsConfig.setCiphers(QStringLiteral("DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA:AES256-SHA"));
-//! [1]
-
diff --git a/src/network/doc/snippets/code/src_network_ssl_qsslpresharedkeyauthenticator.cpp b/src/network/doc/snippets/code/src_network_ssl_qsslpresharedkeyauthenticator.cpp
index 22e60840a3..b3242e057d 100644
--- a/src/network/doc/snippets/code/src_network_ssl_qsslpresharedkeyauthenticator.cpp
+++ b/src/network/doc/snippets/code/src_network_ssl_qsslpresharedkeyauthenticator.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [0]
connect(socket, &QSslSocket::preSharedKeyAuthenticationRequired,
diff --git a/src/network/doc/snippets/code/src_network_ssl_qsslsocket.cpp b/src/network/doc/snippets/code/src_network_ssl_qsslsocket.cpp
index c1b3ceaf69..eed032589e 100644
--- a/src/network/doc/snippets/code/src_network_ssl_qsslsocket.cpp
+++ b/src/network/doc/snippets/code/src_network_ssl_qsslsocket.cpp
@@ -1,56 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** 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.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+using namespace Qt::StringLiterals;
//! [0]
QSslSocket *socket = new QSslSocket(this);
-connect(socket, SIGNAL(encrypted()), this, SLOT(ready()));
+connect(socket, &QSslSocket::encrypted, this, &Receiver::ready);
socket->connectToHostEncrypted("imap.example.com", 993);
//! [0]
@@ -87,19 +42,13 @@ while (socket.waitForReadyRead())
//! [3]
QSslSocket socket;
-connect(&socket, SIGNAL(encrypted()), receiver, SLOT(socketEncrypted()));
+connect(&socket, &QSslSocket::encrypted, receiver, &Receiver::socketEncrypted);
socket.connectToHostEncrypted("imap", 993);
socket->write("1 CAPABILITY\r\n");
//! [3]
-//! [4]
-QSslSocket socket;
-socket.setCiphers("DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA:AES256-SHA");
-//! [4]
-
-
//! [5]
socket->connectToHostEncrypted("imap", 993);
if (socket->waitForEncrypted(1000))
@@ -107,7 +56,7 @@ if (socket->waitForEncrypted(1000))
//! [5]
//! [6]
-QList<QSslCertificate> cert = QSslCertificate::fromPath(QLatin1String("server-certificate.pem"));
+QList<QSslCertificate> cert = QSslCertificate::fromPath("server-certificate.pem"_L1);
QSslError error(QSslError::SelfSignedCertificate, cert.at(0));
QList<QSslError> expectedSslErrors;
expectedSslErrors.append(error);
diff --git a/src/network/doc/snippets/network/CMakeLists.txt b/src/network/doc/snippets/network/CMakeLists.txt
new file mode 100644
index 0000000000..b75aeafea0
--- /dev/null
+++ b/src/network/doc/snippets/network/CMakeLists.txt
@@ -0,0 +1,8 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+add_library(network_cppsnippets OBJECT tcpwait.cpp)
+
+target_link_libraries(network_cppsnippets PRIVATE
+ Qt::Network
+)
diff --git a/src/network/doc/snippets/network/network.pro b/src/network/doc/snippets/network/network.pro
index 7d3d2415ff..a100943e58 100644
--- a/src/network/doc/snippets/network/network.pro
+++ b/src/network/doc/snippets/network/network.pro
@@ -1,6 +1,3 @@
-TEMPLATE = lib
-TARGET = network_snippet
-QT = core network
-
-SOURCES = \
- tcpwait.cpp
+#! [0]
+QT += network
+#! [0]
diff --git a/src/network/doc/snippets/network/tcpwait.cpp b/src/network/doc/snippets/network/tcpwait.cpp
index b81c5c1d53..b3afa84a8a 100644
--- a/src/network/doc/snippets/network/tcpwait.cpp
+++ b/src/network/doc/snippets/network/tcpwait.cpp
@@ -1,60 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** 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.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-#include <QCoreApplication>
#include <QTcpSocket>
-int main(int argv, char **args)
+int test_tcpwait()
{
- QCoreApplication app(argv, args);
-
QTcpSocket socket;
socket.connectToHost("localhost", 1025);
@@ -72,6 +22,5 @@ int main(int argv, char **args)
break;
}
//! [0]
-
- return app.exec();
+ return numReadTotal;
}
diff --git a/src/network/doc/snippets/snippets.pro b/src/network/doc/snippets/snippets.pro
deleted file mode 100644
index 745511da7b..0000000000
--- a/src/network/doc/snippets/snippets.pro
+++ /dev/null
@@ -1,9 +0,0 @@
-TEMPLATE = subdirs
-TARGET = network_cppsnippets
-SUBDIRS =
-
-contains(QT_BUILD_PARTS, tests) {
- SUBDIRS += \
- network
-}
-
diff --git a/src/network/doc/src/dontdocument.qdoc b/src/network/doc/src/dontdocument.qdoc
index fe2e54b34c..eb0f8eb07e 100644
--- a/src/network/doc/src/dontdocument.qdoc
+++ b/src/network/doc/src/dontdocument.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\dontdocument (QTypeInfo QMetaTypeId QIPv6Address)
diff --git a/src/network/doc/src/examples.qdoc b/src/network/doc/src/examples.qdoc
index 8dc598daff..ee9084c74c 100644
--- a/src/network/doc/src/examples.qdoc
+++ b/src/network/doc/src/examples.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\group examples-network
@@ -31,7 +7,7 @@
\title Network Examples
\brief How to do network programming in Qt.
- \image network-examples.png
+ \image network-examples.webp
Qt is provided with an extensive set of network classes to support both
client-based and server side network programming.
@@ -46,18 +22,12 @@
\li \l{network/blockingfortuneclient}{Blocking Fortune Client}\raisedaster
\li \l{network/broadcastreceiver}{Broadcast Receiver}
\li \l{network/broadcastsender}{Broadcast Sender}
- \li \l{network/download}{Download}
- \li \l{network/downloadmanager}{Download Manager}
\li \l{network/network-chat}{Network Chat}
\li \l{network/fortuneclient}{Fortune Client}\raisedaster
\li \l{network/fortuneserver}{Fortune Server}\raisedaster
\li \l{network/http}{HTTP}
- \li \l{network/loopback}{Loopback}
\li \l{network/threadedfortuneserver}{Threaded Fortune Server}\raisedaster
\li \l{network/torrent}{Torrent}
- \li \l{network/googlesuggest}{Google Suggest}
- \li \l{network/bearercloud}{Bearer Cloud}\raisedaster
- \li \l{network/bearermonitor}{Bearer Monitor}
\li \l{network/securesocketclient}{Secure Socket Client}
\li \l{network/multicastreceiver}{Multicast Receiver}
\li \l{network/multicastsender}{Multicast Sender}
diff --git a/src/network/doc/src/external-resources.qdoc b/src/network/doc/src/external-resources.qdoc
index f033ddc729..60680cde0a 100644
--- a/src/network/doc/src/external-resources.qdoc
+++ b/src/network/doc/src/external-resources.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\externalpage https://www.openssl.org/
diff --git a/src/network/doc/src/network-programming.qdoc b/src/network/doc/src/network-programming.qdoc
index 4f2ebf7c54..d301ad01a3 100644
--- a/src/network/doc/src/network-programming.qdoc
+++ b/src/network/doc/src/network-programming.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\group network
diff --git a/src/network/doc/src/qt6-changes.qdoc b/src/network/doc/src/qt6-changes.qdoc
index 21c40dae68..3adce84760 100644
--- a/src/network/doc/src/qt6-changes.qdoc
+++ b/src/network/doc/src/qt6-changes.qdoc
@@ -1,34 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page network-changes-qt6.html
- \title Porting to Qt 6 - Qt Network
- \ingroup porting-guides-5-to-6
+ \title Changes to Qt Network
+ \ingroup changes-qt-5-to-6
\brief Migrate Qt Network to Qt 6.
Qt 6 is a result of the conscious effort to make the framework more
@@ -41,6 +17,169 @@
In this topic we summarize those changes in Qt Network, and provide
guidance to handle them.
- \section1 ADD STUFF HERE
+ \section1 API changes
+ \section2 Ambiguous name overloads
+
+ Several ambiguous overloaded functions are removed. The error() signal
+ is replaced by errorOccurred() in QAbstractSocket and its heirs
+ (QTcpSocket, QUdpSocket, QLocalSocket, and QSslSocket), and in QNetworkReply.
+ Code such as:
+
+ \code
+ connect(socket, qOverload<QAbstractSocket::SocketError>(&QAbstractSocket::error),
+ this, &SomeClass::errorSlot);
+ \endcode
+
+ must therefore be changed to:
+
+ \code
+ connect(socket, &QAbstractSocket::errorOccurred, this, &SomeClass::errorSlot);
+ \endcode
+
+ In QSslSocket, the function that returns a list of errors encountered
+ during the TLS handshake:
+
+ \code
+ QList<QSslError> sslErrors() const;
+ \endcode
+
+ is renamed to sslHandshakeErrors():
+
+ \code
+ const auto tlsErrors = socket.sslHandshakeErrors();
+ \endcode
+
+ \section2 Bearer management is removed
+
+ The classes QNetworkConfiguration and QNetworkConfigurationManager are removed in Qt 6.
+ Consequently, the following member functions of QNetworkAccessManager are also removed:
+
+ \code
+ void setConfiguration(const QNetworkConfiguration &config);
+ QNetworkConfiguration configuration() const;
+ QNetworkConfiguration activeConfiguration() const;
+ void setNetworkAccessible(NetworkAccessibility accessible);
+ NetworkAccessibility networkAccessible() const;
+ void networkSessionConnected();
+ \endcode
+
+ QNetworkInformation, initially introduced in Qt 6.1, aims to replace some
+ aspects of the bearer management API. It works by providing a unified API
+ which subscribes to changes to the network as notified by the operating
+ system.
+
+ QNetworkInformation::reachability(), introduced in Qt 6.1, replaces the
+ QNetworkAccessManager::networkAccessible() function, while adding more
+ detailed information about the reachability of the network. See its
+ documentation for more details.
+
+ In Qt 6.2 QNetworkInformation gained the ability to detect captive portals.
+
+ In Qt 6.3 QNetworkInformation gained QNetworkInformation::transportMedium()
+ and QNetworkInformation::isMetered().
+
+ \section2 Deleted enumerators
+
+ Several enumerators are removed in QtNetwork. This includes constants
+ for no longer supported protocols and functionality:
+
+ \list
+ \li QSsl::SslV2;
+ \li QSsl::SslV3;
+ \li QSsl::TlsV1SslV3;
+ \li QNetworkRequest::SpdyAllowedAttribute;
+ \li QNetworkRequest::SpdyWasUsedAttribute;
+ \li QNetworkAccessManager::UnknownAccessibility;
+ \li QNetworkAccessManager::NotAccessible;
+ \li QNetworkAccessManager::Accessible
+ \endlist
+
+ and enumerators whose names did not follow proper naming conventions:
+
+ \list
+ \li QSsl::TlsV1 (QSsl::TlsV1_0 is the proper name);
+ \li QNetworkRequest::HTTP2AllowedAttribute (use QNetworkRequest::Http2AllowedAttribute);
+ \li QNetworkRequest::HTTP2WasUsedAttribute (use QNetworkRequest::Http2WasUsedAttribute).
+ \endlist
+
+ QNetworkRequest::FollowRedirectsAttribute is removed in Qt 6, see
+ \l {Redirect policies}{the section about redirects handling} below.
+
+ \section2 Configuring QSslSocket
+
+ The following deprecated functions are removed in Qt 6:
+
+ \code
+ QList<QSslCipher> ciphers() const;
+ void setCiphers(const QList<QSslCipher> &ciphers);
+ void setCiphers(const QString &ciphers);
+ static void setDefaultCiphers(const QList<QSslCipher> &ciphers);
+ static QList<QSslCipher> defaultCiphers();
+ static QList<QSslCipher> supportedCiphers();
+ QList<QSslCipher> ciphers() const;
+ void setCiphers(const QList<QSslCipher> &ciphers);
+ void setCiphers(const QString &ciphers);
+ static void setDefaultCiphers(const QList<QSslCipher> &ciphers);
+ static QList<QSslCipher> defaultCiphers();
+ static QList<QSslCipher> supportedCiphers();
+ bool addCaCertificates(const QString &path, QSsl::EncodingFormat format = QSsl::Pem,
+ QRegExp::PatternSyntax syntax = QRegExp::FixedString);
+ void addCaCertificate(const QSslCertificate &certificate);
+ void addCaCertificates(const QList<QSslCertificate> &certificates);
+ void setCaCertificates(const QList<QSslCertificate> &certificates);
+ QList<QSslCertificate> caCertificates() const;
+ static bool addDefaultCaCertificates(const QString &path, QSsl::EncodingFormat format = QSsl::Pem,
+ QRegExp::PatternSyntax syntax = QRegExp::FixedString);
+ static void addDefaultCaCertificate(const QSslCertificate &certificate);
+ static void addDefaultCaCertificates(const QList<QSslCertificate> &certificates);
+ static void setDefaultCaCertificates(const QList<QSslCertificate> &certificates);
+ static QList<QSslCertificate> defaultCaCertificates();
+ static QList<QSslCertificate> systemCaCertificates();
+ \endcode
+
+ Use QSslConfiguration and its member functions to set these parameters, e.g.:
+
+ \code
+ auto sslConfiguration = QSslConfiguration::defaultConfiguration();
+ sslConfiguration.setCiphers("ECDHE-ECDSA-AES256-SHA384");
+ // Set other parameters here ...
+ socket.setSslConfiguration(sslConfiguration);
+ \endcode
+
+ \section1 Changes in QNetworkAccessManager's default behavior
+
+ \section2 Redirect policies
+
+ In Qt 6, the default redirect policy has changed from manual to
+ QNetworkRequest::NoLessSafeRedirectPolicy. If your application relies
+ on manual redirect handling (it connects its slot to the QNetworkReply::redirected
+ signal), you have to explicitly set this policy when creating a request:
+
+ \code
+ request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::ManualRedirectPolicy);
+ \endcode
+
+ \section2 HTTP/2 is enabled by default
+
+ In Qt 6 QNetworkAccessManager enables HTTP/2 protocol by default. Depending on the
+ scheme ("https" or "http"), QNetworkAccessManager will use the Application Layer
+ Protocol Negotiation TLS extension or "protocol upgrade" HTTP header to negotiate HTTP/2.
+ If HTTP/2 cannot be negotiated, the access manager will fall back to using HTTP/1.1.
+ If your application can only use HTTP/1.1, you have to disable HTTP/2 manually
+ on a new request:
+
+ \code
+ request.setAttribute(QNetworkRequest::Http2AllowedAttribute, false);
+ \endcode
+
+ \section2 QNetworkAccessManager now guards against archive bombs
+
+ Starting with Qt 6.2 QNetworkAccessManager will guard against compressed
+ files that decompress to files which are much larger than their compressed
+ form by erroring out the reply if the decompression ratio exceeds a certain
+ threshold.
+ This check is only applied to files larger than a certain size, which can be
+ customized (or disabled by passing -1) by calling
+ \l{QNetworkRequest::setDecompressedSafetyCheckThreshold()}.
*/
diff --git a/src/network/doc/src/qtnetwork.qdoc b/src/network/doc/src/qtnetwork.qdoc
index ccd72400d5..629c7113db 100644
--- a/src/network/doc/src/qtnetwork.qdoc
+++ b/src/network/doc/src/qtnetwork.qdoc
@@ -1,57 +1,36 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtnetwork-index.html
\title Qt Network
\brief Provides networking capabilities
- Qt Network provides a set of APIs for programming applications that use
- TCP/IP. Operations such as requests, cookies, and sending data over HTTP
- are handled by various C++ classes.
+ The Qt Network module provides a set of APIs for programming
+ applications that use TCP/IP. Operations such as requests, cookies, and
+ sending data over HTTP are handled by various C++ classes.
- \include module-use.qdocinc using qt module
- \snippet doc/snippets/CMakeLists.txt 0
+ \section1 Using the Module
- See also the \l[QtDoc]{Build with CMake} overview.
+ \include {module-use.qdocinc} {using the c++ api}
- \section2 Building with qmake
+ \section2 Building with CMake
+
+ \include {module-use.qdocinc} {building with cmake} {Network}
- Add \c network to the \c QT variable:
+ \section2 Building with qmake
- \snippet doc/snippets/snippets.pro 0
+ \include {module-use.qdocinc} {building_with_qmake} {network}
\section1 Articles and Guides
These articles contain information about Qt Network setup and about
applications with networking capabilities.
\list
- \li \l{Network Programming with Qt} - Programming applications with networking capabilities
- \li \l{Secure Sockets Layer (SSL) Classes} - Classes for secure communication over network sockets
+ \li \l{Network Programming with Qt} - Programming applications with
+ networking capabilities
+ \li \l{Secure Sockets Layer (SSL) Classes} - Classes for secure
+ communication over network sockets
\endlist
\section1 API Reference
@@ -61,7 +40,7 @@
\endlist
\section1 Module Evolution
- \l{Porting to Qt 6 - Qt Network} lists important changes in the module API
+ \l{Changes to Qt Network} lists important changes in the module API
and functionality that were done for the Qt 6 series of Qt.
\section1 Licenses and Attributions
@@ -72,7 +51,13 @@
the \l{GNU General Public License, version 2}.
See \l{Qt Licensing} for further details.
- Qt Network can use the \l{OpenSSL Toolkit} as a backend. The library is then
+ Furthermore, Qt Network in Qt \QtVersion may contain third-party
+ modules under the following permissive licenses:
+
+ \generatelist{groupsbymodule attributions-qtnetwork}
+
+ Qt Network can make use of the \l{OpenSSL Toolkit} as a back end.
+ The library is then
linked against OpenSSL in a way that requires compliance with the \l{OpenSSL
License}. To allow linking OpenSSL with Qt Network under the GPL, following
exceptions to the GPL do apply:
@@ -102,6 +87,7 @@
\qtvariable network
\brief Provides classes to make network programming easier and portable.
- Qt Network provides a set of APIs for programming applications that use
- TCP/IP. See the \l{Qt Network} overview for more information.
+
+ The \l{Qt Network} page contains information about how to use the module.
+
*/
diff --git a/src/network/doc/src/ssl.qdoc b/src/network/doc/src/ssl.qdoc
index e485a1b393..83549f61e8 100644
--- a/src/network/doc/src/ssl.qdoc
+++ b/src/network/doc/src/ssl.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page ssl.html
@@ -33,39 +9,64 @@
\keyword SSL
The classes below provide support for secure network communication using
- the Secure Sockets Layer (SSL) protocol, using the \l{OpenSSL Toolkit}
- to perform encryption and protocol handling.
+ the Secure Sockets Layer (SSL) protocol, using a native TLS backend,
+ the \l{OpenSSL Toolkit}, or any appropriate TLS plugin to perform encryption
+ and protocol handling.
- From Qt version 5.6 onwards, the officially supported version for OpenSSL
- is 1.0.0 or later.
+ From Qt version 5.15 onward, the officially supported version for OpenSSL
+ is 1.1.1 or later.
+
+ Qt version 5.15.1 onward is also compatible with OpenSSL 3.
\annotatedlist ssl
+ For Android applications see \l{Adding OpenSSL Support for Android}.
+
+ \section1 Enabling and Disabling SSL Support when Building Qt from Source
- \section1 Enabling and Disabling SSL Support
+ When building Qt from source, Qt builds plugins for native TLS libraries
+ that are supported for the operating system you are building for. For
+ Windows this means
+ \l{https://docs.microsoft.com/en-us/windows/win32/com/schannel}{Schannel},
+ while for macOS this is
+ \l{https://developer.apple.com/documentation/security/secure_transport}{Secure Transport}.
- When building Qt from source, the configuration system checks for the presence
- of the \c{openssl/opensslv.h} header provided by source or developer packages
- of OpenSSL.
+ On all platforms, the configuration system checks for the presence of the
+ \c{openssl/opensslv.h} header provided by source or developer packages
+ of OpenSSL. If found, it will enable and build the OpenSSL backend for Qt.
- By default, an SSL-enabled Qt library dynamically loads any installed OpenSSL
- library at run-time. However, it is possible to link against the library at
- compile-time by configuring Qt with the \c{-openssl-linked} option.
+ By default, an OpenSSL-enabled Qt library dynamically loads any installed
+ OpenSSL library at run-time. However, it is possible to link against the
+ library at compile-time by configuring Qt with the \c{-openssl-linked}
+ option.
- When building a version of Qt linked against OpenSSL, the build system will
- attempt to link with libssl and libcrypt libraries located in the default
- location on the developer's system. This location is configurable:
- set the \c OPENSSL_LIBS environment variable to contain the linker options
- required to link Qt against the installed library. For example, on a Unix/Linux
- system:
+ When building a version of Qt linked against OpenSSL, Qt's build system will
+ use CMake's \c{FindOpenSSL} command to find OpenSSL in several standard
+ locations. You can set the CMake variable OPENSSL_ROOT_DIR to force a
+ specific location.
+ For example:
\code
- OPENSSL_LIBS='-L/opt/ssl/lib -lssl -lcrypto' ./configure -openssl-linked
+ configure -openssl-linked -- -D OPENSSL_ROOT_DIR=<openssl_dir>
\endcode
To disable SSL support in a Qt build, configure Qt with the \c{-no-openssl}
option.
+ \section1 Considerations While Packaging Your Application
+
+ When you package your application, you may run a tool like \l{windeployqt}. This
+ copies all the plugins for the libraries you use to the \c{plugins/} folder.
+ However, for TLS you only need one backend, and you may delete the other
+ plugins before packaging your application. For example, if you're on Windows
+ and don't require any of the extra features the OpenSSL backend provides,
+ you can choose to forego shipping the \c{qopensslbackend} plugin as well as
+ the OpenSSL library, and simply ship the \c{qschannelbackend} plugin.
+
+ However, shipping multiple backends is not a problem. Qt will
+ attempt to load the backends in order (with OpenSSL attempted first) until
+ one is successfully loaded. The other backends are then unused.
+
\section1 Datagram Transport Layer Security
Datagram Transport Layer Security (DTLS) is a protocol that enables security
@@ -73,7 +74,7 @@
eavesdropping, tampering, or message forgery. The DTLS protocol is based on the
stream-oriented Transport Layer Security (TLS) protocol. QtNetwork enables
the use of DTLS with User Datagram Protocol (UDP), as defined by
- \l {https://tools.ietf.org/html/rfc6347}{RFC 6347}.
+ \l {RFC 6347}.
\section1 Import and Export Restrictions
diff --git a/src/network/kernel/kernel.pri b/src/network/kernel/kernel.pri
deleted file mode 100644
index cc78555805..0000000000
--- a/src/network/kernel/kernel.pri
+++ /dev/null
@@ -1,95 +0,0 @@
-# Qt network kernel module
-
-PRECOMPILED_HEADER = ../corelib/global/qt_pch.h
-INCLUDEPATH += $$PWD
-
-HEADERS += kernel/qtnetworkglobal.h \
- kernel/qtnetworkglobal_p.h \
- kernel/qauthenticator.h \
- kernel/qauthenticator_p.h \
- kernel/qhostaddress.h \
- kernel/qhostaddress_p.h \
- kernel/qhostinfo.h \
- kernel/qhostinfo_p.h \
- kernel/qnetworkdatagram.h \
- kernel/qnetworkdatagram_p.h \
- kernel/qnetworkinterface.h \
- kernel/qnetworkinterface_p.h \
- kernel/qnetworkinterface_unix_p.h \
- kernel/qnetworkproxy.h \
- kernel/qnetconmonitor_p.h
-
-SOURCES += kernel/qauthenticator.cpp \
- kernel/qhostaddress.cpp \
- kernel/qhostinfo.cpp \
- kernel/qnetworkdatagram.cpp \
- kernel/qnetworkinterface.cpp \
- kernel/qnetworkproxy.cpp
-
-
-qtConfig(topleveldomain) {
- HEADERS += kernel/qurltlds_p.h \
- kernel/qtldurl_p.h
- SOURCES += kernel/qtldurl.cpp
-}
-
-qtConfig(dnslookup) {
- HEADERS += kernel/qdnslookup.h \
- kernel/qdnslookup_p.h
-
- SOURCES += kernel/qdnslookup.cpp
-}
-
-unix {
- !integrity:qtConfig(dnslookup): SOURCES += kernel/qdnslookup_unix.cpp
-
- SOURCES += kernel/qhostinfo_unix.cpp
-
- qtConfig(dlopen): QMAKE_USE_PRIVATE += libdl
-
- qtConfig(linux-netlink): SOURCES += kernel/qnetworkinterface_linux.cpp
- else: SOURCES += kernel/qnetworkinterface_unix.cpp
-}
-
-android:qtConfig(dnslookup) {
- SOURCES -= kernel/qdnslookup_unix.cpp
- SOURCES += kernel/qdnslookup_android.cpp
-}
-
-win32: {
- SOURCES += kernel/qhostinfo_win.cpp \
- kernel/qnetworkinterface_win.cpp
- qtConfig(dnslookup): SOURCES += kernel/qdnslookup_win.cpp
- LIBS_PRIVATE += -ldnsapi -liphlpapi
-}
-
-mac {
- LIBS_PRIVATE += -framework CoreFoundation
- !uikit: LIBS_PRIVATE += -framework CoreServices -framework SystemConfiguration
-}
-
-macos | ios {
- OBJECTIVE_SOURCES += \
- kernel/qnetconmonitor_darwin.mm
-
- LIBS_PRIVATE += -framework SystemConfiguration
-} else:qtConfig(netlistmgr) {
- SOURCES += kernel/qnetconmonitor_win.cpp
-} else {
- SOURCES += kernel/qnetconmonitor_stub.cpp
-}
-
-qtConfig(gssapi): QMAKE_USE_PRIVATE += gssapi
-
-uikit:HEADERS += kernel/qnetworkinterface_uikit_p.h
-osx:SOURCES += kernel/qnetworkproxy_mac.cpp
-else:win32: SOURCES += kernel/qnetworkproxy_win.cpp
-else: qtConfig(libproxy) {
- SOURCES += kernel/qnetworkproxy_libproxy.cpp
- QMAKE_USE_PRIVATE += libproxy libdl
-}
-else:android: SOURCES += kernel/qnetworkproxy_android.cpp
-else: SOURCES += kernel/qnetworkproxy_generic.cpp
-
-android: ANDROID_BUNDLED_JAR_DEPENDENCIES = \
- jar/QtAndroidNetwork.jar
diff --git a/src/network/kernel/qauthenticator.cpp b/src/network/kernel/qauthenticator.cpp
index 86242b011f..e42450d7e5 100644
--- a/src/network/kernel/qauthenticator.cpp
+++ b/src/network/kernel/qauthenticator.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qauthenticator.h>
#include <qauthenticator_p.h>
@@ -50,6 +14,7 @@
#include <qstring.h>
#include <qdatetime.h>
#include <qrandom.h>
+#include <QtNetwork/qhttpheaders.h>
#ifdef Q_OS_WIN
#include <qmutex.h>
@@ -69,6 +34,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
Q_DECLARE_LOGGING_CATEGORY(lcAuthenticator);
Q_LOGGING_CATEGORY(lcAuthenticator, "qt.network.authenticator");
@@ -77,14 +44,13 @@ static QByteArray qNtlmPhase3(QAuthenticatorPrivate *ctx, const QByteArray& phas
#if QT_CONFIG(sspi) // SSPI
static bool q_SSPI_library_load();
static QByteArray qSspiStartup(QAuthenticatorPrivate *ctx, QAuthenticatorPrivate::Method method,
- const QString& host);
+ QStringView host);
static QByteArray qSspiContinue(QAuthenticatorPrivate *ctx, QAuthenticatorPrivate::Method method,
- const QString& host, const QByteArray& challenge = QByteArray());
+ QStringView host, QByteArrayView challenge = {});
#elif QT_CONFIG(gssapi) // GSSAPI
-static bool qGssapiTestGetCredentials(const QString &host);
-static QByteArray qGssapiStartup(QAuthenticatorPrivate *ctx, const QString& host);
-static QByteArray qGssapiContinue(QAuthenticatorPrivate *ctx,
- const QByteArray& challenge = QByteArray());
+static bool qGssapiTestGetCredentials(QStringView host);
+static QByteArray qGssapiStartup(QAuthenticatorPrivate *ctx, QStringView host);
+static QByteArray qGssapiContinue(QAuthenticatorPrivate *ctx, QByteArrayView challenge = {});
#endif // gssapi
/*!
@@ -154,7 +120,28 @@ static QByteArray qGssapiContinue(QAuthenticatorPrivate *ctx,
\section2 SPNEGO/Negotiate
- This authentication mechanism currently supports no incoming or outgoing options.
+ \table
+ \header
+ \li Option
+ \li Direction
+ \li Type
+ \li Description
+ \row
+ \li \tt{spn}
+ \li Outgoing
+ \li QString
+ \li Provides a custom SPN.
+ \endtable
+
+ This authentication mechanism currently supports no incoming options.
+
+ The \c{spn} property is used on Windows clients when an SSPI library is used.
+ If the property is not set, a default SPN will be used. The default SPN on
+ Windows is \c {HTTP/<hostname>}.
+
+ Other operating systems use GSSAPI libraries. For that it is expected that
+ KDC is set up, and the credentials can be fetched from it. The backend always
+ uses \c {HTTPS@<hostname>} as an SPN.
\sa QSslSocket
*/
@@ -195,7 +182,7 @@ QAuthenticator &QAuthenticator::operator=(const QAuthenticator &other)
if (d == other.d)
return *this;
- // Do not share the d since challange reponse/based changes
+ // Do not share the d since challenge response/based changes
// could corrupt the internal store and different network requests
// can utilize different types of proxies.
detach();
@@ -406,7 +393,7 @@ void QAuthenticatorPrivate::updateCredentials()
switch (method) {
case QAuthenticatorPrivate::Ntlm:
- if ((separatorPosn = user.indexOf(QLatin1String("\\"))) != -1) {
+ if ((separatorPosn = user.indexOf("\\"_L1)) != -1) {
//domain name is present
realm.clear();
userDomain = user.left(separatorPosn);
@@ -423,12 +410,49 @@ void QAuthenticatorPrivate::updateCredentials()
}
}
-void QAuthenticatorPrivate::parseHttpResponse(const QList<QPair<QByteArray, QByteArray> > &values, bool isProxy, const QString &host)
+bool QAuthenticatorPrivate::isMethodSupported(QByteArrayView method)
+{
+ Q_ASSERT(!method.startsWith(' ')); // This should be trimmed during parsing
+ auto separator = method.indexOf(' ');
+ if (separator != -1)
+ method = method.first(separator);
+ const auto isSupported = [method](QByteArrayView reference) {
+ return method.compare(reference, Qt::CaseInsensitive) == 0;
+ };
+ static const char methods[][10] = {
+ "basic",
+ "ntlm",
+ "digest",
+#if QT_CONFIG(sspi) || QT_CONFIG(gssapi)
+ "negotiate",
+#endif
+ };
+ return std::any_of(methods, methods + std::size(methods), isSupported);
+}
+
+static bool verifyDigestMD5(QByteArrayView value)
+{
+ auto opts = QAuthenticatorPrivate::parseDigestAuthenticationChallenge(value);
+ if (auto it = opts.constFind("algorithm"); it != opts.cend()) {
+ QByteArray alg = it.value();
+ if (alg.size() < 3)
+ return false;
+ // Just compare the first 3 characters, that way we match other subvariants as well, such as
+ // "MD5-sess"
+ auto view = QByteArrayView(alg).first(3);
+ return view.compare("MD5", Qt::CaseInsensitive) == 0;
+ }
+ return true; // assume it's ok if algorithm is not specified
+}
+
+void QAuthenticatorPrivate::parseHttpResponse(const QHttpHeaders &headers,
+ bool isProxy, QStringView host)
{
#if !QT_CONFIG(gssapi)
Q_UNUSED(host);
#endif
- const char *search = isProxy ? "proxy-authenticate" : "www-authenticate";
+ const auto search = isProxy ? QHttpHeaders::WellKnownHeader::ProxyAuthenticate
+ : QHttpHeaders::WellKnownHeader::WWWAuthenticate;
method = None;
/*
@@ -441,22 +465,23 @@ void QAuthenticatorPrivate::parseHttpResponse(const QList<QPair<QByteArray, QByt
authentication parameters.
*/
- QByteArray headerVal;
- for (int i = 0; i < values.size(); ++i) {
- const QPair<QByteArray, QByteArray> &current = values.at(i);
- if (current.first.compare(search, Qt::CaseInsensitive) != 0)
- continue;
- QByteArray str = current.second.toLower();
- if (method < Basic && str.startsWith("basic")) {
+ QByteArrayView headerVal;
+ for (const auto &current : headers.values(search)) {
+ const QLatin1StringView str(current);
+ if (method < Basic && str.startsWith("basic"_L1, Qt::CaseInsensitive)) {
method = Basic;
- headerVal = current.second.mid(6);
- } else if (method < Ntlm && str.startsWith("ntlm")) {
+ headerVal = QByteArrayView(current).mid(6);
+ } else if (method < Ntlm && str.startsWith("ntlm"_L1, Qt::CaseInsensitive)) {
method = Ntlm;
- headerVal = current.second.mid(5);
- } else if (method < DigestMd5 && str.startsWith("digest")) {
+ headerVal = QByteArrayView(current).mid(5);
+ } else if (method < DigestMd5 && str.startsWith("digest"_L1, Qt::CaseInsensitive)) {
+ // Make sure the algorithm is actually MD5 before committing to it:
+ if (!verifyDigestMD5(QByteArrayView(current).sliced(7)))
+ continue;
+
method = DigestMd5;
- headerVal = current.second.mid(7);
- } else if (method < Negotiate && str.startsWith("negotiate")) {
+ headerVal = QByteArrayView(current).mid(7);
+ } else if (method < Negotiate && str.startsWith("negotiate"_L1, Qt::CaseInsensitive)) {
#if QT_CONFIG(sspi) || QT_CONFIG(gssapi) // if it's not supported then we shouldn't try to use it
#if QT_CONFIG(gssapi)
// For GSSAPI there needs to be a KDC set up for the host (afaict).
@@ -466,14 +491,14 @@ void QAuthenticatorPrivate::parseHttpResponse(const QList<QPair<QByteArray, QByt
continue;
#endif
method = Negotiate;
- headerVal = current.second.mid(10);
+ headerVal = QByteArrayView(current).mid(10);
#endif
}
}
// Reparse credentials since we know the method now
updateCredentials();
- challenge = headerVal.trimmed();
+ challenge = headerVal.trimmed().toByteArray();
QHash<QByteArray, QByteArray> options = parseDigestAuthenticationChallenge(challenge);
// Sets phase to Start if this updates our realm and sets the two locations where we store
@@ -483,7 +508,7 @@ void QAuthenticatorPrivate::parseHttpResponse(const QList<QPair<QByteArray, QByt
if (phase == Done)
phase = Start;
realm = newRealm;
- this->options[QLatin1String("realm")] = realm;
+ this->options["realm"_L1] = realm;
}
};
@@ -514,22 +539,21 @@ void QAuthenticatorPrivate::parseHttpResponse(const QList<QPair<QByteArray, QByt
}
}
-QByteArray QAuthenticatorPrivate::calculateResponse(const QByteArray &requestMethod, const QByteArray &path, const QString& host)
+QByteArray QAuthenticatorPrivate::calculateResponse(QByteArrayView requestMethod,
+ QByteArrayView path, QStringView host)
{
#if !QT_CONFIG(sspi) && !QT_CONFIG(gssapi)
Q_UNUSED(host);
#endif
QByteArray response;
- const char* methodString = nullptr;
+ QByteArrayView methodString;
switch(method) {
case QAuthenticatorPrivate::None:
- methodString = "";
phase = Done;
break;
case QAuthenticatorPrivate::Basic:
methodString = "Basic";
- response = user.toLatin1() + ':' + password.toLatin1();
- response = response.toBase64();
+ response = (user + ':'_L1 + password).toLatin1().toBase64();
phase = Done;
break;
case QAuthenticatorPrivate::DigestMd5:
@@ -599,9 +623,11 @@ QByteArray QAuthenticatorPrivate::calculateResponse(const QByteArray &requestMet
} else {
QByteArray phase3Token;
#if QT_CONFIG(sspi) // SSPI
- phase3Token = qSspiContinue(this, method, host, QByteArray::fromBase64(challenge));
+ if (sspiWindowsHandles)
+ phase3Token = qSspiContinue(this, method, host, QByteArray::fromBase64(challenge));
#elif QT_CONFIG(gssapi) // GSSAPI
- phase3Token = qGssapiContinue(this, QByteArray::fromBase64(challenge));
+ if (gssApiHandles)
+ phase3Token = qGssapiContinue(this, QByteArray::fromBase64(challenge));
#endif
if (!phase3Token.isEmpty()) {
response = phase3Token.toBase64();
@@ -616,25 +642,35 @@ QByteArray QAuthenticatorPrivate::calculateResponse(const QByteArray &requestMet
break;
}
- return QByteArray::fromRawData(methodString, qstrlen(methodString)) + ' ' + response;
+ return methodString + ' ' + response;
}
// ---------------------------- Digest Md5 code ----------------------------------------
-QHash<QByteArray, QByteArray> QAuthenticatorPrivate::parseDigestAuthenticationChallenge(const QByteArray &challenge)
+static bool containsAuth(QByteArrayView data)
+{
+ for (auto element : QLatin1StringView(data).tokenize(','_L1)) {
+ if (element == "auth"_L1)
+ return true;
+ }
+ return false;
+}
+
+QHash<QByteArray, QByteArray>
+QAuthenticatorPrivate::parseDigestAuthenticationChallenge(QByteArrayView challenge)
{
QHash<QByteArray, QByteArray> options;
// parse the challenge
- const char *d = challenge.constData();
- const char *end = d + challenge.length();
+ const char *d = challenge.data();
+ const char *end = d + challenge.size();
while (d < end) {
while (d < end && (*d == ' ' || *d == '\n' || *d == '\r'))
++d;
const char *start = d;
while (d < end && *d != '=')
++d;
- QByteArray key = QByteArray(start, d - start);
+ QByteArrayView key = QByteArrayView(start, d - start);
++d;
if (d >= end)
break;
@@ -643,7 +679,6 @@ QHash<QByteArray, QByteArray> QAuthenticatorPrivate::parseDigestAuthenticationCh
++d;
if (d >= end)
break;
- start = d;
QByteArray value;
while (d < end) {
bool backslash = false;
@@ -666,13 +701,12 @@ QHash<QByteArray, QByteArray> QAuthenticatorPrivate::parseDigestAuthenticationCh
while (d < end && *d != ',')
++d;
++d;
- options[key] = value;
+ options[key.toByteArray()] = std::move(value);
}
QByteArray qop = options.value("qop");
if (!qop.isEmpty()) {
- QList<QByteArray> qopoptions = qop.split(',');
- if (!qopoptions.contains("auth"))
+ if (!containsAuth(qop))
return QHash<QByteArray, QByteArray>();
// #### can't do auth-int currently
// if (qop.contains("auth-int"))
@@ -698,24 +732,24 @@ QHash<QByteArray, QByteArray> QAuthenticatorPrivate::parseDigestAuthenticationCh
/* calculate request-digest/response-digest as per HTTP Digest spec */
static QByteArray digestMd5ResponseHelper(
- const QByteArray &alg,
- const QByteArray &userName,
- const QByteArray &realm,
- const QByteArray &password,
- const QByteArray &nonce, /* nonce from server */
- const QByteArray &nonceCount, /* 8 hex digits */
- const QByteArray &cNonce, /* client nonce */
- const QByteArray &qop, /* qop-value: "", "auth", "auth-int" */
- const QByteArray &method, /* method from the request */
- const QByteArray &digestUri, /* requested URL */
- const QByteArray &hEntity /* H(entity body) if qop="auth-int" */
+ QByteArrayView alg,
+ QByteArrayView userName,
+ QByteArrayView realm,
+ QByteArrayView password,
+ QByteArrayView nonce, /* nonce from server */
+ QByteArrayView nonceCount, /* 8 hex digits */
+ QByteArrayView cNonce, /* client nonce */
+ QByteArrayView qop, /* qop-value: "", "auth", "auth-int" */
+ QByteArrayView method, /* method from the request */
+ QByteArrayView digestUri, /* requested URL */
+ QByteArrayView hEntity /* H(entity body) if qop="auth-int" */
)
{
QCryptographicHash hash(QCryptographicHash::Md5);
hash.addData(userName);
- hash.addData(":", 1);
+ hash.addData(":");
hash.addData(realm);
- hash.addData(":", 1);
+ hash.addData(":");
hash.addData(password);
QByteArray ha1 = hash.result();
if (alg.compare("md5-sess", Qt::CaseInsensitive) == 0) {
@@ -725,9 +759,9 @@ static QByteArray digestMd5ResponseHelper(
// but according to the errata page at http://www.rfc-editor.org/errata_list.php, ID 1649, it
// must be the following line:
hash.addData(ha1.toHex());
- hash.addData(":", 1);
+ hash.addData(":");
hash.addData(nonce);
- hash.addData(":", 1);
+ hash.addData(":");
hash.addData(cNonce);
ha1 = hash.result();
};
@@ -736,10 +770,10 @@ static QByteArray digestMd5ResponseHelper(
// calculate H(A2)
hash.reset();
hash.addData(method);
- hash.addData(":", 1);
+ hash.addData(":");
hash.addData(digestUri);
if (qop.compare("auth-int", Qt::CaseInsensitive) == 0) {
- hash.addData(":", 1);
+ hash.addData(":");
hash.addData(hEntity);
}
QByteArray ha2hex = hash.result().toHex();
@@ -747,28 +781,29 @@ static QByteArray digestMd5ResponseHelper(
// calculate response
hash.reset();
hash.addData(ha1);
- hash.addData(":", 1);
+ hash.addData(":");
hash.addData(nonce);
- hash.addData(":", 1);
+ hash.addData(":");
if (!qop.isNull()) {
hash.addData(nonceCount);
- hash.addData(":", 1);
+ hash.addData(":");
hash.addData(cNonce);
- hash.addData(":", 1);
+ hash.addData(":");
hash.addData(qop);
- hash.addData(":", 1);
+ hash.addData(":");
}
hash.addData(ha2hex);
return hash.result().toHex();
}
-QByteArray QAuthenticatorPrivate::digestMd5Response(const QByteArray &challenge, const QByteArray &method, const QByteArray &path)
+QByteArray QAuthenticatorPrivate::digestMd5Response(QByteArrayView challenge, QByteArrayView method,
+ QByteArrayView path)
{
QHash<QByteArray,QByteArray> options = parseDigestAuthenticationChallenge(challenge);
++nonceCount;
QByteArray nonceCountString = QByteArray::number(nonceCount, 16);
- while (nonceCountString.length() < 8)
+ while (nonceCountString.size() < 8)
nonceCountString.prepend('0');
QByteArray nonce = options.value("nonce");
@@ -1029,9 +1064,9 @@ static void qStreamNtlmString(QDataStream& ds, const QString& s, bool unicode)
qStreamNtlmBuffer(ds, s.toLatin1());
return;
}
- const ushort *d = s.utf16();
- for (int i = 0; i < s.length(); ++i)
- ds << d[i];
+
+ for (QChar ch : s)
+ ds << quint16(ch.unicode());
}
@@ -1049,7 +1084,7 @@ static int qEncodeNtlmString(QNtlmBuffer& buf, int offset, const QString& s, boo
{
if (!unicode)
return qEncodeNtlmBuffer(buf, offset, s.toLatin1());
- buf.len = 2 * s.length();
+ buf.len = 2 * s.size();
buf.maxLen = buf.len;
buf.offset = (offset + 1) & ~1;
return buf.offset + buf.len;
@@ -1171,12 +1206,11 @@ static QByteArray qNtlmPhase1()
static QByteArray qStringAsUcs2Le(const QString& src)
{
- QByteArray rc(2*src.length(), 0);
- const unsigned short *s = src.utf16();
+ QByteArray rc(2*src.size(), 0);
unsigned short *d = (unsigned short*)rc.data();
- for (int i = 0; i < src.length(); ++i) {
- d[i] = qToLittleEndian(s[i]);
- }
+ for (QChar ch : src)
+ *d++ = qToLittleEndian(quint16(ch.unicode()));
+
return rc;
}
@@ -1185,7 +1219,7 @@ static QString qStringFromUcs2Le(QByteArray src)
{
Q_ASSERT(src.size() % 2 == 0);
unsigned short *d = (unsigned short*)src.data();
- for (int i = 0; i < src.length() / 2; ++i) {
+ for (int i = 0; i < src.size() / 2; ++i) {
d[i] = qFromLittleEndian(d[i]);
}
return QString((const QChar *)src.data(), src.size()/2);
@@ -1214,13 +1248,12 @@ static QString qStringFromUcs2Le(QByteArray src)
* ---------------------------------------
*
*********************************************************************/
-QByteArray qEncodeHmacMd5(QByteArray &key, const QByteArray &message)
+QByteArray qEncodeHmacMd5(QByteArray &key, QByteArrayView message)
{
Q_ASSERT_X(!(message.isEmpty()),"qEncodeHmacMd5", "Empty message check");
Q_ASSERT_X(!(key.isEmpty()),"qEncodeHmacMd5", "Empty key check");
QCryptographicHash hash(QCryptographicHash::Md5);
- QByteArray hMsg;
QByteArray iKeyPad(blockSize, 0x36);
QByteArray oKeyPad(blockSize, 0x5c);
@@ -1228,7 +1261,7 @@ QByteArray qEncodeHmacMd5(QByteArray &key, const QByteArray &message)
hash.reset();
// Adjust the key length to blockSize
- if(blockSize < key.length()) {
+ if (blockSize < key.size()) {
hash.addData(key);
key = hash.result(); //MD5 will always return 16 bytes length output
}
@@ -1253,7 +1286,7 @@ QByteArray qEncodeHmacMd5(QByteArray &key, const QByteArray &message)
hash.reset();
hash.addData(iKeyPad);
- hMsg = hash.result();
+ QByteArrayView hMsg = hash.resultView();
//Digest gen after pass-1: H((K0 xor ipad)||text)
QByteArray hmacDigest;
@@ -1280,10 +1313,10 @@ static QByteArray qCreatev2Hash(const QAuthenticatorPrivate *ctx,
Q_ASSERT(phase3 != nullptr);
// since v2 Hash is need for both NTLMv2 and LMv2 it is calculated
// only once and stored and reused
- if(phase3->v2Hash.size() == 0) {
+ if (phase3->v2Hash.size() == 0) {
QCryptographicHash md4(QCryptographicHash::Md4);
QByteArray passUnicode = qStringAsUcs2Le(ctx->password);
- md4.addData(passUnicode.data(), passUnicode.size());
+ md4.addData(passUnicode);
QByteArray hashKey = md4.result();
Q_ASSERT(hashKey.size() == 16);
@@ -1317,7 +1350,7 @@ static QByteArray qExtractServerTime(const QByteArray& targetInfoBuff)
ds >> avId;
ds >> avLen;
while(avId != 0) {
- if(avId == AVTIMESTAMP) {
+ if (avId == AVTIMESTAMP) {
timeArray.resize(avLen);
//avLen size of QByteArray is allocated
ds.readRawData(timeArray.data(), avLen);
@@ -1352,13 +1385,13 @@ static QByteArray qEncodeNtlmv2Response(const QAuthenticatorPrivate *ctx,
quint64 time = 0;
QByteArray timeArray;
- if(ch.targetInfo.len)
+ if (ch.targetInfo.len)
{
timeArray = qExtractServerTime(ch.targetInfoBuff);
}
//if server sends time, use it instead of current time
- if(timeArray.size()) {
+ if (timeArray.size()) {
ds.writeRawData(timeArray.constData(), timeArray.size());
} else {
// number of seconds between 1601 and the epoch (1970)
@@ -1442,7 +1475,7 @@ static bool qNtlmDecodePhase2(const QByteArray& data, QNtlmPhase2Block& ch)
ds >> ch.targetInfo;
if (ch.targetName.len > 0) {
- if (ch.targetName.len + ch.targetName.offset > (unsigned)data.size())
+ if (qsizetype(ch.targetName.len + ch.targetName.offset) > data.size())
return false;
ch.targetNameStr = qStringFromUcs2Le(data.mid(ch.targetName.offset, ch.targetName.len));
@@ -1490,7 +1523,7 @@ static QByteArray qNtlmPhase3(QAuthenticatorPrivate *ctx, const QByteArray& phas
Q_ASSERT(QNtlmPhase3BlockBase::Size == sizeof(QNtlmPhase3BlockBase));
// for kerberos style user@domain logins, NTLM domain string should be left empty
- if (ctx->userDomain.isEmpty() && !ctx->extractedUser.contains(QLatin1Char('@'))) {
+ if (ctx->userDomain.isEmpty() && !ctx->extractedUser.contains(u'@')) {
offset = qEncodeNtlmString(pb.domain, offset, ch.targetNameStr, unicode);
pb.domainStr = ch.targetNameStr;
} else {
@@ -1530,27 +1563,16 @@ static QByteArray qNtlmPhase3(QAuthenticatorPrivate *ctx, const QByteArray& phas
// See http://davenport.sourceforge.net/ntlm.html
// and libcurl http_ntlm.c
-// Handle of secur32.dll
-static HMODULE securityDLLHandle = nullptr;
// Pointer to SSPI dispatch table
-static PSecurityFunctionTable pSecurityFunctionTable = nullptr;
+static PSecurityFunctionTableW pSecurityFunctionTable = nullptr;
static bool q_SSPI_library_load()
{
- static QBasicMutex mutex;
+ Q_CONSTINIT static QBasicMutex mutex;
QMutexLocker l(&mutex);
- // Initialize security interface
- if (pSecurityFunctionTable == nullptr) {
- securityDLLHandle = LoadLibrary(L"secur32.dll");
- if (securityDLLHandle != nullptr) {
- INIT_SECURITY_INTERFACE pInitSecurityInterface =
- reinterpret_cast<INIT_SECURITY_INTERFACE>(
- reinterpret_cast<QFunctionPointer>(GetProcAddress(securityDLLHandle, "InitSecurityInterfaceW")));
- if (pInitSecurityInterface != nullptr)
- pSecurityFunctionTable = pInitSecurityInterface();
- }
- }
+ if (pSecurityFunctionTable == nullptr)
+ pSecurityFunctionTable = InitSecurityInterfaceW();
if (pSecurityFunctionTable == nullptr)
return false;
@@ -1559,7 +1581,7 @@ static bool q_SSPI_library_load()
}
static QByteArray qSspiStartup(QAuthenticatorPrivate *ctx, QAuthenticatorPrivate::Method method,
- const QString& host)
+ QStringView host)
{
if (!q_SSPI_library_load())
return QByteArray();
@@ -1568,17 +1590,18 @@ static QByteArray qSspiStartup(QAuthenticatorPrivate *ctx, QAuthenticatorPrivate
if (!ctx->sspiWindowsHandles)
ctx->sspiWindowsHandles.reset(new QSSPIWindowsHandles);
- memset(&ctx->sspiWindowsHandles->credHandle, 0, sizeof(CredHandle));
+ SecInvalidateHandle(&ctx->sspiWindowsHandles->credHandle);
+ SecInvalidateHandle(&ctx->sspiWindowsHandles->ctxHandle);
SEC_WINNT_AUTH_IDENTITY auth;
auth.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
bool useAuth = false;
if (method == QAuthenticatorPrivate::Negotiate && !ctx->user.isEmpty()) {
- auth.Domain = const_cast<ushort *>(ctx->userDomain.utf16());
+ auth.Domain = const_cast<ushort *>(reinterpret_cast<const ushort *>(ctx->userDomain.constData()));
auth.DomainLength = ctx->userDomain.size();
- auth.User = const_cast<ushort *>(ctx->user.utf16());
+ auth.User = const_cast<ushort *>(reinterpret_cast<const ushort *>(ctx->user.constData()));
auth.UserLength = ctx->user.size();
- auth.Password = const_cast<ushort *>(ctx->password.utf16());
+ auth.Password = const_cast<ushort *>(reinterpret_cast<const ushort *>(ctx->password.constData()));
auth.PasswordLength = ctx->password.size();
useAuth = true;
}
@@ -1599,7 +1622,7 @@ static QByteArray qSspiStartup(QAuthenticatorPrivate *ctx, QAuthenticatorPrivate
}
static QByteArray qSspiContinue(QAuthenticatorPrivate *ctx, QAuthenticatorPrivate::Method method,
- const QString &host, const QByteArray &challenge)
+ QStringView host, QByteArrayView challenge)
{
QByteArray result;
SecBuffer challengeBuf;
@@ -1629,8 +1652,11 @@ static QByteArray qSspiContinue(QAuthenticatorPrivate *ctx, QAuthenticatorPrivat
responseBuf.cbBuffer = 0;
// Calculate target (SPN for Negotiate, empty for NTLM)
- std::wstring targetNameW = (method == QAuthenticatorPrivate::Negotiate
- ? QLatin1String("HTTP/") + host : QString()).toStdWString();
+ QString targetName = ctx->options.value("spn"_L1).toString();
+ if (targetName.isEmpty())
+ targetName = "HTTP/"_L1 + host;
+ const std::wstring targetNameW = (method == QAuthenticatorPrivate::Negotiate
+ ? targetName : QString()).toStdWString();
// Generate our challenge-response message
SECURITY_STATUS secStatus = pSecurityFunctionTable->InitializeSecurityContext(
@@ -1692,7 +1718,7 @@ static void q_GSSAPI_error(const char *message, OM_uint32 majStat, OM_uint32 min
q_GSSAPI_error_int(message, minStat, GSS_C_MECH_CODE);
}
-static gss_name_t qGSsapiGetServiceName(const QString &host)
+static gss_name_t qGSsapiGetServiceName(QStringView host)
{
QByteArray serviceName = "HTTPS@" + host.toLocal8Bit();
gss_buffer_desc nameDesc = {static_cast<std::size_t>(serviceName.size()), serviceName.data()};
@@ -1710,7 +1736,7 @@ static gss_name_t qGSsapiGetServiceName(const QString &host)
}
// Send initial GSS authentication token
-static QByteArray qGssapiStartup(QAuthenticatorPrivate *ctx, const QString &host)
+static QByteArray qGssapiStartup(QAuthenticatorPrivate *ctx, QStringView host)
{
if (!ctx->gssApiHandles)
ctx->gssApiHandles.reset(new QGssApiHandles);
@@ -1729,7 +1755,7 @@ static QByteArray qGssapiStartup(QAuthenticatorPrivate *ctx, const QString &host
}
// Continue GSS authentication with next token as needed
-static QByteArray qGssapiContinue(QAuthenticatorPrivate *ctx, const QByteArray& challenge)
+static QByteArray qGssapiContinue(QAuthenticatorPrivate *ctx, QByteArrayView challenge)
{
OM_uint32 majStat, minStat, ignored;
QByteArray result;
@@ -1738,7 +1764,7 @@ static QByteArray qGssapiContinue(QAuthenticatorPrivate *ctx, const QByteArray&
if (!challenge.isEmpty()) {
inBuf.value = const_cast<char*>(challenge.data());
- inBuf.length = challenge.length();
+ inBuf.length = challenge.size();
}
majStat = gss_init_sec_context(&minStat,
@@ -1775,7 +1801,7 @@ static QByteArray qGssapiContinue(QAuthenticatorPrivate *ctx, const QByteArray&
return result;
}
-static bool qGssapiTestGetCredentials(const QString &host)
+static bool qGssapiTestGetCredentials(QStringView host)
{
gss_name_t serviceName = qGSsapiGetServiceName(host);
if (!serviceName)
diff --git a/src/network/kernel/qauthenticator.h b/src/network/kernel/qauthenticator.h
index 1032c2f501..a05d359e93 100644
--- a/src/network/kernel/qauthenticator.h
+++ b/src/network/kernel/qauthenticator.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QAUTHENTICATOR_H
#define QAUTHENTICATOR_H
@@ -52,6 +16,7 @@ class QUrl;
class Q_NETWORK_EXPORT QAuthenticator
{
+ Q_GADGET
public:
QAuthenticator();
~QAuthenticator();
diff --git a/src/network/kernel/qauthenticator_p.h b/src/network/kernel/qauthenticator_p.h
index 1813634ee0..bc16139941 100644
--- a/src/network/kernel/qauthenticator_p.h
+++ b/src/network/kernel/qauthenticator_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QAUTHENTICATOR_P_H
#define QAUTHENTICATOR_P_H
@@ -62,13 +26,14 @@
QT_BEGIN_NAMESPACE
class QHttpResponseHeader;
+class QHttpHeaders;
#if QT_CONFIG(sspi) // SSPI
class QSSPIWindowsHandles;
#elif QT_CONFIG(gssapi) // GSSAPI
class QGssApiHandles;
#endif
-class Q_AUTOTEST_EXPORT QAuthenticatorPrivate
+class Q_NETWORK_EXPORT QAuthenticatorPrivate
{
public:
enum Method { None, Basic, Negotiate, Ntlm, DigestMd5, };
@@ -91,6 +56,7 @@ public:
enum Phase {
Start,
+ Phase1,
Phase2,
Done,
Invalid
@@ -105,16 +71,20 @@ public:
QString workstation;
QString userDomain;
- QByteArray calculateResponse(const QByteArray &method, const QByteArray &path, const QString& host);
+ QByteArray calculateResponse(QByteArrayView method, QByteArrayView path, QStringView host);
inline static QAuthenticatorPrivate *getPrivate(QAuthenticator &auth) { return auth.d; }
inline static const QAuthenticatorPrivate *getPrivate(const QAuthenticator &auth) { return auth.d; }
- QByteArray digestMd5Response(const QByteArray &challenge, const QByteArray &method, const QByteArray &path);
- static QHash<QByteArray, QByteArray> parseDigestAuthenticationChallenge(const QByteArray &challenge);
+ QByteArray digestMd5Response(QByteArrayView challenge, QByteArrayView method,
+ QByteArrayView path);
+ static QHash<QByteArray, QByteArray>
+ parseDigestAuthenticationChallenge(QByteArrayView challenge);
- void parseHttpResponse(const QList<QPair<QByteArray, QByteArray> >&, bool isProxy, const QString &host);
+ void parseHttpResponse(const QHttpHeaders &headers, bool isProxy, QStringView host);
void updateCredentials();
+
+ static bool isMethodSupported(QByteArrayView method);
};
diff --git a/src/network/kernel/qdnslookup.cpp b/src/network/kernel/qdnslookup.cpp
index f679f27b36..c310c7e28e 100644
--- a/src/network/kernel/qdnslookup.cpp
+++ b/src/network/kernel/qdnslookup.cpp
@@ -1,47 +1,14 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 Jeremy Lainé <jeremy.laine@m4x.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2012 Jeremy Lainé <jeremy.laine@m4x.org>
+// Copyright (C) 2023 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdnslookup.h"
#include "qdnslookup_p.h"
+#include <qapplicationstatic.h>
#include <qcoreapplication.h>
#include <qdatetime.h>
+#include <qloggingcategory.h>
#include <qrandom.h>
#include <qurl.h>
@@ -49,9 +16,20 @@
QT_BEGIN_NAMESPACE
-#if QT_CONFIG(thread)
-Q_GLOBAL_STATIC(QDnsLookupThreadPool, theDnsLookupThreadPool);
-#endif
+static Q_LOGGING_CATEGORY(lcDnsLookup, "qt.network.dnslookup", QtCriticalMsg)
+
+namespace {
+struct QDnsLookupThreadPool : QThreadPool
+{
+ QDnsLookupThreadPool()
+ {
+ // Run up to 5 lookups in parallel.
+ setMaxThreadCount(5);
+ }
+};
+}
+
+Q_APPLICATION_STATIC(QDnsLookupThreadPool, theDnsLookupThreadPool);
static bool qt_qdnsmailexchangerecord_less_than(const QDnsMailExchangeRecord &r1, const QDnsMailExchangeRecord &r2)
{
@@ -86,7 +64,7 @@ static void qt_qdnsmailexchangerecord_sort(QList<QDnsMailExchangeRecord> &record
// Randomize the slice of records.
while (!slice.isEmpty()) {
- const unsigned int pos = QRandomGenerator::global()->bounded(int(slice.size()));
+ const unsigned int pos = QRandomGenerator::global()->bounded(slice.size());
records[i++] = slice.takeAt(pos);
}
}
@@ -155,9 +133,6 @@ static void qt_qdnsservicerecord_sort(QList<QDnsServiceRecord> &records)
}
}
-const char *QDnsLookupPrivate::msgNoIpV6NameServerAdresses =
- QT_TRANSLATE_NOOP("QDnsLookupRunnable", "IPv6 addresses for nameservers are currently not supported");
-
/*!
\class QDnsLookup
\brief The QDnsLookup class represents a DNS lookup.
@@ -212,6 +187,9 @@ const char *QDnsLookupPrivate::msgNoIpV6NameServerAdresses =
\value NotFoundError the requested domain name does not exist
(NXDOMAIN).
+
+ \value TimeoutError the server was not reached or did not reply
+ in time (since 6.6).
*/
/*!
@@ -267,8 +245,8 @@ const char *QDnsLookupPrivate::msgNoIpV6NameServerAdresses =
QDnsLookup::QDnsLookup(QObject *parent)
: QObject(*new QDnsLookupPrivate, parent)
{
- qRegisterMetaType<QDnsLookupReply>();
}
+
/*!
Constructs a QDnsLookup object for the given \a type and \a name and sets
\a parent as the parent object.
@@ -278,7 +256,6 @@ QDnsLookup::QDnsLookup(Type type, const QString &name, QObject *parent)
: QObject(*new QDnsLookupPrivate, parent)
{
Q_D(QDnsLookup);
- qRegisterMetaType<QDnsLookupReply>();
d->name = name;
d->type = type;
}
@@ -286,17 +263,39 @@ QDnsLookup::QDnsLookup(Type type, const QString &name, QObject *parent)
/*!
\fn QDnsLookup::QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, QObject *parent)
\since 5.4
- Constructs a QDnsLookup object for the given \a type, \a name and
- \a nameserver and sets \a parent as the parent object.
+
+ Constructs a QDnsLookup object to issue a query for \a name of record type
+ \a type, using the DNS server \a nameserver running on the default DNS port,
+ and sets \a parent as the parent object.
*/
QDnsLookup::QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, QObject *parent)
+ : QDnsLookup(type, name, nameserver, DnsPort, parent)
+{
+}
+
+/*!
+ \fn QDnsLookup::QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, quint16 port, QObject *parent)
+ \since 6.6
+
+ Constructs a QDnsLookup object to issue a query for \a name of record type
+ \a type, using the DNS server \a nameserver running on port \a port, and
+ sets \a parent as the parent object.
+
+//! [nameserver-port]
+ \note Setting the port number to any value other than the default (53) can
+ cause the name resolution to fail, depending on the operating system
+ limitations and firewalls. Notably, the Windows API used by QDnsLookup is
+ unable to handle alternate port numbers.
+//! [nameserver-port]
+*/
+QDnsLookup::QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, quint16 port, QObject *parent)
: QObject(*new QDnsLookupPrivate, parent)
{
Q_D(QDnsLookup);
- qRegisterMetaType<QDnsLookupReply>();
d->name = name;
d->type = type;
+ d->port = port;
d->nameserver = nameserver;
}
@@ -344,6 +343,10 @@ bool QDnsLookup::isFinished() const
\property QDnsLookup::name
\brief the name to lookup.
+ If the name to look up is empty, QDnsLookup will attempt to resolve the
+ root domain of DNS. That query is usually performed with QDnsLookup::type
+ set to \l{QDnsLookup::Type}{NS}.
+
\note The name will be encoded using IDNA, which means it's unsuitable for
querying SRV records compatible with the DNS-SD specification.
*/
@@ -356,10 +359,13 @@ QString QDnsLookup::name() const
void QDnsLookup::setName(const QString &name)
{
Q_D(QDnsLookup);
- if (name != d->name) {
- d->name = name;
- emit nameChanged(name);
- }
+ d->name = name;
+}
+
+QBindable<QString> QDnsLookup::bindableName()
+{
+ Q_D(QDnsLookup);
+ return &d->name;
}
/*!
@@ -375,10 +381,13 @@ QDnsLookup::Type QDnsLookup::type() const
void QDnsLookup::setType(Type type)
{
Q_D(QDnsLookup);
- if (type != d->type) {
- d->type = type;
- emit typeChanged(type);
- }
+ d->type = type;
+}
+
+QBindable<QDnsLookup::Type> QDnsLookup::bindableType()
+{
+ Q_D(QDnsLookup);
+ return &d->type;
}
/*!
@@ -394,10 +403,53 @@ QHostAddress QDnsLookup::nameserver() const
void QDnsLookup::setNameserver(const QHostAddress &nameserver)
{
Q_D(QDnsLookup);
- if (nameserver != d->nameserver) {
- d->nameserver = nameserver;
- emit nameserverChanged(nameserver);
- }
+ d->nameserver = nameserver;
+}
+
+QBindable<QHostAddress> QDnsLookup::bindableNameserver()
+{
+ Q_D(QDnsLookup);
+ return &d->nameserver;
+}
+
+/*!
+ \property QDnsLookup::nameserverPort
+ \since 6.6
+ \brief the port number of nameserver to use for DNS lookup.
+ \include qdnslookup.cpp nameserver-port
+*/
+
+quint16 QDnsLookup::nameserverPort() const
+{
+ return d_func()->port;
+}
+
+void QDnsLookup::setNameserverPort(quint16 nameserverPort)
+{
+ Q_D(QDnsLookup);
+ d->port = nameserverPort;
+}
+
+QBindable<quint16> QDnsLookup::bindableNameserverPort()
+{
+ Q_D(QDnsLookup);
+ return &d->port;
+}
+
+/*!
+ \since 6.6
+ Sets the nameserver to \a nameserver and the port to \a port.
+
+ \include qdnslookup.cpp nameserver-port
+
+ \sa QDnsLookup::nameserver, QDnsLookup::nameserverPort
+*/
+void QDnsLookup::setNameserver(const QHostAddress &nameserver, quint16 port)
+{
+ Qt::beginPropertyUpdateGroup();
+ setNameserver(nameserver);
+ setNameserverPort(port);
+ Qt::endPropertyUpdateGroup();
}
/*!
@@ -501,13 +553,29 @@ void QDnsLookup::lookup()
Q_D(QDnsLookup);
d->isFinished = false;
d->reply = QDnsLookupReply();
- d->runnable = new QDnsLookupRunnable(d->type, QUrl::toAce(d->name), d->nameserver);
- connect(d->runnable, SIGNAL(finished(QDnsLookupReply)),
- this, SLOT(_q_lookupFinished(QDnsLookupReply)),
- Qt::BlockingQueuedConnection);
-#if QT_CONFIG(thread)
- theDnsLookupThreadPool()->start(d->runnable);
+ if (!QCoreApplication::instance()) {
+ // NOT qCWarning because this isn't a result of the lookup
+ qWarning("QDnsLookup requires a QCoreApplication");
+ return;
+ }
+
+ auto l = [this](const QDnsLookupReply &reply) {
+ Q_D(QDnsLookup);
+ if (d->runnable == sender()) {
+#ifdef QDNSLOOKUP_DEBUG
+ qDebug("DNS reply for %s: %i (%s)", qPrintable(d->name), reply.error, qPrintable(reply.errorString));
#endif
+ d->reply = reply;
+ d->runnable = nullptr;
+ d->isFinished = true;
+ emit finished();
+ }
+ };
+
+ d->runnable = new QDnsLookupRunnable(d);
+ connect(d->runnable, &QDnsLookupRunnable::finished, this, l,
+ Qt::BlockingQueuedConnection);
+ theDnsLookupThreadPool->start(d->runnable);
}
/*!
@@ -984,18 +1052,26 @@ QDnsTextRecord &QDnsTextRecord::operator=(const QDnsTextRecord &other)
very fast and never fails.
*/
-void QDnsLookupPrivate::_q_lookupFinished(const QDnsLookupReply &_reply)
+static QDnsLookupRunnable::EncodedLabel encodeLabel(const QString &label)
{
- Q_Q(QDnsLookup);
- if (runnable == q->sender()) {
-#ifdef QDNSLOOKUP_DEBUG
- qDebug("DNS reply for %s: %i (%s)", qPrintable(name), _reply.error, qPrintable(_reply.errorString));
+ QDnsLookupRunnable::EncodedLabel::value_type rootDomain = u'.';
+ if (label.isEmpty())
+ return QDnsLookupRunnable::EncodedLabel(1, rootDomain);
+
+ QString encodedLabel = qt_ACE_do(label, ToAceOnly, ForbidLeadingDot);
+#ifdef Q_OS_WIN
+ return encodedLabel;
+#else
+ return std::move(encodedLabel).toLatin1();
#endif
- reply = _reply;
- runnable = nullptr;
- isFinished = true;
- emit q->finished();
- }
+}
+
+inline QDnsLookupRunnable::QDnsLookupRunnable(const QDnsLookupPrivate *d)
+ : requestName(encodeLabel(d->name)),
+ nameserver(d->nameserver),
+ requestType(d->type),
+ port(d->port)
+{
}
void QDnsLookupRunnable::run()
@@ -1003,60 +1079,54 @@ void QDnsLookupRunnable::run()
QDnsLookupReply reply;
// Validate input.
- if (requestName.isEmpty()) {
+ if (qsizetype n = requestName.size(); n > MaxDomainNameLength || n == 0) {
reply.error = QDnsLookup::InvalidRequestError;
- reply.errorString = tr("Invalid domain name");
- emit finished(reply);
- return;
+ reply.errorString = QDnsLookup::tr("Invalid domain name");
+ } else {
+ // Perform request.
+ query(&reply);
+
+ // Sort results.
+ qt_qdnsmailexchangerecord_sort(reply.mailExchangeRecords);
+ qt_qdnsservicerecord_sort(reply.serviceRecords);
}
- // Perform request.
- query(requestType, requestName, nameserver, &reply);
-
- // Sort results.
- qt_qdnsmailexchangerecord_sort(reply.mailExchangeRecords);
- qt_qdnsservicerecord_sort(reply.serviceRecords);
-
emit finished(reply);
-}
-
-#if QT_CONFIG(thread)
-QDnsLookupThreadPool::QDnsLookupThreadPool()
- : signalsConnected(false)
-{
- // Run up to 5 lookups in parallel.
- setMaxThreadCount(5);
-}
-
-void QDnsLookupThreadPool::start(QRunnable *runnable)
-{
- // Ensure threads complete at application destruction.
- if (!signalsConnected) {
- QMutexLocker signalsLocker(&signalsMutex);
- if (!signalsConnected) {
- QCoreApplication *app = QCoreApplication::instance();
- if (!app) {
- qWarning("QDnsLookup requires a QCoreApplication");
- delete runnable;
- return;
- }
- moveToThread(app->thread());
- connect(app, SIGNAL(destroyed()),
- SLOT(_q_applicationDestroyed()), Qt::DirectConnection);
- signalsConnected = true;
- }
+ // maybe print the lookup error as warning
+ switch (reply.error) {
+ case QDnsLookup::NoError:
+ case QDnsLookup::OperationCancelledError:
+ case QDnsLookup::NotFoundError:
+ case QDnsLookup::ServerFailureError:
+ case QDnsLookup::ServerRefusedError:
+ case QDnsLookup::TimeoutError:
+ break; // no warning for these
+
+ case QDnsLookup::ResolverError:
+ case QDnsLookup::InvalidRequestError:
+ case QDnsLookup::InvalidReplyError:
+ qCWarning(lcDnsLookup()).nospace()
+ << "DNS lookup failed (" << reply.error << "): "
+ << qUtf16Printable(reply.errorString)
+ << "; request was " << this; // continues below
}
-
- QThreadPool::start(runnable);
}
-void QDnsLookupThreadPool::_q_applicationDestroyed()
+inline QDebug operator<<(QDebug &d, QDnsLookupRunnable *r)
{
- waitForDone();
- signalsConnected = false;
+ // continued: print the information about the request
+ d << r->requestName.left(MaxDomainNameLength);
+ if (r->requestName.size() > MaxDomainNameLength)
+ d << "... (truncated)";
+ d << " type " << r->requestType;
+ if (!r->nameserver.isNull())
+ d << " to nameserver " << qUtf16Printable(r->nameserver.toString())
+ << " port " << (r->port ? r->port : DnsPort);
+ return d;
}
-#endif // QT_CONFIG(thread)
+
QT_END_NAMESPACE
#include "moc_qdnslookup.cpp"
+#include "moc_qdnslookup_p.cpp"
diff --git a/src/network/kernel/qdnslookup.h b/src/network/kernel/qdnslookup.h
index 110a74da44..ae89a0a11f 100644
--- a/src/network/kernel/qdnslookup.h
+++ b/src/network/kernel/qdnslookup.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 Jeremy Lainé <jeremy.laine@m4x.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2012 Jeremy Lainé <jeremy.laine@m4x.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDNSLOOKUP_H
#define QDNSLOOKUP_H
@@ -44,8 +8,8 @@
#include <QtCore/qlist.h>
#include <QtCore/qobject.h>
#include <QtCore/qshareddata.h>
-#include <QtCore/qsharedpointer.h>
#include <QtCore/qstring.h>
+#include <QtCore/qproperty.h>
QT_REQUIRE_CONFIG(dnslookup);
@@ -68,7 +32,7 @@ public:
QDnsDomainNameRecord &operator=(const QDnsDomainNameRecord &other);
~QDnsDomainNameRecord();
- void swap(QDnsDomainNameRecord &other) noexcept { qSwap(d, other.d); }
+ void swap(QDnsDomainNameRecord &other) noexcept { d.swap(other.d); }
QString name() const;
quint32 timeToLive() const;
@@ -90,7 +54,7 @@ public:
QDnsHostAddressRecord &operator=(const QDnsHostAddressRecord &other);
~QDnsHostAddressRecord();
- void swap(QDnsHostAddressRecord &other) noexcept { qSwap(d, other.d); }
+ void swap(QDnsHostAddressRecord &other) noexcept { d.swap(other.d); }
QString name() const;
quint32 timeToLive() const;
@@ -112,7 +76,7 @@ public:
QDnsMailExchangeRecord &operator=(const QDnsMailExchangeRecord &other);
~QDnsMailExchangeRecord();
- void swap(QDnsMailExchangeRecord &other) noexcept { qSwap(d, other.d); }
+ void swap(QDnsMailExchangeRecord &other) noexcept { d.swap(other.d); }
QString exchange() const;
QString name() const;
@@ -135,7 +99,7 @@ public:
QDnsServiceRecord &operator=(const QDnsServiceRecord &other);
~QDnsServiceRecord();
- void swap(QDnsServiceRecord &other) noexcept { qSwap(d, other.d); }
+ void swap(QDnsServiceRecord &other) noexcept { d.swap(other.d); }
QString name() const;
quint16 port() const;
@@ -160,7 +124,7 @@ public:
QDnsTextRecord &operator=(const QDnsTextRecord &other);
~QDnsTextRecord();
- void swap(QDnsTextRecord &other) noexcept { qSwap(d, other.d); }
+ void swap(QDnsTextRecord &other) noexcept { d.swap(other.d); }
QString name() const;
quint32 timeToLive() const;
@@ -178,9 +142,12 @@ class Q_NETWORK_EXPORT QDnsLookup : public QObject
Q_OBJECT
Q_PROPERTY(Error error READ error NOTIFY finished)
Q_PROPERTY(QString errorString READ errorString NOTIFY finished)
- Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
- Q_PROPERTY(Type type READ type WRITE setType NOTIFY typeChanged)
- Q_PROPERTY(QHostAddress nameserver READ nameserver WRITE setNameserver NOTIFY nameserverChanged)
+ Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged BINDABLE bindableName)
+ Q_PROPERTY(Type type READ type WRITE setType NOTIFY typeChanged BINDABLE bindableType)
+ Q_PROPERTY(QHostAddress nameserver READ nameserver WRITE setNameserver NOTIFY nameserverChanged
+ BINDABLE bindableNameserver)
+ Q_PROPERTY(quint16 nameserverPort READ nameserverPort WRITE setNameserverPort
+ NOTIFY nameserverPortChanged BINDABLE bindableNameserverPort)
public:
enum Error
@@ -192,7 +159,8 @@ public:
InvalidReplyError,
ServerFailureError,
ServerRefusedError,
- NotFoundError
+ NotFoundError,
+ TimeoutError,
};
Q_ENUM(Error)
@@ -213,6 +181,8 @@ public:
explicit QDnsLookup(QObject *parent = nullptr);
QDnsLookup(Type type, const QString &name, QObject *parent = nullptr);
QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, QObject *parent = nullptr);
+ QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, quint16 port,
+ QObject *parent = nullptr);
~QDnsLookup();
Error error() const;
@@ -221,12 +191,19 @@ public:
QString name() const;
void setName(const QString &name);
+ QBindable<QString> bindableName();
Type type() const;
void setType(QDnsLookup::Type);
+ QBindable<Type> bindableType();
QHostAddress nameserver() const;
void setNameserver(const QHostAddress &nameserver);
+ QBindable<QHostAddress> bindableNameserver();
+ quint16 nameserverPort() const;
+ void setNameserverPort(quint16 port);
+ QBindable<quint16> bindableNameserverPort();
+ void setNameserver(const QHostAddress &nameserver, quint16 port);
QList<QDnsDomainNameRecord> canonicalNameRecords() const;
QList<QDnsHostAddressRecord> hostAddressRecords() const;
@@ -246,10 +223,10 @@ Q_SIGNALS:
void nameChanged(const QString &name);
void typeChanged(Type type);
void nameserverChanged(const QHostAddress &nameserver);
+ void nameserverPortChanged(quint16 port);
private:
Q_DECLARE_PRIVATE(QDnsLookup)
- Q_PRIVATE_SLOT(d_func(), void _q_lookupFinished(const QDnsLookupReply &reply))
};
QT_END_NAMESPACE
diff --git a/src/network/kernel/qdnslookup_android.cpp b/src/network/kernel/qdnslookup_android.cpp
deleted file mode 100644
index 131fc56298..0000000000
--- a/src/network/kernel/qdnslookup_android.cpp
+++ /dev/null
@@ -1,56 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 Collabora Ltd, author <robin.burchell@collabora.co.uk>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qdnslookup_p.h"
-
-QT_BEGIN_NAMESPACE
-
-void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestName, const QHostAddress &nameserver, QDnsLookupReply *reply)
-{
- Q_UNUSED(requestType);
- Q_UNUSED(requestName);
- Q_UNUSED(nameserver);
- Q_UNUSED(reply);
- qWarning("Not yet supported on Android");
- reply->error = QDnsLookup::ResolverError;
- reply->errorString = tr("Not yet supported on Android");
- return;
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/kernel/qdnslookup_dummy.cpp b/src/network/kernel/qdnslookup_dummy.cpp
new file mode 100644
index 0000000000..6cc6ed92c5
--- /dev/null
+++ b/src/network/kernel/qdnslookup_dummy.cpp
@@ -0,0 +1,15 @@
+// Copyright (C) 2012 Collabora Ltd, author <robin.burchell@collabora.co.uk>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qdnslookup_p.h"
+
+QT_BEGIN_NAMESPACE
+
+void QDnsLookupRunnable::query(QDnsLookupReply *reply)
+{
+ reply->error = QDnsLookup::ResolverError;
+ reply->errorString = tr("Not yet supported on this OS");
+ return;
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/kernel/qdnslookup_p.h b/src/network/kernel/qdnslookup_p.h
index 8c3c2ed3e1..da4721411b 100644
--- a/src/network/kernel/qdnslookup_p.h
+++ b/src/network/kernel/qdnslookup_p.h
@@ -1,41 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 Jeremy Lainé <jeremy.laine@m4x.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2012 Jeremy Lainé <jeremy.laine@m4x.org>
+// Copyright (C) 2023 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDNSLOOKUP_P_H
#define QDNSLOOKUP_P_H
@@ -54,13 +19,13 @@
#include <QtNetwork/private/qtnetworkglobal_p.h>
#include "QtCore/qmutex.h"
#include "QtCore/qrunnable.h"
-#include "QtCore/qsharedpointer.h"
#if QT_CONFIG(thread)
#include "QtCore/qthreadpool.h"
#endif
#include "QtNetwork/qdnslookup.h"
#include "QtNetwork/qhostaddress.h"
#include "private/qobject_p.h"
+#include "private/qurl_p.h"
QT_REQUIRE_CONFIG(dnslookup);
@@ -68,16 +33,16 @@ QT_BEGIN_NAMESPACE
//#define QDNSLOOKUP_DEBUG
+constexpr qsizetype MaxDomainNameLength = 255;
+constexpr quint16 DnsPort = 53;
+
class QDnsLookupRunnable;
+QDebug operator<<(QDebug &, QDnsLookupRunnable *);
class QDnsLookupReply
{
public:
- QDnsLookupReply()
- : error(QDnsLookup::NoError)
- { }
-
- QDnsLookup::Error error;
+ QDnsLookup::Error error = QDnsLookup::NoError;
QString errorString;
QList<QDnsDomainNameRecord> canonicalNameRecords;
@@ -87,27 +52,120 @@ public:
QList<QDnsDomainNameRecord> pointerRecords;
QList<QDnsServiceRecord> serviceRecords;
QList<QDnsTextRecord> textRecords;
+
+ // helper methods
+ void setError(QDnsLookup::Error err, QString &&msg)
+ {
+ error = err;
+ errorString = std::move(msg);
+ }
+
+ void makeResolverSystemError(int code = -1)
+ {
+ Q_ASSERT(allAreEmpty());
+ setError(QDnsLookup::ResolverError, qt_error_string(code));
+ }
+
+ void makeTimeoutError()
+ {
+ Q_ASSERT(allAreEmpty());
+ setError(QDnsLookup::TimeoutError, QDnsLookup::tr("Request timed out"));
+ }
+
+ void makeDnsRcodeError(quint8 rcode)
+ {
+ Q_ASSERT(allAreEmpty());
+ switch (rcode) {
+ case 1: // FORMERR
+ error = QDnsLookup::InvalidRequestError;
+ errorString = QDnsLookup::tr("Server could not process query");
+ return;
+ case 2: // SERVFAIL
+ case 4: // NOTIMP
+ error = QDnsLookup::ServerFailureError;
+ errorString = QDnsLookup::tr("Server failure");
+ return;
+ case 3: // NXDOMAIN
+ error = QDnsLookup::NotFoundError;
+ errorString = QDnsLookup::tr("Non existent domain");
+ return;
+ case 5: // REFUSED
+ error = QDnsLookup::ServerRefusedError;
+ errorString = QDnsLookup::tr("Server refused to answer");
+ return;
+ default:
+ error = QDnsLookup::InvalidReplyError;
+ errorString = QDnsLookup::tr("Invalid reply received (rcode %1)")
+ .arg(rcode);
+ return;
+ }
+ }
+
+ void makeInvalidReplyError(QString &&msg = QString())
+ {
+ if (msg.isEmpty())
+ msg = QDnsLookup::tr("Invalid reply received");
+ else
+ msg = QDnsLookup::tr("Invalid reply received (%1)").arg(std::move(msg));
+ *this = QDnsLookupReply(); // empty our lists
+ setError(QDnsLookup::InvalidReplyError, std::move(msg));
+ }
+
+private:
+ bool allAreEmpty() const
+ {
+ return canonicalNameRecords.isEmpty()
+ && hostAddressRecords.isEmpty()
+ && mailExchangeRecords.isEmpty()
+ && nameServerRecords.isEmpty()
+ && pointerRecords.isEmpty()
+ && serviceRecords.isEmpty()
+ && textRecords.isEmpty();
+ }
};
class QDnsLookupPrivate : public QObjectPrivate
{
public:
QDnsLookupPrivate()
- : isFinished(false)
- , type(QDnsLookup::A)
- , runnable(nullptr)
+ : type(QDnsLookup::A)
+ , port(DnsPort)
{ }
- void _q_lookupFinished(const QDnsLookupReply &reply);
+ void nameChanged()
+ {
+ emit q_func()->nameChanged(name);
+ }
+ Q_OBJECT_BINDABLE_PROPERTY(QDnsLookupPrivate, QString, name,
+ &QDnsLookupPrivate::nameChanged);
+
+ void nameserverChanged()
+ {
+ emit q_func()->nameserverChanged(nameserver);
+ }
+ Q_OBJECT_BINDABLE_PROPERTY(QDnsLookupPrivate, QHostAddress, nameserver,
+ &QDnsLookupPrivate::nameserverChanged);
+
+ void typeChanged()
+ {
+ emit q_func()->typeChanged(type);
+ }
+
+ Q_OBJECT_BINDABLE_PROPERTY(QDnsLookupPrivate, QDnsLookup::Type,
+ type, &QDnsLookupPrivate::typeChanged);
+
+ void nameserverPortChanged()
+ {
+ emit q_func()->nameserverPortChanged(port);
+ }
+
+ Q_OBJECT_BINDABLE_PROPERTY(QDnsLookupPrivate, quint16,
+ port, &QDnsLookupPrivate::nameserverPortChanged);
- static const char *msgNoIpV6NameServerAdresses;
- bool isFinished;
- QString name;
- QDnsLookup::Type type;
- QHostAddress nameserver;
QDnsLookupReply reply;
- QDnsLookupRunnable *runnable;
+ QDnsLookupRunnable *runnable = nullptr;
+ bool isFinished = false;
Q_DECLARE_PUBLIC(QDnsLookup)
};
@@ -117,40 +175,31 @@ class QDnsLookupRunnable : public QObject, public QRunnable
Q_OBJECT
public:
- QDnsLookupRunnable(QDnsLookup::Type type, const QByteArray &name, const QHostAddress &nameserver)
- : requestType(type)
- , requestName(name)
- , nameserver(nameserver)
- { }
+#ifdef Q_OS_WIN
+ using EncodedLabel = QString;
+#else
+ using EncodedLabel = QByteArray;
+#endif
+
+ QDnsLookupRunnable(const QDnsLookupPrivate *d);
void run() override;
signals:
void finished(const QDnsLookupReply &reply);
private:
- static void query(const int requestType, const QByteArray &requestName, const QHostAddress &nameserver, QDnsLookupReply *reply);
- QDnsLookup::Type requestType;
- QByteArray requestName;
- QHostAddress nameserver;
-};
-
-#if QT_CONFIG(thread)
-class QDnsLookupThreadPool : public QThreadPool
-{
- Q_OBJECT
+ template <typename T> static QString decodeLabel(T encodedLabel)
+ {
+ return qt_ACE_do(encodedLabel.toString(), NormalizeAce, ForbidLeadingDot);
+ }
+ void query(QDnsLookupReply *reply);
-public:
- QDnsLookupThreadPool();
- void start(QRunnable *runnable);
-
-private slots:
- void _q_applicationDestroyed();
-
-private:
- QMutex signalsMutex;
- bool signalsConnected;
+ EncodedLabel requestName;
+ QHostAddress nameserver;
+ QDnsLookup::Type requestType;
+ quint16 port;
+ friend QDebug operator<<(QDebug &, QDnsLookupRunnable *);
};
-#endif // QT_CONFIG(thread)
class QDnsRecordPrivate : public QSharedData
{
@@ -218,6 +267,4 @@ public:
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QDnsLookupReply)
-
#endif // QDNSLOOKUP_P_H
diff --git a/src/network/kernel/qdnslookup_unix.cpp b/src/network/kernel/qdnslookup_unix.cpp
index 1449c32937..5696a3ca70 100644
--- a/src/network/kernel/qdnslookup_unix.cpp
+++ b/src/network/kernel/qdnslookup_unix.cpp
@@ -1,421 +1,392 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 Jeremy Lainé <jeremy.laine@m4x.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2012 Jeremy Lainé <jeremy.laine@m4x.org>
+// Copyright (C) 2023 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdnslookup_p.h"
-#if QT_CONFIG(library)
-#include <qlibrary.h>
-#endif
-#include <qvarlengtharray.h>
+#include <qendian.h>
#include <qscopedpointer.h>
#include <qurl.h>
-#include <private/qnativesocketengine_p.h>
+#include <qvarlengtharray.h>
+#include <private/qnativesocketengine_p.h> // for setSockAddr
+#include <private/qtnetwork-config_p.h>
+
+QT_REQUIRE_CONFIG(libresolv);
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
-#if !defined(Q_OS_OPENBSD)
+#if __has_include(<arpa/nameser_compat.h>)
# include <arpa/nameser_compat.h>
#endif
+#include <errno.h>
#include <resolv.h>
-#if defined(__GNU_LIBRARY__) && !defined(__UCLIBC__)
-# include <gnu/lib-names.h>
-#endif
+#include <array>
-#if defined(Q_OS_FREEBSD) || QT_CONFIG(dlopen)
-# include <dlfcn.h>
+#ifndef T_OPT
+// the older arpa/nameser_compat.h wasn't updated between 1999 and 2016 in glibc
+# define T_OPT ns_t_opt
#endif
-#include <cstring>
-
QT_BEGIN_NAMESPACE
-#if QT_CONFIG(library)
+using namespace Qt::StringLiterals;
-#if defined(Q_OS_OPENBSD)
-typedef struct __res_state* res_state;
-#endif
-typedef int (*dn_expand_proto)(const unsigned char *, const unsigned char *, const unsigned char *, char *, int);
-static dn_expand_proto local_dn_expand = nullptr;
-typedef void (*res_nclose_proto)(res_state);
-static res_nclose_proto local_res_nclose = nullptr;
-typedef int (*res_ninit_proto)(res_state);
-static res_ninit_proto local_res_ninit = nullptr;
-typedef int (*res_nquery_proto)(res_state, const char *, int, int, unsigned char *, int);
-static res_nquery_proto local_res_nquery = nullptr;
-
-// Custom deleter to close resolver state.
-
-struct QDnsLookupStateDeleter
-{
- static inline void cleanup(struct __res_state *pointer)
- {
- local_res_nclose(pointer);
- }
+// minimum IPv6 MTU (1280) minus the IPv6 (40) and UDP headers (8)
+static constexpr qsizetype ReplyBufferSize = 1280 - 40 - 8;
+
+// https://www.rfc-editor.org/rfc/rfc6891
+static constexpr unsigned char Edns0Record[] = {
+ 0x00, // root label
+ T_OPT >> 8, T_OPT & 0xff, // type OPT
+ ReplyBufferSize >> 8, ReplyBufferSize & 0xff, // payload size
+ NOERROR, // extended rcode
+ 0, // version
+ 0x00, 0x00, // flags
+ 0x00, 0x00, // option length
};
-static QFunctionPointer resolveSymbol(QLibrary &lib, const char *sym)
-{
- if (lib.isLoaded())
- return lib.resolve(sym);
+// maximum length of a EDNS0 query with a 255-character domain (rounded up to 16)
+static constexpr qsizetype QueryBufferSize =
+ HFIXEDSZ + QFIXEDSZ + MAXCDNAME + 1 + sizeof(Edns0Record);
+using QueryBuffer = std::array<unsigned char, (QueryBufferSize + 15) / 16 * 16>;
-#if defined(RTLD_DEFAULT) && (defined(Q_OS_FREEBSD) || QT_CONFIG(dlopen))
- return reinterpret_cast<QFunctionPointer>(dlsym(RTLD_DEFAULT, sym));
-#else
- return nullptr;
-#endif
+namespace {
+struct QDnsCachedName
+{
+ QString name;
+ int code = 0;
+ QDnsCachedName(const QString &name, int code) : name(name), code(code) {}
+};
}
+Q_DECLARE_TYPEINFO(QDnsCachedName, Q_RELOCATABLE_TYPE);
+using Cache = QList<QDnsCachedName>; // QHash or QMap are overkill
-static bool resolveLibraryInternal()
+#if QT_CONFIG(res_setservers)
+// https://www.ibm.com/docs/en/i/7.3?topic=ssw_ibm_i_73/apis/ressetservers.html
+// https://docs.oracle.com/cd/E86824_01/html/E54774/res-setservers-3resolv.html
+static bool applyNameServer(res_state state, const QHostAddress &nameserver, quint16 port)
{
- QLibrary lib;
-#ifdef LIBRESOLV_SO
- lib.setFileName(QStringLiteral(LIBRESOLV_SO));
- if (!lib.load())
-#endif
- {
- lib.setFileName(QLatin1String("resolv"));
- lib.load();
+ if (!nameserver.isNull()) {
+ union res_sockaddr_union u;
+ setSockaddr(reinterpret_cast<sockaddr *>(&u.sin), nameserver, port);
+ res_setservers(state, &u, 1);
}
+ return true;
+}
+#else
+template <typename T> void setNsMap(T &ext, std::enable_if_t<sizeof(T::nsmap) != 0, uint16_t> v)
+{
+ // Set nsmap[] to indicate that nsaddrs[0] is an IPv6 address
+ // See: https://sourceware.org/ml/libc-hacker/2002-05/msg00035.html
+ // Unneeded since glibc 2.22 (2015), but doesn't hurt to set it
+ // See: https://sourceware.org/git/?p=glibc.git;a=commit;h=2212c1420c92a33b0e0bd9a34938c9814a56c0f7
+ ext.nsmap[0] = v;
+}
+template <typename T> void setNsMap(T &, ...)
+{
+ // fallback
+}
- local_dn_expand = dn_expand_proto(resolveSymbol(lib, "__dn_expand"));
- if (!local_dn_expand)
- local_dn_expand = dn_expand_proto(resolveSymbol(lib, "dn_expand"));
+template <bool Condition>
+using EnableIfIPv6 = std::enable_if_t<Condition, const QHostAddress *>;
- local_res_nclose = res_nclose_proto(resolveSymbol(lib, "__res_nclose"));
- if (!local_res_nclose)
- local_res_nclose = res_nclose_proto(resolveSymbol(lib, "res_9_nclose"));
- if (!local_res_nclose)
- local_res_nclose = res_nclose_proto(resolveSymbol(lib, "res_nclose"));
+template <typename State>
+bool setIpv6NameServer(State *state,
+ EnableIfIPv6<sizeof(std::declval<State>()._u._ext.nsaddrs) != 0> addr,
+ quint16 port)
+{
+ // glibc-like API to set IPv6 name servers
+ struct sockaddr_in6 *ns = state->_u._ext.nsaddrs[0];
+
+ // nsaddrs will be NULL if no nameserver is set in /etc/resolv.conf
+ if (!ns) {
+ // Memory allocated here will be free()'d in res_close() as we
+ // have done res_init() above.
+ ns = static_cast<struct sockaddr_in6*>(calloc(1, sizeof(struct sockaddr_in6)));
+ Q_CHECK_PTR(ns);
+ state->_u._ext.nsaddrs[0] = ns;
+ }
- local_res_ninit = res_ninit_proto(resolveSymbol(lib, "__res_ninit"));
- if (!local_res_ninit)
- local_res_ninit = res_ninit_proto(resolveSymbol(lib, "res_9_ninit"));
- if (!local_res_ninit)
- local_res_ninit = res_ninit_proto(resolveSymbol(lib, "res_ninit"));
+ setNsMap(state->_u._ext, MAXNS + 1);
+ state->_u._ext.nscount6 = 1;
+ setSockaddr(ns, *addr, port);
+ return true;
+}
- local_res_nquery = res_nquery_proto(resolveSymbol(lib, "__res_nquery"));
- if (!local_res_nquery)
- local_res_nquery = res_nquery_proto(resolveSymbol(lib, "res_9_nquery"));
- if (!local_res_nquery)
- local_res_nquery = res_nquery_proto(resolveSymbol(lib, "res_nquery"));
+template <typename State> bool setIpv6NameServer(State *, const void *, quint16)
+{
+ // fallback
+ return false;
+}
+static bool applyNameServer(res_state state, const QHostAddress &nameserver, quint16 port)
+{
+ if (nameserver.isNull())
+ return true;
+
+ state->nscount = 1;
+ state->nsaddr_list[0].sin_family = AF_UNSPEC;
+ if (nameserver.protocol() == QAbstractSocket::IPv6Protocol)
+ return setIpv6NameServer(state, &nameserver, port);
+ setSockaddr(&state->nsaddr_list[0], nameserver, port);
return true;
}
-Q_GLOBAL_STATIC_WITH_ARGS(bool, resolveLibrary, (resolveLibraryInternal()))
+#endif // !QT_CONFIG(res_setservers)
-void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestName, const QHostAddress &nameserver, QDnsLookupReply *reply)
+static int
+prepareQueryBuffer(res_state state, QueryBuffer &buffer, const char *label, ns_rcode type)
{
- // Load dn_expand, res_ninit and res_nquery on demand.
- resolveLibrary();
-
- // If dn_expand, res_ninit or res_nquery is missing, fail.
- if (!local_dn_expand || !local_res_nclose || !local_res_ninit || !local_res_nquery) {
- reply->error = QDnsLookup::ResolverError;
- reply->errorString = tr("Resolver functions not found");
- return;
- }
+ // Create header and our query
+ int queryLength = res_nmkquery(state, QUERY, label, C_IN, type, nullptr, 0, nullptr,
+ buffer.data(), buffer.size());
+ Q_ASSERT(queryLength < int(buffer.size()));
+ if (Q_UNLIKELY(queryLength < 0))
+ return queryLength;
+
+ // Append EDNS0 record and set the number of additional RRs to 1
+ Q_ASSERT(queryLength + sizeof(Edns0Record) < buffer.size());
+ std::copy_n(std::begin(Edns0Record), sizeof(Edns0Record), buffer.begin() + queryLength);
+ reinterpret_cast<HEADER *>(buffer.data())->arcount = qToBigEndian<quint16>(1);
+
+ return queryLength + sizeof(Edns0Record);
+}
+void QDnsLookupRunnable::query(QDnsLookupReply *reply)
+{
// Initialize state.
- struct __res_state state;
- std::memset(&state, 0, sizeof(state));
- if (local_res_ninit(&state) < 0) {
- reply->error = QDnsLookup::ResolverError;
- reply->errorString = tr("Resolver initialization failed");
- return;
+ std::remove_pointer_t<res_state> state = {};
+ if (res_ninit(&state) < 0) {
+ int error = errno;
+ qErrnoWarning(error, "QDnsLookup: Resolver initialization failed");
+ return reply->makeResolverSystemError(error);
}
+ auto guard = qScopeGuard([&] { res_nclose(&state); });
//Check if a nameserver was set. If so, use it
- if (!nameserver.isNull()) {
- if (nameserver.protocol() == QAbstractSocket::IPv4Protocol) {
- state.nsaddr_list[0].sin_addr.s_addr = htonl(nameserver.toIPv4Address());
- state.nscount = 1;
- } else if (nameserver.protocol() == QAbstractSocket::IPv6Protocol) {
-#if defined(Q_OS_LINUX)
- struct sockaddr_in6 *ns;
- ns = state._u._ext.nsaddrs[0];
- // nsaddrs will be NULL if no nameserver is set in /etc/resolv.conf
- if (!ns) {
- // Memory allocated here will be free'd in res_close() as we
- // have done res_init() above.
- ns = (struct sockaddr_in6*) calloc(1, sizeof(struct sockaddr_in6));
- Q_CHECK_PTR(ns);
- state._u._ext.nsaddrs[0] = ns;
- }
-#ifndef __UCLIBC__
- // Set nsmap[] to indicate that nsaddrs[0] is an IPv6 address
- // See: https://sourceware.org/ml/libc-hacker/2002-05/msg00035.html
- state._u._ext.nsmap[0] = MAXNS + 1;
-#endif
- state._u._ext.nscount6 = 1;
- ns->sin6_family = AF_INET6;
- ns->sin6_port = htons(53);
- SetSALen::set(ns, sizeof(*ns));
-
- Q_IPV6ADDR ipv6Address = nameserver.toIPv6Address();
- for (int i=0; i<16; i++) {
- ns->sin6_addr.s6_addr[i] = ipv6Address[i];
- }
-#else
- qWarning("%s", QDnsLookupPrivate::msgNoIpV6NameServerAdresses);
- reply->error = QDnsLookup::ResolverError;
- reply->errorString = tr(QDnsLookupPrivate::msgNoIpV6NameServerAdresses);
- return;
-#endif
- }
- }
+ if (!applyNameServer(&state, nameserver, port))
+ return reply->setError(QDnsLookup::ResolverError,
+ QDnsLookup::tr("IPv6 nameservers are currently not supported on this OS"));
#ifdef QDNSLOOKUP_DEBUG
state.options |= RES_DEBUG;
#endif
- QScopedPointer<struct __res_state, QDnsLookupStateDeleter> state_ptr(&state);
+
+ // Prepare the DNS query.
+ QueryBuffer qbuffer;
+ int queryLength = prepareQueryBuffer(&state, qbuffer, requestName.constData(), ns_rcode(requestType));
+ if (Q_UNLIKELY(queryLength < 0))
+ return reply->makeResolverSystemError();
// Perform DNS query.
- QVarLengthArray<unsigned char, PACKETSZ> buffer(PACKETSZ);
- std::memset(buffer.data(), 0, buffer.size());
- int responseLength = local_res_nquery(&state, requestName, C_IN, requestType, buffer.data(), buffer.size());
- if (Q_UNLIKELY(responseLength > PACKETSZ)) {
- buffer.resize(responseLength);
- std::memset(buffer.data(), 0, buffer.size());
- responseLength = local_res_nquery(&state, requestName, C_IN, requestType, buffer.data(), buffer.size());
+ QVarLengthArray<unsigned char, ReplyBufferSize> buffer(ReplyBufferSize);
+ auto attemptToSend = [&]() {
+ std::memset(buffer.data(), 0, HFIXEDSZ); // the header is enough
+ int responseLength = res_nsend(&state, qbuffer.data(), queryLength, buffer.data(), buffer.size());
+ if (responseLength >= 0)
+ return responseLength; // success
+
+ // libresolv uses ETIMEDOUT for resolver errors ("no answer")
+ if (errno == ECONNREFUSED)
+ reply->setError(QDnsLookup::ServerRefusedError, qt_error_string());
+ else if (errno != ETIMEDOUT)
+ reply->makeResolverSystemError(); // some other error
+
+ auto query = reinterpret_cast<HEADER *>(qbuffer.data());
+ auto header = reinterpret_cast<HEADER *>(buffer.data());
+ if (query->id == header->id && header->qr)
+ reply->makeDnsRcodeError(header->rcode);
+ else
+ reply->makeTimeoutError(); // must really be a timeout
+ return -1;
+ };
+
+ // strictly use UDP, we'll deal with truncated replies ourselves
+ state.options |= RES_IGNTC;
+ int responseLength = attemptToSend();
+ if (responseLength < 0)
+ return;
+
+ // check if we need to use the virtual circuit (TCP)
+ auto header = reinterpret_cast<HEADER *>(buffer.data());
+ if (header->rcode == NOERROR && header->tc) {
+ // yes, increase our buffer size
+ buffer.resize(std::numeric_limits<quint16>::max());
+ header = reinterpret_cast<HEADER *>(buffer.data());
+
+ // remove the EDNS record in the query
+ reinterpret_cast<HEADER *>(qbuffer.data())->arcount = 0;
+ queryLength -= sizeof(Edns0Record);
+
+ // send using the virtual circuit
+ state.options |= RES_USEVC;
+ responseLength = attemptToSend();
if (Q_UNLIKELY(responseLength > buffer.size())) {
// Ok, we give up.
- reply->error = QDnsLookup::ResolverError;
- reply->errorString.clear(); // We cannot be more specific, alas.
- return;
+ return reply->setError(QDnsLookup::ResolverError,
+ QDnsLookup::tr("Reply was too large"));
}
}
-
- unsigned char *response = buffer.data();
- // Check the response header. Though res_nquery returns -1 as a
- // responseLength in case of error, we still can extract the
- // exact error code from the response.
- HEADER *header = (HEADER*)response;
- const int answerCount = ntohs(header->ancount);
- switch (header->rcode) {
- case NOERROR:
- break;
- case FORMERR:
- reply->error = QDnsLookup::InvalidRequestError;
- reply->errorString = tr("Server could not process query");
+ if (responseLength < 0)
return;
- case SERVFAIL:
- reply->error = QDnsLookup::ServerFailureError;
- reply->errorString = tr("Server failure");
- return;
- case NXDOMAIN:
- reply->error = QDnsLookup::NotFoundError;
- reply->errorString = tr("Non existent domain");
- return;
- case REFUSED:
- reply->error = QDnsLookup::ServerRefusedError;
- reply->errorString = tr("Server refused to answer");
- return;
- default:
- reply->error = QDnsLookup::InvalidReplyError;
- reply->errorString = tr("Invalid reply received");
- return;
- }
// Check the reply is valid.
- if (responseLength < int(sizeof(HEADER))) {
- reply->error = QDnsLookup::InvalidReplyError;
- reply->errorString = tr("Invalid reply received");
- return;
- }
+ if (responseLength < int(sizeof(HEADER)))
+ return reply->makeInvalidReplyError();
- // Skip the query host, type (2 bytes) and class (2 bytes).
- char host[PACKETSZ], answer[PACKETSZ];
- unsigned char *p = response + sizeof(HEADER);
- int status = local_dn_expand(response, response + responseLength, p, host, sizeof(host));
- if (status < 0) {
- reply->error = QDnsLookup::InvalidReplyError;
- reply->errorString = tr("Could not expand domain name");
- return;
+ // Parse the reply.
+ if (header->rcode)
+ return reply->makeDnsRcodeError(header->rcode);
+
+ qptrdiff offset = sizeof(HEADER);
+ unsigned char *response = buffer.data();
+ int status;
+
+ auto expandHost = [&, cache = Cache{}](qptrdiff offset) mutable {
+ if (uchar n = response[offset]; n & NS_CMPRSFLGS) {
+ // compressed name, see if we already have it cached
+ if (offset + 1 < responseLength) {
+ int id = ((n & ~NS_CMPRSFLGS) << 8) | response[offset + 1];
+ auto it = std::find_if(cache.constBegin(), cache.constEnd(),
+ [id](const QDnsCachedName &n) { return n.code == id; });
+ if (it != cache.constEnd()) {
+ status = 2;
+ return it->name;
+ }
+ }
+ }
+
+ // uncached, expand it
+ char host[MAXCDNAME + 1];
+ status = dn_expand(response, response + responseLength, response + offset,
+ host, sizeof(host));
+ if (status >= 0)
+ return cache.emplaceBack(decodeLabel(QLatin1StringView(host)), offset).name;
+
+ // failed
+ reply->makeInvalidReplyError(QDnsLookup::tr("Could not expand domain name"));
+ return QString();
+ };
+
+ if (ntohs(header->qdcount) == 1) {
+ // Skip the query host, type (2 bytes) and class (2 bytes).
+ expandHost(offset);
+ if (status < 0)
+ return;
+ if (offset + status + 4 >= responseLength)
+ header->qdcount = 0xffff; // invalid reply below
+ else
+ offset += status + 4;
}
- p += status + 4;
+ if (ntohs(header->qdcount) > 1)
+ return reply->makeInvalidReplyError();
// Extract results.
+ const int answerCount = ntohs(header->ancount);
int answerIndex = 0;
- while ((p < response + responseLength) && (answerIndex < answerCount)) {
- status = local_dn_expand(response, response + responseLength, p, host, sizeof(host));
- if (status < 0) {
- reply->error = QDnsLookup::InvalidReplyError;
- reply->errorString = tr("Could not expand domain name");
+ while ((offset < responseLength) && (answerIndex < answerCount)) {
+ const QString name = expandHost(offset);
+ if (status < 0)
return;
- }
- const QString name = QUrl::fromAce(host);
- p += status;
- const quint16 type = (p[0] << 8) | p[1];
- p += 2; // RR type
- p += 2; // RR class
- const quint32 ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
- p += 4;
- const quint16 size = (p[0] << 8) | p[1];
- p += 2;
+ offset += status;
+ if (offset + RRFIXEDSZ > responseLength) {
+ // probably just a truncated reply, return what we have
+ return;
+ }
+ const quint16 type = qFromBigEndian<quint16>(response + offset);
+ const qint16 rrclass = qFromBigEndian<quint16>(response + offset + 2);
+ const quint32 ttl = qFromBigEndian<quint32>(response + offset + 4);
+ const quint16 size = qFromBigEndian<quint16>(response + offset + 8);
+ offset += RRFIXEDSZ;
+ if (offset + size > responseLength)
+ return; // truncated
+ if (rrclass != C_IN)
+ continue;
if (type == QDnsLookup::A) {
- if (size != 4) {
- reply->error = QDnsLookup::InvalidReplyError;
- reply->errorString = tr("Invalid IPv4 address record");
- return;
- }
- const quint32 addr = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
+ if (size != 4)
+ return reply->makeInvalidReplyError(QDnsLookup::tr("Invalid IPv4 address record"));
+ const quint32 addr = qFromBigEndian<quint32>(response + offset);
QDnsHostAddressRecord record;
record.d->name = name;
record.d->timeToLive = ttl;
record.d->value = QHostAddress(addr);
reply->hostAddressRecords.append(record);
} else if (type == QDnsLookup::AAAA) {
- if (size != 16) {
- reply->error = QDnsLookup::InvalidReplyError;
- reply->errorString = tr("Invalid IPv6 address record");
- return;
- }
+ if (size != 16)
+ return reply->makeInvalidReplyError(QDnsLookup::tr("Invalid IPv6 address record"));
QDnsHostAddressRecord record;
record.d->name = name;
record.d->timeToLive = ttl;
- record.d->value = QHostAddress(p);
+ record.d->value = QHostAddress(response + offset);
reply->hostAddressRecords.append(record);
} else if (type == QDnsLookup::CNAME) {
- status = local_dn_expand(response, response + responseLength, p, answer, sizeof(answer));
- if (status < 0) {
- reply->error = QDnsLookup::InvalidReplyError;
- reply->errorString = tr("Invalid canonical name record");
- return;
- }
QDnsDomainNameRecord record;
record.d->name = name;
record.d->timeToLive = ttl;
- record.d->value = QUrl::fromAce(answer);
+ record.d->value = expandHost(offset);
+ if (status < 0)
+ return reply->makeInvalidReplyError(QDnsLookup::tr("Invalid canonical name record"));
reply->canonicalNameRecords.append(record);
} else if (type == QDnsLookup::NS) {
- status = local_dn_expand(response, response + responseLength, p, answer, sizeof(answer));
- if (status < 0) {
- reply->error = QDnsLookup::InvalidReplyError;
- reply->errorString = tr("Invalid name server record");
- return;
- }
QDnsDomainNameRecord record;
record.d->name = name;
record.d->timeToLive = ttl;
- record.d->value = QUrl::fromAce(answer);
+ record.d->value = expandHost(offset);
+ if (status < 0)
+ return reply->makeInvalidReplyError(QDnsLookup::tr("Invalid name server record"));
reply->nameServerRecords.append(record);
} else if (type == QDnsLookup::PTR) {
- status = local_dn_expand(response, response + responseLength, p, answer, sizeof(answer));
- if (status < 0) {
- reply->error = QDnsLookup::InvalidReplyError;
- reply->errorString = tr("Invalid pointer record");
- return;
- }
QDnsDomainNameRecord record;
record.d->name = name;
record.d->timeToLive = ttl;
- record.d->value = QUrl::fromAce(answer);
+ record.d->value = expandHost(offset);
+ if (status < 0)
+ return reply->makeInvalidReplyError(QDnsLookup::tr("Invalid pointer record"));
reply->pointerRecords.append(record);
} else if (type == QDnsLookup::MX) {
- const quint16 preference = (p[0] << 8) | p[1];
- status = local_dn_expand(response, response + responseLength, p + 2, answer, sizeof(answer));
- if (status < 0) {
- reply->error = QDnsLookup::InvalidReplyError;
- reply->errorString = tr("Invalid mail exchange record");
- return;
- }
+ const quint16 preference = qFromBigEndian<quint16>(response + offset);
QDnsMailExchangeRecord record;
- record.d->exchange = QUrl::fromAce(answer);
+ record.d->exchange = expandHost(offset + 2);
record.d->name = name;
record.d->preference = preference;
record.d->timeToLive = ttl;
+ if (status < 0)
+ return reply->makeInvalidReplyError(QDnsLookup::tr("Invalid mail exchange record"));
reply->mailExchangeRecords.append(record);
} else if (type == QDnsLookup::SRV) {
- const quint16 priority = (p[0] << 8) | p[1];
- const quint16 weight = (p[2] << 8) | p[3];
- const quint16 port = (p[4] << 8) | p[5];
- status = local_dn_expand(response, response + responseLength, p + 6, answer, sizeof(answer));
- if (status < 0) {
- reply->error = QDnsLookup::InvalidReplyError;
- reply->errorString = tr("Invalid service record");
- return;
- }
+ const quint16 priority = qFromBigEndian<quint16>(response + offset);
+ const quint16 weight = qFromBigEndian<quint16>(response + offset + 2);
+ const quint16 port = qFromBigEndian<quint16>(response + offset + 4);
QDnsServiceRecord record;
record.d->name = name;
- record.d->target = QUrl::fromAce(answer);
+ record.d->target = expandHost(offset + 6);
record.d->port = port;
record.d->priority = priority;
record.d->timeToLive = ttl;
record.d->weight = weight;
+ if (status < 0)
+ return reply->makeInvalidReplyError(QDnsLookup::tr("Invalid service record"));
reply->serviceRecords.append(record);
} else if (type == QDnsLookup::TXT) {
- unsigned char *txt = p;
QDnsTextRecord record;
record.d->name = name;
record.d->timeToLive = ttl;
- while (txt < p + size) {
- const unsigned char length = *txt;
+ qptrdiff txt = offset;
+ while (txt < offset + size) {
+ const unsigned char length = response[txt];
txt++;
- if (txt + length > p + size) {
- reply->error = QDnsLookup::InvalidReplyError;
- reply->errorString = tr("Invalid text record");
- return;
- }
- record.d->values << QByteArray((char*)txt, length);
+ if (txt + length > offset + size)
+ return reply->makeInvalidReplyError(QDnsLookup::tr("Invalid text record"));
+ record.d->values << QByteArrayView(response + txt, length).toByteArray();
txt += length;
}
reply->textRecords.append(record);
}
- p += size;
+ offset += size;
answerIndex++;
}
}
-#else
-void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestName, const QHostAddress &nameserver, QDnsLookupReply *reply)
-{
- Q_UNUSED(requestType);
- Q_UNUSED(requestName);
- Q_UNUSED(nameserver);
- reply->error = QDnsLookup::ResolverError;
- reply->errorString = tr("Resolver library can't be loaded: No runtime library loading support");
- return;
-}
-
-#endif /* QT_CONFIG(library) */
-
QT_END_NAMESPACE
diff --git a/src/network/kernel/qdnslookup_win.cpp b/src/network/kernel/qdnslookup_win.cpp
index 262893179c..72d5ae5c86 100644
--- a/src/network/kernel/qdnslookup_win.cpp
+++ b/src/network/kernel/qdnslookup_win.cpp
@@ -1,105 +1,115 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 Jeremy Lainé <jeremy.laine@m4x.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2012 Jeremy Lainé <jeremy.laine@m4x.org>
+// Copyright (C) 2023 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <winsock2.h>
#include "qdnslookup_p.h"
#include <qurl.h>
+#include <private/qnativesocketengine_p.h>
#include <private/qsystemerror_p.h>
#include <qt_windows.h>
#include <windns.h>
#include <memory.h>
+#ifndef DNS_ADDR_MAX_SOCKADDR_LENGTH
+// MinGW headers are missing almost all of this
+typedef struct Qt_DnsAddr {
+ CHAR MaxSa[32];
+ DWORD DnsAddrUserDword[8];
+} DNS_ADDR, *PDNS_ADDR;
+typedef struct Qt_DnsAddrArray {
+ DWORD MaxCount;
+ DWORD AddrCount;
+ DWORD Tag;
+ WORD Family;
+ WORD WordReserved;
+ DWORD Flags;
+ DWORD MatchFlag;
+ DWORD Reserved1;
+ DWORD Reserved2;
+ DNS_ADDR AddrArray[];
+} DNS_ADDR_ARRAY, *PDNS_ADDR_ARRAY;
+# ifndef DNS_QUERY_RESULTS_VERSION1
+typedef struct Qt_DNS_QUERY_RESULT {
+ ULONG Version;
+ DNS_STATUS QueryStatus;
+ ULONG64 QueryOptions;
+ PDNS_RECORD pQueryRecords;
+ PVOID Reserved;
+} DNS_QUERY_RESULT, *PDNS_QUERY_RESULT;
+typedef VOID WINAPI DNS_QUERY_COMPLETION_ROUTINE(PVOID pQueryContext,PDNS_QUERY_RESULT pQueryResults);
+typedef DNS_QUERY_COMPLETION_ROUTINE *PDNS_QUERY_COMPLETION_ROUTINE;
+# endif
+typedef struct Qt_DNS_QUERY_REQUEST {
+ ULONG Version;
+ PCWSTR QueryName;
+ WORD QueryType;
+ ULONG64 QueryOptions;
+ PDNS_ADDR_ARRAY pDnsServerList;
+ ULONG InterfaceIndex;
+ PDNS_QUERY_COMPLETION_ROUTINE pQueryCompletionCallback;
+ PVOID pQueryContext;
+} DNS_QUERY_REQUEST, *PDNS_QUERY_REQUEST;
+
+typedef void *PDNS_QUERY_CANCEL; // not really, but we don't need it
+extern "C" {
+DNS_STATUS WINAPI DnsQueryEx(PDNS_QUERY_REQUEST pQueryRequest,
+ PDNS_QUERY_RESULT pQueryResults,
+ PDNS_QUERY_CANCEL pCancelHandle);
+}
+#endif
+
QT_BEGIN_NAMESPACE
-void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestName, const QHostAddress &nameserver, QDnsLookupReply *reply)
+void QDnsLookupRunnable::query(QDnsLookupReply *reply)
{
// Perform DNS query.
- PDNS_RECORD dns_records = 0;
- const QString requestNameUtf16 = QString::fromUtf8(requestName.data(), requestName.size());
- IP4_ARRAY srvList;
- memset(&srvList, 0, sizeof(IP4_ARRAY));
+ alignas(DNS_ADDR_ARRAY) uchar dnsAddresses[sizeof(DNS_ADDR_ARRAY) + sizeof(DNS_ADDR)];
+ DNS_QUERY_REQUEST request = {};
+ request.Version = 1;
+ request.QueryName = reinterpret_cast<const wchar_t *>(requestName.constData());
+ request.QueryType = requestType;
+ request.QueryOptions = DNS_QUERY_STANDARD | DNS_QUERY_TREAT_AS_FQDN;
+
if (!nameserver.isNull()) {
- if (nameserver.protocol() == QAbstractSocket::IPv4Protocol) {
- // The below code is referenced from: http://support.microsoft.com/kb/831226
- srvList.AddrCount = 1;
- srvList.AddrArray[0] = htonl(nameserver.toIPv4Address());
- } else if (nameserver.protocol() == QAbstractSocket::IPv6Protocol) {
- // For supoprting IPv6 nameserver addresses, we'll need to switch
- // from DnsQuey() to DnsQueryEx() as it supports passing an IPv6
- // address in the nameserver list
- qWarning("%s", QDnsLookupPrivate::msgNoIpV6NameServerAdresses);
- reply->error = QDnsLookup::ResolverError;
- reply->errorString = tr(QDnsLookupPrivate::msgNoIpV6NameServerAdresses);
- return;
- }
- }
- const DNS_STATUS status = DnsQuery_W(reinterpret_cast<const wchar_t*>(requestNameUtf16.utf16()), requestType, DNS_QUERY_STANDARD, &srvList, &dns_records, NULL);
- switch (status) {
- case ERROR_SUCCESS:
- break;
- case DNS_ERROR_RCODE_FORMAT_ERROR:
- reply->error = QDnsLookup::InvalidRequestError;
- reply->errorString = tr("Server could not process query");
- return;
- case DNS_ERROR_RCODE_SERVER_FAILURE:
- reply->error = QDnsLookup::ServerFailureError;
- reply->errorString = tr("Server failure");
- return;
- case DNS_ERROR_RCODE_NAME_ERROR:
- reply->error = QDnsLookup::NotFoundError;
- reply->errorString = tr("Non existent domain");
- return;
- case DNS_ERROR_RCODE_REFUSED:
- reply->error = QDnsLookup::ServerRefusedError;
- reply->errorString = tr("Server refused to answer");
- return;
- default:
- reply->error = QDnsLookup::InvalidReplyError;
- reply->errorString = QSystemError(status, QSystemError::NativeError).toString();
- return;
+ memset(dnsAddresses, 0, sizeof(dnsAddresses));
+ request.pDnsServerList = new (dnsAddresses) DNS_ADDR_ARRAY;
+ auto addr = new (request.pDnsServerList->AddrArray) DNS_ADDR[1];
+ auto sa = new (addr[0].MaxSa) sockaddr;
+ request.pDnsServerList->MaxCount = sizeof(dnsAddresses);
+ request.pDnsServerList->AddrCount = 1;
+ // ### setting port 53 seems to cause some systems to fail
+ setSockaddr(sa, nameserver, port == DnsPort ? 0 : port);
+ request.pDnsServerList->Family = sa->sa_family;
}
+ DNS_QUERY_RESULT results = {};
+ results.Version = 1;
+ const DNS_STATUS status = DnsQueryEx(&request, &results, nullptr);
+ if (status >= DNS_ERROR_RCODE_FORMAT_ERROR && status <= DNS_ERROR_RCODE_LAST)
+ return reply->makeDnsRcodeError(status - DNS_ERROR_RCODE_FORMAT_ERROR + 1);
+ else if (status == ERROR_TIMEOUT)
+ return reply->makeTimeoutError();
+ else if (status != ERROR_SUCCESS)
+ return reply->makeResolverSystemError(status);
+
+ QStringView lastEncodedName;
+ QString cachedDecodedName;
+ auto extractAndCacheHost = [&](QStringView name) -> const QString & {
+ lastEncodedName = name;
+ cachedDecodedName = decodeLabel(name);
+ return cachedDecodedName;
+ };
+ auto extractMaybeCachedHost = [&](QStringView name) -> const QString & {
+ return lastEncodedName == name ? cachedDecodedName : extractAndCacheHost(name);
+ };
+
// Extract results.
- for (PDNS_RECORD ptr = dns_records; ptr != NULL; ptr = ptr->pNext) {
- const QString name = QUrl::fromAce( QString::fromWCharArray( ptr->pName ).toLatin1() );
+ for (PDNS_RECORD ptr = results.pQueryRecords; ptr != NULL; ptr = ptr->pNext) {
+ // warning: always assign name to the record before calling extractXxxHost() again
+ const QString &name = extractMaybeCachedHost(ptr->pName);
if (ptr->wType == QDnsLookup::A) {
QDnsHostAddressRecord record;
record.d->name = name;
@@ -119,12 +129,12 @@ void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestN
QDnsDomainNameRecord record;
record.d->name = name;
record.d->timeToLive = ptr->dwTtl;
- record.d->value = QUrl::fromAce(QString::fromWCharArray(ptr->Data.Cname.pNameHost).toLatin1());
+ record.d->value = extractAndCacheHost(ptr->Data.Cname.pNameHost);
reply->canonicalNameRecords.append(record);
} else if (ptr->wType == QDnsLookup::MX) {
QDnsMailExchangeRecord record;
record.d->name = name;
- record.d->exchange = QUrl::fromAce(QString::fromWCharArray(ptr->Data.Mx.pNameExchange).toLatin1());
+ record.d->exchange = decodeLabel(QStringView(ptr->Data.Mx.pNameExchange));
record.d->preference = ptr->Data.Mx.wPreference;
record.d->timeToLive = ptr->dwTtl;
reply->mailExchangeRecords.append(record);
@@ -132,18 +142,18 @@ void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestN
QDnsDomainNameRecord record;
record.d->name = name;
record.d->timeToLive = ptr->dwTtl;
- record.d->value = QUrl::fromAce(QString::fromWCharArray(ptr->Data.Ns.pNameHost).toLatin1());
+ record.d->value = decodeLabel(QStringView(ptr->Data.Ns.pNameHost));
reply->nameServerRecords.append(record);
} else if (ptr->wType == QDnsLookup::PTR) {
QDnsDomainNameRecord record;
record.d->name = name;
record.d->timeToLive = ptr->dwTtl;
- record.d->value = QUrl::fromAce(QString::fromWCharArray(ptr->Data.Ptr.pNameHost).toLatin1());
+ record.d->value = decodeLabel(QStringView(ptr->Data.Ptr.pNameHost));
reply->pointerRecords.append(record);
} else if (ptr->wType == QDnsLookup::SRV) {
QDnsServiceRecord record;
record.d->name = name;
- record.d->target = QUrl::fromAce(QString::fromWCharArray(ptr->Data.Srv.pNameTarget).toLatin1());
+ record.d->target = decodeLabel(QStringView(ptr->Data.Srv.pNameTarget));
record.d->port = ptr->Data.Srv.wPort;
record.d->priority = ptr->Data.Srv.wPriority;
record.d->timeToLive = ptr->dwTtl;
@@ -154,13 +164,13 @@ void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestN
record.d->name = name;
record.d->timeToLive = ptr->dwTtl;
for (unsigned int i = 0; i < ptr->Data.Txt.dwStringCount; ++i) {
- record.d->values << QString::fromWCharArray((ptr->Data.Txt.pStringArray[i])).toLatin1();;
+ record.d->values << QStringView(ptr->Data.Txt.pStringArray[i]).toLatin1();
}
reply->textRecords.append(record);
}
}
- DnsRecordListFree(dns_records, DnsFreeRecordList);
+ DnsRecordListFree(results.pQueryRecords, DnsFreeRecordList);
}
QT_END_NAMESPACE
diff --git a/src/network/kernel/qhostaddress.cpp b/src/network/kernel/qhostaddress.cpp
index 007608dd68..0330fb091b 100644
--- a/src/network/kernel/qhostaddress.cpp
+++ b/src/network/kernel/qhostaddress.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qhostaddress.h"
#include "qhostaddress_p.h"
@@ -65,7 +29,7 @@
QT_BEGIN_NAMESPACE
QHostAddressPrivate::QHostAddressPrivate()
- : a(0), protocol(QAbstractSocket::UnknownNetworkLayerProtocol)
+ : a(0), protocol(QHostAddress::UnknownNetworkLayerProtocol)
{
memset(&a6, 0, sizeof(a6));
}
@@ -73,7 +37,7 @@ QHostAddressPrivate::QHostAddressPrivate()
void QHostAddressPrivate::setAddress(quint32 a_)
{
a = a_;
- protocol = QAbstractSocket::IPv4Protocol;
+ protocol = QHostAddress::IPv4Protocol;
//create mapped address, except for a_ == 0 (any)
a6_64.c[0] = 0;
@@ -122,7 +86,7 @@ static bool convertToIpv4(quint32& a, const Q_IPV6ADDR &a6, const QHostAddress::
void QHostAddressPrivate::setAddress(const quint8 *a_)
{
- protocol = QAbstractSocket::IPv6Protocol;
+ protocol = QHostAddress::IPv6Protocol;
memcpy(a6.c, a_, sizeof(a6));
a = 0;
convertToIpv4(a, a6, (QHostAddress::ConvertV4MappedToIPv4
@@ -137,7 +101,7 @@ void QHostAddressPrivate::setAddress(const Q_IPV6ADDR &a_)
static bool parseIp6(const QString &address, QIPAddressUtils::IPv6Address &addr, QString *scopeId)
{
QStringView tmp(address);
- int scopeIdPos = tmp.lastIndexOf(QLatin1Char('%'));
+ qsizetype scopeIdPos = tmp.lastIndexOf(u'%');
if (scopeIdPos != -1) {
*scopeId = tmp.mid(scopeIdPos + 1).toString();
tmp.chop(tmp.size() - scopeIdPos);
@@ -149,13 +113,13 @@ static bool parseIp6(const QString &address, QIPAddressUtils::IPv6Address &addr,
bool QHostAddressPrivate::parse(const QString &ipString)
{
- protocol = QAbstractSocket::UnknownNetworkLayerProtocol;
+ protocol = QHostAddress::UnknownNetworkLayerProtocol;
QString a = ipString.simplified();
if (a.isEmpty())
return false;
// All IPv6 addresses contain a ':', and may contain a '.'.
- if (a.contains(QLatin1Char(':'))) {
+ if (a.contains(u':')) {
quint8 maybeIp6[16];
if (parseIp6(a, maybeIp6, &scopeId)) {
setAddress(maybeIp6);
@@ -175,7 +139,7 @@ bool QHostAddressPrivate::parse(const QString &ipString)
void QHostAddressPrivate::clear()
{
a = 0;
- protocol = QAbstractSocket::UnknownNetworkLayerProtocol;
+ protocol = QHostAddress::UnknownNetworkLayerProtocol;
memset(&a6, 0, sizeof(a6));
}
@@ -200,8 +164,12 @@ AddressClassification QHostAddressPrivate::classify() const
return BroadcastAddress;
return UnknownAddress;
}
+ if (((a & 0xff000000U) == 0x0a000000U) // 10.0.0.0/8
+ || ((a & 0xfff00000U) == 0xac100000U) // 172.16.0.0/12
+ || ((a & 0xffff0000U) == 0xc0a80000U)) // 192.168.0.0/16
+ return PrivateNetworkAddress;
- // Not testing for PrivateNetworkAddress and TestNetworkAddress
+ // Not testing for TestNetworkAddress
// since we don't need them yet.
return GlobalAddress;
}
@@ -242,7 +210,7 @@ AddressClassification QHostAddressPrivate::classify() const
if (low64) // not ::
return GlobalAddress;
- if (protocol == QAbstractSocket::UnknownNetworkLayerProtocol)
+ if (protocol == QHostAddress::UnknownNetworkLayerProtocol)
return UnknownAddress;
// only :: and 0.0.0.0 remain now
@@ -262,10 +230,10 @@ bool QNetmask::setAddress(const QHostAddress &address)
quint8 *end;
length = 255;
- if (address.protocol() == QAbstractSocket::IPv4Protocol) {
+ if (address.protocol() == QHostAddress::IPv4Protocol) {
ip.v4 = qToBigEndian(address.toIPv4Address());
end = ptr + 4;
- } else if (address.protocol() == QAbstractSocket::IPv6Protocol) {
+ } else if (address.protocol() == QHostAddress::IPv6Protocol) {
memcpy(ip.v6, address.toIPv6Address().c, 16);
end = ptr + 16;
} else {
@@ -331,12 +299,12 @@ static void clearBits(quint8 *where, int start, int end)
memset(where + (start + 7) / 8, 0, end / 8 - (start + 7) / 8);
}
-QHostAddress QNetmask::address(QAbstractSocket::NetworkLayerProtocol protocol) const
+QHostAddress QNetmask::address(QHostAddress::NetworkLayerProtocol protocol) const
{
- if (length == 255 || protocol == QAbstractSocket::AnyIPProtocol ||
- protocol == QAbstractSocket::UnknownNetworkLayerProtocol) {
+ if (length == 255 || protocol == QHostAddress::AnyIPProtocol ||
+ protocol == QHostAddress::UnknownNetworkLayerProtocol) {
return QHostAddress();
- } else if (protocol == QAbstractSocket::IPv4Protocol) {
+ } else if (protocol == QHostAddress::IPv4Protocol) {
quint32 a;
if (length == 0)
a = 0;
@@ -657,7 +625,7 @@ void QHostAddress::setAddress(SpecialAddress address)
return;
case Any:
- d->protocol = QAbstractSocket::AnyIPProtocol;
+ d->protocol = QHostAddress::AnyIPProtocol;
return;
}
@@ -684,8 +652,8 @@ quint32 QHostAddress::toIPv4Address(bool *ok) const
{
quint32 dummy;
if (ok)
- *ok = d->protocol == QAbstractSocket::IPv4Protocol || d->protocol == QAbstractSocket::AnyIPProtocol
- || (d->protocol == QAbstractSocket::IPv6Protocol
+ *ok = d->protocol == QHostAddress::IPv4Protocol || d->protocol == QHostAddress::AnyIPProtocol
+ || (d->protocol == QHostAddress::IPv6Protocol
&& convertToIpv4(dummy, d->a6, ConversionMode(QHostAddress::ConvertV4MappedToIPv4
| QHostAddress::ConvertUnspecifiedAddress)));
return d->a;
@@ -694,9 +662,9 @@ quint32 QHostAddress::toIPv4Address(bool *ok) const
/*!
Returns the network layer protocol of the host address.
*/
-QAbstractSocket::NetworkLayerProtocol QHostAddress::protocol() const
+QHostAddress::NetworkLayerProtocol QHostAddress::protocol() const
{
- return QAbstractSocket::NetworkLayerProtocol(d->protocol);
+ return QHostAddress::NetworkLayerProtocol(d->protocol);
}
/*!
@@ -709,7 +677,7 @@ QAbstractSocket::NetworkLayerProtocol QHostAddress::protocol() const
\l{QAbstractSocket::}{IPv6Protocol}.
If the protocol is
\l{QAbstractSocket::}{IPv4Protocol},
- then the address is returned an an IPv4 mapped IPv6 address. (RFC4291)
+ then the address is returned as an IPv4 mapped IPv6 address. (RFC4291)
\sa toString()
*/
@@ -731,14 +699,14 @@ Q_IPV6ADDR QHostAddress::toIPv6Address() const
QString QHostAddress::toString() const
{
QString s;
- if (d->protocol == QAbstractSocket::IPv4Protocol
- || d->protocol == QAbstractSocket::AnyIPProtocol) {
+ if (d->protocol == QHostAddress::IPv4Protocol
+ || d->protocol == QHostAddress::AnyIPProtocol) {
quint32 i = toIPv4Address();
QIPAddressUtils::toString(s, i);
- } else if (d->protocol == QAbstractSocket::IPv6Protocol) {
+ } else if (d->protocol == QHostAddress::IPv6Protocol) {
QIPAddressUtils::toString(s, d->a6.c);
if (!d->scopeId.isEmpty())
- s.append(QLatin1Char('%') + d->scopeId);
+ s += u'%' + d->scopeId;
}
return s;
}
@@ -781,7 +749,7 @@ QString QHostAddress::toString() const
*/
QString QHostAddress::scopeId() const
{
- return (d->protocol == QAbstractSocket::IPv6Protocol) ? d->scopeId : QString();
+ return (d->protocol == QHostAddress::IPv6Protocol) ? d->scopeId : QString();
}
/*!
@@ -799,7 +767,7 @@ QString QHostAddress::scopeId() const
void QHostAddress::setScopeId(const QString &id)
{
d.detach();
- if (d->protocol == QAbstractSocket::IPv6Protocol)
+ if (d->protocol == QHostAddress::IPv6Protocol)
d->scopeId = id;
}
@@ -820,7 +788,7 @@ bool QHostAddress::operator==(const QHostAddress &other) const
Returns \c true if this host address is the same as the \a other address
given; otherwise returns \c false.
- The parameter \a mode controls which conversions are preformed between addresses
+ The parameter \a mode controls which conversions are performed between addresses
of differing protocols. If no \a mode is given, \c TolerantConversion is performed
by default.
@@ -831,41 +799,41 @@ bool QHostAddress::isEqual(const QHostAddress &other, ConversionMode mode) const
if (d == other.d)
return true;
- if (d->protocol == QAbstractSocket::IPv4Protocol) {
+ if (d->protocol == QHostAddress::IPv4Protocol) {
switch (other.d->protocol) {
- case QAbstractSocket::IPv4Protocol:
+ case QHostAddress::IPv4Protocol:
return d->a == other.d->a;
- case QAbstractSocket::IPv6Protocol:
+ case QHostAddress::IPv6Protocol:
quint32 a4;
return convertToIpv4(a4, other.d->a6, mode) && (a4 == d->a);
- case QAbstractSocket::AnyIPProtocol:
+ case QHostAddress::AnyIPProtocol:
return (mode & QHostAddress::ConvertUnspecifiedAddress) && d->a == 0;
- case QAbstractSocket::UnknownNetworkLayerProtocol:
+ case QHostAddress::UnknownNetworkLayerProtocol:
return false;
}
}
- if (d->protocol == QAbstractSocket::IPv6Protocol) {
+ if (d->protocol == QHostAddress::IPv6Protocol) {
switch (other.d->protocol) {
- case QAbstractSocket::IPv4Protocol:
+ case QHostAddress::IPv4Protocol:
quint32 a4;
return convertToIpv4(a4, d->a6, mode) && (a4 == other.d->a);
- case QAbstractSocket::IPv6Protocol:
+ case QHostAddress::IPv6Protocol:
return memcmp(&d->a6, &other.d->a6, sizeof(Q_IPV6ADDR)) == 0;
- case QAbstractSocket::AnyIPProtocol:
+ case QHostAddress::AnyIPProtocol:
return (mode & QHostAddress::ConvertUnspecifiedAddress)
- && (other.d->a6_64.c[0] == 0) && (other.d->a6_64.c[1] == 0);
- case QAbstractSocket::UnknownNetworkLayerProtocol:
+ && (d->a6_64.c[0] == 0) && (d->a6_64.c[1] == 0);
+ case QHostAddress::UnknownNetworkLayerProtocol:
return false;
}
}
- if ((d->protocol == QAbstractSocket::AnyIPProtocol)
+ if ((d->protocol == QHostAddress::AnyIPProtocol)
&& (mode & QHostAddress::ConvertUnspecifiedAddress)) {
switch (other.d->protocol) {
- case QAbstractSocket::IPv4Protocol:
+ case QHostAddress::IPv4Protocol:
return other.d->a == 0;
- case QAbstractSocket::IPv6Protocol:
+ case QHostAddress::IPv6Protocol:
return (other.d->a6_64.c[0] == 0) && (other.d->a6_64.c[1] == 0);
default:
break;
@@ -884,7 +852,7 @@ bool QHostAddress::operator ==(SpecialAddress other) const
quint32 ip4 = INADDR_ANY;
switch (other) {
case Null:
- return d->protocol == QAbstractSocket::UnknownNetworkLayerProtocol;
+ return d->protocol == QHostAddress::UnknownNetworkLayerProtocol;
case Broadcast:
ip4 = INADDR_BROADCAST;
@@ -895,14 +863,14 @@ bool QHostAddress::operator ==(SpecialAddress other) const
break;
case Any:
- return d->protocol == QAbstractSocket::AnyIPProtocol;
+ return d->protocol == QHostAddress::AnyIPProtocol;
case AnyIPv4:
break;
case LocalHostIPv6:
case AnyIPv6:
- if (d->protocol == QAbstractSocket::IPv6Protocol) {
+ if (d->protocol == QHostAddress::IPv6Protocol) {
quint64 second = quint8(other == LocalHostIPv6); // 1 for localhost, 0 for any
return d->a6_64.c[0] == 0 && d->a6_64.c[1] == qToBigEndian(second);
}
@@ -910,7 +878,7 @@ bool QHostAddress::operator ==(SpecialAddress other) const
}
// common IPv4 part
- return d->protocol == QAbstractSocket::IPv4Protocol && d->a == ip4;
+ return d->protocol == QHostAddress::IPv4Protocol && d->a == ip4;
}
/*!
@@ -922,7 +890,7 @@ bool QHostAddress::operator ==(SpecialAddress other) const
*/
bool QHostAddress::isNull() const
{
- return d->protocol == QAbstractSocket::UnknownNetworkLayerProtocol;
+ return d->protocol == QHostAddress::UnknownNetworkLayerProtocol;
}
/*!
@@ -955,14 +923,14 @@ bool QHostAddress::isInSubnet(const QHostAddress &subnet, int netmask) const
} ip4, net4;
const quint8 *ip;
const quint8 *net;
- if (d->protocol == QAbstractSocket::IPv4Protocol) {
+ if (d->protocol == QHostAddress::IPv4Protocol) {
if (netmask > 32)
netmask = 32;
ip4.ip = qToBigEndian(d->a);
net4.ip = qToBigEndian(subnet.d->a);
ip = ip4.data;
net = net4.data;
- } else if (d->protocol == QAbstractSocket::IPv6Protocol) {
+ } else if (d->protocol == QHostAddress::IPv6Protocol) {
if (netmask > 128)
netmask = 128;
ip = d->a6.c;
@@ -1043,17 +1011,17 @@ QPair<QHostAddress, int> QHostAddress::parseSubnet(const QString &subnet)
if (subnet.isEmpty())
return invalid;
- int slash = subnet.indexOf(QLatin1Char('/'));
+ qsizetype slash = subnet.indexOf(u'/');
QStringView netStr(subnet);
if (slash != -1)
netStr.truncate(slash);
int netmask = -1;
- bool isIpv6 = netStr.contains(QLatin1Char(':'));
+ bool isIpv6 = netStr.contains(u':');
if (slash != -1) {
// is the netmask given in IP-form or in bit-count form?
- if (!isIpv6 && subnet.indexOf(QLatin1Char('.'), slash + 1) != -1) {
+ if (!isIpv6 && subnet.indexOf(u'.', slash + 1) != -1) {
// IP-style, convert it to bit-count form
QHostAddress mask;
QNetmask parser;
@@ -1089,15 +1057,15 @@ QPair<QHostAddress, int> QHostAddress::parseSubnet(const QString &subnet)
return invalid; // invalid netmask
// parse the address manually
- auto parts = netStr.split(QLatin1Char('.'));
- if (parts.isEmpty() || parts.count() > 4)
+ auto parts = netStr.split(u'.');
+ if (parts.isEmpty() || parts.size() > 4)
return invalid; // invalid IPv4 address
if (parts.constLast().isEmpty())
parts.removeLast();
quint32 addr = 0;
- for (int i = 0; i < parts.count(); ++i) {
+ for (int i = 0; i < parts.size(); ++i) {
bool ok;
uint byteValue = parts.at(i).toUInt(&ok);
if (!ok || byteValue > 255)
@@ -1106,9 +1074,9 @@ QPair<QHostAddress, int> QHostAddress::parseSubnet(const QString &subnet)
addr <<= 8;
addr += byteValue;
}
- addr <<= 8 * (4 - parts.count());
+ addr <<= 8 * (4 - parts.size());
if (netmask == -1) {
- netmask = 8 * parts.count();
+ netmask = 8 * parts.size();
} else if (netmask == 0) {
// special case here
// x86's instructions "shr" and "shl" do not operate when
@@ -1143,13 +1111,13 @@ bool QHostAddress::isLoopback() const
Note that IPv6 unique local unicast addresses are considered global
addresses (see isUniqueLocalUnicast()), as are IPv4 addresses reserved for
- local networks by \l {https://tools.ietf.org/html/rfc1918}{RFC 1918}.
+ local networks by \l {RFC 1918}.
Also note that IPv6 site-local addresses are deprecated and should be
considered as global in new applications. This function returns true for
site-local addresses too.
- \sa isLoopback(), isSiteLocal(), isUniqueLocalUnicast()
+ \sa isLoopback(), isSiteLocal(), isUniqueLocalUnicast(), isPrivateUse()
*/
bool QHostAddress::isGlobal() const
{
@@ -1167,7 +1135,7 @@ bool QHostAddress::isGlobal() const
\l{https://www.iana.org/assignments/ipv6-address-space/ipv6-address-space.xhtml}{IANA
IPv6 Address Space} registry for more information.
- \sa isLoopback(), isGlobal(), isMulticast(), isSiteLocal(), isUniqueLocalUnicast()
+ \sa isLoopback(), isGlobal(), isMulticast(), isSiteLocal(), isUniqueLocalUnicast(), isPrivateUse()
*/
bool QHostAddress::isLinkLocal() const
{
@@ -1190,7 +1158,7 @@ bool QHostAddress::isLinkLocal() const
isGlobal() also returns true). Site-local addresses were replaced by Unique
Local Addresses (ULA).
- \sa isLoopback(), isGlobal(), isMulticast(), isLinkLocal(), isUniqueLocalUnicast()
+ \sa isLoopback(), isGlobal(), isMulticast(), isLinkLocal(), isUniqueLocalUnicast(), isPrivateUse()
*/
bool QHostAddress::isSiteLocal() const
{
@@ -1211,7 +1179,7 @@ bool QHostAddress::isSiteLocal() const
4193 says that, in practice, "applications may treat these addresses like
global scoped addresses." Only routers need care about the distinction.
- \sa isLoopback(), isGlobal(), isMulticast(), isLinkLocal(), isUniqueLocalUnicast()
+ \sa isLoopback(), isGlobal(), isMulticast(), isLinkLocal(), isUniqueLocalUnicast(), isPrivateUse()
*/
bool QHostAddress::isUniqueLocalUnicast() const
{
@@ -1224,7 +1192,7 @@ bool QHostAddress::isUniqueLocalUnicast() const
Returns \c true if the address is an IPv4 or IPv6 multicast address, \c
false otherwise.
- \sa isLoopback(), isGlobal(), isLinkLocal(), isSiteLocal(), isUniqueLocalUnicast()
+ \sa isLoopback(), isGlobal(), isLinkLocal(), isSiteLocal(), isUniqueLocalUnicast(), isPrivateUse()
*/
bool QHostAddress::isMulticast() const
{
@@ -1241,13 +1209,27 @@ bool QHostAddress::isMulticast() const
broadcast address. For that, please use \l QNetworkInterface to obtain the
broadcast addresses of the local machine.
- \sa isLoopback(), isGlobal(), isMulticast(), isLinkLocal(), isUniqueLocalUnicast()
+ \sa isLoopback(), isGlobal(), isMulticast(), isLinkLocal(), isUniqueLocalUnicast(), isPrivateUse()
*/
bool QHostAddress::isBroadcast() const
{
return d->classify() == BroadcastAddress;
}
+/*!
+ \since 6.6
+
+ Returns \c true if the address is an IPv6 unique local unicast address or
+ IPv4 address reserved for local networks by \l {RFC 1918}, \c false otherwise.
+
+ \sa isLoopback(), isGlobal(), isMulticast(), isLinkLocal(), isUniqueLocalUnicast(), isBroadcast()
+*/
+bool QHostAddress::isPrivateUse() const
+{
+ const AddressClassification classification = d->classify();
+ return (classification == PrivateNetworkAddress) || (classification == UniqueLocalAddress);
+}
+
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug d, const QHostAddress &address)
{
@@ -1272,8 +1254,7 @@ size_t qHash(const QHostAddress &key, size_t seed) noexcept
}
/*!
- \fn bool operator==(QHostAddress::SpecialAddress lhs, const QHostAddress &rhs)
- \relates QHostAddress
+ \fn bool QHostAddress::operator==(QHostAddress::SpecialAddress lhs, const QHostAddress &rhs)
Returns \c true if special address \a lhs is the same as host address \a rhs;
otherwise returns \c false.
@@ -1282,8 +1263,7 @@ size_t qHash(const QHostAddress &key, size_t seed) noexcept
*/
/*!
- \fn bool operator!=(QHostAddress::SpecialAddress lhs, const QHostAddress &rhs)
- \relates QHostAddress
+ \fn bool QHostAddress::operator!=(QHostAddress::SpecialAddress lhs, const QHostAddress &rhs)
\since 5.9
Returns \c false if special address \a lhs is the same as host address \a rhs;
@@ -1307,13 +1287,13 @@ QDataStream &operator<<(QDataStream &out, const QHostAddress &address)
prot = qint8(address.protocol());
out << prot;
switch (address.protocol()) {
- case QAbstractSocket::UnknownNetworkLayerProtocol:
- case QAbstractSocket::AnyIPProtocol:
+ case QHostAddress::UnknownNetworkLayerProtocol:
+ case QHostAddress::AnyIPProtocol:
break;
- case QAbstractSocket::IPv4Protocol:
+ case QHostAddress::IPv4Protocol:
out << address.toIPv4Address();
break;
- case QAbstractSocket::IPv6Protocol:
+ case QHostAddress::IPv6Protocol:
{
Q_IPV6ADDR ipv6 = address.toIPv6Address();
for (int i = 0; i < 16; ++i)
@@ -1336,18 +1316,18 @@ QDataStream &operator>>(QDataStream &in, QHostAddress &address)
{
qint8 prot;
in >> prot;
- switch (QAbstractSocket::NetworkLayerProtocol(prot)) {
- case QAbstractSocket::UnknownNetworkLayerProtocol:
+ switch (QHostAddress::NetworkLayerProtocol(prot)) {
+ case QHostAddress::UnknownNetworkLayerProtocol:
address.clear();
break;
- case QAbstractSocket::IPv4Protocol:
+ case QHostAddress::IPv4Protocol:
{
quint32 ipv4;
in >> ipv4;
address.setAddress(ipv4);
}
break;
- case QAbstractSocket::IPv6Protocol:
+ case QHostAddress::IPv6Protocol:
{
Q_IPV6ADDR ipv6;
for (int i = 0; i < 16; ++i)
@@ -1359,7 +1339,7 @@ QDataStream &operator>>(QDataStream &in, QHostAddress &address)
address.setScopeId(scope);
}
break;
- case QAbstractSocket::AnyIPProtocol:
+ case QHostAddress::AnyIPProtocol:
address = QHostAddress::Any;
break;
default:
@@ -1372,3 +1352,5 @@ QDataStream &operator>>(QDataStream &in, QHostAddress &address)
#endif //QT_NO_DATASTREAM
QT_END_NAMESPACE
+
+#include "moc_qhostaddress.cpp"
diff --git a/src/network/kernel/qhostaddress.h b/src/network/kernel/qhostaddress.h
index 82790fa28d..6aa045c959 100644
--- a/src/network/kernel/qhostaddress.h
+++ b/src/network/kernel/qhostaddress.h
@@ -1,42 +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 QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QHOSTADDRESS_H
#define QHOSTADDRESS_H
@@ -45,7 +9,9 @@
#include <QtCore/qpair.h>
#include <QtCore/qstring.h>
#include <QtCore/qshareddata.h>
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
#include <QtNetwork/qabstractsocket.h>
+#endif
struct sockaddr;
@@ -54,7 +20,7 @@ QT_BEGIN_NAMESPACE
class QHostAddressPrivate;
-class Q_NETWORK_EXPORT QIPv6Address
+class QT6_ONLY(Q_NETWORK_EXPORT) QIPv6Address
{
public:
inline quint8 &operator [](int index) { return c[index]; }
@@ -70,6 +36,7 @@ Q_NETWORK_EXPORT size_t qHash(const QHostAddress &key, size_t seed = 0) noexcept
class Q_NETWORK_EXPORT QHostAddress
{
+ Q_GADGET
public:
enum SpecialAddress {
Null,
@@ -91,6 +58,22 @@ public:
};
Q_DECLARE_FLAGS(ConversionMode, ConversionModeFlag)
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+ using NetworkLayerProtocol = QAbstractSocket::NetworkLayerProtocol;
+ static constexpr auto IPv4Protocol = QAbstractSocket::IPv4Protocol;
+ static constexpr auto IPv6Protocol = QAbstractSocket::IPv6Protocol;
+ static constexpr auto AnyIPProtocol = QAbstractSocket::AnyIPProtocol;
+ static constexpr auto UnknownNetworkLayerProtocol = QAbstractSocket::UnknownNetworkLayerProtocol;
+#else
+ enum NetworkLayerProtocol {
+ IPv4Protocol,
+ IPv6Protocol,
+ AnyIPProtocol,
+ UnknownNetworkLayerProtocol = -1
+ };
+ Q_ENUM(NetworkLayerProtocol)
+#endif
+
QHostAddress();
explicit QHostAddress(quint32 ip4Addr);
explicit QHostAddress(const quint8 *ip6Addr);
@@ -115,7 +98,7 @@ public:
bool setAddress(const QString &address);
void setAddress(SpecialAddress address);
- QAbstractSocket::NetworkLayerProtocol protocol() const;
+ NetworkLayerProtocol protocol() const;
quint32 toIPv4Address(bool *ok = nullptr) const;
Q_IPV6ADDR toIPv6Address() const;
@@ -144,10 +127,17 @@ public:
bool isUniqueLocalUnicast() const;
bool isMulticast() const;
bool isBroadcast() const;
+ bool isPrivateUse() const;
static QPair<QHostAddress, int> parseSubnet(const QString &subnet);
friend Q_NETWORK_EXPORT size_t qHash(const QHostAddress &key, size_t seed) noexcept;
+
+ friend bool operator ==(QHostAddress::SpecialAddress lhs, const QHostAddress &rhs)
+ { return rhs == lhs; }
+ friend bool operator!=(QHostAddress::SpecialAddress lhs, const QHostAddress &rhs)
+ { return rhs != lhs; }
+
protected:
friend class QHostAddressPrivate;
QExplicitlySharedDataPointer<QHostAddressPrivate> d;
@@ -155,11 +145,6 @@ protected:
Q_DECLARE_OPERATORS_FOR_FLAGS(QHostAddress::ConversionMode)
Q_DECLARE_SHARED(QHostAddress)
-inline bool operator ==(QHostAddress::SpecialAddress address1, const QHostAddress &address2)
-{ return address2 == address1; }
-inline bool operator!=(QHostAddress::SpecialAddress lhs, const QHostAddress &rhs)
-{ return rhs != lhs; }
-
#ifndef QT_NO_DEBUG_STREAM
Q_NETWORK_EXPORT QDebug operator<<(QDebug, const QHostAddress &);
#endif
diff --git a/src/network/kernel/qhostaddress_p.h b/src/network/kernel/qhostaddress_p.h
index 101c163800..98586fb374 100644
--- a/src/network/kernel/qhostaddress_p.h
+++ b/src/network/kernel/qhostaddress_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QHOSTADDRESSPRIVATE_H
#define QHOSTADDRESSPRIVATE_H
diff --git a/src/network/kernel/qhostinfo.cpp b/src/network/kernel/qhostinfo.cpp
index b3d6844e43..62bb210ca1 100644
--- a/src/network/kernel/qhostinfo.cpp
+++ b/src/network/kernel/qhostinfo.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//#define QHOSTINFO_DEBUG
@@ -43,6 +7,7 @@
#include "qhostinfo_p.h"
#include <qplatformdefs.h>
+#include "QtCore/qapplicationstatic.h"
#include "QtCore/qscopedpointer.h"
#include <qabstracteventdispatcher.h>
#include <qcoreapplication.h>
@@ -58,7 +23,7 @@
# include <unistd.h>
# include <netdb.h>
# include <netinet/in.h>
-# if defined(AI_ADDRCONFIG)
+# if defined(AI_ADDRCONFIG) && !defined(Q_OS_WASM)
# define Q_ADDRCONFIG AI_ADDRCONFIG
# endif
#elif defined Q_OS_WIN
@@ -69,8 +34,12 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
//#define QHOSTINFO_DEBUG
+QT_IMPL_METATYPE_EXTERN(QHostInfo)
+
namespace {
struct ToBeLookedUpEquals {
typedef bool result_type;
@@ -99,27 +68,20 @@ std::pair<OutputIt1, OutputIt2> separate_if(InputIt first, InputIt last, OutputI
return std::make_pair(dest1, dest2);
}
-QHostInfoLookupManager* theHostInfoLookupManager()
-{
- static QHostInfoLookupManager* theManager = nullptr;
- static QBasicMutex theMutex;
-
- const QMutexLocker locker(&theMutex);
- if (theManager == nullptr) {
- theManager = new QHostInfoLookupManager();
- Q_ASSERT(QCoreApplication::instance());
- QObject::connect(QCoreApplication::instance(), &QCoreApplication::destroyed, [] {
- const QMutexLocker locker(&theMutex);
- delete theManager;
- theManager = nullptr;
- });
- }
+Q_APPLICATION_STATIC(QHostInfoLookupManager, theHostInfoLookupManager)
- return theManager;
}
+QHostInfoResult::QHostInfoResult(const QObject *receiver, QtPrivate::SlotObjUniquePtr slot)
+ : receiver{receiver ? receiver : this}, slotObj{std::move(slot)}
+{
+ Q_ASSERT(this->receiver);
+ moveToThread(this->receiver->thread());
}
+QHostInfoResult::~QHostInfoResult()
+ = default;
+
/*
The calling thread is likely the one that executes the lookup via
QHostInfoRunnable. Unless we operate with a queued connection already,
@@ -128,8 +90,8 @@ QHostInfoLookupManager* theHostInfoLookupManager()
the thread that made the call to lookupHost. That QHostInfoResult object
then calls the user code in the correct thread.
- The 'result' object deletes itself (via deleteLater) when the metacall
- event is received.
+ The 'result' object deletes itself (via deleteLater) when
+ finalizePostResultsReady is called.
*/
void QHostInfoResult::postResultsReady(const QHostInfo &info)
{
@@ -139,55 +101,33 @@ void QHostInfoResult::postResultsReady(const QHostInfo &info)
return;
}
// we used to have a context object, but it's already destroyed
- if (withContextObject && !receiver)
+ if (!receiver)
return;
- static const int signal_index = []() -> int {
- auto senderMetaObject = &QHostInfoResult::staticMetaObject;
- auto signal = &QHostInfoResult::resultsReady;
- int signal_index = -1;
- void *args[] = { &signal_index, &signal };
- senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args);
- return signal_index + QMetaObjectPrivate::signalOffset(senderMetaObject);
- }();
-
// a long-living version of this
auto result = new QHostInfoResult(this);
Q_CHECK_PTR(result);
- const int nargs = 2;
- auto metaCallEvent = new QMetaCallEvent(slotObj, nullptr, signal_index, nargs);
- Q_CHECK_PTR(metaCallEvent);
- void **args = metaCallEvent->args();
- QMetaType *types = metaCallEvent->types();
- auto voidType = QMetaType::fromType<void>();
- auto hostInfoType = QMetaType::fromType<QHostInfo>();
- types[0] = voidType;
- types[1] = hostInfoType;
- args[0] = nullptr;
- args[1] = hostInfoType.create(&info);
- Q_CHECK_PTR(args[1]);
- qApp->postEvent(result, metaCallEvent);
+ QMetaObject::invokeMethod(result,
+ &QHostInfoResult::finalizePostResultsReady,
+ Qt::QueuedConnection,
+ info);
}
/*
- Receives the event posted by postResultsReady, and calls the functor.
+ Receives the info from postResultsReady, and calls the functor.
*/
-bool QHostInfoResult::event(QEvent *event)
+void QHostInfoResult::finalizePostResultsReady(const QHostInfo &info)
{
- if (event->type() == QEvent::MetaCall) {
- Q_ASSERT(slotObj);
- auto metaCallEvent = static_cast<QMetaCallEvent *>(event);
- auto args = metaCallEvent->args();
- // we didn't have a context object, or it's still alive
- if (!withContextObject || receiver)
- slotObj->call(const_cast<QObject*>(receiver.data()), args);
- slotObj->destroyIfLastRef();
-
- deleteLater();
- return true;
+ Q_ASSERT(slotObj);
+
+ // we used to have a context object, but it's already destroyed
+ if (receiver) {
+ void *args[] = { nullptr, const_cast<QHostInfo *>(&info) };
+ slotObj->call(const_cast<QObject *>(receiver.data()), args);
}
- return QObject::event(event);
+
+ deleteLater();
}
/*!
@@ -234,7 +174,7 @@ bool QHostInfoResult::event(QEvent *event)
QHostInfo::localHostName() function.
QHostInfo uses the mechanisms provided by the operating system
- to perform the lookup. As per {https://tools.ietf.org/html/rfc6724}{RFC 6724}
+ to perform the lookup. As per \l {RFC 6724}
there is no guarantee that all IP addresses registered for a domain or
host will be returned.
@@ -245,13 +185,12 @@ bool QHostInfoResult::event(QEvent *event)
\note Since Qt 4.6.3 QHostInfo is using a small internal 60 second DNS cache
for performance improvements.
- \sa QAbstractSocket, {http://www.rfc-editor.org/rfc/rfc3492.txt}{RFC 3492},
- {https://tools.ietf.org/html/rfc6724}{RFC 6724}
+ \sa QAbstractSocket, {RFC 3492}, {RFC 6724}
*/
static int nextId()
{
- static QBasicAtomicInt counter = Q_BASIC_ATOMIC_INITIALIZER(0);
+ Q_CONSTINIT static QBasicAtomicInt counter = Q_BASIC_ATOMIC_INITIALIZER(0);
return 1 + counter.fetchAndAddRelaxed(1);
}
@@ -282,10 +221,17 @@ static int nextId()
\note There is no guarantee on the order the signals will be emitted
if you start multiple requests with lookupHost().
+ \note In Qt versions prior to 6.7, this function took \a receiver as
+ (non-const) \c{QObject*}.
+
\sa abortHostLookup(), addresses(), error(), fromName()
*/
-int QHostInfo::lookupHost(const QString &name, QObject *receiver, const char *member)
+int QHostInfo::lookupHost(const QString &name, const QObject *receiver, const char *member)
{
+ if (!receiver || !member) {
+ qWarning("QHostInfo::lookupHost: both the receiver and the member to invoke must be non-null");
+ return -1;
+ }
return QHostInfo::lookupHostImpl(name, receiver, nullptr, member);
}
@@ -311,7 +257,7 @@ int QHostInfo::lookupHost(const QString &name, QObject *receiver, const char *me
*/
/*!
- \fn template<typename Functor> int QHostInfo::lookupHost(const QString &name, Functor functor)
+ \fn template<typename Functor> int QHostInfo::lookupHost(const QString &name, Functor &&functor)
\since 5.9
@@ -395,12 +341,17 @@ QHostInfo QHostInfo::fromName(const QString &name)
qDebug("QHostInfo::fromName(\"%s\")",name.toLatin1().constData());
#endif
+#ifdef Q_OS_WASM
+ return QHostInfoAgent::lookup(name);
+#else
QHostInfo hostInfo = QHostInfoAgent::fromName(name);
QHostInfoLookupManager* manager = theHostInfoLookupManager();
manager->cache.put(name, hostInfo);
return hostInfo;
+#endif
}
+
QHostInfo QHostInfoAgent::reverseLookup(const QHostAddress &address)
{
QHostInfo results;
@@ -546,7 +497,7 @@ QHostInfo QHostInfoAgent::lookup(const QString &hostName)
QString tmp;
QList<QHostAddress> addresses = results.addresses();
for (int i = 0; i < addresses.count(); ++i) {
- if (i != 0) tmp += QLatin1String(", ");
+ if (i != 0) tmp += ", "_L1;
tmp += addresses.at(i).toString();
}
qDebug("QHostInfoAgent::fromName(): found %i entries for \"%s\": {%s}",
@@ -609,10 +560,11 @@ QHostInfo::QHostInfo(const QHostInfo &other)
*/
QHostInfo &QHostInfo::operator=(const QHostInfo &other)
{
- if (d_ptr)
- *d_ptr = *other.d_ptr;
- else
- d_ptr = new QHostInfoPrivate(*other.d_ptr);
+ if (this == &other)
+ return *this;
+
+ Q_ASSERT(d_ptr && other.d_ptr);
+ *d_ptr = *other.d_ptr;
return *this;
}
@@ -777,22 +729,25 @@ QString QHostInfo::localHostName()
\internal
Called by the various lookupHost overloads to perform the lookup.
- Signals either the functor encapuslated in the \a slotObj in the context
+ Signals either the functor encapuslated in the \a slotObjRaw in the context
of \a receiver, or the \a member slot of the \a receiver.
- \a receiver might be the nullptr, but only if a \a slotObj is provided.
+ \a receiver might be the nullptr, but only if a \a slotObjRaw is provided.
*/
int QHostInfo::lookupHostImpl(const QString &name,
const QObject *receiver,
- QtPrivate::QSlotObjectBase *slotObj,
+ QtPrivate::QSlotObjectBase *slotObjRaw,
const char *member)
{
+ QtPrivate::SlotObjUniquePtr slotObj{slotObjRaw};
#if defined QHOSTINFO_DEBUG
qDebug("QHostInfo::lookupHostImpl(\"%s\", %p, %p, %s)",
- name.toLatin1().constData(), receiver, slotObj, member ? member + 1 : 0);
+ name.toLatin1().constData(), receiver, slotObj.get(), member ? member + 1 : 0);
#endif
Q_ASSERT(!member != !slotObj); // one of these must be set, but not both
Q_ASSERT(receiver || slotObj);
+ Q_ASSERT(!member || receiver); // if member is set, also is receiver
+ const bool isUsingStringBasedSlot = static_cast<bool>(member);
if (!QAbstractEventDispatcher::instance(QThread::currentThread())) {
qWarning("QHostInfo::lookupHost() called with no event dispatcher");
@@ -808,15 +763,31 @@ int QHostInfo::lookupHostImpl(const QString &name,
hostInfo.setError(QHostInfo::HostNotFound);
hostInfo.setErrorString(QCoreApplication::translate("QHostInfo", "No host name given"));
- QHostInfoResult result(receiver, slotObj);
- if (receiver && member)
+ QHostInfoResult result(receiver, std::move(slotObj));
+ if (isUsingStringBasedSlot) {
QObject::connect(&result, SIGNAL(resultsReady(QHostInfo)),
receiver, member, Qt::QueuedConnection);
+ }
result.postResultsReady(hostInfo);
return id;
}
+#ifdef Q_OS_WASM
+ // Resolve the host name directly without using a thread or cache,
+ // since Emscripten's host lookup is fast. Emscripten maintains an internal
+ // mapping of hosts and addresses for the purposes of WebSocket socket
+ // tunnelling, and does not perform an actual host lookup.
+ QHostInfo hostInfo = QHostInfoAgent::lookup(name);
+ hostInfo.setLookupId(id);
+
+ QHostInfoResult result(receiver, std::move(slotObj));
+ if (isUsingStringBasedSlot) {
+ QObject::connect(&result, SIGNAL(resultsReady(QHostInfo)),
+ receiver, member, Qt::QueuedConnection);
+ }
+ result.postResultsReady(hostInfo);
+#else
QHostInfoLookupManager *manager = theHostInfoLookupManager();
if (Q_LIKELY(manager)) {
@@ -827,32 +798,38 @@ int QHostInfo::lookupHostImpl(const QString &name,
QHostInfo info = manager->cache.get(name, &valid);
if (valid) {
info.setLookupId(id);
- QHostInfoResult result(receiver, slotObj);
- if (receiver && member)
+ QHostInfoResult result(receiver, std::move(slotObj));
+ if (isUsingStringBasedSlot) {
QObject::connect(&result, SIGNAL(resultsReady(QHostInfo)),
receiver, member, Qt::QueuedConnection);
+ }
result.postResultsReady(info);
return id;
}
}
// cache is not enabled or it was not in the cache, do normal lookup
- QHostInfoRunnable *runnable = new QHostInfoRunnable(name, id, receiver, slotObj);
- if (receiver && member)
+ QHostInfoRunnable *runnable = new QHostInfoRunnable(name, id, receiver, std::move(slotObj));
+ if (isUsingStringBasedSlot) {
QObject::connect(&runnable->resultEmitter, SIGNAL(resultsReady(QHostInfo)),
receiver, member, Qt::QueuedConnection);
+ }
manager->scheduleLookup(runnable);
}
+#endif // Q_OS_WASM
return id;
}
QHostInfoRunnable::QHostInfoRunnable(const QString &hn, int i, const QObject *receiver,
- QtPrivate::QSlotObjectBase *slotObj) :
- toBeLookedUp(hn), id(i), resultEmitter(receiver, slotObj)
+ QtPrivate::SlotObjUniquePtr slotObj)
+ : toBeLookedUp{hn}, id{i}, resultEmitter{receiver, std::move(slotObj)}
{
setAutoDelete(true);
}
+QHostInfoRunnable::~QHostInfoRunnable()
+ = default;
+
// the QHostInfoLookupManager will at some point call this via a QThreadPool
void QHostInfoRunnable::run()
{
@@ -962,7 +939,7 @@ void QHostInfoLookupManager::rescheduleWithMutexHeld()
if (!finishedLookups.isEmpty()) {
// remove ID from aborted if it is in there
- for (int i = 0; i < finishedLookups.length(); i++) {
+ for (int i = 0; i < finishedLookups.size(); i++) {
abortedLookups.removeAll(finishedLookups.at(i)->id);
}
@@ -990,7 +967,7 @@ void QHostInfoLookupManager::rescheduleWithMutexHeld()
isAlreadyRunning).second,
scheduledLookups.end());
- const int availableThreads = threadPool.maxThreadCount() - currentLookups.size();
+ const int availableThreads = std::max(threadPool.maxThreadCount(), 1) - currentLookups.size();
if (availableThreads > 0) {
int readyToStartCount = qMin(availableThreads, scheduledLookups.size());
auto it = scheduledLookups.begin();
@@ -1028,9 +1005,12 @@ void QHostInfoLookupManager::abortLookup(int id)
if (wasDeleted)
return;
+ if (id == -1)
+ return;
+
#if QT_CONFIG(thread)
// is postponed? delete and return
- for (int i = 0; i < postponedLookups.length(); i++) {
+ for (int i = 0; i < postponedLookups.size(); i++) {
if (postponedLookups.at(i)->id == id) {
delete postponedLookups.takeAt(i);
return;
@@ -1039,7 +1019,7 @@ void QHostInfoLookupManager::abortLookup(int id)
#endif
// is scheduled? delete and return
- for (int i = 0; i < scheduledLookups.length(); i++) {
+ for (int i = 0; i < scheduledLookups.size(); i++) {
if (scheduledLookups.at(i)->id == id) {
delete scheduledLookups.takeAt(i);
return;
@@ -1174,3 +1154,5 @@ void QHostInfoCache::clear()
}
QT_END_NAMESPACE
+
+#include "moc_qhostinfo_p.cpp"
diff --git a/src/network/kernel/qhostinfo.h b/src/network/kernel/qhostinfo.h
index fd1567eb07..3942e41498 100644
--- a/src/network/kernel/qhostinfo.h
+++ b/src/network/kernel/qhostinfo.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QHOSTINFO_H
#define QHOSTINFO_H
@@ -53,6 +17,7 @@ class QHostInfoPrivate;
class Q_NETWORK_EXPORT QHostInfo
{
+ Q_GADGET
public:
enum HostInfoError {
NoError,
@@ -62,12 +27,12 @@ public:
explicit QHostInfo(int lookupId = -1);
QHostInfo(const QHostInfo &d);
- QHostInfo(QHostInfo &&other) noexcept : d_ptr(qExchange(other.d_ptr, nullptr)) {}
+ QHostInfo(QHostInfo &&other) noexcept : d_ptr(std::exchange(other.d_ptr, nullptr)) {}
QHostInfo &operator=(const QHostInfo &d);
QHostInfo &operator=(QHostInfo &&other) noexcept { swap(other); return *this; }
~QHostInfo();
- void swap(QHostInfo &other) noexcept { qSwap(d_ptr, other.d_ptr); }
+ void swap(QHostInfo &other) noexcept { qt_ptr_swap(d_ptr, other.d_ptr); }
QString hostName() const;
void setHostName(const QString &name);
@@ -84,68 +49,42 @@ public:
void setLookupId(int id);
int lookupId() const;
+#if QT_NETWORK_REMOVED_SINCE(6, 7)
static int lookupHost(const QString &name, QObject *receiver, const char *member);
+#endif
+ static int lookupHost(const QString &name, const QObject *receiver, const char *member);
static void abortHostLookup(int lookupId);
static QHostInfo fromName(const QString &name);
static QString localHostName();
static QString localDomainName();
-#ifdef Q_CLANG_QDOC
- template<typename Functor>
- static int lookupHost(const QString &name, Functor functor);
+#ifdef Q_QDOC
template<typename Functor>
static int lookupHost(const QString &name, const QObject *context, Functor functor);
#else
- // lookupHost to a QObject slot
- template <typename Func>
+ // lookupHost to a callable (with context)
+ template <typename Functor>
static inline int lookupHost(const QString &name,
- const typename QtPrivate::FunctionPointer<Func>::Object *receiver,
- Func slot)
+ const typename QtPrivate::ContextTypeForFunctor<Functor>::ContextType *receiver,
+ Functor &&func)
{
- typedef QtPrivate::FunctionPointer<Func> SlotType;
-
- typedef QtPrivate::FunctionPointer<void (*)(QHostInfo)> SignalType;
- static_assert(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount),
- "The slot requires more arguments than the signal provides.");
- static_assert((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments,
- typename SlotType::Arguments>::value),
- "Signal and slot arguments are not compatible.");
- static_assert((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType,
- typename SignalType::ReturnType>::value),
- "Return type of the slot is not compatible "
- "with the return type of the signal.");
-
- auto slotObj = new QtPrivate::QSlotObject<Func, typename SlotType::Arguments, void>(slot);
- return lookupHostImpl(name, receiver, slotObj, nullptr);
+ using Prototype = void(*)(QHostInfo);
+ QtPrivate::AssertCompatibleFunctions<Prototype, Functor>();
+ return lookupHostImpl(name, receiver,
+ QtPrivate::makeCallableObject<Prototype>(std::forward<Functor>(func)),
+ nullptr);
}
+#endif // Q_QDOC
+#ifndef QT_NO_CONTEXTLESS_CONNECT
// lookupHost to a callable (without context)
- template <typename Func>
- static inline typename std::enable_if<!QtPrivate::FunctionPointer<Func>::IsPointerToMemberFunction &&
- !std::is_same<const char *, Func>::value, int>::type
- lookupHost(const QString &name, Func slot)
- {
- return lookupHost(name, nullptr, std::move(slot));
- }
-
- // lookupHost to a functor or function pointer (with context)
- template <typename Func1>
- static inline typename std::enable_if<!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction &&
- !std::is_same<const char*, Func1>::value, int>::type
- lookupHost(const QString &name, QObject *context, Func1 slot)
+ template <typename Functor>
+ static inline int lookupHost(const QString &name, Functor &&slot)
{
- typedef QtPrivate::FunctionPointer<Func1> SlotType;
-
- static_assert(int(SlotType::ArgumentCount) <= 1,
- "The slot must not require more than one argument");
-
- auto slotObj = new QtPrivate::QFunctorSlotObject<Func1, 1,
- typename QtPrivate::List<QHostInfo>,
- void>(std::move(slot));
- return lookupHostImpl(name, context, slotObj, nullptr);
+ return lookupHost(name, nullptr, std::forward<Functor>(slot));
}
-#endif // Q_QDOC
+#endif // QT_NO_CONTEXTLESS_CONNECT
private:
QHostInfoPrivate *d_ptr;
@@ -164,6 +103,6 @@ Q_DECLARE_SHARED(QHostInfo)
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QHostInfo)
+QT_DECL_METATYPE_EXTERN(QHostInfo, Q_NETWORK_EXPORT)
#endif // QHOSTINFO_H
diff --git a/src/network/kernel/qhostinfo_p.h b/src/network/kernel/qhostinfo_p.h
index cc34d575b2..b229eb1cd8 100644
--- a/src/network/kernel/qhostinfo_p.h
+++ b/src/network/kernel/qhostinfo_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QHOSTINFO_P_H
#define QHOSTINFO_P_H
@@ -70,8 +34,6 @@
#include <QElapsedTimer>
#include <QCache>
-#include <QSharedPointer>
-
#include <atomic>
QT_BEGIN_NAMESPACE
@@ -81,26 +43,21 @@ class QHostInfoResult : public QObject
{
Q_OBJECT
public:
- QHostInfoResult(const QObject *receiver, QtPrivate::QSlotObjectBase *slotObj)
- : receiver(receiver), slotObj(slotObj),
- withContextObject(slotObj && receiver)
- {
- if (receiver)
- moveToThread(receiver->thread());
- }
+ explicit QHostInfoResult(const QObject *receiver, QtPrivate::SlotObjUniquePtr slot);
+ ~QHostInfoResult() override;
void postResultsReady(const QHostInfo &info);
Q_SIGNALS:
void resultsReady(const QHostInfo &info);
-protected:
- bool event(QEvent *event) override;
+private Q_SLOTS:
+ void finalizePostResultsReady(const QHostInfo &info);
private:
- QHostInfoResult(const QHostInfoResult *other)
- : receiver(other->receiver), slotObj(other->slotObj),
- withContextObject(other->withContextObject)
+ QHostInfoResult(QHostInfoResult *other)
+ : receiver(other->receiver.get() != other ? other->receiver.get() : this),
+ slotObj{std::move(other->slotObj)}
{
// cleanup if the application terminates before results are delivered
connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit,
@@ -109,16 +66,16 @@ private:
moveToThread(other->thread());
}
+ // receiver is either a QObject provided by the user,
+ // or it's set to `this` (to emulate the behavior of the contextless connect())
QPointer<const QObject> receiver = nullptr;
- QtPrivate::QSlotObjectBase *slotObj = nullptr;
- const bool withContextObject = false;
+ QtPrivate::SlotObjUniquePtr slotObj;
};
class QHostInfoAgent
{
public:
static QHostInfo fromName(const QString &hostName);
-private:
static QHostInfo lookup(const QString &hostName);
static QHostInfo reverseLookup(const QHostAddress &address);
};
@@ -128,7 +85,7 @@ class QHostInfoPrivate
public:
inline QHostInfoPrivate()
: err(QHostInfo::NoError),
- errorStr(QLatin1String(QT_TRANSLATE_NOOP("QHostInfo", "Unknown error"))),
+ errorStr(QLatin1StringView(QT_TRANSLATE_NOOP("QHostInfo", "Unknown error"))),
lookupId(0)
{
}
@@ -180,8 +137,10 @@ private:
class QHostInfoRunnable : public QRunnable
{
public:
- QHostInfoRunnable(const QString &hn, int i, const QObject *receiver,
- QtPrivate::QSlotObjectBase *slotObj);
+ explicit QHostInfoRunnable(const QString &hn, int i, const QObject *receiver,
+ QtPrivate::SlotObjUniquePtr slotObj);
+ ~QHostInfoRunnable() override;
+
void run() override;
QString toBeLookedUp;
diff --git a/src/network/kernel/qhostinfo_unix.cpp b/src/network/kernel/qhostinfo_unix.cpp
index 9b0a2ee669..80d386a13d 100644
--- a/src/network/kernel/qhostinfo_unix.cpp
+++ b/src/network/kernel/qhostinfo_unix.cpp
@@ -1,192 +1,80 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//#define QHOSTINFO_DEBUG
-#include "qplatformdefs.h"
-
#include "qhostinfo_p.h"
-#include "private/qnativesocketengine_p.h"
-#include "qiodevice.h"
+
#include <qbytearray.h>
-#if QT_CONFIG(library)
-#include <qlibrary.h>
-#endif
-#include <qbasicatomic.h>
-#include <qurl.h>
#include <qfile.h>
-#include <private/qnet_unix_p.h>
+#include <qplatformdefs.h>
+#include <qurl.h>
#include <sys/types.h>
#include <netdb.h>
-#include <arpa/inet.h>
-#if defined(Q_OS_VXWORKS)
-# include <hostLib.h>
-#else
-# include <resolv.h>
-#endif
+#include <netinet/in.h>
-#if defined(__GNU_LIBRARY__) && !defined(__UCLIBC__)
-# include <gnu/lib-names.h>
+#if QT_CONFIG(libresolv)
+# include <resolv.h>
#endif
-#if defined(Q_OS_FREEBSD) || QT_CONFIG(dlopen)
-# include <dlfcn.h>
+#ifndef _PATH_RESCONF
+# define _PATH_RESCONF "/etc/resolv.conf"
#endif
QT_BEGIN_NAMESPACE
-enum LibResolvFeature {
- NeedResInit,
- NeedResNInit
-};
-
-typedef struct __res_state *res_state_ptr;
-
-typedef int (*res_init_proto)(void);
-static res_init_proto local_res_init = nullptr;
-typedef int (*res_ninit_proto)(res_state_ptr);
-static res_ninit_proto local_res_ninit = nullptr;
-typedef void (*res_nclose_proto)(res_state_ptr);
-static res_nclose_proto local_res_nclose = nullptr;
-static res_state_ptr local_res = nullptr;
-
-#if QT_CONFIG(library) && !defined(Q_OS_QNX)
-namespace {
-struct LibResolv
-{
- enum {
-#ifdef RES_NORELOAD
- // If RES_NORELOAD is defined, then the libc is capable of watching
- // /etc/resolv.conf for changes and reloading as necessary. So accept
- // whatever is configured.
- ReinitNecessary = false
-#else
- ReinitNecessary = true
-#endif
- };
-
- QLibrary lib;
- LibResolv();
- ~LibResolv() { lib.unload(); }
-};
-}
-
-static QFunctionPointer resolveSymbol(QLibrary &lib, const char *sym)
-{
- if (lib.isLoaded())
- return lib.resolve(sym);
-
-#if defined(RTLD_DEFAULT) && (defined(Q_OS_FREEBSD) || QT_CONFIG(dlopen))
- return reinterpret_cast<QFunctionPointer>(dlsym(RTLD_DEFAULT, sym));
-#else
- return nullptr;
-#endif
-}
+using namespace Qt::StringLiterals;
-LibResolv::LibResolv()
+static void maybeRefreshResolver()
{
- QLibrary lib;
-#ifdef LIBRESOLV_SO
- lib.setFileName(QStringLiteral(LIBRESOLV_SO));
- if (!lib.load())
+#if defined(RES_NORELOAD)
+ // If RES_NORELOAD is defined, then the libc is capable of watching
+ // /etc/resolv.conf for changes and reloading as necessary. So accept
+ // whatever is configured.
+ return;
+#elif defined(Q_OS_DARWIN)
+ // Apple's libsystem_info.dylib:getaddrinfo() uses the
+ // libsystem_dnssd.dylib to resolve hostnames. Using res_init() has no
+ // effect on it and is thread-unsafe.
+ return;
+#elif defined(Q_OS_FREEBSD)
+ // FreeBSD automatically refreshes:
+ // https://github.com/freebsd/freebsd-src/blob/b3fe5d932264445cbf9a1c4eab01afb6179b499b/lib/libc/resolv/res_state.c#L69
+ return;
+#elif defined(Q_OS_OPENBSD)
+ // OpenBSD automatically refreshes:
+ // https://github.com/ligurio/openbsd-src/blob/b1ce0da17da254cc15b8aff25b3d55d3c7a82cec/lib/libc/asr/asr.c#L367
+ return;
+#elif defined(Q_OS_QNX)
+ // res_init() is not thread-safe; executing it leads to state corruption.
+ // Whether it reloads resolv.conf on its own is unknown.
+ return;
#endif
- {
- lib.setFileName(QLatin1String("resolv"));
- lib.load();
- }
-
- // res_ninit is required for localDomainName()
- local_res_ninit = res_ninit_proto(resolveSymbol(lib, "__res_ninit"));
- if (!local_res_ninit)
- local_res_ninit = res_ninit_proto(resolveSymbol(lib, "res_ninit"));
- if (local_res_ninit) {
- // we must now find res_nclose
- local_res_nclose = res_nclose_proto(resolveSymbol(lib, "res_nclose"));
- if (!local_res_nclose)
- local_res_nclose = res_nclose_proto(resolveSymbol(lib, "__res_nclose"));
- if (!local_res_nclose)
- local_res_ninit = nullptr;
- }
- if (ReinitNecessary || !local_res_ninit) {
- local_res_init = res_init_proto(resolveSymbol(lib, "__res_init"));
- if (!local_res_init)
- local_res_init = res_init_proto(resolveSymbol(lib, "res_init"));
-
- if (local_res_init && !local_res_ninit) {
- // if we can't get a thread-safe context, we have to use the global _res state
- local_res = res_state_ptr(resolveSymbol(lib, "_res"));
+#if QT_CONFIG(libresolv)
+ // OSes known or thought to reach here: AIX, NetBSD, Solaris,
+ // Linux with MUSL (though res_init() does nothing and is unnecessary)
+
+ Q_CONSTINIT static QT_STATBUF lastStat = {};
+ Q_CONSTINIT static QBasicMutex mutex = {};
+ if (QT_STATBUF st; QT_STAT(_PATH_RESCONF, &st) == 0) {
+ QMutexLocker locker(&mutex);
+ bool refresh = false;
+ if ((_res.options & RES_INIT) == 0)
+ refresh = true;
+ else if (lastStat.st_ctime != st.st_ctime)
+ refresh = true; // file was updated
+ else if (lastStat.st_dev != st.st_dev || lastStat.st_ino != st.st_ino)
+ refresh = true; // file was replaced
+ if (refresh) {
+ lastStat = st;
+ res_init();
}
}
+#endif
}
-LibResolv* libResolv()
-{
- static LibResolv* theLibResolv = nullptr;
- static QBasicMutex theMutex;
-
- const QMutexLocker locker(&theMutex);
- if (theLibResolv == nullptr) {
- theLibResolv = new LibResolv();
- Q_ASSERT(QCoreApplication::instance());
- QObject::connect(QCoreApplication::instance(), &QCoreApplication::destroyed, [] {
- const QMutexLocker locker(&theMutex);
- delete theLibResolv;
- theLibResolv = nullptr;
- });
- }
-
- return theLibResolv;
-}
-
-static void resolveLibrary(LibResolvFeature f)
-{
- if (LibResolv::ReinitNecessary || f == NeedResNInit)
- libResolv();
-}
-#else // QT_CONFIG(library) || Q_OS_QNX
-static void resolveLibrary(LibResolvFeature)
-{
-}
-#endif // QT_CONFIG(library) || Q_OS_QNX
-
QHostInfo QHostInfoAgent::fromName(const QString &hostName)
{
QHostInfo results;
@@ -196,12 +84,7 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
hostName.toLatin1().constData());
#endif
- // Load res_init on demand.
- resolveLibrary(NeedResInit);
-
- // If res_init is available, poll it.
- if (local_res_init)
- local_res_init();
+ maybeRefreshResolver();
QHostAddress address;
if (address.setAddress(hostName))
@@ -212,56 +95,49 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
QString QHostInfo::localDomainName()
{
-#if !defined(Q_OS_VXWORKS) && !defined(Q_OS_ANDROID)
- resolveLibrary(NeedResNInit);
- if (local_res_ninit) {
- // using thread-safe version
- res_state_ptr state = res_state_ptr(malloc(sizeof(*state)));
- Q_CHECK_PTR(state);
- memset(state, 0, sizeof(*state));
- local_res_ninit(state);
- QString domainName = QUrl::fromAce(state->defdname);
+#if QT_CONFIG(libresolv)
+ auto domainNameFromRes = [](res_state r) {
+ QString domainName;
+ if (r->defdname[0])
+ domainName = QUrl::fromAce(r->defdname);
if (domainName.isEmpty())
- domainName = QUrl::fromAce(state->dnsrch[0]);
- local_res_nclose(state);
- free(state);
-
+ domainName = QUrl::fromAce(r->dnsrch[0]);
return domainName;
+ };
+ std::remove_pointer_t<res_state> state = {};
+ if (res_ninit(&state) == 0) {
+ // using thread-safe version
+ auto guard = qScopeGuard([&] { res_nclose(&state); });
+ return domainNameFromRes(&state);
}
- if (local_res_init && local_res) {
- // using thread-unsafe version
+ // using thread-unsafe version
+ maybeRefreshResolver();
+ return domainNameFromRes(&_res);
+#endif // !QT_CONFIG(libresolv)
- local_res_init();
- QString domainName = QUrl::fromAce(local_res->defdname);
- if (domainName.isEmpty())
- domainName = QUrl::fromAce(local_res->dnsrch[0]);
- return domainName;
- }
-#endif
// nothing worked, try doing it by ourselves:
QFile resolvconf;
-#if defined(_PATH_RESCONF)
- resolvconf.setFileName(QFile::decodeName(_PATH_RESCONF));
-#else
- resolvconf.setFileName(QLatin1String("/etc/resolv.conf"));
-#endif
+ resolvconf.setFileName(_PATH_RESCONF ""_L1);
if (!resolvconf.open(QIODevice::ReadOnly))
return QString(); // failure
QString domainName;
while (!resolvconf.atEnd()) {
- QByteArray line = resolvconf.readLine().trimmed();
- if (line.startsWith("domain "))
- return QUrl::fromAce(line.mid(sizeof "domain " - 1).trimmed());
+ const QByteArray lineArray = resolvconf.readLine();
+ QByteArrayView line = QByteArrayView(lineArray).trimmed();
+ constexpr QByteArrayView domainWithSpace = "domain ";
+ if (line.startsWith(domainWithSpace))
+ return QUrl::fromAce(line.mid(domainWithSpace.size()).trimmed().toByteArray());
// in case there's no "domain" line, fall back to the first "search" entry
- if (domainName.isEmpty() && line.startsWith("search ")) {
- QByteArray searchDomain = line.mid(sizeof "search " - 1).trimmed();
+ constexpr QByteArrayView searchWithSpace = "search ";
+ if (domainName.isEmpty() && line.startsWith(searchWithSpace)) {
+ QByteArrayView searchDomain = line.mid(searchWithSpace.size()).trimmed();
int pos = searchDomain.indexOf(' ');
if (pos != -1)
searchDomain.truncate(pos);
- domainName = QUrl::fromAce(searchDomain);
+ domainName = QUrl::fromAce(searchDomain.toByteArray());
}
}
diff --git a/src/network/kernel/qhostinfo_win.cpp b/src/network/kernel/qhostinfo_win.cpp
index 0b5cc98970..61a1983e9d 100644
--- a/src/network/kernel/qhostinfo_win.cpp
+++ b/src/network/kernel/qhostinfo_win.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <winsock2.h>
diff --git a/src/network/kernel/qnetconmonitor_darwin.mm b/src/network/kernel/qnetconmonitor_darwin.mm
index 9c0c4a55f4..60b3cd6581 100644
--- a/src/network/kernel/qnetconmonitor_darwin.mm
+++ b/src/network/kernel/qnetconmonitor_darwin.mm
@@ -1,43 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "private/qnativesocketengine_p.h"
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "private/qnativesocketengine_p_p.h"
#include "private/qnetconmonitor_p.h"
#include "private/qobject_p.h"
@@ -124,6 +88,9 @@ public:
void updateState(SCNetworkReachabilityFlags newState);
void reset();
bool isReachable() const;
+#ifdef QT_PLATFORM_UIKIT
+ bool isWwan() const;
+#endif
static void probeCallback(SCNetworkReachabilityRef probe, SCNetworkReachabilityFlags flags, void *info);
@@ -139,9 +106,19 @@ void QNetworkConnectionMonitorPrivate::updateState(SCNetworkReachabilityFlags ne
// is set. There are more possible flags that require more tests/some special
// setup. So in future this part and related can change/be extended.
const bool wasReachable = isReachable();
+
+#ifdef QT_PLATFORM_UIKIT
+ const bool hadWwan = isWwan();
+#endif
+
state = newState;
if (wasReachable != isReachable())
emit q->reachabilityChanged(isReachable());
+
+#ifdef QT_PLATFORM_UIKIT
+ if (hadWwan != isWwan())
+ emit q->isWwanChanged(isWwan());
+#endif
}
void QNetworkConnectionMonitorPrivate::reset()
@@ -160,6 +137,13 @@ bool QNetworkConnectionMonitorPrivate::isReachable() const
return !!(state & kSCNetworkReachabilityFlagsReachable);
}
+#ifdef QT_PLATFORM_UIKIT // The IsWWAN flag is not available on macOS
+bool QNetworkConnectionMonitorPrivate::isWwan() const
+{
+ return !!(state & kSCNetworkReachabilityFlagsIsWWAN);
+}
+#endif
+
void QNetworkConnectionMonitorPrivate::probeCallback(SCNetworkReachabilityRef probe, SCNetworkReachabilityFlags flags, void *info)
{
// To be executed only on the reachability queue.
@@ -208,7 +192,7 @@ bool QNetworkConnectionMonitor::setTargets(const QHostAddress &local, const QHos
qt_sockaddr client = qt_hostaddress_to_sockaddr(local);
if (remote.isNull()) {
- // That's a special case our QNetworkStatusMonitor is using (AnyIpv4/6 address to check an overall status).
+ // That's a special case our QNetworkInformation backend is using (AnyIpv4/6 address to check an overall status).
d->probe = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, reinterpret_cast<sockaddr *>(&client));
} else {
qt_sockaddr target = qt_hostaddress_to_sockaddr(remote);
@@ -301,124 +285,28 @@ bool QNetworkConnectionMonitor::isReachable()
return d->isReachable();
}
-class QNetworkStatusMonitorPrivate : public QObjectPrivate
+#ifdef QT_PLATFORM_UIKIT
+bool QNetworkConnectionMonitor::isWwan() const
{
-public:
- QNetworkConnectionMonitor ipv4Probe;
- bool isOnlineIpv4 = false;
- QNetworkConnectionMonitor ipv6Probe;
- bool isOnlineIpv6 = false;
-};
-
-QNetworkStatusMonitor::QNetworkStatusMonitor(QObject *parent)
- : QObject(*new QNetworkStatusMonitorPrivate, parent)
-{
- Q_D(QNetworkStatusMonitor);
-
- if (d->ipv4Probe.setTargets(QHostAddress::AnyIPv4, {})) {
- // We manage to create SCNetworkReachabilityRef for IPv4, let's
- // read the last known state then!
- d->isOnlineIpv4 = d->ipv4Probe.isReachable();
- }
-
- if (d->ipv6Probe.setTargets(QHostAddress::AnyIPv6, {})) {
- // We manage to create SCNetworkReachability ref for IPv6, let's
- // read the last known state then!
- d->isOnlineIpv6 = d->ipv6Probe.isReachable();
- }
-
-
- connect(&d->ipv4Probe, &QNetworkConnectionMonitor::reachabilityChanged, this,
- &QNetworkStatusMonitor::reachabilityChanged, Qt::QueuedConnection);
- connect(&d->ipv6Probe, &QNetworkConnectionMonitor::reachabilityChanged, this,
- &QNetworkStatusMonitor::reachabilityChanged, Qt::QueuedConnection);
-}
-
-QNetworkStatusMonitor::~QNetworkStatusMonitor()
-{
- Q_D(QNetworkStatusMonitor);
-
- d->ipv4Probe.disconnect();
- d->ipv4Probe.stopMonitoring();
- d->ipv6Probe.disconnect();
- d->ipv6Probe.stopMonitoring();
-}
-
-bool QNetworkStatusMonitor::start()
-{
- Q_D(QNetworkStatusMonitor);
+ Q_D(const QNetworkConnectionMonitor);
if (isMonitoring()) {
- qCWarning(lcNetMon, "Network status monitor is already active");
- return true;
+ qCWarning(lcNetMon, "Calling isWwan() is unsafe after the monitoring started");
+ return false;
}
- d->ipv4Probe.startMonitoring();
- d->ipv6Probe.startMonitoring();
-
- return isMonitoring();
-}
-
-void QNetworkStatusMonitor::stop()
-{
- Q_D(QNetworkStatusMonitor);
-
- if (d->ipv4Probe.isMonitoring())
- d->ipv4Probe.stopMonitoring();
- if (d->ipv6Probe.isMonitoring())
- d->ipv6Probe.stopMonitoring();
-}
-
-bool QNetworkStatusMonitor::isMonitoring() const
-{
- Q_D(const QNetworkStatusMonitor);
-
- return d->ipv4Probe.isMonitoring() || d->ipv6Probe.isMonitoring();
-}
-
-bool QNetworkStatusMonitor::isNetworkAccessible()
-{
- // This function is to be executed on the thread that created
- // and uses 'this'.
- Q_D(QNetworkStatusMonitor);
-
- return d->isOnlineIpv4 || d->isOnlineIpv6;
-}
+ if (!d->probe) {
+ qCWarning(lcNetMon, "Medium is unknown, set the target first");
+ return false;
+ }
-bool QNetworkStatusMonitor::event(QEvent *event)
-{
- return QObject::event(event);
+ return d->isWwan();
}
+#endif
-bool QNetworkStatusMonitor::isEnabled()
+bool QNetworkConnectionMonitor::isEnabled()
{
return true;
}
-void QNetworkStatusMonitor::reachabilityChanged(bool online)
-{
- // This function is executed on the thread that created/uses 'this',
- // not on the reachability queue.
- Q_D(QNetworkStatusMonitor);
-
- auto probe = qobject_cast<QNetworkConnectionMonitor *>(sender());
- if (!probe)
- return;
-
- const bool isIpv4 = probe == &d->ipv4Probe;
- bool &probeOnline = isIpv4 ? d->isOnlineIpv4 : d->isOnlineIpv6;
- bool otherOnline = isIpv4 ? d->isOnlineIpv6 : d->isOnlineIpv4;
-
- if (probeOnline == online) {
- // We knew this already?
- return;
- }
-
- probeOnline = online;
- if (!otherOnline) {
- // We either just lost or got a network access.
- emit onlineStateChanged(probeOnline);
- }
-}
-
QT_END_NAMESPACE
diff --git a/src/network/kernel/qnetconmonitor_p.h b/src/network/kernel/qnetconmonitor_p.h
index 30e3fa16ea..26211bb770 100644
--- a/src/network/kernel/qnetconmonitor_p.h
+++ b/src/network/kernel/qnetconmonitor_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNETCONMONITOR_P_H
#define QNETCONMONITOR_P_H
@@ -61,7 +25,7 @@
QT_BEGIN_NAMESPACE
class QNetworkConnectionMonitorPrivate;
-class Q_AUTOTEST_EXPORT QNetworkConnectionMonitor : public QObject
+class Q_NETWORK_EXPORT QNetworkConnectionMonitor : public QObject
{
Q_OBJECT
@@ -73,54 +37,33 @@ public:
bool setTargets(const QHostAddress &local, const QHostAddress &remote);
bool isReachable();
- // Important: on Darwin you should not call isReachable() after
+#ifdef QT_PLATFORM_UIKIT
+ bool isWwan() const;
+#endif
+
+ // Important: on Darwin you should not call isReachable/isWwan() after
// startMonitoring(), you have to listen to reachabilityChanged()
// signal instead.
bool startMonitoring();
bool isMonitoring() const;
void stopMonitoring();
+ static bool isEnabled();
+
Q_SIGNALS:
// Important: connect to this using QueuedConnection. On Darwin
// callback is coming on a special dispatch queue.
void reachabilityChanged(bool isOnline);
+#ifdef QT_PLATFORM_UIKIT
+ void isWwanChanged(bool isWwan);
+#endif
+
private:
Q_DECLARE_PRIVATE(QNetworkConnectionMonitor)
Q_DISABLE_COPY_MOVE(QNetworkConnectionMonitor)
};
-class QNetworkStatusMonitorPrivate;
-class Q_AUTOTEST_EXPORT QNetworkStatusMonitor : public QObject
-{
- Q_OBJECT
-
-public:
- QNetworkStatusMonitor(QObject *parent);
- ~QNetworkStatusMonitor();
-
- bool isNetworkAccessible();
-
- bool start();
- void stop();
- bool isMonitoring() const;
-
- bool event(QEvent *event) override;
-
- static bool isEnabled();
-
-Q_SIGNALS:
- // Unlike QNetworkConnectionMonitor, this can be connected to directly.
- void onlineStateChanged(bool isOnline);
-
-private slots:
- void reachabilityChanged(bool isOnline);
-
-private:
- Q_DECLARE_PRIVATE(QNetworkStatusMonitor)
- Q_DISABLE_COPY_MOVE(QNetworkStatusMonitor)
-};
-
Q_DECLARE_LOGGING_CATEGORY(lcNetMon)
QT_END_NAMESPACE
diff --git a/src/network/kernel/qnetconmonitor_stub.cpp b/src/network/kernel/qnetconmonitor_stub.cpp
index a992339e42..d3f1224e86 100644
--- a/src/network/kernel/qnetconmonitor_stub.cpp
+++ b/src/network/kernel/qnetconmonitor_stub.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qnetconmonitor_p.h"
@@ -45,7 +9,7 @@ QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcNetMon, "qt.network.monitor");
-// Note: this 'stub' version is never enabled (see QNetworkStatusMonitor::isEnabled below)
+// Note: this 'stub' version is never enabled (see QNetworkConnectionMonitor::isEnabled below)
// and thus should never affect QNAM in any unusuall way. Having this 'stub' version is similar
// to building Qt with bearer management configured out.
@@ -96,51 +60,9 @@ bool QNetworkConnectionMonitor::isReachable()
return false;
}
-class QNetworkStatusMonitorPrivate : public QObjectPrivate
-{
-};
-
-QNetworkStatusMonitor::QNetworkStatusMonitor(QObject *parent)
- : QObject(*new QNetworkStatusMonitorPrivate, parent)
-{
-}
-
-QNetworkStatusMonitor::~QNetworkStatusMonitor()
-{
-}
-
-bool QNetworkStatusMonitor::start()
-{
- return false;
-}
-
-void QNetworkStatusMonitor::stop()
-{
-}
-
-bool QNetworkStatusMonitor::isMonitoring() const
-{
- return false;
-}
-
-bool QNetworkStatusMonitor::isNetworkAccessible()
+bool QNetworkConnectionMonitor::isEnabled()
{
return false;
}
-bool QNetworkStatusMonitor::event(QEvent *event)
-{
- return QObject::event(event);
-}
-
-bool QNetworkStatusMonitor::isEnabled()
-{
- return false;
-}
-
-void QNetworkStatusMonitor::reachabilityChanged(bool online)
-{
- Q_UNUSED(online);
-}
-
QT_END_NAMESPACE
diff --git a/src/network/kernel/qnetconmonitor_win.cpp b/src/network/kernel/qnetconmonitor_win.cpp
index c3f28d77b1..bf6aff1e46 100644
--- a/src/network/kernel/qnetconmonitor_win.cpp
+++ b/src/network/kernel/qnetconmonitor_win.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qnetconmonitor_p.h"
@@ -44,13 +8,15 @@
#include <QtCore/quuid.h>
#include <QtCore/qmetaobject.h>
+#include <QtCore/private/qfunctions_win_p.h>
+#include <QtCore/private/qsystemerror_p.h>
+
#include <QtNetwork/qnetworkinterface.h>
#include <objbase.h>
#include <netlistmgr.h>
#include <wrl/client.h>
#include <wrl/wrappers/corewrappers.h>
-#include <comdef.h>
#include <iphlpapi.h>
#include <algorithm>
@@ -62,12 +28,6 @@ QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcNetMon, "qt.network.monitor");
namespace {
-QString errorStringFromHResult(HRESULT hr)
-{
- _com_error error(hr);
- return QString::fromWCharArray(error.ErrorMessage());
-}
-
template<typename T>
bool QueryInterfaceImpl(IUnknown *from, REFIID riid, void **ppvObject)
{
@@ -160,6 +120,8 @@ public:
void setConnectivity(NLM_CONNECTIVITY newConnectivity);
private:
+ QComHelper comHelper;
+
ComPtr<QNetworkConnectionEvents> connectionEvents;
// We can assume we have access to internet/subnet when this class is created because
// connection has already been established to the peer:
@@ -172,7 +134,6 @@ private:
bool sameSubnet = false;
bool isLinkLocal = false;
bool monitoring = false;
- bool comInitFailed = false;
bool remoteIsIPv6 = false;
};
@@ -182,8 +143,8 @@ QNetworkConnectionEvents::QNetworkConnectionEvents(QNetworkConnectionMonitorPriv
auto hr = CoCreateInstance(CLSID_NetworkListManager, nullptr, CLSCTX_INPROC_SERVER,
IID_INetworkListManager, &networkListManager);
if (FAILED(hr)) {
- qCWarning(lcNetMon) << "Could not get a NetworkListManager instance:"
- << errorStringFromHResult(hr);
+ qCDebug(lcNetMon) << "Could not get a NetworkListManager instance:"
+ << QSystemError::windowsComString(hr);
return;
}
@@ -194,8 +155,8 @@ QNetworkConnectionEvents::QNetworkConnectionEvents(QNetworkConnectionMonitorPriv
&connectionPoint);
}
if (FAILED(hr)) {
- qCWarning(lcNetMon) << "Failed to get connection point for network events:"
- << errorStringFromHResult(hr);
+ qCDebug(lcNetMon) << "Failed to get connection point for network events:"
+ << QSystemError::windowsComString(hr);
}
}
@@ -206,27 +167,33 @@ QNetworkConnectionEvents::~QNetworkConnectionEvents()
ComPtr<INetworkConnection> QNetworkConnectionEvents::getNetworkConnectionFromAdapterGuid(QUuid guid)
{
+ if (!networkListManager) {
+ qCDebug(lcNetMon) << "Failed to enumerate network connections:"
+ << "NetworkListManager was not instantiated";
+ return nullptr;
+ }
+
ComPtr<IEnumNetworkConnections> connections;
auto hr = networkListManager->GetNetworkConnections(connections.GetAddressOf());
if (FAILED(hr)) {
- qCWarning(lcNetMon) << "Failed to enumerate network connections:"
- << errorStringFromHResult(hr);
+ qCDebug(lcNetMon) << "Failed to enumerate network connections:"
+ << QSystemError::windowsComString(hr);
return nullptr;
}
ComPtr<INetworkConnection> connection = nullptr;
do {
hr = connections->Next(1, connection.GetAddressOf(), nullptr);
if (FAILED(hr)) {
- qCWarning(lcNetMon) << "Failed to get next network connection in enumeration:"
- << errorStringFromHResult(hr);
+ qCDebug(lcNetMon) << "Failed to get next network connection in enumeration:"
+ << QSystemError::windowsComString(hr);
break;
}
if (connection) {
GUID adapterId;
hr = connection->GetAdapterId(&adapterId);
if (FAILED(hr)) {
- qCWarning(lcNetMon) << "Failed to get adapter ID from network connection:"
- << errorStringFromHResult(hr);
+ qCDebug(lcNetMon) << "Failed to get adapter ID from network connection:"
+ << QSystemError::windowsComString(hr);
continue;
}
if (guid == adapterId)
@@ -276,22 +243,23 @@ bool QNetworkConnectionEvents::setTarget(const QNetworkInterface &iface)
NET_LUID luid;
if (ConvertInterfaceIndexToLuid(iface.index(), &luid) != NO_ERROR) {
- qCWarning(lcNetMon, "Could not get the LUID for the interface.");
+ qCDebug(lcNetMon, "Could not get the LUID for the interface.");
return false;
}
GUID guid;
if (ConvertInterfaceLuidToGuid(&luid, &guid) != NO_ERROR) {
- qCWarning(lcNetMon, "Could not get the GUID for the interface.");
+ qCDebug(lcNetMon, "Could not get the GUID for the interface.");
return false;
}
ComPtr<INetworkConnection> connection = getNetworkConnectionFromAdapterGuid(guid);
if (!connection) {
- qCWarning(lcNetMon, "Could not get the INetworkConnection instance for the adapter GUID.");
+ qCDebug(lcNetMon, "Could not get the INetworkConnection instance for the adapter GUID.");
return false;
}
auto hr = connection->GetConnectionId(&guid);
if (FAILED(hr)) {
- qCWarning(lcNetMon) << "Failed to get the connection's GUID:" << errorStringFromHResult(hr);
+ qCDebug(lcNetMon) << "Failed to get the connection's GUID:"
+ << QSystemError::windowsComString(hr);
return false;
}
currentConnectionId = guid;
@@ -302,19 +270,19 @@ bool QNetworkConnectionEvents::setTarget(const QNetworkInterface &iface)
bool QNetworkConnectionEvents::startMonitoring()
{
if (currentConnectionId.isNull()) {
- qCWarning(lcNetMon, "Can not start monitoring, set targets first");
+ qCDebug(lcNetMon, "Can not start monitoring, set targets first");
return false;
}
if (!connectionPoint) {
- qCWarning(lcNetMon,
+ qCDebug(lcNetMon,
"We don't have the connection point, cannot start listening to events!");
return false;
}
auto hr = connectionPoint->Advise(this, &cookie);
if (FAILED(hr)) {
- qCWarning(lcNetMon) << "Failed to subscribe to network connectivity events:"
- << errorStringFromHResult(hr);
+ qCDebug(lcNetMon) << "Failed to subscribe to network connectivity events:"
+ << QSystemError::windowsComString(hr);
return false;
}
return true;
@@ -324,8 +292,8 @@ bool QNetworkConnectionEvents::stopMonitoring()
{
auto hr = connectionPoint->Unadvise(cookie);
if (FAILED(hr)) {
- qCWarning(lcNetMon) << "Failed to unsubscribe from network connection events:"
- << errorStringFromHResult(hr);
+ qCDebug(lcNetMon) << "Failed to unsubscribe from network connection events:"
+ << QSystemError::windowsComString(hr);
return false;
}
cookie = 0;
@@ -335,30 +303,25 @@ bool QNetworkConnectionEvents::stopMonitoring()
QNetworkConnectionMonitorPrivate::QNetworkConnectionMonitorPrivate()
{
- auto hr = CoInitialize(nullptr);
- if (FAILED(hr)) {
- qCWarning(lcNetMon) << "Failed to initialize COM:" << errorStringFromHResult(hr);
- comInitFailed = true;
+ if (!comHelper.isValid())
return;
- }
connectionEvents = new QNetworkConnectionEvents(this);
}
QNetworkConnectionMonitorPrivate::~QNetworkConnectionMonitorPrivate()
{
- if (comInitFailed)
+ if (!comHelper.isValid())
return;
if (monitoring)
stopMonitoring();
connectionEvents.Reset();
- CoUninitialize();
}
bool QNetworkConnectionMonitorPrivate::setTargets(const QHostAddress &local,
const QHostAddress &remote)
{
- if (comInitFailed)
+ if (!comHelper.isValid())
return false;
QNetworkInterface iface = getInterfaceFromHostAddress(local);
@@ -369,7 +332,7 @@ bool QNetworkConnectionMonitorPrivate::setTargets(const QHostAddress &local,
addressEntries.cbegin(), addressEntries.cend(),
[&local](const QNetworkAddressEntry &entry) { return entry.ip() == local; });
if (Q_UNLIKELY(it == addressEntries.cend())) {
- qCWarning(lcNetMon, "The address entry we were working with disappeared");
+ qCDebug(lcNetMon, "The address entry we were working with disappeared");
return false;
}
sameSubnet = remote.isInSubnet(local, it->prefixLength());
@@ -423,11 +386,11 @@ QNetworkConnectionMonitor::~QNetworkConnectionMonitor() = default;
bool QNetworkConnectionMonitor::setTargets(const QHostAddress &local, const QHostAddress &remote)
{
if (isMonitoring()) {
- qCWarning(lcNetMon, "Monitor is already active, call stopMonitoring() first");
+ qCDebug(lcNetMon, "Monitor is already active, call stopMonitoring() first");
return false;
}
if (local.isNull()) {
- qCWarning(lcNetMon, "Invalid (null) local address, cannot create a reachability target");
+ qCDebug(lcNetMon, "Invalid (null) local address, cannot create a reachability target");
return false;
}
// Silently return false for loopback addresses instead of printing warnings later
@@ -441,7 +404,7 @@ bool QNetworkConnectionMonitor::startMonitoring()
{
Q_D(QNetworkConnectionMonitor);
if (isMonitoring()) {
- qCWarning(lcNetMon, "Monitor is already active, call stopMonitoring() first");
+ qCDebug(lcNetMon, "Monitor is already active, call stopMonitoring() first");
return false;
}
return d->startMonitoring();
@@ -456,7 +419,7 @@ void QNetworkConnectionMonitor::stopMonitoring()
{
Q_D(QNetworkConnectionMonitor);
if (!isMonitoring()) {
- qCWarning(lcNetMon, "stopMonitoring was called when not monitoring!");
+ qCDebug(lcNetMon, "stopMonitoring was called when not monitoring!");
return;
}
d->stopMonitoring();
@@ -490,280 +453,9 @@ bool QNetworkConnectionMonitor::isReachable()
return d_func()->connectivity & required;
}
-class QNetworkListManagerEvents : public INetworkListManagerEvents
-{
-public:
- QNetworkListManagerEvents(QNetworkStatusMonitorPrivate *monitor);
- virtual ~QNetworkListManagerEvents();
-
- HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) override;
-
- ULONG STDMETHODCALLTYPE AddRef() override { return ++ref; }
- ULONG STDMETHODCALLTYPE Release() override
- {
- if (--ref == 0) {
- delete this;
- return 0;
- }
- return ref;
- }
-
- HRESULT STDMETHODCALLTYPE ConnectivityChanged(NLM_CONNECTIVITY newConnectivity) override;
-
- [[nodiscard]]
- bool start();
- bool stop();
-
-private:
- ComPtr<INetworkListManager> networkListManager = nullptr;
- ComPtr<IConnectionPoint> connectionPoint = nullptr;
-
- QNetworkStatusMonitorPrivate *monitor = nullptr;
-
- QAtomicInteger<ULONG> ref = 0;
- DWORD cookie = 0;
-};
-
-class QNetworkStatusMonitorPrivate : public QObjectPrivate
-{
- Q_DECLARE_PUBLIC(QNetworkStatusMonitor);
-
-public:
- QNetworkStatusMonitorPrivate();
- ~QNetworkStatusMonitorPrivate();
-
- [[nodiscard]]
- bool start();
- void stop();
-
- void setConnectivity(NLM_CONNECTIVITY newConnectivity);
-
-private:
- friend class QNetworkListManagerEvents;
-
- ComPtr<QNetworkListManagerEvents> managerEvents;
- NLM_CONNECTIVITY connectivity = NLM_CONNECTIVITY_DISCONNECTED;
-
- bool monitoring = false;
- bool comInitFailed = false;
-};
-
-QNetworkListManagerEvents::QNetworkListManagerEvents(QNetworkStatusMonitorPrivate *monitor)
- : monitor(monitor)
-{
- auto hr = CoCreateInstance(CLSID_NetworkListManager, nullptr, CLSCTX_INPROC_SERVER,
- IID_INetworkListManager, &networkListManager);
- if (FAILED(hr)) {
- qCWarning(lcNetMon) << "Could not get a NetworkListManager instance:"
- << errorStringFromHResult(hr);
- return;
- }
-
- // Set initial connectivity
- hr = networkListManager->GetConnectivity(&monitor->connectivity);
- if (FAILED(hr))
- qCWarning(lcNetMon) << "Could not get connectivity:" << errorStringFromHResult(hr);
-
- ComPtr<IConnectionPointContainer> connectionPointContainer;
- hr = networkListManager.As(&connectionPointContainer);
- if (SUCCEEDED(hr)) {
- hr = connectionPointContainer->FindConnectionPoint(IID_INetworkListManagerEvents,
- &connectionPoint);
- }
- if (FAILED(hr)) {
- qCWarning(lcNetMon) << "Failed to get connection point for network list manager events:"
- << errorStringFromHResult(hr);
- }
-}
-
-QNetworkListManagerEvents::~QNetworkListManagerEvents()
-{
- Q_ASSERT(ref == 0);
-}
-
-HRESULT STDMETHODCALLTYPE QNetworkListManagerEvents::QueryInterface(REFIID riid, void **ppvObject)
-{
- if (!ppvObject)
- return E_INVALIDARG;
-
- return QueryInterfaceImpl<IUnknown>(this, riid, ppvObject)
- || QueryInterfaceImpl<INetworkListManagerEvents>(this, riid, ppvObject)
- ? S_OK
- : E_NOINTERFACE;
-}
-
-HRESULT STDMETHODCALLTYPE
-QNetworkListManagerEvents::ConnectivityChanged(NLM_CONNECTIVITY newConnectivity)
+bool QNetworkConnectionMonitor::isEnabled()
{
- // This function is run on a different thread than 'monitor' is created on, so we need to run
- // it on that thread
- QMetaObject::invokeMethod(monitor->q_ptr,
- [newConnectivity, monitor = this->monitor]() {
- monitor->setConnectivity(newConnectivity);
- },
- Qt::QueuedConnection);
- return S_OK;
-}
-
-bool QNetworkListManagerEvents::start()
-{
- if (!connectionPoint) {
- qCWarning(lcNetMon, "Initialization failed, can't start!");
- return false;
- }
- auto hr = connectionPoint->Advise(this, &cookie);
- if (FAILED(hr)) {
- qCWarning(lcNetMon) << "Failed to subscribe to network connectivity events:"
- << errorStringFromHResult(hr);
- return false;
- }
-
- // Update connectivity since it might have changed since this class was constructed
- NLM_CONNECTIVITY connectivity;
- hr = networkListManager->GetConnectivity(&connectivity);
- if (FAILED(hr))
- qCWarning(lcNetMon) << "Could not get connectivity:" << errorStringFromHResult(hr);
- else
- monitor->setConnectivity(connectivity);
- return true;
-}
-
-bool QNetworkListManagerEvents::stop()
-{
- Q_ASSERT(connectionPoint);
- auto hr = connectionPoint->Unadvise(cookie);
- if (FAILED(hr)) {
- qCWarning(lcNetMon) << "Failed to unsubscribe from network connectivity events:"
- << errorStringFromHResult(hr);
- return false;
- }
- cookie = 0;
return true;
}
-QNetworkStatusMonitorPrivate::QNetworkStatusMonitorPrivate()
-{
- auto hr = CoInitialize(nullptr);
- if (FAILED(hr)) {
- qCWarning(lcNetMon) << "Failed to initialize COM:" << errorStringFromHResult(hr);
- comInitFailed = true;
- return;
- }
- managerEvents = new QNetworkListManagerEvents(this);
-}
-
-QNetworkStatusMonitorPrivate::~QNetworkStatusMonitorPrivate()
-{
- if (comInitFailed)
- return;
- if (monitoring)
- stop();
-}
-
-void QNetworkStatusMonitorPrivate::setConnectivity(NLM_CONNECTIVITY newConnectivity)
-{
- Q_Q(QNetworkStatusMonitor);
-
- const bool oldAccessibility = q->isNetworkAccessible();
- connectivity = newConnectivity;
- const bool accessibility = q->isNetworkAccessible();
- if (oldAccessibility != accessibility)
- emit q->onlineStateChanged(accessibility);
-}
-
-bool QNetworkStatusMonitorPrivate::start()
-{
- Q_ASSERT(!monitoring);
-
- if (comInitFailed) {
- auto hr = CoInitialize(nullptr);
- if (FAILED(hr)) {
- qCWarning(lcNetMon) << "Failed to initialize COM:" << errorStringFromHResult(hr);
- comInitFailed = true;
- return false;
- }
- comInitFailed = false;
- }
- if (!managerEvents)
- managerEvents = new QNetworkListManagerEvents(this);
-
- if (managerEvents->start())
- monitoring = true;
- return monitoring;
-}
-
-void QNetworkStatusMonitorPrivate::stop()
-{
- Q_ASSERT(managerEvents);
- Q_ASSERT(monitoring);
- // Can return false but realistically shouldn't since that would break everything:
- managerEvents->stop();
- monitoring = false;
- managerEvents.Reset();
-
- CoUninitialize();
- comInitFailed = true; // we check this value in start() to see if we need to re-initialize
-}
-
-QNetworkStatusMonitor::QNetworkStatusMonitor(QObject *parent)
- : QObject(*new QNetworkStatusMonitorPrivate, parent)
-{
-}
-
-QNetworkStatusMonitor::~QNetworkStatusMonitor() {}
-
-bool QNetworkStatusMonitor::start()
-{
- if (isMonitoring()) {
- qCWarning(lcNetMon, "Monitor is already active, call stopMonitoring() first");
- return false;
- }
-
- return d_func()->start();
-}
-
-void QNetworkStatusMonitor::stop()
-{
- if (!isMonitoring()) {
- qCWarning(lcNetMon, "stopMonitoring was called when not monitoring!");
- return;
- }
-
- d_func()->stop();
-}
-
-bool QNetworkStatusMonitor::isMonitoring() const
-{
- return d_func()->monitoring;
-}
-
-bool QNetworkStatusMonitor::isNetworkAccessible()
-{
- return d_func()->connectivity
- & (NLM_CONNECTIVITY_IPV4_INTERNET | NLM_CONNECTIVITY_IPV6_INTERNET
- | NLM_CONNECTIVITY_IPV4_SUBNET | NLM_CONNECTIVITY_IPV6_SUBNET
- | NLM_CONNECTIVITY_IPV4_LOCALNETWORK | NLM_CONNECTIVITY_IPV6_LOCALNETWORK);
-}
-
-bool QNetworkStatusMonitor::event(QEvent *event)
-{
- if (event->type() == QEvent::ThreadChange && isMonitoring()) {
- stop();
- QMetaObject::invokeMethod(this, &QNetworkStatusMonitor::start, Qt::QueuedConnection);
- }
-
- return QObject::event(event);
-}
-
-bool QNetworkStatusMonitor::isEnabled()
-{
- return true;
-}
-
-void QNetworkStatusMonitor::reachabilityChanged(bool online)
-{
- Q_UNUSED(online);
- Q_UNREACHABLE();
-}
-
QT_END_NAMESPACE
diff --git a/src/network/kernel/qnetworkdatagram.cpp b/src/network/kernel/qnetworkdatagram.cpp
index c8c87d4549..a97eb25a51 100644
--- a/src/network/kernel/qnetworkdatagram.cpp
+++ b/src/network/kernel/qnetworkdatagram.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qnetworkdatagram.h"
#include "qnetworkdatagram_p.h"
@@ -44,6 +8,8 @@
QT_BEGIN_NAMESPACE
+QT_IMPL_METATYPE_EXTERN(QNetworkDatagram)
+
/*!
\class QNetworkDatagram
\brief The QNetworkDatagram class provides the data and metadata of a UDP datagram.
@@ -515,7 +481,7 @@ void QNetworkDatagram::makeReply_helper_inplace(const QByteArray &data)
void QNetworkDatagram::destroy(QNetworkDatagramPrivate *d)
{
- Q_ASSUME(d);
+ Q_ASSERT(d);
delete d;
}
diff --git a/src/network/kernel/qnetworkdatagram.h b/src/network/kernel/qnetworkdatagram.h
index 70958fea42..dcc2f1102f 100644
--- a/src/network/kernel/qnetworkdatagram.h
+++ b/src/network/kernel/qnetworkdatagram.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNETWORKDATAGRAM_H
#define QNETWORKDATAGRAM_H
@@ -68,7 +32,7 @@ public:
{ swap(other); return *this; }
void swap(QNetworkDatagram &other) noexcept
- { qSwap(d, other.d); }
+ { qt_ptr_swap(d, other.d); }
void clear();
bool isValid() const;
@@ -91,7 +55,7 @@ public:
QByteArray data() const;
void setData(const QByteArray &data);
-#if defined(Q_COMPILER_REF_QUALIFIERS) || defined(Q_CLANG_QDOC)
+#if defined(Q_COMPILER_REF_QUALIFIERS) || defined(Q_QDOC)
QNetworkDatagram makeReply(const QByteArray &payload) const &
{ return makeReply_helper(payload); }
QNetworkDatagram makeReply(const QByteArray &payload) &&
@@ -116,7 +80,7 @@ Q_DECLARE_SHARED(QNetworkDatagram)
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QNetworkDatagram)
+QT_DECL_METATYPE_EXTERN(QNetworkDatagram, Q_NETWORK_EXPORT)
#endif // QT_NO_UDPSOCKET
diff --git a/src/network/kernel/qnetworkdatagram_p.h b/src/network/kernel/qnetworkdatagram_p.h
index 5b5c037488..dcaddff1a9 100644
--- a/src/network/kernel/qnetworkdatagram_p.h
+++ b/src/network/kernel/qnetworkdatagram_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2015 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNETWORKDATAGRAM_P_H
#define QNETWORKDATAGRAM_P_H
diff --git a/src/network/kernel/qnetworkinformation.cpp b/src/network/kernel/qnetworkinformation.cpp
new file mode 100644
index 0000000000..10d6b89e2c
--- /dev/null
+++ b/src/network/kernel/qnetworkinformation.cpp
@@ -0,0 +1,774 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+// #define DEBUG_LOADING
+
+#include "qnetworkinformation.h"
+#include <QtNetwork/private/qnetworkinformation_p.h>
+#include <QtNetwork/qnetworkinformation.h>
+
+#include <QtCore/private/qobject_p.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qthread.h>
+#include <QtCore/private/qfactoryloader_p.h>
+
+#include <algorithm>
+#include <memory>
+#include <mutex>
+
+QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcNetInfo)
+Q_LOGGING_CATEGORY(lcNetInfo, "qt.network.info");
+
+struct QNetworkInformationDeleter
+{
+ void operator()(QNetworkInformation *information) { delete information; }
+};
+
+Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, qniLoader,
+ (QNetworkInformationBackendFactory_iid,
+ QStringLiteral("/networkinformation")))
+
+struct QStaticNetworkInformationDataHolder
+{
+ QMutex instanceMutex;
+ std::unique_ptr<QNetworkInformation, QNetworkInformationDeleter> instanceHolder;
+ QList<QNetworkInformationBackendFactory *> factories;
+};
+Q_GLOBAL_STATIC(QStaticNetworkInformationDataHolder, dataHolder);
+
+static void networkInfoCleanup()
+{
+ if (!dataHolder.exists())
+ return;
+ QMutexLocker locker(&dataHolder->instanceMutex);
+ QNetworkInformation *instance = dataHolder->instanceHolder.get();
+ if (!instance)
+ return;
+
+ dataHolder->instanceHolder.reset();
+}
+
+using namespace Qt::Literals::StringLiterals;
+
+class QNetworkInformationDummyBackend : public QNetworkInformationBackend {
+ Q_OBJECT
+public:
+ QString name() const override { return u"dummy"_s; }
+ QNetworkInformation::Features featuresSupported() const override
+ {
+ return {};
+ }
+};
+
+class QNetworkInformationPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QNetworkInformation)
+public:
+ QNetworkInformationPrivate(QNetworkInformationBackend *backend) : backend(backend) {
+ qAddPostRoutine(&networkInfoCleanup);
+ }
+
+ static QNetworkInformation *create(QNetworkInformation::Features features);
+ static QNetworkInformation *create(QStringView name);
+ static QNetworkInformation *createDummy();
+ static QNetworkInformation *instance()
+ {
+ if (!dataHolder())
+ return nullptr;
+ QMutexLocker locker(&dataHolder->instanceMutex);
+ return dataHolder->instanceHolder.get();
+ }
+ static QStringList backendNames();
+ static void addToList(QNetworkInformationBackendFactory *factory);
+ static void removeFromList(QNetworkInformationBackendFactory *factory);
+
+private:
+ static bool initializeList();
+
+ std::unique_ptr<QNetworkInformationBackend> backend;
+};
+
+bool QNetworkInformationPrivate::initializeList()
+{
+ if (!qniLoader())
+ return false;
+ if (!dataHolder())
+ return false;
+ Q_CONSTINIT static QBasicMutex mutex;
+ QMutexLocker initLocker(&mutex);
+
+#if QT_CONFIG(library)
+ qniLoader->update();
+#endif
+ // Instantiates the plugins (and registers the factories)
+ int index = 0;
+ while (qniLoader->instance(index))
+ ++index;
+ initLocker.unlock();
+
+ // Now sort the list on number of features available (then name)
+ const auto featuresNameOrder = [](QNetworkInformationBackendFactory *a,
+ QNetworkInformationBackendFactory *b) {
+ if (!a || !b)
+ return a && !b;
+ auto aFeaturesSupported = qPopulationCount(unsigned(a->featuresSupported()));
+ auto bFeaturesSupported = qPopulationCount(unsigned(b->featuresSupported()));
+ return aFeaturesSupported > bFeaturesSupported
+ || (aFeaturesSupported == bFeaturesSupported
+ && a->name().compare(b->name(), Qt::CaseInsensitive) < 0);
+ };
+ QMutexLocker instanceLocker(&dataHolder->instanceMutex);
+ std::sort(dataHolder->factories.begin(), dataHolder->factories.end(), featuresNameOrder);
+
+ return !dataHolder->factories.isEmpty();
+}
+
+void QNetworkInformationPrivate::addToList(QNetworkInformationBackendFactory *factory)
+{
+ // @note: factory is in the base class ctor
+ if (!dataHolder())
+ return;
+ QMutexLocker locker(&dataHolder->instanceMutex);
+ dataHolder->factories.append(factory);
+}
+
+void QNetworkInformationPrivate::removeFromList(QNetworkInformationBackendFactory *factory)
+{
+ // @note: factory is in the base class dtor
+ if (!dataHolder.exists())
+ return;
+ QMutexLocker locker(&dataHolder->instanceMutex);
+ dataHolder->factories.removeAll(factory);
+}
+
+QStringList QNetworkInformationPrivate::backendNames()
+{
+ if (!dataHolder())
+ return {};
+ if (!initializeList())
+ return {};
+
+ QMutexLocker locker(&dataHolder->instanceMutex);
+ const QList copy = dataHolder->factories;
+ locker.unlock();
+
+ QStringList result;
+ result.reserve(copy.size());
+ for (const auto *factory : copy)
+ result << factory->name();
+ return result;
+}
+
+QNetworkInformation *QNetworkInformationPrivate::create(QStringView name)
+{
+ if (name.isEmpty())
+ return nullptr;
+ if (!dataHolder())
+ return nullptr;
+#ifdef DEBUG_LOADING
+ qDebug().nospace() << "create() called with name=\"" << name
+ << "\". instanceHolder initialized? " << !!dataHolder->instanceHolder;
+#endif
+ if (!initializeList()) {
+#ifdef DEBUG_LOADING
+ qDebug("Failed to initialize list, returning.");
+#endif
+ return nullptr;
+ }
+
+ QMutexLocker locker(&dataHolder->instanceMutex);
+ if (dataHolder->instanceHolder)
+ return dataHolder->instanceHolder.get();
+
+
+ const auto nameMatches = [name](QNetworkInformationBackendFactory *factory) {
+ return factory->name().compare(name, Qt::CaseInsensitive) == 0;
+ };
+ auto it = std::find_if(dataHolder->factories.cbegin(), dataHolder->factories.cend(),
+ nameMatches);
+ if (it == dataHolder->factories.cend()) {
+#ifdef DEBUG_LOADING
+ if (dataHolder->factories.isEmpty()) {
+ qDebug("No plugins available");
+ } else {
+ QString listNames;
+ listNames.reserve(8 * dataHolder->factories.count());
+ for (const auto *factory : std::as_const(dataHolder->factories))
+ listNames += factory->name() + ", "_L1;
+ listNames.chop(2);
+ qDebug().nospace() << "Couldn't find " << name << " in list with names: { "
+ << listNames << " }";
+ }
+#endif
+ return nullptr;
+ }
+#ifdef DEBUG_LOADING
+ qDebug() << "Creating instance using loader named " << (*it)->name();
+#endif
+ QNetworkInformationBackend *backend = (*it)->create((*it)->featuresSupported());
+ if (!backend)
+ return nullptr;
+ dataHolder->instanceHolder.reset(new QNetworkInformation(backend));
+ Q_ASSERT(name.isEmpty()
+ || dataHolder->instanceHolder->backendName().compare(name, Qt::CaseInsensitive) == 0);
+ return dataHolder->instanceHolder.get();
+}
+
+QNetworkInformation *QNetworkInformationPrivate::create(QNetworkInformation::Features features)
+{
+ if (!dataHolder())
+ return nullptr;
+#ifdef DEBUG_LOADING
+ qDebug().nospace() << "create() called with features=\"" << features
+ << "\". instanceHolder initialized? " << !!dataHolder->instanceHolder;
+#endif
+ if (features == 0)
+ return nullptr;
+
+ if (!initializeList()) {
+#ifdef DEBUG_LOADING
+ qDebug("Failed to initialize list, returning.");
+#endif
+ return nullptr;
+ }
+ QMutexLocker locker(&dataHolder->instanceMutex);
+ if (dataHolder->instanceHolder)
+ return dataHolder->instanceHolder.get();
+
+ const auto supportsRequestedFeatures = [features](QNetworkInformationBackendFactory *factory) {
+ return factory && factory->featuresSupported().testFlags(features);
+ };
+
+ for (auto it = dataHolder->factories.cbegin(), end = dataHolder->factories.cend(); it != end;
+ ++it) {
+ it = std::find_if(it, end, supportsRequestedFeatures);
+ if (it == end) {
+#ifdef DEBUG_LOADING
+ if (dataHolder->factories.isEmpty()) {
+ qDebug("No plugins available");
+ } else {
+ QStringList names;
+ names.reserve(dataHolder->factories.count());
+ for (const auto *factory : std::as_const(dataHolder->factories))
+ names += factory->name();
+ qDebug() << "None of the following backends has all the requested features:"
+ << names << features;
+ }
+#endif
+ break;
+ }
+#ifdef DEBUG_LOADING
+ qDebug() << "Creating instance using loader named" << (*it)->name();
+#endif
+ if (QNetworkInformationBackend *backend = (*it)->create(features)) {
+ dataHolder->instanceHolder.reset(new QNetworkInformation(backend));
+ Q_ASSERT(dataHolder->instanceHolder->supports(features));
+ return dataHolder->instanceHolder.get();
+ }
+#ifdef DEBUG_LOADING
+ else {
+ qDebug() << "The factory returned a nullptr";
+ }
+#endif
+ }
+#ifdef DEBUG_LOADING
+ qDebug() << "Couldn't find/create an appropriate backend.";
+#endif
+ return nullptr;
+}
+
+QNetworkInformation *QNetworkInformationPrivate::createDummy()
+{
+ if (!dataHolder())
+ return nullptr;
+
+ QMutexLocker locker(&dataHolder->instanceMutex);
+ if (dataHolder->instanceHolder)
+ return dataHolder->instanceHolder.get();
+
+ QNetworkInformationBackend *backend = new QNetworkInformationDummyBackend;
+ dataHolder->instanceHolder.reset(new QNetworkInformation(backend));
+ return dataHolder->instanceHolder.get();
+}
+
+/*!
+ \class QNetworkInformationBackend
+ \internal (Semi-private)
+ \brief QNetworkInformationBackend provides the interface with
+ which QNetworkInformation does all of its actual work.
+
+ Deriving from and implementing this class makes it a candidate
+ for use with QNetworkInformation. The derived class must, on
+ updates, call setters in the QNetworkInformationBackend which
+ will update the values and emit signals if the value has changed.
+
+ \sa QNetworkInformationBackendFactory
+*/
+
+/*!
+ \internal
+ Destroys base backend class.
+*/
+QNetworkInformationBackend::~QNetworkInformationBackend() = default;
+
+/*!
+ \fn QNetworkInformationBackend::name()
+
+ Backend name, return the same in
+ QNetworkInformationBackendFactory::name().
+*/
+
+/*!
+ \fn QNetworkInformation::Features QNetworkInformationBackend::featuresSupported()
+
+ Features supported, return the same in
+ QNetworkInformationBackendFactory::featuresSupported().
+*/
+
+/*!
+ \fn void QNetworkInformationBackend::reachabilityChanged()
+
+ You should not emit this signal manually, call setReachability()
+ instead which will emit this signal when the value changes.
+
+ \sa setReachability
+*/
+
+/*!
+ \fn void QNetworkInformationBackend::setReachability(QNetworkInformation::Reachability reachability)
+
+ Call this when reachability has changed. It will automatically
+ emit reachabilityChanged().
+
+ \sa setReachability
+*/
+
+/*!
+ \class QNetworkInformationBackendFactory
+ \internal (Semi-private)
+ \brief QNetworkInformationBackendFactory provides the interface
+ for creating instances of QNetworkInformationBackend.
+
+ Deriving from and implementing this class will let you register
+ your plugin with QNetworkInformation. It must provide some basic
+ information for querying information about the backend, and must
+ also create the backend if requested. If some pre-conditions for
+ the backend is not met it must return \nullptr.
+*/
+
+/*!
+ \internal
+ Adds the factory to an internal list.
+*/
+QNetworkInformationBackendFactory::QNetworkInformationBackendFactory()
+{
+ QNetworkInformationPrivate::addToList(this);
+}
+
+/*!
+ \internal
+ Removes the factory from an internal list.
+*/
+QNetworkInformationBackendFactory::~QNetworkInformationBackendFactory()
+{
+ QNetworkInformationPrivate::removeFromList(this);
+}
+
+/*!
+ \fn QString QNetworkInformationBackendFactory::name()
+
+ Backend name, return the same in
+ QNetworkInformationBackend::name().
+*/
+
+/*!
+ \fn QNetworkInformation::Features QNetworkInformationBackendFactory::featuresSupported()
+
+ Features supported, return the same in
+ QNetworkInformationBackend::featuresSupported().
+ The factory should not promise support for features that wouldn't
+ be available after creating the backend.
+*/
+
+/*!
+ \fn QNetworkInformationBackend *QNetworkInformationBackendFactory::create()
+
+ Create and return an instance of QNetworkInformationBackend. It
+ will be deallocated by QNetworkInformation on shutdown. If some
+ precondition is not met, meaning the backend would not function
+ correctly, then you must return \nullptr.
+*/
+
+/*!
+ \class QNetworkInformation
+ \inmodule QtNetwork
+ \since 6.1
+ \brief QNetworkInformation exposes various network information
+ through native backends.
+
+ QNetworkInformation provides a cross-platform interface to
+ network-related information through plugins.
+
+ Various plugins can have various functionality supported, and so
+ you can load() plugins based on which features are needed.
+
+ QNetworkInformation is a singleton and stays alive from the first
+ successful load() until destruction of the QCoreApplication object.
+ If you destroy and re-create the QCoreApplication object you must call
+ load() again.
+
+ \sa QNetworkInformation::Feature
+*/
+
+/*!
+ \enum QNetworkInformation::Feature
+
+ Lists all of the features that a plugin may currently support.
+ This can be used in QNetworkInformation::load().
+
+ \value Reachability
+ If the plugin supports this feature then the \c reachability property
+ will provide useful results. Otherwise it will always return
+ \c{Reachability::Unknown}.
+ See also QNetworkInformation::Reachability.
+
+ \value CaptivePortal
+ If the plugin supports this feature then the \c isBehindCaptivePortal
+ property will provide useful results. Otherwise it will always return
+ \c{false}.
+
+ \value TransportMedium
+ If the plugin supports this feature then the \c transportMedium
+ property will provide useful results. Otherwise it will always return
+ \c{TransportMedium::Unknown}.
+ See also QNetworkInformation::TransportMedium.
+
+ \value Metered
+ If the plugin supports this feature then the \c isMetered
+ property will provide useful results. Otherwise it will always return
+ \c{false}.
+*/
+
+/*!
+ \enum QNetworkInformation::Reachability
+
+ \value Unknown
+ If this value is returned then we may be connected but the OS
+ has still not confirmed full connectivity, or this feature
+ is not supported.
+ \value Disconnected
+ Indicates that the system may have no connectivity at all.
+ \value Local
+ Indicates that the system is connected to a network, but it
+ might only be able to access devices on the local network.
+ \value Site
+ Indicates that the system is connected to a network, but it
+ might only be able to access devices on the local subnet or an
+ intranet.
+ \value Online
+ Indicates that the system is connected to a network and
+ able to access the Internet.
+
+ \sa QNetworkInformation::reachability
+*/
+
+/*!
+ \enum QNetworkInformation::TransportMedium
+ \since 6.3
+
+ Lists the currently recognized media with which one can connect to the
+ internet.
+
+ \value Unknown
+ Returned if either the OS reports no active medium, the active medium is
+ not recognized by Qt, or the TransportMedium feature is not supported.
+ \value Ethernet
+ Indicates that the currently active connection is using ethernet.
+ Note: This value may also be returned when Windows is connected to a
+ Bluetooth personal area network.
+ \value Cellular
+ Indicates that the currently active connection is using a cellular
+ network.
+ \value WiFi
+ Indicates that the currently active connection is using Wi-Fi.
+ \value Bluetooth
+ Indicates that the currently active connection is connected using
+ Bluetooth.
+
+ \sa QNetworkInformation::transportMedium
+*/
+
+/*!
+ \internal ctor
+*/
+QNetworkInformation::QNetworkInformation(QNetworkInformationBackend *backend)
+ : QObject(*(new QNetworkInformationPrivate(backend)))
+{
+ connect(backend, &QNetworkInformationBackend::reachabilityChanged, this,
+ &QNetworkInformation::reachabilityChanged);
+ connect(backend, &QNetworkInformationBackend::behindCaptivePortalChanged, this,
+ &QNetworkInformation::isBehindCaptivePortalChanged);
+ connect(backend, &QNetworkInformationBackend::transportMediumChanged, this,
+ &QNetworkInformation::transportMediumChanged);
+ connect(backend, &QNetworkInformationBackend::isMeteredChanged, this,
+ &QNetworkInformation::isMeteredChanged);
+
+ QThread *main = nullptr;
+
+ if (QCoreApplication::instance())
+ main = QCoreApplication::instance()->thread();
+
+ if (main && thread() != main)
+ moveToThread(main);
+}
+
+/*!
+ \internal dtor
+*/
+QNetworkInformation::~QNetworkInformation() = default;
+
+/*!
+ \property QNetworkInformation::reachability
+ \brief The current state of the system's network connectivity.
+
+ Indicates the level of connectivity that can be expected. Do note
+ that this is only based on what the plugin/operating system
+ reports. In certain scenarios this is known to be wrong. For
+ example, on Windows the 'Online' check, by default, is performed
+ by Windows connecting to a Microsoft-owned server. If this server
+ is for any reason blocked then it will assume it does not have
+ Online reachability. Because of this you should not use this as a
+ pre-check before attempting to make a connection.
+*/
+
+QNetworkInformation::Reachability QNetworkInformation::reachability() const
+{
+ return d_func()->backend->reachability();
+}
+
+/*!
+ \property QNetworkInformation::isBehindCaptivePortal
+ \brief Lets you know if the user's device is behind a captive portal.
+ \since 6.2
+
+ This property indicates if the user's device is currently known to be
+ behind a captive portal. This functionality relies on the operating system's
+ detection of captive portals and is not supported on systems that don't
+ report this. On systems where this is not supported this will always return
+ \c{false}.
+*/
+bool QNetworkInformation::isBehindCaptivePortal() const
+{
+ return d_func()->backend->behindCaptivePortal();
+}
+
+/*!
+ \property QNetworkInformation::transportMedium
+ \brief The currently active transport medium for the application
+ \since 6.3
+
+ This property returns the currently active transport medium for the
+ application, on operating systems where such information is available.
+
+ When the current transport medium changes a signal is emitted, this can,
+ for instance, occur when a user leaves the range of a WiFi network, unplugs
+ their ethernet cable or enables Airplane mode.
+*/
+QNetworkInformation::TransportMedium QNetworkInformation::transportMedium() const
+{
+ return d_func()->backend->transportMedium();
+}
+
+/*!
+ \property QNetworkInformation::isMetered
+ \brief Check if the current connection is metered
+ \since 6.3
+
+ This property returns whether the current connection is (known to be)
+ metered or not. You can use this as a guiding factor to decide whether your
+ application should perform certain network requests or uploads.
+ For instance, you may not want to upload logs or diagnostics while this
+ property is \c true.
+*/
+bool QNetworkInformation::isMetered() const
+{
+ return d_func()->backend->isMetered();
+}
+
+/*!
+ Returns the name of the currently loaded backend.
+*/
+QString QNetworkInformation::backendName() const
+{
+ return d_func()->backend->name();
+}
+
+/*!
+ Returns \c true if the currently loaded backend supports
+ \a features.
+*/
+bool QNetworkInformation::supports(Features features) const
+{
+ return (d_func()->backend->featuresSupported() & features) == features;
+}
+
+/*!
+ \since 6.3
+
+ Returns all the supported features of the current backend.
+*/
+QNetworkInformation::Features QNetworkInformation::supportedFeatures() const
+{
+ return d_func()->backend->featuresSupported();
+}
+
+/*!
+ \since 6.3
+
+ Attempts to load the platform-default backend.
+
+ \note Starting with 6.7 this tries to load any backend that supports
+ \l{QNetworkInformation::Feature::Reachability}{Reachability} if the
+ platform-default backend is not available or fails to load.
+ If this also fails it will fall back to a backend that only returns
+ the default values for all properties.
+
+ This platform-to-plugin mapping is as follows:
+
+ \table
+ \header
+ \li Platform
+ \li Plugin-name
+ \row
+ \li Windows
+ \li networklistmanager
+ \row
+ \li Apple (macOS/iOS)
+ \li scnetworkreachability
+ \row
+ \li Android
+ \li android
+ \row
+ \li Linux
+ \li networkmanager
+ \endtable
+
+ This function is provided for convenience where the logic earlier
+ is good enough. If you require a specific plugin then you should call
+ loadBackendByName() or loadBackendByFeatures() directly instead.
+
+ Determines a suitable backend to load and returns \c true if this backend
+ is already loaded or on successful loading of it. Returns \c false if any
+ other backend has already been loaded, or if loading of the selected
+ backend fails.
+
+ \sa instance(), load()
+*/
+bool QNetworkInformation::loadDefaultBackend()
+{
+ int index = -1;
+#ifdef Q_OS_WIN
+ index = QNetworkInformationBackend::PluginNamesWindowsIndex;
+#elif defined(Q_OS_DARWIN)
+ index = QNetworkInformationBackend::PluginNamesAppleIndex;
+#elif defined(Q_OS_ANDROID)
+ index = QNetworkInformationBackend::PluginNamesAndroidIndex;
+#elif defined(Q_OS_LINUX)
+ index = QNetworkInformationBackend::PluginNamesLinuxIndex;
+#endif
+ if (index != -1 && loadBackendByName(QNetworkInformationBackend::PluginNames[index]))
+ return true;
+ // We assume reachability is the most commonly wanted feature, and try to
+ // load the backend that advertises the most features including that:
+ if (loadBackendByFeatures(Feature::Reachability))
+ return true;
+
+ // Fall back to the dummy backend
+ return loadBackendByName(u"dummy");
+}
+
+/*!
+ \since 6.4
+
+ Attempts to load a backend whose name matches \a backend
+ (case insensitively).
+
+ Returns \c true if it managed to load the requested backend or
+ if it was already loaded. Returns \c false otherwise.
+
+ \sa instance
+*/
+bool QNetworkInformation::loadBackendByName(QStringView backend)
+{
+ if (backend == u"dummy")
+ return QNetworkInformationPrivate::createDummy() != nullptr;
+
+ auto loadedBackend = QNetworkInformationPrivate::create(backend);
+ return loadedBackend && loadedBackend->backendName().compare(backend, Qt::CaseInsensitive) == 0;
+}
+
+#if QT_DEPRECATED_SINCE(6,4)
+/*!
+ \deprecated [6.4] Use loadBackendByName() instead.
+
+ \sa loadBackendByName(), loadDefaultBackend(), loadBackendByFeatures()
+*/
+bool QNetworkInformation::load(QStringView backend)
+{
+ return loadBackendByName(backend);
+}
+#endif // QT_DEPRECATED_SINCE(6,4)
+
+/*!
+ \since 6.4
+ Load a backend which supports \a features.
+
+ Returns \c true if it managed to load the requested backend or
+ if it was already loaded. Returns \c false otherwise.
+
+ \sa instance
+*/
+bool QNetworkInformation::loadBackendByFeatures(Features features)
+{
+ auto loadedBackend = QNetworkInformationPrivate::create(features);
+ return loadedBackend && loadedBackend->supports(features);
+}
+
+#if QT_DEPRECATED_SINCE(6,4)
+/*!
+ \deprecated [6.4] Use loadBackendByFeatures() instead.
+
+ \sa loadBackendByName(), loadDefaultBackend(), loadBackendByFeatures()
+*/
+bool QNetworkInformation::load(Features features)
+{
+ return loadBackendByFeatures(features);
+}
+#endif // QT_DEPRECATED_SINCE(6,4)
+
+/*!
+ Returns a list of the names of all currently available backends.
+*/
+QStringList QNetworkInformation::availableBackends()
+{
+ return QNetworkInformationPrivate::backendNames();
+}
+
+/*!
+ Returns a pointer to the instance of the QNetworkInformation,
+ if any.
+
+ \sa load()
+*/
+QNetworkInformation *QNetworkInformation::instance()
+{
+ return QNetworkInformationPrivate::instance();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qnetworkinformation.cpp"
+#include "moc_qnetworkinformation_p.cpp"
+#include "qnetworkinformation.moc"
diff --git a/src/network/kernel/qnetworkinformation.h b/src/network/kernel/qnetworkinformation.h
new file mode 100644
index 0000000000..4e70a7faf2
--- /dev/null
+++ b/src/network/kernel/qnetworkinformation.h
@@ -0,0 +1,97 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QNETWORKINFORMATION_H
+#define QNETWORKINFORMATION_H
+
+#include <QtNetwork/qtnetworkglobal.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qstringview.h>
+#include <QtCore/qstringlist.h>
+
+QT_BEGIN_NAMESPACE
+
+class QNetworkInformationBackend;
+class QNetworkInformationPrivate;
+struct QNetworkInformationDeleter;
+class Q_NETWORK_EXPORT QNetworkInformation : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QNetworkInformation)
+ Q_PROPERTY(Reachability reachability READ reachability NOTIFY reachabilityChanged)
+ Q_PROPERTY(bool isBehindCaptivePortal READ isBehindCaptivePortal
+ NOTIFY isBehindCaptivePortalChanged)
+ Q_PROPERTY(TransportMedium transportMedium READ transportMedium NOTIFY transportMediumChanged)
+ Q_PROPERTY(bool isMetered READ isMetered NOTIFY isMeteredChanged)
+ Q_CLASSINFO("RegisterEnumClassesUnscoped", "false")
+public:
+ enum class Reachability {
+ Unknown,
+ Disconnected,
+ Local,
+ Site,
+ Online,
+ };
+ Q_ENUM(Reachability)
+
+ enum class TransportMedium {
+ Unknown,
+ Ethernet,
+ Cellular,
+ WiFi,
+ Bluetooth,
+ };
+ Q_ENUM(TransportMedium)
+
+ enum class Feature {
+ Reachability = 0x1,
+ CaptivePortal = 0x2,
+ TransportMedium = 0x4,
+ Metered = 0x8,
+ };
+ Q_DECLARE_FLAGS(Features, Feature)
+ Q_FLAG(Features)
+
+ Reachability reachability() const;
+
+ bool isBehindCaptivePortal() const;
+
+ TransportMedium transportMedium() const;
+
+ bool isMetered() const;
+
+ QString backendName() const;
+
+ bool supports(Features features) const;
+ Features supportedFeatures() const;
+
+ static bool loadDefaultBackend();
+ static bool loadBackendByName(QStringView backend);
+ static bool loadBackendByFeatures(Features features);
+#if QT_DEPRECATED_SINCE(6,4)
+ QT_DEPRECATED_VERSION_X_6_4("Use loadBackendByName") static bool load(QStringView backend);
+ QT_DEPRECATED_VERSION_X_6_4("Use loadBackendByFeatures") static bool load(Features features);
+#endif
+ static QStringList availableBackends();
+ static QNetworkInformation *instance();
+
+Q_SIGNALS:
+ void reachabilityChanged(Reachability newReachability);
+ void isBehindCaptivePortalChanged(bool state);
+ void transportMediumChanged(TransportMedium current);
+ void isMeteredChanged(bool isMetered);
+
+private:
+ friend struct QNetworkInformationDeleter;
+ friend class QNetworkInformationPrivate;
+ QNetworkInformation(QNetworkInformationBackend *backend);
+ ~QNetworkInformation() override;
+
+ Q_DISABLE_COPY_MOVE(QNetworkInformation)
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QNetworkInformation::Features)
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/network/kernel/qnetworkinformation_p.h b/src/network/kernel/qnetworkinformation_p.h
new file mode 100644
index 0000000000..504955a6e1
--- /dev/null
+++ b/src/network/kernel/qnetworkinformation_p.h
@@ -0,0 +1,156 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QNETWORKINFORMATION_P_H
+#define QNETWORKINFORMATION_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the Network Information API. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtNetwork/private/qtnetworkglobal_p.h>
+
+#include <QtNetwork/qnetworkinformation.h>
+
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qreadwritelock.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_NETWORK_EXPORT QNetworkInformationBackend : public QObject
+{
+ Q_OBJECT
+
+ using Reachability = QNetworkInformation::Reachability;
+ using TransportMedium = QNetworkInformation::TransportMedium;
+
+public:
+ static inline const char16_t PluginNames[4][22] = {
+ { u"networklistmanager" },
+ { u"scnetworkreachability" },
+ { u"android" },
+ { u"networkmanager" },
+ };
+ static constexpr int PluginNamesWindowsIndex = 0;
+ static constexpr int PluginNamesAppleIndex = 1;
+ static constexpr int PluginNamesAndroidIndex = 2;
+ static constexpr int PluginNamesLinuxIndex = 3;
+
+ QNetworkInformationBackend() = default;
+ ~QNetworkInformationBackend() override;
+
+ virtual QString name() const = 0;
+ virtual QNetworkInformation::Features featuresSupported() const = 0;
+
+ Reachability reachability() const
+ {
+ QReadLocker locker(&m_lock);
+ return m_reachability;
+ }
+
+ bool behindCaptivePortal() const
+ {
+ QReadLocker locker(&m_lock);
+ return m_behindCaptivePortal;
+ }
+
+ TransportMedium transportMedium() const
+ {
+ QReadLocker locker(&m_lock);
+ return m_transportMedium;
+ }
+
+ bool isMetered() const
+ {
+ QReadLocker locker(&m_lock);
+ return m_metered;
+ }
+
+Q_SIGNALS:
+ void reachabilityChanged(Reachability reachability);
+ void behindCaptivePortalChanged(bool behindPortal);
+ void transportMediumChanged(TransportMedium medium);
+ void isMeteredChanged(bool isMetered);
+
+protected:
+ void setReachability(QNetworkInformation::Reachability reachability)
+ {
+ QWriteLocker locker(&m_lock);
+ if (m_reachability != reachability) {
+ m_reachability = reachability;
+ locker.unlock();
+ emit reachabilityChanged(reachability);
+ }
+ }
+
+ void setBehindCaptivePortal(bool behindPortal)
+ {
+ QWriteLocker locker(&m_lock);
+ if (m_behindCaptivePortal != behindPortal) {
+ m_behindCaptivePortal = behindPortal;
+ locker.unlock();
+ emit behindCaptivePortalChanged(behindPortal);
+ }
+ }
+
+ void setTransportMedium(TransportMedium medium)
+ {
+ QWriteLocker locker(&m_lock);
+ if (m_transportMedium != medium) {
+ m_transportMedium = medium;
+ locker.unlock();
+ emit transportMediumChanged(medium);
+ }
+ }
+
+ void setMetered(bool isMetered)
+ {
+ QWriteLocker locker(&m_lock);
+ if (m_metered != isMetered) {
+ m_metered = isMetered;
+ locker.unlock();
+ emit isMeteredChanged(isMetered);
+ }
+ }
+
+private:
+ mutable QReadWriteLock m_lock;
+ Reachability m_reachability = Reachability::Unknown;
+ TransportMedium m_transportMedium = TransportMedium::Unknown;
+ bool m_behindCaptivePortal = false;
+ bool m_metered = false;
+
+ Q_DISABLE_COPY_MOVE(QNetworkInformationBackend)
+ friend class QNetworkInformation;
+ friend class QNetworkInformationPrivate;
+};
+
+class Q_NETWORK_EXPORT QNetworkInformationBackendFactory : public QObject
+{
+ Q_OBJECT
+
+ using Features = QNetworkInformation::Features;
+
+public:
+ QNetworkInformationBackendFactory();
+ virtual ~QNetworkInformationBackendFactory();
+ virtual QString name() const = 0;
+ virtual QNetworkInformationBackend *create(Features requiredFeatures) const = 0;
+ virtual Features featuresSupported() const = 0;
+
+private:
+ Q_DISABLE_COPY_MOVE(QNetworkInformationBackendFactory)
+};
+#define QNetworkInformationBackendFactory_iid "org.qt-project.Qt.NetworkInformationBackendFactory"
+Q_DECLARE_INTERFACE(QNetworkInformationBackendFactory, QNetworkInformationBackendFactory_iid);
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/network/kernel/qnetworkinterface.cpp b/src/network/kernel/qnetworkinterface.cpp
index eed57f8a32..f03e85c7f6 100644
--- a/src/network/kernel/qnetworkinterface.cpp
+++ b/src/network/kernel/qnetworkinterface.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2017 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2017 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qnetworkinterface.h"
#include "qnetworkinterface_p.h"
@@ -49,6 +13,12 @@
QT_BEGIN_NAMESPACE
+QT_IMPL_METATYPE_EXTERN(QNetworkAddressEntry)
+QT_IMPL_METATYPE_EXTERN(QNetworkInterface)
+
+static_assert(QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+ && sizeof(QScopedPointer<QNetworkAddressEntryPrivate>) == sizeof(std::unique_ptr<QNetworkAddressEntryPrivate>));
+
static QList<QNetworkInterfacePrivate *> postProcess(QList<QNetworkInterfacePrivate *> list)
{
// Some platforms report a netmask but don't report a broadcast address
@@ -139,7 +109,7 @@ QString QNetworkInterfacePrivate::makeHwAddress(int len, uchar *data)
QChar *out = result.data();
for (int i = 0; i < len; ++i) {
if (i)
- *out++ = QLatin1Char(':');
+ *out++ = u':';
*out++ = QLatin1Char(QtMiscUtils::toHexUpper(data[i] / 16));
*out++ = QLatin1Char(QtMiscUtils::toHexUpper(data[i] % 16));
}
@@ -204,7 +174,7 @@ QNetworkAddressEntry::QNetworkAddressEntry()
object \a other.
*/
QNetworkAddressEntry::QNetworkAddressEntry(const QNetworkAddressEntry &other)
- : d(new QNetworkAddressEntryPrivate(*other.d.data()))
+ : d(new QNetworkAddressEntryPrivate(*other.d.get()))
{
}
@@ -213,7 +183,7 @@ QNetworkAddressEntry::QNetworkAddressEntry(const QNetworkAddressEntry &other)
*/
QNetworkAddressEntry &QNetworkAddressEntry::operator=(const QNetworkAddressEntry &other)
{
- *d.data() = *other.d.data();
+ *d.get() = *other.d.get();
return *this;
}
@@ -489,7 +459,7 @@ void QNetworkAddressEntry::clearAddressLifetime()
\since 5.11
Returns \c true if this address is permanent on this interface, \c false if
- it's temporary. A permenant address is one which has no expiration time and
+ it's temporary. A permanent address is one which has no expiration time and
is often static (manually configured).
If this information could not be determined, this function returns \c true.
@@ -552,9 +522,11 @@ bool QNetworkAddressEntry::isPermanent() const
Specifies the flags associated with this network interface. The
possible values are:
- \value IsUp the network interface is active
- \value IsRunning the network interface has resources
- allocated
+ \value IsUp the network interface is "up" -
+ enabled by administrative action
+ \value IsRunning the network interface is operational:
+ configured "up" and (typically)
+ physically connected to a network
\value CanBroadcast the network interface works in
broadcast mode
\value IsLoopBack the network interface is a loopback
@@ -901,7 +873,7 @@ QList<QHostAddress> QNetworkInterface::allAddresses()
if ((p->flags & QNetworkInterface::IsUp) == 0)
continue;
- for (const QNetworkAddressEntry &entry : qAsConst(p->addressEntries))
+ for (const QNetworkAddressEntry &entry : std::as_const(p->addressEntries))
result += entry.ip();
}
@@ -926,17 +898,32 @@ static inline QDebug flagsDebug(QDebug debug, QNetworkInterface::InterfaceFlags
return debug;
}
-static inline QDebug operator<<(QDebug debug, const QNetworkAddressEntry &entry)
+/*!
+ \since 6.2
+
+ Writes the QNetworkAddressEntry \a entry to the stream and
+ returns a reference to the \a debug stream.
+
+ \relates QNetworkAddressEntry
+ */
+QDebug operator<<(QDebug debug, const QNetworkAddressEntry &entry)
{
- debug << "(address = " << entry.ip();
+ QDebugStateSaver saver(debug);
+ debug.resetFormat().nospace();
+ debug << "address = " << entry.ip();
if (!entry.netmask().isNull())
debug << ", netmask = " << entry.netmask();
if (!entry.broadcast().isNull())
debug << ", broadcast = " << entry.broadcast();
- debug << ')';
return debug;
}
+/*!
+ Writes the QNetworkInterface \a networkInterface to the stream and
+ returns a reference to the \a debug stream.
+
+ \relates QNetworkInterface
+ */
QDebug operator<<(QDebug debug, const QNetworkInterface &networkInterface)
{
QDebugStateSaver saver(debug);
diff --git a/src/network/kernel/qnetworkinterface.h b/src/network/kernel/qnetworkinterface.h
index c65ea58860..2d79f9e2a1 100644
--- a/src/network/kernel/qnetworkinterface.h
+++ b/src/network/kernel/qnetworkinterface.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNETWORKINTERFACE_H
#define QNETWORKINTERFACE_H
@@ -45,6 +9,8 @@
#include <QtCore/qscopedpointer.h>
#include <QtNetwork/qhostaddress.h>
+#include <memory>
+
#ifndef QT_NO_NETWORKINTERFACE
QT_BEGIN_NAMESPACE
@@ -67,7 +33,7 @@ public:
QNetworkAddressEntry &operator=(const QNetworkAddressEntry &other);
~QNetworkAddressEntry();
- void swap(QNetworkAddressEntry &other) noexcept { qSwap(d, other.d); }
+ void swap(QNetworkAddressEntry &other) noexcept { d.swap(other.d); }
bool operator==(const QNetworkAddressEntry &other) const;
inline bool operator!=(const QNetworkAddressEntry &other) const
@@ -96,7 +62,8 @@ public:
bool isTemporary() const { return !isPermanent(); }
private:
- QScopedPointer<QNetworkAddressEntryPrivate> d;
+ // ### Qt 7: make implicitly shared
+ std::unique_ptr<QNetworkAddressEntryPrivate> d;
};
Q_DECLARE_SHARED(QNetworkAddressEntry)
@@ -143,7 +110,7 @@ public:
QNetworkInterface &operator=(const QNetworkInterface &other);
~QNetworkInterface();
- void swap(QNetworkInterface &other) noexcept { qSwap(d, other.d); }
+ void swap(QNetworkInterface &other) noexcept { d.swap(other.d); }
bool isValid() const;
@@ -173,13 +140,14 @@ Q_DECLARE_SHARED(QNetworkInterface)
Q_DECLARE_OPERATORS_FOR_FLAGS(QNetworkInterface::InterfaceFlags)
#ifndef QT_NO_DEBUG_STREAM
+Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, const QNetworkAddressEntry &entry);
Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, const QNetworkInterface &networkInterface);
#endif
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QNetworkAddressEntry)
-Q_DECLARE_METATYPE(QNetworkInterface)
+QT_DECL_METATYPE_EXTERN(QNetworkAddressEntry, Q_NETWORK_EXPORT)
+QT_DECL_METATYPE_EXTERN(QNetworkInterface, Q_NETWORK_EXPORT)
#endif // QT_NO_NETWORKINTERFACE
diff --git a/src/network/kernel/qnetworkinterface_linux.cpp b/src/network/kernel/qnetworkinterface_linux.cpp
index c9d22eb247..67ed8006bb 100644
--- a/src/network/kernel/qnetworkinterface_linux.cpp
+++ b/src/network/kernel/qnetworkinterface_linux.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qnetworkinterface.h"
#include "qnetworkinterface_p.h"
@@ -47,7 +11,7 @@
#include <qobjectdefs.h>
#include <qvarlengtharray.h>
-// accordding to rtnetlink(7)
+// according to rtnetlink(7)
#include <asm/types.h>
#include <linux/if.h>
#include <linux/if_arp.h>
@@ -147,7 +111,10 @@ struct NetlinkSocket
template <typename Lambda> struct ProcessNetlinkRequest
{
using FunctionTraits = QtPrivate::FunctionPointer<decltype(&Lambda::operator())>;
- using FirstArgument = typename FunctionTraits::Arguments::Car;
+ using FirstArgumentPointer = typename FunctionTraits::Arguments::Car;
+ using FirstArgument = std::remove_pointer_t<FirstArgumentPointer>;
+ static_assert(std::is_pointer_v<FirstArgumentPointer>);
+ static_assert(std::is_aggregate_v<FirstArgument>);
static int expectedTypeForRequest(int rtype)
{
@@ -172,7 +139,7 @@ template <typename Lambda> struct ProcessNetlinkRequest
if (!NLMSG_OK(hdr, quint32(len)))
return;
- auto arg = reinterpret_cast<FirstArgument>(NLMSG_DATA(hdr));
+ auto arg = static_cast<FirstArgument *>(NLMSG_DATA(hdr));
size_t payloadLen = NLMSG_PAYLOAD(hdr, 0);
// is this a multipart message?
@@ -192,7 +159,7 @@ template <typename Lambda> struct ProcessNetlinkRequest
// NLMSG_NEXT also updates the len variable
hdr = NLMSG_NEXT(hdr, len);
- arg = reinterpret_cast<FirstArgument>(NLMSG_DATA(hdr));
+ arg = static_cast<FirstArgument *>(NLMSG_DATA(hdr));
payloadLen = NLMSG_PAYLOAD(hdr, 0);
} while (NLMSG_OK(hdr, quint32(len)));
@@ -222,7 +189,7 @@ void processNetlinkRequest(int sock, struct nlmsghdr *hdr, char *buf, size_t buf
uint QNetworkInterfaceManager::interfaceIndexFromName(const QString &name)
{
uint index = 0;
- if (name.length() >= IFNAMSIZ)
+ if (name.size() >= IFNAMSIZ)
return index;
int socket = qt_safe_socket(AF_INET, SOCK_DGRAM, 0);
@@ -303,9 +270,9 @@ static QList<QNetworkInterfacePrivate *> getInterfaces(int sock, char *buf)
case IFLA_OPERSTATE: // operational state
if (*payloadPtr != IF_OPER_UNKNOWN) {
// override the flag
- iface->flags &= ~QNetworkInterface::IsUp;
+ iface->flags &= ~QNetworkInterface::IsRunning;
if (*payloadPtr == IF_OPER_UP)
- iface->flags |= QNetworkInterface::IsUp;
+ iface->flags |= QNetworkInterface::IsRunning;
}
break;
}
@@ -345,7 +312,7 @@ static void getAddresses(int sock, char *buf, QList<QNetworkInterfacePrivate *>
// find the interface this is relevant to
QNetworkInterfacePrivate *iface = nullptr;
- for (auto candidate : qAsConst(result)) {
+ for (auto candidate : std::as_const(result)) {
if (candidate->index != int(ifa->ifa_index))
continue;
iface = candidate;
diff --git a/src/network/kernel/qnetworkinterface_p.h b/src/network/kernel/qnetworkinterface_p.h
index b879a397f2..2a24826a3e 100644
--- a/src/network/kernel/qnetworkinterface_p.h
+++ b/src/network/kernel/qnetworkinterface_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNETWORKINTERFACEPRIVATE_H
#define QNETWORKINTERFACEPRIVATE_H
@@ -56,7 +20,6 @@
#include <QtCore/qatomic.h>
#include <QtCore/qdeadlinetimer.h>
#include <QtCore/qlist.h>
-#include <QtCore/qreadwritelock.h>
#include <QtCore/qstring.h>
#include <QtNetwork/qhostaddress.h>
#include <QtNetwork/qabstractsocket.h>
@@ -104,14 +67,15 @@ public:
{
// this implements an algorithm that yields the same results as Windows
// produces, for the same input (as far as I can test)
- if (isTemporary || isDeprecated)
+ if (isTemporary || isDeprecated) {
entry->setDnsEligibility(QNetworkAddressEntry::DnsIneligible);
-
- AddressClassification cl = QHostAddressPrivate::classify(entry->ip());
- if (cl == LoopbackAddress || cl == LinkLocalAddress)
- entry->setDnsEligibility(QNetworkAddressEntry::DnsIneligible);
- else
- entry->setDnsEligibility(QNetworkAddressEntry::DnsEligible);
+ } else {
+ AddressClassification cl = QHostAddressPrivate::classify(entry->ip());
+ if (cl == LoopbackAddress || cl == LinkLocalAddress)
+ entry->setDnsEligibility(QNetworkAddressEntry::DnsIneligible);
+ else
+ entry->setDnsEligibility(QNetworkAddressEntry::DnsEligible);
+ }
}
private:
diff --git a/src/network/kernel/qnetworkinterface_uikit_p.h b/src/network/kernel/qnetworkinterface_uikit_p.h
index ea40e74f5c..49e2db007b 100644
--- a/src/network/kernel/qnetworkinterface_uikit_p.h
+++ b/src/network/kernel/qnetworkinterface_uikit_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNETWORKINTERFACE_UIKIT_P_H
#define QNETWORKINTERFACE_UIKIT_P_H
@@ -237,26 +201,5 @@ struct in6_ifreq {
#define SIOCGIFAFLAG_IN6 _IOWR('i', 73, struct in6_ifreq)
#define SIOCGIFALIFETIME_IN6 _IOWR('i', 81, struct in6_ifreq)
-// The definition below is ONLY a temporary workaround to unblock
-// integrations on CI. MUST be removed ASAP, as soon as SDK is
-// updated. Currently, we have WatchOS SDK 3.2 and it's missing
-// net/if_types.h (unlike SDK 4.0, which has it). Alas, we have to
-// work this around. We only define constants that we use in code.
-
-#if !QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_NA, __IPHONE_NA, __TVOS_NA, __WATCHOS_4_0)
-
-#define QT_WATCHOS_OUTDATED_SDK_WORKAROUND
-
-#define IFT_PPP 0x17 /* RFC 1331 */
-#define IFT_LOOP 0x18 /* loopback */
-#define IFT_SLIP 0x1c /* IP over generic TTY */
-
-#define IFT_GIF 0x37 /*0xf0*/
-#define IFT_STF 0x39 /*0xf3*/
-
-#define IFT_IEEE1394 0x90 /* IEEE1394 High Performance SerialBus*/
-
-#endif // WatchOS SDK below 4.0
-
#endif // QNETWORKINTERFACE_UIKIT_P_H
diff --git a/src/network/kernel/qnetworkinterface_unix.cpp b/src/network/kernel/qnetworkinterface_unix.cpp
index 4b8c58cb40..c0a7d9e00d 100644
--- a/src/network/kernel/qnetworkinterface_unix.cpp
+++ b/src/network/kernel/qnetworkinterface_unix.cpp
@@ -1,42 +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 QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbytearray.h"
#include "qset.h"
@@ -53,11 +17,7 @@
# include "qdatetime.h"
#endif
-#if defined(QT_LINUXBASE)
-# define QT_NO_GETIFADDRS
-#endif
-
-#ifndef QT_NO_GETIFADDRS
+#if QT_CONFIG(getifaddrs)
# include <ifaddrs.h>
#endif
@@ -92,36 +52,49 @@ static QHostAddress addressFromSockaddr(sockaddr *sa, int ifindex = 0, const QSt
}
}
return address;
+}
+
+template <typename Req> [[maybe_unused]]
+static auto &ifreq_index(Req &req, std::enable_if_t<sizeof(std::declval<Req>().ifr_index) != 0, int> = 0)
+{
+ return req.ifr_index;
+}
+template <typename Req> [[maybe_unused]]
+static auto &ifreq_index(Req &req, std::enable_if_t<sizeof(std::declval<Req>().ifr_ifindex) != 0, int> = 0)
+{
+ return req.ifr_ifindex;
}
uint QNetworkInterfaceManager::interfaceIndexFromName(const QString &name)
{
-#ifndef QT_NO_IPV6IFNAME
- return ::if_nametoindex(name.toLatin1());
+#if QT_CONFIG(ipv6ifname)
+ return ::if_nametoindex(name.toLatin1().constData());
#elif defined(SIOCGIFINDEX)
struct ifreq req;
int socket = qt_safe_socket(AF_INET, SOCK_STREAM, 0);
if (socket < 0)
return 0;
- QByteArray name8bit = name.toLatin1();
+ const QByteArray name8bit = name.toLatin1();
memset(&req, 0, sizeof(ifreq));
- memcpy(req.ifr_name, name8bit, qMin<int>(name8bit.length() + 1, sizeof(req.ifr_name) - 1));
+ if (!name8bit.isNull())
+ memcpy(req.ifr_name, name8bit.data(), qMin(size_t(name8bit.length()) + 1, sizeof(req.ifr_name) - 1));
uint id = 0;
if (qt_safe_ioctl(socket, SIOCGIFINDEX, &req) >= 0)
- id = req.ifr_ifindex;
+ id = ifreq_index(req);
qt_safe_close(socket);
return id;
#else
+ Q_UNUSED(name);
return 0;
#endif
}
QString QNetworkInterfaceManager::interfaceNameFromIndex(uint index)
{
-#ifndef QT_NO_IPV6IFNAME
+#if QT_CONFIG(ipv6ifname)
char buf[IF_NAMESIZE];
if (::if_indextoname(index, buf))
return QString::fromLatin1(buf);
@@ -130,8 +103,7 @@ QString QNetworkInterfaceManager::interfaceNameFromIndex(uint index)
int socket = qt_safe_socket(AF_INET, SOCK_STREAM, 0);
if (socket >= 0) {
memset(&req, 0, sizeof(ifreq));
- req.ifr_ifindex = index;
-
+ ifreq_index(req) = index;
if (qt_safe_ioctl(socket, SIOCGIFNAME, &req) >= 0) {
qt_safe_close(socket);
return QString::fromLatin1(req.ifr_name);
@@ -151,13 +123,13 @@ static int getMtu(int socket, struct ifreq *req)
return 0;
}
-#ifdef QT_NO_GETIFADDRS
+#if !QT_CONFIG(getifaddrs)
// getifaddrs not available
static QSet<QByteArray> interfaceNames(int socket)
{
QSet<QByteArray> result;
-#ifdef QT_NO_IPV6IFNAME
+#if !QT_CONFIG(ipv6ifname)
QByteArray storageBuffer;
struct ifconf interfaceList;
static const int STORAGEBUFFER_GROWTH = 256;
@@ -209,18 +181,14 @@ static QSet<QByteArray> interfaceNames(int socket)
static QNetworkInterfacePrivate *findInterface(int socket, QList<QNetworkInterfacePrivate *> &interfaces,
struct ifreq &req)
{
- QNetworkInterfacePrivate *iface = 0;
+ QNetworkInterfacePrivate *iface = nullptr;
int ifindex = 0;
-#if !defined(QT_NO_IPV6IFNAME) || defined(SIOCGIFINDEX)
+#if QT_CONFIG(ipv6ifname) || defined(SIOCGIFINDEX)
// Get the interface index
# ifdef SIOCGIFINDEX
if (qt_safe_ioctl(socket, SIOCGIFINDEX, &req) >= 0)
-# if defined(Q_OS_HAIKU)
- ifindex = req.ifr_index;
-# else
- ifindex = req.ifr_ifindex;
-# endif
+ ifindex = ifreq_index(req);
# else
ifindex = if_nametoindex(req.ifr_name);
# endif
@@ -234,10 +202,11 @@ static QNetworkInterfacePrivate *findInterface(int socket, QList<QNetworkInterfa
break;
}
#else
+ Q_UNUSED(socket);
// Search by name
QList<QNetworkInterfacePrivate *>::Iterator if_it = interfaces.begin();
for ( ; if_it != interfaces.end(); ++if_it)
- if ((*if_it)->name == QLatin1String(req.ifr_name)) {
+ if ((*if_it)->name == QLatin1StringView(req.ifr_name)) {
// existing interface
iface = *if_it;
break;
@@ -267,7 +236,8 @@ static QList<QNetworkInterfacePrivate *> interfaceListing()
for ( ; it != names.constEnd(); ++it) {
ifreq req;
memset(&req, 0, sizeof(ifreq));
- memcpy(req.ifr_name, *it, qMin<int>(it->length() + 1, sizeof(req.ifr_name) - 1));
+ if (!it->isNull())
+ memcpy(req.ifr_name, it->constData(), qMin(size_t(it->length()) + 1, sizeof(req.ifr_name) - 1));
QNetworkInterfacePrivate *iface = findInterface(socket, interfaces, req);
@@ -278,7 +248,8 @@ static QList<QNetworkInterfacePrivate *> interfaceListing()
iface->name = QString::fromLatin1(req.ifr_name);
// reset the name:
- memcpy(req.ifr_name, oldName, qMin<int>(oldName.length() + 1, sizeof(req.ifr_name) - 1));
+ if (!oldName.isNull())
+ memcpy(req.ifr_name, oldName.constData(), qMin(size_t(oldName.length()) + 1, sizeof(req.ifr_name) - 1));
} else
#endif
{
@@ -408,10 +379,7 @@ QT_BEGIN_INCLUDE_NAMESPACE
# include <net/if_dl.h>
#if defined(QT_PLATFORM_UIKIT)
# include "qnetworkinterface_uikit_p.h"
-#if !defined(QT_WATCHOS_OUTDATED_SDK_WORKAROUND)
-// TODO: remove it as soon as SDK is updated on CI!!!
# include <net/if_types.h>
-#endif
#else
# include <net/if_media.h>
# include <net/if_types.h>
@@ -488,7 +456,8 @@ static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList)
// ensure both structs start with the name field, of size IFNAMESIZ
static_assert(sizeof(mediareq.ifm_name) == sizeof(req.ifr_name));
- Q_ASSERT(&mediareq.ifm_name == &req.ifr_name);
+ static_assert(offsetof(struct ifmediareq, ifm_name) == 0);
+ static_assert(offsetof(struct ifreq, ifr_name) == 0);
// on NetBSD we use AF_LINK and sockaddr_dl
// scan the list for that family
@@ -617,8 +586,8 @@ static QList<QNetworkInterfacePrivate *> interfaceListing()
interfaces = createInterfaces(interfaceListing);
for (ifaddrs *ptr = interfaceListing; ptr; ptr = ptr->ifa_next) {
// Find the interface
- QLatin1String name(ptr->ifa_name);
- QNetworkInterfacePrivate *iface = 0;
+ QLatin1StringView name(ptr->ifa_name);
+ QNetworkInterfacePrivate *iface = nullptr;
QList<QNetworkInterfacePrivate *>::Iterator if_it = interfaces.begin();
for ( ; if_it != interfaces.end(); ++if_it)
if ((*if_it)->name == name) {
diff --git a/src/network/kernel/qnetworkinterface_unix_p.h b/src/network/kernel/qnetworkinterface_unix_p.h
index e5c8909eca..80af9c8e0d 100644
--- a/src/network/kernel/qnetworkinterface_unix_p.h
+++ b/src/network/kernel/qnetworkinterface_unix_p.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Copyright (C) 2017 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// Copyright (C) 2017 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNETWORKINTERFACE_UNIX_P_H
#define QNETWORKINTERFACE_UNIX_P_H
diff --git a/src/network/kernel/qnetworkinterface_win.cpp b/src/network/kernel/qnetworkinterface_win.cpp
index a8d56a9b11..20e75139db 100644
--- a/src/network/kernel/qnetworkinterface_win.cpp
+++ b/src/network/kernel/qnetworkinterface_win.cpp
@@ -1,42 +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 QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#define WIN32_LEAN_AND_MEAN 1
diff --git a/src/network/kernel/qnetworkproxy.cpp b/src/network/kernel/qnetworkproxy.cpp
index 75f81a0037..62bba24bce 100644
--- a/src/network/kernel/qnetworkproxy.cpp
+++ b/src/network/kernel/qnetworkproxy.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/*!
@@ -189,7 +153,7 @@
QNetworkProxy sets different capabilities by default when the
object is created (see QNetworkProxy::ProxyType for a list of the
- defaults). However, it is possible to change the capabitilies
+ defaults). However, it is possible to change the capabilities
after the object has been created with setCapabilities().
The capabilities that QNetworkProxy supports are:
@@ -243,6 +207,10 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
+QT_IMPL_METATYPE_EXTERN(QNetworkProxy)
+
class QSocks5SocketEngineHandler;
class QHttpSocketEngineHandler;
@@ -354,10 +322,8 @@ QList<QNetworkProxy> QGlobalNetworkProxy::proxyForQuery(const QNetworkProxyQuery
// don't look for proxies for a local connection
QHostAddress parsed;
QString hostname = query.url().host();
- if (hostname == QLatin1String("localhost")
- || hostname.startsWith(QLatin1String("localhost."))
- || (parsed.setAddress(hostname)
- && (parsed.isLoopback()))) {
+ if (hostname == "localhost"_L1 || hostname.startsWith("localhost."_L1)
+ || (parsed.setAddress(hostname) && (parsed.isLoopback()))) {
result << QNetworkProxy(QNetworkProxy::NoProxy);
return result;
}
@@ -1500,13 +1466,18 @@ void QNetworkProxyFactory::setApplicationProxyFactory(QNetworkProxyFactory *fact
Internet Explorer's settings and use them.
On \macos, this function will obtain the proxy settings using the
- SystemConfiguration framework from Apple. It will apply the FTP,
+ CFNetwork framework from Apple. It will apply the FTP,
HTTP and HTTPS proxy configurations for queries that contain the
protocol tag "ftp", "http" and "https", respectively. If the SOCKS
proxy is enabled in that configuration, this function will use the
SOCKS server for all queries. If SOCKS isn't enabled, it will use
the HTTPS proxy for all TcpSocket and UrlRequest queries.
+ On systems configured with libproxy support, this function will
+ rely on libproxy to obtain the proxy settings. Depending on
+ libproxy configurations, this can in turn delegate to desktop
+ settings, environment variables, etc.
+
On other systems, this function will pick up proxy settings from
the "http_proxy" environment variable. This variable must be a URL
using one of the following schemes: "http", "socks5" or "socks5h".
@@ -1518,9 +1489,6 @@ void QNetworkProxyFactory::setApplicationProxyFactory(QNetworkProxyFactory *fact
listed here.
\list
- \li On \macos, this function will ignore the Proxy Auto Configuration
- settings, since it cannot execute the associated ECMAScript code.
-
\li On Windows platforms, this function may take several seconds to
execute depending on the configuration of the user's system.
\endlist
@@ -1585,7 +1553,7 @@ QDebug operator<<(QDebug debug, const QNetworkProxy &proxy)
scaps << QStringLiteral("SctpTunnel");
if (caps & QNetworkProxy::SctpListeningCapability)
scaps << QStringLiteral("SctpListen");
- debug << '[' << scaps.join(QLatin1Char(' ')) << ']';
+ debug << '[' << scaps.join(u' ') << ']';
return debug;
}
@@ -1607,4 +1575,6 @@ QDebug operator<<(QDebug debug, const QNetworkProxyQuery &proxyQuery)
QT_END_NAMESPACE
+#include "moc_qnetworkproxy.cpp"
+
#endif // QT_NO_NETWORKPROXY
diff --git a/src/network/kernel/qnetworkproxy.h b/src/network/kernel/qnetworkproxy.h
index 1f0409e8ab..d04bd9ee13 100644
--- a/src/network/kernel/qnetworkproxy.h
+++ b/src/network/kernel/qnetworkproxy.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNETWORKPROXY_H
#define QNETWORKPROXY_H
@@ -79,7 +43,7 @@ public:
QNetworkProxyQuery &operator=(const QNetworkProxyQuery &other);
~QNetworkProxyQuery();
- void swap(QNetworkProxyQuery &other) noexcept { qSwap(d, other.d); }
+ void swap(QNetworkProxyQuery &other) noexcept { d.swap(other.d); }
bool operator==(const QNetworkProxyQuery &other) const;
inline bool operator!=(const QNetworkProxyQuery &other) const
@@ -113,6 +77,7 @@ class QNetworkProxyPrivate;
class Q_NETWORK_EXPORT QNetworkProxy
{
+ Q_GADGET
public:
enum ProxyType {
DefaultProxy,
@@ -142,7 +107,7 @@ public:
QNetworkProxy &operator=(const QNetworkProxy &other);
~QNetworkProxy();
- void swap(QNetworkProxy &other) noexcept { qSwap(d, other.d); }
+ void swap(QNetworkProxy &other) noexcept { d.swap(other.d); }
bool operator==(const QNetworkProxy &other) const;
inline bool operator!=(const QNetworkProxy &other) const
@@ -210,7 +175,7 @@ Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, const QNetworkProxyQuery &proxy
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QNetworkProxy)
+QT_DECL_METATYPE_EXTERN(QNetworkProxy, Q_NETWORK_EXPORT)
#endif // QT_NO_NETWORKPROXY
diff --git a/src/network/kernel/qnetworkproxy_android.cpp b/src/network/kernel/qnetworkproxy_android.cpp
index ddfe86960f..3d37266b70 100644
--- a/src/network/kernel/qnetworkproxy_android.cpp
+++ b/src/network/kernel/qnetworkproxy_android.cpp
@@ -1,45 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qnetworkproxy.h"
-#include <QtCore/private/qjni_p.h>
-#include <QtCore/private/qjnihelpers_p.h>
+
+#include <QtCore/qcoreapplication_platform.h>
+#include <QtCore/qjnienvironment.h>
+#include <QtCore/qjniobject.h>
#ifndef QT_NO_NETWORKPROXY
@@ -52,24 +18,27 @@ public:
~ProxyInfoObject();
};
+using namespace QNativeInterface;
+
Q_GLOBAL_STATIC(ProxyInfoObject, proxyInfoInstance)
-static const char networkClass[] = "org/qtproject/qt5/android/network/QtNetwork";
+static const char networkClass[] = "org/qtproject/qt/android/network/QtNetwork";
+
+Q_DECLARE_JNI_CLASS(ProxyInfo, "android/net/ProxyInfo")
+Q_DECLARE_JNI_TYPE(JStringArray, "[Ljava/lang/String;")
ProxyInfoObject::ProxyInfoObject()
{
- QJNIObjectPrivate::callStaticMethod<void>(networkClass,
- "registerReceiver",
- "(Landroid/content/Context;)V",
- QtAndroidPrivate::context());
+ QJniObject::callStaticMethod<void>(networkClass,
+ "registerReceiver",
+ QAndroidApplication::context());
}
ProxyInfoObject::~ProxyInfoObject()
{
- QJNIObjectPrivate::callStaticMethod<void>(networkClass,
- "unregisterReceiver",
- "(Landroid/content/Context;)V",
- QtAndroidPrivate::context());
+ QJniObject::callStaticMethod<void>(networkClass,
+ "unregisterReceiver",
+ QAndroidApplication::context());
}
QList<QNetworkProxy> QNetworkProxyFactory::systemProxyForQuery(const QNetworkProxyQuery &query)
@@ -78,18 +47,16 @@ QList<QNetworkProxy> QNetworkProxyFactory::systemProxyForQuery(const QNetworkPro
if (!proxyInfoInstance)
return proxyList;
- QJNIObjectPrivate proxyInfo = QJNIObjectPrivate::callStaticObjectMethod(networkClass,
- "getProxyInfo",
- "(Landroid/content/Context;)Landroid/net/ProxyInfo;",
- QtAndroidPrivate::context());
+ QJniObject proxyInfo = QJniObject::callStaticObjectMethod<QtJniTypes::ProxyInfo>(
+ networkClass, "getProxyInfo", QAndroidApplication::context());
if (proxyInfo.isValid()) {
- QJNIObjectPrivate exclusionList = proxyInfo.callObjectMethod("getExclusionList",
- "()[Ljava/lang/String;");
+ QJniObject exclusionList =
+ proxyInfo.callObjectMethod<QtJniTypes::JStringArray>("getExclusionList");
bool exclude = false;
if (exclusionList.isValid()) {
- jobjectArray listObject = static_cast<jobjectArray>(exclusionList.object());
- QJNIEnvironmentPrivate env;
- QJNIObjectPrivate entry;
+ jobjectArray listObject = exclusionList.object<jobjectArray>();
+ QJniEnvironment env;
+ QJniObject entry;
const int size = env->GetArrayLength(listObject);
QUrl host = QUrl(query.url().host());
for (int i = 0; i < size; ++i) {
@@ -101,7 +68,7 @@ QList<QNetworkProxy> QNetworkProxyFactory::systemProxyForQuery(const QNetworkPro
}
}
if (!exclude) {
- QJNIObjectPrivate hostName = proxyInfo.callObjectMethod<jstring>("getHost");
+ QJniObject hostName = proxyInfo.callObjectMethod<jstring>("getHost");
const int port = proxyInfo.callMethod<jint>("getPort");
QNetworkProxy proxy(QNetworkProxy::HttpProxy, hostName.toString(), port);
proxyList << proxy;
diff --git a/src/network/kernel/qnetworkproxy_mac.cpp b/src/network/kernel/qnetworkproxy_darwin.cpp
index e4d2663f7a..d2bd4958dd 100644
--- a/src/network/kernel/qnetworkproxy_mac.cpp
+++ b/src/network/kernel/qnetworkproxy_darwin.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qnetworkproxy.h"
@@ -50,6 +14,7 @@
#include <QtCore/QUrl>
#include <QtCore/qendian.h>
#include <QtCore/qstringlist.h>
+#include <QtCore/qsystemdetection.h>
#include "private/qcore_mac_p.h"
/*
@@ -68,25 +33,33 @@
* \li Bypass list (by default: *.local, 169.254/16)
* \endlist
*
- * The matching configuration can be obtained by calling SCDynamicStoreCopyProxies
- * (from <SystemConfiguration/SCDynamicStoreCopySpecific.h>). See
+ * The matching configuration can be obtained by calling CFNetworkCopySystemProxySettings()
+ * (from <CFNetwork/CFProxySupport.h>). See
* Apple's documentation:
*
- * http://developer.apple.com/DOCUMENTATION/Networking/Reference/SysConfig/SCDynamicStoreCopySpecific/CompositePage.html#//apple_ref/c/func/SCDynamicStoreCopyProxies
+ * https://developer.apple.com/documentation/cfnetwork/1426754-cfnetworkcopysystemproxysettings?language=objc
*
*/
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
static bool isHostExcluded(CFDictionaryRef dict, const QString &host)
{
+ Q_ASSERT(dict);
+
if (host.isEmpty())
return true;
- bool isSimple = !host.contains(QLatin1Char('.')) && !host.contains(QLatin1Char(':'));
+#ifndef Q_OS_IOS
+ // On iOS all those keys are not available, and worse so - entries
+ // for HTTPS are not in the dictionary, but instead in some nested dictionary
+ // with undocumented keys/object types.
+ bool isSimple = !host.contains(u'.') && !host.contains(u':');
CFNumberRef excludeSimples;
if (isSimple &&
- (excludeSimples = (CFNumberRef)CFDictionaryGetValue(dict, kSCPropNetProxiesExcludeSimpleHostnames))) {
+ (excludeSimples = (CFNumberRef)CFDictionaryGetValue(dict, kCFNetworkProxiesExcludeSimpleHostnames))) {
int enabled;
if (CFNumberGetValue(excludeSimples, kCFNumberIntType, &enabled) && enabled)
return true;
@@ -97,7 +70,7 @@ static bool isHostExcluded(CFDictionaryRef dict, const QString &host)
// not a simple host name
// does it match the list of exclusions?
- CFArrayRef exclusionList = (CFArrayRef)CFDictionaryGetValue(dict, kSCPropNetProxiesExceptionsList);
+ CFArrayRef exclusionList = (CFArrayRef)CFDictionaryGetValue(dict, kCFNetworkProxiesExceptionsList);
if (!exclusionList)
return false;
@@ -115,7 +88,9 @@ static bool isHostExcluded(CFDictionaryRef dict, const QString &host)
return true;
}
}
-
+#else
+ Q_UNUSED(dict);
+#endif // Q_OS_IOS
// host was not excluded
return false;
}
@@ -146,7 +121,6 @@ static QNetworkProxy proxyFromDictionary(CFDictionaryRef dict, QNetworkProxy::Pr
return QNetworkProxy();
}
-
static QNetworkProxy proxyFromDictionary(CFDictionaryRef dict)
{
QNetworkProxy::ProxyType proxyType = QNetworkProxy::DefaultProxy;
@@ -208,20 +182,47 @@ QCFType<CFStringRef> stringByAddingPercentEscapes(CFStringRef originalPath)
{
Q_ASSERT(originalPath);
const auto qtPath = QString::fromCFString(originalPath);
- const auto escaped = QString::fromUtf8(QUrl::toPercentEncoding(qtPath));
+ const auto escaped = QString::fromUtf8(QUrl(qtPath).toEncoded());
return escaped.toCFString();
}
-} // anon namespace
+#ifdef Q_OS_IOS
+QList<QNetworkProxy> proxiesForQueryUrl(CFDictionaryRef dict, const QUrl &url)
+{
+ Q_ASSERT(dict);
+
+ const QCFType<CFURLRef> cfUrl = url.toCFURL();
+ const QCFType<CFArrayRef> proxies = CFNetworkCopyProxiesForURL(cfUrl, dict);
+ Q_ASSERT(proxies);
+
+ QList<QNetworkProxy> result;
+ const auto count = CFArrayGetCount(proxies);
+ if (!count) // Could be no proper proxy or host excluded.
+ return result;
+
+ for (CFIndex i = 0; i < count; ++i) {
+ const void *obj = CFArrayGetValueAtIndex(proxies, i);
+ if (CFGetTypeID(obj) != CFDictionaryGetTypeID())
+ continue;
+ const QNetworkProxy proxy = proxyFromDictionary(static_cast<CFDictionaryRef>(obj));
+ if (proxy.type() == QNetworkProxy::NoProxy || proxy.type() == QNetworkProxy::DefaultProxy)
+ continue;
+ result << proxy;
+ }
+
+ return result;
+}
+#endif // Q_OS_IOS
+} // unnamed namespace.
QList<QNetworkProxy> macQueryInternal(const QNetworkProxyQuery &query)
{
QList<QNetworkProxy> result;
// obtain a dictionary to the proxy settings:
- const QCFType<CFDictionaryRef> dict = SCDynamicStoreCopyProxies(NULL);
+ const QCFType<CFDictionaryRef> dict = CFNetworkCopySystemProxySettings();
if (!dict) {
- qWarning("QNetworkProxyFactory::systemProxyForQuery: SCDynamicStoreCopyProxies returned NULL");
+ qWarning("QNetworkProxyFactory::systemProxyForQuery: CFNetworkCopySystemProxySettings returned nullptr");
return result; // failed
}
@@ -230,13 +231,13 @@ QList<QNetworkProxy> macQueryInternal(const QNetworkProxyQuery &query)
// is there a PAC enabled? If so, use it first.
CFNumberRef pacEnabled;
- if ((pacEnabled = (CFNumberRef)CFDictionaryGetValue(dict, kSCPropNetProxiesProxyAutoConfigEnable))) {
+ if ((pacEnabled = (CFNumberRef)CFDictionaryGetValue(dict, kCFNetworkProxiesProxyAutoConfigEnable))) {
int enabled;
if (CFNumberGetValue(pacEnabled, kCFNumberIntType, &enabled) && enabled) {
// PAC is enabled
// kSCPropNetProxiesProxyAutoConfigURLString returns the URL string
// as entered in the system proxy configuration dialog
- CFStringRef pacLocationSetting = (CFStringRef)CFDictionaryGetValue(dict, kSCPropNetProxiesProxyAutoConfigURLString);
+ CFStringRef pacLocationSetting = (CFStringRef)CFDictionaryGetValue(dict, kCFNetworkProxiesProxyAutoConfigURLString);
auto cfPacLocation = stringByAddingPercentEscapes(pacLocationSetting);
QCFType<CFDataRef> pacData;
QCFType<CFURLRef> pacUrl = CFURLCreateWithString(kCFAllocatorDefault, cfPacLocation, NULL);
@@ -286,53 +287,77 @@ QList<QNetworkProxy> macQueryInternal(const QNetworkProxyQuery &query)
}
}
- // no PAC, decide which proxy we're looking for based on the query
- bool isHttps = false;
- QString protocol = query.protocolTag().toLower();
-
+ // No PAC, decide which proxy we're looking for based on the query
// try the protocol-specific proxy
+ const QString protocol = query.protocolTag();
QNetworkProxy protocolSpecificProxy;
- if (protocol == QLatin1String("ftp")) {
- protocolSpecificProxy =
- proxyFromDictionary(dict, QNetworkProxy::FtpCachingProxy,
- kSCPropNetProxiesFTPEnable,
- kSCPropNetProxiesFTPProxy,
- kSCPropNetProxiesFTPPort);
- } else if (protocol == QLatin1String("http")) {
+ if (protocol.compare("http"_L1, Qt::CaseInsensitive) == 0) {
protocolSpecificProxy =
proxyFromDictionary(dict, QNetworkProxy::HttpProxy,
- kSCPropNetProxiesHTTPEnable,
- kSCPropNetProxiesHTTPProxy,
- kSCPropNetProxiesHTTPPort);
- } else if (protocol == QLatin1String("https")) {
+ kCFNetworkProxiesHTTPEnable,
+ kCFNetworkProxiesHTTPProxy,
+ kCFNetworkProxiesHTTPPort);
+ }
+
+
+#ifdef Q_OS_IOS
+ if (protocolSpecificProxy.type() != QNetworkProxy::DefaultProxy
+ && protocolSpecificProxy.type() != QNetworkProxy::DefaultProxy) {
+ // HTTP proxy is enabled (on iOS there is no separate HTTPS, though
+ // 'dict' contains deeply buried entries which are the same as HTTP.
+ result << protocolSpecificProxy;
+ }
+
+ // TODO: check query.queryType()? It's possible, the exclude list
+ // did exclude it but above we added a proxy because HTTP proxy
+ // is found. We'll deal with such a situation later, since now NMI.
+ const auto proxiesForUrl = proxiesForQueryUrl(dict, query.url());
+ for (const auto &proxy : proxiesForUrl) {
+ if (!result.contains(proxy))
+ result << proxy;
+ }
+#else
+ bool isHttps = false;
+ if (protocol.compare("ftp"_L1, Qt::CaseInsensitive) == 0) {
+ protocolSpecificProxy =
+ proxyFromDictionary(dict, QNetworkProxy::FtpCachingProxy,
+ kCFNetworkProxiesFTPEnable,
+ kCFNetworkProxiesFTPProxy,
+ kCFNetworkProxiesFTPPort);
+ } else if (protocol.compare("https"_L1, Qt::CaseInsensitive) == 0) {
isHttps = true;
protocolSpecificProxy =
proxyFromDictionary(dict, QNetworkProxy::HttpProxy,
- kSCPropNetProxiesHTTPSEnable,
- kSCPropNetProxiesHTTPSProxy,
- kSCPropNetProxiesHTTPSPort);
+ kCFNetworkProxiesHTTPSEnable,
+ kCFNetworkProxiesHTTPSProxy,
+ kCFNetworkProxiesHTTPSPort);
}
+
if (protocolSpecificProxy.type() != QNetworkProxy::DefaultProxy)
result << protocolSpecificProxy;
// let's add SOCKSv5 if present too
QNetworkProxy socks5 = proxyFromDictionary(dict, QNetworkProxy::Socks5Proxy,
- kSCPropNetProxiesSOCKSEnable,
- kSCPropNetProxiesSOCKSProxy,
- kSCPropNetProxiesSOCKSPort);
+ kCFNetworkProxiesSOCKSEnable,
+ kCFNetworkProxiesSOCKSProxy,
+ kCFNetworkProxiesSOCKSPort);
if (socks5.type() != QNetworkProxy::DefaultProxy)
result << socks5;
// let's add the HTTPS proxy if present (and if we haven't added
// yet)
if (!isHttps) {
- QNetworkProxy https = proxyFromDictionary(dict, QNetworkProxy::HttpProxy,
- kSCPropNetProxiesHTTPSEnable,
- kSCPropNetProxiesHTTPSProxy,
- kSCPropNetProxiesHTTPSPort);
+ QNetworkProxy https;
+ https = proxyFromDictionary(dict, QNetworkProxy::HttpProxy,
+ kCFNetworkProxiesHTTPSEnable,
+ kCFNetworkProxiesHTTPSProxy,
+ kCFNetworkProxiesHTTPSPort);
+
+
if (https.type() != QNetworkProxy::DefaultProxy && https != protocolSpecificProxy)
result << https;
}
+#endif // !Q_OS_IOS
return result;
}
diff --git a/src/network/kernel/qnetworkproxy_generic.cpp b/src/network/kernel/qnetworkproxy_generic.cpp
index d2c7b29bc4..b915ee8fc8 100644
--- a/src/network/kernel/qnetworkproxy_generic.cpp
+++ b/src/network/kernel/qnetworkproxy_generic.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qnetworkproxy.h"
@@ -51,6 +15,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
static bool ignoreProxyFor(const QNetworkProxyQuery &query)
{
const QByteArray noProxy = qgetenv("no_proxy").trimmed();
@@ -62,7 +28,7 @@ static bool ignoreProxyFor(const QNetworkProxyQuery &query)
const QList<QByteArray> noProxyTokens = noProxy.split(',');
for (const QByteArray &rawToken : noProxyTokens) {
- auto token = QLatin1String(rawToken).trimmed();
+ auto token = QLatin1StringView(rawToken).trimmed();
// Since we use suffix matching, "*" is our 'default' behaviour
if (token.startsWith(u'*'))
@@ -101,11 +67,11 @@ QList<QNetworkProxy> QNetworkProxyFactory::systemProxyForQuery(const QNetworkPro
const QString queryProtocol = query.protocolTag();
QByteArray proxy_env;
- if (queryProtocol == QLatin1String("http"))
+ if (queryProtocol == "http"_L1)
proxy_env = qgetenv("http_proxy");
- else if (queryProtocol == QLatin1String("https"))
+ else if (queryProtocol == "https"_L1)
proxy_env = qgetenv("https_proxy");
- else if (queryProtocol == QLatin1String("ftp"))
+ else if (queryProtocol == "ftp"_L1)
proxy_env = qgetenv("ftp_proxy");
else
proxy_env = qgetenv("all_proxy");
@@ -117,16 +83,16 @@ QList<QNetworkProxy> QNetworkProxyFactory::systemProxyForQuery(const QNetworkPro
if (!proxy_env.isEmpty()) {
QUrl url = QUrl(QString::fromLocal8Bit(proxy_env));
const QString scheme = url.scheme();
- if (scheme == QLatin1String("socks5")) {
+ if (scheme == "socks5"_L1) {
QNetworkProxy proxy(QNetworkProxy::Socks5Proxy, url.host(),
url.port() ? url.port() : 1080, url.userName(), url.password());
proxyList << proxy;
- } else if (scheme == QLatin1String("socks5h")) {
+ } else if (scheme == "socks5h"_L1) {
QNetworkProxy proxy(QNetworkProxy::Socks5Proxy, url.host(),
url.port() ? url.port() : 1080, url.userName(), url.password());
proxy.setCapabilities(QNetworkProxy::HostNameLookupCapability);
proxyList << proxy;
- } else if ((scheme.isEmpty() || scheme == QLatin1String("http"))
+ } else if ((scheme.isEmpty() || scheme == "http"_L1)
&& query.queryType() != QNetworkProxyQuery::UdpSocket
&& query.queryType() != QNetworkProxyQuery::TcpServer) {
QNetworkProxy proxy(QNetworkProxy::HttpProxy, url.host(),
diff --git a/src/network/kernel/qnetworkproxy_libproxy.cpp b/src/network/kernel/qnetworkproxy_libproxy.cpp
index 29d2a0bd3b..248a8d2456 100644
--- a/src/network/kernel/qnetworkproxy_libproxy.cpp
+++ b/src/network/kernel/qnetworkproxy_libproxy.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2017 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2017 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qnetworkproxy.h"
@@ -48,12 +12,15 @@
#include <QtCore/QUrl>
#include <QtCore/private/qeventdispatcher_unix_p.h>
#include <QtCore/private/qthread_p.h>
+#include <QtCore/qapplicationstatic.h>
#include <proxy.h>
#include <dlfcn.h>
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
static bool isThreadingNeeded()
{
// Try to guess if the libproxy we linked to is from the libproxy project
@@ -106,7 +73,7 @@ private:
Data *request;
};
-Q_GLOBAL_STATIC(QLibProxyWrapper, libProxyWrapper);
+Q_APPLICATION_STATIC(QLibProxyWrapper, libProxyWrapper)
QLibProxyWrapper::QLibProxyWrapper()
{
@@ -221,14 +188,13 @@ QList<QNetworkProxy> QNetworkProxyFactory::systemProxyForQuery(const QNetworkPro
for (const QUrl& url : rawProxies) {
QNetworkProxy::ProxyType type;
const QString scheme = url.scheme();
- if (scheme == QLatin1String("http")) {
+ if (scheme == "http"_L1) {
type = QNetworkProxy::HttpProxy;
- } else if (scheme == QLatin1String("socks")
- || scheme == QLatin1String("socks5")) {
+ } else if (scheme == "socks"_L1 || scheme == "socks5"_L1) {
type = QNetworkProxy::Socks5Proxy;
- } else if (scheme == QLatin1String("ftp")) {
+ } else if (scheme == "ftp"_L1) {
type = QNetworkProxy::FtpCachingProxy;
- } else if (scheme == QLatin1String("direct")) {
+ } else if (scheme == "direct"_L1) {
type = QNetworkProxy::NoProxy;
haveDirectConnection = true;
} else {
diff --git a/src/network/kernel/qnetworkproxy_win.cpp b/src/network/kernel/qnetworkproxy_win.cpp
index 30663917ce..a2daa62e84 100644
--- a/src/network/kernel/qnetworkproxy_win.cpp
+++ b/src/network/kernel/qnetworkproxy_win.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qnetworkproxy.h"
@@ -45,109 +9,38 @@
#include <qstringlist.h>
#include <qregularexpression.h>
#include <qurl.h>
-#include <private/qsystemlibrary_p.h>
#include <qnetworkinterface.h>
#include <qdebug.h>
+#include <qvarlengtharray.h>
+#include <qhash.h>
#include <string.h>
#include <qt_windows.h>
-#include <wininet.h>
#include <lmcons.h>
-
-/*
- * Information on the WinHTTP DLL:
- * http://msdn.microsoft.com/en-us/library/aa384122(VS.85).aspx example for WPAD
- *
- * http://msdn.microsoft.com/en-us/library/aa384097(VS.85).aspx WinHttpGetProxyForUrl
- * http://msdn.microsoft.com/en-us/library/aa384096(VS.85).aspx WinHttpGetIEProxyConfigForCurrentUs
- * http://msdn.microsoft.com/en-us/library/aa384095(VS.85).aspx WinHttpGetDefaultProxyConfiguration
- */
-
-// We don't want to include winhttp.h because that's not
-// present in some Windows SDKs (I don't know why)
-// So, instead, copy the definitions here
-
-typedef struct {
- DWORD dwFlags;
- DWORD dwAutoDetectFlags;
- LPCWSTR lpszAutoConfigUrl;
- LPVOID lpvReserved;
- DWORD dwReserved;
- BOOL fAutoLogonIfChallenged;
-} WINHTTP_AUTOPROXY_OPTIONS;
-
-typedef struct {
- DWORD dwAccessType;
- LPWSTR lpszProxy;
- LPWSTR lpszProxyBypass;
-} WINHTTP_PROXY_INFO;
-
-typedef struct {
- BOOL fAutoDetect;
- LPWSTR lpszAutoConfigUrl;
- LPWSTR lpszProxy;
- LPWSTR lpszProxyBypass;
-} WINHTTP_CURRENT_USER_IE_PROXY_CONFIG;
-
-#define WINHTTP_AUTOPROXY_AUTO_DETECT 0x00000001
-#define WINHTTP_AUTOPROXY_CONFIG_URL 0x00000002
-
-#define WINHTTP_AUTO_DETECT_TYPE_DHCP 0x00000001
-#define WINHTTP_AUTO_DETECT_TYPE_DNS_A 0x00000002
-
-#define WINHTTP_ACCESS_TYPE_DEFAULT_PROXY 0
-#define WINHTTP_ACCESS_TYPE_NO_PROXY 1
-#define WINHTTP_ACCESS_TYPE_NAMED_PROXY 3
-
-#define WINHTTP_NO_PROXY_NAME NULL
-#define WINHTTP_NO_PROXY_BYPASS NULL
-
-#define WINHTTP_ERROR_BASE 12000
-#define ERROR_WINHTTP_LOGIN_FAILURE (WINHTTP_ERROR_BASE + 15)
-#define ERROR_WINHTTP_UNABLE_TO_DOWNLOAD_SCRIPT (WINHTTP_ERROR_BASE + 167)
-#define ERROR_WINHTTP_AUTODETECTION_FAILED (WINHTTP_ERROR_BASE + 180)
+#include <winhttp.h>
QT_BEGIN_NAMESPACE
-typedef BOOL (WINAPI * PtrWinHttpGetProxyForUrl)(HINTERNET, LPCWSTR, WINHTTP_AUTOPROXY_OPTIONS*, WINHTTP_PROXY_INFO*);
-typedef HINTERNET (WINAPI * PtrWinHttpOpen)(LPCWSTR, DWORD, LPCWSTR, LPCWSTR,DWORD);
-typedef BOOL (WINAPI * PtrWinHttpGetDefaultProxyConfiguration)(WINHTTP_PROXY_INFO*);
-typedef BOOL (WINAPI * PtrWinHttpGetIEProxyConfigForCurrentUser)(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG*);
-typedef BOOL (WINAPI * PtrWinHttpCloseHandle)(HINTERNET);
-typedef BOOL (WINAPI * PtrCloseServiceHandle)(SC_HANDLE hSCObject);
-static PtrWinHttpGetProxyForUrl ptrWinHttpGetProxyForUrl = 0;
-static PtrWinHttpOpen ptrWinHttpOpen = 0;
-static PtrWinHttpGetDefaultProxyConfiguration ptrWinHttpGetDefaultProxyConfiguration = 0;
-static PtrWinHttpGetIEProxyConfigForCurrentUser ptrWinHttpGetIEProxyConfigForCurrentUser = 0;
-static PtrWinHttpCloseHandle ptrWinHttpCloseHandle = 0;
-
+using namespace Qt::StringLiterals;
static bool currentProcessIsService()
{
- typedef BOOL (WINAPI *PtrGetUserName)(LPTSTR lpBuffer, LPDWORD lpnSize);
- typedef BOOL (WINAPI *PtrLookupAccountName)(LPCTSTR lpSystemName, LPCTSTR lpAccountName, PSID Sid,
- LPDWORD cbSid, LPTSTR ReferencedDomainName, LPDWORD cchReferencedDomainName, PSID_NAME_USE peUse);
- static PtrGetUserName ptrGetUserName = (PtrGetUserName)QSystemLibrary::resolve(QLatin1String("Advapi32"), "GetUserNameW");
- static PtrLookupAccountName ptrLookupAccountName = (PtrLookupAccountName)QSystemLibrary::resolve(QLatin1String("Advapi32"), "LookupAccountNameW");
-
- if (ptrGetUserName && ptrLookupAccountName) {
- wchar_t userName[UNLEN + 1] = L"";
- DWORD size = UNLEN;
- if (ptrGetUserName(userName, &size)) {
- SID_NAME_USE type = SidTypeUser;
- DWORD sidSize = 0;
- DWORD domainSize = 0;
- // first call is to get the correct size
- bool bRet = ptrLookupAccountName(NULL, userName, NULL, &sidSize, NULL, &domainSize, &type);
- if (bRet == FALSE && ERROR_INSUFFICIENT_BUFFER != GetLastError())
- return false;
- QVarLengthArray<BYTE, 68> buff(sidSize);
- QVarLengthArray<wchar_t, MAX_PATH> domainName(domainSize);
- // second call to LookupAccountNameW actually gets the SID
- // both the pointer to the buffer and the pointer to the domain name should not be NULL
- if (ptrLookupAccountName(NULL, userName, buff.data(), &sidSize, domainName.data(), &domainSize, &type))
- return type != SidTypeUser; //returns true if the current user is not a user
- }
+ wchar_t userName[UNLEN + 1] = L"";
+ DWORD size = UNLEN;
+ if (GetUserNameW(userName, &size)) {
+ SID_NAME_USE type = SidTypeUser;
+ DWORD sidSize = 0;
+ DWORD domainSize = 0;
+ // first call is to get the correct size
+ bool bRet = LookupAccountNameW(NULL, userName, NULL, &sidSize, NULL, &domainSize, &type);
+ if (bRet == FALSE && ERROR_INSUFFICIENT_BUFFER != GetLastError())
+ return false;
+ QVarLengthArray<BYTE, 68> buff(sidSize);
+ QVarLengthArray<wchar_t, MAX_PATH> domainName(domainSize);
+ // second call to LookupAccountNameW actually gets the SID
+ // both the pointer to the buffer and the pointer to the domain name should not be NULL
+ if (LookupAccountNameW(NULL, userName, buff.data(), &sidSize, domainName.data(), &domainSize, &type))
+ return type != SidTypeUser; //returns true if the current user is not a user
}
return false;
}
@@ -155,11 +48,11 @@ static bool currentProcessIsService()
static QStringList splitSpaceSemicolon(const QString &source)
{
QStringList list;
- int start = 0;
- int end;
+ qsizetype start = 0;
+ qsizetype end;
while (true) {
- int space = source.indexOf(QLatin1Char(' '), start);
- int semicolon = source.indexOf(QLatin1Char(';'), start);
+ qsizetype space = source.indexOf(u' ', start);
+ qsizetype semicolon = source.indexOf(u';', start);
end = space;
if (semicolon != -1 && (end == -1 || semicolon < end))
end = semicolon;
@@ -181,7 +74,7 @@ static bool isBypassed(const QString &host, const QStringList &bypassList)
if (host.isEmpty())
return false;
- bool isSimple = !host.contains(QLatin1Char('.')) && !host.contains(QLatin1Char(':'));
+ bool isSimple = !host.contains(u'.') && !host.contains(u':');
QHostAddress ipAddress;
bool isIpAddress = ipAddress.setAddress(host);
@@ -192,7 +85,7 @@ static bool isBypassed(const QString &host, const QStringList &bypassList)
// does it match the list of exclusions?
for (const QString &entry : bypassList) {
- if (entry == QLatin1String("<local>")) {
+ if (entry == "<local>"_L1) {
if (isSimple)
return true;
if (isIpAddress) {
@@ -292,32 +185,32 @@ static QList<QNetworkProxy> parseServerList(const QNetworkProxyQuery &query, con
&& query.queryType() != QNetworkProxyQuery::TcpServer
&& query.queryType() != QNetworkProxyQuery::SctpServer;
for (const QString &entry : proxyList) {
- int server = 0;
+ qsizetype server = 0;
QNetworkProxy::ProxyType proxyType = QNetworkProxy::HttpProxy;
quint16 port = 8080;
- int pos = entry.indexOf(QLatin1Char('='));
+ qsizetype pos = entry.indexOf(u'=');
QStringView scheme;
QStringView protocolTag;
if (pos != -1) {
scheme = protocolTag = QStringView{entry}.left(pos);
server = pos + 1;
}
- pos = entry.indexOf(QLatin1String("://"), server);
+ pos = entry.indexOf("://"_L1, server);
if (pos != -1) {
scheme = QStringView{entry}.mid(server, pos - server);
server = pos + 3;
}
if (!scheme.isEmpty()) {
- if (scheme == QLatin1String("http") || scheme == QLatin1String("https")) {
+ if (scheme == "http"_L1 || scheme == "https"_L1) {
// no-op
// defaults are above
- } else if (scheme == QLatin1String("socks") || scheme == QLatin1String("socks5")) {
+ } else if (scheme == "socks"_L1 || scheme == "socks5"_L1) {
proxyType = QNetworkProxy::Socks5Proxy;
port = 1080;
- } else if (scheme == QLatin1String("ftp")) {
+ } else if (scheme == "ftp"_L1) {
proxyType = QNetworkProxy::FtpCachingProxy;
port = 2121;
} else {
@@ -326,7 +219,7 @@ static QList<QNetworkProxy> parseServerList(const QNetworkProxyQuery &query, con
}
}
- pos = entry.indexOf(QLatin1Char(':'), server);
+ pos = entry.indexOf(u':', server);
if (pos != -1) {
bool ok;
uint value = QStringView{entry}.mid(pos + 1).toUInt(&ok);
@@ -352,10 +245,10 @@ static QList<QNetworkProxy> parseServerList(const QNetworkProxyQuery &query, con
result.prepend(taggedProxies.value(requiredTag));
}
}
- if (!checkTags || requiredTag != QLatin1String("http")) {
+ if (!checkTags || requiredTag != "http"_L1) {
// if there are different http proxies for http and https, prefer the https one (more likely to be capable of CONNECT)
- QNetworkProxy httpProxy = taggedProxies.value(QLatin1String("http"));
- QNetworkProxy httpsProxy = taggedProxies.value(QLatin1String("http"));
+ QNetworkProxy httpProxy = taggedProxies.value("http"_L1);
+ QNetworkProxy httpsProxy = taggedProxies.value("http"_L1);
if (httpProxy != httpsProxy && httpProxy.type() == QNetworkProxy::HttpProxy && httpsProxy.type() == QNetworkProxy::HttpProxy) {
for (int i = 0; i < result.count(); i++) {
if (httpProxy == result.at(i))
@@ -402,9 +295,9 @@ public:
}
void clear() {
- for (HANDLE event : qAsConst(m_watchEvents))
+ for (HANDLE event : std::as_const(m_watchEvents))
CloseHandle(event);
- for (HKEY key : qAsConst(m_registryHandles))
+ for (HKEY key : std::as_const(m_registryHandles))
RegCloseKey(key);
m_watchEvents.clear();
@@ -456,7 +349,7 @@ QWindowsSystemProxy::QWindowsSystemProxy()
QWindowsSystemProxy::~QWindowsSystemProxy()
{
if (hHttpSession)
- ptrWinHttpCloseHandle(hHttpSession);
+ WinHttpCloseHandle(hHttpSession);
}
void QWindowsSystemProxy::reset()
@@ -486,20 +379,9 @@ void QWindowsSystemProxy::init()
proxySettingsWatcher.addLocation(HKEY_LOCAL_MACHINE, QStringLiteral("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"));
proxySettingsWatcher.addLocation(HKEY_LOCAL_MACHINE, QStringLiteral("Software\\Policies\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"));
- // load the winhttp.dll library
- QSystemLibrary lib(L"winhttp");
- if (!lib.load())
- return; // failed to load
-
- ptrWinHttpOpen = (PtrWinHttpOpen)lib.resolve("WinHttpOpen");
- ptrWinHttpCloseHandle = (PtrWinHttpCloseHandle)lib.resolve("WinHttpCloseHandle");
- ptrWinHttpGetProxyForUrl = (PtrWinHttpGetProxyForUrl)lib.resolve("WinHttpGetProxyForUrl");
- ptrWinHttpGetDefaultProxyConfiguration = (PtrWinHttpGetDefaultProxyConfiguration)lib.resolve("WinHttpGetDefaultProxyConfiguration");
- ptrWinHttpGetIEProxyConfigForCurrentUser = (PtrWinHttpGetIEProxyConfigForCurrentUser)lib.resolve("WinHttpGetIEProxyConfigForCurrentUser");
-
// Try to obtain the Internet Explorer configuration.
WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ieProxyConfig;
- const bool hasIEConfig = ptrWinHttpGetIEProxyConfigForCurrentUser(&ieProxyConfig);
+ const bool hasIEConfig = WinHttpGetIEProxyConfigForCurrentUser(&ieProxyConfig);
if (hasIEConfig) {
if (ieProxyConfig.lpszAutoConfigUrl) {
autoConfigUrl = QString::fromWCharArray(ieProxyConfig.lpszAutoConfigUrl);
@@ -524,7 +406,7 @@ void QWindowsSystemProxy::init()
// attempt to get the default configuration instead
// that config will serve as default if WPAD fails
WINHTTP_PROXY_INFO proxyInfo;
- if (ptrWinHttpGetDefaultProxyConfiguration(&proxyInfo) &&
+ if (WinHttpGetDefaultProxyConfiguration(&proxyInfo) &&
proxyInfo.dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY) {
// we got information from the registry
// overwrite the IE configuration, if any
@@ -542,11 +424,11 @@ void QWindowsSystemProxy::init()
hHttpSession = NULL;
if (ieProxyConfig.fAutoDetect || !autoConfigUrl.isEmpty()) {
// open the handle and obtain the options
- hHttpSession = ptrWinHttpOpen(L"Qt System Proxy access/1.0",
- WINHTTP_ACCESS_TYPE_NO_PROXY,
- WINHTTP_NO_PROXY_NAME,
- WINHTTP_NO_PROXY_BYPASS,
- 0);
+ hHttpSession = WinHttpOpen(L"Qt System Proxy access/1.0",
+ WINHTTP_ACCESS_TYPE_NO_PROXY,
+ WINHTTP_NO_PROXY_NAME,
+ WINHTTP_NO_PROXY_BYPASS,
+ 0);
if (!hHttpSession)
return;
@@ -588,11 +470,11 @@ QList<QNetworkProxy> QNetworkProxyFactory::systemProxyForQuery(const QNetworkPro
// url could be empty, e.g. from QNetworkProxy::applicationProxy(), that's fine,
// we'll still ask for the proxy.
// But for a file url, we know we don't need one.
- if (url.scheme() == QLatin1String("file") || url.scheme() == QLatin1String("qrc"))
+ if (url.scheme() == "file"_L1 || url.scheme() == "qrc"_L1)
return sp->defaultResult;
if (query.queryType() != QNetworkProxyQuery::UrlRequest) {
// change the scheme to https, maybe it'll work
- url.setScheme(QLatin1String("https"));
+ url.setScheme("https"_L1);
}
QString urlQueryString = url.toString();
@@ -603,7 +485,7 @@ QList<QNetworkProxy> QNetworkProxyFactory::systemProxyForQuery(const QNetworkPro
urlQueryString = url.toString().left(2083);
}
- bool getProxySucceeded = ptrWinHttpGetProxyForUrl(sp->hHttpSession,
+ bool getProxySucceeded = WinHttpGetProxyForUrl(sp->hHttpSession,
reinterpret_cast<LPCWSTR>(urlQueryString.utf16()),
&sp->autoProxyOptions,
&proxyInfo);
@@ -621,7 +503,7 @@ QList<QNetworkProxy> QNetworkProxyFactory::systemProxyForQuery(const QNetworkPro
sp->autoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL;
sp->autoProxyOptions.lpszAutoConfigUrl =
reinterpret_cast<LPCWSTR>(sp->autoConfigUrl.utf16());
- getProxySucceeded = ptrWinHttpGetProxyForUrl(sp->hHttpSession,
+ getProxySucceeded = WinHttpGetProxyForUrl(sp->hHttpSession,
reinterpret_cast<LPCWSTR>(urlQueryString.utf16()),
&sp->autoProxyOptions,
&proxyInfo);
@@ -634,7 +516,7 @@ QList<QNetworkProxy> QNetworkProxyFactory::systemProxyForQuery(const QNetworkPro
// We first tried without AutoLogon, because this might prevent caching the result.
// But now we've to enable it (http://msdn.microsoft.com/en-us/library/aa383153%28v=VS.85%29.aspx)
sp->autoProxyOptions.fAutoLogonIfChallenged = TRUE;
- getProxySucceeded = ptrWinHttpGetProxyForUrl(sp->hHttpSession,
+ getProxySucceeded = WinHttpGetProxyForUrl(sp->hHttpSession,
reinterpret_cast<LPCWSTR>(urlQueryString.utf16()),
&sp->autoProxyOptions,
&proxyInfo);
diff --git a/src/network/kernel/qtldurl.cpp b/src/network/kernel/qtldurl.cpp
index 7dc4e9cd47..a7aceddb18 100644
--- a/src/network/kernel/qtldurl.cpp
+++ b/src/network/kernel/qtldurl.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qglobal.h>
@@ -43,70 +7,167 @@
#if QT_CONFIG(topleveldomain)
-#include "qplatformdefs.h"
-#include "qurl.h"
-#include "private/qurltlds_p.h"
-#include "private/qtldurl_p.h"
-#include "QtCore/qlist.h"
+#include "QtCore/qfile.h"
+#include "QtCore/qloggingcategory.h"
+#include "QtCore/qstandardpaths.h"
#include "QtCore/qstring.h"
+#if !QT_CONFIG(publicsuffix_qt) && !QT_CONFIG(publicsuffix_system)
+# error Enable at least one feature: publicsuffix-qt, publicsuffix-system
+#endif
+
+#if QT_CONFIG(publicsuffix_qt)
+# include "psl_data.cpp"
+#endif
+
+// Defined in src/3rdparty/libpsl/src/lookup_string_in_fixed_set.c
+extern "C" int LookupStringInFixedSet(const unsigned char *graph, std::size_t length,
+ const char *key, std::size_t key_length);
+
QT_BEGIN_NAMESPACE
-enum TLDMatchType {
- ExactMatch,
- SuffixMatch,
- ExceptionMatch,
+using namespace Qt::StringLiterals;
+
+Q_LOGGING_CATEGORY(lcTld, "qt.network.tld")
+
+static constexpr int PSL_NOT_FOUND = -1;
+static constexpr int PSL_FLAG_EXCEPTION = 1 << 0;
+static constexpr int PSL_FLAG_WILDCARD = 1 << 1;
+
+class QPublicSuffixDatabase final
+{
+public:
+#if QT_CONFIG(publicsuffix_system)
+ QPublicSuffixDatabase();
+#endif // QT_CONFIG(publicsuffix_system)
+
+ int lookupDomain(QByteArrayView domain) const;
+
+private:
+ QByteArrayView m_data
+#if QT_CONFIG(publicsuffix_qt)
+ {
+ kDafsa, sizeof(kDafsa)
+ }
+#endif // QT_CONFIG(publicsuffix_qt)
+ ;
+
+#if QT_CONFIG(publicsuffix_system)
+ std::unique_ptr<QFile> m_dev;
+ QByteArray m_storage;
+ bool loadFile(const QString &fileName);
+#endif // QT_CONFIG(publicsuffix_system)
};
-// Scan the auto-generated table of TLDs for an entry. For more details
-// see comments in file: util/corelib/qurl-generateTLDs/main.cpp
-static bool containsTLDEntry(QStringView entry, TLDMatchType match)
+int QPublicSuffixDatabase::lookupDomain(QByteArrayView domain) const
+{
+ return LookupStringInFixedSet(reinterpret_cast<const unsigned char *>(m_data.constData()),
+ m_data.size(), domain.data(), domain.size());
+}
+
+#if QT_CONFIG(publicsuffix_system)
+
+static QStringList locatePublicSuffixFiles()
+{
+ return QStandardPaths::locateAll(QStandardPaths::GenericDataLocation,
+ u"publicsuffix/public_suffix_list.dafsa"_s);
+}
+
+QPublicSuffixDatabase::QPublicSuffixDatabase()
{
- const QStringView matchSymbols[] = {
- u"",
- u"*",
- u"!",
- };
- const auto symbol = matchSymbols[match];
- const int index = qt_hash(entry, qt_hash(symbol)) % tldCount;
-
- // select the right chunk from the big table
- short chunk = 0;
- uint chunkIndex = tldIndices[index], offset = 0;
-
- // The offset in the big string, of the group that our entry hashes into.
- const auto tldGroupOffset = tldIndices[index];
-
- // It should always be inside all chunks' total size.
- Q_ASSERT(tldGroupOffset < tldChunks[tldChunkCount - 1]);
- // All offsets are stored in non-decreasing order.
- // This check is within bounds as tldIndices has length tldCount+1.
- Q_ASSERT(tldGroupOffset <= tldIndices[index + 1]);
- // The last extra entry in tldIndices
- // should be equal to the total of all chunks' lengths.
- static_assert(tldIndices[tldCount] == tldChunks[tldChunkCount - 1]);
-
- // Find which chunk contains the tldGroupOffset
- while (tldGroupOffset >= tldChunks[chunk]) {
- chunkIndex -= tldChunks[chunk];
- offset += tldChunks[chunk];
- chunk++;
-
- // We can not go above the number of chunks we have, since all our
- // indices are less than the total chunks' size (see asserts above).
- Q_ASSERT(chunk < tldChunkCount);
+ for (auto &&fileName : locatePublicSuffixFiles()) {
+ if (loadFile(fileName))
+ return;
}
- // check all the entries from the given offset
- while (chunkIndex < tldIndices[index+1] - offset) {
- const auto utf8 = tldData[chunk] + chunkIndex;
- if ((symbol.isEmpty() || QLatin1Char(*utf8) == symbol) && entry == QString::fromUtf8(utf8 + symbol.size()))
- return true;
- chunkIndex += uint(qstrlen(utf8)) + 1; // +1 for the ending \0
+#if QT_CONFIG(publicsuffix_qt)
+ qCDebug(lcTld, "Using builtin publicsuffix list");
+#else
+ qCWarning(lcTld, "No usable publicsuffix file found");
+#endif
+}
+
+bool QPublicSuffixDatabase::loadFile(const QString &fileName)
+{
+ static const QByteArrayView DafsaFileHeader = ".DAFSA@PSL_0 \n";
+
+ qCDebug(lcTld, "Loading publicsuffix file: %s", qUtf8Printable(fileName));
+
+ auto systemFile = std::make_unique<QFile>(fileName);
+
+ if (!systemFile->open(QIODevice::ReadOnly)) {
+ qCDebug(lcTld, "Failed to open publicsuffix file: %s",
+ qUtf8Printable(systemFile->errorString()));
+ return false;
+ }
+
+ auto fileSize = systemFile->size();
+ // Check if there is enough data for header, version byte and some data
+ if (fileSize < DafsaFileHeader.size() + 2) {
+ qCWarning(lcTld, "publicsuffix file is too small: %zu", std::size_t(fileSize));
+ return false;
+ }
+
+ auto header = systemFile->read(DafsaFileHeader.size());
+ if (header != DafsaFileHeader) {
+ qCWarning(lcTld, "Invalid publicsuffix file header: %s", header.toHex().constData());
+ return false;
+ }
+
+ // Check if the file is UTF-8 compatible
+ if (!systemFile->seek(fileSize - 1)) {
+ qCWarning(lcTld, "Failed to seek to the end of file: %s",
+ qUtf8Printable(systemFile->errorString()));
+ return false;
+ }
+
+ char version;
+ if (systemFile->read(&version, 1) != 1) {
+ qCWarning(lcTld, "Failed to read publicsuffix version");
+ return false;
+ }
+
+ if (version != 0x01) {
+ qCWarning(lcTld, "Unsupported publicsuffix version: %d", int(version));
+ return false;
+ }
+
+ const auto dataSize = fileSize - DafsaFileHeader.size() - 1;
+ // Try to map the file first
+ auto mappedData = systemFile->map(DafsaFileHeader.size(), dataSize);
+ if (mappedData) {
+ qCDebug(lcTld, "Using mapped system publicsuffix data");
+ systemFile->close();
+ m_data = QByteArrayView(mappedData, dataSize);
+ m_dev = std::move(systemFile);
+ return true;
+ }
+
+ qCDebug(lcTld, "Failed to map publicsuffix file: %s",
+ qUtf8Printable(systemFile->errorString()));
+
+ systemFile->seek(DafsaFileHeader.size());
+ m_storage = systemFile->read(dataSize);
+ if (m_storage.size() != dataSize) {
+ qCWarning(lcTld, "Failed to read publicsuffix file");
+ m_storage.clear();
+ return false;
}
- return false;
+
+ qCDebug(lcTld, "Using system publicsuffix data");
+ m_data = m_storage;
+
+ return true;
}
+Q_GLOBAL_STATIC(QPublicSuffixDatabase, publicSuffix);
+
+#else
+
+static const QPublicSuffixDatabase m_publicSuffix;
+
+#endif // QT_CONFIG(publicsuffix_system)
+
/*!
\internal
@@ -118,21 +179,37 @@ static bool containsTLDEntry(QStringView entry, TLDMatchType match)
Q_NETWORK_EXPORT bool qIsEffectiveTLD(QStringView domain)
{
// for domain 'foo.bar.com':
- // 1. return if TLD table contains 'foo.bar.com'
- // 2. else if table contains '*.bar.com',
- // 3. test that table does not contain '!foo.bar.com'
-
- if (containsTLDEntry(domain, ExactMatch)) // 1
- return true;
+ // 1. return false if TLD table contains '!foo.bar.com'
+ // 2. return true if TLD table contains 'foo.bar.com'
+ // 3. return true if the table contains '*.bar.com'
+
+ QByteArray decodedDomain = domain.toUtf8();
+ QByteArrayView domainView(decodedDomain);
+
+#if QT_CONFIG(publicsuffix_system)
+ if (publicSuffix.isDestroyed())
+ return false;
+#else
+ auto publicSuffix = &m_publicSuffix;
+#endif // QT_CONFIG(publicsuffix_system)
+
+ auto ret = publicSuffix->lookupDomain(domainView);
+ if (ret != PSL_NOT_FOUND) {
+ if (ret & PSL_FLAG_EXCEPTION) // 1
+ return false;
+ if ((ret & PSL_FLAG_WILDCARD) == 0) // 2
+ return true;
+ }
- const auto dot = domain.indexOf(QLatin1Char('.'));
+ const auto dot = domainView.indexOf('.');
if (dot < 0) // Actual TLD: may be effective if the subject of a wildcard rule:
- return containsTLDEntry(QString(QLatin1Char('.') + domain), SuffixMatch);
- if (containsTLDEntry(domain.mid(dot), SuffixMatch)) // 2
- return !containsTLDEntry(domain, ExceptionMatch); // 3
- return false;
+ return ret != PSL_NOT_FOUND;
+ ret = publicSuffix->lookupDomain(domainView.sliced(dot + 1)); // 3
+ if (ret == PSL_NOT_FOUND)
+ return false;
+ return (ret & PSL_FLAG_WILDCARD) != 0;
}
QT_END_NAMESPACE
-#endif
+#endif // QT_CONFIG(topleveldomain)
diff --git a/src/network/kernel/qtldurl_p.h b/src/network/kernel/qtldurl_p.h
index ea1ed78034..86b163f161 100644
--- a/src/network/kernel/qtldurl_p.h
+++ b/src/network/kernel/qtldurl_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QTLDURL_P_H
#define QTLDURL_P_H
@@ -52,7 +16,6 @@
//
#include <QtNetwork/private/qtnetworkglobal_p.h>
-#include "QtCore/qurl.h"
#include "QtCore/qstring.h"
QT_REQUIRE_CONFIG(topleveldomain);
@@ -67,4 +30,4 @@ inline bool qIsEffectiveTLD(const QString &domain)
QT_END_NAMESPACE
-#endif // QDATAURL_P_H
+#endif // QTLDURL_P_H
diff --git a/src/network/kernel/qtnetworkglobal.h b/src/network/kernel/qtnetworkglobal.h
index 586b847816..b22ddc6950 100644
--- a/src/network/kernel/qtnetworkglobal.h
+++ b/src/network/kernel/qtnetworkglobal.h
@@ -1,61 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QTNETWORKGLOBAL_H
#define QTNETWORKGLOBAL_H
#include <QtCore/qglobal.h>
#include <QtNetwork/qtnetwork-config.h>
-
-QT_BEGIN_NAMESPACE
-
-#ifndef QT_STATIC
-# if defined(QT_BUILD_NETWORK_LIB)
-# define Q_NETWORK_EXPORT Q_DECL_EXPORT
-# else
-# define Q_NETWORK_EXPORT Q_DECL_IMPORT
-# endif
-#else
-# define Q_NETWORK_EXPORT
-#endif
-
-QT_END_NAMESPACE
+#include <QtNetwork/qtnetworkexports.h>
#endif
diff --git a/src/network/kernel/qtnetworkglobal_p.h b/src/network/kernel/qtnetworkglobal_p.h
index 859e3d9ebd..b90e675cb4 100644
--- a/src/network/kernel/qtnetworkglobal_p.h
+++ b/src/network/kernel/qtnetworkglobal_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QTNETWORKGLOBAL_P_H
#define QTNETWORKGLOBAL_P_H
@@ -55,4 +19,15 @@
#include <QtCore/private/qglobal_p.h>
#include <QtNetwork/private/qtnetwork-config_p.h>
+QT_BEGIN_NAMESPACE
+
+enum {
+#if defined(Q_OS_LINUX) || defined(Q_OS_QNX)
+ PlatformSupportsAbstractNamespace = true
+#else
+ PlatformSupportsAbstractNamespace = false
+#endif
+};
+
+QT_END_NAMESPACE
#endif // QTNETWORKGLOBAL_P_H
diff --git a/src/network/kernel/qurltlds_p.h b/src/network/kernel/qurltlds_p.h
deleted file mode 100644
index 3738e5bab5..0000000000
--- a/src/network/kernel/qurltlds_p.h
+++ /dev/null
@@ -1,14540 +0,0 @@
-// License: MPL 2.0/GPL 2.0/LGPL 3
-//
-// The contents of this file are subject to the Mozilla Public License Version
-// 2.0 (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-// http://www.mozilla.org/MPL/
-//
-// Software distributed under the License is distributed on an "AS IS" basis,
-// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
-// for the specific language governing rights and limitations under the
-// License.
-//
-// The Original Code is the Public Suffix List.
-//
-// The Initial Developer of the Original Code is
-// Jo Hermans <jo.hermans@gmail.com>.
-// Portions created by the Initial Developer are Copyright (C) 2007
-// the Initial Developer. All Rights Reserved.
-//
-// Contributor(s):
-// Ruben Arakelyan <ruben@wackomenace.co.uk>
-// Gervase Markham <gerv@gerv.net>
-// Pamela Greene <pamg.bugs@gmail.com>
-// David Triendl <david@triendl.name>
-// Jothan Frakes <jothan@gmail.com>
-// The kind representatives of many TLD registries
-//
-// Alternatively, the contents of this file may be used under the terms of
-// either the GNU General Public License Version 2 or later (the "GPL"), or
-// the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
-// in which case the provisions of the GPL or the LGPL are applicable instead
-// of those above. If you wish to allow use of your version of this file only
-// under the terms of either the GPL or the LGPL, and not to allow others to
-// use your version of this file under the terms of the MPL, indicate your
-// decision by deleting the provisions above and replace them with the notice
-// and other provisions required by the GPL or the LGPL. If you do not delete
-// the provisions above, a recipient may use your version of this file under
-// the terms of any one of the MPL, the GPL or the LGPL.
-//
-
-#ifndef QURLTLD_P_H
-#define QURLTLD_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists for the convenience
-// of the Network Access and Core framework. This header file may change from
-// version to version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtNetwork/private/qtnetworkglobal_p.h>
-
-QT_BEGIN_NAMESPACE
-
-// note to maintainer:
-// this file should be updated before each release ->
-// for instructions see the program at
-// util/corelib/qurl-generateTLDs/
-
-static const quint16 tldCount = 8853;
-// After the tldCount "real" entries in tldIndices, include a final entry
-// that records the sum of the lengths of all the chunks, i.e. the index
-// just past the end of tldChunks.
-static constexpr quint32 tldIndices[tldCount + 1] = {
-0,
-7,
-7,
-7,
-7,
-7,
-7,
-7,
-7,
-14,
-14,
-14,
-14,
-37,
-55,
-89,
-120,
-120,
-120,
-120,
-127,
-137,
-143,
-152,
-169,
-176,
-209,
-226,
-226,
-235,
-260,
-260,
-260,
-260,
-260,
-260,
-260,
-260,
-260,
-260,
-271,
-279,
-296,
-306,
-306,
-306,
-323,
-323,
-338,
-350,
-350,
-433,
-464,
-479,
-479,
-479,
-485,
-509,
-528,
-564,
-583,
-604,
-604,
-616,
-624,
-624,
-637,
-637,
-637,
-644,
-650,
-670,
-683,
-714,
-730,
-730,
-739,
-754,
-767,
-767,
-784,
-784,
-808,
-808,
-826,
-826,
-833,
-833,
-852,
-879,
-897,
-897,
-906,
-906,
-933,
-933,
-933,
-933,
-941,
-941,
-941,
-954,
-960,
-960,
-960,
-966,
-985,
-985,
-1020,
-1020,
-1045,
-1045,
-1045,
-1076,
-1076,
-1088,
-1088,
-1088,
-1088,
-1122,
-1151,
-1157,
-1157,
-1157,
-1157,
-1179,
-1209,
-1209,
-1226,
-1260,
-1267,
-1267,
-1276,
-1276,
-1290,
-1298,
-1330,
-1341,
-1363,
-1363,
-1387,
-1416,
-1434,
-1452,
-1464,
-1496,
-1513,
-1539,
-1539,
-1539,
-1556,
-1556,
-1556,
-1565,
-1591,
-1602,
-1616,
-1616,
-1620,
-1629,
-1641,
-1670,
-1670,
-1670,
-1686,
-1716,
-1746,
-1770,
-1770,
-1787,
-1794,
-1803,
-1803,
-1803,
-1826,
-1832,
-1858,
-1858,
-1881,
-1881,
-1881,
-1881,
-1889,
-1907,
-1907,
-1907,
-1919,
-1931,
-1940,
-1949,
-1949,
-1969,
-1969,
-2007,
-2007,
-2007,
-2011,
-2028,
-2035,
-2045,
-2052,
-2058,
-2064,
-2064,
-2092,
-2110,
-2124,
-2135,
-2135,
-2144,
-2157,
-2173,
-2173,
-2173,
-2213,
-2273,
-2283,
-2309,
-2309,
-2343,
-2364,
-2372,
-2388,
-2402,
-2412,
-2420,
-2437,
-2465,
-2470,
-2505,
-2524,
-2534,
-2534,
-2548,
-2559,
-2569,
-2569,
-2576,
-2581,
-2592,
-2605,
-2617,
-2639,
-2646,
-2646,
-2660,
-2702,
-2735,
-2735,
-2754,
-2754,
-2754,
-2754,
-2754,
-2754,
-2766,
-2772,
-2772,
-2772,
-2779,
-2779,
-2792,
-2817,
-2835,
-2845,
-2864,
-2875,
-2891,
-2891,
-2898,
-2898,
-2920,
-2920,
-2920,
-2928,
-2928,
-2944,
-2944,
-2967,
-2967,
-2983,
-3008,
-3008,
-3008,
-3028,
-3062,
-3101,
-3110,
-3121,
-3121,
-3140,
-3144,
-3160,
-3164,
-3164,
-3221,
-3221,
-3228,
-3248,
-3285,
-3285,
-3306,
-3326,
-3337,
-3337,
-3337,
-3378,
-3412,
-3429,
-3429,
-3461,
-3461,
-3461,
-3461,
-3461,
-3472,
-3503,
-3516,
-3516,
-3516,
-3529,
-3539,
-3592,
-3604,
-3611,
-3611,
-3611,
-3633,
-3633,
-3652,
-3659,
-3659,
-3663,
-3670,
-3670,
-3670,
-3698,
-3698,
-3704,
-3733,
-3733,
-3773,
-3785,
-3802,
-3802,
-3829,
-3849,
-3867,
-3888,
-3901,
-3901,
-3901,
-3901,
-3917,
-3917,
-3917,
-3917,
-3917,
-3931,
-3931,
-3951,
-3951,
-3961,
-3970,
-3970,
-3970,
-4002,
-4002,
-4052,
-4052,
-4052,
-4052,
-4064,
-4064,
-4094,
-4116,
-4116,
-4116,
-4116,
-4116,
-4141,
-4160,
-4160,
-4160,
-4191,
-4214,
-4224,
-4232,
-4242,
-4246,
-4246,
-4251,
-4278,
-4282,
-4292,
-4292,
-4300,
-4300,
-4300,
-4319,
-4319,
-4319,
-4319,
-4319,
-4319,
-4338,
-4357,
-4357,
-4357,
-4369,
-4369,
-4392,
-4392,
-4398,
-4398,
-4402,
-4402,
-4411,
-4411,
-4443,
-4443,
-4443,
-4453,
-4453,
-4464,
-4502,
-4524,
-4524,
-4524,
-4524,
-4524,
-4554,
-4562,
-4573,
-4573,
-4579,
-4583,
-4583,
-4583,
-4612,
-4628,
-4647,
-4657,
-4668,
-4693,
-4693,
-4727,
-4739,
-4763,
-4763,
-4779,
-4783,
-4787,
-4787,
-4802,
-4802,
-4814,
-4814,
-4814,
-4814,
-4826,
-4834,
-4894,
-4894,
-4928,
-4928,
-4946,
-4960,
-4968,
-4972,
-4972,
-4972,
-4991,
-4991,
-4991,
-5011,
-5029,
-5055,
-5077,
-5077,
-5077,
-5077,
-5077,
-5077,
-5077,
-5121,
-5121,
-5126,
-5126,
-5163,
-5174,
-5174,
-5174,
-5181,
-5181,
-5188,
-5188,
-5188,
-5205,
-5213,
-5235,
-5235,
-5242,
-5242,
-5242,
-5242,
-5249,
-5256,
-5263,
-5271,
-5271,
-5305,
-5305,
-5342,
-5342,
-5374,
-5400,
-5467,
-5471,
-5493,
-5493,
-5517,
-5517,
-5539,
-5578,
-5578,
-5586,
-5594,
-5594,
-5594,
-5594,
-5623,
-5640,
-5649,
-5662,
-5679,
-5703,
-5733,
-5738,
-5738,
-5769,
-5769,
-5819,
-5832,
-5849,
-5849,
-5875,
-5909,
-5909,
-5914,
-5921,
-5921,
-5921,
-5936,
-5944,
-5952,
-5952,
-5959,
-5959,
-5978,
-5978,
-6025,
-6031,
-6055,
-6055,
-6066,
-6066,
-6066,
-6093,
-6105,
-6105,
-6105,
-6111,
-6144,
-6144,
-6181,
-6192,
-6201,
-6231,
-6231,
-6238,
-6266,
-6277,
-6287,
-6287,
-6305,
-6331,
-6338,
-6338,
-6338,
-6338,
-6345,
-6345,
-6345,
-6352,
-6371,
-6371,
-6379,
-6379,
-6379,
-6379,
-6404,
-6422,
-6457,
-6457,
-6475,
-6482,
-6489,
-6489,
-6528,
-6537,
-6552,
-6562,
-6580,
-6580,
-6586,
-6593,
-6598,
-6598,
-6622,
-6638,
-6683,
-6725,
-6725,
-6725,
-6725,
-6725,
-6748,
-6748,
-6763,
-6774,
-6788,
-6800,
-6800,
-6815,
-6856,
-6863,
-6916,
-6958,
-6967,
-6967,
-6976,
-6976,
-7025,
-7025,
-7025,
-7046,
-7053,
-7061,
-7068,
-7104,
-7104,
-7114,
-7114,
-7124,
-7124,
-7124,
-7146,
-7146,
-7146,
-7166,
-7166,
-7166,
-7192,
-7192,
-7202,
-7215,
-7228,
-7235,
-7264,
-7274,
-7278,
-7278,
-7278,
-7278,
-7298,
-7316,
-7316,
-7334,
-7347,
-7364,
-7369,
-7400,
-7400,
-7400,
-7400,
-7412,
-7442,
-7466,
-7489,
-7489,
-7498,
-7554,
-7568,
-7572,
-7572,
-7572,
-7572,
-7572,
-7600,
-7600,
-7626,
-7641,
-7641,
-7688,
-7722,
-7755,
-7782,
-7789,
-7827,
-7857,
-7878,
-7885,
-7892,
-7892,
-7910,
-7910,
-7931,
-7931,
-7974,
-7990,
-7990,
-7990,
-7990,
-7997,
-8005,
-8011,
-8022,
-8030,
-8030,
-8030,
-8040,
-8064,
-8105,
-8146,
-8181,
-8219,
-8254,
-8261,
-8283,
-8283,
-8283,
-8325,
-8342,
-8342,
-8366,
-8391,
-8428,
-8428,
-8428,
-8439,
-8451,
-8451,
-8466,
-8473,
-8504,
-8520,
-8524,
-8533,
-8533,
-8553,
-8553,
-8575,
-8575,
-8583,
-8583,
-8608,
-8622,
-8635,
-8645,
-8645,
-8675,
-8702,
-8702,
-8702,
-8707,
-8737,
-8737,
-8767,
-8790,
-8790,
-8829,
-8829,
-8836,
-8836,
-8866,
-8883,
-8883,
-8891,
-8891,
-8928,
-8941,
-8941,
-8949,
-8949,
-8967,
-8967,
-8973,
-8988,
-9007,
-9013,
-9013,
-9013,
-9050,
-9083,
-9083,
-9083,
-9090,
-9104,
-9129,
-9173,
-9173,
-9204,
-9204,
-9217,
-9217,
-9233,
-9255,
-9265,
-9265,
-9272,
-9314,
-9322,
-9334,
-9365,
-9385,
-9394,
-9394,
-9402,
-9421,
-9421,
-9428,
-9428,
-9428,
-9439,
-9446,
-9452,
-9452,
-9452,
-9452,
-9476,
-9476,
-9484,
-9503,
-9503,
-9531,
-9531,
-9537,
-9553,
-9578,
-9578,
-9611,
-9611,
-9634,
-9651,
-9658,
-9658,
-9658,
-9658,
-9675,
-9707,
-9707,
-9707,
-9707,
-9732,
-9732,
-9732,
-9764,
-9773,
-9805,
-9805,
-9841,
-9856,
-9856,
-9864,
-9879,
-9894,
-9931,
-9972,
-9998,
-10016,
-10033,
-10033,
-10033,
-10033,
-10043,
-10043,
-10082,
-10092,
-10092,
-10118,
-10125,
-10125,
-10150,
-10150,
-10157,
-10175,
-10191,
-10209,
-10219,
-10289,
-10318,
-10336,
-10343,
-10350,
-10361,
-10361,
-10383,
-10401,
-10419,
-10419,
-10419,
-10432,
-10450,
-10454,
-10454,
-10454,
-10492,
-10492,
-10498,
-10498,
-10502,
-10541,
-10561,
-10575,
-10575,
-10575,
-10611,
-10611,
-10621,
-10621,
-10688,
-10695,
-10695,
-10699,
-10731,
-10731,
-10751,
-10764,
-10796,
-10872,
-10898,
-10931,
-10931,
-10959,
-10959,
-10964,
-10973,
-11014,
-11024,
-11064,
-11064,
-11064,
-11064,
-11097,
-11111,
-11125,
-11193,
-11193,
-11213,
-11224,
-11224,
-11224,
-11224,
-11248,
-11266,
-11305,
-11305,
-11321,
-11339,
-11339,
-11339,
-11339,
-11339,
-11339,
-11339,
-11339,
-11355,
-11404,
-11423,
-11430,
-11430,
-11430,
-11435,
-11448,
-11457,
-11457,
-11469,
-11469,
-11469,
-11494,
-11494,
-11500,
-11516,
-11524,
-11533,
-11554,
-11554,
-11560,
-11587,
-11595,
-11595,
-11629,
-11639,
-11652,
-11652,
-11652,
-11674,
-11684,
-11684,
-11684,
-11684,
-11745,
-11755,
-11774,
-11778,
-11782,
-11782,
-11782,
-11804,
-11843,
-11843,
-11854,
-11874,
-11886,
-11904,
-11919,
-11919,
-11919,
-11929,
-11938,
-11953,
-11997,
-12045,
-12057,
-12057,
-12057,
-12081,
-12104,
-12110,
-12120,
-12120,
-12141,
-12141,
-12182,
-12234,
-12234,
-12254,
-12254,
-12280,
-12299,
-12299,
-12299,
-12311,
-12311,
-12334,
-12334,
-12334,
-12347,
-12347,
-12374,
-12374,
-12421,
-12434,
-12451,
-12451,
-12465,
-12465,
-12472,
-12472,
-12492,
-12498,
-12498,
-12517,
-12522,
-12535,
-12535,
-12535,
-12545,
-12545,
-12569,
-12569,
-12569,
-12588,
-12598,
-12598,
-12615,
-12643,
-12643,
-12664,
-12719,
-12719,
-12738,
-12738,
-12750,
-12759,
-12780,
-12780,
-12780,
-12780,
-12780,
-12780,
-12780,
-12785,
-12785,
-12785,
-12800,
-12836,
-12853,
-12853,
-12869,
-12881,
-12924,
-12924,
-12934,
-12946,
-12946,
-12962,
-12976,
-12976,
-12976,
-12985,
-13013,
-13023,
-13023,
-13042,
-13042,
-13042,
-13058,
-13092,
-13120,
-13120,
-13127,
-13138,
-13138,
-13138,
-13138,
-13153,
-13169,
-13169,
-13189,
-13189,
-13189,
-13197,
-13239,
-13239,
-13256,
-13285,
-13320,
-13334,
-13334,
-13334,
-13359,
-13370,
-13392,
-13425,
-13425,
-13437,
-13437,
-13458,
-13487,
-13515,
-13515,
-13525,
-13525,
-13574,
-13582,
-13603,
-13603,
-13633,
-13633,
-13649,
-13689,
-13696,
-13707,
-13730,
-13730,
-13749,
-13769,
-13791,
-13797,
-13807,
-13807,
-13816,
-13836,
-13850,
-13872,
-13872,
-13872,
-13886,
-13886,
-13886,
-13901,
-13923,
-13933,
-13933,
-13954,
-13954,
-13954,
-14017,
-14032,
-14032,
-14049,
-14068,
-14079,
-14079,
-14079,
-14100,
-14100,
-14109,
-14125,
-14125,
-14155,
-14168,
-14180,
-14186,
-14190,
-14190,
-14201,
-14201,
-14201,
-14201,
-14219,
-14236,
-14266,
-14266,
-14305,
-14359,
-14359,
-14359,
-14382,
-14410,
-14410,
-14419,
-14435,
-14435,
-14459,
-14469,
-14479,
-14479,
-14479,
-14513,
-14513,
-14541,
-14556,
-14566,
-14573,
-14573,
-14592,
-14602,
-14602,
-14624,
-14624,
-14634,
-14642,
-14642,
-14642,
-14642,
-14642,
-14642,
-14654,
-14654,
-14654,
-14664,
-14664,
-14670,
-14670,
-14684,
-14684,
-14684,
-14690,
-14690,
-14690,
-14699,
-14699,
-14699,
-14699,
-14699,
-14699,
-14699,
-14733,
-14795,
-14795,
-14804,
-14814,
-14846,
-14881,
-14891,
-14910,
-14929,
-14940,
-14998,
-14998,
-14998,
-14998,
-14998,
-15014,
-15037,
-15059,
-15085,
-15114,
-15135,
-15135,
-15135,
-15163,
-15163,
-15183,
-15183,
-15200,
-15200,
-15209,
-15230,
-15230,
-15230,
-15230,
-15241,
-15241,
-15259,
-15295,
-15311,
-15329,
-15329,
-15329,
-15348,
-15348,
-15374,
-15379,
-15392,
-15392,
-15392,
-15405,
-15415,
-15425,
-15425,
-15425,
-15443,
-15443,
-15450,
-15467,
-15467,
-15467,
-15486,
-15486,
-15502,
-15502,
-15520,
-15532,
-15532,
-15546,
-15546,
-15558,
-15565,
-15575,
-15575,
-15575,
-15575,
-15575,
-15603,
-15603,
-15612,
-15612,
-15645,
-15666,
-15677,
-15677,
-15686,
-15696,
-15696,
-15706,
-15706,
-15706,
-15734,
-15734,
-15768,
-15784,
-15800,
-15800,
-15800,
-15837,
-15837,
-15837,
-15844,
-15860,
-15869,
-15876,
-15890,
-15890,
-15900,
-15938,
-15957,
-15989,
-15989,
-15989,
-15995,
-15995,
-16001,
-16001,
-16057,
-16069,
-16069,
-16081,
-16097,
-16109,
-16113,
-16113,
-16118,
-16133,
-16148,
-16163,
-16163,
-16163,
-16178,
-16203,
-16203,
-16214,
-16214,
-16234,
-16251,
-16251,
-16274,
-16292,
-16311,
-16311,
-16311,
-16311,
-16311,
-16311,
-16339,
-16339,
-16339,
-16385,
-16385,
-16385,
-16394,
-16394,
-16394,
-16394,
-16414,
-16428,
-16428,
-16445,
-16463,
-16463,
-16469,
-16469,
-16469,
-16469,
-16500,
-16500,
-16527,
-16581,
-16581,
-16601,
-16601,
-16601,
-16636,
-16643,
-16665,
-16703,
-16703,
-16714,
-16742,
-16764,
-16764,
-16764,
-16764,
-16783,
-16793,
-16803,
-16818,
-16822,
-16827,
-16870,
-16890,
-16894,
-16903,
-16903,
-16903,
-16970,
-16988,
-16988,
-17004,
-17019,
-17023,
-17023,
-17041,
-17045,
-17061,
-17087,
-17087,
-17109,
-17109,
-17109,
-17138,
-17149,
-17149,
-17149,
-17155,
-17165,
-17165,
-17174,
-17174,
-17188,
-17211,
-17227,
-17249,
-17264,
-17289,
-17311,
-17352,
-17352,
-17363,
-17373,
-17373,
-17373,
-17384,
-17415,
-17431,
-17450,
-17462,
-17489,
-17489,
-17508,
-17528,
-17540,
-17540,
-17550,
-17587,
-17587,
-17587,
-17587,
-17587,
-17587,
-17593,
-17605,
-17605,
-17609,
-17639,
-17639,
-17644,
-17644,
-17659,
-17678,
-17678,
-17690,
-17690,
-17701,
-17707,
-17746,
-17763,
-17763,
-17763,
-17763,
-17776,
-17776,
-17787,
-17795,
-17795,
-17812,
-17812,
-17818,
-17824,
-17830,
-17850,
-17850,
-17850,
-17869,
-17897,
-17915,
-17934,
-17953,
-17969,
-17995,
-17995,
-17995,
-17995,
-17995,
-18022,
-18048,
-18048,
-18048,
-18076,
-18076,
-18082,
-18091,
-18109,
-18126,
-18126,
-18159,
-18166,
-18166,
-18177,
-18206,
-18206,
-18206,
-18253,
-18273,
-18273,
-18273,
-18273,
-18273,
-18291,
-18291,
-18291,
-18302,
-18302,
-18313,
-18339,
-18339,
-18346,
-18354,
-18354,
-18372,
-18382,
-18382,
-18382,
-18393,
-18393,
-18393,
-18411,
-18411,
-18417,
-18417,
-18436,
-18436,
-18436,
-18444,
-18462,
-18462,
-18462,
-18462,
-18484,
-18484,
-18484,
-18484,
-18484,
-18484,
-18510,
-18526,
-18530,
-18548,
-18548,
-18548,
-18560,
-18560,
-18588,
-18588,
-18614,
-18614,
-18614,
-18635,
-18635,
-18667,
-18670,
-18673,
-18676,
-18695,
-18695,
-18714,
-18730,
-18747,
-18750,
-18753,
-18753,
-18756,
-18760,
-18766,
-18804,
-18807,
-18833,
-18846,
-18862,
-18868,
-18902,
-18928,
-18950,
-18966,
-18966,
-19003,
-19006,
-19014,
-19014,
-19017,
-19033,
-19078,
-19084,
-19103,
-19125,
-19131,
-19134,
-19160,
-19180,
-19202,
-19224,
-19242,
-19258,
-19261,
-19272,
-19285,
-19306,
-19306,
-19306,
-19323,
-19343,
-19413,
-19416,
-19443,
-19449,
-19452,
-19452,
-19462,
-19462,
-19489,
-19500,
-19514,
-19523,
-19550,
-19550,
-19569,
-19587,
-19597,
-19597,
-19608,
-19611,
-19634,
-19655,
-19673,
-19673,
-19673,
-19718,
-19729,
-19729,
-19777,
-19791,
-19794,
-19873,
-19897,
-19897,
-19910,
-19926,
-19945,
-19965,
-19986,
-19986,
-20002,
-20006,
-20052,
-20058,
-20063,
-20117,
-20145,
-20148,
-20151,
-20181,
-20184,
-20184,
-20184,
-20193,
-20196,
-20199,
-20218,
-20221,
-20244,
-20252,
-20255,
-20258,
-20261,
-20261,
-20264,
-20299,
-20330,
-20330,
-20333,
-20338,
-20351,
-20354,
-20371,
-20371,
-20379,
-20389,
-20432,
-20438,
-20444,
-20463,
-20463,
-20463,
-20476,
-20498,
-20498,
-20501,
-20504,
-20507,
-20541,
-20541,
-20544,
-20560,
-20579,
-20582,
-20605,
-20638,
-20644,
-20650,
-20667,
-20685,
-20704,
-20718,
-20718,
-20752,
-20755,
-20763,
-20777,
-20787,
-20787,
-20833,
-20836,
-20836,
-20850,
-20850,
-20870,
-20887,
-20912,
-20912,
-20915,
-20932,
-20947,
-20950,
-20953,
-20967,
-20970,
-20970,
-20970,
-21000,
-21003,
-21003,
-21009,
-21012,
-21015,
-21023,
-21041,
-21041,
-21041,
-21059,
-21062,
-21083,
-21098,
-21110,
-21116,
-21129,
-21132,
-21135,
-21150,
-21150,
-21164,
-21172,
-21188,
-21191,
-21216,
-21250,
-21263,
-21266,
-21281,
-21312,
-21324,
-21330,
-21370,
-21386,
-21429,
-21432,
-21442,
-21452,
-21459,
-21466,
-21469,
-21469,
-21492,
-21495,
-21495,
-21514,
-21517,
-21533,
-21553,
-21573,
-21581,
-21596,
-21622,
-21631,
-21651,
-21663,
-21663,
-21751,
-21754,
-21754,
-21770,
-21780,
-21802,
-21842,
-21868,
-21893,
-21916,
-21916,
-21919,
-21922,
-21925,
-21940,
-21947,
-21954,
-21957,
-21991,
-21999,
-22028,
-22028,
-22042,
-22045,
-22062,
-22107,
-22152,
-22170,
-22170,
-22196,
-22209,
-22209,
-22209,
-22222,
-22238,
-22250,
-22257,
-22292,
-22300,
-22300,
-22320,
-22326,
-22331,
-22340,
-22340,
-22354,
-22376,
-22390,
-22390,
-22393,
-22401,
-22427,
-22448,
-22454,
-22454,
-22460,
-22463,
-22466,
-22493,
-22496,
-22499,
-22508,
-22541,
-22571,
-22577,
-22586,
-22589,
-22626,
-22644,
-22651,
-22665,
-22681,
-22691,
-22722,
-22753,
-22770,
-22781,
-22784,
-22787,
-22811,
-22841,
-22844,
-22862,
-22862,
-22881,
-22897,
-22900,
-22906,
-22906,
-22906,
-22919,
-22941,
-22959,
-22990,
-23011,
-23011,
-23021,
-23024,
-23035,
-23055,
-23055,
-23058,
-23058,
-23061,
-23061,
-23107,
-23110,
-23133,
-23148,
-23155,
-23162,
-23176,
-23199,
-23199,
-23199,
-23199,
-23199,
-23263,
-23270,
-23275,
-23280,
-23280,
-23280,
-23292,
-23292,
-23292,
-23292,
-23329,
-23344,
-23372,
-23372,
-23375,
-23375,
-23375,
-23379,
-23389,
-23389,
-23394,
-23394,
-23428,
-23433,
-23477,
-23477,
-23477,
-23477,
-23495,
-23505,
-23505,
-23510,
-23526,
-23549,
-23568,
-23568,
-23568,
-23579,
-23579,
-23579,
-23579,
-23605,
-23605,
-23605,
-23605,
-23633,
-23655,
-23675,
-23691,
-23706,
-23706,
-23713,
-23713,
-23727,
-23752,
-23767,
-23789,
-23793,
-23793,
-23793,
-23820,
-23820,
-23820,
-23834,
-23834,
-23834,
-23837,
-23837,
-23837,
-23856,
-23856,
-23856,
-23871,
-23910,
-23927,
-23927,
-23933,
-23957,
-23983,
-23994,
-24022,
-24027,
-24051,
-24051,
-24061,
-24061,
-24061,
-24092,
-24097,
-24122,
-24127,
-24144,
-24158,
-24194,
-24204,
-24211,
-24232,
-24256,
-24256,
-24266,
-24266,
-24266,
-24310,
-24310,
-24381,
-24381,
-24381,
-24408,
-24408,
-24424,
-24424,
-24443,
-24443,
-24484,
-24484,
-24484,
-24499,
-24499,
-24499,
-24517,
-24517,
-24517,
-24540,
-24554,
-24562,
-24562,
-24617,
-24617,
-24625,
-24625,
-24630,
-24647,
-24647,
-24657,
-24674,
-24674,
-24674,
-24674,
-24674,
-24674,
-24685,
-24685,
-24685,
-24685,
-24685,
-24697,
-24697,
-24705,
-24723,
-24737,
-24768,
-24768,
-24802,
-24819,
-24831,
-24858,
-24858,
-24858,
-24910,
-24921,
-24941,
-24941,
-24968,
-24968,
-24968,
-24968,
-24981,
-24981,
-24981,
-24995,
-25034,
-25049,
-25054,
-25090,
-25096,
-25109,
-25109,
-25126,
-25126,
-25130,
-25155,
-25161,
-25166,
-25184,
-25216,
-25239,
-25288,
-25308,
-25321,
-25356,
-25375,
-25388,
-25392,
-25392,
-25407,
-25467,
-25515,
-25569,
-25590,
-25605,
-25622,
-25640,
-25658,
-25658,
-25689,
-25689,
-25689,
-25689,
-25700,
-25700,
-25700,
-25700,
-25710,
-25710,
-25710,
-25710,
-25723,
-25772,
-25786,
-25799,
-25822,
-25858,
-25858,
-25858,
-25876,
-25887,
-25904,
-25904,
-25904,
-25919,
-25937,
-25937,
-25944,
-25951,
-25958,
-25974,
-25996,
-26012,
-26026,
-26049,
-26056,
-26068,
-26098,
-26105,
-26125,
-26185,
-26215,
-26215,
-26238,
-26238,
-26238,
-26245,
-26252,
-26277,
-26281,
-26281,
-26288,
-26313,
-26320,
-26320,
-26320,
-26327,
-26334,
-26341,
-26341,
-26341,
-26348,
-26387,
-26398,
-26405,
-26405,
-26420,
-26455,
-26467,
-26525,
-26562,
-26570,
-26570,
-26570,
-26584,
-26653,
-26653,
-26697,
-26710,
-26739,
-26739,
-26755,
-26767,
-26792,
-26832,
-26849,
-26849,
-26849,
-26866,
-26873,
-26926,
-26933,
-26933,
-26975,
-26975,
-26975,
-27013,
-27035,
-27035,
-27053,
-27053,
-27074,
-27106,
-27106,
-27106,
-27113,
-27120,
-27120,
-27120,
-27120,
-27171,
-27171,
-27195,
-27205,
-27205,
-27220,
-27228,
-27235,
-27247,
-27260,
-27290,
-27296,
-27296,
-27303,
-27303,
-27310,
-27317,
-27364,
-27381,
-27381,
-27400,
-27414,
-27447,
-27447,
-27454,
-27472,
-27479,
-27487,
-27500,
-27529,
-27541,
-27553,
-27563,
-27586,
-27608,
-27615,
-27615,
-27615,
-27635,
-27635,
-27635,
-27652,
-27690,
-27690,
-27697,
-27713,
-27713,
-27713,
-27717,
-27736,
-27761,
-27773,
-27780,
-27822,
-27838,
-27838,
-27861,
-27891,
-27914,
-27921,
-27928,
-27950,
-27987,
-28010,
-28025,
-28025,
-28038,
-28038,
-28064,
-28084,
-28084,
-28132,
-28132,
-28132,
-28139,
-28146,
-28160,
-28160,
-28160,
-28167,
-28187,
-28216,
-28241,
-28241,
-28241,
-28248,
-28255,
-28267,
-28274,
-28314,
-28339,
-28356,
-28363,
-28397,
-28397,
-28404,
-28404,
-28446,
-28453,
-28473,
-28473,
-28488,
-28499,
-28499,
-28518,
-28531,
-28575,
-28593,
-28612,
-28619,
-28635,
-28655,
-28676,
-28687,
-28687,
-28694,
-28768,
-28768,
-28789,
-28809,
-28831,
-28862,
-28892,
-28939,
-28964,
-28977,
-29003,
-29017,
-29024,
-29056,
-29101,
-29109,
-29127,
-29127,
-29141,
-29165,
-29202,
-29202,
-29209,
-29209,
-29222,
-29228,
-29228,
-29228,
-29235,
-29260,
-29267,
-29304,
-29317,
-29350,
-29362,
-29362,
-29362,
-29369,
-29392,
-29411,
-29417,
-29424,
-29437,
-29437,
-29463,
-29463,
-29463,
-29492,
-29499,
-29515,
-29542,
-29542,
-29556,
-29582,
-29599,
-29606,
-29620,
-29620,
-29620,
-29652,
-29652,
-29659,
-29659,
-29665,
-29665,
-29694,
-29694,
-29704,
-29704,
-29704,
-29719,
-29719,
-29747,
-29771,
-29781,
-29794,
-29794,
-29794,
-29794,
-29794,
-29811,
-29818,
-29818,
-29849,
-29849,
-29871,
-29905,
-29926,
-29940,
-29954,
-29954,
-29968,
-29975,
-29991,
-30001,
-30001,
-30008,
-30008,
-30015,
-30022,
-30051,
-30060,
-30078,
-30085,
-30127,
-30127,
-30166,
-30166,
-30166,
-30173,
-30187,
-30196,
-30196,
-30218,
-30225,
-30270,
-30289,
-30296,
-30303,
-30316,
-30328,
-30328,
-30382,
-30396,
-30396,
-30412,
-30412,
-30419,
-30452,
-30452,
-30464,
-30482,
-30494,
-30498,
-30505,
-30541,
-30552,
-30567,
-30567,
-30573,
-30573,
-30600,
-30607,
-30607,
-30653,
-30653,
-30669,
-30751,
-30751,
-30751,
-30751,
-30771,
-30776,
-30783,
-30789,
-30831,
-30848,
-30902,
-30934,
-30934,
-30998,
-31017,
-31017,
-31022,
-31022,
-31022,
-31022,
-31083,
-31116,
-31132,
-31165,
-31165,
-31171,
-31171,
-31175,
-31203,
-31203,
-31203,
-31213,
-31246,
-31251,
-31260,
-31282,
-31282,
-31282,
-31312,
-31341,
-31341,
-31341,
-31358,
-31358,
-31380,
-31395,
-31411,
-31429,
-31429,
-31436,
-31443,
-31443,
-31443,
-31492,
-31510,
-31510,
-31526,
-31526,
-31544,
-31544,
-31544,
-31566,
-31573,
-31573,
-31578,
-31578,
-31609,
-31658,
-31658,
-31664,
-31664,
-31664,
-31694,
-31706,
-31706,
-31741,
-31741,
-31768,
-31781,
-31781,
-31794,
-31794,
-31822,
-31822,
-31832,
-31832,
-31832,
-31832,
-31832,
-31848,
-31848,
-31848,
-31871,
-31881,
-31903,
-31903,
-31939,
-31939,
-31949,
-31997,
-32006,
-32006,
-32006,
-32006,
-32019,
-32025,
-32063,
-32078,
-32083,
-32083,
-32099,
-32117,
-32117,
-32117,
-32127,
-32127,
-32146,
-32146,
-32164,
-32211,
-32224,
-32224,
-32297,
-32309,
-32309,
-32309,
-32346,
-32356,
-32356,
-32372,
-32385,
-32385,
-32385,
-32392,
-32401,
-32401,
-32401,
-32401,
-32410,
-32410,
-32410,
-32421,
-32434,
-32434,
-32434,
-32467,
-32467,
-32526,
-32539,
-32549,
-32557,
-32557,
-32561,
-32579,
-32612,
-32656,
-32672,
-32718,
-32735,
-32753,
-32776,
-32792,
-32799,
-32799,
-32799,
-32799,
-32813,
-32820,
-32862,
-32910,
-32922,
-32922,
-32938,
-32957,
-32965,
-32981,
-33007,
-33024,
-33040,
-33075,
-33075,
-33098,
-33098,
-33114,
-33142,
-33150,
-33159,
-33159,
-33159,
-33169,
-33188,
-33205,
-33214,
-33225,
-33225,
-33248,
-33248,
-33248,
-33248,
-33261,
-33291,
-33291,
-33291,
-33291,
-33291,
-33291,
-33299,
-33327,
-33327,
-33327,
-33342,
-33349,
-33356,
-33361,
-33367,
-33380,
-33380,
-33380,
-33380,
-33380,
-33393,
-33434,
-33434,
-33449,
-33449,
-33474,
-33487,
-33493,
-33535,
-33543,
-33543,
-33543,
-33551,
-33578,
-33585,
-33599,
-33599,
-33599,
-33609,
-33609,
-33671,
-33671,
-33671,
-33707,
-33707,
-33707,
-33713,
-33720,
-33734,
-33752,
-33752,
-33769,
-33797,
-33821,
-33830,
-33837,
-33837,
-33857,
-33857,
-33857,
-33887,
-33901,
-33901,
-33925,
-33957,
-33957,
-33957,
-33957,
-33981,
-33996,
-33996,
-33996,
-34013,
-34013,
-34026,
-34048,
-34058,
-34063,
-34108,
-34108,
-34108,
-34143,
-34143,
-34143,
-34171,
-34184,
-34197,
-34211,
-34231,
-34248,
-34269,
-34301,
-34301,
-34307,
-34307,
-34330,
-34350,
-34368,
-34395,
-34414,
-34414,
-34433,
-34443,
-34443,
-34493,
-34526,
-34536,
-34552,
-34552,
-34581,
-34592,
-34599,
-34599,
-34618,
-34623,
-34623,
-34635,
-34635,
-34650,
-34650,
-34650,
-34691,
-34691,
-34696,
-34715,
-34724,
-34724,
-34742,
-34742,
-34763,
-34770,
-34785,
-34785,
-34807,
-34807,
-34814,
-34836,
-34856,
-34884,
-34927,
-34927,
-34943,
-34943,
-34943,
-34952,
-34970,
-35006,
-35022,
-35022,
-35032,
-35071,
-35085,
-35101,
-35101,
-35107,
-35107,
-35114,
-35114,
-35114,
-35125,
-35154,
-35172,
-35192,
-35192,
-35192,
-35211,
-35211,
-35218,
-35231,
-35231,
-35231,
-35231,
-35249,
-35268,
-35268,
-35268,
-35268,
-35285,
-35285,
-35285,
-35291,
-35318,
-35336,
-35353,
-35371,
-35398,
-35406,
-35457,
-35457,
-35463,
-35494,
-35504,
-35504,
-35512,
-35512,
-35519,
-35545,
-35583,
-35601,
-35637,
-35647,
-35662,
-35686,
-35695,
-35701,
-35711,
-35715,
-35720,
-35720,
-35726,
-35726,
-35771,
-35794,
-35809,
-35809,
-35815,
-35815,
-35831,
-35843,
-35843,
-35843,
-35843,
-35843,
-35895,
-35899,
-35911,
-35915,
-35919,
-35932,
-35966,
-35978,
-35999,
-36012,
-36012,
-36012,
-36024,
-36024,
-36030,
-36045,
-36077,
-36077,
-36085,
-36101,
-36129,
-36135,
-36167,
-36167,
-36184,
-36184,
-36184,
-36184,
-36209,
-36229,
-36229,
-36244,
-36244,
-36244,
-36292,
-36317,
-36335,
-36357,
-36357,
-36361,
-36378,
-36401,
-36417,
-36417,
-36434,
-36449,
-36469,
-36481,
-36518,
-36535,
-36548,
-36561,
-36561,
-36571,
-36591,
-36618,
-36618,
-36618,
-36618,
-36618,
-36650,
-36650,
-36665,
-36675,
-36675,
-36686,
-36686,
-36700,
-36700,
-36735,
-36735,
-36735,
-36735,
-36735,
-36735,
-36735,
-36735,
-36735,
-36735,
-36735,
-36735,
-36746,
-36746,
-36746,
-36762,
-36762,
-36779,
-36824,
-36824,
-36849,
-36860,
-36860,
-36885,
-36909,
-36936,
-36993,
-36993,
-36993,
-36999,
-36999,
-37031,
-37031,
-37040,
-37054,
-37054,
-37075,
-37075,
-37101,
-37101,
-37101,
-37101,
-37111,
-37111,
-37118,
-37134,
-37153,
-37168,
-37175,
-37182,
-37203,
-37221,
-37247,
-37267,
-37267,
-37287,
-37315,
-37315,
-37346,
-37359,
-37373,
-37373,
-37386,
-37405,
-37420,
-37431,
-37478,
-37478,
-37484,
-37493,
-37540,
-37550,
-37550,
-37550,
-37560,
-37583,
-37599,
-37608,
-37615,
-37615,
-37615,
-37639,
-37690,
-37690,
-37690,
-37706,
-37716,
-37716,
-37746,
-37746,
-37746,
-37768,
-37768,
-37768,
-37791,
-37791,
-37795,
-37805,
-37827,
-37827,
-37827,
-37836,
-37852,
-37871,
-37871,
-37871,
-37887,
-37887,
-37893,
-37893,
-37893,
-37897,
-37919,
-37939,
-37963,
-37974,
-37974,
-37974,
-38001,
-38025,
-38043,
-38066,
-38089,
-38106,
-38146,
-38146,
-38178,
-38194,
-38194,
-38206,
-38206,
-38206,
-38227,
-38254,
-38268,
-38268,
-38268,
-38299,
-38320,
-38320,
-38320,
-38340,
-38340,
-38365,
-38399,
-38399,
-38399,
-38419,
-38438,
-38438,
-38454,
-38458,
-38474,
-38474,
-38491,
-38519,
-38519,
-38519,
-38541,
-38541,
-38552,
-38567,
-38572,
-38579,
-38583,
-38609,
-38650,
-38650,
-38664,
-38664,
-38699,
-38699,
-38715,
-38735,
-38741,
-38741,
-38745,
-38751,
-38757,
-38776,
-38801,
-38822,
-38844,
-38870,
-38870,
-38875,
-38875,
-38875,
-38895,
-38895,
-38911,
-38925,
-38925,
-38925,
-38951,
-38961,
-38967,
-38991,
-39017,
-39033,
-39051,
-39066,
-39066,
-39066,
-39066,
-39072,
-39091,
-39141,
-39141,
-39141,
-39169,
-39205,
-39205,
-39205,
-39224,
-39231,
-39304,
-39304,
-39332,
-39376,
-39376,
-39406,
-39416,
-39449,
-39459,
-39478,
-39507,
-39531,
-39538,
-39568,
-39622,
-39646,
-39653,
-39680,
-39680,
-39690,
-39694,
-39715,
-39746,
-39746,
-39793,
-39797,
-39806,
-39806,
-39826,
-39884,
-39884,
-39884,
-39889,
-39902,
-39902,
-39911,
-39911,
-39931,
-39931,
-39931,
-39931,
-39931,
-39935,
-39951,
-39958,
-39987,
-39994,
-39994,
-39994,
-40014,
-40018,
-40038,
-40045,
-40052,
-40066,
-40066,
-40073,
-40073,
-40113,
-40120,
-40137,
-40153,
-40183,
-40229,
-40236,
-40282,
-40300,
-40319,
-40319,
-40352,
-40352,
-40352,
-40352,
-40362,
-40373,
-40394,
-40421,
-40421,
-40421,
-40433,
-40433,
-40437,
-40437,
-40455,
-40455,
-40455,
-40455,
-40469,
-40476,
-40489,
-40505,
-40512,
-40512,
-40534,
-40551,
-40569,
-40569,
-40569,
-40593,
-40603,
-40625,
-40641,
-40641,
-40641,
-40658,
-40664,
-40664,
-40673,
-40673,
-40673,
-40673,
-40673,
-40679,
-40696,
-40702,
-40702,
-40708,
-40708,
-40708,
-40708,
-40763,
-40780,
-40780,
-40804,
-40810,
-40823,
-40828,
-40828,
-40828,
-40852,
-40878,
-40892,
-40921,
-40921,
-40927,
-40927,
-40942,
-40978,
-40978,
-41013,
-41013,
-41028,
-41063,
-41079,
-41091,
-41116,
-41124,
-41138,
-41153,
-41187,
-41192,
-41192,
-41231,
-41231,
-41231,
-41244,
-41256,
-41256,
-41256,
-41261,
-41295,
-41295,
-41313,
-41338,
-41347,
-41363,
-41363,
-41389,
-41398,
-41398,
-41398,
-41398,
-41398,
-41427,
-41433,
-41447,
-41459,
-41465,
-41481,
-41519,
-41519,
-41555,
-41555,
-41576,
-41583,
-41583,
-41583,
-41583,
-41590,
-41618,
-41618,
-41640,
-41640,
-41640,
-41657,
-41657,
-41657,
-41657,
-41674,
-41687,
-41720,
-41720,
-41742,
-41785,
-41790,
-41794,
-41810,
-41817,
-41839,
-41847,
-41858,
-41858,
-41876,
-41891,
-41896,
-41914,
-41920,
-41920,
-41935,
-41957,
-42009,
-42009,
-42009,
-42009,
-42032,
-42053,
-42075,
-42075,
-42075,
-42075,
-42086,
-42090,
-42097,
-42113,
-42113,
-42154,
-42154,
-42174,
-42204,
-42208,
-42239,
-42273,
-42283,
-42301,
-42307,
-42321,
-42333,
-42345,
-42369,
-42392,
-42415,
-42415,
-42422,
-42451,
-42459,
-42459,
-42459,
-42459,
-42477,
-42477,
-42477,
-42477,
-42483,
-42505,
-42538,
-42561,
-42591,
-42591,
-42598,
-42627,
-42627,
-42650,
-42650,
-42662,
-42662,
-42720,
-42739,
-42755,
-42755,
-42761,
-42761,
-42805,
-42809,
-42817,
-42838,
-42856,
-42863,
-42863,
-42881,
-42881,
-42907,
-42915,
-42922,
-42922,
-42957,
-42957,
-42967,
-42973,
-42993,
-43025,
-43029,
-43035,
-43076,
-43076,
-43083,
-43094,
-43106,
-43106,
-43106,
-43113,
-43120,
-43120,
-43120,
-43131,
-43131,
-43141,
-43151,
-43151,
-43166,
-43181,
-43189,
-43199,
-43199,
-43214,
-43249,
-43307,
-43314,
-43321,
-43321,
-43321,
-43345,
-43388,
-43415,
-43415,
-43460,
-43460,
-43468,
-43477,
-43484,
-43559,
-43577,
-43594,
-43600,
-43609,
-43616,
-43620,
-43620,
-43632,
-43655,
-43655,
-43655,
-43668,
-43681,
-43681,
-43681,
-43688,
-43688,
-43743,
-43743,
-43764,
-43788,
-43825,
-43839,
-43860,
-43887,
-43887,
-43903,
-43921,
-43927,
-43933,
-43933,
-43933,
-43946,
-43959,
-43966,
-43972,
-43972,
-43984,
-43994,
-44007,
-44007,
-44013,
-44024,
-44024,
-44024,
-44058,
-44085,
-44125,
-44137,
-44137,
-44144,
-44144,
-44173,
-44203,
-44213,
-44213,
-44237,
-44265,
-44287,
-44317,
-44336,
-44336,
-44336,
-44349,
-44349,
-44349,
-44356,
-44356,
-44363,
-44363,
-44377,
-44383,
-44383,
-44383,
-44402,
-44416,
-44416,
-44416,
-44423,
-44423,
-44423,
-44423,
-44448,
-44481,
-44481,
-44481,
-44481,
-44510,
-44524,
-44544,
-44603,
-44603,
-44603,
-44630,
-44640,
-44652,
-44652,
-44672,
-44679,
-44679,
-44705,
-44705,
-44730,
-44747,
-44753,
-44759,
-44759,
-44759,
-44772,
-44787,
-44787,
-44810,
-44845,
-44867,
-44906,
-44928,
-44935,
-44935,
-44947,
-44961,
-44977,
-44977,
-44984,
-44984,
-44991,
-45010,
-45033,
-45033,
-45033,
-45033,
-45040,
-45076,
-45093,
-45102,
-45112,
-45112,
-45132,
-45139,
-45139,
-45151,
-45169,
-45176,
-45207,
-45240,
-45240,
-45276,
-45276,
-45295,
-45295,
-45308,
-45318,
-45325,
-45325,
-45343,
-45367,
-45371,
-45381,
-45387,
-45404,
-45415,
-45454,
-45466,
-45466,
-45466,
-45484,
-45484,
-45509,
-45515,
-45515,
-45515,
-45515,
-45515,
-45515,
-45515,
-45515,
-45515,
-45515,
-45534,
-45534,
-45541,
-45541,
-45541,
-45551,
-45551,
-45551,
-45574,
-45574,
-45590,
-45610,
-45610,
-45617,
-45653,
-45663,
-45680,
-45686,
-45686,
-45700,
-45709,
-45753,
-45774,
-45794,
-45794,
-45805,
-45812,
-45812,
-45841,
-45860,
-45860,
-45895,
-45895,
-45905,
-45939,
-45939,
-45949,
-45953,
-45984,
-45984,
-45984,
-46006,
-46035,
-46035,
-46035,
-46035,
-46056,
-46056,
-46070,
-46070,
-46070,
-46107,
-46114,
-46124,
-46124,
-46142,
-46166,
-46166,
-46181,
-46199,
-46199,
-46229,
-46266,
-46307,
-46320,
-46320,
-46320,
-46339,
-46351,
-46393,
-46406,
-46438,
-46473,
-46473,
-46481,
-46494,
-46494,
-46501,
-46501,
-46501,
-46529,
-46529,
-46529,
-46552,
-46590,
-46594,
-46615,
-46615,
-46628,
-46686,
-46709,
-46716,
-46729,
-46753,
-46775,
-46800,
-46833,
-46833,
-46833,
-46881,
-46881,
-46889,
-46902,
-46902,
-46956,
-47019,
-47069,
-47088,
-47095,
-47119,
-47119,
-47146,
-47173,
-47196,
-47196,
-47196,
-47230,
-47237,
-47243,
-47258,
-47258,
-47283,
-47316,
-47375,
-47385,
-47385,
-47385,
-47385,
-47392,
-47411,
-47411,
-47418,
-47425,
-47438,
-47445,
-47445,
-47452,
-47470,
-47470,
-47475,
-47482,
-47482,
-47494,
-47519,
-47535,
-47535,
-47561,
-47582,
-47599,
-47613,
-47643,
-47666,
-47689,
-47689,
-47729,
-47729,
-47736,
-47762,
-47783,
-47792,
-47805,
-47848,
-47848,
-47886,
-47890,
-47900,
-47909,
-47921,
-47921,
-47939,
-47948,
-47955,
-47973,
-47973,
-47973,
-47990,
-48006,
-48032,
-48055,
-48069,
-48069,
-48083,
-48083,
-48083,
-48103,
-48131,
-48131,
-48131,
-48138,
-48138,
-48150,
-48163,
-48170,
-48170,
-48170,
-48170,
-48177,
-48203,
-48203,
-48203,
-48203,
-48215,
-48215,
-48235,
-48293,
-48293,
-48309,
-48332,
-48357,
-48357,
-48364,
-48364,
-48376,
-48376,
-48376,
-48391,
-48391,
-48396,
-48406,
-48418,
-48425,
-48464,
-48480,
-48480,
-48480,
-48501,
-48517,
-48542,
-48551,
-48558,
-48558,
-48582,
-48595,
-48635,
-48642,
-48649,
-48649,
-48649,
-48658,
-48681,
-48685,
-48691,
-48709,
-48716,
-48716,
-48716,
-48727,
-48727,
-48756,
-48756,
-48756,
-48794,
-48814,
-48814,
-48821,
-48821,
-48828,
-48858,
-48864,
-48864,
-48898,
-48905,
-48905,
-48924,
-48944,
-48951,
-48958,
-48975,
-48975,
-48975,
-48982,
-48982,
-49004,
-49011,
-49018,
-49042,
-49068,
-49082,
-49082,
-49082,
-49089,
-49130,
-49153,
-49160,
-49174,
-49181,
-49188,
-49188,
-49195,
-49195,
-49202,
-49259,
-49275,
-49290,
-49321,
-49321,
-49347,
-49384,
-49391,
-49391,
-49407,
-49419,
-49433,
-49444,
-49458,
-49465,
-49476,
-49476,
-49480,
-49480,
-49480,
-49489,
-49505,
-49512,
-49512,
-49519,
-49519,
-49527,
-49527,
-49527,
-49546,
-49546,
-49546,
-49558,
-49591,
-49609,
-49609,
-49622,
-49644,
-49664,
-49669,
-49669,
-49686,
-49686,
-49710,
-49730,
-49740,
-49740,
-49747,
-49754,
-49769,
-49776,
-49776,
-49800,
-49815,
-49822,
-49844,
-49905,
-49932,
-49932,
-49932,
-49952,
-49959,
-49959,
-49982,
-49998,
-49998,
-50016,
-50016,
-50016,
-50052,
-50052,
-50064,
-50070,
-50070,
-50077,
-50077,
-50077,
-50097,
-50115,
-50130,
-50176,
-50186,
-50194,
-50209,
-50215,
-50239,
-50269,
-50318,
-50339,
-50346,
-50346,
-50360,
-50382,
-50398,
-50427,
-50449,
-50456,
-50482,
-50492,
-50499,
-50499,
-50499,
-50499,
-50506,
-50523,
-50523,
-50532,
-50557,
-50579,
-50611,
-50633,
-50640,
-50665,
-50672,
-50691,
-50708,
-50708,
-50726,
-50733,
-50733,
-50748,
-50772,
-50772,
-50779,
-50788,
-50788,
-50788,
-50795,
-50819,
-50819,
-50819,
-50819,
-50819,
-50834,
-50849,
-50856,
-50856,
-50881,
-50905,
-50914,
-50926,
-50926,
-50946,
-50959,
-50966,
-50977,
-50999,
-51034,
-51034,
-51034,
-51034,
-51034,
-51034,
-51065,
-51101,
-51101,
-51112,
-51130,
-51148,
-51166,
-51172,
-51202,
-51202,
-51236,
-51254,
-51254,
-51261,
-51282,
-51282,
-51298,
-51298,
-51310,
-51322,
-51322,
-51347,
-51347,
-51374,
-51379,
-51379,
-51379,
-51379,
-51395,
-51407,
-51414,
-51414,
-51420,
-51420,
-51439,
-51444,
-51460,
-51480,
-51498,
-51518,
-51518,
-51549,
-51565,
-51580,
-51593,
-51598,
-51615,
-51615,
-51615,
-51615,
-51637,
-51650,
-51681,
-51681,
-51709,
-51720,
-51767,
-51767,
-51786,
-51792,
-51825,
-51870,
-51876,
-51894,
-51901,
-51901,
-51908,
-51934,
-51955,
-51971,
-51971,
-51987,
-51987,
-52000,
-52000,
-52007,
-52027,
-52041,
-52041,
-52041,
-52041,
-52041,
-52041,
-52041,
-52051,
-52064,
-52064,
-52108,
-52129,
-52150,
-52150,
-52168,
-52168,
-52168,
-52168,
-52168,
-52187,
-52187,
-52194,
-52210,
-52210,
-52220,
-52220,
-52220,
-52224,
-52233,
-52253,
-52253,
-52253,
-52253,
-52253,
-52265,
-52265,
-52280,
-52287,
-52303,
-52341,
-52341,
-52353,
-52367,
-52375,
-52375,
-52388,
-52440,
-52440,
-52440,
-52471,
-52471,
-52471,
-52481,
-52499,
-52499,
-52499,
-52499,
-52545,
-52553,
-52553,
-52571,
-52571,
-52617,
-52632,
-52640,
-52660,
-52678,
-52678,
-52695,
-52705,
-52705,
-52722,
-52734,
-52734,
-52734,
-52751,
-52751,
-52771,
-52785,
-52785,
-52785,
-52803,
-52841,
-52855,
-52874,
-52884,
-52897,
-52909,
-52931,
-52958,
-52969,
-52969,
-52982,
-52982,
-52982,
-52988,
-53001,
-53001,
-53001,
-53008,
-53008,
-53020,
-53025,
-53068,
-53097,
-53128,
-53146,
-53146,
-53153,
-53199,
-53199,
-53234,
-53234,
-53252,
-53269,
-53290,
-53298,
-53308,
-53316,
-53353,
-53368,
-53368,
-53387,
-53416,
-53421,
-53438,
-53438,
-53468,
-53483,
-53496,
-53510,
-53510,
-53510,
-53510,
-53534,
-53572,
-53622,
-53622,
-53642,
-53680,
-53708,
-53723,
-53723,
-53723,
-53730,
-53746,
-53753,
-53763,
-53808,
-53815,
-53829,
-53847,
-53858,
-53873,
-53873,
-53888,
-53895,
-53915,
-53937,
-53953,
-53953,
-53960,
-53974,
-53981,
-53981,
-53981,
-53995,
-54055,
-54071,
-54079,
-54092,
-54100,
-54131,
-54145,
-54182,
-54182,
-54192,
-54199,
-54233,
-54240,
-54240,
-54250,
-54275,
-54282,
-54282,
-54316,
-54316,
-54365,
-54365,
-54389,
-54402,
-54411,
-54422,
-54436,
-54436,
-54443,
-54453,
-54453,
-54453,
-54460,
-54500,
-54517,
-54534,
-54573,
-54583,
-54594,
-54631,
-54631,
-54645,
-54645,
-54645,
-54664,
-54670,
-54680,
-54697,
-54704,
-54732,
-54732,
-54759,
-54794,
-54802,
-54816,
-54823,
-54828,
-54840,
-54862,
-54862,
-54862,
-54872,
-54911,
-54937,
-55004,
-55037,
-55048,
-55052,
-55081,
-55104,
-55111,
-55118,
-55172,
-55179,
-55218,
-55235,
-55255,
-55262,
-55268,
-55275,
-55280,
-55336,
-55343,
-55361,
-55361,
-55361,
-55373,
-55373,
-55413,
-55423,
-55423,
-55430,
-55454,
-55466,
-55466,
-55493,
-55510,
-55547,
-55547,
-55547,
-55547,
-55564,
-55564,
-55583,
-55583,
-55608,
-55615,
-55615,
-55629,
-55635,
-55651,
-55665,
-55693,
-55713,
-55713,
-55752,
-55778,
-55778,
-55786,
-55798,
-55802,
-55816,
-55826,
-55826,
-55833,
-55840,
-55851,
-55851,
-55878,
-55893,
-55903,
-55912,
-55919,
-55919,
-55939,
-55948,
-55948,
-55948,
-55955,
-55955,
-55967,
-55985,
-56013,
-56032,
-56054,
-56073,
-56073,
-56093,
-56100,
-56108,
-56115,
-56122,
-56138,
-56158,
-56158,
-56165,
-56165,
-56195,
-56195,
-56202,
-56202,
-56209,
-56228,
-56250,
-56269,
-56269,
-56283,
-56299,
-56306,
-56313,
-56353,
-56353,
-56360,
-56366,
-56383,
-56389,
-56396,
-56409,
-56433,
-56447,
-56471,
-56478,
-56508,
-56508,
-56508,
-56516,
-56516,
-56528,
-56544,
-56544,
-56544,
-56551,
-56562,
-56591,
-56591,
-56608,
-56620,
-56661,
-56661,
-56661,
-56673,
-56673,
-56690,
-56690,
-56690,
-56690,
-56697,
-56715,
-56715,
-56723,
-56751,
-56778,
-56836,
-56843,
-56843,
-56883,
-56933,
-56952,
-56956,
-56956,
-56966,
-57003,
-57057,
-57064,
-57081,
-57121,
-57121,
-57173,
-57173,
-57173,
-57196,
-57196,
-57222,
-57222,
-57222,
-57222,
-57228,
-57236,
-57269,
-57269,
-57287,
-57287,
-57322,
-57322,
-57322,
-57322,
-57322,
-57336,
-57345,
-57372,
-57384,
-57384,
-57391,
-57391,
-57415,
-57444,
-57451,
-57458,
-57492,
-57492,
-57509,
-57516,
-57525,
-57525,
-57547,
-57554,
-57574,
-57588,
-57595,
-57606,
-57606,
-57617,
-57634,
-57663,
-57667,
-57681,
-57681,
-57681,
-57696,
-57703,
-57721,
-57734,
-57745,
-57778,
-57805,
-57805,
-57812,
-57838,
-57858,
-57882,
-57882,
-57893,
-57915,
-57915,
-57915,
-57915,
-57915,
-57915,
-57934,
-57949,
-57965,
-57974,
-57974,
-57981,
-57988,
-57988,
-57995,
-58001,
-58022,
-58022,
-58067,
-58074,
-58074,
-58086,
-58086,
-58141,
-58148,
-58172,
-58172,
-58172,
-58172,
-58172,
-58190,
-58190,
-58190,
-58190,
-58190,
-58216,
-58247,
-58279,
-58294,
-58294,
-58294,
-58312,
-58322,
-58330,
-58337,
-58337,
-58337,
-58358,
-58401,
-58408,
-58408,
-58450,
-58450,
-58450,
-58450,
-58455,
-58459,
-58468,
-58492,
-58510,
-58546,
-58581,
-58588,
-58588,
-58588,
-58593,
-58613,
-58634,
-58634,
-58669,
-58702,
-58702,
-58702,
-58706,
-58706,
-58706,
-58716,
-58750,
-58768,
-58768,
-58782,
-58801,
-58812,
-58812,
-58827,
-58840,
-58847,
-58856,
-58874,
-58895,
-58909,
-58925,
-58925,
-58944,
-58964,
-58964,
-58964,
-58982,
-58982,
-58982,
-58989,
-58989,
-59000,
-59020,
-59032,
-59067,
-59067,
-59100,
-59110,
-59121,
-59141,
-59141,
-59147,
-59161,
-59161,
-59161,
-59161,
-59161,
-59171,
-59180,
-59180,
-59188,
-59221,
-59221,
-59221,
-59232,
-59263,
-59263,
-59282,
-59298,
-59305,
-59324,
-59324,
-59349,
-59349,
-59363,
-59393,
-59399,
-59399,
-59418,
-59432,
-59432,
-59445,
-59445,
-59445,
-59445,
-59445,
-59466,
-59466,
-59466,
-59466,
-59466,
-59466,
-59466,
-59483,
-59490,
-59509,
-59509,
-59509,
-59522,
-59548,
-59563,
-59574,
-59618,
-59628,
-59641,
-59647,
-59657,
-59662,
-59681,
-59681,
-59687,
-59687,
-59703,
-59710,
-59726,
-59769,
-59778,
-59778,
-59845,
-59845,
-59857,
-59857,
-59857,
-59863,
-59892,
-59935,
-59941,
-59941,
-59963,
-59981,
-59981,
-60014,
-60014,
-60056,
-60056,
-60079,
-60095,
-60117,
-60134,
-60159,
-60159,
-60173,
-60192,
-60192,
-60233,
-60233,
-60241,
-60241,
-60241,
-60272,
-60272,
-60272,
-60286,
-60298,
-60298,
-60298,
-60298,
-60298,
-60346,
-60370,
-60382,
-60402,
-60409,
-60419,
-60441,
-60441,
-60476,
-60476,
-60510,
-60548,
-60589,
-60609,
-60626,
-60636,
-60648,
-60699,
-60719,
-60719,
-60726,
-60754,
-60764,
-60790,
-60800,
-60817,
-60845,
-60845,
-60845,
-60860,
-60887,
-60906,
-60934,
-60958,
-60958,
-60982,
-60982,
-61029,
-61029,
-61029,
-61036,
-61048,
-61048,
-61066,
-61075,
-61075,
-61075,
-61086,
-61099,
-61099,
-61133,
-61133,
-61133,
-61144,
-61144,
-61144,
-61197,
-61211,
-61225,
-61245,
-61284,
-61290,
-61290,
-61290,
-61290,
-61290,
-61290,
-61290,
-61301,
-61305,
-61305,
-61312,
-61323,
-61342,
-61349,
-61349,
-61372,
-61372,
-61372,
-61372,
-61372,
-61388,
-61388,
-61388,
-61410,
-61410,
-61427,
-61476,
-61492,
-61492,
-61492,
-61492,
-61499,
-61499,
-61499,
-61499,
-61504,
-61514,
-61532,
-61532,
-61541,
-61541,
-61541,
-61541,
-61541,
-61541,
-61552,
-61574,
-61583,
-61606,
-61606,
-61611,
-61622,
-61622,
-61639,
-61647,
-61663,
-61669,
-61685,
-61685,
-61700,
-61700,
-61727,
-61780,
-61792,
-61807,
-61828,
-61828,
-61860,
-61860,
-61873,
-61873,
-61873,
-61877,
-61877,
-61889,
-61896,
-61904,
-61923,
-61933,
-61933,
-61933,
-61946,
-61959,
-61987,
-61994,
-62014,
-62022,
-62022,
-62030,
-62068,
-62068,
-62077,
-62095,
-62125,
-62125,
-62131,
-62140,
-62140,
-62177,
-62177,
-62177,
-62177,
-62177,
-62186,
-62204,
-62204,
-62204,
-62204,
-62209,
-62218,
-62218,
-62218,
-62234,
-62249,
-62249,
-62266,
-62266,
-62266,
-62266,
-62286,
-62300,
-62307,
-62350,
-62356,
-62381,
-62412,
-62429,
-62429,
-62445,
-62476,
-62489,
-62498,
-62498,
-62498,
-62513,
-62513,
-62513,
-62541,
-62553,
-62570,
-62585,
-62585,
-62598,
-62614,
-62614,
-62621,
-62621,
-62648,
-62664,
-62664,
-62671,
-62678,
-62702,
-62713,
-62734,
-62734,
-62734,
-62752,
-62765,
-62784,
-62784,
-62841,
-62848,
-62862,
-62871,
-62871,
-62896,
-62896,
-62908,
-62931,
-62940,
-62947,
-62947,
-62964,
-63017,
-63024,
-63031,
-63041,
-63041,
-63048,
-63055,
-63062,
-63078,
-63090,
-63105,
-63123,
-63130,
-63170,
-63170,
-63170,
-63177,
-63214,
-63221,
-63221,
-63221,
-63240,
-63252,
-63262,
-63269,
-63284,
-63317,
-63325,
-63332,
-63332,
-63339,
-63339,
-63364,
-63364,
-63371,
-63409,
-63409,
-63409,
-63437,
-63445,
-63445,
-63461,
-63479,
-63485,
-63495,
-63524,
-63536,
-63555,
-63630,
-63630,
-63630,
-63630,
-63637,
-63637,
-63644,
-63651,
-63651,
-63651,
-63676,
-63676,
-63703,
-63723,
-63748,
-63765,
-63780,
-63789,
-63805,
-63805,
-63805,
-63805,
-63805,
-63822,
-63836,
-63849,
-63856,
-63856,
-63856,
-63856,
-63856,
-63879,
-63898,
-63905,
-63914,
-63921,
-63934,
-63941,
-63941,
-63948,
-63968,
-63968,
-63968,
-63968,
-63985,
-64004,
-64021,
-64030,
-64030,
-64037,
-64045,
-64068,
-64068,
-64123,
-64136,
-64150,
-64213,
-64213,
-64229,
-64229,
-64229,
-64238,
-64250,
-64257,
-64264,
-64278,
-64278,
-64278,
-64285,
-64302,
-64309,
-64309,
-64340,
-64359,
-64359,
-64388,
-64388,
-64388,
-64388,
-64404,
-64423,
-64423,
-64430,
-64435,
-64445,
-64445,
-64479,
-64479,
-64492,
-64492,
-64524,
-64539,
-64566,
-64576,
-64585,
-64615,
-64622,
-64629,
-64629,
-64642,
-64658,
-64665,
-64681,
-64681,
-64681,
-64731,
-64743,
-64743,
-64795,
-64822,
-64829,
-64829,
-64841,
-64841,
-64841,
-64841,
-64863,
-64887,
-64902,
-64911,
-64926,
-64933,
-64962,
-64962,
-64969,
-64969,
-64976,
-64990,
-64990,
-65003,
-65010,
-65020,
-65020,
-65020,
-65041,
-65048,
-65055,
-65083,
-65103,
-65121,
-65135,
-65142,
-65146,
-65146,
-65173,
-65173,
-65173,
-65193,
-65193,
-65204,
-65204,
-65208,
-65208,
-65208,
-65242,
-65242,
-65261,
-65287,
-65287,
-65297,
-65316,
-65358,
-65358,
-65365,
-65372,
-65372,
-65372,
-65372,
-65397,
-65397,
-65397,
-65453,
-65453,
-65453,
-65480,
-65496,
-65512,
-65531,
-65531,
-65536,
-65543,
-65550,
-65573,
-65580,
-65591,
-65599,
-65608,
-65627,
-65634,
-65634,
-65667,
-65667,
-65686,
-65701,
-65709,
-65716,
-65723,
-65735,
-65735,
-65735,
-65773,
-65786,
-65786,
-65814,
-65827,
-65839,
-65864,
-65864,
-65873,
-65873,
-65886,
-65907,
-65931,
-65955,
-66001,
-66036,
-66054,
-66054,
-66089,
-66131,
-66144,
-66159,
-66159,
-66166,
-66218,
-66236,
-66265,
-66265,
-66324,
-66341,
-66348,
-66355,
-66378,
-66378,
-66378,
-66413,
-66420,
-66427,
-66446,
-66446,
-66453,
-66460,
-66486,
-66486,
-66517,
-66541,
-66556,
-66563,
-66599,
-66599,
-66615,
-66634,
-66654,
-66662,
-66675,
-66681,
-66702,
-66735,
-66735,
-66744,
-66754,
-66783,
-66790,
-66801,
-66808,
-66840,
-66846,
-66846,
-66885,
-66892,
-66892,
-66892,
-66899,
-66906,
-66932,
-66939,
-66945,
-66945,
-66963,
-66979,
-66999,
-66999,
-67007,
-67047,
-67057,
-67070,
-67081,
-67095,
-67095,
-67095,
-67095,
-67101,
-67101,
-67111,
-67139,
-67139,
-67139,
-67139,
-67178,
-67200,
-67223,
-67251,
-67251,
-67251,
-67270,
-67294,
-67305,
-67334,
-67334,
-67334,
-67366,
-67386,
-67405,
-67424,
-67424,
-67424,
-67448,
-67448,
-67467,
-67482,
-67492,
-67492,
-67492,
-67508,
-67515,
-67515,
-67531,
-67549,
-67561,
-67588,
-67594,
-67640,
-67657,
-67679,
-67679,
-67679,
-67701,
-67701,
-67709,
-67709,
-67709,
-67719,
-67719,
-67725,
-67750,
-67787,
-67801,
-67811,
-67842,
-67857,
-67874,
-67874,
-67892,
-67892,
-67939,
-67939,
-67945,
-67945,
-67959,
-67959,
-67959,
-67966,
-67966,
-67978,
-67978,
-67991,
-67991,
-67991,
-68009,
-68009,
-68009,
-68009,
-68027,
-68045,
-68057,
-68057,
-68070,
-68070,
-68115,
-68125,
-68147,
-68183,
-68193,
-68206,
-68214,
-68214,
-68214,
-68214,
-68214,
-68214,
-68214,
-68241,
-68263,
-68284,
-68301,
-68328,
-68328,
-68355,
-68374,
-68395,
-68450,
-68450,
-68471,
-68481,
-68495,
-68506,
-68506,
-68550,
-68550,
-68550,
-68550,
-68569,
-68569,
-68579,
-68593,
-68593,
-68593,
-68609,
-68626,
-68679,
-68696,
-68702,
-68724,
-68724,
-68724,
-68739,
-68759,
-68778,
-68809,
-68824,
-68835,
-68835,
-68890,
-68890,
-68890,
-68907,
-68907,
-68920,
-68938,
-68958,
-68958,
-68979,
-68979,
-68979,
-68997,
-69018,
-69037,
-69056,
-69056,
-69062,
-69062,
-69062,
-69062,
-69082,
-69090,
-69090,
-69090,
-69101,
-69131,
-69131,
-69145,
-69153,
-69182,
-69182,
-69182,
-69196,
-69196,
-69196,
-69196,
-69213,
-69213,
-69223,
-69240,
-69260,
-69279,
-69289,
-69307,
-69307,
-69318,
-69324,
-69347,
-69347,
-69353,
-69353,
-69374,
-69379,
-69379,
-69404,
-69412,
-69412,
-69412,
-69412,
-69435,
-69435,
-69465,
-69485,
-69485,
-69495,
-69495,
-69495,
-69495,
-69495,
-69507,
-69530,
-69552,
-69552,
-69552,
-69552,
-69558,
-69558,
-69562,
-69573,
-69595,
-69595,
-69595,
-69611,
-69619,
-69637,
-69648,
-69648,
-69648,
-69688,
-69711,
-69728,
-69728,
-69754,
-69754,
-69754,
-69754,
-69776,
-69785,
-69785,
-69795,
-69805,
-69825,
-69825,
-69853,
-69853,
-69853,
-69853,
-69873,
-69873,
-69873,
-69883,
-69903,
-69903,
-69917,
-69933,
-69943,
-69943,
-69954,
-69979,
-69999,
-69999,
-69999,
-69999,
-69999,
-70026,
-70041,
-70070,
-70093,
-70121,
-70157,
-70176,
-70176,
-70176,
-70221,
-70221,
-70228,
-70228,
-70232,
-70239,
-70246,
-70250,
-70294,
-70294,
-70316,
-70341,
-70341,
-70341,
-70348,
-70348,
-70348,
-70348,
-70348,
-70412,
-70426,
-70442,
-70442,
-70465,
-70465,
-70465,
-70483,
-70508,
-70515,
-70528,
-70528,
-70581,
-70588,
-70605,
-70626,
-70644,
-70651,
-70675,
-70682,
-70689,
-70695,
-70702,
-70702,
-70744,
-70751,
-70757,
-70780,
-70780,
-70798,
-70805,
-70805,
-70805,
-70812,
-70819,
-70819,
-70826,
-70842,
-70855,
-70866,
-70882,
-70882,
-70882,
-70902,
-70919,
-70939,
-70962,
-70969,
-70978,
-70998,
-71005,
-71005,
-71070,
-71084,
-71109,
-71119,
-71119,
-71141,
-71156,
-71162,
-71171,
-71171,
-71171,
-71171,
-71183,
-71183,
-71200,
-71207,
-71221,
-71229,
-71229,
-71246,
-71297,
-71312,
-71312,
-71312,
-71316,
-71316,
-71316,
-71316,
-71316,
-71316,
-71323,
-71323,
-71351,
-71351,
-71351,
-71381,
-71398,
-71398,
-71422,
-71467,
-71473,
-71480,
-71480,
-71504,
-71542,
-71574,
-71574,
-71590,
-71597,
-71626,
-71626,
-71648,
-71655,
-71655,
-71680,
-71688,
-71737,
-71760,
-71760,
-71792,
-71792,
-71792,
-71816,
-71823,
-71839,
-71839,
-71839,
-71859,
-71859,
-71859,
-71881,
-71881,
-71881,
-71893,
-71893,
-71908,
-71943,
-71950,
-71986,
-71993,
-72006,
-72021,
-72041,
-72041,
-72056,
-72056,
-72065,
-72100,
-72126,
-72148,
-72155,
-72188,
-72188,
-72188,
-72221,
-72240,
-72258,
-72265,
-72284,
-72284,
-72319,
-72329,
-72335,
-72343,
-72375,
-72395,
-72420,
-72432,
-72461,
-72504,
-72511,
-72511,
-72522,
-72544,
-72575,
-72575,
-72587,
-72594,
-72601,
-72601,
-72636,
-72636,
-72636,
-72636,
-72651,
-72665,
-72679,
-72679,
-72693,
-72700,
-72719,
-72762,
-72769,
-72769,
-72776,
-72783,
-72838,
-72852,
-72875,
-72899,
-72899,
-72944,
-72951,
-72958,
-72958,
-72965,
-72979,
-72999,
-73020,
-73056,
-73069,
-73086,
-73106,
-73116,
-73130,
-73137,
-73153,
-73176,
-73188,
-73194,
-73194,
-73210,
-73248,
-73275,
-73301,
-73323,
-73323,
-73344,
-73351,
-73358,
-73358,
-73382,
-73389,
-73389,
-73389,
-73389,
-73396,
-73403,
-73439,
-73446,
-73464,
-73464,
-73487,
-73529,
-73542,
-73598,
-73598,
-73598,
-73605,
-73612,
-73639,
-73671,
-73671,
-73671,
-73687,
-73687,
-73694,
-73701,
-73701,
-73725,
-73750,
-73767,
-73780,
-73794,
-73811,
-73829,
-73854,
-73873,
-73873,
-73873,
-73873,
-73883,
-73883,
-73894,
-73901,
-73928,
-73968,
-73994,
-74001,
-74012,
-74033,
-74040,
-74054,
-74066,
-74086,
-74104,
-74137,
-74137,
-74137,
-74147,
-74147,
-74154,
-74161,
-74192,
-74199,
-74206,
-74206,
-74218,
-74225,
-74232,
-74258,
-74275,
-74303,
-74303,
-74310,
-74330,
-74330,
-74337,
-74359,
-74379,
-74408,
-74423,
-74430,
-74488,
-74488,
-74495,
-74495,
-74505,
-74525,
-74525,
-74540,
-74547,
-74547,
-74547,
-74572,
-74580,
-74587,
-74587,
-74630,
-74650,
-74657,
-74672,
-74679,
-74716,
-74720,
-74720,
-74727,
-74742,
-74742,
-74742,
-74742,
-74749,
-74749,
-74770,
-74770,
-74770,
-74770,
-74770,
-74795,
-74805,
-74805,
-74805,
-74819,
-74832,
-74832,
-74832,
-74832,
-74832,
-74857,
-74882,
-74882,
-74882,
-74907,
-74956,
-74956,
-75011,
-75011,
-75011,
-75017,
-75017,
-75017,
-75017,
-75017,
-75017,
-75017,
-75017,
-75017,
-75017,
-75043,
-75043,
-75053,
-75067,
-75080,
-75131,
-75160,
-75225,
-75298,
-75298,
-75298,
-75329,
-75329,
-75329,
-75336,
-75336,
-75336,
-75336,
-75336,
-75388,
-75413,
-75448,
-75448,
-75461,
-75461,
-75461,
-75516,
-75516,
-75516,
-75516,
-75516,
-75537,
-75576,
-75576,
-75576,
-75597,
-75597,
-75597,
-75626,
-75626,
-75632,
-75664,
-75664,
-75664,
-75680,
-75680,
-75687,
-75709,
-75755,
-75755,
-75812,
-75827,
-75827,
-75838,
-75838,
-75873,
-75873,
-75873,
-75873,
-75873,
-75873,
-75873,
-75896,
-75896,
-75915,
-75919,
-75919,
-75941,
-75962,
-75962,
-75962,
-75972,
-76003,
-76028,
-76062,
-76082,
-76082,
-76082,
-76082,
-76082,
-76088,
-76100,
-76100,
-76100,
-76119,
-76148,
-76169,
-76169,
-76169,
-76181,
-76181,
-76216,
-76238,
-76238,
-76238,
-76264,
-76278,
-76278,
-76293,
-76323,
-76323,
-76323,
-76323,
-76331,
-76351,
-76351,
-76369,
-76369,
-76384,
-76390,
-76416,
-76429,
-76440,
-76478,
-76478,
-76517,
-76517,
-76517,
-76517,
-76526,
-76539,
-76539,
-76591,
-76591,
-76591,
-76591,
-76597,
-76616,
-76616,
-76616,
-76626,
-76626,
-76636,
-76636,
-76646,
-76659,
-76670,
-76682,
-76688,
-76688,
-76688,
-76688,
-76721,
-76721,
-76731,
-76731,
-76731,
-76742,
-76754,
-76754,
-76754,
-76776,
-76776,
-76776,
-76780,
-76780,
-76838,
-76850,
-76857,
-76907,
-76907,
-76907,
-76928,
-76928,
-76968,
-76968,
-76974,
-76974,
-76974,
-76974,
-77008,
-77024,
-77030,
-77036,
-77050,
-77050,
-77067,
-77067,
-77084,
-77112,
-77117,
-77117,
-77126,
-77146,
-77146,
-77154,
-77169,
-77187,
-77193,
-77215,
-77238,
-77266,
-77285,
-77285,
-77291,
-77291,
-77291,
-77304,
-77311,
-77326,
-77326,
-77326,
-77326,
-77332,
-77332,
-77332,
-77332,
-77332,
-77332,
-77348,
-77395,
-77395,
-77395,
-77412,
-77412,
-77412,
-77412,
-77412,
-77437,
-77446,
-77450,
-77466,
-77466,
-77487,
-77487,
-77496,
-77496,
-77496,
-77521,
-77521,
-77521,
-77521,
-77521,
-77521,
-77537,
-77537,
-77552,
-77552,
-77552,
-77552,
-77575,
-77587,
-77587,
-77587,
-77587,
-77587,
-77607,
-77607,
-77607,
-77633,
-77633,
-77640,
-77659,
-77659,
-77659,
-77659,
-77670,
-77670,
-77670,
-77688,
-77738,
-77738,
-77745,
-77745,
-77763,
-77763,
-77763,
-77763,
-77778,
-77796,
-77796,
-77815,
-77832,
-77840,
-77854,
-77854,
-77869,
-77869,
-77869,
-77903,
-77914,
-77914,
-77944,
-77960,
-77960,
-77960,
-77960,
-77976,
-77976,
-77989,
-78005,
-78012,
-78012,
-78042,
-78049,
-78073,
-78107,
-78121,
-78130,
-78168,
-78219,
-78256,
-78256,
-78265,
-78265,
-78272,
-78272,
-78306,
-78318,
-78369,
-78369,
-78369,
-78387,
-78387,
-78403,
-78403,
-78409,
-78409,
-78441,
-78454,
-78459,
-78469,
-78482,
-78531,
-78556,
-78556,
-78556,
-78576,
-78594,
-78600,
-78600,
-78622,
-78622,
-78648,
-78648,
-78670,
-78678,
-78678,
-78684,
-78690,
-78690,
-78690,
-78690,
-78690,
-78716,
-78735,
-78743,
-78743,
-78743,
-78743,
-78743,
-78743,
-78767,
-78801,
-78814,
-78814,
-78814,
-78814,
-78832,
-78839,
-78855,
-78871,
-78871,
-78881,
-78900,
-78929,
-78973,
-79004,
-79022,
-79047,
-79078,
-79113,
-79113,
-79113,
-79128,
-79128,
-79128,
-79146,
-79171,
-79171,
-79205,
-79218,
-79250,
-79250,
-79282,
-79302,
-79309,
-79336,
-79336,
-79341,
-79355,
-79355,
-79355,
-79355,
-79355,
-79355,
-79360,
-79382,
-79382,
-79382,
-79391,
-79427,
-79439,
-79476,
-79476,
-79476,
-79488,
-79488,
-79516,
-79526,
-79526,
-79559,
-79559,
-79559,
-79597,
-79603,
-79603,
-79624,
-79624,
-79660,
-79692,
-79729,
-79736,
-79762,
-79773,
-79773,
-79779,
-79796,
-79824,
-79824,
-79824,
-79830,
-79844,
-79874,
-79896,
-79908,
-79946,
-79956,
-79956,
-79965,
-79971,
-79971,
-80012,
-80060,
-80060,
-80060,
-80076,
-80096,
-80117,
-80135,
-80153,
-80153,
-80153,
-80172,
-80219,
-80219,
-80255,
-80255,
-80264,
-80281,
-80281,
-80291,
-80291,
-80313,
-80332,
-80349,
-80356,
-80365,
-80365,
-80393,
-80406,
-80428,
-80444,
-80450,
-80463,
-80516,
-80537,
-80554,
-80565,
-80565,
-80565,
-80576,
-80576,
-80576,
-80600,
-80600,
-80618,
-80624,
-80624,
-80653,
-80653,
-80690,
-80690,
-80696,
-80696,
-80717,
-80740,
-80748,
-80748,
-80769,
-80780,
-80798,
-80798,
-80804,
-80804,
-80825,
-80835,
-80858,
-80868,
-80874,
-80874,
-80880,
-80896,
-80896,
-80911,
-80921,
-80921,
-80927,
-80932,
-80938,
-80938,
-80975,
-80975,
-80975,
-80975,
-80992,
-80992,
-81002,
-81008,
-81027,
-81039,
-81071,
-81071,
-81089,
-81089,
-81096,
-81096,
-81096,
-81096,
-81123,
-81123,
-81123,
-81148,
-81170,
-81187,
-81213,
-81219,
-81237,
-81255,
-81255,
-81261,
-81289,
-81349,
-81349,
-81358,
-81358,
-81368,
-81374,
-81381,
-81381,
-81386,
-81386,
-81386,
-81410,
-81410,
-81442,
-81460,
-81460,
-81460,
-81460,
-81460,
-81467,
-81467,
-81481,
-81481,
-81488,
-81488,
-81488,
-81502,
-81502,
-81502,
-81502,
-81502,
-81502,
-81510,
-81516,
-81523,
-81540,
-81556,
-81576,
-81639,
-81647,
-81647,
-81673,
-81688,
-81703,
-81703,
-81703,
-81703,
-81721,
-81721,
-81721,
-81756,
-81756,
-81770,
-81781,
-81806,
-81806,
-81826,
-81857,
-81876,
-81882,
-81917,
-81917,
-81917,
-81952,
-81952,
-81952,
-81979,
-82018,
-82018,
-82024,
-82060,
-82067,
-82073,
-82093,
-82100,
-82100,
-82100,
-82100,
-82100,
-82100,
-82127,
-82133,
-82143,
-82163,
-82172,
-82193,
-82216,
-82235,
-82246,
-82246,
-82246,
-82263,
-82276,
-82276,
-82295,
-82305,
-82305,
-82305,
-82305,
-82311,
-82328,
-82341,
-82364,
-82364,
-82385,
-82385,
-82404,
-82404,
-82418,
-82427,
-82427,
-82427,
-82427,
-82434,
-82434,
-82451,
-82468,
-82489,
-82499,
-82499,
-82499,
-82499,
-82510,
-82529,
-82549,
-82578,
-82602,
-82634,
-82647,
-82647,
-82647,
-82659,
-82659,
-82678,
-82678,
-82691,
-82691,
-82699,
-82714,
-82714,
-82734,
-82755,
-82783,
-82795,
-82801,
-82808,
-82826,
-82826,
-82826,
-82838,
-82838,
-82838,
-82838,
-82838,
-82838,
-82852,
-82864,
-82883,
-82925,
-82937,
-82952,
-82952,
-82952,
-82952,
-82952,
-82958,
-82958,
-82964,
-82964,
-82964,
-82964,
-82964,
-82964,
-82969,
-82978,
-82978,
-82995,
-82995,
-83031,
-83039,
-83082,
-83082,
-83098,
-83114,
-83146,
-83146,
-83156,
-83169,
-83169,
-83216,
-83216,
-83230,
-83250,
-83250,
-83250,
-83255,
-83255,
-83291,
-83291,
-83315,
-83315,
-83315,
-83326,
-83343,
-83343,
-83343,
-83343,
-83362,
-83378,
-83432,
-83471,
-83471,
-83471,
-83481,
-83492,
-83492,
-83504,
-83504,
-83504,
-83520,
-83520,
-83520,
-83530,
-83541,
-83541,
-83590,
-83607,
-83626,
-83626,
-83660,
-83693,
-83693,
-83693,
-83693,
-83693,
-83729,
-83735,
-83755,
-83755,
-83763,
-83769,
-83769,
-83782,
-83790,
-83809,
-83829,
-83846,
-83852,
-83852,
-83868,
-83878,
-83898,
-83918,
-83935,
-83935,
-83962,
-83988,
-83998,
-84009,
-84032,
-84070,
-84090,
-84090,
-84090,
-84097,
-84097,
-84097,
-84108,
-84108,
-84108,
-84146,
-84158,
-84177,
-84177,
-84177,
-84177,
-84177,
-84203,
-84220,
-84232,
-84259,
-84311,
-84320,
-84345,
-84345,
-84408,
-84408,
-84441,
-84441,
-84474,
-84481,
-84493,
-84508,
-84520,
-84539,
-84555,
-84567,
-84581,
-84600,
-84600,
-84630,
-84630,
-84642,
-84658,
-84668,
-84668,
-84668,
-84684,
-84695,
-84695,
-84710,
-84742,
-84751,
-84751,
-84765,
-84765,
-84765,
-84765,
-84765,
-84793,
-84814,
-84870,
-84905,
-84917,
-84917,
-84927,
-84927,
-84927,
-84948,
-84963,
-85005,
-85064,
-85076,
-85082,
-85082,
-85093,
-85093,
-85124,
-85136,
-85148,
-85170,
-85170,
-85195,
-85195,
-85220,
-85253,
-85253,
-85253,
-85264,
-85264,
-85264,
-85264,
-85264,
-85269,
-85303,
-85303,
-85314,
-85336,
-85336,
-85336,
-85336,
-85347,
-85347,
-85362,
-85371,
-85412,
-85442,
-85480,
-85519,
-85528,
-85548,
-85548,
-85548,
-85572,
-85582,
-85582,
-85614,
-85614,
-85614,
-85644,
-85666,
-85678,
-85690,
-85710,
-85710,
-85710,
-85720,
-85720,
-85738,
-85738,
-85738,
-85738,
-85755,
-85774,
-85794,
-85794,
-85794,
-85806,
-85818,
-85818,
-85845,
-85862,
-85872,
-85882,
-85892,
-85916,
-85995,
-86005,
-86014,
-86046,
-86090,
-86090,
-86105,
-86114,
-86124,
-86124,
-86150,
-86166,
-86166,
-86176,
-86191,
-86216,
-86216,
-86230,
-86230,
-86230,
-86265,
-86265,
-86277,
-86282,
-86294,
-86310,
-86310,
-86310,
-86320,
-86366,
-86379,
-86403,
-86403,
-86423,
-86434,
-86434,
-86434,
-86434,
-86490,
-86490,
-86548,
-86560,
-86560,
-86560,
-86567,
-86582,
-86596,
-86608,
-86624,
-86653,
-86653,
-86653,
-86669,
-86699,
-86699,
-86713,
-86725,
-86744,
-86760,
-86767,
-86767,
-86779,
-86779,
-86779,
-86792,
-86792,
-86792,
-86792,
-86797,
-86797,
-86829,
-86829,
-86829,
-86829,
-86829,
-86848,
-86854,
-86881,
-86881,
-86881,
-86881,
-86881,
-86939,
-86977,
-86977,
-86977,
-86996,
-86996,
-87036,
-87066,
-87066,
-87075,
-87075,
-87080,
-87098,
-87145,
-87145,
-87166,
-87166,
-87166,
-87166,
-87172,
-87184,
-87237,
-87237,
-87276,
-87276,
-87299,
-87299,
-87299,
-87309,
-87323,
-87323,
-87323,
-87361,
-87378,
-87378,
-87396,
-87396,
-87396,
-87411,
-87432,
-87432,
-87450,
-87460,
-87460,
-87493,
-87507,
-87521,
-87528,
-87533,
-87533,
-87545,
-87576,
-87586,
-87586,
-87586,
-87586,
-87598,
-87613,
-87645,
-87660,
-87666,
-87666,
-87692,
-87700,
-87720,
-87738,
-87762,
-87773,
-87786,
-87786,
-87786,
-87830,
-87851,
-87861,
-87861,
-87879,
-87891,
-87932,
-87932,
-87965,
-87979,
-87986,
-88013,
-88018,
-88018,
-88025,
-88049,
-88049,
-88049,
-88060,
-88060,
-88099,
-88107,
-88107,
-88107,
-88107,
-88117,
-88130,
-88130,
-88130,
-88130,
-88138,
-88148,
-88189,
-88196,
-88214,
-88235,
-88255,
-88268,
-88268,
-88268,
-88278,
-88278,
-88319,
-88361,
-88361,
-88361,
-88361,
-88361,
-88371,
-88396,
-88403,
-88418,
-88440,
-88440,
-88462,
-88462,
-88471,
-88508,
-88514,
-88514,
-88514,
-88514,
-88514,
-88514,
-88514,
-88520,
-88542,
-88549,
-88549,
-88579,
-88579,
-88585,
-88585,
-88597,
-88615,
-88615,
-88615,
-88632,
-88649,
-88660,
-88688,
-88688,
-88688,
-88688,
-88688,
-88700,
-88721,
-88748,
-88760,
-88799,
-88804,
-88831,
-88843,
-88843,
-88843,
-88843,
-88843,
-88856,
-88879,
-88879,
-88895,
-88904,
-88904,
-88904,
-88904,
-88920,
-88920,
-88953,
-88953,
-88953,
-88971,
-88971,
-88971,
-88981,
-88981,
-88981,
-88981,
-88981,
-88994,
-88994,
-89015,
-89027,
-89044,
-89044,
-89074,
-89074,
-89074,
-89074,
-89074,
-89084,
-89097,
-89097,
-89097,
-89097,
-89112,
-89138,
-89158,
-89158,
-89158,
-89164,
-89164,
-89164,
-89180,
-89198,
-89211,
-89222,
-89242,
-89265,
-89265,
-89273,
-89300,
-89312,
-89322,
-89339,
-89349,
-89368,
-89380,
-89391,
-89391,
-89391,
-89391,
-89415,
-89432,
-89441,
-89441,
-89470,
-89492,
-89492,
-89497,
-89509,
-89527,
-89527,
-89535,
-89535,
-89535,
-89535,
-89553,
-89576,
-89576,
-89576,
-89607,
-89612,
-89632,
-89632,
-89632,
-89632,
-89656,
-89656,
-89656,
-89656,
-89656,
-89656,
-89656,
-89656,
-89686,
-89709,
-89709,
-89759,
-89759,
-89759,
-89794,
-89794,
-89802,
-89802,
-89802,
-89819,
-89819,
-89860,
-89873,
-89896,
-89896,
-89907,
-89936,
-89936,
-89983,
-90001,
-90017,
-90022,
-90045,
-90045,
-90045,
-90045,
-90051,
-90071,
-90071,
-90071,
-90071,
-90071,
-90071,
-90088,
-90114,
-90151,
-90151,
-90162,
-90162,
-90162,
-90195,
-90195,
-90195,
-90195,
-90229,
-90229,
-90247,
-90269,
-90269,
-90286,
-90312,
-90312,
-90312,
-90356,
-90356,
-90372,
-90378,
-90410,
-90410,
-90431,
-90431,
-90441,
-90441,
-90441,
-90447,
-90499,
-90513,
-90513,
-90513,
-90524,
-90524,
-90524,
-90542,
-90548,
-90578,
-90578,
-90583,
-90621,
-90621,
-90627,
-90627,
-90690,
-90690,
-90721,
-90727,
-90727,
-90732,
-90732,
-90755,
-90755,
-90768,
-90783,
-90783,
-90783,
-90793,
-90820,
-90829,
-90838,
-90838,
-90847,
-90847,
-90858,
-90858,
-90858,
-90874,
-90874,
-90874,
-90901,
-90911,
-90933,
-90938,
-90949,
-90949,
-90961,
-91014,
-91045,
-91045,
-91067,
-91067,
-91067,
-91067,
-91067,
-91067,
-91092,
-91113,
-91113,
-91113,
-91133,
-91156,
-91161,
-91161,
-91171,
-91182,
-91197,
-91234,
-91234,
-91252,
-91252,
-91252,
-91297,
-91297,
-91297,
-91297,
-91306,
-91306,
-91318,
-91318,
-91329,
-91329,
-91329,
-91336,
-91336,
-91336,
-91342,
-91342,
-91342,
-91372,
-91372,
-91382,
-91420,
-91420,
-91450,
-91450,
-91450,
-91450,
-91477,
-91477,
-91487,
-91510,
-91510,
-91510,
-91529,
-91545,
-91605,
-91605,
-91605,
-91627,
-91645,
-91645,
-91655,
-91655,
-91687,
-91704,
-91704,
-91714,
-91719,
-91734,
-91734,
-91734,
-91759,
-91759,
-91759,
-91759,
-91759,
-91759,
-91764,
-91774,
-91811,
-91811,
-91811,
-91819,
-91855,
-91870,
-91870,
-91870,
-91870,
-91870,
-91870,
-91893,
-91898,
-91905,
-91905,
-91923,
-91934,
-91934,
-91934,
-91963,
-91975,
-91992,
-92004,
-92023,
-92041,
-92052,
-92052,
-92052,
-92112,
-92123,
-92134,
-92134,
-92140,
-92156,
-92169,
-92175,
-92194,
-92194,
-92229,
-92229,
-92229,
-92229,
-92253,
-92273,
-92290,
-92306,
-92327,
-92327,
-92334,
-92342,
-92342,
-92342,
-92352,
-92368,
-92385,
-92393,
-92404,
-92404,
-92430,
-92455,
-92455,
-92455,
-92455,
-92455,
-92475,
-92475,
-92475,
-92475,
-92482,
-92495,
-92531,
-92547,
-92555,
-92567,
-92567,
-92567,
-92575,
-92575,
-92582,
-92582,
-92582,
-92582,
-92635,
-92655,
-92672,
-92672,
-92690,
-92702,
-92713,
-92746,
-92756,
-92756,
-92761,
-92774,
-92774,
-92814,
-92814,
-92820,
-92844,
-92872,
-92919,
-92927,
-92927,
-92945,
-92986,
-93026,
-93067,
-93099,
-93099,
-93120,
-93135,
-93135,
-93142,
-93186,
-93195,
-93208,
-93227,
-93232,
-93232,
-93232,
-93232,
-93245,
-93255,
-93255,
-93264,
-93278,
-93278,
-93288,
-93288,
-93301,
-93320,
-93326,
-93333,
-93348,
-93348,
-93348,
-93357,
-93357,
-93362,
-93396,
-93412,
-93412,
-93421,
-93444,
-93444,
-93460,
-93476,
-93476,
-93481,
-93481,
-93497,
-93528,
-93552,
-93560,
-93581,
-93599,
-93599,
-93599,
-93612,
-93641,
-93667,
-93683,
-93699,
-93707,
-93718,
-93740,
-93756,
-93756,
-93756,
-93756,
-93767,
-93785,
-93785,
-93802,
-93802,
-93837,
-93837,
-93860,
-93885,
-93885,
-93893,
-93893,
-93914,
-93957,
-93957,
-93957,
-93978,
-93986,
-93986,
-93986,
-93986,
-93995,
-94003,
-94003,
-94003,
-94012,
-94030,
-94040,
-94040,
-94054,
-94054,
-94074,
-94074,
-94092,
-94106,
-94106,
-94113,
-94113,
-94121,
-94121,
-94121,
-94139,
-94139,
-94139,
-94150,
-94150,
-94163,
-94163,
-94163,
-94192,
-94192,
-94199,
-94199,
-94214,
-94250,
-94250,
-94259,
-94271,
-94316,
-94316,
-94359,
-94359,
-94372,
-94372,
-94372,
-94380,
-94380,
-94380,
-94395,
-94395,
-94400,
-94411,
-94411,
-94411,
-94411,
-94430,
-94430,
-94439,
-94439,
-94439,
-94439,
-94456,
-94469,
-94469,
-94469,
-94469,
-94488,
-94488,
-94488,
-94503,
-94524,
-94524,
-94546,
-94560,
-94574,
-94587,
-94593,
-94611,
-94626,
-94663,
-94663,
-94663,
-94674,
-94684,
-94699,
-94699,
-94715,
-94721,
-94721,
-94783,
-94783,
-94783,
-94783,
-94804,
-94804,
-94804,
-94804,
-94813,
-94824,
-94837,
-94837,
-94837,
-94850,
-94870,
-94889,
-94902,
-94902,
-94911,
-94943,
-94957,
-94957,
-94989,
-95001,
-95001,
-95023,
-95023,
-95035,
-95049,
-95058,
-95067,
-95104,
-95104,
-95104,
-95118,
-95127,
-95127,
-95127,
-95127,
-95146,
-95146,
-95182,
-95182,
-95196,
-95196,
-95196,
-95224,
-95241,
-95279,
-95279,
-95299,
-95299,
-95309,
-95323,
-95352,
-95372,
-95380,
-95380,
-95390,
-95390,
-95421,
-95421,
-95421,
-95421,
-95455,
-95473,
-95486,
-95492,
-95525,
-95538,
-95557,
-95627,
-95627,
-95627,
-95641,
-95641,
-95664,
-95673,
-95673,
-95673,
-95708,
-95717,
-95717,
-95725,
-95732,
-95748,
-95748,
-95748,
-95760,
-95788,
-95796,
-95796,
-95855,
-95875,
-95875,
-95875,
-95875,
-95875,
-95909,
-95909,
-95909,
-95909,
-95929,
-95939,
-95939,
-95948,
-95948,
-95948,
-95958,
-95991,
-96014,
-96014,
-96033,
-96033,
-96056,
-96081,
-96088,
-96103,
-96126,
-96157,
-96157,
-96157,
-96176,
-96189,
-96189,
-96189,
-96213,
-96260,
-96283,
-96283,
-96283,
-96283,
-96283,
-96283,
-96283,
-96283,
-96290,
-96296,
-96296,
-96314,
-96314,
-96314,
-96338,
-96363,
-96374,
-96374,
-96374,
-96374,
-96374,
-96374,
-96380,
-96385,
-96419,
-96434,
-96440,
-96440,
-96450,
-96473,
-96512,
-96542,
-96542,
-96563,
-96563,
-96594,
-96654,
-96654,
-96654,
-96654,
-96681,
-96701,
-96721,
-96744,
-96744,
-96754,
-96754,
-96768,
-96779,
-96804,
-96836,
-96836,
-96855,
-96884,
-96884,
-96894,
-96926,
-96934,
-96934,
-96973,
-96993,
-96993,
-97020,
-97050,
-97075,
-97075,
-97093,
-97093,
-97118,
-97132,
-97152,
-97152,
-97175,
-97175,
-97175,
-97198,
-97221,
-97241,
-97284,
-97314,
-97322,
-97322,
-97322,
-97334,
-97356,
-97364,
-97380,
-97398,
-97416,
-97416,
-97416,
-97437,
-97437,
-97437,
-97457,
-97457,
-97499,
-97515,
-97541,
-97541,
-97573,
-97611,
-97611,
-97620,
-97637,
-97637,
-97660,
-97701,
-97701,
-97720,
-97750,
-97768,
-97768,
-97799,
-97799,
-97826,
-97840,
-97840,
-97840,
-97840,
-97847,
-97847,
-97847,
-97847,
-97867,
-97867,
-97880,
-97919,
-97919,
-97934,
-97962,
-97979,
-97979,
-97988,
-97988,
-97988,
-97998,
-98033,
-98041,
-98070,
-98077,
-98077,
-98117,
-98124,
-98184,
-98198,
-98198,
-98212,
-98222,
-98222,
-98222,
-98222,
-98238,
-98245,
-98245,
-98259,
-98259,
-98259,
-98259,
-98269,
-98269,
-98269,
-98279,
-98279,
-98279,
-98287,
-98300,
-98300,
-98300,
-98307,
-98320,
-98337,
-98347,
-98372,
-98388,
-98412,
-98412,
-98426,
-98434,
-98487,
-98492,
-98522,
-98522,
-98537,
-98562,
-98571,
-98571,
-98571,
-98610,
-98630,
-98630,
-98640,
-98652,
-98671,
-98692,
-98718,
-98725,
-98759,
-98759,
-98759,
-98759,
-98793,
-98801,
-98818,
-98835,
-98865,
-98879,
-98891,
-98891,
-98910,
-98933,
-98933,
-98951,
-98960,
-98960,
-98960,
-98969,
-98991,
-98991,
-99025,
-99049,
-99049,
-99049,
-99049,
-99049,
-99071,
-99071,
-99071,
-99084,
-99101,
-99115,
-99125,
-99125,
-99125,
-99125,
-99144,
-99182,
-99212,
-99218,
-99218,
-99256,
-99256,
-99284,
-99284,
-99305,
-99305,
-99305,
-99323,
-99339,
-99339,
-99339,
-99339,
-99360,
-99360,
-99376,
-99376,
-99403,
-99416,
-99416,
-99416,
-99441,
-99441,
-99441,
-99441,
-99467,
-99487,
-99497,
-99497,
-99515,
-99515,
-99515,
-99515,
-99525,
-99525,
-99525,
-99525,
-99525,
-99525,
-99540,
-99545,
-99545,
-99545,
-99551,
-99570,
-99570,
-99611,
-99611,
-99643,
-99643,
-99643,
-99653,
-99660,
-99660,
-99679,
-99679,
-99679,
-99679,
-99679,
-99707,
-99707,
-99707,
-99707,
-99724,
-99734,
-99755,
-99755,
-99781,
-99795,
-99795,
-99803,
-99810,
-99828,
-99828,
-99828,
-99847,
-99847,
-99866,
-99866,
-99866,
-99877,
-99877,
-99908,
-99913,
-99913,
-99940,
-99940,
-99940,
-99947,
-99947,
-99947,
-99947,
-99952,
-99952,
-99952,
-99957,
-99957,
-99957,
-99972,
-100009,
-100017,
-100034,
-100054,
-100054,
-100069,
-100069,
-100094,
-100094,
-100102,
-100124,
-100124,
-100124,
-100147,
-100147,
-100153,
-100183,
-100183,
-100207,
-100207,
-100231,
-100231,
-100231,
-100241,
-100265,
-100265,
-100265,
-100265,
-100265,
-100265,
-100282,
-100282,
-100301,
-100333,
-100351,
-100351,
-100357,
-100370,
-100383,
-100383,
-100442,
-100442,
-100459,
-100478,
-100483,
-100502,
-100508,
-100508,
-100518,
-100518,
-100518,
-100528,
-100528,
-100528,
-100544,
-100563,
-100563,
-100563,
-100575,
-100617,
-100642,
-100678,
-100678,
-100678,
-100693,
-100693,
-100702,
-100702,
-100702,
-100720,
-100733,
-100748,
-100748,
-100766,
-100789,
-100789,
-100796,
-100803,
-100819,
-100819,
-100841,
-100857,
-100857,
-100885,
-100907,
-100907,
-100915,
-100932,
-100938,
-100952,
-100961,
-100998,
-101021,
-101021,
-101029,
-101042,
-101042,
-101059,
-101069,
-101092,
-101092,
-101092,
-101142,
-101181,
-101198,
-101206,
-101206,
-101211,
-101222,
-101222,
-101248,
-101248,
-101248,
-101248,
-101259,
-101284,
-101284,
-101300,
-101321,
-101336,
-101336,
-101343,
-101352,
-101368,
-101389,
-101398,
-101410,
-101416,
-101416,
-101429,
-101441,
-101457,
-101463,
-101463,
-101497,
-101497,
-101507,
-101507,
-101507,
-101507,
-101513,
-101523,
-101540,
-101553,
-101585,
-101585,
-101616,
-101683,
-101683,
-101698,
-101705,
-101718,
-101745,
-101745,
-101745,
-101751,
-101763,
-101770,
-101770,
-101770,
-101794,
-101794,
-101794,
-101813,
-101841,
-101876,
-101884,
-101903,
-101903,
-101903,
-101934,
-101954,
-101967,
-101980,
-101980,
-101993,
-102006,
-102006,
-102016,
-102016,
-102041,
-102051,
-102051,
-102051,
-102065,
-102065,
-102065,
-102087,
-102102,
-102120,
-102120,
-102140,
-102153,
-102159,
-102191,
-102240,
-102240,
-102251,
-102251,
-102269,
-102303,
-102303,
-102329,
-102329,
-102377,
-102377,
-102377,
-102402,
-102408,
-102408,
-102423,
-102436,
-102436,
-102447,
-102460,
-102460,
-102460,
-102460,
-102467,
-102484,
-102502,
-102526,
-102526,
-102526,
-102526,
-102526,
-102526,
-102559,
-102578,
-102592,
-102600,
-102600,
-102600,
-102600,
-102600,
-102614,
-102614,
-102625,
-102625,
-102640,
-102670,
-102676,
-102676,
-102700,
-102733,
-102733,
-102733,
-102779,
-102793,
-102809,
-102869,
-102869,
-102879,
-102914,
-102923,
-102948,
-102968,
-102968,
-102974,
-102987,
-103014,
-103037,
-103073,
-103094,
-103112,
-103128,
-103135,
-103135,
-103145,
-103145,
-103145,
-103160,
-103160,
-103166,
-103173,
-103173,
-103214,
-103214,
-103226,
-103226,
-103226,
-103237,
-103237,
-103237,
-103254,
-103273,
-103302,
-103302,
-103319,
-103336,
-103336,
-103355,
-103370,
-103380,
-103380,
-103396,
-103407,
-103419,
-103455,
-103500,
-103507,
-103517,
-103542,
-103574,
-103574,
-103588,
-103588,
-103602,
-103602,
-103613,
-103636,
-103656,
-103656,
-103670,
-103675,
-103689,
-103712,
-103712,
-103712,
-103719,
-103747,
-103747,
-103793,
-103801,
-103820,
-103826,
-103826,
-103837,
-103837,
-103837,
-103837,
-103848,
-103859,
-103859,
-103865,
-103865,
-103875,
-103881,
-103933,
-103950,
-103973,
-103991,
-104008,
-104008,
-104027,
-104046,
-104058,
-104062,
-104062,
-104062,
-104062,
-104077,
-104087,
-104097,
-104104,
-104104,
-104124,
-104155,
-104170
-};
-
-static const quint16 tldChunkCount = 2;
-static const char * const tldData[tldChunkCount] = {
-"int.ar\0"
-"int.az\0"
-"siljan.no\0fastlylb.net\0"
-"int.bo\0afl\0repair\0"
-"elvendrell.museum\0citic\0in-vpn.de\0"
-"gobo.wakayama.jp\0hellas.museum\0"
-"review\0"
-"to.leg.br\0"
-"jetzt\0"
-"naroy.no\0"
-"crew.aero\0int.ci\0"
-"\xe6\xbe\xb3\xe9\x96\x80\0"
-"inami.toyama.jp\0nyuzen.toyama.jp\0"
-"sakai.ibaraki.jp\0"
-"deloitte\0"
-"int.co\0nagahama.shiga.jp\0"
-"en-root.fr\0"
-"vang.no\0"
-"takatori.nara.jp\0"
-"es.eu.org\0"
-"omuta.fukuoka.jp\0"
-"lel.br\0careers\0"
-"warszawa.pl\0"
-"tajiri.osaka.jp\0kudoyama.wakayama.jp\0vossevangen.no\0s3-us-gov-west-1.amazonaws.com\0"
-"heimatunduhren.museum\0trana.no\0"
-"boleslawiec.pl\0"
-"mi.it\0"
-"minobu.yamanashi.jp\0aig\0"
-"gallup\0now-dns.net\0"
-"ap-northeast-3.elasticbeanstalk.com\0"
-"shimamoto.osaka.jp\0"
-"tokashiki.okinawa.jp\0"
-"doomdns.com\0"
-"gouv.fr\0"
-"homelink.one\0"
-"physio\0"
-"chase\0"
-"nf.ca\0chuo.tokyo.jp\0"
-"ine.kyoto.jp\0"
-"deporte.bo\0karasjok.no\0hotmail\0"
-"mallorca.museum\0"
-"askim.no\0"
-"cookingchannel\0"
-"depot.museum\0"
-"shingo.aomori.jp\0"
-"eiheiji.fukui.jp\0nowruz\0"
-"misaki.okayama.jp\0"
-"plo.ps\0"
-"kyotanabe.kyoto.jp\0"
-"s3-us-west-1.amazonaws.com\0"
-"szex.hu\0larvik.no\0"
-"roros.no\0"
-"ing.pa\0*.hosting.myjino.ru\0"
-"gouv.ht\0"
-"is-found.org\0"
-"deals\0"
-"am.br\0"
-"iwaki.fukushima.jp\0"
-"kaminokawa.tochigi.jp\0temp-dns.com\0"
-"telekommunikation.museum\0"
-"fujieda.shizuoka.jp\0pointto.us\0"
-"barclaycard\0"
-"consultant.aero\0staging.onred.one\0"
-"gouv.bj\0kawatana.nagasaki.jp\0"
-"cv.ua\0"
-"nat.tn\0country\0vision\0"
-"yamanashi.jp\0nagawa.nagano.jp\0"
-"hi.us\0memset.net\0"
-"nikaho.akita.jp\0\xe6\xbe\xb3\xe9\x97\xa8\0management\0"
-"int.is\0"
-"cc.nm.us\0"
-"meinforum.net\0"
-"gouv.ci\0"
-"sunagawa.hokkaido.jp\0slattum.no\0"
-"oum.gov.pl\0"
-"marche.it\0williamhill\0"
-"g12.br\0noto.ishikawa.jp\0"
-"trentinoaadige.it\0nyc.museum\0"
-"exhibition.museum\0"
-"yasuoka.nagano.jp\0"
-"hokksund.no\0"
-"takasago.hyogo.jp\0oshu.iwate.jp\0"
-"ethnology.museum\0"
-"ambulance.museum\0ngrok.io\0"
-"africa\0mk.eu.org\0"
-"services\0"
-"yakage.okayama.jp\0""16-b.it\0"
-"gloppen.no\0"
-"lib.ks.us\0anz\0"
-"aol\0"
-"dynu.net\0"
-"aero\0int.la\0"
-"higashine.yamagata.jp\0futbol\0"
-"adachi.tokyo.jp\0"
-"katsuragi.wakayama.jp\0godaddy\0"
-"nanjo.okinawa.jp\0drangedal.no\0"
-"iki.nagasaki.jp\0sula.no\0"
-"santacruz.museum\0"
-"int.lk\0"
-"klepp.no\0"
-"botanicalgarden.museum\0"
-"ri.it\0"
-"stalowa-wola.pl\0no-ip.org\0"
-"app\0user.aseinet.ne.jp\0"
-"bolt.hu\0"
-"cloudapps.digital\0"
-"zhitomir.ua\0"
-"unj\xc3\xa1rga.no\0"
-"yombo.me\0"
-"reliance\0"
-"uchihara.ibaraki.jp\0"
-"esan.hokkaido.jp\0kautokeino.no\0\xe5\x98\x89\xe9\x87\x8c\0"
-"bar\0"
-"is.it\0int.mv\0bbc\0"
-"int.mw\0"
-"odessa.ua\0"
-"int.ni\0"
-"ns.ca\0"
-"final\0"
-"bolzano-altoadige.it\0secure\0"
-"servehalflife.com\0"
-"pvt.k12.ma.us\0"
-"fukuoka.jp\0"
-"barefoot\0"
-"\xe0\xa6\xad\xe0\xa6\xbe\xe0\xa7\xb0\xe0\xa6\xa4\0"
-"kokonoe.oita.jp\0"
-"art\0bbt\0cloudns.pro\0lu.eu.org\0me.eu.org\0"
-"ecn.br\0minakami.gunma.jp\0ishigaki.okinawa.jp\0ass.km\0holiday\0"
-"k12.wa.us\0"
-"k.bg\0karumai.iwate.jp\0bcg\0"
-"sakura.chiba.jp\0inami.wakayama.jp\0"
-"genkai.saga.jp\0mi.th\0"
-"arts.co\0"
-"brussels.museum\0"
-"tono.iwate.jp\0"
-"fm.br\0bcn\0"
-"rnrt.tn\0"
-"yachiyo.chiba.jp\0"
-"kitadaito.okinawa.jp\0expert\0"
-"vote\0"
-"accident-prevention.aero\0fosnes.no\0"
-"okayama.okayama.jp\0"
-"chieti.it\0"
-"sydney.museum\0"
-"university\0"
-"fi.eu.org\0"
-"act.au\0"
-"voto\0"
-"mad.museum\0"
-"psi.br\0if.ua\0"
-"skjervoy.no\0"
-"trentin-sued-tirol.it\0"
-"int.pt\0"
-"b\xc3\xa5tsfjord.no\0"
-"ullensvang.no\0lv.eu.org\0ravendb.community\0"
-"bj.cn\0fukagawa.hokkaido.jp\0mi.us\0"
-"balena-devices.com\0"
-"hokkaido.jp\0"
-"epson\0"
-"oracle\0"
-"\xe5\x92\x8c\xe6\xad\x8c\xe5\xb1\xb1.jp\0"
-"kiyokawa.kanagawa.jp\0bet\0"
-"shinjo.okayama.jp\0"
-"lib.tn.us\0"
-"tsuyama.okayama.jp\0"
-"qbuser.com\0"
-"sweetpepper.org\0"
-"\xe5\x8f\xb0\xe6\xb9\xbe\0"
-"parliament.nz\0ng.city\0"
-"berg.no\0"
-"int.ru\0dedyn.io\0"
-"sagamihara.kanagawa.jp\0"
-"undersea.museum\0"
-"trieste.it\0seto.aichi.jp\0"
-"kainan.tokushima.jp\0"
-"presse.km\0settlers.museum\0singles\0"
-"ogawa.saitama.jp\0ralingen.no\0lib.md.us\0"
-"symantec\0"
-"malbork.pl\0"
-"tozawa.yamagata.jp\0"
-"axa\0"
-"\xe0\xa4\xb8\xe0\xa4\x82\xe0\xa4\x97\xe0\xa4\xa0\xe0\xa4\xa8\0"
-"aws\0"
-"konan.aichi.jp\0anamizu.ishikawa.jp\0ome.tokyo.jp\0cc.ca.us\0"
-"int.tj\0"
-"shimada.shizuoka.jp\0"
-"trentin-s\xc3\xbc""d-tirol.it\0virtualuser.de\0"
-"fedorainfracloud.org\0"
-"is-a-linux-user.org\0"
-"sunndal.no\0"
-"nakatombetsu.hokkaido.jp\0national.museum\0"
-"\xe5\xae\xae\xe5\x9f\x8e.jp\0int.tt\0is-a-teacher.com\0"
-"arakawa.tokyo.jp\0"
-"hara.nagano.jp\0randaberg.no\0bid\0"
-"homeip.net\0"
-"trentinosuedtirol.it\0presse.ml\0"
-"homeunix.net\0"
-"appchizi.com\0"
-"tc.br\0bio\0"
-"kawamata.fukushima.jp\0kitagawa.miyazaki.jp\0half.host\0"
-"ravendb.run\0"
-"int.ve\0"
-"communications.museum\0"
-"bozen-suedtirol.it\0"
-"now.sh\0"
-"biz\0"
-"int.vn\0"
-"brussel.museum\0gratangen.no\0"
-"fm.it\0"
-"nebraska.museum\0\xd9\x81\xd9\x84\xd8\xb3\xd8\xb7\xd9\x8a\xd9\x86\0"
-"minamitane.kagoshima.jp\0nakano.tokyo.jp\0"
-"wios.gov.pl\0"
-"hekinan.aichi.jp\0"
-"passenger-association.aero\0"
-"obihiro.hokkaido.jp\0"
-"x.bg\0zachpomor.pl\0"
-"osakasayama.osaka.jp\0"
-"industria.bo\0"
-"guernsey.museum\0"
-"5.bg\0partners\0"
-"svelvik.no\0saarland\0"
-"ce.gov.br\0"
-"salud.bo\0"
-"ozora.hokkaido.jp\0ri.us\0hangout\0"
-"plc.co.im\0reggio-emilia.it\0wales.museum\0k12.or.us\0"
-"lodingen.no\0"
-"georgia.museum\0news\0kr.eu.org\0"
-"kaluga.su\0murmansk.su\0"
-"tochigi.tochigi.jp\0sf.no\0"
-"\xd9\x85\xd9\x88\xd8\xb1\xd9\x8a\xd8\xaa\xd8\xa7\xd9\x86\xd9\x8a\xd8\xa7\0"
-"tempioolbia.it\0ureshino.mie.jp\0"
-"tranibarlettaandria.it\0"
-"lanbib.se\0"
-"arts.ve\0"
-"orkdal.no\0"
-"bms\0"
-"next\0"
-"okoppe.hokkaido.jp\0time.no\0"
-"bmw\0"
-"df.leg.br\0"
-"gouv.sn\0"
-"haebaru.okinawa.jp\0"
-"trader.aero\0hughes\0"
-"sasebo.nagasaki.jp\0"
-"investments\0"
-"haugesund.no\0frontdoor\0"
-"fm.no\0"
-"bom\0"
-"boo\0pics\0"
-"omigawa.chiba.jp\0ushuaia.museum\0"
-"bot\0crown\0"
-"realestate\0"
-"iijima.nagano.jp\0assassination.museum\0"
-"kamikawa.hyogo.jp\0box\0"
-"info.gu\0naturalhistory.museum\0"
-"hs.zone\0"
-"cloudns.eu\0"
-"ss.it\0"
-"cab\0"
-"fujikawaguchiko.yamanashi.jp\0"
-"pesarourbino.it\0"
-"rokunohe.aomori.jp\0"
-"\xe5\x8d\x83\xe8\x91\x89.jp\0"
-"unjarga.no\0"
-"aarborte.no\0yolasite.com\0"
-"jampa.br\0info.ht\0hornindal.no\0cal\0"
-"info.hu\0cam\0"
-"microsoft\0spreadbetting\0"
-"is-a-knight.org\0"
-"cba\0"
-"car\0"
-"cat\0wroclaw.pl\0"
-"engerdal.no\0"
-"tysfjord.no\0"
-"arts.ro\0"
-"info.et\0minokamo.gifu.jp\0s\xc3\xb8r-aurdal.no\0tana.no\0cloudns.org\0"
-"group.aero\0mitou.yamaguchi.jp\0cbn\0"
-"cheltenham.museum\0"
-"*.triton.zone\0"
-"info.fj\0"
-"cbs\0"
-"uchinomi.kagawa.jp\0"
-"trentino-a-adige.it\0"
-"belem.br\0somna.no\0"
-"aisai.aichi.jp\0gliwice.pl\0"
-"rv.ua\0*.vps.myjino.ru\0"
-"shibetsu.hokkaido.jp\0kurobe.toyama.jp\0wi.us\0"
-"k.se\0"
-"yahiko.niigata.jp\0raholt.no\0volyn.ua\0"
-"cloudns.in\0"
-"mil.ac\0"
-"mil.ae\0"
-"discount\0info.cx\0"
-"ferrero\0"
-"california.museum\0ceb\0"
-"mil.al\0"
-"airbus\0"
-"mil.ba\0"
-"mil.ar\0"
-"info.ec\0"
-"kudamatsu.yamaguchi.jp\0cloudns.cc\0"
-"matsubara.osaka.jp\0luzern.museum\0ceo\0"
-"kumano.mie.jp\0g\xc3\xa1ivuotna.no\0cfa\0"
-"mil.az\0arts.nf\0legnica.pl\0"
-"cesena-forl\xc3\xac.it\0takatsuki.osaka.jp\0farmers.museum\0bearalv\xc3\xa1hki.no\0"
-"cfd\0"
-"shimotsuma.ibaraki.jp\0"
-"mil.bo\0iiyama.nagano.jp\0"
-"latina.it\0gouv.km\0buy\0"
-"info.bb\0mil.br\0austin.museum\0lib.vt.us\0"
-"info.at\0"
-"info.au\0"
-"mil.by\0realm.cz\0scrapping.cc\0"
-"info.az\0forde.no\0"
-"cc.ma.us\0"
-"mil.cl\0trust\0"
-"paderborn.museum\0"
-"mil.cn\0niihama.ehime.jp\0"
-"info.bo\0mil.co\0is-a-nurse.com\0"
-"\xd0\xb1\xd0\xb3\0"
-"campobasso.it\0az.us\0ivanovo.su\0"
-"forlicesena.it\0nakagusuku.okinawa.jp\0pixolino.com\0"
-"journal.aero\0"
-"stuff-4-sale.org\0"
-"mishima.shizuoka.jp\0click\0"
-"village.museum\0is-an-engineer.com\0"
-"citi\0"
-"natura\0"
-"info.co\0mil.do\0"
-"gouv.ml\0"
-"chintai\0"
-"mil.ec\0"
-"kinko.kagoshima.jp\0"
-"mil.eg\0nationalfirearms.museum\0sandoy.no\0edeka\0"
-"lupin\0"
-"pharmacy\0hobby-site.com\0"
-"tp.it\0city\0"
-"sakai.fukui.jp\0sor-fron.no\0"
-"wskr.gov.pl\0"
-"place\0"
-"tawaramoto.nara.jp\0karasjohka.no\0"
-"s3.dualstack.sa-east-1.amazonaws.com\0"
-"vicenza.it\0"
-"gmina.pl\0"
-"entomology.museum\0barsy.co.uk\0"
-"mil.fj\0"
-"lea\xc5\x8bgaviika.no\0ping\0col.ng\0"
-"treviso.it\0"
-"casino.hu\0"
-"pink\0in-berlin.de\0"
-"l\xc3\xa4ns.museum\0bzh\0\xd0\xb4\xd0\xb5\xd1\x82\xd0\xb8\0"
-"aid.pl\0"
-"mil.ge\0"
-"mil.gh\0"
-"ichikai.tochigi.jp\0"
-"florist\0"
-"id.au\0oirm.gov.pl\0intuit\0"
-"adobeaemcloud.com\0"
-"trustee.museum\0leksvik.no\0tunk.org\0"
-"earth\0scrysec.com\0"
-"mil.gt\0"
-"art.br\0"
-"ct.it\0wakasa.fukui.jp\0akiruno.tokyo.jp\0"
-"aosta.it\0"
-"googleapis.com\0"
-"dgca.aero\0"
-"namikata.ehime.jp\0"
-"wv.us\0"
-"mil.hn\0"
-"x.se\0"
-"minami.kyoto.jp\0komatsu\0"
-"fet.no\0naklo.pl\0"
-"reggioemilia.it\0iwafune.tochigi.jp\0no-ip.net\0"
-"mil.id\0shimonoseki.yamaguchi.jp\0solutions\0"
-"potenza.it\0enterprises\0"
-"\xd0\xb5\xd1\x8e\0rj.leg.br\0"
-"km.ua\0gold\0"
-"torino.museum\0"
-"mil.in\0golf\0"
-"filegear-ie.me\0"
-"mil.iq\0kodaira.tokyo.jp\0is-a-blogger.com\0"
-"art.do\0"
-"cagliari.it\0okazaki.aichi.jp\0skanland.no\0now-dns.org\0"
-"yanaizu.fukushima.jp\0hino.tottori.jp\0java\0"
-"daegu.kr\0"
-"cc.ut.us\0"
-"!city.nagoya.jp\0itano.tokushima.jp\0berlin.museum\0"
-"divtasvuodna.no\0wang\0"
-"art.dz\0"
-"alta.no\0"
-"mil.jo\0"
-"kani.gifu.jp\0skiptvet.no\0tourism.tn\0"
-"venice.it\0"
-"lib.wy.us\0"
-"mil.kg\0seaport.museum\0"
-"matsumoto.nagano.jp\0"
-"\xe5\xb2\xa1\xe5\xb1\xb1.jp\0mil.km\0cc.mn.us\0"
-"presse.ci\0"
-"tokushima.jp\0"
-"marnardal.no\0"
-"mil.kr\0"
-"fot.br\0trentino-altoadige.it\0"
-"health.nz\0"
-"com\0"
-"nogi.tochigi.jp\0cpa\0"
-"mil.kz\0g\xc3\xa1ls\xc3\xa1.no\0"
-"ebina.kanagawa.jp\0"
-"\xe0\xa8\xad\xe0\xa8\xbe\xe0\xa8\xb0\xe0\xa8\xa4\0"
-"rochester.museum\0"
-"goog\0"
-"go.gov.br\0omihachiman.shiga.jp\0"
-"from-ar.com\0"
-"app.banzaicloud.io\0cloudns.us\0"
-"yaese.okinawa.jp\0mil.lv\0"
-"mil.mg\0g\xc3\xa1\xc5\x8bgaviika.no\0"
-"romsa.no\0"
-"yokaichiba.chiba.jp\0takinoue.hokkaido.jp\0detroit.museum\0"
-"koto.tokyo.jp\0"
-"dad\0"
-"okawa.kochi.jp\0svn-repos.de\0"
-"bieszczady.pl\0from-mo.com\0"
-"senseering.net\0"
-"trentinsuedtirol.it\0takahagi.ibaraki.jp\0mil.mv\0"
-"art.ht\0preservation.museum\0mil.ng\0"
-"pz.it\0for-our.info\0servehttp.com\0"
-"mil.my\0mil.ni\0serveftp.com\0"
-"mil.mz\0"
-"hakodate.hokkaido.jp\0artcenter.museum\0"
-"steiermark.museum\0syncloud.it\0"
-"kunneppu.hokkaido.jp\0"
-"gos.pk\0"
-"mil.no\0"
-"mihama.mie.jp\0day\0"
-"fujikawa.shizuoka.jp\0"
-"info.ve\0\xe5\x85\xab\xe5\x8d\xa6\0s3-external-1.amazonaws.com\0"
-"schwarz\0storage\0"
-"mil.nz\0"
-"crs\0csc\0"
-"id.ir\0"
-"\xc3\xa5""fjord.no\0"
-"info.vn\0"
-"fuel.aero\0"
-"nes.buskerud.no\0nctu.me\0"
-"rishirifuji.hokkaido.jp\0fastpanel.direct\0"
-"sampa.br\0parliament.cy\0ranzan.saitama.jp\0"
-"varese.it\0himeshima.oita.jp\0mil.pe\0"
-"trd.br\0mus.mi.us\0onyourside\0\xe6\x88\x91\xe7\x88\xb1\xe4\xbd\xa0\0"
-"s\xc3\xb8r-varanger.no\0luxury\0syno-ds.de\0"
-"mil.ph\0"
-"pyatigorsk.ru\0orx.biz\0"
-"chikujo.fukuoka.jp\0mihara.kochi.jp\0mil.pl\0"
-"tagajo.miyagi.jp\0"
-"kamaishi.iwate.jp\0bible\0"
-"logistics.aero\0\xe4\xb8\x89\xe9\x87\x8d.jp\0"
-"misato.miyagi.jp\0mil.qa\0clic2000.net\0"
-"alesund.no\0"
-"ybo.science\0"
-"filegear-de.me\0"
-"\xe5\x8f\xb0\xe7\x81\xa3\0"
-"santoandre.br\0recht.pro\0mil.py\0"
-"missoula.museum\0"
-"dds\0"
-"tokyo.jp\0"
-"bern.museum\0info.tn\0"
-"nirasaki.yamanashi.jp\0"
-"info.tr\0"
-"eisenbahn.museum\0info.tt\0"
-"nose.osaka.jp\0"
-"homeunix.org\0"
-"k12.mn.us\0"
-"stordal.no\0trysil.no\0cc.wa.us\0"
-"yakumo.hokkaido.jp\0info.tz\0"
-"lego\0"
-"kuzumaki.iwate.jp\0kids.us\0dev\0"
-"usuki.oita.jp\0id.lv\0gen.mi.us\0"
-"hyllestad.no\0myvnc.com\0"
-"hokuto.hokkaido.jp\0id.ly\0portal.museum\0"
-"mil.ru\0"
-"higashiizu.shizuoka.jp\0mil.rw\0"
-"mil.sh\0health.vn\0"
-"geek.nz\0"
-"trentins\xc3\xbc""dtirol.it\0imabari.ehime.jp\0"
-"shima.mie.jp\0"
-"info.ro\0"
-"pordenone.it\0\xd1\x80\xd1\x84\0"
-"prime\0"
-"info.sd\0mil.st\0"
-"timekeeping.museum\0"
-"ct.us\0"
-"workinggroup.aero\0mil.sy\0zhytomyr.ua\0"
-"estate.museum\0mil.tj\0netlify.app\0"
-"mil.tm\0"
-"\xc3\xa1laheadju.no\0"
-"plantation.museum\0mil.to\0"
-"moma.museum\0palmsprings.museum\0ui.nabu.casa\0"
-"cim.br\0kakuda.miyagi.jp\0mil.tr\0"
-"parma.it\0dhl\0"
-"kiyosu.aichi.jp\0"
-"mil.tw\0cheap\0samsclub\0"
-"\xe7\xae\x87\xe4\xba\xba.hk\0"
-"mil.tz\0"
-"nakano.nagano.jp\0johana.toyama.jp\0info.pk\0"
-"info.pl\0"
-"from-co.net\0"
-"haboro.hokkaido.jp\0eidsvoll.no\0"
-"art.pl\0mintere.site\0"
-"cc.ar.us\0"
-"info.pr\0"
-"mil.vc\0blockbuster\0"
-"mil.ve\0"
-"harstad.no\0"
-"mil.uy\0"
-"rg.it\0"
-"alaheadju.no\0tourism.pl\0"
-"tula.su\0"
-"info.na\0diy\0suzuki\0"
-"bmd.br\0iwakuni.yamaguchi.jp\0"
-"mt.it\0"
-"info.mv\0info.nf\0"
-"higashishirakawa.gifu.jp\0"
-"sasayama.hyogo.jp\0info.ni\0mormon\0"
-"asaminami.hiroshima.jp\0"
-"is-a-painter.com\0"
-"\xd0\xb1\xd0\xb5\xd0\xbb\0"
-"soeda.fukuoka.jp\0"
-"info.nr\0cloud.fedoraproject.org\0"
-"sd.cn\0mikasa.hokkaido.jp\0"
-"cloudns.pw\0is-a-hard-worker.com\0"
-"hyogo.jp\0"
-"en.it\0fla.no\0\xe0\xa4\xad\xe0\xa4\xbe\xe0\xa4\xb0\xe0\xa4\xa4\xe0\xa4\xae\xe0\xa5\x8d\0"
-"ichikawa.hyogo.jp\0foundation.museum\0"
-"on-aptible.com\0"
-"fusa.no\0"
-"info.la\0art.sn\0"
-"collegefan.org\0"
-"saijo.ehime.jp\0rmit\0is-very-good.org\0"
-"i.bg\0ryuoh.shiga.jp\0nishiizu.shizuoka.jp\0"
-"uw.gov.pl\0americanexpress\0"
-"scrapper-site.net\0"
-"\xe5\x85\xac\xe5\x8f\xb8\0gotdns.ch\0"
-"rr.leg.br\0"
-"trentino-alto-adige.it\0perspecta.cloud\0"
-"glitch.me\0"
-"barrell-of-knowledge.info\0"
-"mil.za\0"
-"info.ls\0grainger\0i234.me\0"
-"aramco\0"
-"iwaizumi.iwate.jp\0"
-"\xe0\xa6\xac\xe0\xa6\xbe\xe0\xa6\x82\xe0\xa6\xb2\xe0\xa6\xbe\0"
-"\xc3\xb8ystre-slidre.no\0"
-"k12.ny.us\0"
-"bilbao.museum\0finearts.museum\0geelvinck.museum\0s\xc3\xb8rreisa.no\0ddnss.org\0"
-"\xe6\x84\x9b\xe5\xaa\x9b.jp\0here-for-more.info\0"
-"university.museum\0"
-"mil.zm\0"
-"ngo.lk\0"
-"protection\0"
-"shiranuka.hokkaido.jp\0"
-"kisarazu.chiba.jp\0"
-"kumiyama.kyoto.jp\0"
-"steinkjer.no\0"
-"ekloges.cy\0mil.zw\0"
-"dnp\0"
-"katagami.akita.jp\0rs.leg.br\0sc.leg.br\0"
-"id.us\0"
-"dog\0"
-"sakaki.nagano.jp\0morimachi.shizuoka.jp\0"
-"jeonnam.kr\0cc.oh.us\0"
-"is-a-guru.com\0"
-"info.ke\0*.elb.amazonaws.com\0of.work\0"
-"e164.arpa\0"
-"brescia.it\0otaki.chiba.jp\0info.ki\0environmentalconservation.museum\0"
-"ngo.ng\0"
-"dot\0"
-"badajoz.museum\0aure.no\0holdings\0"
-"muroran.hokkaido.jp\0"
-"clock.museum\0"
-"oumu.hokkaido.jp\0app.render.com\0"
-"kita.osaka.jp\0chiyoda.tokyo.jp\0sandnessj\xc3\xb8""en.no\0marine.ru\0azurewebsites.net\0"
-"sciencesnaturelles.museum\0"
-"\xe5\x85\xac\xe7\x9b\x8a\0*.compute-1.amazonaws.com\0"
-"\xe9\xb9\xbf\xe5\x85\x90\xe5\xb3\xb6.jp\0land-4-sale.us\0"
-"town\0"
-"*.nom.br\0"
-"kawaue.gifu.jp\0touch.museum\0azure\0\xd8\xb9\xd8\xb1\xd8\xa8\0"
-"namsos.no\0"
-"s3.dualstack.eu-central-1.amazonaws.com\0"
-"loyalist.museum\0is-certified.com\0"
-"nature.museum\0"
-"myravendb.com\0"
-"kozagawa.wakayama.jp\0dinosaur.museum\0ham-radio-op.net\0mein-iserv.de\0"
-"munakata.fukuoka.jp\0"
-"apartments\0"
-"bale.museum\0stjordal.no\0"
-"karm\xc3\xb8y.no\0ngo.ph\0"
-"rybnik.pl\0eat\0windows\0b.ssl.fastly.net\0"
-"email\0gdynia.pl\0"
-"unazuki.toyama.jp\0"
-"ozu.kumamoto.jp\0"
-"iitate.fukushima.jp\0himeji.hyogo.jp\0\xd0\xbc\xd0\xbe\xd1\x81\xd0\xba\xd0\xb2\xd0\xb0\0"
-"kuroiso.tochigi.jp\0"
-"\xe5\xa4\xa7\xe6\x8b\xbf\0"
-"toys\0"
-"basel.museum\0"
-"padua.it\0"
-"wedeploy.sh\0"
-"seika.kyoto.jp\0\xe5\x95\x86\xe6\xa5\xad.tw\0"
-"on.ca\0"
-"bahn.museum\0eco\0"
-"club.tw\0"
-"belau.pw\0"
-"townnews-staging.com\0"
-"uz.ua\0"
-"kuwana.mie.jp\0kolobrzeg.pl\0"
-"hosting\0"
-"kai.yamanashi.jp\0sakura\0ba.leg.br\0"
-"lifestyle\0"
-"space.museum\0"
-"madrid\0better-than.tv\0"
-"v.bg\0aigo\0"
-"shibecha.hokkaido.jp\0toyoura.hokkaido.jp\0architecture.museum\0"
-"rn.leg.br\0"
-"marumori.miyagi.jp\0"
-"edu\0"
-"dtv\0"
-"3.bg\0myshopblocks.com\0"
-"taishin.fukushima.jp\0lancashire.museum\0"
-"froland.no\0"
-"yoshida.shizuoka.jp\0"
-"dray-dns.de\0"
-"aurskog-holand.no\0"
-"cesenaforli.it\0"
-"flor\xc3\xb8.no\0"
-"slask.pl\0"
-"pacific.museum\0"
-"recreation.aero\0nanbu.tottori.jp\0mosjoen.no\0"
-"ap-southeast-1.elasticbeanstalk.com\0merseine.nu\0"
-"aeroport.fr\0"
-"ostroleka.pl\0selfip.net\0"
-"mt.us\0nd.us\0boxfuse.io\0"
-"wales\0"
-"mincom.tn\0"
-"tsubetsu.hokkaido.jp\0"
-"correios-e-telecomunica\xc3\xa7\xc3\xb5""es.museum\0dvr\0"
-"hirono.fukushima.jp\0naustdal.no\0wielun.pl\0ro.leg.br\0"
-"hiroshima.jp\0degree\0"
-"elblag.pl\0dyndns-blog.com\0"
-"ryokami.saitama.jp\0"
-"from-nm.com\0"
-"trading.aero\0v\xc3\xa5gan.no\0"
-"shell.museum\0"
-"freiburg.museum\0gotdns.org\0"
-"kawakita.ishikawa.jp\0astronomy.museum\0opole.pl\0"
-"krasnodar.su\0"
-"satte.saitama.jp\0"
-"swiebodzin.pl\0"
-"anquan\0"
-"railway.museum\0i.ng\0"
-"ak.us\0"
-"kashiwara.osaka.jp\0"
-"nico\0"
-"kv\xc3\xa6""fjord.no\0"
-"jp.eu.org\0"
-"\xd0\xb8\xd0\xba\xd0\xbe\xd0\xbc.museum\0tuva.su\0"
-"press.cy\0lublin.pl\0"
-"r\xc3\xb8ros.no\0"
-"\xd8\xa7\xd9\x84\xd8\xb3\xd8\xb9\xd9\x88\xd8\xaf\xdb\x8c\xd8\xa9\0"
-"\xe5\xbe\xb3\xe5\xb3\xb6.jp\0evenes.no\0cricket\0"
-"dynv6.net\0vologda.su\0"
-"kouhoku.saga.jp\0itau\0dyndns.dappnode.io\0skygearapp.com\0"
-"mino.gifu.jp\0space\0"
-"kvafjord.no\0"
-"r\xc3\xb8st.no\0"
-"ta.it\0station.museum\0"
-"i.ph\0"
-"diskstation.me\0"
-"kaga.ishikawa.jp\0kamiichi.toyama.jp\0"
-"hair\0webhop.info\0"
-"gojome.akita.jp\0"
-"notodden.no\0"
-"fujinomiya.shizuoka.jp\0north-kazakhstan.su\0"
-"toyama.jp\0"
-"verbania.it\0"
-"in-the-band.net\0"
-"ngo.za\0c66.me\0"
-"gs.hl.no\0"
-"blogsite.xyz\0diskstation.eu\0"
-"hisamitsu\0"
-"association.museum\0"
-"ikaruga.nara.jp\0"
-"chiropractic.museum\0servepics.com\0"
-"slupsk.pl\0organic\0am.leg.br\0"
-"sel.no\0"
-"l\xc3\xa1hppi.no\0"
-"isumi.chiba.jp\0"
-"sandiego.museum\0"
-"ce.it\0mydissent.net\0"
-"kiwi.nz\0"
-"nonoichi.ishikawa.jp\0hurum.no\0wedeploy.me\0"
-"takagi.nagano.jp\0"
-"b\xc3\xa5""d\xc3\xa5""ddj\xc3\xa5.no\0\xd0\xbe\xd1\x80\xd0\xb3.\xd1\x81\xd1\x80\xd0\xb1\0"
-"shimosuwa.nagano.jp\0i.se\0k12.tx.us\0"
-"xen.prgmr.com\0"
-"mus.br\0akishima.tokyo.jp\0"
-"air.museum\0"
-"muncie.museum\0ebiz.tw\0"
-"takino.hyogo.jp\0kitagata.saga.jp\0"
-"he.cn\0sd.us\0"
-"forl\xc3\xac""cesena.it\0play\0"
-"kawaba.gunma.jp\0dnsalias.net\0"
-"ogaki.gifu.jp\0test-iserv.de\0"
-"mandal.no\0"
-"s3-website-sa-east-1.amazonaws.com\0mayfirst.info\0"
-"lier.no\0"
-"cloudns.asia\0web.app\0"
-"inagawa.hyogo.jp\0gose.nara.jp\0"
-"sakawa.kochi.jp\0"
-"sano.tochigi.jp\0from-mt.com\0from-nd.com\0"
-"xihuan\0"
-"goiania.br\0"
-"aisho.shiga.jp\0info.zm\0"
-"shimoji.okinawa.jp\0"
-"akkeshi.hokkaido.jp\0"
-"okinoshima.shimane.jp\0"
-"tatar\0"
-"k12.gu.us\0"
-"cc.pr.us\0"
-"kumagaya.saitama.jp\0"
-"co.technology\0"
-"karlsoy.no\0bss.design\0"
-"quebec.museum\0"
-"k12.ct.us\0nike\0"
-"sakuragawa.ibaraki.jp\0"
-"\xe5\xb1\xb1\xe5\xbd\xa2.jp\0"
-"coal.museum\0ardal.no\0"
-"vall\xc3\xa9""e-aoste.it\0oirase.aomori.jp\0ohkura.yamagata.jp\0um.gov.pl\0"
-"*.futurecms.at\0"
-"myhome-server.de\0"
-"omitama.ibaraki.jp\0"
-"piw.gov.pl\0"
-"omotego.fukushima.jp\0"
-"ilawa.pl\0"
-"kariya.aichi.jp\0"
-"vet.br\0hikawa.shimane.jp\0lgbt\0"
-"seki.gifu.jp\0"
-"birkenes.no\0"
-"bu.no\0"
-"fan\0"
-"\xd8\xa7\xdb\x8c\xd8\xb1\xd8\xa7\xd9\x86\0"
-"copenhagen.museum\0"
-"iwama.ibaraki.jp\0"
-"revista.bo\0saikai.nagasaki.jp\0"
-"tn.it\0kaminoyama.yamagata.jp\0ap.leg.br\0"
-"\xe6\x94\xbf\xe5\xba\x9c.hk\0fuso.aichi.jp\0portlligat.museum\0from-me.org\0"
-"koza.wakayama.jp\0canon\0"
-"mansion.museum\0sells-it.net\0"
-"panel.gg\0"
-"gotpantheon.com\0"
-"hitachiomiya.ibaraki.jp\0"
-"se.leg.br\0"
-"bloomberg\0"
-"salangen.no\0playstation-cloud.com\0"
-"yn.cn\0is-a-photographer.com\0"
-"weatherchannel\0"
-"sn\xc3\xa5sa.no\0"
-"coupon\0"
-"nara.jp\0no-ip.info\0"
-"vads\xc3\xb8.no\0"
-"toride.ibaraki.jp\0esq\0"
-"balsan.it\0"
-"reviews\0"
-"creditunion\0"
-"us.gov.pl\0"
-"qh.cn\0"
-"aircraft.aero\0"
-"cr.it\0"
-"olawa.pl\0"
-"aikawa.kanagawa.jp\0omachi.saga.jp\0"
-"musashimurayama.tokyo.jp\0asahi.toyama.jp\0saves-the-whales.com\0"
-"*.sch.uk\0"
-"ask\xc3\xb8y.no\0"
-"suita.osaka.jp\0\xd8\xa7\xd9\x85\xd8\xa7\xd8\xb1\xd8\xa7\xd8\xaa\0eus\0"
-"from-vt.com\0direct.quickconnect.to\0"
-"in.london\0"
-"kawanishi.hyogo.jp\0"
-"writesthisblog.com\0"
-"act.edu.au\0"
-"sardinia.it\0shimabara.nagasaki.jp\0from-ms.com\0from-nc.com\0"
-"krokstadelva.no\0"
-"r\xc3\xa5holt.no\0netlify.com\0"
-"marburg.museum\0inc.hk\0"
-"freesite.host\0tashkent.su\0"
-"zentsuji.kagawa.jp\0k12.me.us\0"
-"asahi.nagano.jp\0haus\0"
-"ravenna.it\0\xd8\xa7\xd9\x84\xd8\xb3\xd8\xb9\xd9\x88\xd8\xaf\xdb\x8c\xdb\x83\0"
-"taito.tokyo.jp\0v.ua\0"
-"botanical.museum\0"
-"bozen.it\0"
-"nesseby.no\0k12.id.us\0"
-"skierva.no\0"
-"today\0mydatto.com\0"
-"suzu.ishikawa.jp\0kasaoka.okayama.jp\0"
-"horology.museum\0"
-"*.bzz.dapps.earth\0"
-"matsuyama.ehime.jp\0"
-"eidskog.no\0nedre-eiker.no\0"
-"club\0"
-"spydeberg.no\0"
-"ohi.fukui.jp\0"
-"\xe5\xa4\xa9\xe4\xb8\xbb\xe6\x95\x99\0"
-"wa.edu.au\0"
-"fujisato.akita.jp\0"
-"co.krd\0"
-"agano.niigata.jp\0"
-"mango\0l-o-g-i-n.de\0"
-"maritimo.museum\0"
-"azumino.nagano.jp\0"
-"wedeploy.io\0"
-"\xd2\x9b\xd0\xb0\xd0\xb7\0george\0"
-"saga.jp\0fit\0"
-"cruise\0"
-"wa.gov.au\0"
-"sakai.osaka.jp\0codespot.com\0"
-"gs.rl.no\0"
-"is-a-socialist.com\0freebox-os.fr\0"
-"minamiaiki.nagano.jp\0"
-"mup.gov.pl\0"
-"stryn.no\0"
-"analytics\0"
-"\xe5\xa4\xa7\xe5\x88\x86.jp\0"
-"dyndns-pics.com\0vapor.cloud\0"
-"nakatsugawa.gifu.jp\0comcast\0tmall\0"
-"lasalle\0wedding\0"
-"lima-city.rocks\0"
-"lu.it\0me.it\0\xd9\x85\xd9\x88\xd9\x82\xd8\xb9\0pantheonsite.io\0"
-"ski.no\0"
-"miyako.iwate.jp\0"
-"press.se\0"
-"berlin\0"
-"chernovtsy.ua\0"
-"\xe9\xb3\xa5\xe5\x8f\x96.jp\0"
-"zushi.kanagawa.jp\0oshino.yamanashi.jp\0"
-"esashi.hokkaido.jp\0"
-"feste-ip.net\0members.linode.com\0"
-"nb.ca\0"
-"me.ke\0"
-"setagaya.tokyo.jp\0epilepsy.museum\0hoyanger.no\0\xe6\xb7\xa1\xe9\xa9\xac\xe9\x94\xa1\0"
-"winb.gov.pl\0"
-"from-ct.com\0"
-"svizzera.museum\0"
-"oster\xc3\xb8y.no\0"
-"fly\0"
-"jeep\0"
-"shiwa.iwate.jp\0"
-"knx-server.net\0"
-"shinjo.nara.jp\0"
-"awaji.hyogo.jp\0"
-"ic.gov.pl\0webspace.rocks\0"
-"webhop.biz\0"
-"fujimino.saitama.jp\0"
-"tsu.mie.jp\0tn.us\0"
-"kuchinotsu.nagasaki.jp\0"
-"suginami.tokyo.jp\0"
-"yoshida.saitama.jp\0"
-"yamaga.kumamoto.jp\0frontier\0"
-"iraq.museum\0k12.mt.us\0is.eu.org\0serveblog.net\0"
-"greta.fr\0"
-"shiraoka.saitama.jp\0"
-"dyndns-ip.com\0"
-"nagano.nagano.jp\0"
-"namdalseid.no\0foo\0"
-"cr.ua\0"
-"kamigori.hyogo.jp\0u2.xnbay.com\0"
-"\xe0\xa4\xad\xe0\xa4\xbe\xe0\xa4\xb0\xe0\xa5\x8b\xe0\xa4\xa4\0karacol.su\0"
-"asahi.mie.jp\0tsubame.niigata.jp\0pruszkow.pl\0gu.us\0fox\0"
-"kirkenes.no\0tiffany\0"
-"obu.aichi.jp\0chikushino.fukuoka.jp\0"
-"e12.ve\0"
-"kawanabe.kagoshima.jp\0"
-"wassamu.hokkaido.jp\0beiarn.no\0nysa.pl\0"
-"of.fashion\0"
-"children.museum\0workers.dev\0"
-"it.eu.org\0lugs.org.uk\0"
-"shimonita.gunma.jp\0"
-"lib.or.us\0"
-"s\xc3\xb8mna.no\0"
-"phoenix.museum\0"
-"gal\0"
-"akdn\0"
-"andriabarlettatrani.it\0compare\0from-ky.com\0"
-"plus\0for-better.biz\0"
-"gap\0"
-"press.ma\0"
-"kotohira.kagawa.jp\0kikugawa.shizuoka.jp\0notaires.km\0marshalls\0room\0"
-"tokoname.aichi.jp\0"
-"catholic.edu.au\0"
-"operaunite.com\0"
-"gay\0"
-"u.channelsdvr.net\0"
-"frl\0"
-"is-a-doctor.com\0"
-"kanna.gunma.jp\0inderoy.no\0"
-"medicina.bo\0insurance\0"
-"\xe0\xb8\xa3\xe0\xb8\xb1\xe0\xb8\x90\xe0\xb8\x9a\xe0\xb8\xb2\xe0\xb8\xa5.\xe0\xb9\x84\xe0\xb8\x97\xe0\xb8\xa2\0"
-"tottori.jp\0"
-"re.it\0"
-"olkusz.pl\0"
-"gs.of.no\0"
-"bialowieza.pl\0"
-"divttasvuotna.no\0we.bs\0"
-"kiyose.tokyo.jp\0"
-"nome.pt\0herokuapp.com\0"
-"denmark.museum\0"
-"nanao.ishikawa.jp\0dealer\0"
-"assisi.museum\0fl\xc3\xa5.no\0"
-"kumano.hiroshima.jp\0livinghistory.museum\0"
-"bnpparibas\0"
-"bedzin.pl\0"
-"laquila.it\0"
-"us-east-1.elasticbeanstalk.com\0"
-"nasu.tochigi.jp\0"
-"yamamoto.miyagi.jp\0"
-"from-dc.com\0"
-"miyake.nara.jp\0gdn\0mex.com\0"
-"shinshiro.aichi.jp\0"
-"akashi.hyogo.jp\0gea\0"
-"ftr\0wroc.pl\0"
-"in.eu.org\0"
-"izumi.kagoshima.jp\0re.kr\0rennesoy.no\0"
-"me.so\0"
-"noticias.bo\0"
-"fun\0"
-"\xe7\xa5\x9e\xe5\xa5\x88\xe5\xb7\x9d.jp\0onojo.fukuoka.jp\0"
-"g.bg\0"
-"lucerne.museum\0"
-"limited\0armenia.su\0"
-"telebit.app\0"
-"natural.bo\0"
-"jl.cn\0"
-"sue.fukuoka.jp\0toshiba\0forgot.her.name\0"
-"cityeats\0conn.uk\0"
-"meiwa.mie.jp\0"
-"square7.de\0"
-"company\0"
-"tas.au\0ancona.it\0"
-"me.tz\0"
-"me.uk\0"
-"fi.cr\0"
-"kagamino.okayama.jp\0"
-"kashima.ibaraki.jp\0"
-"technology.museum\0dnsup.net\0"
-"isa-hockeynut.com\0"
-"cyber.museum\0me.us\0"
-"hiraizumi.iwate.jp\0"
-"home.dyndns.org\0"
-"fukui.jp\0community.museum\0"
-"friulivgiulia.it\0vacations\0"
-"es.gov.br\0mansions.museum\0"
-"r\xc3\xb8yken.no\0linkitools.space\0"
-"mr.no\0"
-"cc.nv.us\0"
-"arida.wakayama.jp\0"
-"isshiki.aichi.jp\0"
-"naturalsciences.museum\0school.na\0"
-"\xe9\xa3\x9f\xe5\x93\x81\0"
-"ibestad.no\0"
-"aurskog-h\xc3\xb8land.no\0\xe8\xaf\xba\xe5\x9f\xba\xe4\xba\x9a\0"
-"muroto.kochi.jp\0fyi\0s3.eu-west-3.amazonaws.com\0"
-"odawara.kanagawa.jp\0"
-"austevoll.no\0weir\0"
-"lucania.it\0"
-"square7.ch\0"
-"kasuga.fukuoka.jp\0gallery\0"
-"durban\0"
-"vega.no\0"
-"verm\xc3\xb6gensberater\0"
-"school.nz\0"
-"selfip.org\0"
-"mizusawa.iwate.jp\0"
-"nikon\0"
-"nakijin.okinawa.jp\0"
-"bentley\0"
-"naamesjevuemie.no\0"
-"soka.saitama.jp\0video\0"
-"nanae.hokkaido.jp\0fashion\0"
-"no.it\0\xe7\xa6\x8f\xe5\xb2\xa1.jp\0"
-"gle\0"
-"emilia-romagna.it\0"
-"from-va.com\0"
-"botanicgarden.museum\0hs.run\0"
-"natal.br\0is-into-cars.com\0"
-"minamimaki.nagano.jp\0"
-"ac\0\xe6\x84\x9b\xe7\x9f\xa5.jp\0musashino.tokyo.jp\0"
-"ad\0"
-"ae\0"
-"af\0"
-"ag\0ashiya.hyogo.jp\0"
-"ai\0!city.sendai.jp\0"
-"knowsitall.info\0"
-"fi.it\0vinnica.ua\0"
-"al\0"
-"am\0"
-"ao\0"
-"gmo\0"
-"aq\0ba\0"
-"ar\0bb\0izumo.shimane.jp\0tvedestrand.no\0"
-"as\0"
-"at\0t.bg\0kitakami.iwate.jp\0"
-"au\0be\0\xe5\x95\x86\xe5\xba\x97\0"
-"gob.ar\0bf\0av.it\0"
-"aw\0bg\0"
-"ax\0bh\0pistoia.it\0bruxelles.museum\0"
-"bi\0nishiwaki.hyogo.jp\0gmx\0"
-"az\0bj\0\xc4\x8d\xc3\xa1hcesuolo.no\0"
-"gru.br\0chiba.jp\0"
-"bm\0shibata.niigata.jp\0british.museum\0"
-"bn\0"
-"1.bg\0bo\0"
-"ca\0"
-"br\0ballangen.no\0"
-"gob.bo\0bs\0cc\0bari.it\0read-books.org\0ddns.net\0"
-"bt\0cd\0"
-"planetarium.museum\0"
-"bv\0cf\0daemon.panel.gg\0"
-"bw\0cg\0"
-"ch\0"
-"by\0ci\0moroyama.saitama.jp\0"
-"bz\0skedsmokorset.no\0"
-"cc.wy.us\0is-saved.org\0"
-"cl\0ebetsu.hokkaido.jp\0"
-"cm\0chita.aichi.jp\0"
-"cn\0kunst.museum\0"
-"co\0"
-"gob.cl\0goo\0"
-"gop\0training\0"
-"cr\0ilovecollege.info\0"
-"adm.br\0cu\0de\0got\0"
-"cv\0minnesota.museum\0"
-"cw\0gov\0naturalhistorymuseum.museum\0austrheim.no\0dyn.home-webserver.de\0"
-"cx\0"
-"cy\0hazu.aichi.jp\0hurdal.no\0"
-"cz\0dj\0"
-"dk\0"
-"dm\0lefrak\0"
-"do\0sakae.chiba.jp\0tychy.pl\0"
-"incheon.kr\0"
-"ullensaker.no\0"
-"kutno.pl\0"
-"gob.do\0ec\0chiyoda.gunma.jp\0"
-"ee\0valled-aosta.it\0"
-"isen.kagoshima.jp\0"
-"gob.ec\0eg\0"
-"ulm.museum\0"
-"dz\0"
-"takasaki.gunma.jp\0fage\0"
-"takikawa.hokkaido.jp\0"
-"*.ex.futurecms.at\0"
-"shinichi.hiroshima.jp\0fujitsu\0\xd8\xa7\xd9\x84\xd8\xb9\xd9\x84\xd9\x8a\xd8\xa7\xd9\x86\0"
-"pilot.aero\0"
-"es\0minamifurano.hokkaido.jp\0yonabaru.okinawa.jp\0"
-"et\0kharkiv.ua\0"
-"eu\0"
-"towada.aomori.jp\0daigo.ibaraki.jp\0hitachiota.ibaraki.jp\0nara.nara.jp\0homegoods\0"
-"gob.es\0noheji.aomori.jp\0"
-"fi\0lib.nm.us\0"
-"fj\0dnsalias.org\0"
-"bamble.no\0hitra.no\0"
-"bandai.fukushima.jp\0"
-"fm\0saintlouis.museum\0"
-"fo\0fastvps.host\0"
-"hbo\0"
-"ga\0toki.gifu.jp\0s3-eu-central-1.amazonaws.com\0"
-"fr\0gb\0"
-"lidl\0"
-"gd\0trentinosud-tirol.it\0ibaraki.osaka.jp\0soc.srcf.net\0"
-"ge\0naturhistorisches.museum\0"
-"gf\0"
-"gg\0"
-"gh\0york.museum\0\xd9\xbe\xd8\xa7\xd9\x83\xd8\xb3\xd8\xaa\xd8\xa7\xd9\x86\0"
-"gi\0"
-"gl\0so.it\0"
-"gm\0"
-"gn\0"
-"shingu.wakayama.jp\0"
-"gp\0"
-"gq\0ichinomiya.aichi.jp\0"
-"gr\0fail\0"
-"gs\0"
-"gt\0"
-"gu\0"
-"gw\0"
-"gob.gt\0appspot.com\0*.r.appspot.com\0"
-"gy\0biella.it\0est-le-patron.com\0"
-"hk\0"
-"life\0"
-"\xe7\xbb\x84\xe7\xbb\x87.hk\0hm\0"
-"hn\0"
-"shirako.chiba.jp\0"
-"news.hu\0"
-"gob.hn\0hr\0"
-"kamikawa.hokkaido.jp\0koshimizu.hokkaido.jp\0"
-"ht\0id\0"
-"hu\0ie\0"
-"kaita.hiroshima.jp\0"
-"pomorskie.pl\0"
-"udi.br\0society.museum\0"
-"il\0"
-"im\0"
-"in\0"
-"io\0kushima.miyazaki.jp\0healthcare\0"
-"iq\0"
-"ir\0blogspot.com\0"
-"is\0b\xc3\xa1hcavuotna.no\0"
-"it\0"
-"je\0shunan.yamaguchi.jp\0"
-"londrina.br\0shirosato.ibaraki.jp\0"
-"sb.ua\0"
-"bs.it\0"
-"noshiro.akita.jp\0"
-"jewelry\0travelers\0"
-"susono.shizuoka.jp\0"
-"\xe6\x94\xbf\xe5\xba\x9c.\xe9\xa6\x99\xe6\xb8\xaf\0"
-"ora.gunma.jp\0kumamoto.kumamoto.jp\0"
-"jo\0"
-"jp\0g.se\0"
-"my-gateway.de\0"
-"napoli.it\0"
-"shingu.fukuoka.jp\0boston.museum\0baseball\0hdfc\0"
-"ke\0"
-"kg\0loab\xc3\xa1t.no\0"
-"gs.cn\0ki\0schaeffler\0"
-"bci.dnstrace.pro\0"
-"fudai.iwate.jp\0k12.pa.us\0"
-"km\0"
-"asso.fr\0kn\0dabur\0"
-"linkyard.cloud\0"
-"kp\0"
-"la\0"
-"kr\0lb\0pioneer\0"
-"lc\0"
-"\xe7\x86\x8a\xe6\x9c\xac.jp\0drammen.no\0rissa.no\0"
-"kw\0"
-"ky\0li\0"
-"kz\0"
-"lk\0"
-"asso.gp\0"
-"safe\0loginline.io\0"
-"curitiba.br\0rugby\0"
-"ma\0"
-"lr\0ol.no\0engineering\0"
-"ls\0mc\0radom.pl\0"
-"lt\0md\0av.tr\0"
-"lu\0me\0"
-"lv\0wegrow.pl\0"
-"mg\0"
-"mh\0"
-"ly\0fans\0rocher\0"
-"mk\0rennebu.no\0"
-"ml\0like\0"
-"settsu.osaka.jp\0"
-"mn\0"
-"mo\0town.museum\0tec.mi.us\0"
-"asso.ht\0tokushima.tokushima.jp\0mp\0"
-"mq\0na\0abbott\0"
-"mr\0"
-"ms\0nc\0dyroy.no\0"
-"yoichi.hokkaido.jp\0mt\0turen.tn\0"
-"mu\0cc.na\0ne\0"
-"mv\0nf\0"
-"grandrapids.museum\0mw\0ng\0enebakk.no\0hiv\0"
-"mx\0for-more.biz\0"
-"inazawa.aichi.jp\0my\0ni\0yalta.ua\0ally\0faith\0"
-"mz\0"
-"lib.mn.us\0"
-"gob.mx\0nl\0"
-"gob.ni\0"
-"fhv.se\0"
-"no\0"
-"*.ocp.customer-oci.com\0"
-"nr\0"
-"vall\xc3\xa9""e-d-aoste.it\0"
-"nu\0"
-"asso.bj\0sund.no\0"
-"barcelona\0ooguy.com\0"
-"folldal.no\0graphics\0"
-"whoswho\0"
-"rendalen.no\0nz\0"
-"\xe9\x9d\x99\xe5\xb2\xa1.jp\0sumita.iwate.jp\0"
-"firmdale\0"
-"asaka.saitama.jp\0om\0"
-"hjartdal.no\0"
-"biei.hokkaido.jp\0iron.museum\0s3.dualstack.ap-northeast-2.amazonaws.com\0azure-mobile.net\0"
-"pa\0"
-"shisui.chiba.jp\0"
-"bulsan.it\0"
-"asso.ci\0gob.pa\0pe\0hkt\0"
-"sabae.fukui.jp\0goto.nagasaki.jp\0pf\0limo\0"
-"kv\xc3\xa6nangen.no\0levanger.no\0"
-"tsukigata.hokkaido.jp\0ph\0"
-"pi.it\0gob.pe\0ce.leg.br\0"
-"pk\0"
-"pl\0"
-"pm\0"
-"sorocaba.br\0pn\0"
-"gob.pk\0"
-"eng.br\0"
-"qa\0"
-"suedtirol.it\0langev\xc3\xa5g.no\0pr\0link\0"
-"ps\0farm\0"
-"ouchi.saga.jp\0notteroy.no\0pt\0"
-"sayo.hyogo.jp\0"
-"pw\0"
-"bas.it\0lunner.no\0"
-"izunokuni.shizuoka.jp\0stpetersburg.museum\0py\0"
-"notaires.fr\0nishikata.tochigi.jp\0lamborghini\0"
-"hakata.fukuoka.jp\0"
-"genova.it\0honjyo.akita.jp\0"
-"gehirn.ne.jp\0"
-"\xe3\x82\xaf\xe3\x83\xa9\xe3\x82\xa6\xe3\x83\x89\0"
-"azimuth.network\0"
-"bridgestone\0"
-"eu.com\0"
-"kofu.yamanashi.jp\0hawaii.museum\0re\0"
-"asso.dz\0"
-"basilicata.it\0oy.lc\0"
-"coach\0"
-"fast\0"
-"skaun.no\0"
-"gs.aa.no\0sale\0"
-"diskussionsbereich.de\0"
-"ro\0kherson.ua\0"
-"sa\0"
-"sb\0t.se\0"
-"indianapolis.museum\0rs\0sc\0"
-"hofu.yamaguchi.jp\0sd\0"
-"ru\0se\0"
-"rw\0sg\0"
-"sh\0"
-"si\0"
-"\xe7\xb6\xb2\xe7\xb5\xa1.cn\0pors\xc3\xa1\xc5\x8bgu.no\0sj\0"
-"sk\0"
-"sl\0"
-"sm\0cymru\0"
-"koganei.tokyo.jp\0sn\0gentapps.com\0"
-"so\0tunes\0verisign\0abkhazia.su\0"
-"beats\0"
-"loppa.no\0"
-"sr\0"
-"forsand.no\0ss\0tc\0est-a-la-masion.com\0"
-"kumamoto.jp\0st\0td\0"
-"su\0hot\0"
-"sv\0tf\0yamaxun\0"
-"aki.kochi.jp\0tg\0"
-"sx\0th\0how\0"
-"jewish.museum\0sy\0\xe7\xb6\xb2\xe7\xb5\xa1.\xe9\xa6\x99\xe6\xb8\xaf\0"
-"ebino.miyazaki.jp\0gob.sv\0sz\0tj\0"
-"tk\0likes-pie.com\0"
-"tl\0android\0"
-"tm\0"
-"tn\0"
-"to\0volvo\0wpdevcloud.com\0"
-"tsuga.tochigi.jp\0sarpsborg.no\0"
-"ua\0"
-"kanan.osaka.jp\0tr\0"
-"massacarrara.it\0tt\0"
-"cc.ua\0pt.eu.org\0"
-"tv\0"
-"tw\0ug\0"
-"tz\0cyon.link\0"
-"yamashina.kyoto.jp\0uk\0"
-"\xc3\xb8ksnes.no\0fam.pk\0"
-"nantan.kyoto.jp\0oe.yamagata.jp\0"
-"takamori.kumamoto.jp\0"
-"padova.it\0"
-"va\0"
-"gorlice.pl\0"
-"ginan.gifu.jp\0us\0vc\0"
-"ve\0"
-"vg\0"
-"trentino-sued-tirol.it\0k12.al.us\0uy\0gob.ve\0vi\0"
-"uz\0"
-"benevento.it\0marker.no\0"
-"synology-ds.de\0"
-"vao.it\0"
-"vn\0ibm\0"
-"living.museum\0"
-"yamagata.jp\0tcm.museum\0"
-"minamiawaji.hyogo.jp\0yosemite.museum\0vu\0\xd8\xa8\xd8\xa7\xd8\xb2\xd8\xa7\xd8\xb1\0homeunix.com\0"
-"wf\0ice\0"
-"cool\0"
-"amex\0"
-"coop\0sld.do\0"
-"sciencehistory.museum\0service.gov.uk\0"
-"oto.fukuoka.jp\0"
-"fujimi.nagano.jp\0sko.gov.pl\0"
-"ws\0"
-"icu\0"
-"\xe7\xb6\xb2\xe7\xb5\xa1.hk\0"
-"pohl\0"
-"lodi.it\0pv.it\0\xc3\xa5lesund.no\0brother\0"
-"live\0"
-"tome.miyagi.jp\0higashiyoshino.nara.jp\0gifts\0"
-"is-a-democrat.com\0"
-"zapto.org\0"
-"sarl\0"
-"forli-cesena.it\0"
-"mc.it\0*.ex.ortsinfo.at\0"
-"moskenes.no\0olayan\0"
-"nsw.edu.au\0"
-"maritime.museum\0halden.no\0"
-"fujioka.gunma.jp\0sand\xc3\xb8y.no\0"
-"utashinai.hokkaido.jp\0"
-"togura.nagano.jp\0yt\0"
-"yamada.iwate.jp\0"
-"mp.br\0ericsson\0"
-"\xe9\xa4\x90\xe5\x8e\x85\0"
-"mangyshlak.su\0"
-"minamiyamashiro.kyoto.jp\0"
-"\xe6\x94\xbf\xe5\x8a\xa1\0for.men\0"
-"shimofusa.chiba.jp\0zm\0"
-"ifm\0"
-"honjo.akita.jp\0potager.org\0"
-"muko.kyoto.jp\0"
-"zw\0"
-"kumakogen.ehime.jp\0"
-"discourse.team\0"
-"ouda.nara.jp\0kawagoe.saitama.jp\0\xe6\x9b\xb8\xe7\xb1\x8d\0"
-"*.cns.joyent.com\0"
-"kv.ua\0"
-"kariwa.niigata.jp\0cards\0"
-"naples.it\0helsinki.museum\0"
-"meraker.no\0"
-"lecco.it\0moriyoshi.akita.jp\0"
-"guge\0"
-"saltdal.no\0tr\xc3\xb8gstad.no\0"
-"nesset.no\0"
-"tenei.fukushima.jp\0bloxcms.com\0"
-"save\0"
-"friuli-venezia-giulia.it\0"
-"erni\0"
-"alstom\0hopto.org\0"
-"togo.aichi.jp\0"
-"katsuyama.fukui.jp\0publishproxy.com\0"
-"ybo.party\0"
-"ar.com\0"
-"takahashi.okayama.jp\0"
-"vercelli.it\0mordovia.su\0"
-"a.run.app\0"
-"chirurgiens-dentistes.fr\0hidaka.wakayama.jp\0"
-"student.aero\0culturalcenter.museum\0historichouses.museum\0freeboxos.com\0"
-"fortworth.museum\0k12.fl.us\0"
-"scotland.museum\0"
-"furukawa.miyagi.jp\0"
-"figueres.museum\0moscow.museum\0vestnes.no\0"
-"is-a-llama.com\0"
-"otaru.hokkaido.jp\0"
-"yamatsuri.fukushima.jp\0"
-"chuo.chiba.jp\0"
-"asso.re\0"
-"nosegawa.nara.jp\0gausdal.no\0trycloudflare.com\0hopto.me\0"
-"flog.br\0"
-"saxo\0"
-"podlasie.pl\0tube\0"
-"lib.ky.us\0"
-"komoro.nagano.jp\0"
-"edugit.org\0"
-"mordovia.ru\0"
-"como.it\0"
-"artgallery.museum\0"
-"anjo.aichi.jp\0"
-"nozawaonsen.nagano.jp\0ulsan.kr\0"
-"rc.it\0ssl.origin.cdn77-secure.org\0"
-"kimitsu.chiba.jp\0"
-"kiwa.mie.jp\0"
-"gs.nt.no\0lease\0r.cdn77.net\0"
-"kitahata.saga.jp\0s3-website.us-east-2.amazonaws.com\0"
-"elverum.no\0"
-"vlog.br\0nyny.museum\0"
-"yoshinogari.saga.jp\0www.ro\0"
-"\xe0\xaa\xad\xe0\xaa\xbe\xe0\xaa\xb0\xe0\xaa\xa4\0"
-"j\xc3\xb8rpeland.no\0"
-"emiliaromagna.it\0global.ssl.fastly.net\0"
-"coldwar.museum\0"
-"help\0"
-"jinsekikogen.hiroshima.jp\0marketing\0"
-"im.it\0"
-"sogne.no\0inc\0"
-"jaguar\0pgfog.com\0"
-"ing\0"
-"shinyoshitomi.fukuoka.jp\0"
-"omega\0"
-"porn\0"
-"ink\0loginline.dev\0"
-"koya.wakayama.jp\0sld.pa\0isla.pr\0"
-"hitachinaka.ibaraki.jp\0"
-"kahoku.ishikawa.jp\0nakagawa.tokushima.jp\0asso.nc\0"
-"tsurugi.ishikawa.jp\0"
-"agrigento.it\0"
-"kita.kyoto.jp\0uzhgorod.ua\0softbank\0"
-"shinjo.yamagata.jp\0"
-"nm.cn\0caseih\0"
-"int\0"
-"e.bg\0dd-dns.de\0"
-"accident-investigation.aero\0akaiwa.okayama.jp\0crafts.museum\0"
-"ag.it\0kuriyama.hokkaido.jp\0tsuruoka.yamagata.jp\0"
-"mutsu.aomori.jp\0kunstunddesign.museum\0virginia.museum\0"
-"matsuura.nagasaki.jp\0"
-"valleeaoste.it\0"
-"beauxarts.museum\0"
-"shonai.fukuoka.jp\0"
-"kamogawa.chiba.jp\0"
-"b\xc3\xa1hccavuotna.no\0\xc3\xb8yer.no\0post\0"
-"utwente.io\0"
-"go.leg.br\0"
-"vf.no\0\xe9\xa6\x99\xe6\xb8\xaf\0"
-"aerodrome.aero\0psc.br\0sandefjord.no\0\xe3\x82\xb0\xe3\x83\xbc\xe3\x82\xb0\xe3\x83\xab\0"
-"gamo.shiga.jp\0"
-"ftpaccess.cc\0"
-"nakamichi.yamanashi.jp\0"
-"web.bo\0capebreton.museum\0sn\xc3\xa5""ase.no\0"
-"tozsde.hu\0lapy.pl\0"
-"agdenes.no\0"
-"markets\0cnpy.gdn\0"
-"loginline.site\0"
-"org.ac\0swidnik.pl\0"
-"org.ae\0"
-"org.af\0"
-"org.ag\0"
-"susaki.kochi.jp\0"
-"org.ai\0pavia.it\0e4.cz\0"
-"web.co\0flora.no\0"
-"kami.kochi.jp\0"
-"org.al\0otari.nagano.jp\0"
-"org.am\0"
-"flesberg.no\0"
-"engineer.aero\0taira.toyama.jp\0"
-"pictet\0"
-"org.ba\0uhren.museum\0"
-"org.ar\0org.bb\0imperia.it\0chuo.fukuoka.jp\0komagane.nagano.jp\0"
-"sayama.osaka.jp\0tama.tokyo.jp\0"
-"org.au\0chiryu.aichi.jp\0"
-"org.bh\0"
-"org.bi\0"
-"org.az\0web.do\0selfip.biz\0"
-"jcb\0"
-"org.bm\0"
-"org.bn\0mo-i-rana.no\0here\0"
-"org.bo\0"
-"org.br\0"
-"org.bs\0"
-"org.bt\0"
-"org.bw\0"
-"masaki.ehime.jp\0britishcolumbia.museum\0"
-"org.ci\0jcp\0"
-"org.bz\0"
-"vs.it\0aukra.no\0"
-"yatsushiro.kumamoto.jp\0oslo.no\0ist\0"
-"org.cn\0guru\0"
-"org.co\0gs.st.no\0s3.dualstack.ap-southeast-1.amazonaws.com\0"
-"hiranai.aomori.jp\0koshu.yamanashi.jp\0"
-"asso.km\0"
-"n\xc3\xb8tter\xc3\xb8y.no\0"
-"org.cu\0aga.niigata.jp\0manchester.museum\0privatizehealthinsurance.net\0"
-"org.cw\0noboribetsu.hokkaido.jp\0kvanangen.no\0"
-"servebbs.net\0"
-"org.cy\0karasuyama.tochigi.jp\0"
-"iz.hr\0school.za\0"
-"homeftp.org\0"
-"org.dm\0wsa.gov.pl\0isa.us\0"
-"maebashi.gunma.jp\0narusawa.yamanashi.jp\0"
-"org.do\0itv\0ninja\0"
-"toya.hokkaido.jp\0"
-"org.ec\0"
-"port.fr\0kumatori.osaka.jp\0circus.museum\0construction\0"
-"org.ee\0"
-"org.eg\0asso.mc\0natuurwetenschappen.museum\0"
-"org.dz\0shiga.jp\0url.tw\0googlecode.com\0"
-"bhz.br\0bahcavuotna.no\0"
-"defense.tn\0\xe7\x8f\xa0\xe5\xae\x9d\0"
-"minamata.kumamoto.jp\0"
-"web.gu\0tank.museum\0myfast.space\0"
-"org.es\0"
-"org.et\0"
-"fg.it\0asahi.chiba.jp\0yamato.fukushima.jp\0fauske.no\0"
-"org.fj\0arai.shizuoka.jp\0"
-"drobak.no\0"
-"rifu.miyagi.jp\0"
-"pisa.it\0"
-"web.id\0"
-"axis.museum\0"
-"r.bg\0flowers\0"
-"yawata.kyoto.jp\0balestrand.no\0"
-"at.it\0"
-"org.ge\0"
-"org.gg\0"
-"org.gh\0"
-"org.gi\0foggia.it\0tromso.no\0*.landing.myjino.ru\0"
-"paroch.k12.ma.us\0"
-"org.gl\0jessheim.no\0"
-"koka.shiga.jp\0"
-"org.gn\0trentinsud-tirol.it\0promo\0"
-"org.gp\0"
-"dyndns-server.com\0"
-"org.gr\0"
-"for.mom\0"
-"gd.cn\0org.gt\0"
-"org.gu\0repl.run\0siteleaf.net\0"
-"ipifony.net\0"
-"from-al.com\0"
-"\xc3\xa1lt\xc3\xa1.no\0"
-"org.gy\0channelsdvr.net\0"
-"history.museum\0energy\0"
-"org.hk\0"
-"org.hn\0vevelstad.no\0"
-"hakuba.nagano.jp\0"
-"anthropology.museum\0mazowsze.pl\0cloud\0"
-"org.ht\0"
-"org.hu\0cleaning\0"
-"jio\0"
-"hakone.kanagawa.jp\0"
-"krodsherad.no\0extraspace\0"
-"linz.museum\0"
-"org.il\0"
-"org.im\0tsushima.aichi.jp\0dreamhosters.com\0"
-"org.in\0cc.pa.us\0"
-"lib.vi.us\0myddns.rocks\0"
-"org.iq\0kristiansund.no\0est.pr\0"
-"org.ir\0vallee-aoste.it\0"
-"org.is\0"
-"\xe1\x83\x92\xe1\x83\x94\0"
-"ambulance.aero\0org.je\0"
-"kasukabe.saitama.jp\0web.lk\0frosta.no\0"
-"lyngen.no\0t\xc3\xb8nsberg.no\0"
-"ogata.akita.jp\0"
-"turystyka.pl\0"
-"ma.gov.br\0mymailer.com.tw\0"
-"tsubata.ishikawa.jp\0"
-"fnd.br\0org.jo\0ca-central-1.elasticbeanstalk.com\0"
-"\xe9\x9b\x86\xe5\x9b\xa2\0"
-"moscow\0"
-"*.webhare.dev\0"
-"org.kg\0"
-"imb.br\0labor.museum\0"
-"tokorozawa.saitama.jp\0org.ki\0"
-"cust.disrec.thingdust.io\0"
-"org.km\0"
-"org.kn\0"
-"konyvelo.hu\0"
-"org.kp\0"
-"bergamo.it\0org.la\0web.nf\0\xd9\xbe\xd8\xa7\xda\xa9\xd8\xb3\xd8\xaa\xd8\xa7\xd9\x86\0"
-"ichihara.chiba.jp\0org.lb\0"
-"org.lc\0muosat.no\0"
-"web.ni\0"
-"ohtawara.tochigi.jp\0fujixerox\0jll\0"
-"org.kw\0"
-"hakusan.ishikawa.jp\0org.ky\0burghof.museum\0"
-"org.kz\0"
-"udono.mie.jp\0org.lk\0"
-"stor-elvdal.no\0"
-"tas.edu.au\0"
-"numazu.shizuoka.jp\0"
-"org.ma\0drive\0"
-"yashiro.hyogo.jp\0org.lr\0salvadordali.museum\0"
-"org.ls\0krasnik.pl\0"
-"doshi.yamanashi.jp\0"
-"org.me\0"
-"org.lv\0ddnss.de\0"
-"org.mg\0stathelle.no\0"
-"gushikami.okinawa.jp\0"
-"org.ly\0jmp\0"
-"org.mk\0"
-"org.ml\0us-east-2.elasticbeanstalk.com\0dynalias.net\0cust.prod.thingdust.io\0"
-"org.mn\0dynathome.net\0"
-"org.mo\0for-some.biz\0"
-"oki.fukuoka.jp\0reisen\0"
-"hamura.tokyo.jp\0org.na\0law.pro\0"
-"wada.nagano.jp\0alwaysdata.net\0"
-"narashino.chiba.jp\0miyota.nagano.jp\0org.ms\0jnj\0"
-"fukaya.saitama.jp\0org.mt\0"
-"tj.cn\0org.mu\0"
-"org.mv\0web.pk\0nfshost.com\0"
-"org.mw\0org.ng\0"
-"org.mx\0"
-"hasuda.saitama.jp\0org.my\0org.ni\0"
-"eun.eg\0org.mz\0s\xc3\xb8rfold.no\0verm\xc3\xb6gensberatung\0"
-"weather\0"
-"tatsuno.nagano.jp\0"
-"user.srcf.net\0"
-"dst.mi.us\0se.net\0ru.net\0"
-"oyamazaki.kyoto.jp\0shinjuku.tokyo.jp\0"
-"org.nr\0"
-"n\xc3\xa1vuotna.no\0"
-"ca.it\0"
-"dating\0"
-"from-fl.com\0barsy.online\0"
-"org.nz\0"
-"website\0b-data.io\0uk.com\0kustanai.ru\0"
-"nord-odal.no\0"
-"kg.kr\0org.om\0e.se\0jot\0selfip.com\0"
-"from-ak.com\0"
-"org.pa\0"
-"educational.museum\0joy\0"
-"yamato.kumamoto.jp\0"
-"bd.se\0"
-"org.pe\0"
-"ha.cn\0org.pf\0"
-"mihama.wakayama.jp\0org.ph\0"
-"\xe6\xb2\x96\xe7\xb8\x84.jp\0org.pk\0kustanai.su\0"
-"org.pl\0"
-"ann-arbor.mi.us\0"
-"chitose.hokkaido.jp\0org.pn\0"
-"prochowice.pl\0"
-"org.qa\0nm.us\0fastvps.site\0"
-"gaular.no\0org.pr\0"
-"org.ps\0"
-"hol.no\0org.pt\0"
-"americana.museum\0filegear-jp.me\0"
-"org.py\0"
-"irish\0"
-"erimo.hokkaido.jp\0sandnes.no\0"
-"no-ip.biz\0"
-"jondal.no\0scor\0"
-"sakaiminato.tottori.jp\0scot\0"
-"okutama.tokyo.jp\0web.tj\0"
-"iris.arpa\0"
-"skjerv\xc3\xb8y.no\0"
-"fuji.shizuoka.jp\0"
-"web.tr\0"
-"sar.it\0org.ro\0futurehosting.at\0"
-"org.sa\0dattolocal.net\0"
-"ca.na\0org.sb\0beta.bounty-full.com\0"
-"elk.pl\0org.rs\0org.sc\0"
-"org.sd\0qc.com\0"
-"org.se\0org.ru\0"
-"org.rw\0org.sg\0"
-"org.sh\0"
-"dyndns-mail.com\0"
-"ragusa.it\0"
-"org.sl\0"
-"org.sn\0"
-"org.so\0"
-"ishikawa.jp\0web.ve\0mypets.ws\0"
-"cc.de.us\0"
-"campidanomedio.it\0"
-"org.ss\0"
-"seirou.niigata.jp\0org.st\0audio\0dyndns1.de\0"
-"akita.jp\0melhus.no\0walbrzych.pl\0org.sv\0"
-"org.sy\0"
-"org.sz\0org.tj\0"
-"caa.aero\0"
-"pharmaciens.km\0org.tm\0"
-"org.tn\0"
-"shiso.hyogo.jp\0uslivinghistory.museum\0org.to\0"
-"kawakami.nagano.jp\0"
-"org.ua\0"
-"org.tr\0"
-"shiftedit.io\0"
-"org.tt\0wien\0"
-"jogasz.hu\0pg.it\0maibara.shiga.jp\0countryestate.museum\0"
-"org.tw\0org.ug\0"
-"happou.akita.jp\0"
-"org.uk\0"
-"xz.cn\0kiso.nagano.jp\0kopervik.no\0"
-"flakstad.no\0"
-"vlaanderen.museum\0"
-"sandcats.io\0"
-"kfh\0"
-"swatch\0"
-"nishio.aichi.jp\0org.vc\0\xe5\xa4\xa7\xe4\xbc\x97\xe6\xb1\xbd\xe8\xbd\xa6\0"
-"s\xc3\xa1l\xc3\xa1t.no\0"
-"org.ve\0watches\0"
-"tw.cn\0"
-"org.uy\0org.vi\0ddnslive.com\0"
-"org.uz\0"
-"sanagochi.tokushima.jp\0nowaruda.pl\0prudential\0"
-"nesna.no\0org.vn\0"
-"hidaka.hokkaido.jp\0hamamatsu.shizuoka.jp\0shirataka.yamagata.jp\0amsw.nl\0telebit.io\0"
-"balat.no\0restaurant\0"
-"data\0"
-"org.vu\0"
-"sm.ua\0"
-"cn.it\0kamishihoro.hokkaido.jp\0casacam.net\0"
-"date\0mydatto.net\0"
-"kaneyama.yamagata.jp\0afamilycompany\0*.platformsh.site\0"
-"perso.ht\0kagoshima.kagoshima.jp\0"
-"tarui.gifu.jp\0b\xc3\xa6rum.no\0web.za\0couchpotatofries.org\0rhcloud.com\0"
-"amot.no\0gjemnes.no\0"
-"r.se\0"
-"colonialwilliamsburg.museum\0org.ws\0\xe0\xb8\xa8\xe0\xb8\xb6\xe0\xb8\x81\xe0\xb8\xa9\xe0\xb8\xb2.\xe0\xb9\x84\xe0\xb8\x97\xe0\xb8\xa2\0"
-"higashikurume.tokyo.jp\0spdns.org\0"
-"\xc3\xb8stre-toten.no\0"
-"ashiya.fukuoka.jp\0oi.kanagawa.jp\0"
-"hn.cn\0"
-"kia\0"
-"goodyear\0is-a-nascarfan.com\0"
-"firestone\0"
-"shiroishi.saga.jp\0\xc3\xb8vre-eiker.no\0"
-"rsvp\0"
-"jgora.pl\0"
-"takehara.hiroshima.jp\0"
-"kutchan.hokkaido.jp\0k12.mi.us\0"
-"nordre-land.no\0komvux.se\0kim\0"
-"watari.miyagi.jp\0"
-"matsuzaki.shizuoka.jp\0"
-"kochi.kochi.jp\0"
-"bunkyo.tokyo.jp\0"
-"miyama.fukuoka.jp\0"
-"walter\0"
-"org.za\0"
-"fussa.tokyo.jp\0\xe0\xae\x9a\xe0\xae\xbf\xe0\xae\x99\xe0\xaf\x8d\xe0\xae\x95\xe0\xae\xaa\xe0\xaf\x8d\xe0\xae\xaa\xe0\xaf\x82\xe0\xae\xb0\xe0\xaf\x8d\0"
-"katsuura.chiba.jp\0"
-"kaho.fukuoka.jp\0"
-"gamagori.aichi.jp\0"
-"kitakata.fukushima.jp\0"
-"org.zm\0"
-"wiki\0"
-"tatsuno.hyogo.jp\0imari.saga.jp\0"
-"sowa.ibaraki.jp\0cloudcontrolapp.com\0*.sys.qcx.io\0"
-"ca.us\0"
-"yamada.toyama.jp\0ha.no\0org.zw\0"
-"from-nh.com\0"
-"niikappu.hokkaido.jp\0l\xc3\xb8renskog.no\0"
-"oksnes.no\0*.compute.estate\0"
-"myeffect.net\0"
-"tosu.saga.jp\0"
-"higashimatsuyama.saitama.jp\0"
-"hemnes.no\0"
-"soja.okayama.jp\0"
-"aparecida.br\0\xe5\xaf\x8c\xe5\xb1\xb1.jp\0"
-"macapa.br\0"
-"tomigusuku.okinawa.jp\0"
-"movimiento.bo\0casadelamoneda.museum\0"
-"vard\xc3\xb8.no\0"
-"togane.chiba.jp\0samegawa.fukushima.jp\0lierne.no\0"
-"mckinsey\0"
-"is-slick.com\0"
-"pt.it\0"
-"mitoyo.kagawa.jp\0\xc3\xa5seral.no\0hicam.net\0"
-"ostre-toten.no\0"
-"wine\0"
-"hichiso.gifu.jp\0"
-"yasugi.shimane.jp\0"
-"dynns.com\0"
-"fukuchi.fukuoka.jp\0"
-"saito.miyazaki.jp\0"
-"bolivia.bo\0ap-northeast-2.elasticbeanstalk.com\0"
-"app.lmpm.com\0"
-"nishiaizu.fukushima.jp\0fukushima.hokkaido.jp\0bjugn.no\0loginline.services\0"
-"rawa-maz.pl\0"
-"nishikawa.yamagata.jp\0dnsupdate.info\0"
-"ybo.trade\0"
-"toyota.aichi.jp\0"
-"xs4all.space\0"
-"sanofi\0"
-"lukow.pl\0"
-"football\0"
-"001www.com\0"
-"soni.nara.jp\0"
-"sciencecenters.museum\0uber.space\0"
-"shizuoka.jp\0shiriuchi.hokkaido.jp\0app.os.fedoraproject.org\0"
-"h\xc3\xa4kkinen.fi\0"
-"patria.bo\0"
-"kaas.gg\0"
-"kpn\0"
-"oketo.hokkaido.jp\0"
-"koshigaya.saitama.jp\0homeftp.net\0"
-"nishinoomote.kagoshima.jp\0shioya.tochigi.jp\0"
-"mihama.fukui.jp\0"
-"shimokawa.hokkaido.jp\0tainai.niigata.jp\0codes\0"
-"aju.br\0pl.eu.org\0"
-"tochio.niigata.jp\0"
-"computerhistory.museum\0"
-"miasa.nagano.jp\0"
-"viking\0"
-"*.yokohama.jp\0"
-"clinic\0"
-"abruzzo.it\0sakegawa.yamagata.jp\0k12.nh.us\0"
-"val-daosta.it\0hinode.tokyo.jp\0us-4.evennode.com\0"
-"rzgw.gov.pl\0"
-"hidaka.kochi.jp\0"
-"okagaki.fukuoka.jp\0"
-"krd\0lat\0"
-"creation.museum\0"
-"gj\xc3\xb8vik.no\0\xd0\xba\xd0\xb0\xd1\x82\xd0\xbe\xd0\xbb\xd0\xb8\xd0\xba\0"
-"fukushima.jp\0law\0"
-"usui.fukuoka.jp\0"
-"kasai.hyogo.jp\0oishida.yamagata.jp\0"
-"hanyu.saitama.jp\0cn.ua\0"
-"dentist\0shriram\0"
-"seiyo.ehime.jp\0bremanger.no\0"
-"!www.ck\0"
-"for.sale\0"
-"lowicz.pl\0"
-"shiogama.miyagi.jp\0"
-"yoita.niigata.jp\0"
-"cc.ne.us\0"
-"etnedal.no\0"
-"\xe0\xb9\x80\xe0\xb8\x99\xe0\xb9\x87\xe0\xb8\x95.\xe0\xb9\x84\xe0\xb8\x97\xe0\xb8\xa2\0"
-"blogsite.org\0"
-"valdaosta.it\0nomi.ishikawa.jp\0"
-"arna.no\0"
-"luster.no\0xenapponazure.com\0"
-"equipment.aero\0"
-"lig.it\0"
-"sydney\0"
-"seat\0"
-"nowtv\0"
-"kongsberg.no\0"
-"thruhere.net\0"
-"motosu.gifu.jp\0aridagawa.wakayama.jp\0lds\0"
-"bristol.museum\0"
-"nahari.kochi.jp\0cc.al.us\0"
-"chambagri.fr\0"
-"wa.au\0"
-"trentino-suedtirol.it\0hashikami.aomori.jp\0"
-"xfinity\0"
-"wiki.bo\0"
-"barclays\0us-3.evennode.com\0"
-"prd.fr\0"
-"wiki.br\0ra.it\0"
-"lib.ca.us\0"
-"yoka.hyogo.jp\0ina.ibaraki.jp\0yono.saitama.jp\0film.museum\0hgtv\0"
-"southwest.museum\0skien.no\0ybo.faith\0"
-"mn.it\0"
-"odo.br\0"
-"myasustor.com\0"
-"\xc3\xa5mli.no\0fjell.no\0"
-"uruma.okinawa.jp\0"
-"funahashi.toyama.jp\0for.one\0"
-"mg.gov.br\0malopolska.pl\0"
-"rygge.no\0"
-"ras.ru\0"
-"aizumi.tokushima.jp\0"
-"matsuda.kanagawa.jp\0sytes.net\0"
-"zao.miyagi.jp\0"
-"b\xc3\xa1id\xc3\xa1r.no\0griw.gov.pl\0"
-"s3-ap-southeast-2.amazonaws.com\0"
-"wajima.ishikawa.jp\0seek\0"
-"schweiz.museum\0"
-"okawa.fukuoka.jp\0"
-"gaivuotna.no\0"
-"ariake.saga.jp\0gda.pl\0"
-"k12.wi.us\0"
-"c.bg\0"
-"artsandcrafts.museum\0d\xc3\xb8nna.no\0*.dapps.earth\0"
-"ostrowiec.pl\0alpha.bounty-full.com\0"
-"cooperativa.bo\0servebbs.org\0"
-"press.museum\0"
-"git-repos.de\0"
-"loginline.app\0"
-"omaha.museum\0ath.cx\0"
-"valer.hedmark.no\0"
-"macerata.it\0ustka.pl\0"
-"nichinan.miyazaki.jp\0h\xc3\xa1""bmer.no\0"
-"apple\0"
-"inabe.mie.jp\0verdal.no\0"
-"inashiki.ibaraki.jp\0"
-"us-2.evennode.com\0"
-"ogose.saitama.jp\0k12.ok.us\0"
-"gokase.miyazaki.jp\0"
-"satosho.okayama.jp\0"
-"veneto.it\0"
-"keisen.fukuoka.jp\0motoyama.kochi.jp\0cdn77-ssl.net\0"
-"midori.chiba.jp\0otaki.saitama.jp\0"
-"\xe7\xb5\x84\xe7\xb9\x94.tw\0"
-"ma.us\0al.eu.org\0"
-"prd.km\0perso.sn\0familyds.com\0"
-"varggat.no\0"
-"flickr\0"
-"nemuro.hokkaido.jp\0"
-"prod\0"
-"prof\0supply\0"
-"scientist.aero\0"
-"tomobe.ibaraki.jp\0contemporaryart.museum\0"
-"ruhr\0"
-"ginowan.okinawa.jp\0"
-"perso.tn\0"
-"kanuma.tochigi.jp\0"
-"takazaki.miyazaki.jp\0"
-"cng.br\0"
-"api.stdlib.com\0"
-"hiroo.hokkaido.jp\0llc\0"
-"prd.mg\0"
-"nakatane.kagoshima.jp\0"
-"hanawa.fukushima.jp\0"
-"bajddar.no\0is-very-evil.org\0"
-"toyono.osaka.jp\0*.compute.amazonaws.com.cn\0"
-"bellevue.museum\0"
-"cc.fl.us\0"
-"marylhurst.museum\0"
-"balsan-s\xc3\xbc""dtirol.it\0oji.nara.jp\0llp\0"
-"targi.pl\0oya.to\0"
-"hapmir.no\0"
-"mizumaki.fukuoka.jp\0de.com\0ashgabad.su\0"
-"services.aero\0"
-"discourse.group\0"
-"rocks\0"
-"pvt.ge\0"
-"erotica.hu\0"
-"nes.akershus.no\0\xd9\x85\xd9\x84\xd9\x8a\xd8\xb3\xd9\x8a\xd8\xa7\0"
-"us-1.evennode.com\0"
-"owariasahi.aichi.jp\0"
-"rn.it\0jan-mayen.no\0"
-"dep.no\0"
-"zgorzelec.pl\0"
-"kanonji.kagawa.jp\0"
-"friuli-v-giulia.it\0"
-"wellbeingzone.eu\0"
-"sk.ca\0"
-"taiki.hokkaido.jp\0showtime\0"
-"endofinternet.net\0"
-"is-a-liberal.com\0"
-"webhop.org\0caa.li\0"
-"safety.aero\0komae.tokyo.jp\0"
-"intl.tn\0"
-"\xe9\x9d\x92\xe6\xa3\xae.jp\0ishikawa.fukushima.jp\0abo.pa\0limanowa.pl\0"
-"bosch\0"
-"lol\0s3-eu-west-2.amazonaws.com\0"
-"fitjar.no\0"
-"d.gv.vc\0"
-"qld.au\0"
-"anani.br\0forl\xc3\xac-cesena.it\0"
-"namegata.ibaraki.jp\0porsangu.no\0green\0"
-"fe.it\0*.on-rio.io\0"
-"ukiha.fukuoka.jp\0dclk\0go.dyndns.org\0"
-"\xe0\xa4\xa8\xe0\xa5\x87\xe0\xa4\x9f\0"
-"cancerresearch\0"
-"hirosaki.aomori.jp\0baby\0"
-"luroy.no\0"
-"nx.cn\0"
-"allfinanz\0"
-"lpl\0"
-"p.bg\0"
-"ar.it\0"
-"orange\0tennis\0us-west-1.elasticbeanstalk.com\0"
-"childrensgarden.museum\0"
-"swinoujscie.pl\0"
-"ut.us\0"
-"blogspot.com.cy\0"
-"vanylven.no\0"
-"shinshinotsu.hokkaido.jp\0does-it.net\0filegear-gb.me\0"
-"man\0"
-"accountants\0"
-"map\0"
-"mba\0"
-"kppsp.gov.pl\0"
-"toyonaka.osaka.jp\0blogspot.com.ee\0"
-"from-ne.com\0"
-"c.la\0blogspot.com.eg\0"
-"dynalias.org\0"
-"witd.gov.pl\0"
-"mn.us\0"
-"zaporizhzhe.ua\0"
-"ichinomiya.chiba.jp\0glas.museum\0"
-"lviv.ua\0"
-"blogspot.com.ar\0"
-"otsu.shiga.jp\0bushey.museum\0"
-"delta\0"
-"mitane.akita.jp\0blogspot.com.au\0"
-"iruma.saitama.jp\0"
-"usarts.museum\0wolomin.pl\0"
-"l\xc3\xb8ten.no\0gdansk.pl\0"
-"minoh.osaka.jp\0"
-"koriyama.fukushima.jp\0safety\0customer.enonic.io\0"
-"redstone\0blogspot.com.br\0"
-"itabashi.tokyo.jp\0"
-"cnt.br\0kyoto.jp\0watch\0"
-"ltd\0"
-"kui.hiroshima.jp\0"
-"\xe7\xbd\x91\xe7\xb5\xa1.hk\0wodzislaw.pl\0"
-"blogspot.com.by\0"
-"arboretum.museum\0"
-"jewelry.museum\0"
-"artanddesign.museum\0"
-"eaton.mi.us\0"
-"blogspot.com.co\0firewall-gateway.com\0"
-"goshiki.hyogo.jp\0"
-"chernigov.ua\0"
-"stavanger.no\0"
-"lib.ma.us\0"
-"firewall-gateway.de\0"
-"media.museum\0med\0passagens\0"
-"utazu.kagawa.jp\0nerima.tokyo.jp\0"
-"carrier.museum\0"
-"tynset.no\0"
-"ltd.cy\0men\0"
-"servegame.com\0"
-"stateofdelaware.museum\0from-md.com\0"
-"perugia.it\0"
-"blogspot.com.es\0"
-"suzaka.nagano.jp\0"
-"toyota.yamaguchi.jp\0rodeo\0woodside\0no.eu.org\0"
-"ikeda.osaka.jp\0scjohnson\0"
-"bielawa.pl\0"
-"monza-e-della-brianza.it\0"
-"ichikawa.chiba.jp\0zt.ua\0"
-"neues.museum\0vaporcloud.io\0"
-"nic.in\0!city.kitakyushu.jp\0os\xc3\xb8yro.no\0serveminecraft.net\0"
-"pe.ca\0"
-"sx.cn\0nishikatsura.yamanashi.jp\0"
-"brand.se\0"
-"mo-siemens.io\0"
-"fr.it\0ontario.museum\0"
-"naha.okinawa.jp\0es.leg.br\0"
-"rollag.no\0"
-"ltd.gi\0"
-"ascolipiceno.it\0"
-"wlocl.pl\0statefarm\0"
-"bo.it\0navoi.su\0"
-"school\0"
-"reg.dk\0"
-"mishima.fukushima.jp\0"
-"shikatsu.aichi.jp\0"
-"askvoll.no\0quicksytes.com\0"
-"oxford.museum\0wa.us\0"
-"norfolk.museum\0c.se\0"
-"hitachi.ibaraki.jp\0salat.no\0"
-"mil\0antiques.museum\0properties\0"
-"go.ci\0ae.org\0"
-"\xe7\xb5\x84\xe7\xb9\x94.\xe9\xa6\x99\xe6\xb8\xaf\0"
-"aetna\0ltd.hk\0"
-"nakagawa.nagano.jp\0"
-"giessen.museum\0"
-"qld.gov.au\0"
-"komaki.aichi.jp\0kraanghke.no\0realestate.pl\0mit\0"
-"go.cr\0"
-"zarow.pl\0"
-"kira.aichi.jp\0misato.akita.jp\0bungoono.oita.jp\0"
-"in-dsl.de\0"
-"poznan.pl\0"
-"mo\xc3\xa5reke.no\0sokndal.no\0"
-"chonan.chiba.jp\0"
-"fidelity\0"
-"adv.br\0"
-"arakawa.saitama.jp\0band\0"
-"nishiokoppe.hokkaido.jp\0oppeg\xc3\xa5rd.no\0*.telebit.xyz\0"
-"cesenaforl\xc3\xac.it\0"
-"narvik.no\0"
-"kawanishi.nara.jp\0bank\0church\0"
-"trentinos\xc3\xbc""d-tirol.it\0"
-"sexy\0router.management\0"
-"mlb\0"
-"s\xc3\xb8gne.no\0"
-"lombardy.it\0bievat.no\0"
-"cc.ky.us\0"
-"tempio-olbia.it\0"
-"trentinsudtirol.it\0"
-"hashima.gifu.jp\0"
-"ar.us\0"
-"mma\0"
-"koto.shiga.jp\0leclerc\0"
-"miho.ibaraki.jp\0mls\0"
-"online.museum\0nz.eu.org\0"
-"donetsk.ua\0"
-"iwanai.hokkaido.jp\0sola.no\0"
-"higashikawa.hokkaido.jp\0"
-"anan.tokushima.jp\0"
-"uscountryestate.museum\0"
-"\xe7\xb5\x84\xe7\xb9\x94.hk\0servemp3.com\0"
-"shop.ht\0cc.dc.us\0"
-"shop.hu\0monzaebrianza.it\0achi.nagano.jp\0"
-"ltd.lk\0barrel-of-knowledge.info\0"
-"gs.oslo.no\0arab\0"
-"hashbang.sh\0"
-"ismaili\0isa-geek.org\0"
-"airtraffic.aero\0loginto.me\0"
-"\xd1\x83\xd0\xbf\xd1\x80.\xd1\x81\xd1\x80\xd0\xb1\0"
-"emergency.aero\0toda.saitama.jp\0"
-"yamagata.yamagata.jp\0"
-"saskatchewan.museum\0"
-"sado.niigata.jp\0tgory.pl\0"
-"pe.it\0miyazaki.jp\0blogspot.com.mt\0"
-"moe\0blogspot.com.ng\0"
-"shiiba.miyazaki.jp\0"
-"go.id\0\xe9\xa6\x99\xe5\xb7\x9d.jp\0"
-"moi\0"
-"my-firewall.org\0"
-"verona.it\0ltd.ng\0"
-"kr.it\0sejny.pl\0mom\0\xd8\xb4\xd8\xa8\xd9\x83\xd8\xa9\0"
-"decorativearts.museum\0"
-"nationwide\0"
-"buyshouses.net\0"
-"loan\0"
-"sa.com\0"
-"mov\0"
-"\xe4\xb8\xad\xe6\x96\x87\xe7\xbd\x91\0barsycenter.com\0"
-"go.it\0*.oci.customer-oci.com\0from-de.com\0"
-"komono.mie.jp\0"
-"daejeon.kr\0kongsvinger.no\0download\0"
-"koga.ibaraki.jp\0"
-"hokuto.yamanashi.jp\0"
-"pe.kr\0"
-"nab\0"
-"cl.it\0"
-"go.jp\0"
-"delmenhorst.museum\0"
-"ballooning.aero\0frogn.no\0"
-"yugawara.kanagawa.jp\0"
-"vaksdal.no\0int.eu.org\0"
-"setouchi.okayama.jp\0go.ke\0"
-"p.se\0"
-"express.aero\0target\0"
-"blogspot.com.tr\0"
-"nba\0*.otap.co\0"
-"hl.cn\0mochizuki.nagano.jp\0"
-"stockholm\0"
-"go.kr\0"
-"sassari.it\0paris.eu.org\0"
-"nic.tj\0east-kazakhstan.su\0"
-"onga.fukuoka.jp\0"
-"unusualperson.com\0"
-"chofu.tokyo.jp\0"
-"oh.us\0"
-"tushu\0rackmaze.com\0"
-"edunet.tn\0s3-website-ap-southeast-1.amazonaws.com\0"
-"monza.it\0heguri.nara.jp\0msd\0"
-"ogimi.okinawa.jp\0oregontrail.museum\0"
-"tanabe.wakayama.jp\0"
-"nhs.uk\0"
-"tatebayashi.gunma.jp\0nishiazai.shiga.jp\0meeres.museum\0blackfriday\0doctor\0"
-"tado.mie.jp\0diskstation.org\0"
-"komatsu.ishikawa.jp\0yorkshire.museum\0h\xc3\xa5.no\0"
-"caserta.it\0bus.museum\0myds.me\0"
-"lib.wa.us\0"
-"tsuruta.aomori.jp\0england.museum\0"
-"idrett.no\0"
-"kahoku.yamagata.jp\0"
-"matsusaka.mie.jp\0cloudns.biz\0"
-"\xe5\xb2\xa9\xe6\x89\x8b.jp\0miners.museum\0"
-"\xd0\xba\xd0\xbe\xd0\xbc\0"
-"kihoku.ehime.jp\0madrid.museum\0"
-"togakushi.nagano.jp\0imizu.toyama.jp\0afjord.no\0tickets\0"
-"iida.nagano.jp\0vagan.no\0"
-"casino\0"
-"ven.it\0r\xc3\xb8yrvik.no\0metlife\0"
-"is.gov.pl\0"
-"mtn\0"
-"trentinsued-tirol.it\0"
-"\xe0\xb0\xad\xe0\xb0\xbe\xe0\xb0\xb0\xe0\xb0\xa4\xe0\xb1\x8d\0hobby-site.org\0"
-"shari.hokkaido.jp\0ina.nagano.jp\0dr\xc3\xb8""bak.no\0mtr\0"
-"nec\0"
-"is-by.us\0"
-"ikata.ehime.jp\0deal\0"
-"kaneyama.fukushima.jp\0lutsk.ua\0s3-us-east-2.amazonaws.com\0"
-"loft\0"
-"samnanger.no\0"
-"seoul.kr\0"
-"isehara.kanagawa.jp\0"
-"net\0"
-"harima.hyogo.jp\0"
-"ltd.ua\0"
-"rivne.ua\0new\0groks-this.info\0"
-"adv.mz\0"
-"mashike.hokkaido.jp\0"
-"nfl\0"
-"nom.ad\0field.museum\0"
-"nom.ae\0"
-"nom.af\0"
-"nom.ag\0ltd.uk\0"
-"nom.ai\0"
-"pr.it\0dyr\xc3\xb8y.no\0temasek\0is-a-hunter.com\0"
-"nom.al\0"
-"chocolate.museum\0"
-"blogspot.com.uy\0"
-"kamikitayama.nara.jp\0rauma.no\0"
-"flatanger.no\0is-with-theband.com\0remotewd.com\0"
-"gok.pk\0"
-"kitagata.gifu.jp\0mito.ibaraki.jp\0go.pw\0\xd9\x82\xd8\xb7\xd8\xb1\0"
-"omura.nagasaki.jp\0"
-"furano.hokkaido.jp\0"
-"lo.it\0stord.no\0nic.za\0ngo\0zappos\0"
-"*.kobe.jp\0"
-"ringebu.no\0"
-"ninomiya.kanagawa.jp\0"
-"piacenza.it\0tselinograd.su\0"
-"from-pr.com\0"
-"nhk\0"
-"zoological.museum\0"
-"dontexist.net\0"
-"waw.pl\0"
-"ac.ae\0nom.bz\0"
-"minato.osaka.jp\0"
-"nom.cl\0"
-"center.museum\0eng.pro\0"
-"fortal.br\0nom.co\0"
-"hidaka.saitama.jp\0"
-"alaska.museum\0alvdal.no\0"
-"k12.ut.us\0"
-"asahikawa.hokkaido.jp\0"
-"business\0market\0"
-"ac.at\0maringa.br\0"
-"ac.be\0"
-"esurance\0"
-"kr.ua\0"
-"manaus.br\0\xe6\x96\xb0\xe9\x97\xbb\0"
-"go.th\0"
-"go.tj\0"
-"tanagura.fukushima.jp\0nanyo.yamagata.jp\0americanfamily\0"
-"zama.kanagawa.jp\0"
-"fredrikstad.no\0cc.vi.us\0"
-"legal\0"
-"ac.ci\0\xe8\x87\xba\xe7\x81\xa3\0"
-"army\0"
-"yashio.saitama.jp\0go.ug\0"
-"ac.cn\0nom.es\0isa-geek.com\0"
-"kamo.kyoto.jp\0"
-"go.tz\0k12.ia.us\0onrender.com\0"
-"ac.cr\0"
-"user.party.eus\0"
-"izumisano.osaka.jp\0karikatur.museum\0"
-"utsunomiya.tochigi.jp\0lindesnes.no\0"
-"ac.cy\0genoa.it\0"
-"halloffame.museum\0ushistory.museum\0"
-"navigation.aero\0"
-"from-az.net\0"
-"nom.fr\0cc.ms.us\0cc.nc.us\0"
-"sandvik\0"
-"\xe4\xbd\x9b\xe5\xb1\xb1\0nom.gd\0"
-"bauhaus\0nom.ge\0"
-"nobeoka.miyazaki.jp\0garden.museum\0"
-"arpa\0"
-"educator.aero\0shinkamigoto.nagasaki.jp\0"
-"hl.no\0nom.gl\0"
-"\xc3\xa5lg\xc3\xa5rd.no\0"
-"yoga\0"
-"eu.int\0tajimi.gifu.jp\0dnsdojo.com\0"
-"sakura.tochigi.jp\0"
-"*.in.futurecms.at\0nom.gt\0"
-"hemne.no\0"
-"kuki.saitama.jp\0"
-"abbvie\0is-a-candidate.org\0"
-"selje.no\0"
-"ashibetsu.hokkaido.jp\0nom.hn\0"
-"ac.fj\0"
-"mein-vigor.de\0"
-"is-gone.com\0"
-"vb.it\0"
-"*.alces.network\0"
-"s3-website.eu-central-1.amazonaws.com\0"
-"hizen.saga.jp\0is-a-conservative.com\0"
-"kakamigahara.gifu.jp\0"
-"esp.br\0"
-"nom.im\0"
-"feira.br\0okuma.fukushima.jp\0"
-"vall\xc3\xa9""eaoste.it\0tokyo\0"
-"ac.gn\0bronnoy.no\0"
-"siena.it\0contact\0"
-"joinville.br\0"
-"morioka.iwate.jp\0uki.kumamoto.jp\0"
-"uozu.toyama.jp\0events\0"
-"yomitan.okinawa.jp\0*.dev.adobeaemcloud.com\0"
-"dell\0"
-"now\0"
-"yamazoe.nara.jp\0"
-"hiphop\0"
-"higashitsuno.kochi.jp\0"
-"charity\0"
-"industries\0"
-"skedsmo.no\0nom.ke\0"
-"gateway.museum\0"
-"asda\0"
-"utsira.no\0shop.th\0"
-"ac.id\0"
-"arte\0mt.eu.org\0"
-"soundandvision.museum\0"
-"naka.ibaraki.jp\0nom.km\0sos.pl\0githubusercontent.com\0"
-"ac.il\0ohira.tochigi.jp\0"
-"ac.im\0simple-url.com\0"
-"ac.in\0misconfused.org\0"
-"a.bg\0ac.ir\0"
-"nra\0"
-"nom.li\0"
-"kisosaki.mie.jp\0"
-"chippubetsu.hokkaido.jp\0kurotaki.nara.jp\0"
-"contemporary.museum\0"
-"ninohe.iwate.jp\0kizu.kyoto.jp\0"
-"obi\0"
-"s3.cn-north-1.amazonaws.com.cn\0"
-"kimobetsu.hokkaido.jp\0satx.museum\0"
-"directory\0"
-"minami.fukuoka.jp\0"
-"ac.jp\0"
-"pro.az\0nom.lv\0"
-"nom.mg\0bbva\0"
-"uvic.museum\0"
-"museumvereniging.museum\0"
-"ac.ke\0pr.us\0webhop.net\0"
-"mobara.chiba.jp\0nom.mk\0"
-"realty\0"
-"pro.br\0nrw\0endofinternet.org\0"
-"shop.ro\0"
-"nom.nc\0obninsk.su\0"
-"ac.kr\0"
-"matsubushi.saitama.jp\0"
-"nom.ni\0cc.sc.us\0official.academy\0"
-"higashiyamato.tokyo.jp\0"
-"chesapeakebay.museum\0exnet.su\0"
-"uwu.ai\0"
-"works.aero\0takata.fukuoka.jp\0"
-"ac.lk\0wif.gov.pl\0lilly\0"
-"slz.br\0love\0"
-"osasco.br\0tagami.niigata.jp\0is-a-chef.org\0is-very-bad.org\0"
-"pro.cy\0shaw\0nom.nu\0"
-"ac.ma\0lib.tx.us\0"
-"ac.ls\0"
-"oguchi.aichi.jp\0ac.me\0is-an-entertainer.com\0"
-"ntt\0"
-"shop.pl\0"
-"commune.am\0k12.ar.us\0"
-"ginoza.okinawa.jp\0"
-"pro.ec\0"
-"nom.pa\0ketrzyn.pl\0"
-"montreal.museum\0police.uk\0"
-"etne.no\0"
-"nom.pe\0"
-"asia\0fukusaki.hyogo.jp\0lubartow.pl\0"
-"rimini.it\0"
-"ac.mu\0"
-"is-a-republican.com\0"
-"takayama.nagano.jp\0ac.mw\0nom.pl\0"
-"off\0"
-"ac.ni\0"
-"joyo.kyoto.jp\0finland.museum\0ac.mz\0store\0"
-"nom.qa\0"
-"nrw.museum\0"
-"dsmynas.org\0"
-"pro.fj\0"
-"nom.pw\0"
-"my.id\0desi\0"
-"verran.no\0"
-"tranby.no\0"
-"ac.nz\0vanguard\0"
-"ami.ibaraki.jp\0"
-"rexroth\0"
-"lib.ct.us\0"
-"dental\0goip.de\0"
-"lombardia.it\0nom.re\0basicserver.io\0"
-"flight.aero\0nakama.fukuoka.jp\0otoineppu.hokkaido.jp\0ac.pa\0"
-"nym.by\0"
-"nym.bz\0"
-"nishiawakura.okayama.jp\0"
-"s3.ca-central-1.amazonaws.com\0cloud66.zone\0"
-"nishiarita.saga.jp\0""2038.io\0"
-"nom.ro\0s3.dualstack.ap-south-1.amazonaws.com\0"
-"vaga.no\0"
-"catholic\0"
-"nom.rs\0"
-"caxias.br\0chuo.yamanashi.jp\0frogans\0is-not-certified.com\0usr.cloud.muni.cz\0"
-"eastafrica.museum\0"
-"uryu.hokkaido.jp\0"
-"ac.pr\0"
-"allstate\0"
-"nom.si\0"
-"nyc\0"
-"florence.it\0"
-"hjelmeland.no\0ulvik.no\0"
-"pro.ht\0fc.it\0"
-"of.by\0nym.ec\0"
-"nom.st\0"
-"eu-central-1.elasticbeanstalk.com\0is-into-cartoons.com\0"
-"tokamachi.niigata.jp\0"
-"n.bg\0akune.kagoshima.jp\0"
-"is-a-chef.com\0withyoutube.com\0nom.tj\0"
-"ap.it\0academy\0"
-"wakayama.wakayama.jp\0"
-"nom.tm\0knightpoint.systems\0"
-"memorial.museum\0"
-"seihi.nagasaki.jp\0"
-"js.cn\0"
-"vegas\0"
-"ino.kochi.jp\0"
-"\xe0\xac\xad\xe0\xac\xbe\xe0\xac\xb0\xe0\xac\xa4\0"
-"nom.ug\0"
-"ac.rs\0"
-"ac.se\0ac.ru\0"
-"my.eu.org\0"
-"ac.rw\0design\0"
-"es.kr\0"
-"sener\0shia\0"
-"noda.iwate.jp\0kouzushima.tokyo.jp\0"
-"miharu.fukushima.jp\0nom.vc\0"
-"ikoma.nara.jp\0on-the-web.tv\0kalmykia.su\0"
-"contractors\0"
-"nom.vg\0"
-"tarumizu.kagoshima.jp\0nom.uy\0"
-"kisofukushima.nagano.jp\0rl.no\0"
-"institute\0"
-"maniwa.okayama.jp\0ac.th\0"
-"yuasa.wakayama.jp\0cyon.site\0"
-"\xe9\x95\xb7\xe9\x87\x8e.jp\0ac.sz\0ac.tj\0"
-"fiat\0is-an-actress.com\0nym.gr\0"
-"v\xc3\xa5ler.\xc3\xb8stfold.no\0"
-"ogliastra.it\0"
-"nym.gy\0"
-"nym.hk\0"
-"kita.tokyo.jp\0"
-"ac.ug\0"
-"ac.tz\0dyn.ddnss.de\0"
-"ac.uk\0guitars\0"
-"nym.ie\0"
-"nakasatsunai.hokkaido.jp\0"
-"kusatsu.gunma.jp\0koge.tottori.jp\0"
-"\xe6\x95\x8e\xe8\x82\xb2.hk\0geology.museum\0one\0"
-"pro.na\0tec.ve\0"
-"carraramassa.it\0ong\0"
-"cal.it\0kawasaki.miyagi.jp\0servebbs.com\0*.magentosite.cloud\0"
-"kamisato.saitama.jp\0pro.mv\0"
-"ac.vn\0onl\0"
-"kalmykia.ru\0"
-"indianmarket.museum\0"
-"photos\0"
-"gs.tm.no\0lib.id.us\0\xe6\x89\x8b\xe8\xa1\xa8\0"
-"fido\0""32-b.it\0now-dns.top\0"
-"yaita.tochigi.jp\0"
-"lotte\0"
-"dubai\0"
-"si.it\0nom.za\0"
-"zoology.museum\0"
-"suzuka.mie.jp\0maserati\0"
-"shakotan.hokkaido.jp\0\xd0\xbc\xd0\xba\xd0\xb4\0report\0"
-"choyo.kumamoto.jp\0ooo\0"
-"oyodo.nara.jp\0kumenan.okayama.jp\0lotto\0"
-"bingo\0platter-app.dev\0"
-"pro.om\0"
-"eidsberg.no\0"
-"theworkpc.com\0"
-"ohda.shimane.jp\0"
-"nym.la\0"
-"nym.lc\0"
-"toyotsu.fukuoka.jp\0"
-"friuliveneziagiulia.it\0"
-"nym.li\0"
-"honjo.saitama.jp\0nesodden.no\0nym.kz\0"
-"iizuna.nagano.jp\0"
-"kepno.pl\0"
-"nl.eu.org\0"
-"urakawa.hokkaido.jp\0"
-"pro.pr\0"
-"playstation\0"
-"dnipropetrovsk.ua\0"
-"nym.lt\0"
-"cranbrook.museum\0nym.lu\0nym.me\0"
-"arendal.no\0lardal.no\0from-ca.com\0"
-"utazas.hu\0ac.za\0wellbeingzone.co.uk\0"
-"atsugi.kanagawa.jp\0"
-"isa-geek.net\0"
-"reklam.hu\0"
-"nym.mn\0"
-"masoy.no\0org\0shop\0"
-"misato.shimane.jp\0black\0"
-"pay\0"
-"xnbay.com\0"
-"ac.zm\0"
-"niki.hokkaido.jp\0"
-"farsund.no\0"
-"a.se\0neustar\0show\0\xe7\xbd\x91\xe5\x9d\x80\0lebtimnetz.de\0"
-"8.bg\0nym.mx\0"
-"tsugaru.aomori.jp\0"
-"minami-alps.yamanashi.jp\0"
-"ac.zw\0"
-"higashi.fukuoka.jp\0"
-"nym.nz\0"
-"\xe7\xa6\x8f\xe4\xba\x95.jp\0"
-"stalbans.museum\0\xd0\xbc\xd0\xbe\xd0\xbd\0"
-"kashima.saga.jp\0"
-"rovigo.it\0tysvar.no\0"
-"nym.pe\0"
-"friuli-ve-giulia.it\0oshima.tokyo.jp\0"
-"alfaromeo\0"
-"campinagrande.br\0"
-"of.no\0"
-"spjelkavik.no\0"
-"4lima.de\0"
-"ott\0s3.dualstack.ca-central-1.amazonaws.com\0"
-"kunstsammlung.museum\0"
-"nabari.mie.jp\0actor\0"
-"osteroy.no\0"
-"pro.tt\0"
-"tokuyama.yamaguchi.jp\0nym.pt\0"
-"mikawa.yamagata.jp\0"
-"matsushige.tokushima.jp\0dyn-vpn.de\0"
-"avocat.fr\0"
-"ide.kyoto.jp\0bjerkreim.no\0pila.pl\0"
-"skodje.no\0"
-"pet\0"
-"nishihara.kumamoto.jp\0andoy.no\0"
-"ovh\0eu-4.evennode.com\0"
-"lib.mt.us\0lib.nd.us\0carrd.co\0"
-"kadogawa.miyazaki.jp\0"
-"travelchannel\0"
-"santamaria.br\0orsta.no\0film\0""4lima.at\0"
-"pro.vn\0"
-"ng.eu.org\0"
-"hamaroy.no\0nym.ro\0"
-"boutique\0dattorelay.com\0"
-"betainabox.com\0"
-"miyako.fukuoka.jp\0"
-"sv.it\0kayabe.hokkaido.jp\0maif\0"
-"fujikawa.yamanashi.jp\0bananarepublic\0"
-"sukagawa.fukushima.jp\0moriguchi.osaka.jp\0"
-"gyeongbuk.kr\0"
-"is-leet.com\0nym.sk\0"
-"engine.aero\0"
-"bizen.okayama.jp\0hvaler.no\0phd\0twmail.net\0"
-"money.museum\0"
-"bauern.museum\0bryne.no\0""4lima.ch\0"
-"pc.it\0ibaraki.jp\0yaizu.shizuoka.jp\0"
-"conf.au\0"
-"yamaguchi.jp\0"
-"nym.su\0"
-"skydiving.aero\0pp.az\0nym.sx\0"
-"*.ocs.customer-oci.com\0"
-"app.os.stg.fedoraproject.org\0copro.uk\0"
-"pid\0"
-"fujisawa.kanagawa.jp\0"
-"rackmaze.net\0"
-"american.museum\0s3-ap-south-1.amazonaws.com\0onthewifi.com\0"
-"gov.ac\0toho.fukuoka.jp\0"
-"direct\0"
-"gov.ae\0pizza\0"
-"gov.af\0semboku.akita.jp\0"
-"lerdal.no\0ugim.gov.pl\0"
-"pin\0aktyubinsk.su\0nym.tw\0"
-"sardegna.it\0\xd9\x83\xd9\x88\xd9\x85\0servegame.org\0"
-"gov.al\0odate.akita.jp\0komatsushima.tokushima.jp\0"
-"trading\0"
-"music.museum\0"
-"gov.ba\0takamatsu.kagawa.jp\0budapest\0is-into-games.com\0"
-"gov.ar\0gov.bb\0bz.it\0fundacio.museum\0guardian\0eu-3.evennode.com\0"
-"gov.as\0hiraya.nagano.jp\0ichiba.tokushima.jp\0glade\0"
-"hadano.kanagawa.jp\0"
-"gov.au\0"
-"gov.bf\0donna.no\0support\0"
-"gov.bh\0jobs\0rockart.museum\0"
-"midtre-gauldal.no\0nodum.co\0"
-"gov.az\0n.se\0dyndns.biz\0"
-"gov.bm\0pa.gov.br\0takayama.gifu.jp\0"
-"gov.bn\0"
-"linde\0"
-"yaotsu.gifu.jp\0"
-"gov.br\0static-access.net\0"
-"gov.bs\0gz.cn\0wakayama.jp\0edu.krd\0"
-"gov.bt\0gov.cd\0ap-south-1.elasticbeanstalk.com\0is-a-cpa.com\0"
-"k12.pr.us\0"
-"gov.by\0"
-"gov.bz\0*.dweb.link\0"
-"gov.cl\0"
-"gov.cm\0"
-"gov.cn\0nv.us\0"
-"gov.co\0"
-"kep.tr\0"
-"sites.static.land\0"
-"fire\0"
-"gov.cu\0"
-"vladimir.su\0"
-"gov.cx\0hinohara.tokyo.jp\0"
-"gov.cy\0nodum.io\0"
-"k12.il.us\0ditchyourip.com\0"
-"shizuoka.shizuoka.jp\0"
-"pb.gov.br\0gov.dm\0"
-"dontexist.org\0"
-"sch.ae\0gov.do\0kasuga.hyogo.jp\0"
-"rikuzentakata.iwate.jp\0"
-"granvin.no\0from-wv.com\0"
-"gov.ec\0shibata.miyagi.jp\0bitballoon.com\0"
-"gov.ee\0"
-"bato.tochigi.jp\0k12.co.us\0"
-"gov.eg\0dovre.no\0fish\0"
-"cc.md.us\0"
-"leadpages.co\0"
-"gov.dz\0kitanakagusuku.okinawa.jp\0lib.sd.us\0"
-"\xe6\x8b\x9b\xe8\x81\x98\0eu-west-1.elasticbeanstalk.com\0"
-"pnc\0"
-"suldal.no\0"
-"co.place\0"
-"kiho.mie.jp\0"
-"eu-2.evennode.com\0"
-"cc.ia.us\0"
-"gov.et\0"
-"guam.gu\0lib.ny.us\0"
-"machida.tokyo.jp\0"
-"pc.pl\0pulawy.pl\0"
-"gov.fj\0m\xc3\xa1tta-v\xc3\xa1rjjat.no\0"
-"omiya.saitama.jp\0sharp\0"
-"clinique\0silk\0"
-"nsupdate.info\0"
-"citadel\0dvrcam.info\0"
-"namerikawa.toyama.jp\0plc.ly\0"
-"gov.ge\0"
-"vladimir.ru\0"
-"gov.gh\0ts.it\0"
-"gov.gi\0"
-"gb.com\0"
-"gov.gn\0bihoro.hokkaido.jp\0"
-"gov.gr\0sina\0"
-"trade\0is-a-chef.net\0"
-"gov.gu\0kikonai.hokkaido.jp\0gyeongnam.kr\0koebenhavn.museum\0"
-"sennan.osaka.jp\0"
-"kawachinagano.osaka.jp\0"
-"gov.gy\0kamisu.ibaraki.jp\0"
-"gov.hk\0"
-"utah.museum\0"
-"altervista.org\0"
-"audi\0"
-"m\xc4\x81ori.nz\0"
-"cherkasy.ua\0"
-"gov.ie\0"
-"itako.ibaraki.jp\0consulting\0cloud.goog\0"
-"military.museum\0"
-"hirogawa.wakayama.jp\0"
-"otaki.nagano.jp\0"
-"gov.il\0h\xc3\xa1mm\xc3\xa1rfeasta.no\0"
-"lakas.hu\0"
-"gov.in\0"
-"urbino-pesaro.it\0vuelos\0"
-"ed.ao\0gov.iq\0"
-"gov.ir\0lincoln.museum\0eu-1.evennode.com\0"
-"gov.is\0"
-"gov.it\0"
-"gs.ah.no\0"
-"mobi.gp\0hamburg.museum\0"
-"pro\0"
-"wy.us\0"
-"yufu.oita.jp\0beer\0"
-"\xe7\xbd\x91\xe7\xab\x99\0"
-"gov.jo\0pru\0"
-"tsukui.kanagawa.jp\0pony.club\0"
-"ryugasaki.ibaraki.jp\0westfalen.museum\0"
-"kamikawa.saitama.jp\0"
-"gov.kg\0"
-"gov.ki\0"
-"shimokitayama.nara.jp\0winners\0"
-"ed.ci\0"
-"mimata.miyazaki.jp\0gov.km\0athleta\0"
-"gov.kn\0"
-"gov.kp\0szczytno.pl\0"
-"gov.la\0dlugoleka.pl\0"
-"gov.lb\0"
-"gov.lc\0"
-"ed.cr\0ddr.museum\0"
-"gov.kw\0"
-"gov.ky\0even\xc3\xa1\xc5\xa1\xc5\xa1i.no\0"
-"gov.kz\0"
-"gov.lk\0"
-"haibara.shizuoka.jp\0pub\0"
-"risor.no\0blackbaudcdn.net\0"
-"sch.id\0\xe5\x95\x86\xe6\xa0\x87\0"
-"gov.ma\0"
-"yamagata.gifu.jp\0gov.lr\0virtualserver.io\0"
-"gov.ls\0maori.nz\0\xe6\x89\x8b\xe6\x9c\xba\0"
-"gov.lt\0"
-"gov.me\0\xd9\x85\xd8\xb5\xd8\xb1\0"
-"gov.lv\0"
-"gov.mg\0"
-"gov.ly\0"
-"gov.mk\0"
-"sch.ir\0hongo.hiroshima.jp\0gov.ml\0website.yandexcloud.net\0"
-"mihama.chiba.jp\0"
-"gov.mn\0""12hp.de\0"
-"gov.mo\0usdecorativearts.museum\0"
-"aogashima.tokyo.jp\0taipei\0"
-"media.aero\0tachikawa.tokyo.jp\0gov.mr\0"
-"gov.ms\0"
-"gov.mu\0cc.in.us\0"
-"gov.mv\0site\0"
-"gov.mw\0gov.ng\0"
-"bologna.it\0"
-"sch.jo\0gov.my\0"
-"gov.mz\0"
-"*.0emm.com\0"
-"pwc\0"
-"ventures\0"
-"mizuho.tokyo.jp\0"
-"gov.nr\0"
-"plc.uk\0"
-"coop.ht\0"
-"morena.br\0\xda\x80\xd8\xa7\xd8\xb1\xd8\xaa\0"
-"from-in.com\0"
-"tadotsu.kagawa.jp\0gov.om\0""12hp.at\0"
-"za.com\0lug.org.uk\0"
-"force.museum\0"
-"myactivedirectory.com\0"
-"nissedal.no\0capital\0"
-"zara\0"
-"sch.lk\0accenture\0"
-"semine.miyagi.jp\0maison\0"
-"plaza.museum\0gov.ph\0"
-"fr\xc3\xa6na.no\0"
-"gov.pk\0"
-"gov.pl\0"
-"kawagoe.mie.jp\0"
-"gov.pn\0"
-"nasushiobara.tochigi.jp\0"
-"gov.qa\0""12hp.ch\0"
-"gov.pr\0"
-"sch.ly\0gov.ps\0conf.se\0"
-"coop.br\0nakagyo.kyoto.jp\0gov.pt\0pp.se\0is-a-patsfan.org\0pp.ru\0"
-"atami.shizuoka.jp\0\xd8\xb9\xd9\x85\xd8\xa7\xd9\x86\0"
-"it.ao\0cinema.museum\0"
-"gov.py\0"
-"latrobe\0vladikavkaz.ru\0"
-"vestre-toten.no\0"
-"isernia.it\0alipay\0"
-"sch.ng\0troms\xc3\xb8.no\0glass\0shacknet.nu\0"
-"dsmynas.net\0"
-"gripe\0"
-"in.net\0"
-"taiki.mie.jp\0""2ix.at\0"
-"indigena.bo\0ubank\0"
-"vladikavkaz.su\0"
-"kurashiki.okayama.jp\0snillfjord.no\0storj.farm\0"
-"pi.gov.br\0"
-"auspost\0"
-"academy.museum\0"
-"pp.ua\0"
-"gov.sa\0at-band-camp.net\0"
-"ed.jp\0kashiwa.chiba.jp\0gov.sb\0"
-"ichinohe.iwate.jp\0ofunato.iwate.jp\0gov.rs\0gov.sc\0"
-"gov.sd\0""1337.pictures\0"
-"gov.ru\0"
-"gov.rw\0gov.sg\0"
-"aerobatic.aero\0gov.sh\0"
-"bahccavuotna.no\0"
-"ritto.shiga.jp\0mj\xc3\xb8ndalen.no\0"
-"bronnoysund.no\0claims\0"
-"gov.sl\0"
-"kommunalforbund.se\0""2ix.ch\0"
-"\xe4\xba\x9a\xe9\xa9\xac\xe9\x80\x8a\0"
-"gov.so\0"
-"gov.ss\0"
-"gov.st\0k12.mo.us\0"
-"cc.vt.us\0"
-"birdart.museum\0aseral.no\0"
-"bearalvahki.no\0gov.sx\0"
-"heroy.more-og-romsdal.no\0gov.sy\0"
-"gov.tj\0digital\0""2ix.de\0"
-"sch.qa\0"
-"fujimi.saitama.jp\0gov.tl\0"
-"gov.tm\0"
-"gov.tn\0progressive\0"
-"gov.to\0k12.in.us\0"
-"vic.gov.au\0gov.ua\0"
-"gov.tr\0"
-"film.hu\0gov.tt\0"
-"ehime.jp\0bergbau.museum\0"
-"gov.tw\0"
-"sport.hu\0"
-"gov.uk\0"
-"tsurugashima.saitama.jp\0"
-"schulserver.de\0"
-"chtr.k12.ma.us\0"
-"gov.vc\0"
-"historical.museum\0gov.ve\0"
-"dagestan.ru\0no-ip.co.uk\0"
-"raisa.no\0"
-"avellino.it\0"
-"cloudcontrolled.com\0"
-"sch.sa\0paris\0"
-"\xe4\xb8\xad\xe4\xbf\xa1\0"
-"barueri.br\0"
-"gov.vn\0apps.fbsbx.com\0"
-"ivano-frankivsk.ua\0dyndns-home.com\0"
-"togitsu.nagasaki.jp\0aurland.no\0"
-"\xe7\x9f\xb3\xe5\xb7\x9d.jp\0h\xc3\xb8ylandet.no\0dagestan.su\0"
-"volkswagen\0"
-"liguria.it\0sch.so\0"
-"tomisato.chiba.jp\0"
-"mediocampidano.it\0"
-"aa.no\0"
-"naka.hiroshima.jp\0from-ok.com\0"
-"tamaki.mie.jp\0mosvik.no\0lib.gu.us\0"
-"avoues.fr\0cologne\0"
-"\xe6\x85\x88\xe5\x96\x84\0"
-"gov.ws\0iamallama.com\0"
-"midori.gunma.jp\0"
-"toba.mie.jp\0"
-"augustow.pl\0"
-"masuda.shimane.jp\0virgin\0"
-"osakikamijima.hiroshima.jp\0"
-"best\0"
-"nanto.toyama.jp\0"
-"dali.museum\0"
-"rnu.tn\0"
-"nt.au\0"
-"bozen-s\xc3\xbc""dtirol.it\0"
-"auto\0"
-"ed.pw\0grozny.su\0"
-"oyer.no\0vennesla.no\0"
-"miura.kanagawa.jp\0"
-"historisches.museum\0"
-"yamatokoriyama.nara.jp\0med.pro\0"
-"molde.no\0amazon\0"
-"map.fastly.net\0"
-"nt.ca\0gov.za\0"
-"work\0"
-"childrens.museum\0"
-"vibovalentia.it\0tools\0"
-"paleo.museum\0"
-"toyotomi.hokkaido.jp\0hareid.no\0"
-"science.museum\0applinzi.com\0"
-"ostroda.pl\0"
-"pe.gov.br\0gov.zm\0getmyip.com\0is-into-anime.com\0"
-"eco.br\0psse.gov.pl\0"
-"miami\0"
-"l.bg\0yachiyo.ibaraki.jp\0gulen.no\0"
-"north.museum\0agakhan\0*.compute.amazonaws.com\0"
-"an.it\0"
-"\xe4\xba\xac\xe9\x83\xbd.jp\0conf.lv\0"
-"camera\0"
-"gov.zw\0"
-"nachikatsuura.wakayama.jp\0"
-"modum.no\0kerryhotels\0"
-"lazio.it\0mol.it\0"
-"windmill.museum\0"
-"togliatti.su\0"
-"nsn.us\0"
-"matsukawa.nagano.jp\0"
-"landes.museum\0"
-"grozny.ru\0"
-"consulado.st\0"
-"toyokawa.aichi.jp\0veterinaire.km\0norddal.no\0"
-"miyashiro.saitama.jp\0"
-"fukudomi.saga.jp\0red\0"
-"onagawa.miyagi.jp\0"
-"balsan-sudtirol.it\0"
-"\xd0\xbe\xd1\x80\xd0\xb3\0"
-"grimstad.no\0ren\0"
-"arezzo.it\0"
-"qvc\0"
-"cc.ok.us\0"
-"rishiri.hokkaido.jp\0"
-"freeddns.us\0"
-"saku.nagano.jp\0"
-"sch.zm\0"
-"cloudaccess.net\0"
-"juif.museum\0trust.museum\0wloclawek.pl\0"
-"nagasaki.jp\0"
-"*.platform.sh\0"
-"agro.bo\0"
-"tara.saga.jp\0"
-"unnan.shimane.jp\0s3-website-us-west-1.amazonaws.com\0"
-"public.museum\0transport.museum\0"
-"lib.me.us\0"
-"notogawa.shiga.jp\0"
-"miyawaka.fukuoka.jp\0higashikagura.hokkaido.jp\0"
-"mobi.tt\0"
-"savannahga.museum\0"
-"naoshima.kagawa.jp\0plants.museum\0\xe9\xa6\x99\xe6\xa0\xbc\xe9\x87\x8c\xe6\x8b\x89\0"
-"veterinaire.fr\0"
-"mobi.tz\0"
-"is-a-landscaper.com\0"
-"tamamura.gunma.jp\0"
-"izena.okinawa.jp\0"
-"pa.gov.pl\0"
-"nieruchomosci.pl\0"
-"platterp.us\0"
-"newspaper.museum\0"
-"bungotakada.oita.jp\0"
-"museet.museum\0"
-"kasuya.fukuoka.jp\0"
-"global\0sa-east-1.elasticbeanstalk.com\0"
-"chuo.osaka.jp\0"
-"whaling.museum\0ril\0"
-"lib.al.us\0"
-"2000.hu\0diet\0"
-"coop.rw\0rio\0"
-"kurume.fukuoka.jp\0rip\0"
-"yukuhashi.fukuoka.jp\0parts\0"
-"nhlfan.net\0"
-"rec.br\0zp.ua\0"
-"party\0"
-"bible.museum\0"
-"us.com\0"
-"asso.eu.org\0"
-"jprs\0"
-"civilaviation.aero\0bill.museum\0k\xc3\xa5""fjord.no\0"
-"kasama.ibaraki.jp\0bygland.no\0"
-"rec.co\0yasaka.nagano.jp\0vgs.no\0"
-"kure.hiroshima.jp\0"
-"toyota\0"
-"abudhabi\0s3.dualstack.us-east-2.amazonaws.com\0"
-"naruto.tokushima.jp\0ciscofreak.com\0"
-"y.bg\0bashkiria.ru\0"
-"gonohe.aomori.jp\0"
-"kitakata.miyazaki.jp\0"
-"coop.tt\0"
-"twmail.cc\0"
-"science\0"
-"messina.it\0higashiura.aichi.jp\0kyoto\0"
-"project.museum\0"
-"\xe5\xb1\xb1\xe5\x8f\xa3.jp\0asnes.no\0"
-"lezajsk.pl\0okinawa\0leczna.pl\0"
-"6.bg\0"
-"agents.aero\0skin\0"
-"kainan.wakayama.jp\0twmail.org\0"
-"kanra.gunma.jp\0"
-"bashkiria.su\0"
-"toei.aichi.jp\0"
-"coop.mv\0jelenia-gora.pl\0"
-"com.ac\0izumi.osaka.jp\0coop.mw\0mobi.na\0"
-"trentinosued-tirol.it\0blogdns.org\0dev.static.land\0"
-"com.af\0salem.museum\0"
-"com.ag\0pr.gov.br\0rankoshi.hokkaido.jp\0"
-"takahama.fukui.jp\0zapto.xyz\0"
-"com.ai\0mobi.ng\0"
-"com.al\0"
-"com.am\0terni.it\0"
-"hof.no\0"
-"lur\xc3\xb8y.no\0"
-"gyokuto.kumamoto.jp\0orkanger.no\0lplfinancial\0"
-"com.ba\0"
-"com.ar\0com.bb\0"
-"oguni.kumamoto.jp\0"
-"uklugs.org\0"
-"com.au\0hamburg\0"
-"com.aw\0mail.pl\0"
-"com.bh\0"
-"com.bi\0nt.no\0comsec\0"
-"com.az\0handson.museum\0"
-"katori.chiba.jp\0"
-"com.bm\0"
-"com.bn\0soccer\0"
-"com.bo\0"
-"com.br\0lom.it\0"
-"com.bs\0oristano.it\0takaharu.miyazaki.jp\0fukuroi.shizuoka.jp\0"
-"com.bt\0rieti.it\0"
-"repl.co\0"
-"s\xc3\xb8r-odal.no\0"
-"theater\0"
-"shichinohe.aomori.jp\0v\xc3\xa5g\xc3\xa5.no\0"
-"com.by\0com.ci\0"
-"com.bz\0\xe5\xb1\xb1\xe6\xa2\xa8.jp\0otsuki.yamanashi.jp\0"
-"equipment\0"
-"com.cm\0"
-"com.cn\0versailles.museum\0barsy.me\0"
-"com.co\0"
-"cog.mi.us\0"
-"idf.il\0tsuno.miyazaki.jp\0"
-"4u.com\0"
-"com.cu\0berlevag.no\0coop.py\0com.de\0"
-"com.cw\0nagano.jp\0sanda.hyogo.jp\0seiro.niigata.jp\0"
-"com.cy\0kunisaki.oita.jp\0"
-"kosher\0sucks\0"
-"cc.co.us\0"
-"pomorze.pl\0"
-"com.dm\0stream\0"
-"com.do\0"
-"gamvik.no\0"
-"com.ec\0"
-"tamayu.shimane.jp\0kawanehon.shizuoka.jp\0"
-"com.ee\0\xe7\xa6\x8f\xe5\xb3\xb6.jp\0"
-"caltanissetta.it\0"
-"com.eg\0s3-ap-southeast-1.amazonaws.com\0"
-"lib.fl.us\0"
-"ise.mie.jp\0"
-"com.dz\0holt\xc3\xa5len.no\0valer.ostfold.no\0"
-"far.br\0cn.com\0"
-"yusui.kagoshima.jp\0"
-"pa.it\0"
-"milano.it\0"
-"isleofman.museum\0"
-"com.es\0"
-"com.et\0sap\0is-a-caterer.com\0"
-"s3-us-west-2.amazonaws.com\0"
-"nombre.bo\0mobi.ke\0sas\0\xd0\xbe\xd0\xbd\xd0\xbb\xd0\xb0\xd0\xb9\xd0\xbd\0"
-"grue.no\0"
-"coop.km\0nt.ro\0"
-"com.fj\0"
-"ltda\0"
-"nittedal.no\0"
-"futsu.nagasaki.jp\0sbi\0"
-"\xe5\x85\xb5\xe5\xba\xab.jp\0"
-"nakagawa.fukuoka.jp\0sogndal.no\0sumy.ua\0"
-"com.fr\0eating-organic.net\0"
-"friuli-vegiulia.it\0izumozaki.niigata.jp\0yuza.yamagata.jp\0powiat.pl\0"
-"tsuchiura.ibaraki.jp\0forumz.info\0"
-"com.ge\0sca\0"
-"scb\0"
-"\xe6\x96\xb0\xe5\x8a\xa0\xe5\x9d\xa1\0sbs\0cloudfront.net\0"
-"com.gh\0*.statics.cloud\0"
-"com.gi\0"
-"emb.kw\0"
-"sherbrooke.museum\0ringerike.no\0boldlygoingnowhere.org\0"
-"com.gl\0"
-"shikokuchuo.ehime.jp\0lom.no\0beskidy.pl\0"
-"com.gn\0lima.zone\0"
-"intelligence.museum\0"
-"com.gp\0"
-"ch.it\0"
-"com.gr\0"
-"cyou\0"
-"com.gt\0tateyama.chiba.jp\0hayashima.okayama.jp\0financial\0"
-"com.gu\0"
-"hirara.okinawa.jp\0"
-"com.gy\0l.se\0"
-"com.hk\0od.ua\0flir\0troitsk.su\0graphox.us\0"
-"ma.leg.br\0"
-"com.hn\0"
-"shichikashuku.miyagi.jp\0"
-"bplaced.com\0"
-"gx.cn\0com.hr\0dyn-berlin.de\0"
-"maintenance.aero\0"
-"the.br\0com.ht\0nankoku.kochi.jp\0dance\0"
-"matsudo.chiba.jp\0"
-"evenassi.no\0hk.com\0"
-"rec.nf\0midsund.no\0\xe4\xb8\x96\xe7\x95\x8c\0"
-"com.im\0"
-"com.io\0schule\0"
-"st.no\0"
-"com.iq\0cc.tx.us\0"
-"warmia.pl\0run\0"
-"com.is\0farmequipment.museum\0"
-"takarazuka.hyogo.jp\0"
-"kanegasaki.iwate.jp\0agriculture.museum\0"
-"oppdal.no\0ses\0from-wi.com\0"
-"realtor\0"
-"poivron.org\0"
-"sew\0"
-"travel.pl\0sex\0"
-"tr.eu.org\0"
-"com.jo\0"
-"garden\0"
-"gotdns.com\0"
-"b\xc3\xb8.nordland.no\0mitsubishi\0"
-"miniserver.com\0"
-"k12.de.us\0"
-"dish\0sfr\0"
-"com.kg\0"
-"com.ki\0bradesco\0rwe\0"
-"*.s5y.io\0"
-"com.km\0"
-"ternopil.ua\0"
-"com.kp\0gleeze.com\0"
-"nakayama.yamagata.jp\0com.la\0"
-"com.lb\0salon\0sling\0"
-"com.lc\0myfirewall.org\0"
-"lib.ok.us\0barsy.uk\0"
-"inf.br\0naval.museum\0"
-"com.kw\0"
-"bodo.no\0"
-"com.ky\0"
-"com.kz\0"
-"com.lk\0spdns.eu\0"
-"applicationcloud.io\0"
-"law.za\0"
-"bytom.pl\0lebork.pl\0dscloud.me\0"
-"com.lr\0"
-"cbg.ru\0"
-"tsukiyono.gunma.jp\0"
-"umaji.kochi.jp\0com.lv\0"
-"com.mg\0foodnetwork\0"
-"inf.cu\0com.ly\0"
-"yokawa.hyogo.jp\0"
-"com.mk\0"
-"com.ml\0"
-"s3.eu-west-2.amazonaws.com\0freeddns.org\0"
-"com.mo\0"
-"skype\0"
-"\xe5\xa4\xa7\xe9\x98\xaa.jp\0com.na\0"
-"pn.it\0"
-"com.ms\0"
-"com.mt\0za.bz\0"
-"com.mu\0rec.ro\0lib.ar.us\0"
-"com.mv\0com.nf\0"
-"sicily.it\0com.mw\0com.ng\0"
-"com.mx\0"
-"yuki.ibaraki.jp\0com.my\0com.ni\0"
-"govt.nz\0"
-"badaddja.no\0"
-"daisen.akita.jp\0"
-"com.nr\0"
-"spy.museum\0"
-"savona.it\0travel.tt\0uni5.net\0"
-"yuu.yamaguchi.jp\0"
-"duckdns.org\0"
-"hatsukaichi.hiroshima.jp\0rep.kp\0konin.pl\0"
-"my-vigor.de\0"
-"com.om\0lipsy\0ski\0"
-"com.pa\0"
-"kyowa.hokkaido.jp\0"
-"walmart\0"
-"union.aero\0com.pe\0\xe0\xb9\x84\xe0\xb8\x97\xe0\xb8\xa2\0"
-"gorizia.it\0vefsn.no\0com.pf\0"
-"trentino-stirol.it\0rome.it\0owani.aomori.jp\0trolley.museum\0"
-"com.ph\0"
-"s3-website-ap-northeast-1.amazonaws.com\0"
-"nagara.chiba.jp\0tomakomai.hokkaido.jp\0com.pk\0y.se\0"
-"tananger.no\0com.pl\0"
-"sky\0"
-"recife.br\0"
-"leikanger.no\0rovno.ua\0to.work\0own.pm\0"
-"uri.arpa\0democracia.bo\0po.gov.pl\0com.qa\0international\0"
-"com.pr\0"
-"tr\xc3\xa6na.no\0com.ps\0"
-"ovre-eiker.no\0agro.pl\0com.pt\0barsy.shop\0"
-"\xe4\xbd\x90\xe8\xb3\x80.jp\0fukuyama.hiroshima.jp\0nanporo.hokkaido.jp\0"
-"com.py\0yandexcloud.net\0"
-"kimino.wakayama.jp\0rec.ve\0"
-"pa.us\0"
-"flights\0"
-"minamiechizen.fukui.jp\0k12.nj.us\0"
-"saka.hiroshima.jp\0"
-"ono.hyogo.jp\0konan.shiga.jp\0com.re\0"
-"valley.museum\0"
-"spdns.de\0"
-"her\xc3\xb8y.m\xc3\xb8re-og-romsdal.no\0"
-"stargard.pl\0"
-"com.ro\0"
-"tonami.toyama.jp\0com.sa\0"
-"tabayama.yamanashi.jp\0com.sb\0"
-"com.sc\0"
-"com.sd\0"
-"illustration.museum\0com.se\0com.ru\0"
-"aejrie.no\0com.sg\0"
-"com.sh\0"
-"cc.mo.us\0"
-"coastaldefence.museum\0"
-"com.sl\0"
-"shimizu.shizuoka.jp\0"
-"com.sn\0hzc.io\0"
-"com.so\0"
-"salerno.it\0"
-"okinawa.jp\0"
-"malvik.no\0com.ss\0"
-"com.st\0cc.il.us\0arvo.network\0"
-"spa\0"
-"mat.br\0com.sv\0"
-"com.sy\0mypi.co\0"
-"com.tj\0"
-"usantiques.museum\0"
-"pimienta.org\0"
-"com.tm\0soy\0"
-"naie.hokkaido.jp\0com.tn\0builders\0"
-"chijiwa.nagasaki.jp\0com.to\0"
-"com.ua\0"
-"com.tr\0\xe8\x81\x94\xe9\x80\x9a\0from-ia.com\0"
-"hanamigawa.chiba.jp\0"
-"com.tt\0dynamic-dns.info\0"
-"tab\0tjmaxx\0"
-"auto.pl\0com.tw\0com.ug\0"
-"fujiidera.osaka.jp\0"
-"alessandria.it\0"
-"journalist.aero\0"
-"diamonds\0"
-"london\0"
-"com.vc\0"
-"com.ve\0"
-"ua.rs\0"
-"brindisi.it\0gs.nl.no\0"
-"bibai.hokkaido.jp\0com.uy\0com.vi\0*.advisor.ws\0"
-"com.uz\0"
-"alibaba\0tax\0"
-"profesional.bo\0okegawa.saitama.jp\0com.vn\0dontexist.com\0"
-"inf.mk\0"
-"oshima.yamaguchi.jp\0srl\0"
-"empresa.bo\0com.vu\0"
-"itoman.okinawa.jp\0theatre\0"
-"mitaka.tokyo.jp\0culture.museum\0"
-"friulivegiulia.it\0durham.museum\0"
-"firenze.it\0tci\0"
-"is-very-sweet.org\0"
-"vestby.no\0"
-"arte.bo\0"
-"com.ws\0"
-"watchandclock.museum\0"
-"tomari.hokkaido.jp\0stc\0localhost.daplie.me\0"
-"hu.com\0"
-"isesaki.gunma.jp\0gjovik.no\0readmyblog.org\0"
-"meet\0"
-"tdk\0"
-"barsy.bg\0"
-"storage.yandexcloud.net\0"
-"monticello.museum\0"
-"tokai.ibaraki.jp\0*.quipelements.com\0"
-"agrar.hu\0\xe9\x95\xb7\xe5\xb4\x8e.jp\0tone.ibaraki.jp\0"
-"airtel\0"
-"host\0"
-"schlesisches.museum\0"
-"gjerstad.no\0barsy.ca\0"
-"tako.chiba.jp\0yonezawa.yamagata.jp\0"
-"mihama.aichi.jp\0is-very-nice.org\0"
-"tel\0"
-"k12.ne.us\0"
-"qld.edu.au\0tamatsukuri.ibaraki.jp\0"
-"virtueeldomein.nl\0"
-"stjohn.museum\0"
-"lewismiller.museum\0"
-"siellak.no\0"
-"taketa.oita.jp\0"
-"texas.museum\0"
-"com.zm\0"
-"barsy.de\0"
-"hyuga.miyazaki.jp\0"
-"horonobe.hokkaido.jp\0"
-"onfabrica.com\0"
-"kanmaki.nara.jp\0"
-"kounosu.saitama.jp\0"
-"mashiki.kumamoto.jp\0"
-"date.fukushima.jp\0"
-"agency\0"
-"venezia.it\0"
-"itayanagi.aomori.jp\0"
-"campinas.br\0"
-"shingu.hyogo.jp\0u2-local.xnbay.com\0"
-"hachirogata.akita.jp\0dr.na\0de.us\0"
-"\xe5\x80\x8b\xe4\xba\xba.hk\0"
-"barsy.site\0"
-"crd.co\0karaganda.su\0"
-"toray\0"
-"lib.pa.us\0thd\0"
-"uk.eu.org\0"
-"barsy.eu\0"
-"domains\0"
-"gallery.museum\0shell\0gets-it.net\0"
-"lelux.site\0"
-"taketomi.okinawa.jp\0boomla.net\0"
-"dynamisches-dns.de\0"
-"aso.kumamoto.jp\0"
-"condos\0"
-"trentinos-tirol.it\0"
-"cc.as.us\0platter-app.com\0"
-"dnsupdater.de\0"
-"higashinaruse.akita.jp\0\xd1\x80\xd1\x83\xd1\x81\0"
-"study\0"
-"eti.br\0myfast.host\0"
-"omi.nagano.jp\0"
-"sport\0inf.ua\0"
-"kamakura.kanagawa.jp\0"
-"plurinacional.bo\0"
-"rns.tn\0"
-"her\xc3\xb8y.nordland.no\0"
-"koeln.museum\0"
-"brunel.museum\0bplaced.net\0"
-"ikeda.fukui.jp\0"
-"trapani.it\0"
-"urausu.hokkaido.jp\0misato.saitama.jp\0iwi.nz\0"
-"b\xc3\xb8mlo.no\0"
-"tjx\0clan.rip\0"
-"ne.jp\0"
-"glogow.pl\0"
-"meme\0"
-"toyako.hokkaido.jp\0"
-"ne.ke\0"
-"otsuki.kochi.jp\0"
-"ato.br\0"
-"donostia.museum\0"
-"chikuma.nagano.jp\0barsy.in\0stufftoread.com\0"
-"barsy.io\0"
-"iwatsuki.saitama.jp\0\xd7\xa7\xd7\x95\xd7\x9d\0s3-website-ap-southeast-2.amazonaws.com\0"
-"roma.museum\0"
-"ne.kr\0"
-"j.bg\0ikusaka.nagano.jp\0ricoh\0"
-"yurihonjo.akita.jp\0suisse.museum\0mw.gov.pl\0"
-"al.it\0"
-"boavista.br\0andebu.no\0"
-"home-webserver.de\0"
-"ogawa.nagano.jp\0hanno.saitama.jp\0"
-"xerox\0est-a-la-maison.com\0forgot.his.name\0"
-"kashiwazaki.niigata.jp\0"
-"obuse.nagano.jp\0"
-"uji.kyoto.jp\0other.nf\0"
-"date.hokkaido.jp\0"
-"brussels\0menu\0\xd9\x87\xd9\x85\xd8\xb1\xd8\xa7\xd9\x87\0"
-"sebastopol.ua\0"
-"trentinoa-adige.it\0"
-"vallee-d-aoste.it\0fukushima.fukushima.jp\0"
-"qa2.com\0"
-"aomori.jp\0daplie.me\0nflfan.org\0"
-"saiki.oita.jp\0"
-"swidnica.pl\0"
-"ando.nara.jp\0s3-website-eu-west-1.amazonaws.com\0"
-"pittsburgh.museum\0dr.tr\0"
-"homedns.org\0"
-"lanxess\0photography\0"
-"sic.it\0"
-"ms.gov.br\0"
-"kushimoto.wakayama.jp\0"
-"abeno.osaka.jp\0washingtondc.museum\0"
-"otsuchi.iwate.jp\0r\xc3\xa1hkker\xc3\xa1vju.no\0"
-"chizu.tottori.jp\0cc.ny.us\0mydrobo.com\0"
-"communication.museum\0skoczow.pl\0plumbing\0"
-"sasaguri.fukuoka.jp\0"
-"ono.fukushima.jp\0"
-"strand.no\0"
-"frog.museum\0"
-"cuiaba.br\0hakui.ishikawa.jp\0mamurogawa.yamagata.jp\0"
-"starachowice.pl\0top\0"
-"mattel\0"
-"\xe7\xb5\x84\xe7\xbb\x87.hk\0katsuragi.nara.jp\0"
-"fjaler.no\0"
-"carbonia-iglesias.it\0xbox\0"
-"lib.pr.us\0"
-"k\xc3\xa1r\xc3\xa1\xc5\xa1johka.no\0"
-"pippu.hokkaido.jp\0mg.leg.br\0"
-"wafflecell.com\0"
-"niteroi.br\0chino.nagano.jp\0"
-"blogdns.net\0eu.org\0"
-"microlight.aero\0farm.museum\0"
-"minamiuonuma.niigata.jp\0"
-"bando.ibaraki.jp\0per.la\0"
-"mt.gov.br\0kozaki.chiba.jp\0higashiyama.kyoto.jp\0"
-"hotels\0"
-"kvalsund.no\0"
-"bonn.museum\0al.no\0"
-"hotel.tz\0"
-"sicilia.it\0"
-"leirfjord.no\0"
-"trentins\xc3\xbc""d-tirol.it\0ne.pw\0mobile\0"
-"bukhara.su\0"
-"franziskaner.museum\0historyofscience.museum\0selbu.no\0"
-"exposed\0koeln\0"
-"castle.museum\0"
-"saga.saga.jp\0beauty\0"
-"porsanger.no\0clothing\0marriott\0""64-b.it\0"
-"baidu\0"
-"tochigi.jp\0"
-"ubs\0"
-"\xe7\xbd\x91\xe7\xbb\x9c\0"
-"per.nf\0trv\0"
-"saitama.saitama.jp\0"
-"bio.br\0"
-"webredirect.org\0nov.ru\0"
-"tanabe.kyoto.jp\0"
-"stackhero-network.com\0"
-"miyada.nagano.jp\0"
-"trentin-sudtirol.it\0sakurai.nara.jp\0pubol.museum\0"
-"backplaneapp.io\0"
-"nov.su\0"
-"w.bg\0"
-"meland.no\0"
-"bi.it\0akrehamn.no\0"
-"sklep.pl\0"
-"belluno.it\0"
-"4.bg\0gorge.museum\0tui\0"
-"loten.no\0"
-"delaware.museum\0\xd1\x81\xd1\x80\xd0\xb1\0"
-"sncf\0"
-"bryansk.su\0"
-"modalen.no\0ne.ug\0"
-"oita.jp\0"
-"zaporizhzhia.ua\0"
-"ne.tz\0"
-"nesoddtangen.no\0"
-"philips\0\xe6\x94\xbf\xe5\xba\x9c\0"
-"taiji.wakayama.jp\0sopot.pl\0"
-"yatomi.aichi.jp\0higashihiroshima.hiroshima.jp\0uk.net\0"
-"nordkapp.no\0"
-"\xe7\xb6\xb2\xe7\xbb\x9c.hk\0luxe\0"
-"mitsue.nara.jp\0ne.us\0"
-"ikeda.nagano.jp\0building.museum\0"
-"ota.tokyo.jp\0"
-"tvs\0"
-"r\xc3\xb8mskog.no\0"
-"datsun\0"
-"genting\0"
-"hioki.kagoshima.jp\0"
-"k12.ga.us\0"
-"mytuleap.com\0"
-"balsfjord.no\0"
-"columbia.museum\0static.land\0"
-"tel.tr\0"
-"tateshina.nagano.jp\0"
-"express\0"
-"kyiv.ua\0"
-"tonaki.okinawa.jp\0bike\0""3utilities.com\0"
-"cc.ks.us\0"
-"psp.gov.pl\0per.sg\0"
-"ac.gov.br\0udine.it\0n\xc3\xa6r\xc3\xb8y.no\0"
-"homes\0"
-"hotel.lk\0"
-"maceio.br\0kinokawa.wakayama.jp\0al.us\0"
-"rodoy.no\0"
-"lib.nh.us\0finance\0"
-"zero\0"
-"zgora.pl\0"
-"konsulat.gov.pl\0"
-"costume.museum\0"
-"natori.miyagi.jp\0"
-"philadelphia.museum\0"
-"veg\xc3\xa5rshei.no\0"
-"bsb.br\0"
-"aizubange.fukushima.jp\0tobetsu.hokkaido.jp\0"
-"sr.it\0"
-"higashimurayama.tokyo.jp\0"
-"ushiku.ibaraki.jp\0cloudapp.net\0"
-"jeju.kr\0engineer\0"
-"naumburg.museum\0"
-"massa-carrara.it\0fylkesbibl.no\0"
-"serveirc.com\0"
-"gunma.jp\0"
-"amusement.aero\0"
-"katashina.gunma.jp\0commbank\0"
-"krager\xc3\xb8.no\0"
-"bing\0from-ut.com\0"
-"tele.amune.org\0"
-"kwpsp.gov.pl\0"
-"mibu.tochigi.jp\0"
-"credit\0"
-"sigdal.no\0starostwo.gov.pl\0"
-"net.ac\0gs.hm.no\0"
-"net.ae\0"
-"net.af\0"
-"net.ag\0buzen.fukuoka.jp\0"
-"gv.ao\0kddi\0"
-"net.ai\0health.museum\0"
-"net.al\0kwp.gov.pl\0"
-"net.am\0gv.at\0"
-"tateyama.toyama.jp\0"
-"hosting-cluster.nl\0pagespeedmobilizer.com\0point2this.com\0"
-"net.ba\0"
-"net.ar\0net.bb\0"
-"sveio.no\0"
-"net.au\0urasoe.okinawa.jp\0"
-"uda.nara.jp\0"
-"net.bh\0hammarfeasta.no\0"
-"hotel.hu\0"
-"net.az\0"
-"jerusalem.museum\0"
-"net.bm\0grajewo.pl\0s3-website.eu-west-3.amazonaws.com\0"
-"net.bn\0"
-"net.bo\0"
-"hadsel.no\0"
-"net.br\0"
-"net.bs\0"
-"net.bt\0"
-"joso.ibaraki.jp\0"
-"arts.museum\0"
-"sibenik.museum\0"
-"ayagawa.kagawa.jp\0"
-"net.ci\0"
-"net.bz\0vibo-valentia.it\0kazuno.akita.jp\0"
-"net.cm\0"
-"net.cn\0hino.tokyo.jp\0michigan.museum\0"
-"net.co\0"
-"izumiotsu.osaka.jp\0"
-"lund.no\0uno\0"
-"k12.la.us\0"
-"net.cu\0"
-"theater.museum\0"
-"net.cw\0louvre.museum\0jevnaker.no\0"
-"juniper\0"
-"net.cy\0"
-"\xe7\x82\xb9\xe7\x9c\x8b\0"
-"net.dm\0takaoka.toyama.jp\0"
-"net.do\0"
-"yakumo.shimane.jp\0b\xc3\xb8.telemark.no\0uol\0"
-"net.ec\0honbetsu.hokkaido.jp\0"
-"univ.sn\0"
-"sandnessjoen.no\0"
-"net.eg\0avocat.pro\0"
-"fl.us\0"
-"\xe5\xb2\x90\xe9\x98\x9c.jp\0"
-"net.dz\0k12.dc.us\0from-ny.net\0"
-"wmflabs.org\0"
-"kokubunji.tokyo.jp\0"
-"aip.ee\0media.hu\0tonosho.kagawa.jp\0wakasa.tottori.jp\0hembygdsforbund.museum\0"
-"bayern\0"
-"vix.br\0"
-"net.et\0"
-"kouyama.kagoshima.jp\0ups\0"
-"medizinhistorisches.museum\0"
-"net.fj\0myiphost.com\0"
-"ind.br\0bozen-sudtirol.it\0"
-"iheya.okinawa.jp\0"
-"*.uberspace.de\0"
-"parti.se\0"
-"internet-dns.de\0"
-"umb.it\0lib.in.us\0"
-"net.ge\0joburg\0"
-"lillesand.no\0"
-"net.gg\0"
-"\xe5\x85\xac\xe5\x8f\xb8.cn\0net.gl\0to.it\0"
-"hasami.nagasaki.jp\0"
-"net.gn\0"
-"froya.no\0"
-"net.gp\0"
-"br\xc3\xb8nn\xc3\xb8y.no\0"
-"net.gr\0"
-"net.gt\0"
-"net.gu\0tjeldsund.no\0"
-"net.gy\0\xe5\x85\xac\xe5\x8f\xb8.hk\0"
-"agematsu.nagano.jp\0"
-"net.hk\0and\xc3\xb8y.no\0"
-"nuoro.it\0"
-"net.hn\0"
-"lacaixa\0"
-"global.prod.fastly.net\0"
-"li.it\0kosaka.akita.jp\0misasa.tottori.jp\0dyn.cosidns.de\0"
-"charter.aero\0"
-"net.ht\0net.id\0"
-"eigersund.no\0\xe5\x80\x8b\xe4\xba\xba.\xe9\xa6\x99\xe6\xb8\xaf\0ap-northeast-1.elasticbeanstalk.com\0"
-"is-a-player.com\0"
-"jpmorgan\0"
-"doomdns.org\0"
-"net.il\0"
-"net.im\0"
-"net.in\0vik.no\0"
-"net.iq\0"
-"net.ir\0snoasa.no\0"
-"net.is\0"
-"net.je\0yokohama\0redirectme.net\0"
-"sakata.yamagata.jp\0"
-"cs.it\0is-a-cubicle-slave.com\0"
-"dyndns-wiki.com\0"
-"shinagawa.tokyo.jp\0"
-"net.jo\0"
-"w.se\0"
-"\xe6\xa0\x83\xe6\x9c\xa8.jp\0"
-"*.nagoya.jp\0medecin.km\0can.museum\0"
-"versicherung\0"
-"yamada.fukuoka.jp\0net.kg\0bel.tr\0"
-"lyngdal.no\0vet\0"
-"kumejima.okinawa.jp\0net.ki\0"
-"christmas\0"
-"istanbul\0"
-"philadelphiaarea.museum\0honda\0"
-"ind.gt\0"
-"net.kn\0"
-"h\xc3\xb8nefoss.no\0"
-"lecce.it\0net.la\0"
-"net.lb\0"
-"net.lc\0volda.no\0"
-"cn-northwest-1.eb.amazonaws.com.cn\0freebox-os.com\0"
-"net.kw\0vana\0"
-"asakuchi.okayama.jp\0net.ky\0folkebibl.no\0honefoss.no\0"
-"net.kz\0namsskogan.no\0total\0"
-"net.lk\0"
-"of.football\0"
-"net.ma\0arkhangelsk.su\0"
-"gosen.niigata.jp\0net.lr\0"
-"net.ls\0tinn.no\0"
-"media.pl\0"
-"net.me\0run.app\0"
-"net.lv\0"
-"ind.in\0design.museum\0origins\0"
-"net.ly\0"
-"net.mk\0"
-"slg.br\0net.ml\0"
-"porsgrunn.no\0"
-"net.mo\0"
-"deatnu.no\0"
-"net.ms\0hammerfest.no\0"
-"net.mt\0"
-"net.mu\0"
-"botany.museum\0net.mv\0net.nf\0"
-"net.mw\0net.ng\0""0e.vc\0"
-"net.mx\0wiw.gov.pl\0"
-"net.my\0net.ni\0"
-"net.mz\0"
-"vig\0"
-"kobayashi.miyazaki.jp\0food\0"
-"yotsukaido.chiba.jp\0"
-"net.nr\0vin\0"
-"vip\0"
-"championship.aero\0sor-varanger.no\0"
-"chungnam.kr\0racing\0"
-"chattanooga.museum\0net.nz\0"
-"al.gov.br\0"
-"net.om\0from-pa.com\0"
-"mombetsu.hokkaido.jp\0*.spectrum.myjino.ru\0"
-"ind.kw\0"
-"net.pa\0"
-"sayama.saitama.jp\0net.pe\0"
-"nsw.au\0yoro.gifu.jp\0net.ph\0test.tj\0firewall-gateway.net\0"
-"akabira.hokkaido.jp\0net.pk\0"
-"\xc3\xa5mot.no\0net.pl\0"
-"meguro.tokyo.jp\0"
-"net.pn\0pokrovsk.su\0",
-
-"sohu\0"
-"net.qa\0"
-"net.pr\0"
-"kameyama.mie.jp\0net.ps\0"
-"net.pt\0"
-"ufcfan.org\0"
-"hoteles\0"
-"forum.hu\0"
-"assabu.hokkaido.jp\0"
-"net.py\0"
-"kakinoki.shimane.jp\0hoylandet.no\0"
-"labour.museum\0ford\0"
-"artdeco.museum\0"
-"couk.me\0"
-"not.br\0"
-"insure\0"
-"j\xc3\xb8lster.no\0"
-"experts-comptables.fr\0lcube-server.de\0"
-"r\xc3\xa6lingen.no\0"
-"sauherad.no\0sells-for-u.com\0"
-"iyo.ehime.jp\0"
-"politica.bo\0"
-"stj\xc3\xb8rdal.no\0redumbrella\0"
-"bardu.no\0"
-"embaixada.st\0"
-"uchinada.ishikawa.jp\0"
-"philately.museum\0net.sa\0"
-"tmp.br\0net.sb\0k12.va.us\0"
-"net.sc\0cn-north-1.eb.amazonaws.com.cn\0test.ru\0"
-"net.sd\0pl.ua\0custom.metacentrum.cz\0"
-"jolster.no\0net.ru\0"
-"net.rw\0net.sg\0mysecuritycamera.net\0"
-"ecologia.bo\0kawaminami.miyazaki.jp\0net.sh\0"
-"stadt.museum\0"
-"pub.sa\0ukco.me\0"
-"net.sl\0"
-"hs.kr\0giehtavuoatna.no\0homesecuritypc.com\0nohost.me\0"
-"tohnosho.chiba.jp\0"
-"archaeological.museum\0net.so\0"
-"sandvikcoromant\0dyndns-office.com\0dyndns.ddnss.de\0iobb.net\0"
-"nisshin.aichi.jp\0"
-"net.ss\0"
-"net.st\0"
-"toyoake.aichi.jp\0swiss\0"
-"gran.no\0net.th\0k12.ms.us\0k12.nc.us\0"
-"net.sy\0"
-"net.tj\0"
-"mutsuzawa.chiba.jp\0"
-"net.tm\0"
-"net.tn\0"
-"net.to\0shiksha\0vlaanderen\0"
-"television.museum\0net.ua\0ky.us\0"
-"omachi.nagano.jp\0net.tr\0"
-"clinton.museum\0"
-"net.tt\0"
-"mukawa.hokkaido.jp\0discovery.museum\0"
-"bykle.no\0net.tw\0"
-"\xe8\xb4\xad\xe7\x89\xa9\0myphotos.cc\0"
-"karuizawa.nagano.jp\0"
-"bpl.biz\0"
-"net.uk\0money\0"
-"gv.vc\0"
-"mar.it\0hb.cldmail.ru\0"
-"fuchu.tokyo.jp\0torsken.no\0\xd1\x83\xd0\xba\xd1\x80\0"
-"cc.nj.us\0"
-"trento.it\0"
-"sth.ac.at\0surrey.museum\0song\0"
-"net.vc\0"
-"creditcard\0"
-"net.ve\0"
-"medio-campidano.it\0familyds.net\0"
-"dc.us\0"
-"net.uy\0net.vi\0customer.speedpartner.de\0"
-"net.uz\0"
-"pri.ee\0"
-"net.vn\0"
-"kitashiobara.fukushima.jp\0"
-"imamat\0"
-"amfam\0"
-"iizuka.fukuoka.jp\0"
-"ferrara.it\0sony\0"
-"vinnytsia.ua\0net.vu\0"
-"caravan\0"
-"arao.kumamoto.jp\0watch-and-clock.museum\0"
-"ris\xc3\xb8r.no\0"
-"alstahaug.no\0"
-"technology\0"
-"lifeinsurance\0"
-"vi.it\0"
-"kurgan.su\0"
-"romskog.no\0lib.hi.us\0net.ws\0"
-"ind.tn\0hsbc\0icbc\0khakassia.su\0no-ip.ca\0"
-"tondabayashi.osaka.jp\0"
-"barlettatraniandria.it\0"
-"kuju.oita.jp\0shopware.store\0"
-"higashi.okinawa.jp\0"
-"kamiamakusa.kumamoto.jp\0"
-"budejju.no\0"
-"stj\xc3\xb8rdalshalsen.no\0capetown\0"
-"kviteseid.no\0enterprisecloud.nu\0"
-"niigata.jp\0property\0"
-"kagawa.jp\0hobol.no\0"
-"ms.it\0s\xc3\xb8r-fron.no\0"
-"principe.st\0spacekit.io\0"
-"miyoshi.saitama.jp\0"
-"obama.fukui.jp\0"
-"\xe9\xab\x98\xe7\x9f\xa5.jp\0"
-"yame.fukuoka.jp\0"
-"net.za\0"
-"pharmacy.museum\0"
-"sagae.yamagata.jp\0"
-"\xd0\xbe\xd0\xb4.\xd1\x81\xd1\x80\xd0\xb1\0"
-"sk\xc3\xa1nit.no\0voorloper.cloud\0"
-"sc.cn\0"
-"wed\0s3.dualstack.ap-northeast-1.amazonaws.com\0"
-"ogawa.ibaraki.jp\0"
-"morotsuka.miyazaki.jp\0"
-"insurance.aero\0net.zm\0"
-"noip.us\0"
-"ee.eu.org\0"
-"ms.kr\0"
-"h.bg\0balsan-suedtirol.it\0"
-"unzen.nagasaki.jp\0stjordalshalsen.no\0"
-"russia.museum\0"
-"gitlab.io\0"
-"us-west-2.elasticbeanstalk.com\0"
-"valle-aosta.it\0"
-"education.museum\0"
-"is-a-rockstar.com\0"
-"fukuchiyama.kyoto.jp\0k12.sc.us\0democrat\0locker\0"
-"lv.ua\0"
-"keymachine.de\0"
-"bbs.tr\0"
-"fj.cn\0phone\0"
-"ama.aichi.jp\0"
-"mugi.tokushima.jp\0"
-"sorum.no\0cipriani\0"
-"uonuma.niigata.jp\0"
-"surnadal.no\0"
-"lima-city.de\0"
-"tsushima.nagasaki.jp\0sande.vestfold.no\0dp.ua\0"
-"crimea.ua\0"
-"honai.ehime.jp\0\xe7\xbd\x91\xe5\xba\x97\0"
-"geometre-expert.fr\0nagiso.nagano.jp\0"
-"iserv.dev\0"
-"in-butter.de\0"
-"aero.tt\0"
-"trentinosudtirol.it\0gub.uy\0"
-"hashimoto.wakayama.jp\0"
-"browsersafetymark.io\0"
-"filatelia.museum\0"
-"medecin.fr\0dyndns-work.com\0"
-"carrara-massa.it\0tranoy.no\0"
-"bifuka.hokkaido.jp\0"
-"kamiizumi.saitama.jp\0"
-"ishikawa.okinawa.jp\0chirurgiens-dentistes-en-france.fr\0"
-"paris.museum\0aero.mv\0"
-"tj\xc3\xb8me.no\0"
-"viking.museum\0"
-"mutual\0win\0"
-"minano.saitama.jp\0\xe3\x83\x9d\xe3\x82\xa4\xe3\x83\xb3\xe3\x83\x88\0lima-city.at\0"
-"palmas.br\0cc.ga.us\0"
-"lib.mi.us\0"
-"transporte.bo\0"
-"\xc3\xa1k\xc5\x8boluokta.no\0"
-"stockholm.museum\0"
-"sobetsu.hokkaido.jp\0tendo.yamagata.jp\0newyork.museum\0"
-"stage.nodeart.io\0"
-"vv.it\0"
-"ong.br\0damnserver.com\0"
-"sologne.museum\0"
-"dunlop\0blogsyte.com\0"
-"seven\0lima-city.ch\0"
-"okaya.nagano.jp\0filegear-sg.me\0"
-"western.museum\0"
-"press.aero\0"
-"shika.ishikawa.jp\0\xd7\x99\xd7\xa8\xd7\x95\xd7\xa9\xd7\x9c\xd7\x99\xd7\x9d.museum\0servequake.com\0"
-"lib.co.us\0yandex\0"
-"catanzaro.it\0"
-"kurate.fukuoka.jp\0"
-"mihara.hiroshima.jp\0"
-"nishigo.fukushima.jp\0"
-"yonago.tottori.jp\0"
-"tachiarai.fukuoka.jp\0"
-"podhale.pl\0netbank\0"
-"hirado.nagasaki.jp\0"
-"sc.ke\0"
-"shimizu.hokkaido.jp\0"
-"hole.no\0"
-"bplaced.de\0"
-"omi.niigata.jp\0indiana.museum\0"
-"wme\0apigee.io\0"
-"banamex\0"
-"izumizaki.fukushima.jp\0sc.kr\0"
-"konskowola.pl\0"
-"stavern.no\0photo\0"
-"sm\xc3\xb8la.no\0"
-"oarai.ibaraki.jp\0"
-"embetsu.hokkaido.jp\0"
-"u.bg\0wolterskluwer\0"
-"fbx-os.fr\0"
-"bg.it\0motorcycles\0"
-"gniezno.pl\0"
-"sc.ls\0"
-"oamishirasato.chiba.jp\0"
-"vi.us\0"
-"fetsund.no\0lindas.no\0"
-"2.bg\0"
-"nc.tr\0for-the.biz\0msk.ru\0"
-"schmidt\0"
-"seranishi.hiroshima.jp\0"
-"airguard.museum\0\xe5\x85\xac\xe5\x8f\xb8.\xe9\xa6\x99\xe6\xb8\xaf\0"
-"williamsburg.museum\0"
-"my-wan.de\0"
-"from-ga.com\0"
-"tahara.aichi.jp\0msk.su\0"
-"ms.us\0nc.us\0\xe3\x82\xb9\xe3\x83\x88\xe3\x82\xa2\0"
-"group\0"
-"wow\0"
-"mmafan.biz\0"
-"kvits\xc3\xb8y.no\0ro.eu.org\0"
-"aosta-valley.it\0"
-"noip.me\0"
-"sakado.saitama.jp\0"
-"tuscany.it\0"
-"gangwon.kr\0lib.ut.us\0dupont\0definima.io\0"
-"servecounterstrike.com\0"
-"hanggliding.aero\0"
-"higashisumiyoshi.osaka.jp\0"
-"rzeszow.pl\0vpndns.net\0"
-"cc.la.us\0"
-"lib.ri.us\0"
-"giize.com\0"
-"*.azurecontainer.io\0"
-"lawyer\0elasticbeanstalk.com\0"
-"gotemba.shizuoka.jp\0"
-"lib.nj.us\0"
-"katsushika.tokyo.jp\0"
-"lesja.no\0spot\0"
-"wallonie.museum\0"
-"pramerica\0"
-"basketball\0"
-"atm.pl\0dh.bytemark.co.uk\0"
-"bulsan-s\xc3\xbc""dtirol.it\0"
-"aknoluokta.no\0overhalla.no\0"
-"inzai.chiba.jp\0"
-"yokosuka.kanagawa.jp\0channel\0"
-"traniandriabarletta.it\0"
-"cincinnati.museum\0loabat.no\0"
-"piedmont.it\0sp.it\0ayase.kanagawa.jp\0"
-"kamikoani.akita.jp\0"
-"biz.bb\0yazu.tottori.jp\0opoczno.pl\0dnsking.ch\0"
-"biz.at\0"
-"wtc\0"
-"edu.ac\0"
-"rio.br\0"
-"wtf\0"
-"edu.af\0biz.az\0hanamaki.iwate.jp\0from-nv.com\0"
-"oz.au\0gucci\0si.eu.org\0"
-"haga.tochigi.jp\0snasa.no\0"
-"edu.al\0"
-"edu.ba\0yawatahama.ehime.jp\0torahime.shiga.jp\0skanit.no\0vikna.no\0"
-"edu.ar\0edu.bb\0"
-"kerryproperties\0"
-"edu.au\0aquarium.museum\0"
-"edu.bh\0net.eu.org\0"
-"edu.bi\0soma.fukushima.jp\0"
-"edu.az\0"
-"alsace\0gives\0"
-"edu.bm\0mining.museum\0wzmiuw.gov.pl\0office-on-the.net\0"
-"edu.bn\0"
-"edu.bo\0lahppi.no\0"
-"kinder\0azerbaijan.su\0"
-"tm.cy\0svalbard.no\0"
-"edu.br\0"
-"edu.bs\0aguni.okinawa.jp\0"
-"edu.bt\0"
-"biz.cy\0"
-"bt.it\0"
-"biz.dk\0"
-"edu.ci\0kakogawa.hyogo.jp\0sakuho.nagano.jp\0"
-"edu.bz\0"
-"sc.ug\0"
-"toshima.tokyo.jp\0ws.na\0"
-"edu.cn\0h.se\0sc.tz\0"
-"edu.co\0"
-"kr.com\0"
-"office\0"
-"edu.cu\0"
-"nago.okinawa.jp\0"
-"edu.cw\0sc.us\0"
-"cieszyn.pl\0"
-"sorfold.no\0game\0"
-"aoki.nagano.jp\0docs\0"
-"edu.dm\0cn.eu.org\0"
-"homesecuritymac.com\0"
-"edu.do\0wildlife.museum\0"
-"biz.et\0"
-"res.aero\0"
-"cq.cn\0taifun-dns.de\0"
-"edu.ec\0"
-"edu.ee\0toyooka.hyogo.jp\0kannami.shizuoka.jp\0miyoshi.tokushima.jp\0"
-"biz.fj\0sex.hu\0"
-"edu.eg\0is-a-musician.com\0"
-"sk.eu.org\0"
-"edu.dz\0tm.fr\0\xd8\xaa\xd9\x88\xd9\x86\xd8\xb3\0"
-"olbiatempio.it\0"
-"tours\0"
-"helsinki\0"
-"ingatlan.hu\0"
-"edu.es\0lib.wi.us\0"
-"edu.et\0"
-"ostrowwlkp.pl\0"
-"from.hr\0"
-"lenvik.no\0biz.gl\0"
-"sanuki.kagawa.jp\0toyo.kochi.jp\0sekikawa.niigata.jp\0"
-"umi.fukuoka.jp\0"
-"xin\0"
-"social\0"
-"edu.ge\0mysecuritycamera.org\0"
-"edu.gh\0shishikui.tokushima.jp\0"
-"edu.gi\0lib.mo.us\0"
-"suli.hu\0virtual-user.de\0"
-"edu.gl\0kagoshima.jp\0workshop.museum\0lenug.su\0"
-"tm.hu\0"
-"edu.gn\0"
-"edu.gp\0biz.id\0\xe7\xa7\x8b\xe7\x94\xb0.jp\0"
-"rel.ht\0altoadige.it\0naturbruksgymn.se\0"
-"edu.gr\0taiwa.miyagi.jp\0shopping\0"
-"edu.gt\0gs.va.no\0"
-"edu.gu\0"
-"gotsu.shimane.jp\0mer\xc3\xa5ker.no\0"
-"taki.mie.jp\0szkola.pl\0"
-"edu.gy\0"
-"edu.hk\0cartoonart.museum\0"
-"cpa.pro\0"
-"maizuru.kyoto.jp\0s3-ap-northeast-1.amazonaws.com\0"
-"edu.hn\0koga.fukuoka.jp\0"
-"urayasu.chiba.jp\0*.moonscale.io\0"
-"tomioka.gunma.jp\0kindle\0"
-"edu.ht\0"
-"blog\0adygeya.su\0"
-"ru.eu.org\0se.eu.org\0"
-"higashiosaka.osaka.jp\0"
-"edu.in\0mini\0"
-"dattolocal.com\0"
-"edu.iq\0rebun.hokkaido.jp\0*.lcl.dev\0"
-"\xe5\xbe\xae\xe5\x8d\x9a\0"
-"edu.is\0gifu.gifu.jp\0muenster.museum\0"
-"edu.it\0"
-"biz.ki\0tm.km\0"
-"bomlo.no\0weber\0"
-"outsystemscloud.com\0"
-"finnoy.no\0mint\0"
-"meloy.no\0"
-"minato.tokyo.jp\0dyndns-at-home.com\0"
-"sannan.hyogo.jp\0cy.eu.org\0"
-"lg.jp\0hirono.iwate.jp\0"
-"edu.jo\0"
-"kaizuka.osaka.jp\0karatsu.saga.jp\0"
-"static.observableusercontent.com\0"
-"br.com\0nerdpol.ovh\0"
-"okayama.jp\0fed.us\0"
-"arq.br\0"
-"edu.kg\0upow.gov.pl\0"
-"md.ci\0edu.ki\0otsuka\0dnsiskinky.com\0"
-"modena.it\0"
-"tm.mc\0"
-"roma.it\0"
-"club.aero\0edu.km\0jamison.museum\0"
-"edu.kn\0dattoweb.com\0"
-"biz.ls\0tm.mg\0balashov.su\0"
-"edu.kp\0u.se\0"
-"edu.la\0talk\0workisboring.com\0"
-"otama.fukushima.jp\0edu.lb\0fedorapeople.org\0"
-"edu.lc\0"
-"adygeya.ru\0"
-"monzaedellabrianza.it\0"
-"ogi.saga.jp\0edu.kw\0pcloud.host\0"
-"edu.ky\0free\0"
-"edu.kz\0"
-"edu.lk\0"
-"sex.pl\0cz.eu.org\0lpusercontent.com\0"
-"tamba.hyogo.jp\0"
-"edu.lr\0biz.mv\0"
-"edu.ls\0biz.mw\0"
-"edu.me\0biz.ni\0"
-"edu.lv\0"
-"edu.mg\0tm.no\0style\0"
-"yokkaichi.mie.jp\0ojiya.niigata.jp\0cc.va.us\0"
-"edu.ly\0"
-"edu.mk\0"
-"edu.ml\0"
-"berkeley.museum\0kragero.no\0\xe4\xb8\xad\xe5\x9b\xbd\0online\0meteorapp.com\0"
-"edu.mn\0biz.nr\0"
-"valle-daosta.it\0edu.mo\0"
-"parachuting.aero\0def.br\0"
-"ibigawa.gifu.jp\0yoshimi.saitama.jp\0algard.no\0"
-"edu.ms\0"
-"edu.mt\0"
-"edu.mv\0"
-"edu.mw\0edu.ng\0"
-"edu.mx\0ddnsking.com\0"
-"fst.br\0edu.my\0edu.ni\0"
-"aostavalley.it\0toon.ehime.jp\0edu.mz\0"
-"\xe4\xb8\xad\xe5\x9c\x8b\0gallo\0"
-"ookuwa.nagano.jp\0"
-"\xe7\xbd\x91\xe7\xbb\x9c.cn\0dk.eu.org\0"
-"\xc3\xa5rdal.no\0"
-"acct.pro\0ollo\0"
-"ryukyu\0"
-"tenkawa.nara.jp\0"
-"taishi.osaka.jp\0edu.nr\0"
-"blue\0tattoo\0"
-"tm.pl\0"
-"kristiansand.no\0"
-"yamanobe.yamagata.jp\0biz.pk\0k12.ak.us\0"
-"kawahara.tottori.jp\0biz.pl\0"
-"friulive-giulia.it\0rel.pl\0"
-"hayakawa.yamanashi.jp\0"
-"kitayama.wakayama.jp\0"
-"edu.om\0"
-"biz.pr\0"
-"americanantiques.museum\0"
-"edu.pa\0"
-"edu.pe\0"
-"edu.pf\0"
-"s3-fips-us-gov-west-1.amazonaws.com\0"
-"edu.ph\0"
-"friuli-vgiulia.it\0"
-"edu.pk\0khmelnytskyi.ua\0"
-"nishinomiya.hyogo.jp\0edu.pl\0babia-gora.pl\0"
-"control.aero\0"
-"monza-brianza.it\0edu.pn\0s3.ap-northeast-2.amazonaws.com\0"
-"edu.qa\0"
-"edu.pr\0"
-"niyodogawa.kochi.jp\0edu.ps\0"
-"barletta-trani-andria.it\0edu.pt\0"
-"tm.ro\0pa.leg.br\0"
-"edu.py\0"
-"bharti\0"
-"leg.br\0yorii.saitama.jp\0"
-"kuroishi.aomori.jp\0tm.se\0"
-"manx.museum\0gbiz\0"
-"zj.cn\0gop.pk\0"
-"brasil.museum\0"
-"niimi.okayama.jp\0"
-"mima.tokushima.jp\0"
-"fujiyoshida.yamanashi.jp\0"
-"lt.it\0familyds.org\0"
-"in-brb.de\0"
-"cuisinella\0"
-"asn.au\0"
-"itoigawa.niigata.jp\0alt.za\0"
-"dominic.ua\0de.eu.org\0freetls.fastly.net\0"
-"\xe5\x98\x89\xe9\x87\x8c\xe5\xa4\xa7\xe9\x85\x92\xe5\xba\x97\0khplay.nl\0"
-"biz.ss\0"
-"viterbo.it\0"
-"tarnobrzeg.pl\0edu.sa\0"
-"edu.sb\0"
-"edu.rs\0edu.sc\0"
-"edu.sd\0ieee\0"
-"polkowice.pl\0edu.ru\0"
-"jeonbuk.kr\0biz.tj\0"
-"edu.sg\0pb.leg.br\0bounty-full.com\0"
-"\xe7\xbd\x91\xe7\xbb\x9c.hk\0"
-"edu.sl\0"
-"biz.ua\0"
-"edu.sn\0biz.tr\0futuremailing.at\0"
-"edu.so\0"
-"biz.tt\0"
-"kanagawa.jp\0"
-"edu.ss\0"
-"edu.st\0"
-"ikeda.gifu.jp\0hemsedal.no\0"
-"edu.sv\0homesense\0"
-"iide.yamagata.jp\0war.museum\0"
-"edu.sy\0"
-"frosinone.it\0edu.tj\0"
-"viajes\0"
-"edu.tm\0dyndns-web.com\0"
-"huissier-justice.fr\0"
-"edu.to\0lg.ua\0servehumour.com\0"
-"is-a-green.com\0"
-"edu.ua\0"
-"ooshika.nagano.jp\0kamo.niigata.jp\0abu.yamaguchi.jp\0edu.tr\0"
-"edu.tt\0"
-"nt.edu.au\0"
-"skole.museum\0edu.tw\0"
-"lincoln\0select\0"
-"biz.vn\0"
-"hita.oita.jp\0olayangroup\0"
-"rade.no\0"
-"yachts\0"
-"ah.cn\0kadena.okinawa.jp\0*.customer-oci.com\0"
-"yabuki.fukushima.jp\0"
-"edu.vc\0"
-"kosei.shiga.jp\0"
-"edu.ve\0"
-"wanouchi.gifu.jp\0kitaura.miyazaki.jp\0"
-"xxx\0"
-"edu.uy\0"
-"hasama.oita.jp\0"
-"edu.vn\0"
-"piemonte.it\0cc.nh.us\0"
-"nogata.fukuoka.jp\0edu.vu\0"
-"goldpoint\0"
-"k12.az.us\0xyz\0"
-"mjondalen.no\0"
-"oregon.museum\0games\0taxi\0"
-"andria-barletta-trani.it\0"
-"sannohe.aomori.jp\0edu.ws\0"
-"usa.oita.jp\0s3.dualstack.eu-west-3.amazonaws.com\0"
-"yokoshibahikari.chiba.jp\0barcelona.museum\0poniatowa.pl\0"
-"tm.za\0"
-"\xe5\xba\x83\xe5\xb3\xb6.jp\0is-a-lawyer.com\0"
-"umbria.it\0"
-"tobe.ehime.jp\0"
-"sk\xc3\xa5nland.no\0"
-"misawa.aomori.jp\0nagasu.kumamoto.jp\0judaica.museum\0"
-"christiansburg.museum\0biz.zm\0"
-"bulsan-sudtirol.it\0shimodate.ibaraki.jp\0sakyo.kyoto.jp\0""1kapp.com\0"
-"trani-barletta-andria.it\0evje-og-hornnes.no\0\xe0\xb8\x98\xe0\xb8\xb8\xe0\xb8\xa3\xe0\xb8\x81\xe0\xb8\xb4\xe0\xb8\x88.\xe0\xb9\x84\xe0\xb8\x97\xe0\xb8\xa2\0"
-"production.aero\0sa.au\0attorney\0"
-"edu.za\0"
-"na.it\0olbia-tempio.it\0iwade.wakayama.jp\0dsmynas.com\0"
-"ntr.br\0yusuhara.kochi.jp\0"
-"s3-website.eu-west-2.amazonaws.com\0"
-"t3l3p0rt.net\0"
-"baltimore.museum\0edu.zm\0est-mon-blogueur.com\0ca.eu.org\0"
-"shintomi.miyazaki.jp\0"
-"!city.kawasaki.jp\0matsushima.miyagi.jp\0"
-"sor-odal.no\0sanok.pl\0"
-"itami.hyogo.jp\0kawai.nara.jp\0"
-"sa.cr\0"
-"\xe5\xb3\xb6\xe6\xa0\xb9.jp\0rikubetsu.hokkaido.jp\0"
-"shiroi.chiba.jp\0"
-"iki.fi\0"
-"trentino-sud-tirol.it\0"
-"takahama.aichi.jp\0higashimatsushima.miyagi.jp\0"
-"f.bg\0ishinomaki.miyagi.jp\0tra.kp\0asker.no\0bo.telemark.no\0"
-"virtual.museum\0"
-"q-a.eu.org\0"
-"trentin-suedtirol.it\0*.kawasaki.jp\0"
-"ogano.saitama.jp\0lt.ua\0"
-"okinawa.okinawa.jp\0"
-"you\0"
-"zlg.br\0abr.it\0auction\0"
-"nagasaki.nagasaki.jp\0"
-"k12.oh.us\0"
-"agr.br\0higashiizumo.shimane.jp\0"
-"asn.lv\0embroidery.museum\0"
-"makurazaki.kagoshima.jp\0miasta.pl\0"
-"kawajima.saitama.jp\0"
-"md.us\0"
-"wuoz.gov.pl\0"
-"poa.br\0dn.ua\0media\0"
-"itakura.gunma.jp\0dnsdojo.org\0"
-"is-lost.org\0dyn53.io\0"
-"uk0.bigv.io\0"
-"godo.gifu.jp\0in.na\0vagsoy.no\0ia.us\0"
-"cust.dev.thingdust.io\0"
-"from-nj.com\0barsy.support\0"
-"cloudeity.net\0"
-"airforce\0lamer\0"
-"in.ni\0republican\0kinghost.net\0"
-"ddns.me\0"
-"hokuryu.hokkaido.jp\0"
-"heroy.nordland.no\0"
-"kiryu.gunma.jp\0"
-"amica\0"
-"show.aero\0m\xc3\xa1latvuopmi.no\0"
-"rakkestad.no\0"
-"in-vpn.org\0"
-"schools.nsw.edu.au\0sells-for-less.com\0"
-"andriatranibarletta.it\0numata.gunma.jp\0"
-"haram.no\0"
-"\xc3\xb8ygarden.no\0"
-"amsterdam.museum\0h\xc3\xa1pmir.no\0\xd0\xbe\xd0\xb1\xd1\x80.\xd1\x81\xd1\x80\xd0\xb1\0cd.eu.org\0"
-"nexus\0"
-"vt.it\0ah.no\0jp.net\0"
-"lib.il.us\0"
-"pi.leg.br\0"
-"\xe0\xb8\x84\xe0\xb8\xad\xe0\xb8\xa1\0"
-"gujo.gifu.jp\0"
-"agrinet.tn\0"
-"navuotna.no\0"
-"sa.it\0"
-"from-il.com\0mywire.org\0krakow.pl\0"
-"co.events\0"
-"stranda.no\0"
-"awsmppl.com\0"
-"takanezawa.tochigi.jp\0"
-"yun\0"
-"catering.aero\0saogonca.br\0collection.museum\0gwiddle.co.uk\0"
-"from-mi.com\0"
-"fie.ee\0"
-"takatsuki.shiga.jp\0ama.shimane.jp\0histoire.museum\0"
-"trentin-s\xc3\xbc""dtirol.it\0"
-"kuromatsunai.hokkaido.jp\0baghdad.museum\0"
-"sn.cn\0"
-"fuefuki.yamanashi.jp\0co.financial\0"
-"is-uberleet.com\0"
-"intel\0"
-"in.rs\0"
-"kicks-ass.net\0"
-"\xc3\xa5l.no\0dyndns.tv\0"
-"teaches-yoga.com\0"
-"k12.wy.us\0community-pro.net\0"
-"s.bg\0"
-"r\xc3\xa5""de.no\0"
-"imakane.hokkaido.jp\0"
-"fishing\0"
-"lillehammer.no\0"
-"losangeles.museum\0"
-"jx.cn\0"
-"kamitonda.wakayama.jp\0"
-"in-addr.arpa\0orskog.no\0"
-"0.bg\0trentino-s\xc3\xbc""d-tirol.it\0"
-"sumoto.kumamoto.jp\0"
-"in.th\0"
-"amber.museum\0"
-"gen.in\0"
-"nishi.osaka.jp\0"
-"in.ua\0"
-"qualifioapp.com\0"
-"minamiminowa.nagano.jp\0us-east-1.amazonaws.com\0"
-"\xe8\x8c\xa8\xe5\x9f\x8e.jp\0\xed\x95\x9c\xea\xb5\xad\0"
-"eidfjord.no\0sykkylven.no\0"
-"etisalat\0"
-"zip\0"
-"in.us\0dyndns.ws\0"
-"floro.no\0productions\0"
-"cc.or.us\0"
-"scienceandhistory.museum\0"
-"dni.us\0lundbeck\0"
-"holmestrand.no\0"
-"art.museum\0certmgr.org\0"
-"b\xc3\xa1jddar.no\0"
-"qpon\0schokokeks.net\0"
-"kunohe.iwate.jp\0webhop.me\0"
-"nissan\0"
-"trentino-aadige.it\0"
-"barsy.menu\0"
-"shimoichi.nara.jp\0"
-"southcarolina.museum\0gs.tr.no\0lib.ia.us\0pe.leg.br\0"
-"nissay\0"
-"tsunan.niigata.jp\0"
-"ayabe.kyoto.jp\0"
-"dyndns-remote.com\0"
-"from-ri.com\0gen.ng\0"
-"jewishart.museum\0"
-"wanggou\0"
-"moonscale.net\0"
-"\xd9\x83\xd8\xa7\xd8\xab\xd9\x88\xd9\x84\xd9\x8a\xd9\x83\0"
-"geisei.kochi.jp\0hachioji.tokyo.jp\0"
-"\xc3\xb8rland.no\0"
-"ribeirao.br\0thingdustdata.com\0"
-"yokote.akita.jp\0"
-"fuchu.toyama.jp\0"
-"\xd8\xa7\xd8\xb1\xd8\xa7\xd9\x85\xd9\x83\xd9\x88\0"
-"gen.nz\0curv.dev\0"
-"ng.ink\0"
-"civilization.museum\0bindal.no\0"
-"\xe9\x80\x9a\xe8\xb2\xa9\0"
-"devices.resinstaging.io\0"
-"shonai.yamagata.jp\0lajolla.museum\0"
-"vindafjord.no\0"
-"iwate.jp\0"
-"co.ae\0uenohara.yamanashi.jp\0orland.no\0"
-"minamiboso.chiba.jp\0dnepropetrovsk.ua\0\xe0\xa4\xad\xe0\xa4\xbe\xe0\xa4\xb0\xe0\xa4\xa4\0"
-"co.ag\0ge.it\0is-a-personaltrainer.com\0"
-"lubin.pl\0"
-"kaufen\0"
-"co.am\0shikabe.hokkaido.jp\0aca.pro\0"
-"wmcloud.org\0"
-"co.ao\0laspezia.it\0oizumi.gunma.jp\0tadaoka.osaka.jp\0"
-"co.bb\0br.it\0cb.it\0"
-"co.at\0teramo.it\0"
-"fh.se\0"
-"kitahiroshima.hokkaido.jp\0vt.us\0"
-"co.bi\0norton\0"
-"f.se\0"
-"zp.gov.pl\0"
-"dscloud.mobi\0"
-"\xd8\xa7\xd9\x8a\xd8\xb1\xd8\xa7\xd9\x86.ir\0presidio.museum\0schoenbrunn.museum\0"
-"kotoura.tottori.jp\0co.bn\0"
-"co.ca\0worse-than.tv\0"
-"lixil\0from-wa.com\0"
-"hb.cn\0"
-"grosseto.it\0education\0"
-"co.bw\0chikuhoku.nagano.jp\0"
-"co.ci\0myqnapcloud.com\0"
-"and.mom\0"
-"co.cl\0"
-"co.cm\0"
-"co.cr\0trentino-s-tirol.it\0"
-"bmoattachments.org\0"
-"taxi.br\0"
-"co.cz\0serveexchange.com\0"
-"s3.ap-south-1.amazonaws.com\0co.dk\0"
-"a\xc3\xa9roport.ci\0"
-"joetsu.niigata.jp\0"
-"\xe4\xbf\xa1\xe6\x81\xaf\0"
-"cultural.museum\0"
-"sumoto.hyogo.jp\0"
-"s\xc3\xa1lat.no\0"
-"sosa.chiba.jp\0bofa\0"
-"calabria.it\0jefferson.museum\0"
-"kaisei.kanagawa.jp\0poker\0*.on-rancher.cloud\0"
-"kasugai.aichi.jp\0square.museum\0"
-"med.br\0georgia.su\0"
-"kamisunagawa.hokkaido.jp\0"
-"eu-west-2.elasticbeanstalk.com\0"
-"sera.hiroshima.jp\0kameoka.kyoto.jp\0"
-"chicago.museum\0"
-"urn.arpa\0cc.hi.us\0"
-"moriyama.shiga.jp\0gen.tr\0"
-"tecnologia.bo\0kunimi.fukushima.jp\0"
-"crafting.xyz\0"
-"minamioguni.kumamoto.jp\0drud.io\0"
-"kitami.hokkaido.jp\0\xe7\xbb\x84\xe7\xbb\x87\xe6\x9c\xba\xe6\x9e\x84\0"
-"hisayama.fukuoka.jp\0"
-"estate\0"
-"s3-sa-east-1.amazonaws.com\0"
-"star\0"
-"*.transurl.be\0"
-"raid\0"
-"co.gg\0doesntexist.com\0"
-"radio.br\0"
-"med.ec\0cambridge.museum\0langevag.no\0"
-"yk.ca\0co.gl\0"
-"med.ee\0shibukawa.gunma.jp\0grondar.za\0"
-"v\xc3\xa5gs\xc3\xb8y.no\0"
-"trainer.aero\0\xd8\xa8\xd8\xa7\xd8\xb1\xd8\xaa\0horse\0"
-"s\xc3\xb8rum.no\0"
-"otake.hiroshima.jp\0dallas.museum\0"
-"nishihara.okinawa.jp\0broadcast.museum\0"
-"co.gy\0"
-"funagata.yamagata.jp\0"
-"larsson.museum\0issmarterthanyou.com\0"
-"le.it\0kadoma.osaka.jp\0pr.leg.br\0"
-"furniture.museum\0berlev\xc3\xa5g.no\0\xe6\x9c\xba\xe6\x9e\x84\0"
-"gb.net\0"
-"shirakawa.gifu.jp\0jpn.com\0"
-"pgafan.net\0"
-"co.id\0"
-"co.hu\0mragowo.pl\0"
-"reggio-calabria.it\0\xd8\xa8\xd9\x8a\xd8\xaa\xd9\x83\0"
-"gr.it\0"
-"museum\0giving\0"
-"fujisawa.iwate.jp\0szczecin.pl\0"
-"co.il\0kashiba.nara.jp\0"
-"mb.ca\0co.im\0"
-"broker.aero\0co.in\0shiraoi.hokkaido.jp\0"
-"wnext.app\0"
-"zagan.pl\0"
-"co.ir\0"
-"co.it\0asakawa.fukushima.jp\0yabu.hyogo.jp\0"
-"co.je\0gr.jp\0hagebostad.no\0vadso.no\0dnsalias.com\0"
-"is-a-techie.com\0"
-"nagaokakyo.kyoto.jp\0"
-"ishikari.hokkaido.jp\0"
-"linkyard-cloud.ch\0"
-"kmpsp.gov.pl\0s.se\0"
-"toyohashi.aichi.jp\0"
-"co.jp\0gemological.museum\0grocery\0*.transurl.eu\0"
-"shimoda.shizuoka.jp\0radoy.no\0tsk.tr\0"
-"halsa.no\0"
-"co.ke\0steigen.no\0"
-"novara.it\0"
-"kagami.kochi.jp\0kh.ua\0"
-"corporation.museum\0"
-"kamioka.akita.jp\0"
-"med.ht\0"
-"sauda.no\0"
-"minami.tokushima.jp\0game.tw\0"
-"ok.us\0\xec\x82\xbc\xec\x84\xb1\0"
-"hiratsuka.kanagawa.jp\0"
-"co.kr\0k12.md.us\0"
-"co.lc\0"
-"leasing.aero\0"
-"tomi.nagano.jp\0is-a-financialadvisor.com\0protonet.io\0"
-"trentinoaltoadige.it\0"
-"ascoli-piceno.it\0"
-"fuossko.no\0"
-"mlbfan.org\0"
-"abc.br\0vestre-slidre.no\0"
-"voagat.no\0krym.ua\0"
-"co.ma\0"
-"co.ls\0oceanographique.museum\0"
-"hamatonbetsu.hokkaido.jp\0co.me\0autos\0"
-"co.mg\0"
-"takko.aomori.jp\0bond\0"
-"vantaa.museum\0cc.mi.us\0"
-"network\0"
-"lucca.it\0from-hi.com\0"
-"vaapste.no\0"
-"toyosato.shiga.jp\0"
-"co.na\0"
-"abashiri.hokkaido.jp\0"
-"ch.eu.org\0"
-"association.aero\0co.mu\0"
-"myftp.org\0"
-"co.mw\0"
-"co.ni\0"
-"co.mz\0online.th\0"
-"skjak.no\0co.nl\0"
-"panasonic\0"
-"co.no\0"
-"book\0"
-"smart\0"
-"sciences.museum\0cloud.metacentrum.cz\0"
-"mizunami.gifu.jp\0"
-"averoy.no\0"
-"co.nz\0"
-"tsuwano.shimane.jp\0"
-"dnsdojo.net\0"
-"matsuno.ehime.jp\0barum.no\0co.om\0"
-"iwanuma.miyagi.jp\0"
-"med.ly\0"
-"pu.it\0kiyosato.hokkaido.jp\0"
-"tur.ar\0tamano.okayama.jp\0"
-"iwamizawa.hokkaido.jp\0"
-"nore-og-uvdal.no\0"
-"chikuho.fukuoka.jp\0gon.pk\0"
-"co.pl\0"
-"tohma.hokkaido.jp\0"
-"uppo.gov.pl\0co.pn\0"
-"mb.it\0"
-"kunitomi.miyazaki.jp\0za.net\0"
-"narita.chiba.jp\0s3-website.ca-central-1.amazonaws.com\0ox.rs\0"
-"galsa.no\0"
-"richardli\0"
-"co.pw\0"
-"tur.br\0"
-"kiwi\0"
-"stuttgart.museum\0shouji\0"
-"meiwa.gunma.jp\0kusatsu.shiga.jp\0"
-"yuzawa.niigata.jp\0"
-"med.om\0"
-"research.aero\0"
-"med.pa\0"
-"mo.cn\0drud.us\0"
-"corsica\0"
-"co.rs\0"
-"med.pl\0"
-"eastcoast.museum\0"
-"osaki.miyagi.jp\0"
-"co.rw\0*.transurl.nl\0"
-"alto-adige.it\0samukawa.kanagawa.jp\0ichikawamisato.yamanashi.jp\0"
-"voss.no\0"
-"pvh.br\0kazimierz-dolny.pl\0"
-"val-d-aosta.it\0"
-"kin.okinawa.jp\0"
-"shikama.miyagi.jp\0"
-"co.st\0\xe0\xb8\xad\xe0\xb8\x87\xe0\xb8\x84\xe0\xb9\x8c\xe0\xb8\x81\xe0\xb8\xa3.\xe0\xb9\x84\xe0\xb8\x97\xe0\xb8\xa2\0"
-"magazine.aero\0"
-"sondrio.it\0"
-"campania.it\0co.th\0tienda\0"
-"co.sz\0co.tj\0noho.st\0"
-"wakkanai.hokkaido.jp\0dnsfor.me\0"
-"fuchu.hiroshima.jp\0"
-"co.tm\0"
-"sp.gov.br\0miki.hyogo.jp\0co.network\0"
-"chikuzen.fukuoka.jp\0cc.ri.us\0co.ua\0"
-"co.tt\0politie\0cloudns.club\0"
-"shimogo.fukushima.jp\0iwata.shizuoka.jp\0"
-"co.ug\0"
-"palermo.it\0malatvuopmi.no\0amsterdam\0"
-"med.sa\0"
-"co.tz\0"
-"co.uk\0kicks-ass.org\0"
-"med.sd\0"
-"s\xc3\xb8ndre-land.no\0on.fashion\0"
-"co.us\0"
-"at.eu.org\0"
-"exeter.museum\0co.ve\0"
-"ip6.arpa\0"
-"kamoenai.hokkaido.jp\0"
-"tsuruga.fukui.jp\0quest\0"
-"oga.akita.jp\0co.vi\0"
-"co.uz\0team\0"
-"gjesdal.no\0dy.fi\0"
-"council.aero\0"
-"mashiko.tochigi.jp\0"
-"ponpes.id\0"
-"works\0"
-"toscana.it\0world\0"
-"cherkassy.ua\0"
-"federation.aero\0career\0"
-"kharkov.ua\0yodobashi\0"
-"ve.it\0baths.museum\0"
-"tuxfamily.org\0"
-"gs.sf.no\0"
-"etc.br\0"
-"bjark\xc3\xb8y.no\0tech\0"
-"inuyama.aichi.jp\0"
-"oceanographic.museum\0"
-"so.gov.pl\0"
-"livorno.it\0"
-"torino.it\0giske.no\0"
-"travel\0mayfirst.org\0"
-"mod.gi\0tamakawa.fukushima.jp\0"
-"webcam\0fantasyleague.cc\0"
-"ito.shizuoka.jp\0corvette.museum\0"
-"mo.it\0nis.za\0"
-"gjerdrum.no\0"
-"kitchen\0in-vpn.net\0"
-"*.sapporo.jp\0"
-"recipes\0"
-"openair.museum\0"
-"securitytactics.com\0"
-"imageandsound.museum\0"
-"mitsuke.niigata.jp\0gs.fm.no\0"
-"nl.ca\0co.za\0"
-"tires\0"
-"unicom\0"
-"tagawa.fukuoka.jp\0"
-"tree.museum\0"
-"co.zm\0fitness\0"
-"nikolaev.ua\0"
-"sweden.museum\0fund\0"
-"minowa.nagano.jp\0k12.vt.us\0resindevice.io\0"
-"d.bg\0\xeb\x8b\xb7\xec\xbb\xb4\0"
-"kanie.aichi.jp\0"
-"co.zw\0"
-"tx.us\0"
-"gent\0"
-"aichi.jp\0"
-"bc.ca\0cloud66.ws\0"
-"ashoro.hokkaido.jp\0community\0lab.ms\0"
-"bar.pro\0"
-"nanbu.yamanashi.jp\0k12.nv.us\0homelinux.com\0"
-"cc.wi.us\0no.com\0"
-"manno.kagawa.jp\0"
-"yamatotakada.nara.jp\0\xd8\xa8\xda\xbe\xd8\xa7\xd8\xb1\xd8\xaa\0"
-"enonic.io\0"
-"\xd8\xa7\xd9\x84\xd8\xa7\xd8\xb1\xd8\xaf\xd9\x86\0"
-"uzs.gov.pl\0s3-website.ap-south-1.amazonaws.com\0"
-"ueno.gunma.jp\0"
-"encyclopedic.museum\0"
-"open\0"
-"trentinos\xc3\xbc""dtirol.it\0showa.gunma.jp\0"
-"nishinoshima.shimane.jp\0"
-"crotone.it\0"
-"oystre-slidre.no\0"
-"environment.museum\0"
-"\xe0\xb4\xad\xe0\xb4\xbe\xe0\xb4\xb0\xe0\xb4\xa4\xe0\xb4\x82\0"
-"ujiie.tochigi.jp\0shirahama.wakayama.jp\0blogspot.co.at\0"
-"k12.ec\0s3-ap-northeast-2.amazonaws.com\0"
-"k12.as.us\0"
-"kafjord.no\0"
-"blogspot.vn\0"
-"annaka.gunma.jp\0"
-"\xe0\xa4\x95\xe0\xa5\x89\xe0\xa4\xae\0"
-"saitama.jp\0"
-"futaba.fukushima.jp\0yahaba.iwate.jp\0ddnsfree.com\0"
-"nikko.tochigi.jp\0"
-"freemasonry.museum\0"
-"wajiki.tokushima.jp\0nh-serv.co.uk\0"
-"namegawa.saitama.jp\0vestvagoy.no\0"
-"australia.museum\0cloudfunctions.net\0"
-"vr.it\0"
-"catania.it\0cc.az.us\0"
-"desa.id\0"
-"ro.im\0"
-"steam.museum\0"
-"surgery\0"
-"shimane.shimane.jp\0"
-"tolga.no\0swiftcover\0"
-"hamatama.saga.jp\0"
-"ro.it\0"
-"dyndns-free.com\0"
-"lib.dc.us\0"
-"chikusei.ibaraki.jp\0"
-"museumcenter.museum\0"
-"pagefrontapp.com\0"
-"koori.fukushima.jp\0assn.lk\0"
-"lebesby.no\0\xd8\xa7\xd9\x84\xd8\xac\xd8\xb2\xd8\xa7\xd8\xa6\xd8\xb1\0"
-"r\xc3\xa1isa.no\0"
-"shimane.jp\0"
-"seljord.no\0*.on-k3s.io\0"
-"courses\0s3-ca-central-1.amazonaws.com\0"
-"shiroishi.miyagi.jp\0"
-"\xe5\xae\xb6\xe9\x9b\xbb\0"
-"eurovision\0"
-"kitaaiki.nagano.jp\0fastvps-server.com\0"
-"blogspot.re\0"
-"sodegaura.chiba.jp\0"
-"trentino.it\0mymediapc.net\0"
-"sr.gov.pl\0ens.tn\0"
-"troandin.no\0"
-"aizuwakamatsu.fukushima.jp\0"
-"yamato.kanagawa.jp\0is-a-libertarian.com\0blogspot.ro\0"
-"fedje.no\0"
-"k12.il\0birthplace.museum\0"
-"akita.akita.jp\0ibaraki.ibaraki.jp\0kawakami.nara.jp\0blogspot.rs\0"
-"turek.pl\0blogspot.ru\0blogspot.se\0"
-"q.bg\0computer.museum\0blogspot.sg\0"
-"nyc.mn\0"
-"blogspot.si\0"
-"asuke.aichi.jp\0"
-"blogspot.sk\0"
-"jus.br\0m\xc3\xa5lselv.no\0"
-"gc.ca\0hob\xc3\xb8l.no\0"
-"blogspot.sn\0"
-"coupons\0tirol\0"
-"amagasaki.hyogo.jp\0"
-"oyabe.toyama.jp\0london.museum\0"
-"blogspot.td\0"
-"*.kitakyushu.jp\0"
-"onred.one\0"
-"maryland.museum\0"
-"fuoisku.no\0"
-"rahkkeravju.no\0"
-"nakanojo.gunma.jp\0sor-aurdal.no\0"
-"cc.wv.us\0"
-"arita.saga.jp\0"
-"stange.no\0mo.us\0from-ks.com\0"
-"sciencecenter.museum\0"
-"ikano\0dyndns.org\0blogspot.co.id\0blogspot.tw\0blogspot.ug\0"
-"onjuku.chiba.jp\0nango.fukushima.jp\0"
-"chimkent.su\0"
-"\xe9\xa3\x9e\xe5\x88\xa9\xe6\xb5\xa6\0"
-"aya.miyazaki.jp\0cafe\0"
-"blogspot.co.il\0"
-"takaishi.osaka.jp\0historisch.museum\0il.us\0"
-"salvador.br\0vall\xc3\xa9""edaoste.it\0sukumo.kochi.jp\0rsc.cdn77.org\0"
-"blogspot.mr\0"
-"nl.no\0"
-"tatamotors\0"
-"jaworzno.pl\0\xe0\xae\x87\xe0\xae\xb2\xe0\xae\x99\xe0\xaf\x8d\xe0\xae\x95\xe0\xaf\x88\0"
-"blogspot.mx\0"
-"blogspot.my\0"
-"nalchik.ru\0pubtls.org\0"
-"audnedaln.no\0blogspot.nl\0"
-"sande.more-og-romsdal.no\0"
-"tydal.no\0square7.net\0blogspot.no\0"
-"lind\xc3\xa5s.no\0"
-"surf\0"
-"ichinoseki.iwate.jp\0kr\xc3\xa5""anghke.no\0"
-"nalchik.su\0"
-"kvinesdal.no\0lighting\0"
-"debian.net\0"
-"pol.dz\0booking\0"
-"turin.it\0"
-"nakadomari.aomori.jp\0localhistory.museum\0"
-"s3.eu-central-1.amazonaws.com\0"
-"blogspot.pe\0cust.testing.thingdust.io\0"
-"taka.hyogo.jp\0mosj\xc3\xb8""en.no\0nord-fron.no\0"
-"grane.no\0"
-"au.eu.org\0be.eu.org\0"
-"friuli-veneziagiulia.it\0"
-"ug.gov.pl\0"
-"sekigahara.gifu.jp\0kusu.oita.jp\0"
-"blogspot.qa\0git-pages.rit.edu\0"
-"gwangju.kr\0tran\xc3\xb8y.no\0"
-"*.sendai.jp\0"
-"blogspot.pt\0"
-"\xe4\xbc\x81\xe4\xb8\x9a\0drayddns.com\0"
-"\xe6\x9d\xb1\xe4\xba\xac.jp\0"
-"ikeda.hokkaido.jp\0"
-"sakahogi.gifu.jp\0"
-"atsuma.hokkaido.jp\0"
-"dev-myqnapcloud.com\0"
-"blogspot.is\0"
-"blogspot.it\0"
-"iwate.iwate.jp\0skierv\xc3\xa1.no\0"
-"miyagi.jp\0nid.io\0"
-"rindal.no\0"
-"shangrila\0"
-"*.stg.dev\0"
-"baseball.museum\0publ.pt\0"
-"ogori.fukuoka.jp\0kembuchi.hokkaido.jp\0fujishiro.ibaraki.jp\0hikari.yamaguchi.jp\0"
-"9guacu.br\0"
-"tokke.no\0"
-"nagato.yamaguchi.jp\0dscloud.biz\0"
-"kawaguchi.saitama.jp\0lugansk.ua\0blogspot.jp\0"
-"teva\0ms.leg.br\0"
-"czest.pl\0"
-"\xe3\x82\xbb\xe3\x83\xbc\xe3\x83\xab\0"
-"ota.gunma.jp\0h\xc3\xb8yanger.no\0"
-"aviation.museum\0"
-"beardu.no\0"
-"gs.svalbard.no\0"
-"pol.ht\0fhs.no\0in-dsl.org\0"
-"miyama.mie.jp\0"
-"s3-website-us-east-1.amazonaws.com\0"
-"blogspot.kr\0"
-"d.se\0"
-"oppegard.no\0"
-"muos\xc3\xa1t.no\0call\0"
-"bg.eu.org\0"
-"oseto.nagasaki.jp\0is-a-soxfan.org\0blogspot.li\0"
-"cloudns.info\0"
-"hamar.no\0sondre-land.no\0"
-"otofuke.hokkaido.jp\0"
-"cistron.nl\0"
-"museum.tt\0ap-southeast-2.elasticbeanstalk.com\0mt.leg.br\0"
-"\xe7\xbe\xa4\xe9\xa6\xac.jp\0kagamiishi.fukushima.jp\0blogspot.lt\0blogspot.md\0"
-"blogspot.lu\0"
-"za.org\0"
-"k12.ks.us\0camp\0"
-"valleaosta.it\0"
-"blogspot.mk\0"
-"izu.shizuoka.jp\0"
-"niiza.saitama.jp\0cechire.com\0"
-"ivgu.no\0pisz.pl\0"
-"ggf.br\0makinohara.shizuoka.jp\0"
-"yasu.shiga.jp\0"
-"tingvoll.no\0"
-"kishiwada.osaka.jp\0"
-"moka.tochigi.jp\0"
-"k12.tr\0"
-"blogspot.fi\0"
-"glass.museum\0"
-"page\0"
-"n\xc3\xa5\xc3\xa5mesjevuemie.no\0blogspot.fr\0"
-"kitaakita.akita.jp\0"
-"as.us\0"
-"newport.museum\0co.business\0"
-"hirakata.osaka.jp\0lib.ms.us\0lib.nc.us\0k12.vi\0broke-it.net\0"
-"\xce\xb5\xce\xbb\0newholland\0health-carereform.com\0"
-"latino\0blogspot.gr\0"
-"salzburg.museum\0netflix\0barsyonline.com\0"
-"from-or.com\0cloudycluster.net\0"
-"cc.ct.us\0"
-"\xce\xb5\xcf\x85\0"
-"zamami.okinawa.jp\0"
-"kyuragi.saga.jp\0archaeology.museum\0blogspot.hk\0"
-"convent.museum\0yahoo\0"
-"tv.bb\0"
-"blogspot.hr\0"
-"miyoshi.aichi.jp\0ashikaga.tochigi.jp\0flanders.museum\0"
-"fukui.fukui.jp\0blogspot.hu\0blogspot.ie\0"
-"omasvuotna.no\0catering\0"
-"kozow.com\0"
-"leitungsen.de\0"
-"tv.bo\0care\0blogspot.co.uk\0blogspot.in\0"
-"lib.az.us\0\xe7\xa7\xbb\xe5\x8a\xa8\0"
-"tv.br\0blogspot.ba\0"
-"ggee\0of.london\0"
-"cuneo.it\0blogspot.be\0"
-"lc.it\0blogspot.bg\0"
-"hr.eu.org\0"
-"tos.it\0casa\0mortgage\0blogspot.bj\0"
-"qc.ca\0x443.pw\0"
-"fermo.it\0cars\0"
-"taobao\0"
-"case\0"
-"riopreto.br\0"
-"cash\0homelinux.net\0blogspot.ca\0"
-"to.gov.br\0"
-"blogspot.cf\0"
-"kerrylogistics\0"
-"hirata.fukushima.jp\0blogspot.ch\0"
-"mobi\0lpages.co\0"
-"rehab\0"
-"beppu.oita.jp\0blogspot.cl\0"
-"mine.nu\0"
-"hatoyama.saitama.jp\0"
-"kommune.no\0\xe6\xb8\xb8\xe6\x88\x8f\0"
-"higashikagawa.kagawa.jp\0"
-"klodzko.pl\0"
-"v\xc3\xa1rgg\xc3\xa1t.no\0"
-"is-an-accountant.com\0blogspot.de\0ravendb.me\0"
-"exchange\0blogspot.cv\0"
-"ac.leg.br\0"
-"adobeaemcloud.net\0"
-"blogspot.cz\0"
-"mesaverde.museum\0trogstad.no\0blogspot.dk\0"
-"consulting.aero\0nishi.fukuoka.jp\0"
-"audible\0shoes\0"
-"cci.fr\0"
-"s3-eu-west-1.amazonaws.com\0"
-"moda\0"
-"abarth\0"
-"brandywinevalley.museum\0"
-"usa.museum\0"
-"ako.hyogo.jp\0isahaya.nagasaki.jp\0ny.us\0"
-"frei.no\0"
-"landrover\0"
-"co.education\0"
-"staples\0"
-"museum.mv\0"
-"tsukuba.ibaraki.jp\0museum.mw\0blogdns.com\0"
-"mie.jp\0"
-"kurogi.fukuoka.jp\0"
-"moseushi.hokkaido.jp\0"
-"andasuolo.no\0eid.no\0"
-"dolls.museum\0"
-"museum.no\0"
-"mantova.it\0railroad.museum\0servebeer.com\0"
-"s3.dualstack.ap-southeast-2.amazonaws.com\0"
-"lib.sc.us\0"
-"podzone.net\0apps.lair.io\0"
-"hermes\0"
-"blogspot.co.ke\0"
-"textile.museum\0pol.tr\0"
-"author.aero\0museum.om\0"
-"discover\0"
-"aprendemas.cl\0cc.id.us\0villas\0\xe6\x97\xb6\xe5\xb0\x9a\0"
-"guide\0"
-"house\0"
-"gs.jan-mayen.no\0build\0"
-"gol.no\0"
-"nanmoku.gunma.jp\0trondheim.no\0"
-"tv.im\0"
-"mykolaiv.ua\0"
-"tarama.okinawa.jp\0"
-"is-an-artist.com\0"
-"tv.it\0\xd8\xb3\xd9\x88\xd8\xaf\xd8\xa7\xd9\x86\0"
-"royrvik.no\0"
-"toyone.aichi.jp\0blogspot.ae\0"
-"calvinklein\0"
-"baidar.no\0olsztyn.pl\0"
-"florida.museum\0blogspot.al\0"
-"blogspot.am\0"
-"castres.museum\0synology-diskstation.de\0"
-"duck\0"
-"ena.gifu.jp\0store.nf\0onion\0"
-"holtalen.no\0"
-"\xe5\x8c\x97\xe6\xb5\xb7\xe9\x81\x93.jp\0"
-"yamanashi.yamanashi.jp\0"
-"research.museum\0"
-"video.hu\0"
-"karpacz.pl\0pars\0"
-"valle-d-aosta.it\0stuff-4-sale.us\0"
-"kamagaya.chiba.jp\0"
-"kl\xc3\xa6""bu.no\0"
-"sosnowiec.pl\0"
-"globo\0blogspot.co.nz\0"
-"time.museum\0"
-"cz.it\0\xc3\xb8rskog.no\0"
-"conference.aero\0isteingeek.de\0"
-"aquila.it\0"
-"gildeskal.no\0"
-"handa.aichi.jp\0"
-"santafe.museum\0associates\0"
-"observer\0ptplus.fit\0"
-"tv.na\0"
-"rotorcraft.aero\0"
-"lans.museum\0ks.ua\0"
-"boats\0hu.net\0"
-"finn\xc3\xb8y.no\0"
-"nagareyama.chiba.jp\0"
-"airport.aero\0mel\xc3\xb8y.no\0"
-"abogado\0"
-"yawara.ibaraki.jp\0security\0"
-"chungbuk.kr\0"
-"k12.nm.us\0"
-"kijo.miyazaki.jp\0"
-"byen.site\0"
-"volkenkunde.museum\0"
-"\xd0\xb0\xd0\xba.\xd1\x81\xd1\x80\xd0\xb1\0"
-"boehringer\0"
-"warabi.saitama.jp\0ks.us\0"
-"servesarcasm.com\0"
-"infiniti\0"
-"\xe6\x95\x99\xe8\x82\xb2.hk\0amami.kagoshima.jp\0"
-"sarufutsu.hokkaido.jp\0"
-"visa\0"
-"from-wy.com\0"
-"tsuiki.fukuoka.jp\0"
-"forsale\0"
-"cc.mt.us\0cc.nd.us\0"
-"*.elb.amazonaws.com.cn\0"
-"eu-west-3.elasticbeanstalk.com\0"
-"read\0"
-"foz.br\0rennes\xc3\xb8y.no\0"
-"hm.no\0us.org\0logoip.com\0"
-"matta-varjjat.no\0bydgoszcz.pl\0"
-"aland.fi\0hasura-app.io\0"
-"ciencia.bo\0francaise.museum\0ipiranga\0my-router.de\0"
-"\xe0\xb8\x97\xe0\xb8\xab\xe0\xb8\xb2\xe0\xb8\xa3.\xe0\xb9\x84\xe0\xb8\x97\xe0\xb8\xa2\0dyn-ip24.de\0"
-"hitachi\0"
-"valle.no\0aaa.pro\0"
-"miyazaki.miyazaki.jp\0sanfrancisco.museum\0"
-"vc.it\0emerck\0"
-"aioi.hyogo.jp\0cc.ak.us\0"
-"tas.gov.au\0"
-"omaezaki.shizuoka.jp\0de.cool\0"
-"ainan.ehime.jp\0hatogaya.saitama.jp\0sortland.no\0"
-"takayama.gunma.jp\0"
-"saotome.st\0viva\0"
-"cbre\0"
-"niepce.museum\0store.ve\0"
-"tv.sd\0"
-"murakami.niigata.jp\0"
-"isa.kagoshima.jp\0"
-"miyoshi.hiroshima.jp\0vivo\0"
-"air-traffic-control.aero\0from-oh.com\0"
-"capitalone\0"
-"roan.no\0jobs.tt\0eu.meteorapp.com\0"
-"qsl.br\0higashichichibu.saitama.jp\0"
-"nakamura.kochi.jp\0"
-"nativeamerican.museum\0"
-"uwajima.ehime.jp\0"
-"scienceandindustry.museum\0"
-"teshikaga.hokkaido.jp\0minamiizu.shizuoka.jp\0"
-"is-an-actor.com\0"
-"tv.tr\0"
-"*.kunden.ortsinfo.at\0barsy.info\0"
-"nakanoto.ishikawa.jp\0"
-"\xe4\xb8\xaa\xe4\xba\xba.hk\0"
-"tv.tz\0"
-"b.bg\0\xe5\xae\xae\xe5\xb4\x8e.jp\0s3.dualstack.eu-west-1.amazonaws.com\0"
-"modern.museum\0"
-"bjarkoy.no\0"
-"juedisches.museum\0"
-"us.na\0"
-"gliding.aero\0usculture.museum\0"
-"b.br\0"
-"shitara.aichi.jp\0etajima.hiroshima.jp\0"
-"ad.jp\0"
-"taa.it\0hachinohe.aomori.jp\0shiojiri.nagano.jp\0newjersey.museum\0"
-"nationalheritage.museum\0n4t.co\0"
-"movie\0"
-"moto\0"
-"shinanomachi.nagano.jp\0"
-"lancia\0loans\0"
-"blogspot.co.za\0"
-"al.leg.br\0"
-"iwakura.aichi.jp\0il.eu.org\0"
-"store.ro\0"
-"feedback\0"
-"cc.sd.us\0"
-"r\xc3\xb8""d\xc3\xb8y.no\0"
-"choshi.chiba.jp\0"
-"cri.br\0kunigami.okinawa.jp\0"
-"kalisz.pl\0"
-"shimotsuke.tochigi.jp\0"
-"zone\0"
-"in-dsl.net\0"
-"tonsberg.no\0"
-"matsumae.hokkaido.jp\0minamiashigara.kanagawa.jp\0dvag\0"
-"kawara.fukuoka.jp\0servep2p.com\0"
-"store.st\0hockey\0macys\0"
-"hasvik.no\0groks-the.info\0"
-"beeldengeluid.museum\0"
-"hu.eu.org\0ie.eu.org\0"
-"echizen.fukui.jp\0archi\0"
-"reit\0"
-"lancaster\0"
-"barsy.mobi\0"
-"homebuilt.aero\0"
-"abiko.chiba.jp\0nakaniikawa.toyama.jp\0"
-"kosai.shizuoka.jp\0"
-"tobishima.aichi.jp\0sande.m\xc3\xb8re-og-romsdal.no\0"
-"software\0"
-"wiih.gov.pl\0"
-"karelia.su\0"
-"google\0"
-"rm.it\0"
-"amakusa.kumamoto.jp\0lib.de.us\0"
-"df.gov.br\0"
-"mulhouse.museum\0mazury.pl\0from-mn.com\0"
-"og.ao\0urawa.saitama.jp\0hk.org\0"
-"moriya.ibaraki.jp\0merckmsd\0"
-"fr\xc3\xb8ya.no\0"
-"matsumoto.kagoshima.jp\0"
-"niigata.niigata.jp\0"
-"usgarden.museum\0"
-"shizukuishi.iwate.jp\0yonaguni.okinawa.jp\0tottori.tottori.jp\0"
-"trentino-s\xc3\xbc""dtirol.it\0"
-"kyotamba.kyoto.jp\0"
-"\xc3\xb8rsta.no\0"
-"trentin-sud-tirol.it\0edu.eu.org\0"
-"murata.miyagi.jp\0"
-"olecko.pl\0"
-"pccw\0"
-"game-server.cc\0"
-"wazuka.kyoto.jp\0gs.bu.no\0"
-"o.bg\0"
-"\xe3\x81\xbf\xe3\x82\x93\xe3\x81\xaa\0"
-"aq.it\0ba.it\0weibo\0fuettertdasnetz.de\0"
-"rana.no\0"
-"certification.aero\0yura.wakayama.jp\0"
-"bo.nordland.no\0"
-"ski.museum\0glug.org.uk\0"
-"rent\0"
-"bostik\0"
-"journalism.museum\0"
-"vpnplus.to\0"
-"osoyro.no\0mielno.pl\0bargains\0"
-"design.aero\0"
-"akagi.shimane.jp\0"
-"selfip.info\0"
-"americanart.museum\0"
-"opencraft.hosting\0"
-"hasura.app\0"
-"suifu.ibaraki.jp\0kvam.no\0us-gov-west-1.elasticbeanstalk.com\0"
-"jfk.museum\0"
-"moareke.no\0"
-"praxi\0"
-"egyptian.museum\0"
-"cymru.museum\0"
-"radio\0"
-"midatlantic.museum\0"
-"shijonawate.osaka.jp\0homelinux.org\0"
-"\xe5\xa5\x88\xe8\x89\xaf.jp\0cleverapps.io\0"
-"santabarbara.museum\0"
-"dielddanuorri.no\0"
-"portland.museum\0"
-"endoftheinternet.org\0"
-"vic.au\0"
-"bokn.no\0"
-"myftp.biz\0"
-"database.museum\0"
-"minamiise.mie.jp\0"
-"asti.it\0"
-"cupcake.is\0"
-"jab.br\0saroma.hokkaido.jp\0"
-"farmstead.museum\0rost.no\0"
-"yamagata.ibaraki.jp\0"
-"cam.it\0"
-"mydobiss.com\0"
-"shimamaki.hokkaido.jp\0kobierzyce.pl\0"
-"mozilla-iot.org\0"
-"kiev.ua\0"
-"lavangen.no\0"
-"youtube\0"
-"fin.ci\0"
-"studio\0nodebalancer.linode.com\0alpha-myqnapcloud.com\0"
-"tokigawa.saitama.jp\0"
-"laz.it\0termez.su\0"
-"matsue.shimane.jp\0"
-"c.cdn77.org\0"
-"lolipop.io\0"
-"kosuge.yamanashi.jp\0essex.museum\0"
-"gr.eu.org\0"
-"rest\0"
-"nannestad.no\0"
-"leangaviika.no\0tysnes.no\0shopitsite.com\0"
-"og.it\0"
-"taranto.it\0\xc3\xa5krehamn.no\0"
-"furubira.hokkaido.jp\0nagoya\0"
-"sugito.saitama.jp\0lib.ak.us\0\xe3\x83\x95\xe3\x82\xa1\xe3\x83\x83\xe3\x82\xb7\xe3\x83\xa7\xe3\x83\xb3\0"
-"priv.hu\0"
-"xj.cn\0katowice.pl\0"
-"fin.ec\0anpachi.gifu.jp\0a.prod.fastly.net\0"
-"shirakawa.fukushima.jp\0s3.amazonaws.com\0"
-"kamifurano.hokkaido.jp\0kitagawa.kochi.jp\0"
-"fortmissoula.museum\0podzone.org\0"
-"mysecuritycamera.com\0"
-"blog.bo\0cri.nz\0"
-"boston\0"
-"blog.br\0kasahara.gifu.jp\0tsuru.yamanashi.jp\0"
-"scapp.io\0"
-"bounceme.net\0"
-"cosenza.it\0avianca\0"
-"gift\0"
-"riobranco.br\0"
-"jambyl.su\0"
-"computer\0"
-"\xd8\xa7\xdb\x8c\xd8\xb1\xd8\xa7\xd9\x86.ir\0"
-"on-web.fr\0"
-"\xe0\xb6\xbd\xe0\xb6\x82\xe0\xb6\x9a\xe0\xb7\x8f\0"
-"bn.it\0scholarships\0"
-"hyatt\0"
-"voting\0"
-"filegear-au.me\0"
-"\xd8\xb9\xd8\xb1\xd8\xa7\xd9\x82\0"
-"b.se\0"
-"9.bg\0economia.bo\0\xd8\xa7\xd9\x84\xd8\xb3\xd8\xb9\xd9\x88\xd8\xaf\xd9\x8a\xd9\x87\0"
-"davvenj\xc3\xa1rga.no\0"
-"store.bb\0"
-"bolzano.it\0fedex\0reise\0"
-"chosei.chiba.jp\0"
-"cesena-forli.it\0"
-"tiaa\0"
-"instantcloud.cn\0"
-"minamisanriku.miyagi.jp\0coffee\0"
-"fvg.it\0traeumtgerade.de\0"
-"firm.ht\0"
-"education.tas.edu.au\0"
-"trentinostirol.it\0"
-"grp.lk\0nj.us\0"
-"inder\xc3\xb8y.no\0community-pro.de\0"
-"topology.museum\0k12.ky.us\0"
-"cable-modem.org\0"
-"ppg.br\0cc.tn.us\0"
-"firm.in\0"
-"iveland.no\0"
-"\xe0\xae\x87\xe0\xae\xa8\xe0\xaf\x8d\xe0\xae\xa4\xe0\xae\xbf\xe0\xae\xaf\xe0\xae\xbe\0"
-"heritage.museum\0"
-"draydns.de\0"
-"kashihara.nara.jp\0"
-"\xd8\xa7\xd9\x84\xd8\xb3\xd8\xb9\xd9\x88\xd8\xaf\xd9\x8a\xd8\xa9\0"
-"guovdageaidnu.no\0v\xc3\xa5ler.hedmark.no\0"
-"muenchen.museum\0gr.com\0"
-"historicalsociety.museum\0"
-"priv.at\0"
-"takahata.yamagata.jp\0"
-"habikino.osaka.jp\0monmouth.museum\0store.dk\0"
-"takanabe.miyazaki.jp\0"
-"gifu.jp\0"
-"penza.su\0"
-"cooking\0"
-"cc.gu.us\0"
-"rj.gov.br\0firm.co\0"
-"lib.ne.us\0"
-"masfjorden.no\0"
-"naganohara.gunma.jp\0"
-"motegi.tochigi.jp\0"
-"kvinnherad.no\0"
-"\xd5\xb0\xd5\xa1\xd5\xb5\0"
-"firm.dk\0"
-"ogawara.miyagi.jp\0"
-"golffan.us\0"
-"dynalias.com\0"
-"toyama.toyama.jp\0cody.museum\0"
-"chrome\0"
-"suwa.nagano.jp\0"
-"ikawa.akita.jp\0yamanouchi.nagano.jp\0"
-"fbxos.fr\0"
-"ot.it\0pd.it\0"
-"bulsan-suedtirol.it\0davvesiida.no\0v\xc3\xa6r\xc3\xb8y.no\0"
-"nakagawa.hokkaido.jp\0aremark.no\0sdn.gov.pl\0"
-"oita.oita.jp\0"
-"enna.it\0"
-"vipsinaapp.com\0"
-"aarp\0"
-"biev\xc3\xa1t.no\0"
-"*.sensiosite.cloud\0"
-"milan.it\0"
-"aomori.aomori.jp\0"
-"ono.fukui.jp\0"
-"yachimata.chiba.jp\0"
-"alabama.museum\0"
-"youth.museum\0clubmed\0"
-"ina.saitama.jp\0monash\0"
-"misugi.mie.jp\0"
-"toolforge.org\0"
-"przeworsk.pl\0"
-"ln.cn\0"
-"flt.cloud.muni.cz\0"
-"o.se\0k12.tn.us\0"
-"ujitawara.kyoto.jp\0automotive.museum\0"
-"and.museum\0"
-"homedepot\0"
-"asago.hyogo.jp\0"
-"kazo.saitama.jp\0"
-"hk.cn\0"
-"kanoya.kagoshima.jp\0yamakita.kanagawa.jp\0nagi.okayama.jp\0name\0"
-"trentino-sudtirol.it\0"
-"herad.no\0"
-"suwalki.pl\0"
-"\xe0\xa6\xad\xe0\xa6\xbe\xe0\xa6\xb0\xe0\xa6\xa4\0"
-"ddnsgeek.com\0"
-"kikuchi.kumamoto.jp\0"
-"nishitosa.kochi.jp\0"
-"hiji.oita.jp\0"
-"pictures\0"
-"jorpeland.no\0is-a-therapist.com\0"
-"gangaviika.no\0"
-"annefrank.museum\0medical.museum\0"
-"pinb.gov.pl\0"
-"furudono.fukushima.jp\0"
-"\xd0\xbf\xd1\x80.\xd1\x81\xd1\x80\xd0\xb1\0"
-"aeroclub.aero\0"
-"agric.za\0"
-"bod\xc3\xb8.no\0"
-"idv.hk\0asmatart.museum\0leka.no\0ga.us\0"
-"koryo.nara.jp\0"
-"cc.me.us\0"
-"dazaifu.fukuoka.jp\0"
-"yamanakako.yamanashi.jp\0graz.museum\0"
-"webhosting.be\0"
-"yasuda.kochi.jp\0myfritz.net\0"
-"edogawa.tokyo.jp\0"
-"noda.chiba.jp\0gildesk\xc3\xa5l.no\0lib.nv.us\0"
-"inatsuki.fukuoka.jp\0"
-"stokke.no\0"
-"game-host.org\0"
-"games.hu\0newhampshire.museum\0"
-"nagatoro.saitama.jp\0"
-"odda.no\0"
-"pueblo.bo\0"
-"tt.im\0molise.it\0missile.museum\0"
-"motobu.okinawa.jp\0khmelnitskiy.ua\0"
-"nakai.kanagawa.jp\0"
-"res.in\0lexus\0"
-"ud.it\0"
-"lomza.pl\0osaka\0sellsyourhome.org\0"
-"emr.it\0gmail\0"
-"funabashi.chiba.jp\0"
-"inawashiro.fukushima.jp\0coloradoplateau.museum\0\xe6\x95\x99\xe8\x82\xb2.\xe9\xa6\x99\xe6\xb8\xaf\0gov.scot\0"
-"gsm.pl\0co.com\0"
-"wake.okayama.jp\0fin.tn\0"
-"hdfcbank\0"
-"s3-website-us-west-2.amazonaws.com\0"
-"gs.mr.no\0"
-"firm.ve\0"
-"uy.com\0"
-"doesntexist.org\0"
-"mill.museum\0"
-"musica.ar\0space-to-rent.com\0"
-"zuerich\0"
-"sci.eg\0kakegawa.shizuoka.jp\0rentals\0from-sd.com\0prvcy.page\0"
-"floripa.br\0vardo.no\0"
-"yoshikawa.saitama.jp\0serveftp.net\0"
-"musica.bo\0skj\xc3\xa5k.no\0"
-"github.io\0"
-"supplies\0"
-"sa.edu.au\0"
-"adult\0s3.us-east-2.amazonaws.com\0"
-"resistance.museum\0able\0"
-"aoste.it\0fresenius\0"
-"m\xc3\xa5s\xc3\xb8y.no\0brasilia.me\0"
-"\xe0\xb2\xad\xe0\xb2\xbe\xe0\xb2\xb0\xe0\xb2\xa4\0from-la.net\0"
-"pug.it\0"
-"davvenjarga.no\0"
-"barreau.bj\0v-info.info\0"
-"iglesias-carbonia.it\0k12.vi.us\0"
-"judygarland.museum\0"
-"\xe9\x9b\xbb\xe8\xa8\x8a\xe7\x9b\x88\xe7\xa7\x91\0"
-"\xd1\x81\xd0\xb0\xd0\xb9\xd1\x82\0likescandy.com\0"
-"aogaki.hyogo.jp\0daito.osaka.jp\0nextdirect\0tips\0"
-"sa.gov.au\0la-spezia.it\0"
-"jor.br\0"
-"ab.ca\0"
-"luxembourg.museum\0"
-"kawai.iwate.jp\0klabu.no\0"
-"forex\0dyndns-at-work.com\0"
-"b\xc3\xa1l\xc3\xa1t.no\0"
-"la.us\0"
-"imdb\0"
-"columbus.museum\0myforum.community\0"
-"name.hr\0family\0"
-"ck.ua\0"
-"barsy.net\0"
-"tsuno.kochi.jp\0firm.ro\0"
-"abira.hokkaido.jp\0murayama.yamagata.jp\0"
-"tsumagoi.gunma.jp\0zakopane.pl\0"
-"fastly-terrarium.com\0"
-"higashi.fukushima.jp\0rad\xc3\xb8y.no\0"
-"campidano-medio.it\0czeladz.pl\0immobilien\0navy\0is-a-geek.com\0"
-"civilisation.museum\0\xeb\x8b\xb7\xeb\x84\xb7\0"
-"is-a-bookkeeper.com\0"
-"is-an-anarchist.com\0"
-"name.et\0valledaosta.it\0"
-"rr.gov.br\0"
-"chernivtsi.ua\0"
-"camdvr.org\0"
-"name.fj\0oiso.kanagawa.jp\0"
-"nagaoka.niigata.jp\0l\xc3\xb8""dingen.no\0"
-"takashima.shiga.jp\0"
-"ltd.co.im\0kawazu.shizuoka.jp\0"
-"snaase.no\0"
-"marugame.kagawa.jp\0ringsaker.no\0"
-"tcp4.me\0"
-"dellogliastra.it\0kawanishi.yamagata.jp\0"
-"yugawa.fukushima.jp\0"
-"satsumasendai.kagoshima.jp\0"
-"!city.kobe.jp\0sakae.nagano.jp\0"
-"rightathome\0\xd8\xa7\xd8\xa8\xd9\x88\xd8\xb8\xd8\xa8\xd9\x8a\0"
-"reggiocalabria.it\0"
-"andria-trani-barletta.it\0"
-"va.it\0priv.pl\0"
-"iglesiascarbonia.it\0"
-"lib.ga.us\0\xd8\xa7\xd9\x84\xd9\x85\xd8\xba\xd8\xb1\xd8\xa8\0"
-"cremona.it\0synology.me\0"
-"siracusa.it\0pup.gov.pl\0"
-"rs.gov.br\0sc.gov.br\0"
-"obanazawa.yamagata.jp\0kvitsoy.no\0us.eu.org\0"
-"software.aero\0cadaques.museum\0"
-"name.cy\0"
-"from-sc.com\0"
-"anthro.museum\0firm.nf\0"
-"firm.ng\0"
-"yoshino.nara.jp\0"
-"obira.hokkaido.jp\0"
-"is-a-designer.com\0"
-"fairwinds\0dvrdns.org\0"
-"name.eg\0*.stolos.io\0"
-"higashiyodogawa.osaka.jp\0melbourne\0quebec\0"
-"freedesktop.org\0"
-"state.museum\0\xe3\x82\xa2\xe3\x83\x9e\xe3\x82\xbe\xe3\x83\xb3\0"
-"saobernardo.br\0kamitsue.oita.jp\0"
-"humanities.museum\0surgeonshall.museum\0"
-"sochi.su\0"
-"osaka.jp\0priv.no\0"
-"aver\xc3\xb8y.no\0filegear.me\0"
-"yoshioka.gunma.jp\0idv.tw\0bugatti\0oldnavy\0"
-"misato.wakayama.jp\0"
-"chihayaakasaka.osaka.jp\0locus\0"
-"oguni.yamagata.jp\0"
-"name.az\0miyakonojo.miyazaki.jp\0"
-"hida.gifu.jp\0cloudera.site\0"
-"jdevcloud.com\0"
-"\xe5\x81\xa5\xe5\xba\xb7\0"
-"tabuse.yamaguchi.jp\0"
-"chernihiv.ua\0"
-"shinto.gunma.jp\0minamidaito.okinawa.jp\0"
-"nord-aurdal.no\0"
-"hagi.yamaguchi.jp\0tromsa.no\0"
-"shiki.saitama.jp\0"
-"broadway\0"
-"habmer.no\0"
-"kamimine.saga.jp\0bestbuy\0dynvpn.de\0"
-"stat.no\0"
-"kushiro.hokkaido.jp\0grong.no\0"
-"pmn.it\0"
-"uchiko.ehime.jp\0shoo.okayama.jp\0priv.me\0"
-"teo.br\0"
-"vald-aosta.it\0va.no\0s3-website.ap-northeast-2.amazonaws.com\0"
-"palace.museum\0"
-"kirovograd.ua\0"
-"solund.no\0"
-"valleedaoste.it\0"
-"spb.ru\0"
-"celtic.museum\0"
-"puglia.it\0"
-"ba.gov.br\0"
-"ferrari\0"
-"bialystok.pl\0"
-"spb.su\0"
-"hepforge.org\0"
-"jdf.br\0karmoy.no\0"
-"f\xc3\xb8rde.no\0"
-"rn.gov.br\0loseyourip.com\0"
-"urbinopesaro.it\0"
-"fyresdal.no\0narviika.no\0"
-"family.museum\0"
-"samsung\0"
-"kyonan.chiba.jp\0higashiagatsuma.gunma.jp\0dynserv.org\0"
-"immo\0"
-"himi.toyama.jp\0fineart.museum\0"
-"\xd8\xa7\xd8\xaa\xd8\xb5\xd8\xa7\xd9\x84\xd8\xa7\xd8\xaa\0"
-"london.cloudapps.digital\0"
-"demon.nl\0"
-"aizumisato.fukushima.jp\0virtuel.museum\0"
-"horten.no\0kuokgroup\0"
-"lib.la.us\0"
-"from-id.com\0"
-"showa.fukushima.jp\0"
-"prof.pr\0cern\0free.hr\0"
-"miyazu.kyoto.jp\0fr.eu.org\0"
-"tkmaxx\0"
-"yamagata.nagano.jp\0vestv\xc3\xa5g\xc3\xb8y.no\0"
-"carboniaiglesias.it\0school.museum\0"
-"monster\0"
-"muika.niigata.jp\0"
-"flynnhosting.net\0"
-"ro.gov.br\0chichibu.saitama.jp\0"
-"is-a-geek.org\0"
-"from-ma.com\0"
-"\xe3\x82\xb3\xe3\x83\xa0\0dyndns.info\0"
-"kochi.jp\0pilots.museum\0"
-"homeoffice.gov.uk\0"
-"gs.ol.no\0"
-"stcgroup\0"
-"nishimera.miyazaki.jp\0"
-"tokai.aichi.jp\0schokoladen.museum\0"
-"civilwar.museum\0jur.pro\0"
-"onna.okinawa.jp\0nokia\0"
-"ozu.ehime.jp\0"
-"frankfurt.museum\0"
-"county.museum\0"
-"barsy.pro\0"
-"ogasawara.tokyo.jp\0"
-"nu.ca\0is-a-bruinsfan.org\0neat-url.com\0"
-"hirokawa.fukuoka.jp\0sp.leg.br\0"
-"sh.cn\0"
-"groundhandling.aero\0kasamatsu.gifu.jp\0"
-"prato.it\0saigawa.fukuoka.jp\0"
-"tosashimizu.kochi.jp\0"
-"motorcycle.museum\0"
-"washtenaw.mi.us\0"
-"m.bg\0ownprovider.com\0"
-"ao.it\0statebank\0"
-"dell-ogliastra.it\0tjome.no\0"
-"nordreisa.no\0"
-"*.bd\0muni.il\0va.us\0forum\0"
-"okuizumo.shimane.jp\0mk.ua\0"
-"riodejaneiro.museum\0"
-"barsy.pub\0"
-"hamada.shimane.jp\0"
-"ng.school\0"
-"geekgalaxy.com\0"
-"kpmg\0"
-"mx.na\0"
-"exchange.aero\0*.ck\0"
-"shobara.hiroshima.jp\0kitamoto.saitama.jp\0"
-"otoyo.kochi.jp\0hachijo.tokyo.jp\0"
-"am.gov.br\0"
-"circle\0"
-"travelersinsurance\0"
-"neyagawa.osaka.jp\0myjino.ru\0"
-"tomiya.miyagi.jp\0"
-"matera.it\0"
-"kanazawa.ishikawa.jp\0"
-"entertainment.aero\0sjc.br\0"
-"accesscam.org\0"
-"name.vn\0"
-"vda.it\0"
-"vm.bytemark.co.uk\0"
-"photography.museum\0"
-"brumunddal.no\0adac\0"
-"\xd8\xb3\xd9\x88\xd8\xb1\xd9\x8a\xd8\xa7\0"
-"aibetsu.hokkaido.jp\0\xd8\xb3\xd9\x88\xd8\xb1\xd9\x8a\xd8\xa9\0"
-"*.er\0"
-"info\0smola.no\0songdalen.no\0"
-"off.ai\0"
-"*.fk\0"
-"buzz\0"
-"name.tj\0voyage\0"
-"daiwa.hiroshima.jp\0yokoze.saitama.jp\0"
-"fhsk.se\0"
-"a.ssl.fastly.net\0"
-"fukumitsu.toyama.jp\0"
-"anan.nagano.jp\0"
-"name.tr\0is-a-student.com\0"
-"name.tt\0"
-"pb.ao\0misaki.osaka.jp\0"
-"paragliding.aero\0nu.it\0"
-"or.at\0"
-"h\xc3\xa6gebostad.no\0readthedocs.io\0"
-"modelling.aero\0busan.kr\0"
-"or.bi\0obama.nagasaki.jp\0"
-"aquarelle\0"
-"government.aero\0cruises\0"
-"oyama.tochigi.jp\0"
-"takamori.nagano.jp\0"
-"cisco\0beep.pl\0builtwithdark.com\0"
-"vn.ua\0urown.cloud\0"
-"or.ci\0"
-"lorenskog.no\0"
-"yao.osaka.jp\0"
-"posts-and-telecommunications.museum\0\xc3\xa5s.no\0development.run\0"
-"br\xc3\xb8nn\xc3\xb8ysund.no\0"
-"is-a-anarchist.com\0"
-"z.bg\0"
-"or.cr\0soundcast.me\0"
-"bl.it\0"
-"ap.gov.br\0"
-"ruovat.no\0"
-"uto.kumamoto.jp\0"
-"7.bg\0tenri.nara.jp\0"
-"contagem.br\0"
-"se.gov.br\0*.jm\0os.hordaland.no\0foundation\0"
-"usercontent.jp\0logoip.de\0"
-"horokanai.hokkaido.jp\0kuji.iwate.jp\0"
-"dyn-o-saur.com\0"
-"adult.ht\0"
-"tanohata.iwate.jp\0"
-"*.kh\0name.qa\0"
-"name.pr\0broker\0"
-"otobe.hokkaido.jp\0"
-"ap.gov.pl\0sec.ps\0nh.us\0"
-"srv.br\0"
-"health\0"
-"ohira.miyagi.jp\0"
-"comunica\xc3\xa7\xc3\xb5""es.museum\0"
-"laakesvuemie.no\0"
-"tksat.bo\0takasu.hokkaido.jp\0"
-"air-surveillance.aero\0"
-"name.na\0"
-"meldal.no\0living\0"
-"vodka\0"
-"karate.museum\0"
-"frana.no\0"
-"interactive.museum\0name.mv\0lib.va.us\0"
-"watarai.mie.jp\0name.ng\0"
-"name.my\0"
-"airline.aero\0"
-"newmexico.museum\0"
-"k12.ca.us\0"
-"academia.bo\0pescara.it\0"
-"chigasaki.kanagawa.jp\0pasadena.museum\0from-tx.com\0"
-"biratori.hokkaido.jp\0storfjord.no\0rich\0"
-"!city.sapporo.jp\0"
-"farmers\0"
-"*.mm\0"
-"komforb.se\0"
-"harvestcelebration.museum\0"
-"malselv.no\0"
-"kota.aichi.jp\0ybo.review\0"
-"fribourg.museum\0"
-"gratis\0herokussl.com\0"
-"inagi.tokyo.jp\0"
-"center\0"
-"mytis.ru\0"
-"hattfjelldal.no\0"
-"shintoku.hokkaido.jp\0"
-"varoy.no\0"
-"its.me\0*.np\0"
-"or.id\0"
-"edgestack.me\0"
-"silk.museum\0"
-"firebaseapp.com\0"
-"te.it\0"
-"friuliv-giulia.it\0hikone.shiga.jp\0"
-"royken.no\0"
-"stada\0"
-"barsy.org\0"
-"cloudaccess.host\0"
-"or.it\0\xe8\xb0\xb7\xe6\xad\x8c\0"
-"katano.osaka.jp\0name.mk\0osen.no\0"
-"pharmacien.fr\0wakuya.miyagi.jp\0"
-"joboji.iwate.jp\0sango.nara.jp\0s3.dualstack.eu-west-2.amazonaws.com\0"
-"*.pg\0sa.gov.pl\0"
-"emp.br\0"
-"solar\0ru.com\0"
-"eniwa.hokkaido.jp\0askoy.no\0"
-"or.jp\0"
-"umig.gov.pl\0"
-"author\0"
-"asahi.yamagata.jp\0or.ke\0"
-"shinonsen.hyogo.jp\0"
-"name.jo\0is-a-celticsfan.org\0"
-"kanzaki.saga.jp\0yatsuka.shimane.jp\0"
-"moss.no\0"
-"is-a-bulls-fan.com\0"
-"mitake.gifu.jp\0hannan.osaka.jp\0"
-"taku.saga.jp\0js.org\0"
-"vegarshei.no\0"
-"or.kr\0\xe5\xb9\xbf\xe4\xb8\x9c\0"
-"s\xc3\xbc""dtirol.it\0"
-"ci.it\0qcx.io\0"
-"\xe5\x9f\xbc\xe7\x8e\x89.jp\0"
-"trani-andria-barletta.it\0"
-"\xc3\xa5snes.no\0"
-"m.se\0memorial\0"
-"onomichi.hiroshima.jp\0"
-"flekkefjord.no\0"
-"\xe7\xb6\xb2\xe8\xb7\xaf.tw\0mycd.eu\0"
-"nichinan.tottori.jp\0"
-"repbody.aero\0"
-"hi.cn\0"
-"kunitachi.tokyo.jp\0definima.net\0"
-"kyotango.kyoto.jp\0arteducation.museum\0*.awdev.ca\0"
-"l\xc3\xa6rdal.no\0"
-"*.cryptonomic.net\0"
-"nayoro.hokkaido.jp\0withgoogle.com\0"
-"futtsu.chiba.jp\0gov.nc.tr\0"
-"friulivenezia-giulia.it\0nagai.yamagata.jp\0or.na\0"
-"mifune.kumamoto.jp\0smile\0"
-"or.mu\0"
-"\xe6\xbb\x8b\xe8\xb3\x80.jp\0land\0"
-"serveftp.org\0"
-"kartuzy.pl\0"
-"otago.museum\0"
-"search\0"
-"myoko.niigata.jp\0"
-"kamijima.ehime.jp\0"
-"batsfjord.no\0lavagis.no\0"
-"taishi.hyogo.jp\0ube.yamaguchi.jp\0"
-"namie.fukushima.jp\0"
-"tosa.kochi.jp\0"
-"city.hu\0"
-"ochi.kochi.jp\0"
-"barsy.club\0"
-"oharu.aichi.jp\0"
-"soc.lk\0sorreisa.no\0kaszuby.pl\0"
-"press\0"
-"indian.museum\0lib.oh.us\0"
-"trentinoalto-adige.it\0leirvik.no\0"
-"soo.kagoshima.jp\0sevastopol.ua\0net-freaks.com\0"
-"panama.museum\0"
-"monzabrianza.it\0"
-"pesaro-urbino.it\0elburg.museum\0settlement.museum\0accountant\0"
-"mc.eu.org\0"
-"cargo.aero\0cahcesuolo.no\0furniture\0"
-"gs.vf.no\0"
-"kyowa.akita.jp\0bergen.no\0"
-"higashiomi.shiga.jp\0"
-"or.pw\0"
-"freeboxos.fr\0"
-"s3-eu-west-3.amazonaws.com\0"
-"egersund.no\0tysv\xc3\xa6r.no\0"
-"tr.it\0toga.toyama.jp\0atlanta.museum\0"
-"kiyama.saga.jp\0iveco\0"
-"hikimi.shimane.jp\0"
-"hyundai\0systems\0"
-"\xe5\x9c\xa8\xe7\xba\xbf\0"
-"ntdll.top\0"
-"tomika.gifu.jp\0"
-"po.it\0"
-"cya.gg\0"
-"yanagawa.fukuoka.jp\0lib.as.us\0\xd8\xa7\xd9\x8a\xd8\xb1\xd8\xa7\xd9\x86\0"
-"kids.museum\0"
-"aaa\0bir.ru\0"
-"bnr.la\0lt.eu.org\0"
-"showa.yamanashi.jp\0"
-"\xd8\xa7\xd9\x84\xd9\x8a\xd9\x85\xd9\x86\0trafficplex.cloud\0"
-"shibuya.tokyo.jp\0"
-"map.fastlylb.net\0"
-"*.ye\0chanel\0\xe5\x95\x86\xe5\x9f\x8e\0"
-"ueda.nagano.jp\0"
-"sirdal.no\0"
-"tsukumi.oita.jp\0"
-"poltava.ua\0"
-"gyeonggi.kr\0"
-"oygarden.no\0abb\0delivery\0dnshome.de\0"
-"kujukuri.chiba.jp\0red.sv\0odesa.ua\0abc\0\xe5\xa8\xb1\xe4\xb9\x90\0"
-"lib.ee\0"
-"\xe7\xbb\x84\xe7\xb9\x94.hk\0"
-"kr\xc3\xb8""dsherad.no\0mypsx.net\0"
-"numata.hokkaido.jp\0house.museum\0"
-"riik.ee\0te.ua\0"
-"or.th\0college\0"
-"istmein.de\0"
-"kasumigaura.ibaraki.jp\0"
-"shikaoi.hokkaido.jp\0"
-"is-a-geek.net\0"
-"z.se\0"
-"canada.museum\0"
-"sumida.tokyo.jp\0pfizer\0"
-"juegos\0"
-"science-fiction.museum\0gmbh\0"
-"starnberg.museum\0or.ug\0kred\0barsyonline.co.uk\0"
-"amli.no\0"
-"northwesternmutual\0"
-"or.tz\0"
-"aco\0rogers\0"
-"erotika.hu\0"
-"mypep.link\0"
-"or.us\0"
-"k12.ma.us\0"
-"tr.no\0"
-"kami.miyagi.jp\0s3.dualstack.us-east-1.amazonaws.com\0"
-"asahi.ibaraki.jp\0"
-"africa.com\0from-tn.com\0"
-"!city.yokohama.jp\0"
-"sanjo.niigata.jp\0"
-"\xe6\x96\xb0\xe6\xbd\x9f.jp\0hospital\0"
-"chikugo.fukuoka.jp\0"
-"sinaapp.com\0"
-"ads\0"
-"vic.edu.au\0aeg\0"
-"ownip.net\0"
-"fhapp.xyz\0"
-"makeup\0"
-"kibichuo.okayama.jp\0"
-"ibara.okayama.jp\0os.hedmark.no\0"
-"mielec.pl\0chat\0"
-};
-static constexpr quint32 tldChunks[tldChunkCount] = {65531, 104170};
-
-QT_END_NAMESPACE
-
-#endif // QURLTLD_P_H
diff --git a/src/network/kernel/qurltlds_p.h.INFO b/src/network/kernel/qurltlds_p.h.INFO
deleted file mode 100644
index 33ccd458bf..0000000000
--- a/src/network/kernel/qurltlds_p.h.INFO
+++ /dev/null
@@ -1,14 +0,0 @@
-The file qurltlds_p.h is generated from the Public Suffix
-List (see [1] and [2]), by the program residing at
-util/corelib/qurl-generateTLDs in the Qt source tree.
-
-That program generates a character array and an index array from the
-list to provide fast lookups of elements within C++.
-
-Those arrays in qurltlds_p.h are derived from the Public
-Suffix List ([2]), which was originally provided by
-Jo Hermans <jo.hermans@gmail.com>.
-
-----
-[1] list: http://mxr.mozilla.org/mozilla-central/source/netwerk/dns/effective_tld_names.dat?raw=1
-[2] homepage: http://publicsuffix.org/
diff --git a/src/network/network.pro b/src/network/network.pro
deleted file mode 100644
index b9fbd3427f..0000000000
--- a/src/network/network.pro
+++ /dev/null
@@ -1,27 +0,0 @@
-TARGET = QtNetwork
-QT = core-private
-
-DEFINES += QT_NO_USING_NAMESPACE QT_NO_FOREACH
-#DEFINES += QLOCALSERVER_DEBUG QLOCALSOCKET_DEBUG
-#DEFINES += QNETWORKDISKCACHE_DEBUG
-#DEFINES += QSSLSOCKET_DEBUG
-#DEFINES += QHOSTINFO_DEBUG
-#DEFINES += QABSTRACTSOCKET_DEBUG QNATIVESOCKETENGINE_DEBUG
-#DEFINES += QTCPSOCKETENGINE_DEBUG QTCPSOCKET_DEBUG QTCPSERVER_DEBUG QSSLSOCKET_DEBUG
-#DEFINES += QUDPSOCKET_DEBUG QUDPSERVER_DEBUG
-#DEFINES += QSCTPSOCKET_DEBUG QSCTPSERVER_DEBUG
-msvc:equals(QT_ARCH, i386): QMAKE_LFLAGS += /BASE:0x64000000
-
-QMAKE_DOCS = $$PWD/doc/qtnetwork.qdocconf
-
-MODULE_PLUGIN_TYPES = \
- networkaccessbackends
-
-include(access/access.pri)
-include(kernel/kernel.pri)
-include(socket/socket.pri)
-include(ssl/ssl.pri)
-
-QMAKE_LIBS += $$QMAKE_LIBS_NETWORK
-
-load(qt_module)
diff --git a/src/network/qt_cmdline.cmake b/src/network/qt_cmdline.cmake
index 0a24507788..0b4c0c239a 100644
--- a/src/network/qt_cmdline.cmake
+++ b/src/network/qt_cmdline.cmake
@@ -1,7 +1,7 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
qt_commandline_option(libproxy TYPE boolean)
-qt_commandline_option(openssl TYPE optionalString VALUES no yes linked runtime)
-qt_commandline_option(openssl-linked TYPE void NAME openssl VALUE linked)
-qt_commandline_option(openssl-runtime TYPE void NAME openssl VALUE runtime)
qt_commandline_option(dtls TYPE boolean)
qt_commandline_option(ocsp TYPE boolean)
qt_commandline_option(sctp TYPE boolean)
@@ -9,4 +9,4 @@ qt_commandline_option(securetransport TYPE boolean)
qt_commandline_option(schannel TYPE boolean)
qt_commandline_option(ssl TYPE boolean)
qt_commandline_option(system-proxies TYPE boolean)
-qt_commandline_assignment(OPENSSL_PATH openssl.prefix)
+qt_commandline_option(publicsuffix TYPE optionalString VALUES system qt no all)
diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp
index f3885a22fe..e456d00713 100644
--- a/src/network/socket/qabstractsocket.cpp
+++ b/src/network/socket/qabstractsocket.cpp
@@ -1,42 +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 QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//#define QABSTRACTSOCKET_DEBUG
@@ -209,8 +173,9 @@
parameter describes the type of error that occurred.
When this signal is emitted, the socket may not be ready for a reconnect
- attempt. In that case, attempts to reconnect should be done from the event
- loop. For example, use a QTimer::singleShot() with 0 as the timeout.
+ attempt. In that case, attempts to reconnect should be done from the
+ event loop. For example, use QChronoTimer::singleShot() with 0ns as
+ the timeout.
QAbstractSocket::SocketError is not a registered metatype, so for queued
connections, you will have to register it with Q_DECLARE_METATYPE() and
@@ -430,7 +395,7 @@
\value DontShareAddress Bind the address and port exclusively, so that
no other services are allowed to rebind. By passing this option to
- QAbstractSocket::bind(), you are guaranteed that on successs, your service
+ QAbstractSocket::bind(), you are guaranteed that on success, your service
is the only one that listens to the address and port. No services are
allowed to rebind, even if they pass ReuseAddressHint. This option
provides more security than ShareAddress, but on certain operating
@@ -475,7 +440,7 @@
#include <qmetaobject.h>
#include <qpointer.h>
#include <qtimer.h>
-#include <qelapsedtimer.h>
+#include <qdeadlinetimer.h>
#include <qscopedvaluerollback.h>
#include <qvarlengtharray.h>
@@ -483,6 +448,7 @@
#ifdef QABSTRACTSOCKET_DEBUG
#include <qdebug.h>
+#include <private/qdebug_p.h>
#endif
#include <time.h>
@@ -499,43 +465,13 @@
QT_BEGIN_NAMESPACE
-static const int DefaultConnectTimeout = 30000;
-
-#if defined QABSTRACTSOCKET_DEBUG
-QT_BEGIN_INCLUDE_NAMESPACE
-#include <qstring.h>
-#include <ctype.h>
-QT_END_INCLUDE_NAMESPACE
-
-/*
- Returns a human readable representation of the first \a len
- characters in \a data.
-*/
-static QByteArray qt_prettyDebug(const char *data, int len, int maxLength)
-{
- if (!data) return "(null)";
- QByteArray out;
- for (int i = 0; i < qMin(len, maxLength); ++i) {
- char c = data[i];
- if (isprint(int(uchar(c)))) {
- out += c;
- } else switch (c) {
- case '\n': out += "\\n"; break;
- case '\r': out += "\\r"; break;
- case '\t': out += "\\t"; break;
- default:
- QString tmp;
- tmp.sprintf("\\%o", c);
- out += tmp.toLatin1();
- }
- }
+using namespace Qt::StringLiterals;
+using namespace std::chrono_literals;
- if (len < maxLength)
- out += "...";
+QT_IMPL_METATYPE_EXTERN_TAGGED(QAbstractSocket::SocketState, QAbstractSocket__SocketState)
+QT_IMPL_METATYPE_EXTERN_TAGGED(QAbstractSocket::SocketError, QAbstractSocket__SocketError)
- return out;
-}
-#endif
+static constexpr auto DefaultConnectTimeout = 30s;
static bool isProxyError(QAbstractSocket::SocketError error)
{
@@ -557,25 +493,6 @@ static bool isProxyError(QAbstractSocket::SocketError error)
Constructs a QAbstractSocketPrivate. Initializes all members.
*/
QAbstractSocketPrivate::QAbstractSocketPrivate()
- : emittedReadyRead(false),
- emittedBytesWritten(false),
- abortCalled(false),
- pendingClose(false),
- pauseMode(QAbstractSocket::PauseNever),
- port(0),
- localPort(0),
- peerPort(0),
- socketEngine(nullptr),
- cachedSocketDescriptor(-1),
- readBufferMaxSize(0),
- isBuffered(false),
- hasPendingData(false),
- connectTimer(nullptr),
- hostLookupId(-1),
- socketType(QAbstractSocket::UnknownSocketType),
- state(QAbstractSocket::UnconnectedState),
- socketError(QAbstractSocket::UnknownSocketError),
- preferredNetworkLayerProtocol(QAbstractSocket::UnknownNetworkLayerProtocol)
{
writeBufferChunkSize = QABSTRACTSOCKET_BUFFERSIZE;
}
@@ -627,14 +544,14 @@ bool QAbstractSocketPrivate::initSocketLayer(QAbstractSocket::NetworkLayerProtoc
Q_Q(QAbstractSocket);
#if defined (QABSTRACTSOCKET_DEBUG)
QString typeStr;
- if (q->socketType() == QAbstractSocket::TcpSocket) typeStr = QLatin1String("TcpSocket");
- else if (q->socketType() == QAbstractSocket::UdpSocket) typeStr = QLatin1String("UdpSocket");
- else if (q->socketType() == QAbstractSocket::SctpSocket) typeStr = QLatin1String("SctpSocket");
- else typeStr = QLatin1String("UnknownSocketType");
+ if (q->socketType() == QAbstractSocket::TcpSocket) typeStr = "TcpSocket"_L1;
+ else if (q->socketType() == QAbstractSocket::UdpSocket) typeStr = "UdpSocket"_L1;
+ else if (q->socketType() == QAbstractSocket::SctpSocket) typeStr = "SctpSocket"_L1;
+ else typeStr = "UnknownSocketType"_L1;
QString protocolStr;
- if (protocol == QAbstractSocket::IPv4Protocol) protocolStr = QLatin1String("IPv4Protocol");
- else if (protocol == QAbstractSocket::IPv6Protocol) protocolStr = QLatin1String("IPv6Protocol");
- else protocolStr = QLatin1String("UnknownNetworkLayerProtocol");
+ if (protocol == QAbstractSocket::IPv4Protocol) protocolStr = "IPv4Protocol"_L1;
+ else if (protocol == QAbstractSocket::IPv6Protocol) protocolStr = "IPv6Protocol"_L1;
+ else protocolStr = "UnknownNetworkLayerProtocol"_L1;
#endif
resetSocketLayer();
@@ -721,11 +638,19 @@ bool QAbstractSocketPrivate::canReadNotification()
return !q->isReadable();
}
} else {
- if (hasPendingData) {
+ const bool isUdpSocket = (socketType == QAbstractSocket::UdpSocket);
+ if (hasPendingData && (!isUdpSocket || hasPendingDatagram)) {
socketEngine->setReadNotificationEnabled(false);
return true;
}
- hasPendingData = true;
+ if (!isUdpSocket
+#if QT_CONFIG(udpsocket)
+ || socketEngine->hasPendingDatagrams()
+#endif
+ ) {
+ hasPendingData = true;
+ hasPendingDatagram = isUdpSocket;
+ }
}
emitReadyRead();
@@ -921,7 +846,7 @@ void QAbstractSocketPrivate::resolveProxy(const QString &hostname, quint16 port)
}
// return the first that we can use
- for (const QNetworkProxy &p : qAsConst(proxies)) {
+ for (const QNetworkProxy &p : std::as_const(proxies)) {
if (socketType == QAbstractSocket::UdpSocket &&
(p.capabilities() & QNetworkProxy::UdpTunnelingCapability) == 0)
continue;
@@ -1020,12 +945,12 @@ void QAbstractSocketPrivate::_q_startConnecting(const QHostInfo &hostInfo)
#if defined(QABSTRACTSOCKET_DEBUG)
- QString s = QLatin1String("{");
+ QString s = "{"_L1;
for (int i = 0; i < addresses.count(); ++i) {
- if (i != 0) s += QLatin1String(", ");
+ if (i != 0) s += ", "_L1;
s += addresses.at(i).toString();
}
- s += QLatin1Char('}');
+ s += u'}';
qDebug("QAbstractSocketPrivate::_q_startConnecting(hostInfo == %s)", s.toLatin1().constData());
#endif
@@ -1142,8 +1067,7 @@ void QAbstractSocketPrivate::_q_connectToNextAddress()
q, SLOT(_q_abortConnectionAttempt()),
Qt::DirectConnection);
}
- int connectTimeout = DefaultConnectTimeout;
- connectTimer->start(connectTimeout);
+ connectTimer->start(DefaultConnectTimeout);
}
// Wait for a write notification that will eventually call
@@ -1381,12 +1305,29 @@ void QAbstractSocketPrivate::pauseSocketNotifiers(QAbstractSocket *socket)
QAbstractSocketEngine *socketEngine = socket->d_func()->socketEngine;
if (!socketEngine)
return;
- socket->d_func()->prePauseReadSocketNotifierState = socketEngine->isReadNotificationEnabled();
- socket->d_func()->prePauseWriteSocketNotifierState = socketEngine->isWriteNotificationEnabled();
- socket->d_func()->prePauseExceptionSocketNotifierState = socketEngine->isExceptionNotificationEnabled();
- socketEngine->setReadNotificationEnabled(false);
- socketEngine->setWriteNotificationEnabled(false);
- socketEngine->setExceptionNotificationEnabled(false);
+ bool read = socketEngine->isReadNotificationEnabled();
+ bool write = socketEngine->isWriteNotificationEnabled();
+ bool except = socketEngine->isExceptionNotificationEnabled();
+
+#ifdef QABSTRACTSOCKET_DEBUG
+ qDebug() << socketEngine->socketDescriptor()
+ << "pause notifiers, storing 'true' states, currently read:" << read
+ << "write:" << write << "except:" << except;
+#endif
+ // We do this if-check to avoid accidentally overwriting any previously stored state
+ // It will reset to false once the socket is re-enabled.
+ if (read) {
+ socket->d_func()->prePauseReadSocketNotifierState = true;
+ socketEngine->setReadNotificationEnabled(false);
+ }
+ if (write) {
+ socket->d_func()->prePauseWriteSocketNotifierState = true;
+ socketEngine->setWriteNotificationEnabled(false);
+ }
+ if (except) {
+ socket->d_func()->prePauseExceptionSocketNotifierState = true;
+ socketEngine->setExceptionNotificationEnabled(false);
+ }
}
void QAbstractSocketPrivate::resumeSocketNotifiers(QAbstractSocket *socket)
@@ -1394,9 +1335,19 @@ void QAbstractSocketPrivate::resumeSocketNotifiers(QAbstractSocket *socket)
QAbstractSocketEngine *socketEngine = socket->d_func()->socketEngine;
if (!socketEngine)
return;
- socketEngine->setReadNotificationEnabled(socket->d_func()->prePauseReadSocketNotifierState);
- socketEngine->setWriteNotificationEnabled(socket->d_func()->prePauseWriteSocketNotifierState);
- socketEngine->setExceptionNotificationEnabled(socket->d_func()->prePauseExceptionSocketNotifierState);
+ QAbstractSocketPrivate *priv = socket->d_func();
+#ifdef QABSTRACTSOCKET_DEBUG
+ qDebug() << socketEngine->socketDescriptor()
+ << "Maybe resume notifiers, read:" << priv->prePauseReadSocketNotifierState
+ << "write:" << priv->prePauseWriteSocketNotifierState
+ << "exception:" << priv->prePauseExceptionSocketNotifierState;
+#endif
+ if (std::exchange(priv->prePauseReadSocketNotifierState, false))
+ socketEngine->setReadNotificationEnabled(true);
+ if (std::exchange(priv->prePauseWriteSocketNotifierState, false))
+ socketEngine->setWriteNotificationEnabled(true);
+ if (std::exchange(priv->prePauseExceptionSocketNotifierState, false))
+ socketEngine->setExceptionNotificationEnabled(true);
}
QAbstractSocketEngine* QAbstractSocketPrivate::getSocketEngine(QAbstractSocket *socket)
@@ -1604,6 +1555,19 @@ bool QAbstractSocketPrivate::bind(const QHostAddress &address, quint16 port, QAb
}
/*!
+ \fn bool QAbstractSocket::bind(QHostAddress::SpecialAddress addr, quint16 port, BindMode mode)
+ \since 6.2
+ \overload
+
+ Binds to the special address \a addr on port \a port, using the BindMode \a
+ mode.
+
+ By default, the socket is bound using the DefaultForPlatform BindMode.
+ If a port is not specified, a random port is chosen.
+*/
+
+/*!
+ \fn bool QAbstractSocket::bind(quint16 port, BindMode mode)
\since 5.0
\overload
@@ -1612,10 +1576,12 @@ bool QAbstractSocketPrivate::bind(const QHostAddress &address, quint16 port, QAb
By default, the socket is bound using the DefaultForPlatform BindMode.
If a port is not specified, a random port is chosen.
*/
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
bool QAbstractSocket::bind(quint16 port, BindMode mode)
{
return bind(QHostAddress::Any, port, mode);
}
+#endif
/*!
Returns \c true if the socket is valid and ready for use; otherwise
@@ -1958,8 +1924,9 @@ bool QAbstractSocket::setSocketDescriptor(qintptr socketDescriptor, SocketState
\since 4.6
Sets the given \a option to the value described by \a value.
- \note On Windows Runtime, QAbstractSocket::KeepAliveOption must be set
- before the socket is connected.
+ \note Since the options are set on an internal socket the options
+ only apply if the socket has been created. This is only guaranteed to
+ have happened after a call to bind(), or when connected() has been emitted.
\sa socketOption()
*/
@@ -2094,8 +2061,7 @@ bool QAbstractSocket::waitForConnected(int msecs)
bool wasPendingClose = d->pendingClose;
d->pendingClose = false;
- QElapsedTimer stopWatch;
- stopWatch.start();
+ QDeadlineTimer deadline{msecs};
if (d->state == HostLookupState) {
#if defined (QABSTRACTSOCKET_DEBUG)
@@ -2115,22 +2081,21 @@ bool QAbstractSocket::waitForConnected(int msecs)
if (state() == UnconnectedState)
return false; // connect not im progress anymore!
- int connectTimeout = DefaultConnectTimeout;
bool timedOut = true;
#if defined (QABSTRACTSOCKET_DEBUG)
int attempt = 1;
#endif
- while (state() == ConnectingState && (msecs == -1 || stopWatch.elapsed() < msecs)) {
- int timeout = qt_subtract_from_timeout(msecs, stopWatch.elapsed());
- if (msecs != -1 && timeout > connectTimeout)
- timeout = connectTimeout;
+ while (state() == ConnectingState && !deadline.hasExpired()) {
+ QDeadlineTimer timer = deadline;
+ if (!deadline.isForever() && deadline.remainingTimeAsDuration() > DefaultConnectTimeout)
+ timer = QDeadlineTimer(DefaultConnectTimeout);
#if defined (QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocket::waitForConnected(%i) waiting %.2f secs for connection attempt #%i",
- msecs, timeout / 1000.0, attempt++);
+ msecs, timer.remainingTime() / 1000.0, attempt++);
#endif
timedOut = false;
- if (d->socketEngine && d->socketEngine->waitForWrite(timeout, &timedOut) && !timedOut) {
+ if (d->socketEngine && d->socketEngine->waitForWrite(timer, &timedOut) && !timedOut) {
d->_q_testConnection();
} else {
d->_q_connectToNextAddress();
@@ -2185,8 +2150,7 @@ bool QAbstractSocket::waitForReadyRead(int msecs)
return false;
}
- QElapsedTimer stopWatch;
- stopWatch.start();
+ QDeadlineTimer deadline{msecs};
// handle a socket in connecting state
if (state() == HostLookupState || state() == ConnectingState) {
@@ -2197,11 +2161,12 @@ bool QAbstractSocket::waitForReadyRead(int msecs)
do {
if (state() != ConnectedState && state() != BoundState)
return false;
+ Q_ASSERT(d->socketEngine);
bool readyToRead = false;
bool readyToWrite = false;
if (!d->socketEngine->waitForReadOrWrite(&readyToRead, &readyToWrite, true, !d->writeBuffer.isEmpty(),
- qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) {
+ deadline)) {
#if defined (QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocket::waitForReadyRead(%i) failed (%i, %s)",
msecs, d->socketEngine->error(), d->socketEngine->errorString().toLatin1().constData());
@@ -2219,7 +2184,7 @@ bool QAbstractSocket::waitForReadyRead(int msecs)
if (readyToWrite)
d->canWriteNotification();
- } while (msecs == -1 || qt_subtract_from_timeout(msecs, stopWatch.elapsed()) > 0);
+ } while (!deadline.hasExpired());
return false;
}
@@ -2255,8 +2220,7 @@ bool QAbstractSocket::waitForBytesWritten(int msecs)
if (d->writeBuffer.isEmpty())
return false;
- QElapsedTimer stopWatch;
- stopWatch.start();
+ QDeadlineTimer deadline{msecs};
// handle a socket in connecting state
if (state() == HostLookupState || state() == ConnectingState) {
@@ -2264,13 +2228,13 @@ bool QAbstractSocket::waitForBytesWritten(int msecs)
return false;
}
- forever {
+ for (;;) {
bool readyToRead = false;
bool readyToWrite = false;
if (!d->socketEngine->waitForReadOrWrite(&readyToRead, &readyToWrite,
!d->readBufferMaxSize || d->buffer.size() < d->readBufferMaxSize,
!d->writeBuffer.isEmpty(),
- qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) {
+ deadline)) {
#if defined (QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocket::waitForBytesWritten(%i) failed (%i, %s)",
msecs, d->socketEngine->error(), d->socketEngine->errorString().toLatin1().constData());
@@ -2334,8 +2298,7 @@ bool QAbstractSocket::waitForDisconnected(int msecs)
return false;
}
- QElapsedTimer stopWatch;
- stopWatch.start();
+ QDeadlineTimer deadline{msecs};
// handle a socket in connecting state
if (state() == HostLookupState || state() == ConnectingState) {
@@ -2345,12 +2308,12 @@ bool QAbstractSocket::waitForDisconnected(int msecs)
return true;
}
- forever {
+ for (;;) {
bool readyToRead = false;
bool readyToWrite = false;
if (!d->socketEngine->waitForReadOrWrite(&readyToRead, &readyToWrite, state() == ConnectedState,
!d->writeBuffer.isEmpty(),
- qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) {
+ deadline)) {
#if defined (QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocket::waitForReadyRead(%i) failed (%i, %s)",
msecs, d->socketEngine->error(), d->socketEngine->errorString().toLatin1().constData());
@@ -2443,9 +2406,8 @@ qint64 QAbstractSocket::readData(char *data, qint64 maxSize)
}
#if defined (QABSTRACTSOCKET_DEBUG)
- qDebug("QAbstractSocket::readData(%p \"%s\", %lli) == %lld [engine]",
- data, qt_prettyDebug(data, 32, readBytes).data(), maxSize,
- readBytes);
+ qDebug("QAbstractSocket::readData(%p \"%s\", %lli) == %lld [engine]", data,
+ QtDebugUtils::toPrintable(data, readBytes, 32).constData(), maxSize, readBytes);
#endif
return readBytes;
}
@@ -2483,8 +2445,7 @@ qint64 QAbstractSocket::writeData(const char *data, qint64 size)
#if defined (QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocket::writeData(%p \"%s\", %lli) == %lli", data,
- qt_prettyDebug(data, qMin((int)size, 32), size).data(),
- size, written);
+ QtDebugUtils::toPrintable(data, size, 32).constData(), size, written);
#endif
return written; // written = actually written + what has been buffered
} else if (!d->isBuffered && d->socketType != TcpSocket) {
@@ -2495,8 +2456,7 @@ qint64 QAbstractSocket::writeData(const char *data, qint64 size)
#if defined (QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocket::writeData(%p \"%s\", %lli) == %lli", data,
- qt_prettyDebug(data, qMin((int)size, 32), size).data(),
- size, written);
+ QtDebugUtils::toPrintable(data, size, 32).constData(), size, written);
#endif
if (written >= 0)
d->emitBytesWritten(written);
@@ -2517,8 +2477,7 @@ qint64 QAbstractSocket::writeData(const char *data, qint64 size)
#if defined (QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocket::writeData(%p \"%s\", %lli) == %lli", data,
- qt_prettyDebug(data, qMin((int)size, 32), size).data(),
- size, written);
+ QtDebugUtils::toPrintable(data, size, 32).constData(), size, written);
#endif
return written;
}
diff --git a/src/network/socket/qabstractsocket.h b/src/network/socket/qabstractsocket.h
index bf1ff7e9a2..1d5d45096a 100644
--- a/src/network/socket/qabstractsocket.h
+++ b/src/network/socket/qabstractsocket.h
@@ -1,46 +1,16 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QABSTRACTSOCKET_H
#define QABSTRACTSOCKET_H
#include <QtNetwork/qtnetworkglobal.h>
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
+#include <QtNetwork/qabstractsocket.h>
+#endif
+#ifdef Q_QDOC
+#include <QtNetwork/qhostaddress.h>
+#endif
#include <QtCore/qiodevice.h>
#include <QtCore/qobject.h>
#ifndef QT_NO_DEBUG_STREAM
@@ -70,6 +40,8 @@ public:
UnknownSocketType = -1
};
Q_ENUM(SocketType)
+
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
enum NetworkLayerProtocol {
IPv4Protocol,
IPv6Protocol,
@@ -77,6 +49,15 @@ public:
UnknownNetworkLayerProtocol = -1
};
Q_ENUM(NetworkLayerProtocol)
+#else
+ // compatibility with Qt 4 to 6
+ using NetworkLayerProtocol = QHostAddress::NetworkLayerProtocol;
+ static constexpr auto IPv4Protocol = QHostAddress::IPv4Protocol;
+ static constexpr auto IPv6Protocol = QHostAddress::IPv6Protocol;
+ static constexpr auto AnyIPProtocol = QHostAddress::AnyIPProtocol;
+ static constexpr auto UnknownNetworkLayerProtocol = QHostAddress::UnknownNetworkLayerProtocol;
+#endif
+
enum SocketError {
ConnectionRefusedError,
RemoteHostClosedError,
@@ -148,7 +129,14 @@ public:
virtual bool bind(const QHostAddress &address, quint16 port = 0,
BindMode mode = DefaultForPlatform);
+#if QT_VERSION >= QT_VERSION_CHECK(7,0,0) || defined(Q_QDOC)
+ bool bind(QHostAddress::SpecialAddress addr, quint16 port = 0, BindMode mode = DefaultForPlatform)
+ { return bind(QHostAddress(addr), port, mode); }
+ bool bind(quint16 port = 0, BindMode mode = DefaultForPlatform)
+ { return bind(QHostAddress::Any, port, mode); }
+#else
bool bind(quint16 port = 0, BindMode mode = DefaultForPlatform);
+#endif
virtual void connectToHost(const QString &hostName, quint16 port, OpenMode mode = ReadWrite, NetworkLayerProtocol protocol = AnyIPProtocol);
void connectToHost(const QHostAddress &address, quint16 port, OpenMode mode = ReadWrite);
@@ -246,7 +234,9 @@ Q_NETWORK_EXPORT QDebug operator<<(QDebug, QAbstractSocket::SocketState);
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QAbstractSocket::SocketState)
-Q_DECLARE_METATYPE(QAbstractSocket::SocketError)
+QT_DECL_METATYPE_EXTERN_TAGGED(QAbstractSocket::SocketState,
+ QAbstractSocket__SocketState, Q_NETWORK_EXPORT)
+QT_DECL_METATYPE_EXTERN_TAGGED(QAbstractSocket::SocketError,
+ QAbstractSocket__SocketError, Q_NETWORK_EXPORT)
#endif // QABSTRACTSOCKET_H
diff --git a/src/network/socket/qabstractsocket_p.h b/src/network/socket/qabstractsocket_p.h
index 83a8afe36d..cc5f53179c 100644
--- a/src/network/socket/qabstractsocket_p.h
+++ b/src/network/socket/qabstractsocket_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QABSTRACTSOCKET_P_H
#define QABSTRACTSOCKET_P_H
@@ -96,27 +60,27 @@ public:
void _q_testConnection();
void _q_abortConnectionAttempt();
- bool emittedReadyRead;
- bool emittedBytesWritten;
+ bool emittedReadyRead = false;
+ bool emittedBytesWritten = false;
- bool abortCalled;
- bool pendingClose;
+ bool abortCalled = false;
+ bool pendingClose = false;
- QAbstractSocket::PauseModes pauseMode;
+ QAbstractSocket::PauseModes pauseMode = QAbstractSocket::PauseNever;
QString hostName;
- quint16 port;
+ quint16 port = 0;
QHostAddress host;
QList<QHostAddress> addresses;
- quint16 localPort;
- quint16 peerPort;
+ quint16 localPort = 0;
+ quint16 peerPort = 0;
QHostAddress localAddress;
QHostAddress peerAddress;
QString peerName;
- QAbstractSocketEngine *socketEngine;
- qintptr cachedSocketDescriptor;
+ QAbstractSocketEngine *socketEngine = nullptr;
+ qintptr cachedSocketDescriptor = -1;
#ifndef QT_NO_NETWORKPROXY
QNetworkProxy proxy;
@@ -143,25 +107,27 @@ public:
void setError(QAbstractSocket::SocketError errorCode, const QString &errorString);
void setErrorAndEmit(QAbstractSocket::SocketError errorCode, const QString &errorString);
- qint64 readBufferMaxSize;
- bool isBuffered;
- bool hasPendingData;
+ qint64 readBufferMaxSize = 0;
+ bool isBuffered = false;
+ bool hasPendingData = false;
+ bool hasPendingDatagram = false;
- QTimer *connectTimer;
+ QTimer *connectTimer = nullptr;
- int hostLookupId;
+ int hostLookupId = -1;
- QAbstractSocket::SocketType socketType;
- QAbstractSocket::SocketState state;
+ QAbstractSocket::SocketType socketType = QAbstractSocket::UnknownSocketType;
+ QAbstractSocket::SocketState state = QAbstractSocket::UnconnectedState;
// Must be kept in sync with QIODevicePrivate::errorString.
- QAbstractSocket::SocketError socketError;
+ QAbstractSocket::SocketError socketError = QAbstractSocket::UnknownSocketError;
- QAbstractSocket::NetworkLayerProtocol preferredNetworkLayerProtocol;
+ QAbstractSocket::NetworkLayerProtocol preferredNetworkLayerProtocol =
+ QAbstractSocket::UnknownNetworkLayerProtocol;
- bool prePauseReadSocketNotifierState;
- bool prePauseWriteSocketNotifierState;
- bool prePauseExceptionSocketNotifierState;
+ bool prePauseReadSocketNotifierState = false;
+ bool prePauseWriteSocketNotifierState = false;
+ bool prePauseExceptionSocketNotifierState = false;
static void pauseSocketNotifiers(QAbstractSocket*);
static void resumeSocketNotifiers(QAbstractSocket*);
static QAbstractSocketEngine* getSocketEngine(QAbstractSocket*);
diff --git a/src/network/socket/qabstractsocketengine.cpp b/src/network/socket/qabstractsocketengine.cpp
index 50462fb11f..864ce8d9ea 100644
--- a/src/network/socket/qabstractsocketengine.cpp
+++ b/src/network/socket/qabstractsocketengine.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qabstractsocketengine_p.h"
@@ -73,7 +37,7 @@ QSocketEngineHandler::~QSocketEngineHandler()
QAbstractSocketEnginePrivate::QAbstractSocketEnginePrivate()
: socketError(QAbstractSocket::UnknownSocketError)
, hasSetSocketError(false)
- , socketErrorString(QLatin1String(QT_TRANSLATE_NOOP(QSocketLayer, "Unknown error")))
+ , socketErrorString(QLatin1StringView(QT_TRANSLATE_NOOP(QSocketLayer, "Unknown error")))
, socketState(QAbstractSocket::UnconnectedState)
, socketType(QAbstractSocket::UnknownSocketType)
, socketProtocol(QAbstractSocket::UnknownNetworkLayerProtocol)
diff --git a/src/network/socket/qabstractsocketengine_p.h b/src/network/socket/qabstractsocketengine_p.h
index 3d9ce96cb3..9ee79cebc1 100644
--- a/src/network/socket/qabstractsocketengine_p.h
+++ b/src/network/socket/qabstractsocketengine_p.h
@@ -1,42 +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 QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QABSTRACTSOCKETENGINE_P_H
#define QABSTRACTSOCKETENGINE_P_H
@@ -55,8 +19,9 @@
#include <QtNetwork/private/qtnetworkglobal_p.h>
#include "QtNetwork/qhostaddress.h"
#include "QtNetwork/qabstractsocket.h"
-#include "private/qobject_p.h"
+#include <QtCore/qdeadlinetimer.h>
#include "private/qnetworkdatagram_p.h"
+#include "private/qobject_p.h"
QT_BEGIN_NAMESPACE
@@ -80,6 +45,8 @@ public:
#endif
};
+static constexpr std::chrono::seconds DefaultTimeout{30};
+
class Q_AUTOTEST_EXPORT QAbstractSocketEngine : public QObject
{
Q_OBJECT
@@ -133,8 +100,8 @@ public:
virtual bool connectToHost(const QHostAddress &address, quint16 port) = 0;
virtual bool connectToHostByName(const QString &name, quint16 port) = 0;
virtual bool bind(const QHostAddress &address, quint16 port) = 0;
- virtual bool listen() = 0;
- virtual int accept() = 0;
+ virtual bool listen(int backlog) = 0;
+ virtual qintptr accept() = 0;
virtual void close() = 0;
virtual qint64 bytesAvailable() const = 0;
@@ -164,11 +131,14 @@ public:
virtual int option(SocketOption option) const = 0;
virtual bool setOption(SocketOption option, int value) = 0;
- virtual bool waitForRead(int msecs = 30000, bool *timedOut = nullptr) = 0;
- virtual bool waitForWrite(int msecs = 30000, bool *timedOut = nullptr) = 0;
+ virtual bool waitForRead(QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout},
+ bool *timedOut = nullptr) = 0;
+ virtual bool waitForWrite(QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout},
+ bool *timedOut = nullptr) = 0;
virtual bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
bool checkRead, bool checkWrite,
- int msecs = 30000, bool *timedOut = nullptr) = 0;
+ QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout},
+ bool *timedOut = nullptr) = 0;
QAbstractSocket::SocketError error() const;
QString errorString() const;
diff --git a/src/network/socket/qhttpsocketengine.cpp b/src/network/socket/qhttpsocketengine.cpp
index 5324038dbd..a700023bd5 100644
--- a/src/network/socket/qhttpsocketengine.cpp
+++ b/src/network/socket/qhttpsocketengine.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qhttpsocketengine_p.h"
#include "qtcpsocket.h"
@@ -43,7 +7,7 @@
#include "qurl.h"
#include "private/qhttpnetworkreply_p.h"
#include "private/qiodevice_p.h"
-#include "qelapsedtimer.h"
+#include "qdeadlinetimer.h"
#include "qnetworkinterface.h"
#if !defined(QT_NO_NETWORKPROXY)
@@ -51,6 +15,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
#define DEBUG
QHttpSocketEngine::QHttpSocketEngine(QObject *parent)
@@ -186,24 +152,22 @@ bool QHttpSocketEngine::connectToHostByName(const QString &hostname, quint16 por
bool QHttpSocketEngine::bind(const QHostAddress &, quint16)
{
qWarning("Operation is not supported");
- setError(QAbstractSocket::UnsupportedSocketOperationError,
- QLatin1String("Unsupported socket operation"));
+ setError(QAbstractSocket::UnsupportedSocketOperationError, "Unsupported socket operation"_L1);
return false;
}
-bool QHttpSocketEngine::listen()
+bool QHttpSocketEngine::listen(int backlog)
{
+ Q_UNUSED(backlog);
qWarning("Operation is not supported");
- setError(QAbstractSocket::UnsupportedSocketOperationError,
- QLatin1String("Unsupported socket operation"));
+ setError(QAbstractSocket::UnsupportedSocketOperationError, "Unsupported socket operation"_L1);
return false;
}
-int QHttpSocketEngine::accept()
+qintptr QHttpSocketEngine::accept()
{
qWarning("Operation is not supported");
- setError(QAbstractSocket::UnsupportedSocketOperationError,
- QLatin1String("Unsupported socket operation"));
+ setError(QAbstractSocket::UnsupportedSocketOperationError, "Unsupported socket operation"_L1);
return -1;
}
@@ -238,8 +202,7 @@ qint64 QHttpSocketEngine::read(char *data, qint64 maxlen)
// failed, return the socket's error. Otherwise, fall through and
// return as much as we read so far.
close();
- setError(QAbstractSocket::RemoteHostClosedError,
- QLatin1String("Remote host closed"));
+ setError(QAbstractSocket::RemoteHostClosedError, "Remote host closed"_L1);
setState(QAbstractSocket::UnconnectedState);
return -1;
}
@@ -258,8 +221,7 @@ bool QHttpSocketEngine::joinMulticastGroup(const QHostAddress &,
const QNetworkInterface &)
{
qWarning("Operation is not supported");
- setError(QAbstractSocket::UnsupportedSocketOperationError,
- QLatin1String("Unsupported socket operation"));
+ setError(QAbstractSocket::UnsupportedSocketOperationError, "Unsupported socket operation"_L1);
return false;
}
@@ -267,8 +229,7 @@ bool QHttpSocketEngine::leaveMulticastGroup(const QHostAddress &,
const QNetworkInterface &)
{
qWarning("Operation is not supported");
- setError(QAbstractSocket::UnsupportedSocketOperationError,
- QLatin1String("Unsupported socket operation"));
+ setError(QAbstractSocket::UnsupportedSocketOperationError, "Unsupported socket operation"_L1);
return false;
}
@@ -280,8 +241,7 @@ QNetworkInterface QHttpSocketEngine::multicastInterface() const
bool QHttpSocketEngine::setMulticastInterface(const QNetworkInterface &)
{
qWarning("Operation is not supported");
- setError(QAbstractSocket::UnsupportedSocketOperationError,
- QLatin1String("Unsupported socket operation"));
+ setError(QAbstractSocket::UnsupportedSocketOperationError, "Unsupported socket operation"_L1);
return false;
}
#endif // QT_NO_NETWORKINTERFACE
@@ -302,16 +262,14 @@ qint64 QHttpSocketEngine::pendingDatagramSize() const
qint64 QHttpSocketEngine::readDatagram(char *, qint64, QIpPacketHeader *, PacketHeaderOptions)
{
qWarning("Operation is not supported");
- setError(QAbstractSocket::UnsupportedSocketOperationError,
- QLatin1String("Unsupported socket operation"));
+ setError(QAbstractSocket::UnsupportedSocketOperationError, "Unsupported socket operation"_L1);
return -1;
}
qint64 QHttpSocketEngine::writeDatagram(const char *, qint64, const QIpPacketHeader &)
{
qWarning("Operation is not supported");
- setError(QAbstractSocket::UnsupportedSocketOperationError,
- QLatin1String("Unsupported socket operation"));
+ setError(QAbstractSocket::UnsupportedSocketOperationError, "Unsupported socket operation"_L1);
return -1;
}
@@ -352,19 +310,16 @@ bool QHttpSocketEngine::setOption(SocketOption option, int value)
return false;
}
-bool QHttpSocketEngine::waitForRead(int msecs, bool *timedOut)
+bool QHttpSocketEngine::waitForRead(QDeadlineTimer deadline, bool *timedOut)
{
Q_D(const QHttpSocketEngine);
if (!d->socket || d->socket->state() == QAbstractSocket::UnconnectedState)
return false;
- QElapsedTimer stopWatch;
- stopWatch.start();
-
// Wait for more data if nothing is available.
if (!d->socket->bytesAvailable()) {
- if (!d->socket->waitForReadyRead(qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) {
+ if (!d->socket->waitForReadyRead(deadline.remainingTime())) {
if (d->socket->state() == QAbstractSocket::UnconnectedState)
return true;
setError(d->socket->error(), d->socket->errorString());
@@ -374,11 +329,7 @@ bool QHttpSocketEngine::waitForRead(int msecs, bool *timedOut)
}
}
- // If we're not connected yet, wait until we are, or until an error
- // occurs.
- while (d->state != Connected && d->socket->waitForReadyRead(qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) {
- // Loop while the protocol handshake is taking place.
- }
+ waitForProtocolHandshake(deadline);
// Report any error that may occur.
if (d->state != Connected) {
@@ -390,14 +341,14 @@ bool QHttpSocketEngine::waitForRead(int msecs, bool *timedOut)
return true;
}
-bool QHttpSocketEngine::waitForWrite(int msecs, bool *timedOut)
+bool QHttpSocketEngine::waitForWrite(QDeadlineTimer deadline, bool *timedOut)
{
Q_D(const QHttpSocketEngine);
// If we're connected, just forward the call.
if (d->state == Connected) {
if (d->socket->bytesToWrite()) {
- if (!d->socket->waitForBytesWritten(msecs)) {
+ if (!d->socket->waitForBytesWritten(deadline.remainingTime())) {
if (d->socket->error() == QAbstractSocket::SocketTimeoutError && timedOut)
*timedOut = true;
return false;
@@ -406,15 +357,7 @@ bool QHttpSocketEngine::waitForWrite(int msecs, bool *timedOut)
return true;
}
- QElapsedTimer stopWatch;
- stopWatch.start();
-
- // If we're not connected yet, wait until we are, and until bytes have
- // been received (i.e., the socket has connected, we have sent the
- // greeting, and then received the response).
- while (d->state != Connected && d->socket->waitForReadyRead(qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) {
- // Loop while the protocol handshake is taking place.
- }
+ waitForProtocolHandshake(deadline);
// Report any error that may occur.
if (d->state != Connected) {
@@ -428,25 +371,37 @@ bool QHttpSocketEngine::waitForWrite(int msecs, bool *timedOut)
bool QHttpSocketEngine::waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
bool checkRead, bool checkWrite,
- int msecs, bool *timedOut)
+ QDeadlineTimer deadline, bool *timedOut)
{
Q_UNUSED(checkRead);
if (!checkWrite) {
// Not interested in writing? Then we wait for read notifications.
- bool canRead = waitForRead(msecs, timedOut);
+ bool canRead = waitForRead(deadline, timedOut);
if (readyToRead)
*readyToRead = canRead;
return canRead;
}
// Interested in writing? Then we wait for write notifications.
- bool canWrite = waitForWrite(msecs, timedOut);
+ bool canWrite = waitForWrite(deadline, timedOut);
if (readyToWrite)
*readyToWrite = canWrite;
return canWrite;
}
+void QHttpSocketEngine::waitForProtocolHandshake(QDeadlineTimer deadline) const
+{
+ Q_D(const QHttpSocketEngine);
+
+ // If we're not connected yet, wait until we are (and until bytes have
+ // been received, i.e. the socket has connected, we have sent the
+ // greeting, and then received the response), or until an error occurs.
+ while (d->state != Connected && d->socket->waitForReadyRead(deadline.remainingTime())) {
+ // Loop while the protocol handshake is taking place.
+ }
+}
+
bool QHttpSocketEngine::isReadNotificationEnabled() const
{
Q_D(const QHttpSocketEngine);
@@ -578,7 +533,7 @@ void QHttpSocketEngine::slotSocketReadNotification()
d->pendingResponseData -= uint(skipped);
if (d->pendingResponseData > 0)
return;
- if (d->reply->d_func()->statusCode == 407)
+ if (d->reply->statusCode() == 407)
d->state = SendAuthentication;
}
@@ -598,16 +553,8 @@ void QHttpSocketEngine::slotSocketReadNotification()
d->authenticator.detach();
priv = QAuthenticatorPrivate::getPrivate(d->authenticator);
- if (d->credentialsSent && priv->phase != QAuthenticatorPrivate::Phase2) {
- // Remember that (e.g.) NTLM is two-phase, so only reset when the authentication is not currently in progress.
- //407 response again means the provided username/password were invalid.
- d->authenticator = QAuthenticator(); //this is needed otherwise parseHttpResponse won't set the state, and then signal isn't emitted.
- d->authenticator.detach();
- priv = QAuthenticatorPrivate::getPrivate(d->authenticator);
- priv->hasFailed = true;
- }
-
- priv->parseHttpResponse(d->reply->header(), true, d->proxy.hostName());
+ const auto headers = d->reply->header();
+ priv->parseHttpResponse(headers, true, d->proxy.hostName());
if (priv->phase == QAuthenticatorPrivate::Invalid) {
// problem parsing the reply
@@ -618,6 +565,29 @@ void QHttpSocketEngine::slotSocketReadNotification()
return;
}
+ if (priv->phase == QAuthenticatorPrivate::Done
+ || (priv->phase == QAuthenticatorPrivate::Start
+ && (priv->method == QAuthenticatorPrivate::Ntlm
+ || priv->method == QAuthenticatorPrivate::Negotiate))) {
+ if (priv->phase == QAuthenticatorPrivate::Start)
+ priv->phase = QAuthenticatorPrivate::Phase1;
+ bool credentialsWasSent = d->credentialsSent;
+ if (d->credentialsSent) {
+ // Remember that (e.g.) NTLM is two-phase, so only reset when the authentication is
+ // not currently in progress. 407 response again means the provided
+ // username/password were invalid.
+ d->authenticator.detach();
+ priv = QAuthenticatorPrivate::getPrivate(d->authenticator);
+ priv->hasFailed = true;
+ d->credentialsSent = false;
+ priv->phase = QAuthenticatorPrivate::Done;
+ }
+ if ((priv->method != QAuthenticatorPrivate::Ntlm
+ && priv->method != QAuthenticatorPrivate::Negotiate)
+ || credentialsWasSent)
+ proxyAuthenticationRequired(d->proxy, &d->authenticator);
+ }
+
bool willClose;
QByteArray proxyConnectionHeader = d->reply->headerField("Proxy-Connection");
// Although most proxies use the unofficial Proxy-Connection header, the Connection header
@@ -642,13 +612,11 @@ void QHttpSocketEngine::slotSocketReadNotification()
d->socket->readAll();
//We're done with the reply and need to reset it for the next connection
delete d->reply;
- d->reply = new QHttpNetworkReply;
+ d->reply = new QHttpNetworkReply(QUrl(), this);
}
- if (priv->phase == QAuthenticatorPrivate::Done)
- proxyAuthenticationRequired(d->proxy, &d->authenticator);
- // priv->phase will get reset to QAuthenticatorPrivate::Start if the authenticator got modified in the signal above.
if (priv->phase == QAuthenticatorPrivate::Done) {
+ d->authenticator = QAuthenticator();
setError(QAbstractSocket::ProxyAuthenticationRequiredError, tr("Authentication required"));
d->socket->disconnectFromHost();
} else {
@@ -790,7 +758,7 @@ void QHttpSocketEngine::emitReadNotification()
{
Q_D(QHttpSocketEngine);
// if there is a connection notification pending we have to emit the readNotification
- // incase there is connection error. This is only needed for Windows, but it does not
+ // in case there is connection error. This is only needed for Windows, but it does not
// hurt in other cases.
if ((d->readNotificationEnabled && !d->readNotificationPending) || d->connectionNotificationPending) {
d->readNotificationPending = true;
diff --git a/src/network/socket/qhttpsocketengine_p.h b/src/network/socket/qhttpsocketengine_p.h
index 0c2c450c81..7926abf513 100644
--- a/src/network/socket/qhttpsocketengine_p.h
+++ b/src/network/socket/qhttpsocketengine_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QHTTPSOCKETENGINE_P_H
#define QHTTPSOCKETENGINE_P_H
@@ -52,10 +16,12 @@
//
#include <QtNetwork/private/qtnetworkglobal_p.h>
-#include "private/qabstractsocketengine_p.h"
+
+#include <QtNetwork/qnetworkproxy.h>
+
#include "qabstractsocket.h"
-#include "qnetworkproxy.h"
#include "private/qauthenticator_p.h"
+#include "private/qabstractsocketengine_p.h"
QT_REQUIRE_CONFIG(http);
@@ -95,8 +61,8 @@ public:
bool connectToHost(const QHostAddress &address, quint16 port) override;
bool connectToHostByName(const QString &name, quint16 port) override;
bool bind(const QHostAddress &address, quint16 port) override;
- bool listen() override;
- int accept() override;
+ bool listen(int backlog) override;
+ qintptr accept() override;
void close() override;
qint64 bytesAvailable() const override;
@@ -126,11 +92,16 @@ public:
int option(SocketOption option) const override;
bool setOption(SocketOption option, int value) override;
- bool waitForRead(int msecs = 30000, bool *timedOut = nullptr) override;
- bool waitForWrite(int msecs = 30000, bool *timedOut = nullptr) override;
+ bool waitForRead(QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout},
+ bool *timedOut = nullptr) override;
+ bool waitForWrite(QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout},
+ bool *timedOut = nullptr) override;
bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
bool checkRead, bool checkWrite,
- int msecs = 30000, bool *timedOut = nullptr) override;
+ QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout},
+ bool *timedOut = nullptr) override;
+
+ void waitForProtocolHandshake(QDeadlineTimer deadline) const;
bool isReadNotificationEnabled() const override;
void setReadNotificationEnabled(bool enable) override;
diff --git a/src/network/socket/qlocalserver.cpp b/src/network/socket/qlocalserver.cpp
index 251b785dfd..5ef2db6b94 100644
--- a/src/network/socket/qlocalserver.cpp
+++ b/src/network/socket/qlocalserver.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qlocalserver.h"
#include "qlocalserver_p.h"
@@ -47,6 +11,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
/*!
\class QLocalServer
\since 4.4
@@ -90,6 +56,8 @@ QT_BEGIN_NAMESPACE
socket. This changes the access permissions on platforms (Linux, Windows)
that support access permissions on the socket. Both GroupAccess and OtherAccess
may vary slightly in meanings depending on the platform.
+ On Linux and Android it is possible to use sockets with abstract addresses;
+ socket permissions have no meaning for such sockets.
\value NoOptions No access restrictions have been set.
\value UserAccessOption
@@ -102,6 +70,10 @@ QT_BEGIN_NAMESPACE
Access is available to everyone on Windows.
\value WorldAccessOption
No access restrictions.
+ \value AbstractNamespaceOption
+ The listening socket will be created in the abstract namespace. This flag is specific to Linux.
+ In case of other platforms, for the sake of code portability, this flag is equivalent
+ to WorldAccessOption.
\sa socketOptions
*/
@@ -138,8 +110,9 @@ QLocalServer::~QLocalServer()
\property QLocalServer::socketOptions
\since 5.0
- The setSocketOptions method controls how the socket operates.
- For example the socket may restrict access to what user ids can
+ \brief the socket options that control how the socket operates.
+
+ For example, the socket may restrict access to what user ids can
connect to the socket.
These options must be set before listen() is called.
@@ -147,7 +120,7 @@ QLocalServer::~QLocalServer()
In some cases, such as with Unix domain sockets on Linux, the
access to the socket will be determined by file system permissions,
and are created based on the umask. Setting the access flags will
- overide this and will restrict or permit access as specified.
+ override this and will restrict or permit access as specified.
Other Unix-based operating systems, such as \macos, do not
honor file permissions for Unix domain sockets and by default
@@ -160,6 +133,11 @@ QLocalServer::~QLocalServer()
in the Windows documentation). OtherAccessOption refers to
the well known "Everyone" group.
+ On Linux platforms it is possible to create a socket in the abstract
+ namespace, which is independent of the filesystem. Using this kind
+ of socket implies ignoring permission options. On other platforms
+ AbstractNamespaceOption is equivalent to WorldAccessOption.
+
By default none of the flags are set, access permissions
are the platform default.
@@ -184,6 +162,12 @@ QLocalServer::SocketOptions QLocalServer::socketOptions() const
return d->socketOptions;
}
+QBindable<QLocalServer::SocketOptions> QLocalServer::bindableSocketOptions()
+{
+ Q_D(QLocalServer);
+ return &d->socketOptions;
+}
+
/*!
\since 5.10
Returns the native socket descriptor the server uses to listen
@@ -192,8 +176,7 @@ QLocalServer::SocketOptions QLocalServer::socketOptions() const
The type of the descriptor depends on the platform:
\list
\li On Windows, the returned value is a
- \l{https://msdn.microsoft.com/en-us/library/windows/desktop/ms740522(v=vs.85).aspx}
- {Winsock 2 Socket Handle}.
+ \l{Winsock 2 Socket Handle}.
\li On INTEGRITY, the returned value is the
QTcpServer socket descriptor and the type is defined by
@@ -282,9 +265,27 @@ bool QLocalServer::hasPendingConnections() const
*/
void QLocalServer::incomingConnection(quintptr socketDescriptor)
{
- Q_D(QLocalServer);
QLocalSocket *socket = new QLocalSocket(this);
socket->setSocketDescriptor(socketDescriptor);
+ addPendingConnection(socket);
+}
+
+/*!
+ This function is called by QLocalServer::incomingConnection()
+ to add the \a socket to the list of pending incoming connections.
+
+ \note Don't forget to call this member from reimplemented
+ incomingConnection() if you do not want to break the
+ Pending Connections mechanism. This function emits the
+ pendingConnectionAvailable() signal after the socket has been
+ added.
+
+ \sa incomingConnection(), pendingConnectionAvailable()
+ \since 6.8
+*/
+void QLocalServer::addPendingConnection(QLocalSocket *socket)
+{
+ Q_D(QLocalServer);
d->pendingConnections.enqueue(socket);
emit newConnection();
}
@@ -331,7 +332,7 @@ bool QLocalServer::listen(const QString &name)
if (name.isEmpty()) {
d->error = QAbstractSocket::HostNotFoundError;
- QString function = QLatin1String("QLocalServer::listen");
+ QString function = "QLocalServer::listen"_L1;
d->errorString = tr("%1: Name error").arg(function);
return false;
}
@@ -358,7 +359,9 @@ bool QLocalServer::listen(const QString &name)
serverName(), fullServerName() may return a string with
a name if this option is supported by the platform;
- otherwise, they return an empty QString.
+ otherwise, they return an empty QString. In particular, the addresses
+ of sockets in the abstract namespace supported by Linux will
+ not yield useful names if they contain unprintable characters.
\sa isListening(), close()
*/
@@ -534,6 +537,36 @@ bool QLocalServer::waitForNewConnection(int msec, bool *timedOut)
return !d->pendingConnections.isEmpty();
}
+/*!
+ Sets the backlog queue size of to be accepted connections to \a
+ size. The operating system might reduce or ignore this value.
+ By default, the queue size is 50.
+
+ \note This property must be set prior to calling listen().
+
+ \since 6.3
+
+ \sa listenBacklogSize()
+*/
+void QLocalServer::setListenBacklogSize(int size)
+{
+ Q_D(QLocalServer);
+ d->listenBacklog = size;
+}
+
+/*!
+ Returns the backlog queue size of to be accepted connections.
+
+ \since 6.3
+
+ \sa setListenBacklogSize()
+*/
+int QLocalServer::listenBacklogSize() const
+{
+ Q_D(const QLocalServer);
+ return d->listenBacklog;
+}
+
QT_END_NAMESPACE
#include "moc_qlocalserver.cpp"
diff --git a/src/network/socket/qlocalserver.h b/src/network/socket/qlocalserver.h
index 211aa94d85..685253e8be 100644
--- a/src/network/socket/qlocalserver.h
+++ b/src/network/socket/qlocalserver.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QLOCALSERVER_H
#define QLOCALSERVER_H
@@ -43,6 +7,8 @@
#include <QtNetwork/qtnetworkglobal.h>
#include <QtNetwork/qabstractsocket.h>
+#include <QtCore/qproperty.h>
+
QT_REQUIRE_CONFIG(localserver);
QT_BEGIN_NAMESPACE
@@ -54,7 +20,8 @@ class Q_NETWORK_EXPORT QLocalServer : public QObject
{
Q_OBJECT
Q_DECLARE_PRIVATE(QLocalServer)
- Q_PROPERTY(SocketOptions socketOptions READ socketOptions WRITE setSocketOptions)
+ Q_PROPERTY(SocketOptions socketOptions READ socketOptions WRITE setSocketOptions
+ BINDABLE bindableSocketOptions)
Q_SIGNALS:
void newConnection();
@@ -65,9 +32,10 @@ public:
UserAccessOption = 0x01,
GroupAccessOption = 0x2,
OtherAccessOption = 0x4,
- WorldAccessOption = 0x7
+ WorldAccessOption = 0x7,
+ AbstractNamespaceOption = 0x8
};
- Q_FLAG(SocketOption)
+ Q_ENUM(SocketOption)
Q_DECLARE_FLAGS(SocketOptions, SocketOption)
Q_FLAG(SocketOptions)
@@ -89,13 +57,18 @@ public:
void setMaxPendingConnections(int numConnections);
bool waitForNewConnection(int msec = 0, bool *timedOut = nullptr);
+ void setListenBacklogSize(int size);
+ int listenBacklogSize() const;
+
void setSocketOptions(SocketOptions options);
SocketOptions socketOptions() const;
+ QBindable<SocketOptions> bindableSocketOptions();
qintptr socketDescriptor() const;
protected:
virtual void incomingConnection(quintptr socketDescriptor);
+ void addPendingConnection(QLocalSocket *socket);
private:
Q_DISABLE_COPY(QLocalServer)
diff --git a/src/network/socket/qlocalserver_p.h b/src/network/socket/qlocalserver_p.h
index f331a3f10d..f7afd5cd32 100644
--- a/src/network/socket/qlocalserver_p.h
+++ b/src/network/socket/qlocalserver_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QLOCALSERVER_P_H
#define QLOCALSERVER_P_H
@@ -61,6 +25,7 @@ QT_REQUIRE_CONFIG(localserver);
#if defined(QT_LOCALSOCKET_TCP)
# include <qtcpserver.h>
+# include <QtCore/qmap.h>
#elif defined(Q_OS_WIN)
# include <qt_windows.h>
# include <qwineventnotifier.h>
@@ -126,7 +91,9 @@ public:
QQueue<QLocalSocket*> pendingConnections;
QString errorString;
QAbstractSocket::SocketError error;
- QLocalServer::SocketOptions socketOptions;
+ int listenBacklog = 50;
+
+ Q_OBJECT_BINDABLE_PROPERTY(QLocalServerPrivate, QLocalServer::SocketOptions, socketOptions)
};
QT_END_NAMESPACE
diff --git a/src/network/socket/qlocalserver_tcp.cpp b/src/network/socket/qlocalserver_tcp.cpp
index b3f1188afa..4d52d2c23a 100644
--- a/src/network/socket/qlocalserver_tcp.cpp
+++ b/src/network/socket/qlocalserver_tcp.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qlocalserver.h"
#include "qlocalserver_p.h"
@@ -48,6 +12,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
void QLocalServerPrivate::init()
{
Q_Q(QLocalServer);
@@ -56,16 +22,18 @@ void QLocalServerPrivate::init()
bool QLocalServerPrivate::listen(const QString &requestedServerName)
{
+ tcpServer.setListenBacklogSize(listenBacklog);
+
if (!tcpServer.listen(QHostAddress::LocalHost))
return false;
- const QLatin1String prefix("QLocalServer/");
+ const auto prefix = "QLocalServer/"_L1;
if (requestedServerName.startsWith(prefix))
fullServerName = requestedServerName;
else
fullServerName = prefix + requestedServerName;
- QSettings settings(QLatin1String("QtProject"), QLatin1String("Qt"));
+ QSettings settings("QtProject"_L1, "Qt"_L1);
if (settings.contains(fullServerName)) {
qWarning("QLocalServer::listen: server name is already in use.");
tcpServer.close();
@@ -83,8 +51,8 @@ bool QLocalServerPrivate::listen(qintptr socketDescriptor)
void QLocalServerPrivate::closeServer()
{
- QSettings settings(QLatin1String("QtProject"), QLatin1String("Qt"));
- if (fullServerName == QLatin1String("QLocalServer"))
+ QSettings settings("QtProject"_L1, "Qt"_L1);
+ if (fullServerName == "QLocalServer"_L1)
settings.setValue(fullServerName, QVariant());
else
settings.remove(fullServerName);
@@ -115,14 +83,14 @@ void QLocalServerPrivate::_q_onNewConnection()
bool QLocalServerPrivate::removeServer(const QString &name)
{
- const QLatin1String prefix("QLocalServer/");
+ const auto prefix = "QLocalServer/"_L1;
QString serverName;
if (name.startsWith(prefix))
serverName = name;
else
serverName = prefix + name;
- QSettings settings(QLatin1String("QtProject"), QLatin1String("Qt"));
+ QSettings settings("QtProject"_L1, "Qt"_L1);
if (settings.contains(serverName))
settings.remove(serverName);
diff --git a/src/network/socket/qlocalserver_unix.cpp b/src/network/socket/qlocalserver_unix.cpp
index c4085b440e..9aa9a5b86f 100644
--- a/src/network/socket/qlocalserver_unix.cpp
+++ b/src/network/socket/qlocalserver_unix.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qlocalserver.h"
#include "qlocalserver_p.h"
@@ -44,6 +8,7 @@
#include "qnet_unix_p.h"
#include "qtemporarydir.h"
+#include <stddef.h>
#include <sys/socket.h>
#include <sys/un.h>
@@ -51,12 +16,33 @@
#include <qdir.h>
#include <qdatetime.h>
+#include <optional>
+
#ifdef Q_OS_VXWORKS
# include <selectLib.h>
#endif
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
+namespace {
+QLocalServer::SocketOptions optionsForPlatform(QLocalServer::SocketOptions srcOptions)
+{
+ // For OS that does not support abstract namespace the AbstractNamespaceOption
+ // means that we go for WorldAccessOption - as it is the closest option in
+ // regards of access rights. In Linux/Android case we clean-up the access rights.
+
+ if (srcOptions.testFlag(QLocalServer::AbstractNamespaceOption)) {
+ if (PlatformSupportsAbstractNamespace)
+ return QLocalServer::AbstractNamespaceOption;
+ else
+ return QLocalServer::WorldAccessOption;
+ }
+ return srcOptions;
+}
+}
+
void QLocalServerPrivate::init()
{
}
@@ -64,11 +50,11 @@ void QLocalServerPrivate::init()
bool QLocalServerPrivate::removeServer(const QString &name)
{
QString fileName;
- if (name.startsWith(QLatin1Char('/'))) {
+ if (name.startsWith(u'/')) {
fileName = name;
} else {
fileName = QDir::cleanPath(QDir::tempPath());
- fileName += QLatin1Char('/') + name;
+ fileName += u'/' + name;
}
if (QFile::exists(fileName))
return QFile::remove(fileName);
@@ -80,50 +66,66 @@ bool QLocalServerPrivate::listen(const QString &requestedServerName)
{
Q_Q(QLocalServer);
+ // socket options adjusted for current platform
+ auto options = optionsForPlatform(socketOptions.value());
+
// determine the full server path
- if (requestedServerName.startsWith(QLatin1Char('/'))) {
+ if (options.testFlag(QLocalServer::AbstractNamespaceOption)
+ || requestedServerName.startsWith(u'/')) {
fullServerName = requestedServerName;
} else {
fullServerName = QDir::cleanPath(QDir::tempPath());
- fullServerName += QLatin1Char('/') + requestedServerName;
+ fullServerName += u'/' + requestedServerName;
}
serverName = requestedServerName;
QByteArray encodedTempPath;
const QByteArray encodedFullServerName = QFile::encodeName(fullServerName);
- QScopedPointer<QTemporaryDir> tempDir;
+ std::optional<QTemporaryDir> tempDir;
- // Check any of the flags
- if (socketOptions & QLocalServer::WorldAccessOption) {
+ if (options & QLocalServer::WorldAccessOption) {
QFileInfo serverNameFileInfo(fullServerName);
- tempDir.reset(new QTemporaryDir(serverNameFileInfo.absolutePath() + QLatin1Char('/')));
+ tempDir.emplace(serverNameFileInfo.absolutePath() + u'/');
if (!tempDir->isValid()) {
- setError(QLatin1String("QLocalServer::listen"));
+ setError("QLocalServer::listen"_L1);
return false;
}
- encodedTempPath = QFile::encodeName(tempDir->path() + QLatin1String("/s"));
+ encodedTempPath = QFile::encodeName(tempDir->path() + "/s"_L1);
}
// create the unix socket
listenSocket = qt_safe_socket(PF_UNIX, SOCK_STREAM, 0);
if (-1 == listenSocket) {
- setError(QLatin1String("QLocalServer::listen"));
+ setError("QLocalServer::listen"_L1);
closeServer();
return false;
}
// Construct the unix address
struct ::sockaddr_un addr;
+
addr.sun_family = PF_UNIX;
- if (sizeof(addr.sun_path) < (uint)encodedFullServerName.size() + 1) {
- setError(QLatin1String("QLocalServer::listen"));
+ ::memset(addr.sun_path, 0, sizeof(addr.sun_path));
+
+ // for abstract namespace add 2 to length, to take into account trailing AND leading null
+ constexpr unsigned int extraCharacters = PlatformSupportsAbstractNamespace ? 2 : 1;
+
+ if (sizeof(addr.sun_path) < static_cast<size_t>(encodedFullServerName.size() + extraCharacters)) {
+ setError("QLocalServer::listen"_L1);
closeServer();
return false;
}
- if (socketOptions & QLocalServer::WorldAccessOption) {
- if (sizeof(addr.sun_path) < (uint)encodedTempPath.size() + 1) {
- setError(QLatin1String("QLocalServer::listen"));
+ QT_SOCKLEN_T addrSize = sizeof(::sockaddr_un);
+ if (options.testFlag(QLocalServer::AbstractNamespaceOption)) {
+ // Abstract socket address is distinguished by the fact
+ // that sun_path[0] is a null byte ('\0')
+ ::memcpy(addr.sun_path + 1, encodedFullServerName.constData(),
+ encodedFullServerName.size() + 1);
+ addrSize = offsetof(::sockaddr_un, sun_path) + encodedFullServerName.size() + 1;
+ } else if (options & QLocalServer::WorldAccessOption) {
+ if (sizeof(addr.sun_path) < static_cast<size_t>(encodedTempPath.size() + 1)) {
+ setError("QLocalServer::listen"_L1);
closeServer();
return false;
}
@@ -135,10 +137,10 @@ bool QLocalServerPrivate::listen(const QString &requestedServerName)
}
// bind
- if(-1 == QT_SOCKET_BIND(listenSocket, (sockaddr *)&addr, sizeof(sockaddr_un))) {
- setError(QLatin1String("QLocalServer::listen"));
+ if (-1 == QT_SOCKET_BIND(listenSocket, (sockaddr *)&addr, addrSize)) {
+ setError("QLocalServer::listen"_L1);
// if address is in use already, just close the socket, but do not delete the file
- if(errno == EADDRINUSE)
+ if (errno == EADDRINUSE)
QT_CLOSE(listenSocket);
// otherwise, close the socket and delete the file
else
@@ -148,35 +150,32 @@ bool QLocalServerPrivate::listen(const QString &requestedServerName)
}
// listen for connections
- if (-1 == qt_safe_listen(listenSocket, 50)) {
- setError(QLatin1String("QLocalServer::listen"));
+ if (-1 == qt_safe_listen(listenSocket, listenBacklog)) {
+ setError("QLocalServer::listen"_L1);
closeServer();
- listenSocket = -1;
- if (error != QAbstractSocket::AddressInUseError)
- QFile::remove(fullServerName);
return false;
}
- if (socketOptions & QLocalServer::WorldAccessOption) {
+ if (options & QLocalServer::WorldAccessOption) {
mode_t mode = 000;
- if (socketOptions & QLocalServer::UserAccessOption)
+ if (options & QLocalServer::UserAccessOption)
mode |= S_IRWXU;
- if (socketOptions & QLocalServer::GroupAccessOption)
+ if (options & QLocalServer::GroupAccessOption)
mode |= S_IRWXG;
- if (socketOptions & QLocalServer::OtherAccessOption)
+ if (options & QLocalServer::OtherAccessOption)
mode |= S_IRWXO;
if (::chmod(encodedTempPath.constData(), mode) == -1) {
- setError(QLatin1String("QLocalServer::listen"));
+ setError("QLocalServer::listen"_L1);
closeServer();
return false;
}
if (::rename(encodedTempPath.constData(), encodedFullServerName.constData()) == -1) {
- setError(QLatin1String("QLocalServer::listen"));
+ setError("QLocalServer::listen"_L1);
closeServer();
return false;
}
@@ -201,28 +200,21 @@ bool QLocalServerPrivate::listen(qintptr socketDescriptor)
::fcntl(listenSocket, F_SETFD, FD_CLOEXEC);
::fcntl(listenSocket, F_SETFL, ::fcntl(listenSocket, F_GETFL) | O_NONBLOCK);
-#ifdef Q_OS_LINUX
+ bool abstractAddress = false;
struct ::sockaddr_un addr;
QT_SOCKLEN_T len = sizeof(addr);
memset(&addr, 0, sizeof(addr));
- if (0 == ::getsockname(listenSocket, (sockaddr *)&addr, &len)) {
- // check for absract sockets
- if (addr.sun_family == PF_UNIX && addr.sun_path[0] == 0) {
- addr.sun_path[0] = '@';
- }
- QString name = QString::fromLatin1(addr.sun_path);
- if (!name.isEmpty()) {
- fullServerName = name;
- serverName = fullServerName.mid(fullServerName.lastIndexOf(QLatin1Char('/')) + 1);
- if (serverName.isEmpty()) {
- serverName = fullServerName;
- }
+ if (::getsockname(socketDescriptor, (sockaddr *)&addr, &len) == 0) {
+#if defined(Q_OS_QNX)
+ if (addr.sun_path[0] == 0 && addr.sun_path[1] == 0)
+ len = SUN_LEN(&addr);
+#endif
+ if (QLocalSocketPrivate::parseSockaddr(addr, len, fullServerName, serverName,
+ abstractAddress)) {
+ QLocalServer::SocketOptions options = socketOptions.value();
+ socketOptions = options.setFlag(QLocalServer::AbstractNamespaceOption, abstractAddress);
}
}
-#else
- serverName.clear();
- fullServerName.clear();
-#endif
Q_ASSERT(!socketNotifier);
socketNotifier = new QSocketNotifier(listenSocket,
@@ -250,8 +242,13 @@ void QLocalServerPrivate::closeServer()
QT_CLOSE(listenSocket);
listenSocket = -1;
- if (!fullServerName.isEmpty())
+ if (!fullServerName.isEmpty()
+ && !optionsForPlatform(socketOptions).testFlag(QLocalServer::AbstractNamespaceOption)) {
QFile::remove(fullServerName);
+ }
+
+ serverName.clear();
+ fullServerName.clear();
}
/*!
@@ -269,8 +266,8 @@ void QLocalServerPrivate::_q_onNewConnection()
::sockaddr_un addr;
QT_SOCKLEN_T length = sizeof(sockaddr_un);
int connectedSocket = qt_safe_accept(listenSocket, (sockaddr *)&addr, &length);
- if(-1 == connectedSocket) {
- setError(QLatin1String("QLocalSocket::activated"));
+ if (-1 == connectedSocket) {
+ setError("QLocalSocket::activated"_L1);
closeServer();
} else {
socketNotifier->setEnabled(pendingConnections.size()
@@ -282,8 +279,7 @@ void QLocalServerPrivate::_q_onNewConnection()
void QLocalServerPrivate::waitForNewConnection(int msec, bool *timedOut)
{
pollfd pfd = qt_make_pollfd(listenSocket, POLLIN);
-
- switch (qt_poll_msecs(&pfd, 1, msec)) {
+ switch (qt_safe_poll(&pfd, 1, QDeadlineTimer(msec))) {
case 0:
if (timedOut)
*timedOut = true;
@@ -299,7 +295,7 @@ void QLocalServerPrivate::waitForNewConnection(int msec, bool *timedOut)
errno = EBADF;
Q_FALLTHROUGH();
case -1:
- setError(QLatin1String("QLocalServer::waitForNewConnection"));
+ setError("QLocalServer::waitForNewConnection"_L1);
closeServer();
break;
}
diff --git a/src/network/socket/qlocalserver_win.cpp b/src/network/socket/qlocalserver_win.cpp
index 6d92ebe93a..bc761b1e8f 100644
--- a/src/network/socket/qlocalserver_win.cpp
+++ b/src/network/socket/qlocalserver_win.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qlocalserver.h"
#include "qlocalserver_p.h"
@@ -53,11 +17,10 @@
// before it is read. Pipewriter is used for write buffering.
#define BUFSIZE 0
-// ###: This should be a property. Should replace the insane 50 on unix as well.
-#define SYSTEM_MAX_PENDING_SOCKETS 8
-
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
bool QLocalServerPrivate::addListener()
{
// The object must not change its address once the
@@ -77,10 +40,10 @@ bool QLocalServerPrivate::addListener()
QByteArray tokenGroupBuffer;
// create security descriptor if access options were specified
- if ((socketOptions & QLocalServer::WorldAccessOption)) {
+ if ((socketOptions.value() & QLocalServer::WorldAccessOption)) {
pSD.reset(new SECURITY_DESCRIPTOR);
if (!InitializeSecurityDescriptor(pSD.data(), SECURITY_DESCRIPTOR_REVISION)) {
- setError(QLatin1String("QLocalServerPrivate::addListener"));
+ setError("QLocalServerPrivate::addListener"_L1);
return false;
}
HANDLE hToken = NULL;
@@ -91,7 +54,7 @@ bool QLocalServerPrivate::addListener()
tokenUserBuffer.fill(0, dwBufferSize);
auto pTokenUser = reinterpret_cast<PTOKEN_USER>(tokenUserBuffer.data());
if (!GetTokenInformation(hToken, TokenUser, pTokenUser, dwBufferSize, &dwBufferSize)) {
- setError(QLatin1String("QLocalServerPrivate::addListener"));
+ setError("QLocalServerPrivate::addListener"_L1);
CloseHandle(hToken);
return false;
}
@@ -101,7 +64,7 @@ bool QLocalServerPrivate::addListener()
tokenGroupBuffer.fill(0, dwBufferSize);
auto pTokenGroup = reinterpret_cast<PTOKEN_PRIMARY_GROUP>(tokenGroupBuffer.data());
if (!GetTokenInformation(hToken, TokenPrimaryGroup, pTokenGroup, dwBufferSize, &dwBufferSize)) {
- setError(QLatin1String("QLocalServerPrivate::addListener"));
+ setError("QLocalServerPrivate::addListener"_L1);
CloseHandle(hToken);
return false;
}
@@ -128,7 +91,7 @@ bool QLocalServerPrivate::addListener()
if (!AllocateAndInitializeSid(&WorldAuth, 1, SECURITY_WORLD_RID,
0, 0, 0, 0, 0, 0, 0,
&worldSID)) {
- setError(QLatin1String("QLocalServerPrivate::addListener"));
+ setError("QLocalServerPrivate::addListener"_L1);
return false;
}
@@ -143,23 +106,23 @@ bool QLocalServerPrivate::addListener()
auto acl = reinterpret_cast<PACL>(aclBuffer.data());
InitializeAcl(acl, aclSize, ACL_REVISION_DS);
- if (socketOptions & QLocalServer::UserAccessOption) {
+ if (socketOptions.value() & QLocalServer::UserAccessOption) {
if (!AddAccessAllowedAce(acl, ACL_REVISION, FILE_ALL_ACCESS, pTokenUser->User.Sid)) {
- setError(QLatin1String("QLocalServerPrivate::addListener"));
+ setError("QLocalServerPrivate::addListener"_L1);
FreeSid(worldSID);
return false;
}
}
- if (socketOptions & QLocalServer::GroupAccessOption) {
+ if (socketOptions.value() & QLocalServer::GroupAccessOption) {
if (!AddAccessAllowedAce(acl, ACL_REVISION, FILE_ALL_ACCESS, pTokenGroup->PrimaryGroup)) {
- setError(QLatin1String("QLocalServerPrivate::addListener"));
+ setError("QLocalServerPrivate::addListener"_L1);
FreeSid(worldSID);
return false;
}
}
- if (socketOptions & QLocalServer::OtherAccessOption) {
+ if (socketOptions.value() & QLocalServer::OtherAccessOption) {
if (!AddAccessAllowedAce(acl, ACL_REVISION, FILE_ALL_ACCESS, worldSID)) {
- setError(QLatin1String("QLocalServerPrivate::addListener"));
+ setError("QLocalServerPrivate::addListener"_L1);
FreeSid(worldSID);
return false;
}
@@ -167,7 +130,7 @@ bool QLocalServerPrivate::addListener()
SetSecurityDescriptorOwner(pSD.data(), pTokenUser->User.Sid, FALSE);
SetSecurityDescriptorGroup(pSD.data(), pTokenGroup->PrimaryGroup, FALSE);
if (!SetSecurityDescriptorDacl(pSD.data(), TRUE, acl, FALSE)) {
- setError(QLatin1String("QLocalServerPrivate::addListener"));
+ setError("QLocalServerPrivate::addListener"_L1);
FreeSid(worldSID);
return false;
}
@@ -188,7 +151,7 @@ bool QLocalServerPrivate::addListener()
&sa);
if (listener->handle == INVALID_HANDLE_VALUE) {
- setError(QLatin1String("QLocalServerPrivate::addListener"));
+ setError("QLocalServerPrivate::addListener"_L1);
listeners.pop_back();
return false;
}
@@ -211,7 +174,7 @@ bool QLocalServerPrivate::addListener()
break;
default:
CloseHandle(listener->handle);
- setError(QLatin1String("QLocalServerPrivate::addListener"));
+ setError("QLocalServerPrivate::addListener"_L1);
listeners.pop_back();
return false;
}
@@ -243,7 +206,7 @@ bool QLocalServerPrivate::listen(const QString &name)
{
Q_Q(QLocalServer);
- const QLatin1String pipePath("\\\\.\\pipe\\");
+ const auto pipePath = "\\\\.\\pipe\\"_L1;
if (name.startsWith(pipePath))
fullServerName = name;
else
@@ -256,7 +219,7 @@ bool QLocalServerPrivate::listen(const QString &name)
connectionEventNotifier = new QWinEventNotifier(eventHandle , q);
q->connect(connectionEventNotifier, SIGNAL(activated(HANDLE)), q, SLOT(_q_onNewConnection()));
- for (int i = 0; i < SYSTEM_MAX_PENDING_SOCKETS; ++i)
+ for (int i = 0; i < listenBacklog; ++i)
if (!addListener())
return false;
@@ -303,7 +266,7 @@ void QLocalServerPrivate::_q_onNewConnection()
} else {
if (GetLastError() != ERROR_IO_INCOMPLETE) {
q->close();
- setError(QLatin1String("QLocalServerPrivate::_q_onNewConnection"));
+ setError("QLocalServerPrivate::_q_onNewConnection"_L1);
return;
}
diff --git a/src/network/socket/qlocalsocket.cpp b/src/network/socket/qlocalsocket.cpp
index 19c0b2389e..dff7e42849 100644
--- a/src/network/socket/qlocalsocket.cpp
+++ b/src/network/socket/qlocalsocket.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtNetwork/private/qtnetworkglobal_p.h>
@@ -66,6 +30,21 @@ QT_BEGIN_NAMESPACE
*/
/*!
+ \enum QLocalSocket::SocketOption
+ \since 6.2
+ This enum describes the possible options that can be used to connect to
+ a server. Currently, on Linux and Android it is used for specifying
+ connection to a server listening to a socket bound to an abstract address.
+
+ \value NoOptions No options have been set.
+ \value AbstractNamespaceOption
+ The socket will try to connect to an abstract address. This flag is specific
+ to Linux and Android. On other platforms is ignored.
+
+ \sa socketOptions
+*/
+
+/*!
\fn void QLocalSocket::connectToServer(OpenMode openMode)
\since 5.1
@@ -90,7 +69,7 @@ QT_BEGIN_NAMESPACE
Note that unlike in most other QIODevice subclasses, open() may not open the device directly.
The function return false if the socket was already connected or if the server to connect
to was not defined and true in any other case. The connected() or errorOccurred() signals will be
- emitted once the device is actualy open (or the connection failed).
+ emitted once the device is actually open (or the connection failed).
See connectToServer() for more details.
*/
@@ -132,8 +111,7 @@ QT_BEGIN_NAMESPACE
\list
\li On Windows, the returned value is a
- \l{https://msdn.microsoft.com/en-us/library/windows/desktop/ms740522(v=vs.85).aspx}
- {Winsock 2 Socket Handle}.
+ \l{Winsock 2 Socket Handle}.
\li On INTEGRITY, the returned value is the
QTcpSocket socket descriptor and the type is defined by
@@ -152,6 +130,11 @@ QT_BEGIN_NAMESPACE
*/
/*!
+ \fn qint64 QLocalSocket::readLineData(char *data, qint64 maxSize)
+ \reimp
+*/
+
+/*!
\fn qint64 QLocalSocket::skipData(qint64 maxSize)
\reimp
*/
@@ -188,7 +171,14 @@ QT_BEGIN_NAMESPACE
/*!
\fn void QLocalSocket::close()
- \reimp
+
+ Closes the I/O device for the socket and calls disconnectFromServer()
+ to close the socket's connection.
+
+ See QIODevice::close() for a description of the actions that occur when an I/O
+ device is closed.
+
+ \sa abort()
*/
/*!
@@ -219,7 +209,7 @@ QT_BEGIN_NAMESPACE
Attempts to close the socket. If there is pending data waiting to be
written, QLocalSocket will enter ClosingState and wait until all data
has been written. Eventually, it will enter UnconnectedState and emit
- the disconnectedFromServer() signal.
+ the disconnected() signal.
\sa connectToServer()
*/
@@ -369,6 +359,8 @@ QLocalSocket::QLocalSocket(QObject * parent)
: QIODevice(*new QLocalSocketPrivate, parent)
{
Q_D(QLocalSocket);
+
+ d->readBufferChunkSize = 0; // force QIODevice unbuffered mode
d->init();
}
@@ -377,7 +369,7 @@ QLocalSocket::QLocalSocket(QObject * parent)
*/
QLocalSocket::~QLocalSocket()
{
- QLocalSocket::close();
+ abort();
#if !defined(Q_OS_WIN) && !defined(QT_LOCALSOCKET_TCP)
Q_D(QLocalSocket);
d->unixSocket.setParent(nullptr);
@@ -439,6 +431,37 @@ QString QLocalSocket::serverName() const
}
/*!
+ \property QLocalSocket::socketOptions
+ \since 6.2
+ \brief the socket options.
+
+ Options must be set while the socket is in \l{UnconnectedState} state.
+
+ \sa connectToServer()
+ */
+QLocalSocket::SocketOptions QLocalSocket::socketOptions() const
+{
+ Q_D(const QLocalSocket);
+ return d->socketOptions;
+}
+
+void QLocalSocket::setSocketOptions(QLocalSocket::SocketOptions option)
+{
+ Q_D(QLocalSocket);
+ if (d->state != UnconnectedState) {
+ qWarning("QLocalSocket::setSocketOptions() called while not in unconnected state");
+ return;
+ }
+ d->socketOptions = option;
+}
+
+QBindable<QLocalSocket::SocketOptions> QLocalSocket::bindableSocketOptions()
+{
+ Q_D(QLocalSocket);
+ return &d->socketOptions;
+}
+
+/*!
Returns the server path that the socket is connected to.
\note The return value of this function is platform specific.
diff --git a/src/network/socket/qlocalsocket.h b/src/network/socket/qlocalsocket.h
index 22763cb339..2bd9689a05 100644
--- a/src/network/socket/qlocalsocket.h
+++ b/src/network/socket/qlocalsocket.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QLOCALSOCKET_H
#define QLOCALSOCKET_H
@@ -44,6 +8,10 @@
#include <QtCore/qiodevice.h>
#include <QtNetwork/qabstractsocket.h>
+#ifndef QT_NO_DEBUG_STREAM
+#include <QtCore/qdebug.h>
+#endif
+
QT_REQUIRE_CONFIG(localserver);
QT_BEGIN_NAMESPACE
@@ -54,6 +22,8 @@ class Q_NETWORK_EXPORT QLocalSocket : public QIODevice
{
Q_OBJECT
Q_DECLARE_PRIVATE(QLocalSocket)
+ Q_PROPERTY(SocketOptions socketOptions READ socketOptions WRITE setSocketOptions
+ BINDABLE bindableSocketOptions)
public:
enum LocalSocketError
@@ -79,6 +49,13 @@ public:
ClosingState = QAbstractSocket::ClosingState
};
+ enum SocketOption {
+ NoOptions = 0x00,
+ AbstractNamespaceOption = 0x01
+ };
+ Q_DECLARE_FLAGS(SocketOptions, SocketOption)
+ Q_FLAG(SocketOptions)
+
QLocalSocket(QObject *parent = nullptr);
~QLocalSocket();
@@ -108,6 +85,10 @@ public:
OpenMode openMode = ReadWrite);
qintptr socketDescriptor() const;
+ void setSocketOptions(SocketOptions option);
+ SocketOptions socketOptions() const;
+ QBindable<SocketOptions> bindableSocketOptions();
+
LocalSocketState state() const;
bool waitForBytesWritten(int msecs = 30000) override;
bool waitForConnected(int msecs = 30000);
@@ -122,6 +103,7 @@ Q_SIGNALS:
protected:
virtual qint64 readData(char*, qint64) override;
+ qint64 readLineData(char *data, qint64 maxSize) override;
qint64 skipData(qint64 maxSize) override;
virtual qint64 writeData(const char*, qint64) override;
@@ -131,7 +113,6 @@ private:
Q_PRIVATE_SLOT(d_func(), void _q_stateChanged(QAbstractSocket::SocketState))
Q_PRIVATE_SLOT(d_func(), void _q_errorOccurred(QAbstractSocket::SocketError))
#elif defined(Q_OS_WIN)
- Q_PRIVATE_SLOT(d_func(), void _q_canWrite())
Q_PRIVATE_SLOT(d_func(), void _q_pipeClosed())
Q_PRIVATE_SLOT(d_func(), void _q_winError(ulong, const QString &))
#else
@@ -143,11 +124,12 @@ private:
};
#ifndef QT_NO_DEBUG_STREAM
-#include <QtCore/qdebug.h>
Q_NETWORK_EXPORT QDebug operator<<(QDebug, QLocalSocket::LocalSocketError);
Q_NETWORK_EXPORT QDebug operator<<(QDebug, QLocalSocket::LocalSocketState);
#endif
+Q_DECLARE_OPERATORS_FOR_FLAGS(QLocalSocket::SocketOptions)
+
QT_END_NAMESPACE
#endif // QLOCALSOCKET_H
diff --git a/src/network/socket/qlocalsocket_p.h b/src/network/socket/qlocalsocket_p.h
index 7eff502607..82446161c7 100644
--- a/src/network/socket/qlocalsocket_p.h
+++ b/src/network/socket/qlocalsocket_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QLOCALSOCKET_P_H
#define QLOCALSOCKET_P_H
@@ -73,9 +37,12 @@ QT_REQUIRE_CONFIG(localserver);
# include <errno.h>
#endif
+struct sockaddr_un;
+
QT_BEGIN_NAMESPACE
#if !defined(Q_OS_WIN) || defined(QT_LOCALSOCKET_TCP)
+
class QLocalUnixSocket : public QTcpSocket
{
@@ -113,9 +80,9 @@ public:
class QLocalSocketPrivate : public QIODevicePrivate
{
+public:
Q_DECLARE_PUBLIC(QLocalSocket)
-public:
QLocalSocketPrivate();
void init();
@@ -129,10 +96,12 @@ public:
void _q_errorOccurred(QAbstractSocket::SocketError newError);
#elif defined(Q_OS_WIN)
~QLocalSocketPrivate();
- void destroyPipeHandles();
- void _q_canWrite();
+ qint64 pipeWriterBytesToWrite() const;
+ void _q_canRead();
+ void _q_bytesWritten(qint64 bytes);
void _q_pipeClosed();
void _q_winError(ulong windowsError, const QString &function);
+ void _q_writeFailed();
HANDLE handle;
QWindowsPipeWriter *pipeWriter;
QWindowsPipeReader *pipeReader;
@@ -146,16 +115,24 @@ public:
void _q_connectToSocket();
void _q_abortConnectionAttempt();
void cancelDelayedConnect();
+ void describeSocket(qintptr socketDescriptor);
+ static bool parseSockaddr(const sockaddr_un &addr, uint len,
+ QString &fullServerName, QString &serverName, bool &abstractNamespace);
QSocketNotifier *delayConnect;
QTimer *connectTimer;
- int connectingSocket;
QString connectingName;
+ int connectingSocket;
QIODevice::OpenMode connectingOpenMode;
#endif
-
+ QLocalSocket::LocalSocketState state;
QString serverName;
QString fullServerName;
- QLocalSocket::LocalSocketState state;
+#if defined(Q_OS_WIN) && !defined(QT_LOCALSOCKET_TCP)
+ bool emittedReadyRead;
+ bool emittedBytesWritten;
+#endif
+
+ Q_OBJECT_BINDABLE_PROPERTY(QLocalSocketPrivate, QLocalSocket::SocketOptions, socketOptions)
};
QT_END_NAMESPACE
diff --git a/src/network/socket/qlocalsocket_tcp.cpp b/src/network/socket/qlocalsocket_tcp.cpp
index 2f0179f40a..c7870b3dff 100644
--- a/src/network/socket/qlocalsocket_tcp.cpp
+++ b/src/network/socket/qlocalsocket_tcp.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qlocalsocket.h"
#include "qlocalsocket_p.h"
@@ -47,6 +11,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
QLocalSocketPrivate::QLocalSocketPrivate() : QIODevicePrivate(),
tcpSocket(0),
ownsTcpSocket(true),
@@ -68,7 +34,6 @@ void QLocalSocketPrivate::setSocket(QLocalUnixSocket* socket)
Q_Q(QLocalSocket);
// QIODevice signals
- q->connect(tcpSocket, SIGNAL(aboutToClose()), q, SIGNAL(aboutToClose()));
q->connect(tcpSocket, SIGNAL(bytesWritten(qint64)),
q, SIGNAL(bytesWritten(qint64)));
q->connect(tcpSocket, SIGNAL(readyRead()), q, SIGNAL(readyRead()));
@@ -86,7 +51,7 @@ void QLocalSocketPrivate::setSocket(QLocalUnixSocket* socket)
void QLocalSocketPrivate::_q_errorOccurred(QAbstractSocket::SocketError socketError)
{
Q_Q(QLocalSocket);
- QString function = QLatin1String("QLocalSocket");
+ QString function = "QLocalSocket"_L1;
QLocalSocket::LocalSocketError error = (QLocalSocket::LocalSocketError)socketError;
QString errorString = generateErrorString(error, function);
q->setErrorString(errorString);
@@ -226,23 +191,21 @@ void QLocalSocket::connectToServer(OpenMode openMode)
emit stateChanged(d->state);
if (d->serverName.isEmpty()) {
- d->setErrorAndEmit(ServerNotFoundError,
- QLatin1String("QLocalSocket::connectToServer"));
+ d->setErrorAndEmit(ServerNotFoundError, "QLocalSocket::connectToServer"_L1);
return;
}
- const QLatin1String prefix("QLocalServer/");
+ const auto prefix = "QLocalServer/"_L1;
if (d->serverName.startsWith(prefix))
d->fullServerName = d->serverName;
else
d->fullServerName = prefix + d->serverName;
- QSettings settings(QLatin1String("QtProject"), QLatin1String("Qt"));
+ QSettings settings("QtProject"_L1, "Qt"_L1);
bool ok;
const quint16 port = settings.value(d->fullServerName).toUInt(&ok);
if (!ok) {
- d->setErrorAndEmit(ServerNotFoundError,
- QLatin1String("QLocalSocket::connectToServer"));
+ d->setErrorAndEmit(ServerNotFoundError, "QLocalSocket::connectToServer"_L1);
return;
}
QIODevice::open(openMode);
@@ -301,6 +264,16 @@ qint64 QLocalSocket::readData(char *data, qint64 c)
return d->tcpSocket->read(data, c);
}
+qint64 QLocalSocket::readLineData(char *data, qint64 maxSize)
+{
+ if (!maxSize)
+ return 0;
+
+ // QIODevice::readLine() reserves space for the trailing '\0' byte,
+ // so we must read 'maxSize + 1' bytes.
+ return d_func()->tcpSocket->readLine(data, maxSize + 1);
+}
+
qint64 QLocalSocket::skipData(qint64 maxSize)
{
return d_func()->tcpSocket->skip(maxSize);
@@ -316,6 +289,7 @@ void QLocalSocket::abort()
{
Q_D(QLocalSocket);
d->tcpSocket->abort();
+ close();
}
qint64 QLocalSocket::bytesAvailable() const
@@ -339,10 +313,11 @@ bool QLocalSocket::canReadLine() const
void QLocalSocket::close()
{
Q_D(QLocalSocket);
+
+ QIODevice::close();
d->tcpSocket->close();
d->serverName.clear();
d->fullServerName.clear();
- QIODevice::close();
}
bool QLocalSocket::waitForBytesWritten(int msecs)
diff --git a/src/network/socket/qlocalsocket_unix.cpp b/src/network/socket/qlocalsocket_unix.cpp
index 6fd17a6213..af0dc988af 100644
--- a/src/network/socket/qlocalsocket_unix.cpp
+++ b/src/network/socket/qlocalsocket_unix.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qlocalsocket.h"
#include "qlocalsocket_p.h"
@@ -49,22 +13,51 @@
#include <errno.h>
#include <qdir.h>
+#include <qdeadlinetimer.h>
#include <qdebug.h>
-#include <qelapsedtimer.h>
+#include <qstringconverter.h>
#ifdef Q_OS_VXWORKS
# include <selectLib.h>
#endif
+using namespace std::chrono_literals;
+
#define QT_CONNECT_TIMEOUT 30000
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
+namespace {
+// determine the full server path
+static QString pathNameForConnection(const QString &connectingName,
+ QLocalSocket::SocketOptions options)
+{
+ if (options.testFlag(QLocalSocket::AbstractNamespaceOption)
+ || connectingName.startsWith(u'/')) {
+ return connectingName;
+ }
+
+ return QDir::tempPath() + u'/' + connectingName;
+}
+
+static QLocalSocket::SocketOptions optionsForPlatform(QLocalSocket::SocketOptions srcOptions)
+{
+ // For OS that does not support abstract namespace the AbstractNamespaceOption
+ // option is cleared.
+ if (!PlatformSupportsAbstractNamespace)
+ return QLocalSocket::NoOptions;
+ return srcOptions;
+}
+}
+
QLocalSocketPrivate::QLocalSocketPrivate() : QIODevicePrivate(),
delayConnect(nullptr),
connectTimer(nullptr),
connectingSocket(-1),
- state(QLocalSocket::UnconnectedState)
+ state(QLocalSocket::UnconnectedState),
+ socketOptions(QLocalSocket::NoOptions)
{
}
@@ -72,7 +65,6 @@ void QLocalSocketPrivate::init()
{
Q_Q(QLocalSocket);
// QIODevice signals
- q->connect(&unixSocket, SIGNAL(aboutToClose()), q, SIGNAL(aboutToClose()));
q->connect(&unixSocket, SIGNAL(bytesWritten(qint64)),
q, SIGNAL(bytesWritten(qint64)));
q->connect(&unixSocket, SIGNAL(readyRead()), q, SIGNAL(readyRead()));
@@ -90,7 +82,7 @@ void QLocalSocketPrivate::init()
void QLocalSocketPrivate::_q_errorOccurred(QAbstractSocket::SocketError socketError)
{
Q_Q(QLocalSocket);
- QString function = QLatin1String("QLocalSocket");
+ QString function = "QLocalSocket"_L1;
QLocalSocket::LocalSocketError error = (QLocalSocket::LocalSocketError)socketError;
QString errorString = generateErrorString(error, function);
q->setErrorString(errorString);
@@ -220,7 +212,7 @@ void QLocalSocket::connectToServer(OpenMode openMode)
{
Q_D(QLocalSocket);
if (state() == ConnectedState || state() == ConnectingState) {
- QString errorString = d->generateErrorString(QLocalSocket::OperationError, QLatin1String("QLocalSocket::connectToserver"));
+ QString errorString = d->generateErrorString(QLocalSocket::OperationError, "QLocalSocket::connectToserver"_L1);
setErrorString(errorString);
emit errorOccurred(QLocalSocket::OperationError);
return;
@@ -232,15 +224,13 @@ void QLocalSocket::connectToServer(OpenMode openMode)
emit stateChanged(d->state);
if (d->serverName.isEmpty()) {
- d->setErrorAndEmit(ServerNotFoundError,
- QLatin1String("QLocalSocket::connectToServer"));
+ d->setErrorAndEmit(ServerNotFoundError, "QLocalSocket::connectToServer"_L1);
return;
}
// create the socket
if (-1 == (d->connectingSocket = qt_safe_socket(PF_UNIX, SOCK_STREAM, 0, O_NONBLOCK))) {
- d->setErrorAndEmit(UnsupportedSocketOperationError,
- QLatin1String("QLocalSocket::connectToServer"));
+ d->setErrorAndEmit(UnsupportedSocketOperationError, "QLocalSocket::connectToServer"_L1);
return;
}
@@ -261,28 +251,34 @@ void QLocalSocket::connectToServer(OpenMode openMode)
void QLocalSocketPrivate::_q_connectToSocket()
{
Q_Q(QLocalSocket);
- QString connectingPathName;
-
- // determine the full server path
- if (connectingName.startsWith(QLatin1Char('/'))) {
- connectingPathName = connectingName;
- } else {
- connectingPathName = QDir::tempPath();
- connectingPathName += QLatin1Char('/') + connectingName;
- }
+ QLocalSocket::SocketOptions options = optionsForPlatform(socketOptions);
+ const QString connectingPathName = pathNameForConnection(connectingName, options);
const QByteArray encodedConnectingPathName = QFile::encodeName(connectingPathName);
- struct sockaddr_un name;
- name.sun_family = PF_UNIX;
- if (sizeof(name.sun_path) < (uint)encodedConnectingPathName.size() + 1) {
- QString function = QLatin1String("QLocalSocket::connectToServer");
+ struct ::sockaddr_un addr;
+ addr.sun_family = PF_UNIX;
+ memset(addr.sun_path, 0, sizeof(addr.sun_path));
+
+ // for abstract socket add 2 to length, to take into account trailing AND leading null
+ constexpr unsigned int extraCharacters = PlatformSupportsAbstractNamespace ? 2 : 1;
+
+ if (sizeof(addr.sun_path) < static_cast<size_t>(encodedConnectingPathName.size() + extraCharacters)) {
+ QString function = "QLocalSocket::connectToServer"_L1;
setErrorAndEmit(QLocalSocket::ServerNotFoundError, function);
return;
}
- ::memcpy(name.sun_path, encodedConnectingPathName.constData(),
- encodedConnectingPathName.size() + 1);
- if (-1 == qt_safe_connect(connectingSocket, (struct sockaddr *)&name, sizeof(name))) {
- QString function = QLatin1String("QLocalSocket::connectToServer");
+
+ QT_SOCKLEN_T addrSize = sizeof(::sockaddr_un);
+ if (options.testFlag(QLocalSocket::AbstractNamespaceOption)) {
+ ::memcpy(addr.sun_path + 1, encodedConnectingPathName.constData(),
+ encodedConnectingPathName.size() + 1);
+ addrSize = offsetof(::sockaddr_un, sun_path) + encodedConnectingPathName.size() + 1;
+ } else {
+ ::memcpy(addr.sun_path, encodedConnectingPathName.constData(),
+ encodedConnectingPathName.size() + 1);
+ }
+ if (-1 == qt_safe_connect(connectingSocket, (struct sockaddr *)&addr, addrSize)) {
+ QString function = "QLocalSocket::connectToServer"_L1;
switch (errno)
{
case EINVAL:
@@ -327,10 +323,10 @@ void QLocalSocketPrivate::_q_connectToSocket()
fullServerName = connectingPathName;
if (unixSocket.setSocketDescriptor(connectingSocket,
QAbstractSocket::ConnectedState, connectingOpenMode)) {
- q->QIODevice::open(connectingOpenMode | QIODevice::Unbuffered);
+ q->QIODevice::open(connectingOpenMode);
q->emit connected();
} else {
- QString function = QLatin1String("QLocalSocket::connectToServer");
+ QString function = "QLocalSocket::connectToServer"_L1;
setErrorAndEmit(QLocalSocket::UnknownSocketError, function);
}
connectingSocket = -1;
@@ -359,10 +355,69 @@ bool QLocalSocket::setSocketDescriptor(qintptr socketDescriptor,
}
QIODevice::open(openMode);
d->state = socketState;
+ d->describeSocket(socketDescriptor);
return d->unixSocket.setSocketDescriptor(socketDescriptor,
newSocketState, openMode);
}
+void QLocalSocketPrivate::describeSocket(qintptr socketDescriptor)
+{
+ bool abstractAddress = false;
+
+ struct ::sockaddr_un addr;
+ QT_SOCKLEN_T len = sizeof(addr);
+ memset(&addr, 0, sizeof(addr));
+ const int getpeernameStatus = ::getpeername(socketDescriptor, (sockaddr *)&addr, &len);
+ if (getpeernameStatus != 0 || len == offsetof(sockaddr_un, sun_path)) {
+ // this is the case when we call it from QLocalServer, then there is no peername
+ len = sizeof(addr);
+ if (::getsockname(socketDescriptor, (sockaddr *)&addr, &len) != 0)
+ return;
+ }
+ if (parseSockaddr(addr, static_cast<uint>(len), fullServerName, serverName, abstractAddress)) {
+ QLocalSocket::SocketOptions options = socketOptions.value();
+ socketOptions = options.setFlag(QLocalSocket::AbstractNamespaceOption, abstractAddress);
+ }
+}
+
+bool QLocalSocketPrivate::parseSockaddr(const struct ::sockaddr_un &addr,
+ uint len,
+ QString &fullServerName,
+ QString &serverName,
+ bool &abstractNamespace)
+{
+ if (len <= offsetof(::sockaddr_un, sun_path))
+ return false;
+ len -= offsetof(::sockaddr_un, sun_path);
+ // check for abstract socket address
+ abstractNamespace = PlatformSupportsAbstractNamespace
+ && (addr.sun_family == PF_UNIX && addr.sun_path[0] == 0);
+ QStringDecoder toUtf16(QStringDecoder::System, QStringDecoder::Flag::Stateless);
+ // An abstract socket address can be arbitrary binary. To properly handle such a case,
+ // we'd have to add new access functions for this very specific case. Instead, we just
+ // attempt to decode it according to OS text encoding. If it fails we ignore the result.
+ QByteArrayView textData(addr.sun_path + (abstractNamespace ? 1 : 0),
+ len - (abstractNamespace ? 1 : 0));
+ QString name = toUtf16(textData);
+ if (!name.isEmpty() && !toUtf16.hasError()) {
+ //conversion encodes the trailing zeros. So, in case of non-abstract namespace we
+ //chop them off as \0 character is not allowed in filenames
+ if (!abstractNamespace && (name.at(name.size() - 1) == QChar::fromLatin1('\0'))) {
+ int truncPos = name.size() - 1;
+ while (truncPos > 0 && name.at(truncPos - 1) == QChar::fromLatin1('\0'))
+ truncPos--;
+ name.truncate(truncPos);
+ }
+ fullServerName = name;
+ serverName = abstractNamespace
+ ? name
+ : fullServerName.mid(fullServerName.lastIndexOf(u'/') + 1);
+ if (serverName.isEmpty())
+ serverName = fullServerName;
+ }
+ return true;
+}
+
void QLocalSocketPrivate::_q_abortConnectionAttempt()
{
Q_Q(QLocalSocket);
@@ -393,6 +448,16 @@ qint64 QLocalSocket::readData(char *data, qint64 c)
return d->unixSocket.read(data, c);
}
+qint64 QLocalSocket::readLineData(char *data, qint64 maxSize)
+{
+ if (!maxSize)
+ return 0;
+
+ // QIODevice::readLine() reserves space for the trailing '\0' byte,
+ // so we must read 'maxSize + 1' bytes.
+ return d_func()->unixSocket.readLine(data, maxSize + 1);
+}
+
qint64 QLocalSocket::skipData(qint64 maxSize)
{
return d_func()->unixSocket.skip(maxSize);
@@ -408,6 +473,7 @@ void QLocalSocket::abort()
{
Q_D(QLocalSocket);
d->unixSocket.abort();
+ close();
}
qint64 QLocalSocket::bytesAvailable() const
@@ -431,6 +497,8 @@ bool QLocalSocket::canReadLine() const
void QLocalSocket::close()
{
Q_D(QLocalSocket);
+
+ QIODevice::close();
d->unixSocket.close();
d->cancelDelayedConnect();
if (d->connectingSocket != -1)
@@ -440,7 +508,6 @@ void QLocalSocket::close()
d->connectingOpenMode = { };
d->serverName.clear();
d->fullServerName.clear();
- QIODevice::close();
}
bool QLocalSocket::waitForBytesWritten(int msecs)
@@ -519,21 +586,20 @@ bool QLocalSocket::waitForConnected(int msec)
if (state() != ConnectingState)
return (state() == ConnectedState);
- QElapsedTimer timer;
- timer.start();
-
pollfd pfd = qt_make_pollfd(d->connectingSocket, POLLIN);
- do {
- const int timeout = (msec > 0) ? qMax(msec - timer.elapsed(), Q_INT64_C(0)) : msec;
- const int result = qt_poll_msecs(&pfd, 1, timeout);
+ QDeadlineTimer deadline{msec};
+ auto remainingTime = deadline.remainingTimeAsDuration();
+ do {
+ const int result = qt_safe_poll(&pfd, 1, deadline);
if (result == -1)
d->setErrorAndEmit(QLocalSocket::UnknownSocketError,
- QLatin1String("QLocalSocket::waitForConnected"));
+ "QLocalSocket::waitForConnected"_L1);
else if (result > 0)
d->_q_connectToSocket();
- } while (state() == ConnectingState && !timer.hasExpired(msec));
+ } while (state() == ConnectingState
+ && (remainingTime = deadline.remainingTimeAsDuration()) > 0ns);
return (state() == ConnectedState);
}
diff --git a/src/network/socket/qlocalsocket_win.cpp b/src/network/socket/qlocalsocket_win.cpp
index e174952b96..b3f3f9002a 100644
--- a/src/network/socket/qlocalsocket_win.cpp
+++ b/src/network/socket/qlocalsocket_win.cpp
@@ -1,51 +1,86 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qlocalsocket_p.h"
+#include <qscopedvaluerollback.h>
+#include <qdeadlinetimer.h>
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
+namespace {
+struct QSocketPoller
+{
+ QSocketPoller(const QLocalSocketPrivate &socket);
+
+ qint64 getRemainingTime(const QDeadlineTimer &deadline) const;
+ bool poll(const QDeadlineTimer &deadline);
+
+ enum { maxHandles = 2 };
+ HANDLE handles[maxHandles];
+ DWORD handleCount = 0;
+ bool waitForClose = false;
+ bool writePending = false;
+};
+
+QSocketPoller::QSocketPoller(const QLocalSocketPrivate &socket)
+{
+ if (socket.pipeWriter && socket.pipeWriter->isWriteOperationActive()) {
+ handles[handleCount++] = socket.pipeWriter->syncEvent();
+ writePending = true;
+ }
+ if (socket.pipeReader->isReadOperationActive())
+ handles[handleCount++] = socket.pipeReader->syncEvent();
+ else
+ waitForClose = true;
+}
+
+qint64 QSocketPoller::getRemainingTime(const QDeadlineTimer &deadline) const
+{
+ const qint64 sleepTime = 10;
+ qint64 remainingTime = deadline.remainingTime();
+ if (waitForClose && (remainingTime > sleepTime || remainingTime == -1))
+ return sleepTime;
+
+ return remainingTime;
+}
+
+/*!
+ \internal
+
+ Waits until new data is available for reading or write operation
+ completes. Returns \c true, if we need to check pipe workers;
+ otherwise it returns \c false (if an error occurred or the operation
+ timed out).
+
+ \note If the read operation is inactive, it succeeds after
+ a short wait, allowing the caller to check the state of the socket.
+*/
+bool QSocketPoller::poll(const QDeadlineTimer &deadline)
+{
+ Q_ASSERT(handleCount != 0);
+ QDeadlineTimer timer(getRemainingTime(deadline));
+ DWORD waitRet;
+
+ do {
+ waitRet = WaitForMultipleObjectsEx(handleCount, handles, FALSE,
+ timer.remainingTime(), TRUE);
+ } while (waitRet == WAIT_IO_COMPLETION);
+
+ if (waitRet == WAIT_TIMEOUT)
+ return waitForClose || !deadline.hasExpired();
+
+ return waitRet - WAIT_OBJECT_0 < handleCount;
+}
+} // anonymous namespace
+
void QLocalSocketPrivate::init()
{
Q_Q(QLocalSocket);
pipeReader = new QWindowsPipeReader(q);
- q->connect(pipeReader, SIGNAL(readyRead()), SIGNAL(readyRead()));
+ QObjectPrivate::connect(pipeReader, &QWindowsPipeReader::readyRead,
+ this, &QLocalSocketPrivate::_q_canRead);
q->connect(pipeReader, SIGNAL(pipeClosed()), SLOT(_q_pipeClosed()), Qt::QueuedConnection);
q->connect(pipeReader, SIGNAL(winError(ulong,QString)), SLOT(_q_winError(ulong,QString)));
}
@@ -99,22 +134,17 @@ QLocalSocketPrivate::QLocalSocketPrivate() : QIODevicePrivate(),
pipeWriter(0),
pipeReader(0),
error(QLocalSocket::UnknownSocketError),
- state(QLocalSocket::UnconnectedState)
+ state(QLocalSocket::UnconnectedState),
+ emittedReadyRead(false),
+ emittedBytesWritten(false)
{
- writeBufferChunkSize = QIODEVICE_BUFFERSIZE;
}
QLocalSocketPrivate::~QLocalSocketPrivate()
{
- destroyPipeHandles();
-}
-
-void QLocalSocketPrivate::destroyPipeHandles()
-{
- if (handle != INVALID_HANDLE_VALUE) {
- DisconnectNamedPipe(handle);
- CloseHandle(handle);
- }
+ Q_ASSERT(state == QLocalSocket::UnconnectedState);
+ Q_ASSERT(handle == INVALID_HANDLE_VALUE);
+ Q_ASSERT(pipeWriter == nullptr);
}
void QLocalSocket::connectToServer(OpenMode openMode)
@@ -133,14 +163,14 @@ void QLocalSocket::connectToServer(OpenMode openMode)
emit stateChanged(d->state);
if (d->serverName.isEmpty()) {
d->error = ServerNotFoundError;
- d->errorString = tr("%1: Invalid name").arg(QLatin1String("QLocalSocket::connectToServer"));
+ d->errorString = tr("%1: Invalid name").arg("QLocalSocket::connectToServer"_L1);
d->state = UnconnectedState;
emit errorOccurred(d->error);
emit stateChanged(d->state);
return;
}
- const QLatin1String pipePath("\\\\.\\pipe\\");
+ const auto pipePath = "\\\\.\\pipe\\"_L1;
if (d->serverName.startsWith(pipePath))
d->fullServerName = d->serverName;
else
@@ -173,7 +203,7 @@ void QLocalSocket::connectToServer(OpenMode openMode)
if (localSocket == INVALID_HANDLE_VALUE) {
const DWORD winError = GetLastError();
- d->_q_winError(winError, QLatin1String("QLocalSocket::connectToServer"));
+ d->_q_winError(winError, "QLocalSocket::connectToServer"_L1);
d->fullServerName = QString();
return;
}
@@ -183,6 +213,20 @@ void QLocalSocket::connectToServer(OpenMode openMode)
emit connected();
}
+static qint64 transformPipeReaderResult(qint64 res)
+{
+ // QWindowsPipeReader's reading functions return error codes
+ // that don't match what we need.
+ switch (res) {
+ case 0: // EOF -> transform to error
+ return -1;
+ case -2: // EWOULDBLOCK -> no error, just no bytes
+ return 0;
+ default:
+ return res;
+ }
+}
+
// This is reading from the buffer
qint64 QLocalSocket::readData(char *data, qint64 maxSize)
{
@@ -191,38 +235,56 @@ qint64 QLocalSocket::readData(char *data, qint64 maxSize)
if (!maxSize)
return 0;
- qint64 ret = d->pipeReader->read(data, maxSize);
+ return transformPipeReaderResult(d->pipeReader->read(data, maxSize));
+}
- // QWindowsPipeReader::read() returns error codes that don't match what we need
- switch (ret) {
- case 0: // EOF -> transform to error
- return -1;
- case -2: // EWOULDBLOCK -> no error, just no bytes
+qint64 QLocalSocket::readLineData(char *data, qint64 maxSize)
+{
+ Q_D(QLocalSocket);
+
+ if (!maxSize)
return 0;
- default:
- return ret;
- }
+
+ // QIODevice::readLine() reserves space for the trailing '\0' byte,
+ // so we must read 'maxSize + 1' bytes.
+ return transformPipeReaderResult(d->pipeReader->readLine(data, maxSize + 1));
}
qint64 QLocalSocket::skipData(qint64 maxSize)
{
- return QIODevice::skipData(maxSize);
+ Q_D(QLocalSocket);
+
+ if (!maxSize)
+ return 0;
+
+ return transformPipeReaderResult(d->pipeReader->skip(maxSize));
}
qint64 QLocalSocket::writeData(const char *data, qint64 len)
{
Q_D(QLocalSocket);
+ if (!isValid()) {
+ d->error = OperationError;
+ d->errorString = tr("Socket is not connected");
+ return -1;
+ }
+
if (len == 0)
return 0;
- d->write(data, len);
+
if (!d->pipeWriter) {
d->pipeWriter = new QWindowsPipeWriter(d->handle, this);
- connect(d->pipeWriter, &QWindowsPipeWriter::bytesWritten,
- this, &QLocalSocket::bytesWritten);
- QObjectPrivate::connect(d->pipeWriter, &QWindowsPipeWriter::canWrite,
- d, &QLocalSocketPrivate::_q_canWrite);
+ QObjectPrivate::connect(d->pipeWriter, &QWindowsPipeWriter::bytesWritten,
+ d, &QLocalSocketPrivate::_q_bytesWritten);
+ QObjectPrivate::connect(d->pipeWriter, &QWindowsPipeWriter::writeFailed,
+ d, &QLocalSocketPrivate::_q_writeFailed);
}
- d->_q_canWrite();
+
+ if (d->isWriteChunkCached(data, len))
+ d->pipeWriter->write(*(d->currentWriteChunk));
+ else
+ d->pipeWriter->write(data, len);
+
return len;
}
@@ -236,31 +298,43 @@ void QLocalSocket::abort()
close();
}
+void QLocalSocketPrivate::_q_canRead()
+{
+ Q_Q(QLocalSocket);
+ if (!emittedReadyRead) {
+ QScopedValueRollback<bool> guard(emittedReadyRead, true);
+ emit q->readyRead();
+ }
+}
+
void QLocalSocketPrivate::_q_pipeClosed()
{
Q_Q(QLocalSocket);
if (state == QLocalSocket::UnconnectedState)
return;
- emit q->readChannelFinished();
if (state != QLocalSocket::ClosingState) {
state = QLocalSocket::ClosingState;
emit q->stateChanged(state);
if (state != QLocalSocket::ClosingState)
return;
}
- state = QLocalSocket::UnconnectedState;
- emit q->stateChanged(state);
- emit q->disconnected();
+ serverName.clear();
+ fullServerName.clear();
pipeReader->stop();
- destroyPipeHandles();
- handle = INVALID_HANDLE_VALUE;
-
- if (pipeWriter) {
- delete pipeWriter;
- pipeWriter = 0;
+ delete pipeWriter;
+ pipeWriter = nullptr;
+ if (handle != INVALID_HANDLE_VALUE) {
+ DisconnectNamedPipe(handle);
+ CloseHandle(handle);
+ handle = INVALID_HANDLE_VALUE;
}
+
+ state = QLocalSocket::UnconnectedState;
+ emit q->stateChanged(state);
+ emit q->readChannelFinished();
+ emit q->disconnected();
}
qint64 QLocalSocket::bytesAvailable() const
@@ -274,7 +348,7 @@ qint64 QLocalSocket::bytesAvailable() const
qint64 QLocalSocket::bytesToWrite() const
{
Q_D(const QLocalSocket);
- return d->writeBuffer.size() + (d->pipeWriter ? d->pipeWriter->bytesToWrite() : 0);
+ return d->pipeWriterBytesToWrite();
}
bool QLocalSocket::canReadLine() const
@@ -286,52 +360,30 @@ bool QLocalSocket::canReadLine() const
void QLocalSocket::close()
{
Q_D(QLocalSocket);
- if (openMode() == NotOpen)
- return;
- d->setWriteChannelCount(0);
QIODevice::close();
+ d->pipeReader->stopAndClear();
d->serverName = QString();
d->fullServerName = QString();
-
- if (state() != UnconnectedState) {
- if (bytesToWrite() > 0) {
- disconnectFromServer();
- return;
- }
-
- d->_q_pipeClosed();
- }
+ disconnectFromServer();
}
bool QLocalSocket::flush()
{
Q_D(QLocalSocket);
- bool written = false;
- while (d->pipeWriter && d->pipeWriter->waitForWrite(0))
- written = true;
- return written;
+
+ return d->pipeWriter && d->pipeWriter->checkForWrite();
}
void QLocalSocket::disconnectFromServer()
{
Q_D(QLocalSocket);
- // Are we still connected?
- if (!isValid()) {
- // If we have unwritten data, the pipeWriter is still present.
- // It must be destroyed before close() to prevent an infinite loop.
- delete d->pipeWriter;
- d->pipeWriter = 0;
- d->writeBuffer.clear();
- }
-
- flush();
- if (bytesToWrite() != 0) {
+ if (bytesToWrite() == 0) {
+ d->_q_pipeClosed();
+ } else if (d->state != QLocalSocket::ClosingState) {
d->state = QLocalSocket::ClosingState;
emit stateChanged(d->state);
- } else {
- close();
}
}
@@ -356,17 +408,30 @@ bool QLocalSocket::setSocketDescriptor(qintptr socketDescriptor,
return true;
}
-void QLocalSocketPrivate::_q_canWrite()
+qint64 QLocalSocketPrivate::pipeWriterBytesToWrite() const
+{
+ return pipeWriter ? pipeWriter->bytesToWrite() : qint64(0);
+}
+
+void QLocalSocketPrivate::_q_bytesWritten(qint64 bytes)
{
Q_Q(QLocalSocket);
- if (writeBuffer.isEmpty()) {
- if (state == QLocalSocket::ClosingState)
- q->close();
- } else {
- Q_ASSERT(pipeWriter);
- if (!pipeWriter->isWriteOperationActive())
- pipeWriter->write(writeBuffer.read());
+ if (!emittedBytesWritten) {
+ QScopedValueRollback<bool> guard(emittedBytesWritten, true);
+ emit q->bytesWritten(bytes);
}
+ if (state == QLocalSocket::ClosingState)
+ q->disconnectFromServer();
+}
+
+void QLocalSocketPrivate::_q_writeFailed()
+{
+ Q_Q(QLocalSocket);
+ error = QLocalSocket::PeerClosedError;
+ errorString = QLocalSocket::tr("Remote closed");
+ emit q->errorOccurred(error);
+
+ _q_pipeClosed();
}
qintptr QLocalSocket::socketDescriptor() const
@@ -400,15 +465,38 @@ bool QLocalSocket::waitForDisconnected(int msecs)
qWarning("QLocalSocket::waitForDisconnected() is not allowed in UnconnectedState");
return false;
}
- if (!openMode().testFlag(QIODevice::ReadOnly)) {
- qWarning("QLocalSocket::waitForDisconnected isn't supported for write only pipes.");
- return false;
- }
- if (d->pipeReader->waitForPipeClosed(msecs)) {
- d->_q_pipeClosed();
- return true;
+
+ QDeadlineTimer deadline(msecs);
+ bool wasChecked = false;
+ while (!d->pipeReader->isPipeClosed()) {
+ if (wasChecked && deadline.hasExpired())
+ return false;
+
+ QSocketPoller poller(*d);
+ // The first parameter of the WaitForMultipleObjectsEx() call cannot
+ // be zero. So we have to call SleepEx() here.
+ if (!poller.writePending && poller.waitForClose) {
+ // Prevent waiting on the first pass, if both the pipe reader
+ // and the pipe writer are inactive.
+ if (wasChecked)
+ SleepEx(poller.getRemainingTime(deadline), TRUE);
+ } else if (!poller.poll(deadline)) {
+ return false;
+ }
+
+ if (d->pipeWriter)
+ d->pipeWriter->checkForWrite();
+
+ // When the read buffer is full, the read sequence is not running,
+ // so we need to peek the pipe to detect disconnection.
+ if (poller.waitForClose && isValid())
+ d->pipeReader->checkPipeState();
+
+ d->pipeReader->checkForReadyRead();
+ wasChecked = true;
}
- return false;
+ d->_q_pipeClosed();
+ return true;
}
bool QLocalSocket::isValid() const
@@ -424,32 +512,51 @@ bool QLocalSocket::waitForReadyRead(int msecs)
if (d->state != QLocalSocket::ConnectedState)
return false;
- // We already know that the pipe is gone, but did not enter the event loop yet.
- if (d->pipeReader->isPipeClosed()) {
- d->_q_pipeClosed();
- return false;
- }
-
- bool result = d->pipeReader->waitForReadyRead(msecs);
+ QDeadlineTimer deadline(msecs);
+ while (!d->pipeReader->isPipeClosed()) {
+ QSocketPoller poller(*d);
+ if (poller.waitForClose || !poller.poll(deadline))
+ return false;
- // We just noticed that the pipe is gone.
- if (d->pipeReader->isPipeClosed())
- d->_q_pipeClosed();
+ if (d->pipeWriter)
+ d->pipeWriter->checkForWrite();
- return result;
+ if (d->pipeReader->checkForReadyRead())
+ return true;
+ }
+ d->_q_pipeClosed();
+ return false;
}
bool QLocalSocket::waitForBytesWritten(int msecs)
{
- Q_D(const QLocalSocket);
- if (!d->pipeWriter)
+ Q_D(QLocalSocket);
+
+ if (d->state == QLocalSocket::UnconnectedState)
return false;
- // Wait for the pipe writer to acknowledge that it has
- // written. This will succeed if either the pipe writer has
- // already written the data, or if it manages to write data
- // within the given timeout.
- return d->pipeWriter->waitForWrite(msecs);
+ QDeadlineTimer deadline(msecs);
+ bool wasChecked = false;
+ while (!d->pipeReader->isPipeClosed()) {
+ if (wasChecked && deadline.hasExpired())
+ return false;
+
+ QSocketPoller poller(*d);
+ if (!poller.writePending || !poller.poll(deadline))
+ return false;
+
+ Q_ASSERT(d->pipeWriter);
+ if (d->pipeWriter->checkForWrite())
+ return true;
+
+ if (poller.waitForClose && isValid())
+ d->pipeReader->checkPipeState();
+
+ d->pipeReader->checkForReadyRead();
+ wasChecked = true;
+ }
+ d->_q_pipeClosed();
+ return false;
}
QT_END_NAMESPACE
diff --git a/src/network/socket/qnativesocketengine.cpp b/src/network/socket/qnativesocketengine.cpp
index 6667a6b097..4c8b3ebf3f 100644
--- a/src/network/socket/qnativesocketengine.cpp
+++ b/src/network/socket/qnativesocketengine.cpp
@@ -1,42 +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 QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//#define QNATIVESOCKETENGINE_DEBUG
@@ -114,7 +78,7 @@
\sa readDatagram(), QNetworkDatagram
*/
-#include "qnativesocketengine_p.h"
+#include "qnativesocketengine_p_p.h"
#include <qabstracteventdispatcher.h>
#include <qsocketnotifier.h>
@@ -135,6 +99,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
//#define QNATIVESOCKETENGINE_DEBUG
#define Q_VOID
@@ -448,13 +414,13 @@ bool QNativeSocketEngine::initialize(QAbstractSocket::SocketType socketType, QAb
// Create the socket
if (!d->createNewSocket(socketType, protocol)) {
#if defined (QNATIVESOCKETENGINE_DEBUG)
- QString typeStr = QLatin1String("UnknownSocketType");
- if (socketType == QAbstractSocket::TcpSocket) typeStr = QLatin1String("TcpSocket");
- else if (socketType == QAbstractSocket::UdpSocket) typeStr = QLatin1String("UdpSocket");
- else if (socketType == QAbstractSocket::SctpSocket) typeStr = QLatin1String("SctpSocket");
- QString protocolStr = QLatin1String("UnknownProtocol");
- if (protocol == QAbstractSocket::IPv4Protocol) protocolStr = QLatin1String("IPv4Protocol");
- else if (protocol == QAbstractSocket::IPv6Protocol) protocolStr = QLatin1String("IPv6Protocol");
+ QString typeStr = "UnknownSocketType"_L1;
+ if (socketType == QAbstractSocket::TcpSocket) typeStr = "TcpSocket"_L1;
+ else if (socketType == QAbstractSocket::UdpSocket) typeStr = "UdpSocket"_L1;
+ else if (socketType == QAbstractSocket::SctpSocket) typeStr = "SctpSocket"_L1;
+ QString protocolStr = "UnknownProtocol"_L1;
+ if (protocol == QAbstractSocket::IPv4Protocol) protocolStr = "IPv4Protocol"_L1;
+ else if (protocol == QAbstractSocket::IPv6Protocol) protocolStr = "IPv6Protocol"_L1;
qDebug("QNativeSocketEngine::initialize(type == %s, protocol == %s) failed: %s",
typeStr.toLatin1().constData(), protocolStr.toLatin1().constData(), d->socketErrorString.toLatin1().constData());
#endif
@@ -476,16 +442,18 @@ bool QNativeSocketEngine::initialize(QAbstractSocket::SocketType socketType, QAb
}
+#ifndef Q_OS_WASM
// Make sure we receive out-of-band data
if (socketType == QAbstractSocket::TcpSocket
&& !setOption(ReceiveOutOfBandData, 1)) {
qWarning("QNativeSocketEngine::initialize unable to inline out-of-band data");
}
+#endif
// Before Qt 4.6, we always set the send and receive buffer size to 49152 as
// this was found to be an optimal value. However, modern OS
// all have some kind of auto tuning for this and we therefore don't set
- // this explictly anymore.
+ // this explicitly anymore.
// If it introduces any performance regressions for Qt 4.6.x (x > 0) then
// it will be put back in.
//
@@ -689,7 +657,7 @@ bool QNativeSocketEngine::bind(const QHostAddress &address, quint16 port)
\sa bind(), accept()
*/
-bool QNativeSocketEngine::listen()
+bool QNativeSocketEngine::listen(int backlog)
{
Q_D(QNativeSocketEngine);
Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::listen(), false);
@@ -701,11 +669,7 @@ bool QNativeSocketEngine::listen()
Q_CHECK_TYPE(QNativeSocketEngine::listen(), QAbstractSocket::TcpSocket, false);
#endif
- // We're using a backlog of 50. Most modern kernels support TCP
- // syncookies by default, and if they do, the backlog is ignored.
- // When there is no support for TCP syncookies, this value is
- // fine.
- return d->nativeListen(50);
+ return d->nativeListen(backlog);
}
/*!
@@ -715,7 +679,7 @@ bool QNativeSocketEngine::listen()
\sa bind(), listen()
*/
-int QNativeSocketEngine::accept()
+qintptr QNativeSocketEngine::accept()
{
Q_D(QNativeSocketEngine);
Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::accept(), -1);
@@ -972,7 +936,7 @@ void QNativeSocketEngine::close()
if (d->exceptNotifier)
d->exceptNotifier->setEnabled(false);
- if(d->socketDescriptor != -1) {
+ if (d->socketDescriptor != -1) {
d->nativeClose();
d->socketDescriptor = -1;
}
@@ -984,23 +948,23 @@ void QNativeSocketEngine::close()
d->peerAddress.clear();
d->inboundStreamCount = d->outboundStreamCount = 0;
if (d->readNotifier) {
- qDeleteInEventHandler(d->readNotifier);
+ delete d->readNotifier;
d->readNotifier = nullptr;
}
if (d->writeNotifier) {
- qDeleteInEventHandler(d->writeNotifier);
+ delete d->writeNotifier;
d->writeNotifier = nullptr;
}
if (d->exceptNotifier) {
- qDeleteInEventHandler(d->exceptNotifier);
+ delete d->exceptNotifier;
d->exceptNotifier = nullptr;
}
}
/*!
- Waits for \a msecs milliseconds or until the socket is ready for
- reading. If \a timedOut is not \nullptr and \a msecs milliseconds
- have passed, the value of \a timedOut is set to true.
+ Waits until \a deadline has expired or until the socket is ready for
+ reading. If \a timedOut is not \nullptr and \a deadline has expired,
+ the value of \a timedOut is set to true.
Returns \c true if data is available for reading; otherwise returns
false.
@@ -1012,7 +976,7 @@ void QNativeSocketEngine::close()
is to create a QSocketNotifier, passing the socket descriptor
returned by socketDescriptor() to its constructor.
*/
-bool QNativeSocketEngine::waitForRead(int msecs, bool *timedOut)
+bool QNativeSocketEngine::waitForRead(QDeadlineTimer deadline, bool *timedOut)
{
Q_D(const QNativeSocketEngine);
Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::waitForRead(), false);
@@ -1022,7 +986,7 @@ bool QNativeSocketEngine::waitForRead(int msecs, bool *timedOut)
if (timedOut)
*timedOut = false;
- int ret = d->nativeSelect(msecs, true);
+ int ret = d->nativeSelect(deadline, true);
if (ret == 0) {
if (timedOut)
*timedOut = true;
@@ -1038,9 +1002,9 @@ bool QNativeSocketEngine::waitForRead(int msecs, bool *timedOut)
}
/*!
- Waits for \a msecs milliseconds or until the socket is ready for
- writing. If \a timedOut is not \nullptr and \a msecs milliseconds
- have passed, the value of \a timedOut is set to true.
+ Waits until \a deadline has expired or until the socket is ready for
+ writing. If \a timedOut is not \nullptr and \a deadline has expired,
+ the value of \a timedOut is set to true.
Returns \c true if data is available for writing; otherwise returns
false.
@@ -1052,7 +1016,7 @@ bool QNativeSocketEngine::waitForRead(int msecs, bool *timedOut)
is to create a QSocketNotifier, passing the socket descriptor
returned by socketDescriptor() to its constructor.
*/
-bool QNativeSocketEngine::waitForWrite(int msecs, bool *timedOut)
+bool QNativeSocketEngine::waitForWrite(QDeadlineTimer deadline, bool *timedOut)
{
Q_D(QNativeSocketEngine);
Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::waitForWrite(), false);
@@ -1062,7 +1026,7 @@ bool QNativeSocketEngine::waitForWrite(int msecs, bool *timedOut)
if (timedOut)
*timedOut = false;
- int ret = d->nativeSelect(msecs, false);
+ int ret = d->nativeSelect(deadline, false);
// On Windows, the socket is in connected state if a call to
// select(writable) is successful. In this case we should not
// issue a second call to WSAConnect()
@@ -1110,14 +1074,14 @@ bool QNativeSocketEngine::waitForWrite(int msecs, bool *timedOut)
bool QNativeSocketEngine::waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
bool checkRead, bool checkWrite,
- int msecs, bool *timedOut)
+ QDeadlineTimer deadline, bool *timedOut)
{
Q_D(QNativeSocketEngine);
Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::waitForReadOrWrite(), false);
Q_CHECK_NOT_STATE(QNativeSocketEngine::waitForReadOrWrite(),
QAbstractSocket::UnconnectedState, false);
- int ret = d->nativeSelect(msecs, checkRead, checkWrite, readyToRead, readyToWrite);
+ int ret = d->nativeSelect(deadline, checkRead, checkWrite, readyToRead, readyToWrite);
// On Windows, the socket is in connected state if a call to
// select(writable) is successful. In this case we should not
// issue a second call to WSAConnect()
@@ -1291,7 +1255,7 @@ bool QReadNotifier::event(QEvent *e)
class QWriteNotifier : public QSocketNotifier
{
public:
- QWriteNotifier(int fd, QNativeSocketEngine *parent)
+ QWriteNotifier(qintptr fd, QNativeSocketEngine *parent)
: QSocketNotifier(fd, QSocketNotifier::Write, parent) { engine = parent; }
protected:
@@ -1315,7 +1279,7 @@ bool QWriteNotifier::event(QEvent *e)
class QExceptionNotifier : public QSocketNotifier
{
public:
- QExceptionNotifier(int fd, QNativeSocketEngine *parent)
+ QExceptionNotifier(qintptr fd, QNativeSocketEngine *parent)
: QSocketNotifier(fd, QSocketNotifier::Exception, parent) { engine = parent; }
protected:
diff --git a/src/network/socket/qnativesocketengine_p.h b/src/network/socket/qnativesocketengine_p.h
index e5f0701d14..4c185b7a4a 100644
--- a/src/network/socket/qnativesocketengine_p.h
+++ b/src/network/socket/qnativesocketengine_p.h
@@ -1,42 +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 QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNATIVESOCKETENGINE_P_H
#define QNATIVESOCKETENGINE_P_H
@@ -56,8 +20,9 @@
#include "QtNetwork/qhostaddress.h"
#include "QtNetwork/qnetworkinterface.h"
#include "private/qabstractsocketengine_p.h"
+#include "qplatformdefs.h"
+
#ifndef Q_OS_WIN
-# include "qplatformdefs.h"
# include <netinet/in.h>
#else
# include <winsock2.h>
@@ -70,51 +35,63 @@ QT_BEGIN_NAMESPACE
#ifdef Q_OS_WIN
# define QT_SOCKLEN_T int
# define QT_SOCKOPTLEN_T int
-
-// The following definitions are copied from the MinGW header mswsock.h which
-// was placed in the public domain. The WSASendMsg and WSARecvMsg functions
-// were introduced with Windows Vista, so some Win32 headers are lacking them.
-// There are no known versions of Windows CE or Embedded that contain them.
-# ifndef WSAID_WSARECVMSG
-typedef INT (WINAPI *LPFN_WSARECVMSG)(SOCKET s, LPWSAMSG lpMsg,
- LPDWORD lpdwNumberOfBytesRecvd,
- LPWSAOVERLAPPED lpOverlapped,
- LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
-# define WSAID_WSARECVMSG {0xf689d7c8,0x6f1f,0x436b,{0x8a,0x53,0xe5,0x4f,0xe3,0x51,0xc3,0x22}}
-# endif // !WSAID_WSARECVMSG
-# ifndef WSAID_WSASENDMSG
-typedef struct {
- LPWSAMSG lpMsg;
- DWORD dwFlags;
- LPDWORD lpNumberOfBytesSent;
- LPWSAOVERLAPPED lpOverlapped;
- LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine;
-} WSASENDMSG, *LPWSASENDMSG;
-
-typedef INT (WSAAPI *LPFN_WSASENDMSG)(SOCKET s, LPWSAMSG lpMsg, DWORD dwFlags,
- LPDWORD lpNumberOfBytesSent,
- LPWSAOVERLAPPED lpOverlapped,
- LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
-
-# define WSAID_WSASENDMSG {0xa441e712,0x754f,0x43ca,{0x84,0xa7,0x0d,0xee,0x44,0xcf,0x60,0x6d}}
-# endif // !WSAID_WSASENDMSG
-#endif // Q_OS_WIN
-
-union qt_sockaddr {
- sockaddr a;
- sockaddr_in a4;
- sockaddr_in6 a6;
-};
+#endif
namespace {
namespace SetSALen {
template <typename T> void set(T *sa, typename std::enable_if<(&T::sa_len, true), QT_SOCKLEN_T>::type len)
{ sa->sa_len = len; }
+ template <typename T> void set(T *sa, typename std::enable_if<(&T::sin_len, true), QT_SOCKLEN_T>::type len)
+ { sa->sin_len = len; }
template <typename T> void set(T *sin6, typename std::enable_if<(&T::sin6_len, true), QT_SOCKLEN_T>::type len)
{ sin6->sin6_len = len; }
template <typename T> void set(T *, ...) {}
}
+
+inline QT_SOCKLEN_T setSockaddr(sockaddr_in *sin, const QHostAddress &addr, quint16 port = 0)
+{
+ *sin = {};
+ SetSALen::set(sin, sizeof(*sin));
+ sin->sin_family = AF_INET;
+ sin->sin_port = htons(port);
+ sin->sin_addr.s_addr = htonl(addr.toIPv4Address());
+ return sizeof(*sin);
+}
+
+inline QT_SOCKLEN_T setSockaddr(sockaddr_in6 *sin6, const QHostAddress &addr, quint16 port = 0)
+{
+ *sin6 = {};
+ SetSALen::set(sin6, sizeof(*sin6));
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_port = htons(port);
+ memcpy(sin6->sin6_addr.s6_addr, addr.toIPv6Address().c, sizeof(sin6->sin6_addr));
+#if QT_CONFIG(networkinterface)
+ sin6->sin6_scope_id = QNetworkInterface::interfaceIndexFromName(addr.scopeId());
+#else
+ // it had better be a number then, if it is not empty
+ sin6->sin6_scope_id = addr.scopeId().toUInt();
+#endif
+ return sizeof(*sin6);
+}
+
+inline QT_SOCKLEN_T setSockaddr(sockaddr *sa, const QHostAddress &addr, quint16 port = 0)
+{
+ switch (addr.protocol()) {
+ case QHostAddress::IPv4Protocol:
+ return setSockaddr(reinterpret_cast<sockaddr_in *>(sa), addr, port);
+
+ case QHostAddress::IPv6Protocol:
+ case QHostAddress::AnyIPProtocol:
+ return setSockaddr(reinterpret_cast<sockaddr_in6 *>(sa), addr, port);
+
+ case QHostAddress::UnknownNetworkLayerProtocol:
+ break;
+ }
+ *sa = {};
+ sa->sa_family = AF_UNSPEC;
+ return 0;
}
+} // unnamed namespace
class QNativeSocketEnginePrivate;
#ifndef QT_NO_NETWORKINTERFACE
@@ -138,8 +115,8 @@ public:
bool connectToHost(const QHostAddress &address, quint16 port) override;
bool connectToHostByName(const QString &name, quint16 port) override;
bool bind(const QHostAddress &address, quint16 port) override;
- bool listen() override;
- int accept() override;
+ bool listen(int backlog) override;
+ qintptr accept() override;
void close() override;
qint64 bytesAvailable() const override;
@@ -177,11 +154,14 @@ public:
int option(SocketOption option) const override;
bool setOption(SocketOption option, int value) override;
- bool waitForRead(int msecs = 30000, bool *timedOut = nullptr) override;
- bool waitForWrite(int msecs = 30000, bool *timedOut = nullptr) override;
+ bool waitForRead(QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout},
+ bool *timedOut = nullptr) override;
+ bool waitForWrite(QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout},
+ bool *timedOut = nullptr) override;
bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
bool checkRead, bool checkWrite,
- int msecs = 30000, bool *timedOut = nullptr) override;
+ QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout},
+ bool *timedOut = nullptr) override;
bool isReadNotificationEnabled() const override;
void setReadNotificationEnabled(bool enable) override;
@@ -199,132 +179,6 @@ private:
Q_DISABLE_COPY_MOVE(QNativeSocketEngine)
};
-class QSocketNotifier;
-
-class QNativeSocketEnginePrivate : public QAbstractSocketEnginePrivate
-{
- Q_DECLARE_PUBLIC(QNativeSocketEngine)
-public:
- QNativeSocketEnginePrivate();
- ~QNativeSocketEnginePrivate();
-
- qintptr socketDescriptor;
-
- QSocketNotifier *readNotifier, *writeNotifier, *exceptNotifier;
-
-#if defined(Q_OS_WIN)
- LPFN_WSASENDMSG sendmsg;
- LPFN_WSARECVMSG recvmsg;
-# endif
- enum ErrorString {
- NonBlockingInitFailedErrorString,
- BroadcastingInitFailedErrorString,
- NoIpV6ErrorString,
- RemoteHostClosedErrorString,
- TimeOutErrorString,
- ResourceErrorString,
- OperationUnsupportedErrorString,
- ProtocolUnsupportedErrorString,
- InvalidSocketErrorString,
- HostUnreachableErrorString,
- NetworkUnreachableErrorString,
- AccessErrorString,
- ConnectionTimeOutErrorString,
- ConnectionRefusedErrorString,
- AddressInuseErrorString,
- AddressNotAvailableErrorString,
- AddressProtectedErrorString,
- DatagramTooLargeErrorString,
- SendDatagramErrorString,
- ReceiveDatagramErrorString,
- WriteErrorString,
- ReadErrorString,
- PortInuseErrorString,
- NotSocketErrorString,
- InvalidProxyTypeString,
- TemporaryErrorString,
- NetworkDroppedConnectionErrorString,
- ConnectionResetErrorString,
-
- UnknownSocketErrorString = -1
- };
-
- void setError(QAbstractSocket::SocketError error, ErrorString errorString) const;
- QHostAddress adjustAddressProtocol(const QHostAddress &address) const;
-
- // native functions
- int option(QNativeSocketEngine::SocketOption option) const;
- bool setOption(QNativeSocketEngine::SocketOption option, int value);
-
- bool createNewSocket(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol &protocol);
-
- bool nativeConnect(const QHostAddress &address, quint16 port);
- bool nativeBind(const QHostAddress &address, quint16 port);
- bool nativeListen(int backlog);
- int nativeAccept();
-#ifndef QT_NO_NETWORKINTERFACE
- bool nativeJoinMulticastGroup(const QHostAddress &groupAddress,
- const QNetworkInterface &iface);
- bool nativeLeaveMulticastGroup(const QHostAddress &groupAddress,
- const QNetworkInterface &iface);
- QNetworkInterface nativeMulticastInterface() const;
- bool nativeSetMulticastInterface(const QNetworkInterface &iface);
-#endif
- qint64 nativeBytesAvailable() const;
-
- bool nativeHasPendingDatagrams() const;
- qint64 nativePendingDatagramSize() const;
- qint64 nativeReceiveDatagram(char *data, qint64 maxLength, QIpPacketHeader *header,
- QAbstractSocketEngine::PacketHeaderOptions options);
- qint64 nativeSendDatagram(const char *data, qint64 length, const QIpPacketHeader &header);
- qint64 nativeRead(char *data, qint64 maxLength);
- qint64 nativeWrite(const char *data, qint64 length);
- int nativeSelect(int timeout, bool selectForRead) const;
- int nativeSelect(int timeout, bool checkRead, bool checkWrite,
- bool *selectForRead, bool *selectForWrite) const;
-
- void nativeClose();
-
- bool checkProxy(const QHostAddress &address);
- bool fetchConnectionParameters();
-
-#if QT_CONFIG(networkinterface)
- static uint scopeIdFromString(const QString &scopeid)
- { return QNetworkInterface::interfaceIndexFromName(scopeid); }
-#endif
-
- /*! \internal
- Sets \a address and \a port in the \a aa sockaddr structure and the size in \a sockAddrSize.
- The address \a is converted to IPv6 if the current socket protocol is also IPv6.
- */
- void setPortAndAddress(quint16 port, const QHostAddress &address, qt_sockaddr *aa, QT_SOCKLEN_T *sockAddrSize)
- {
- if (address.protocol() == QAbstractSocket::IPv6Protocol
- || address.protocol() == QAbstractSocket::AnyIPProtocol
- || socketProtocol == QAbstractSocket::IPv6Protocol
- || socketProtocol == QAbstractSocket::AnyIPProtocol) {
- memset(&aa->a6, 0, sizeof(sockaddr_in6));
- aa->a6.sin6_family = AF_INET6;
-#if QT_CONFIG(networkinterface)
- aa->a6.sin6_scope_id = scopeIdFromString(address.scopeId());
-#endif
- aa->a6.sin6_port = htons(port);
- Q_IPV6ADDR tmp = address.toIPv6Address();
- memcpy(&aa->a6.sin6_addr, &tmp, sizeof(tmp));
- *sockAddrSize = sizeof(sockaddr_in6);
- SetSALen::set(&aa->a, sizeof(sockaddr_in6));
- } else {
- memset(&aa->a, 0, sizeof(sockaddr_in));
- aa->a4.sin_family = AF_INET;
- aa->a4.sin_port = htons(port);
- aa->a4.sin_addr.s_addr = htonl(address.toIPv4Address());
- *sockAddrSize = sizeof(sockaddr_in);
- SetSALen::set(&aa->a, sizeof(sockaddr_in));
- }
- }
-
-};
-
QT_END_NAMESPACE
#endif // QNATIVESOCKETENGINE_P_H
diff --git a/src/network/socket/qnativesocketengine_p_p.h b/src/network/socket/qnativesocketengine_p_p.h
new file mode 100644
index 0000000000..189a4327fd
--- /dev/null
+++ b/src/network/socket/qnativesocketengine_p_p.h
@@ -0,0 +1,189 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QNATIVESOCKETENGINE_P_P_H
+#define QNATIVESOCKETENGINE_P_P_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.
+//
+
+#include "private/qabstractsocketengine_p.h"
+#include "private/qnativesocketengine_p.h"
+
+#ifndef Q_OS_WIN
+# include <netinet/in.h>
+#else
+# include <winsock2.h>
+# include <ws2tcpip.h>
+# include <mswsock.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#ifdef Q_OS_WIN
+
+// The following definitions are copied from the MinGW header mswsock.h which
+// was placed in the public domain. The WSASendMsg and WSARecvMsg functions
+// were introduced with Windows Vista, so some Win32 headers are lacking them.
+// There are no known versions of Windows CE or Embedded that contain them.
+# ifndef WSAID_WSARECVMSG
+typedef INT (WINAPI *LPFN_WSARECVMSG)(SOCKET s, LPWSAMSG lpMsg,
+ LPDWORD lpdwNumberOfBytesRecvd,
+ LPWSAOVERLAPPED lpOverlapped,
+ LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
+# define WSAID_WSARECVMSG {0xf689d7c8,0x6f1f,0x436b,{0x8a,0x53,0xe5,0x4f,0xe3,0x51,0xc3,0x22}}
+# endif // !WSAID_WSARECVMSG
+# ifndef WSAID_WSASENDMSG
+typedef struct {
+ LPWSAMSG lpMsg;
+ DWORD dwFlags;
+ LPDWORD lpNumberOfBytesSent;
+ LPWSAOVERLAPPED lpOverlapped;
+ LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine;
+} WSASENDMSG, *LPWSASENDMSG;
+
+typedef INT (WSAAPI *LPFN_WSASENDMSG)(SOCKET s, LPWSAMSG lpMsg, DWORD dwFlags,
+ LPDWORD lpNumberOfBytesSent,
+ LPWSAOVERLAPPED lpOverlapped,
+ LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
+
+# define WSAID_WSASENDMSG {0xa441e712,0x754f,0x43ca,{0x84,0xa7,0x0d,0xee,0x44,0xcf,0x60,0x6d}}
+# endif // !WSAID_WSASENDMSG
+#endif // Q_OS_WIN
+
+union qt_sockaddr {
+ sockaddr a;
+ sockaddr_in a4;
+ sockaddr_in6 a6;
+};
+
+class QSocketNotifier;
+
+class QNativeSocketEnginePrivate : public QAbstractSocketEnginePrivate
+{
+ Q_DECLARE_PUBLIC(QNativeSocketEngine)
+public:
+ QNativeSocketEnginePrivate();
+ ~QNativeSocketEnginePrivate();
+
+ qintptr socketDescriptor;
+
+ QSocketNotifier *readNotifier, *writeNotifier, *exceptNotifier;
+
+#if defined(Q_OS_WIN)
+ LPFN_WSASENDMSG sendmsg;
+ LPFN_WSARECVMSG recvmsg;
+# endif
+ enum ErrorString {
+ NonBlockingInitFailedErrorString,
+ BroadcastingInitFailedErrorString,
+ NoIpV6ErrorString,
+ RemoteHostClosedErrorString,
+ TimeOutErrorString,
+ ResourceErrorString,
+ OperationUnsupportedErrorString,
+ ProtocolUnsupportedErrorString,
+ InvalidSocketErrorString,
+ HostUnreachableErrorString,
+ NetworkUnreachableErrorString,
+ AccessErrorString,
+ ConnectionTimeOutErrorString,
+ ConnectionRefusedErrorString,
+ AddressInuseErrorString,
+ AddressNotAvailableErrorString,
+ AddressProtectedErrorString,
+ DatagramTooLargeErrorString,
+ SendDatagramErrorString,
+ ReceiveDatagramErrorString,
+ WriteErrorString,
+ ReadErrorString,
+ PortInuseErrorString,
+ NotSocketErrorString,
+ InvalidProxyTypeString,
+ TemporaryErrorString,
+ NetworkDroppedConnectionErrorString,
+ ConnectionResetErrorString,
+
+ UnknownSocketErrorString = -1
+ };
+
+ void setError(QAbstractSocket::SocketError error, ErrorString errorString) const;
+ QHostAddress adjustAddressProtocol(const QHostAddress &address) const;
+
+ // native functions
+ int option(QNativeSocketEngine::SocketOption option) const;
+ bool setOption(QNativeSocketEngine::SocketOption option, int value);
+
+ bool createNewSocket(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol &protocol);
+
+ bool nativeConnect(const QHostAddress &address, quint16 port);
+ bool nativeBind(const QHostAddress &address, quint16 port);
+ bool nativeListen(int backlog);
+ qintptr nativeAccept();
+#ifndef QT_NO_NETWORKINTERFACE
+ bool nativeJoinMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &iface);
+ bool nativeLeaveMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &iface);
+ QNetworkInterface nativeMulticastInterface() const;
+ bool nativeSetMulticastInterface(const QNetworkInterface &iface);
+#endif
+ qint64 nativeBytesAvailable() const;
+
+ bool nativeHasPendingDatagrams() const;
+ qint64 nativePendingDatagramSize() const;
+ qint64 nativeReceiveDatagram(char *data, qint64 maxLength, QIpPacketHeader *header,
+ QAbstractSocketEngine::PacketHeaderOptions options);
+ qint64 nativeSendDatagram(const char *data, qint64 length, const QIpPacketHeader &header);
+ qint64 nativeRead(char *data, qint64 maxLength);
+ qint64 nativeWrite(const char *data, qint64 length);
+ int nativeSelect(QDeadlineTimer deadline, bool selectForRead) const;
+ int nativeSelect(QDeadlineTimer deadline, bool checkRead, bool checkWrite,
+ bool *selectForRead, bool *selectForWrite) const;
+
+ void nativeClose();
+
+ bool checkProxy(const QHostAddress &address);
+ bool fetchConnectionParameters();
+
+ /*! \internal
+ Sets \a address and \a port in the \a aa sockaddr structure and the size in \a sockAddrSize.
+ The address \a is converted to IPv6 if the current socket protocol is also IPv6.
+ */
+ void setPortAndAddress(quint16 port, const QHostAddress &address, qt_sockaddr *aa, QT_SOCKLEN_T *sockAddrSize)
+ {
+ switch (socketProtocol) {
+ case QHostAddress::IPv6Protocol:
+ case QHostAddress::AnyIPProtocol:
+ // force to IPv6
+ setSockaddr(&aa->a6, address, port);
+ *sockAddrSize = sizeof(sockaddr_in6);
+ return;
+
+ case QHostAddress::IPv4Protocol:
+ // force to IPv4
+ setSockaddr(&aa->a4, address, port);
+ *sockAddrSize = sizeof(sockaddr_in);
+ return;
+
+ case QHostAddress::UnknownNetworkLayerProtocol:
+ // don't force
+ break;
+ }
+ *sockAddrSize = setSockaddr(&aa->a, address, port);
+ }
+
+};
+
+QT_END_NAMESPACE
+
+#endif // QNATIVESOCKETENGINE_P_P_H
diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp
index a39b345d30..b6df412253 100644
--- a/src/network/socket/qnativesocketengine_unix.cpp
+++ b/src/network/socket/qnativesocketengine_unix.cpp
@@ -1,70 +1,28 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//#define QNATIVESOCKETENGINE_DEBUG
-#include "qnativesocketengine_p.h"
+#include "qnativesocketengine_p_p.h"
#include "private/qnet_unix_p.h"
+#include "qdeadlinetimer.h"
#include "qiodevice.h"
#include "qhostaddress.h"
-#include "qelapsedtimer.h"
#include "qvarlengtharray.h"
#include "qnetworkinterface.h"
+#include "qendian.h"
+#ifdef Q_OS_WASM
+#include <private/qeventdispatcher_wasm_p.h>
+#endif
#include <time.h>
#include <errno.h>
#include <fcntl.h>
-#ifndef QT_NO_IPV6IFNAME
-#include <net/if.h>
-#endif
-#ifdef QT_LINUXBASE
-#include <arpa/inet.h>
-#endif
-#ifdef Q_OS_BSD4
-#include <net/if_dl.h>
-#endif
#ifdef Q_OS_INTEGRITY
#include <sys/uio.h>
#endif
#if defined QNATIVESOCKETENGINE_DEBUG
-#include <qstring.h>
-#include <ctype.h>
+#include <private/qdebug_p.h>
#endif
#include <netinet/tcp.h>
@@ -73,41 +31,12 @@
#include <sys/socket.h>
#include <netinet/sctp.h>
#endif
+#ifdef Q_OS_BSD4
+# include <net/if_dl.h>
+#endif
QT_BEGIN_NAMESPACE
-#if defined QNATIVESOCKETENGINE_DEBUG
-
-/*
- Returns a human readable representation of the first \a len
- characters in \a data.
-*/
-static QByteArray qt_prettyDebug(const char *data, int len, int maxSize)
-{
- if (!data) return "(null)";
- QByteArray out;
- for (int i = 0; i < len; ++i) {
- char c = data[i];
- if (isprint(c)) {
- out += c;
- } else switch (c) {
- case '\n': out += "\\n"; break;
- case '\r': out += "\\r"; break;
- case '\t': out += "\\t"; break;
- default:
- QString tmp;
- tmp.sprintf("\\%o", c);
- out += tmp.toLatin1();
- }
- }
-
- if (len < maxSize)
- out += "...";
-
- return out;
-}
-#endif
-
/*
Extracts the port and address from a sockaddr, and stores them in
\a port and \a addr if they are non-null.
@@ -312,10 +241,8 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc
#endif
socketDescriptor = socket;
- if (socket != -1) {
- this->socketProtocol = socketProtocol;
- this->socketType = socketType;
- }
+ this->socketProtocol = socketProtocol;
+ this->socketType = socketType;
return true;
}
@@ -364,12 +291,12 @@ int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) co
}
int n, level;
- int v = -1;
+ int v = 0;
QT_SOCKOPTLEN_T len = sizeof(v);
convertToLevelAndOption(opt, socketProtocol, level, n);
if (n != -1 && ::getsockopt(socketDescriptor, level, n, (char *) &v, &len) != -1)
- return v;
+ return len == 1 ? qFromUnaligned<quint8>(&v) : v;
return -1;
}
@@ -509,6 +436,7 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, quint16
case EFAULT:
case ENOTSOCK:
socketState = QAbstractSocket::UnconnectedState;
+ break;
default:
break;
}
@@ -626,7 +554,7 @@ bool QNativeSocketEnginePrivate::nativeListen(int backlog)
return true;
}
-int QNativeSocketEnginePrivate::nativeAccept()
+qintptr QNativeSocketEnginePrivate::nativeAccept()
{
int acceptedDescriptor = qt_safe_accept(socketDescriptor, nullptr, nullptr);
if (acceptedDescriptor == -1) {
@@ -672,7 +600,7 @@ int QNativeSocketEnginePrivate::nativeAccept()
}
}
- return acceptedDescriptor;
+ return qintptr(acceptedDescriptor);
}
#ifndef QT_NO_NETWORKINTERFACE
@@ -785,17 +713,21 @@ QNetworkInterface QNativeSocketEnginePrivate::nativeMulticastInterface() const
return QNetworkInterface::interfaceFromIndex(v);
}
+#if defined(Q_OS_SOLARIS)
+ struct in_addr v = { 0, 0, 0, 0};
+#else
struct in_addr v = { 0 };
+#endif
QT_SOCKOPTLEN_T sizeofv = sizeof(v);
if (::getsockopt(socketDescriptor, IPPROTO_IP, IP_MULTICAST_IF, &v, &sizeofv) == -1)
return QNetworkInterface();
if (v.s_addr != 0 && sizeofv >= QT_SOCKOPTLEN_T(sizeof(v))) {
QHostAddress ipv4(ntohl(v.s_addr));
QList<QNetworkInterface> ifaces = QNetworkInterface::allInterfaces();
- for (int i = 0; i < ifaces.count(); ++i) {
+ for (int i = 0; i < ifaces.size(); ++i) {
const QNetworkInterface &iface = ifaces.at(i);
QList<QNetworkAddressEntry> entries = iface.addressEntries();
- for (int j = 0; j < entries.count(); ++j) {
+ for (int j = 0; j < entries.size(); ++j) {
const QNetworkAddressEntry &entry = entries.at(j);
if (entry.ip() == ipv4)
return iface;
@@ -815,7 +747,7 @@ bool QNativeSocketEnginePrivate::nativeSetMulticastInterface(const QNetworkInter
struct in_addr v;
if (iface.isValid()) {
QList<QNetworkAddressEntry> entries = iface.addressEntries();
- for (int i = 0; i < entries.count(); ++i) {
+ for (int i = 0; i < entries.size(); ++i) {
const QNetworkAddressEntry &entry = entries.at(i);
const QHostAddress &ip = entry.ip();
if (ip.protocol() == QAbstractSocket::IPv4Protocol) {
@@ -862,7 +794,7 @@ bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const
// Peek 1 bytes into the next message.
ssize_t readBytes;
char c;
- EINTR_LOOP(readBytes, ::recv(socketDescriptor, &c, 1, MSG_PEEK));
+ QT_EINTR_LOOP(readBytes, ::recv(socketDescriptor, &c, 1, MSG_PEEK));
// If there's no error, or if our buffer was too small, there must be a
// pending datagram.
@@ -881,7 +813,7 @@ qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const
#ifdef Q_OS_LINUX
// Linux can return the actual datagram size if we use MSG_TRUNC
char c;
- EINTR_LOOP(recvResult, ::recv(socketDescriptor, &c, 1, MSG_PEEK | MSG_TRUNC));
+ QT_EINTR_LOOP(recvResult, ::recv(socketDescriptor, &c, 1, MSG_PEEK | MSG_TRUNC));
#elif defined(SO_NREAD)
// macOS can return the actual datagram size if we use SO_NREAD
int value;
@@ -1061,7 +993,7 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxS
#if defined (QNATIVESOCKETENGINE_DEBUG)
qDebug("QNativeSocketEnginePrivate::nativeReceiveDatagram(%p \"%s\", %lli, %s, %i) == %lli",
- data, qt_prettyDebug(data, qMin(recvResult, ssize_t(16)), recvResult).data(), maxSize,
+ data, QtDebugUtils::toPrintable(data, recvResult, 16).constData(), maxSize,
(recvResult != -1 && options != QAbstractSocketEngine::WantNone)
? header->senderAddress.toString().toLatin1().constData() : "(unknown)",
(recvResult != -1 && options != QAbstractSocketEngine::WantNone)
@@ -1190,7 +1122,7 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l
#if defined (QNATIVESOCKETENGINE_DEBUG)
qDebug("QNativeSocketEngine::sendDatagram(%p \"%s\", %lli, \"%s\", %i) == %lli", data,
- qt_prettyDebug(data, qMin<int>(len, 16), len).data(), len,
+ QtDebugUtils::toPrintable(data, len, 16).constData(), len,
header.destinationAddress.toString().toLatin1().constData(),
header.destinationPort, (qint64) sentBytes);
#endif
@@ -1344,6 +1276,9 @@ qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len)
setError(QAbstractSocket::RemoteHostClosedError, RemoteHostClosedErrorString);
q->close();
break;
+#if EWOULDBLOCK != EAGAIN
+ case EWOULDBLOCK:
+#endif
case EAGAIN:
writtenBytes = 0;
break;
@@ -1356,9 +1291,8 @@ qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len)
}
#if defined (QNATIVESOCKETENGINE_DEBUG)
- qDebug("QNativeSocketEnginePrivate::nativeWrite(%p \"%s\", %llu) == %i",
- data, qt_prettyDebug(data, qMin((int) len, 16),
- (int) len).data(), len, (int) writtenBytes);
+ qDebug("QNativeSocketEnginePrivate::nativeWrite(%p \"%s\", %llu) == %i", data,
+ QtDebugUtils::toPrintable(data, len, 16).constData(), len, (int) writtenBytes);
#endif
return qint64(writtenBytes);
@@ -1407,22 +1341,24 @@ qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxSize)
}
#if defined (QNATIVESOCKETENGINE_DEBUG)
- qDebug("QNativeSocketEnginePrivate::nativeRead(%p \"%s\", %llu) == %zd",
- data, qt_prettyDebug(data, qMin(r, ssize_t(16)), r).data(),
- maxSize, r);
+ qDebug("QNativeSocketEnginePrivate::nativeRead(%p \"%s\", %llu) == %zd", data,
+ QtDebugUtils::toPrintable(data, r, 16).constData(), maxSize, r);
#endif
return qint64(r);
}
-int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) const
+int QNativeSocketEnginePrivate::nativeSelect(QDeadlineTimer deadline, bool selectForRead) const
{
bool dummy;
- return nativeSelect(timeout, selectForRead, !selectForRead, &dummy, &dummy);
+ return nativeSelect(deadline, selectForRead, !selectForRead, &dummy, &dummy);
}
-int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool checkWrite,
- bool *selectForRead, bool *selectForWrite) const
+#ifndef Q_OS_WASM
+
+int QNativeSocketEnginePrivate::nativeSelect(QDeadlineTimer deadline, bool checkRead,
+ bool checkWrite, bool *selectForRead,
+ bool *selectForWrite) const
{
pollfd pfd = qt_make_pollfd(socketDescriptor, 0);
@@ -1432,7 +1368,7 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool c
if (checkWrite)
pfd.events |= POLLOUT;
- const int ret = qt_poll_msecs(&pfd, 1, timeout);
+ const int ret = qt_safe_poll(&pfd, 1, deadline);
if (ret <= 0)
return ret;
@@ -1451,4 +1387,27 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool c
return ret;
}
+#else
+
+int QNativeSocketEnginePrivate::nativeSelect(QDeadlineTimer deadline, bool checkRead,
+ bool checkWrite, bool *selectForRead,
+ bool *selectForWrite) const
+{
+ *selectForRead = checkRead;
+ *selectForWrite = checkWrite;
+ bool socketDisconnect = false;
+ QEventDispatcherWasm::socketSelect(deadline.remainingTime(), socketDescriptor, checkRead,
+ checkWrite, selectForRead, selectForWrite,
+ &socketDisconnect);
+
+ // The disconnect/close handling code in QAbstractsScket::canReadNotification()
+ // does not detect remote disconnect properly; do that here as a workardound.
+ if (socketDisconnect)
+ receiver->closeNotification();
+
+ return 1;
+}
+
+#endif // Q_OS_WASM
+
QT_END_NAMESPACE
diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp
index 35422a1e80..6525f46e30 100644
--- a/src/network/socket/qnativesocketengine_win.cpp
+++ b/src/network/socket/qnativesocketengine_win.cpp
@@ -1,50 +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 QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-// Prevent windows system header files from defining min/max as macros.
-#define NOMINMAX 1
+// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <winsock2.h>
#include <ws2tcpip.h>
-#include "qnativesocketengine_p.h"
+#include "qnativesocketengine_p_p.h"
#include <qabstracteventdispatcher.h>
#include <qsocketnotifier.h>
@@ -52,13 +13,14 @@
#include <qdatetime.h>
#include <qnetworkinterface.h>
#include <qoperatingsystemversion.h>
+#include <qvarlengtharray.h>
#include <algorithm>
+#include <chrono>
//#define QNATIVESOCKETENGINE_DEBUG
#if defined(QNATIVESOCKETENGINE_DEBUG)
-# include <qstring.h>
-# include <qbytearray.h>
+#include <private/qdebug_p.h>
#endif
QT_BEGIN_NAMESPACE
@@ -127,36 +89,6 @@ void verboseWSErrorDebug(int r)
qErrnoWarning(r, "more details");
}
-/*
- Returns a human readable representation of the first \a len
- characters in \a data.
-*/
-static QByteArray qt_prettyDebug(const char *data, int len, int maxLength)
-{
- if (!data) return "(null)";
- QByteArray out;
- for (int i = 0; i < len; ++i) {
- char c = data[i];
- if (isprint(int(uchar(c)))) {
- out += c;
- } else switch (c) {
- case '\n': out += "\\n"; break;
- case '\r': out += "\\r"; break;
- case '\t': out += "\\t"; break;
- default:
- QString tmp;
- tmp.sprintf("\\%o", c);
- out += tmp.toLatin1().constData();
- }
- }
-
- if (len < maxLength)
- out += "...";
-
- return out;
-}
-
-
#define WS_ERROR_DEBUG(x) verboseWSErrorDebug(x)
#else
@@ -325,15 +257,6 @@ static inline QAbstractSocket::SocketType qt_socket_getType(qintptr socketDescri
bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType socketType, QAbstractSocket::NetworkLayerProtocol &socketProtocol)
{
-
- //### no ip6 support on winsocket 1.1 but we will try not to use this !!!!!!!!!!!!1
- /*
- if (winsockVersion < 0x20 && socketProtocol == QAbstractSocket::IPv6Protocol) {
- //### no ip6 support
- return -1;
- }
- */
-
//### SCTP not implemented
if (socketType == QAbstractSocket::SctpSocket) {
setError(QAbstractSocket::UnsupportedSocketOperationError,
@@ -346,34 +269,15 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc
|| (socketProtocol == QAbstractSocket::AnyIPProtocol)) ? AF_INET6 : AF_INET;
int type = (socketType == QAbstractSocket::UdpSocket) ? SOCK_DGRAM : SOCK_STREAM;
- // MSDN KB179942 states that on winnt 4 WSA_FLAG_OVERLAPPED is needed if socket is to be non blocking
- // and recomends alwasy doing it for cross windows version comapablity.
+ // MSDN KB179942 states that on winnt 4 WSA_FLAG_OVERLAPPED is needed if socket is to be non
+ // blocking and recommends always doing it for cross-windows-version compatibility.
- // WSA_FLAG_NO_HANDLE_INHERIT is atomic (like linux O_CLOEXEC), but requires windows 7 SP 1 or later
- // SetHandleInformation is supported since W2K but isn't atomic
+ // WSA_FLAG_NO_HANDLE_INHERIT is atomic (like linux O_CLOEXEC)
#ifndef WSA_FLAG_NO_HANDLE_INHERIT
#define WSA_FLAG_NO_HANDLE_INHERIT 0x80
#endif
SOCKET socket = ::WSASocket(protocol, type, 0, NULL, 0, WSA_FLAG_NO_HANDLE_INHERIT | WSA_FLAG_OVERLAPPED);
- // previous call fails if the windows 7 service pack 1 or hot fix isn't installed.
-
- // Try the old API if the new one failed on Windows 7
- if (socket == INVALID_SOCKET && QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8) {
- socket = ::WSASocket(protocol, type, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
-#ifdef HANDLE_FLAG_INHERIT
- if (socket != INVALID_SOCKET) {
- // make non inheritable the old way
- BOOL handleFlags = SetHandleInformation(reinterpret_cast<HANDLE>(socket), HANDLE_FLAG_INHERIT, 0);
-#ifdef QNATIVESOCKETENGINE_DEBUG
- qDebug() << "QNativeSocketEnginePrivate::createNewSocket - set inheritable" << handleFlags;
-#else
- Q_UNUSED(handleFlags);
-#endif
- }
-#endif
- }
-
if (socket == INVALID_SOCKET) {
int err = WSAGetLastError();
WS_ERROR_DEBUG(err);
@@ -426,10 +330,8 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc
sendmsg = 0;
socketDescriptor = socket;
- if (socket != INVALID_SOCKET) {
- this->socketProtocol = socketProtocol;
- this->socketType = socketType;
- }
+ this->socketProtocol = socketProtocol;
+ this->socketType = socketType;
// Make the socket nonblocking.
if (!setOption(QAbstractSocketEngine::NonBlockingSocketOption, 1)) {
@@ -510,7 +412,6 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt
return false;
}
return true;
- break;
}
case QNativeSocketEngine::TypeOfServiceOption:
case QNativeSocketEngine::MaxStreamsSocketOption:
@@ -870,10 +771,10 @@ bool QNativeSocketEnginePrivate::nativeListen(int backlog)
return true;
}
-int QNativeSocketEnginePrivate::nativeAccept()
+qintptr QNativeSocketEnginePrivate::nativeAccept()
{
- int acceptedDescriptor = WSAAccept(socketDescriptor, 0,0,0,0);
- if (acceptedDescriptor == -1) {
+ SOCKET acceptedDescriptor = WSAAccept(socketDescriptor, 0,0,0,0);
+ if (acceptedDescriptor == INVALID_SOCKET) {
int err = WSAGetLastError();
switch (err) {
case WSAEACCES:
@@ -907,19 +808,19 @@ int QNativeSocketEnginePrivate::nativeAccept()
setError(QAbstractSocket::UnknownSocketError, UnknownSocketErrorString);
break;
}
- } else if (acceptedDescriptor != -1 && QAbstractEventDispatcher::instance()) {
+ } else if (acceptedDescriptor != INVALID_SOCKET && QAbstractEventDispatcher::instance()) {
// Because of WSAAsyncSelect() WSAAccept returns a non blocking socket
// with the same attributes as the listening socket including the current
// WSAAsyncSelect(). To be able to change the socket to blocking mode the
- // WSAAsyncSelect() call must be cancled.
+ // WSAAsyncSelect() call must be canceled.
QSocketNotifier n(acceptedDescriptor, QSocketNotifier::Read);
n.setEnabled(true);
n.setEnabled(false);
}
#if defined (QNATIVESOCKETENGINE_DEBUG)
- qDebug("QNativeSocketEnginePrivate::nativeAccept() == %i", acceptedDescriptor);
+ qDebug("QNativeSocketEnginePrivate::nativeAccept() == %lld", qint64(acceptedDescriptor));
#endif
- return acceptedDescriptor;
+ return qintptr(acceptedDescriptor);
}
static bool multicastMembershipHelper(QNativeSocketEnginePrivate *d,
@@ -1282,7 +1183,7 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxL
#if defined (QNATIVESOCKETENGINE_DEBUG)
bool printSender = (ret != -1 && (options & QNativeSocketEngine::WantDatagramSender) != 0);
qDebug("QNativeSocketEnginePrivate::nativeReceiveDatagram(%p \"%s\", %lli, %s, %i) == %lli",
- data, qt_prettyDebug(data, qMin<qint64>(ret, 16), ret).data(), maxLength,
+ data, QtDebugUtils::toPrintable(data, ret, 16).constData(), maxLength,
printSender ? header->senderAddress.toString().toLatin1().constData() : "(unknown)",
printSender ? header->senderPort : 0, ret);
#endif
@@ -1415,8 +1316,8 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l
}
#if defined (QNATIVESOCKETENGINE_DEBUG)
- qDebug("QNativeSocketEnginePrivate::nativeSendDatagram(%p \"%s\", %lli, \"%s\", %i) == %lli", data,
- qt_prettyDebug(data, qMin<qint64>(len, 16), len).data(), len,
+ qDebug("QNativeSocketEnginePrivate::nativeSendDatagram(%p \"%s\", %lli, \"%s\", %i) == %lli",
+ data, QtDebugUtils::toPrintable(data, len, 16).constData(), len,
header.destinationAddress.toString().toLatin1().constData(),
header.destinationPort, ret);
#endif
@@ -1475,7 +1376,7 @@ qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len)
#if defined (QNATIVESOCKETENGINE_DEBUG)
qDebug("QNativeSocketEnginePrivate::nativeWrite(%p \"%s\", %lli) == %lli",
- data, qt_prettyDebug(data, qMin(int(ret), 16), int(ret)).data(), len, ret);
+ data, QtDebugUtils::toPrintable(data, ret, 16).constData(), len, ret);
#endif
return ret;
@@ -1517,8 +1418,8 @@ qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxLength)
#if defined (QNATIVESOCKETENGINE_DEBUG)
if (ret != -2) {
- qDebug("QNativeSocketEnginePrivate::nativeRead(%p \"%s\", %lli) == %lli",
- data, qt_prettyDebug(data, qMin(int(bytesRead), 16), int(bytesRead)).data(), maxLength, ret);
+ qDebug("QNativeSocketEnginePrivate::nativeRead(%p \"%s\", %lli) == %lli", data,
+ QtDebugUtils::toPrintable(data, bytesRead, 16).constData(), maxLength, ret);
} else {
qDebug("QNativeSocketEnginePrivate::nativeRead(%p, %lli) == -2 (WOULD BLOCK)",
data, maxLength);
@@ -1528,7 +1429,18 @@ qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxLength)
return ret;
}
-int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) const
+inline timeval durationToTimeval(std::chrono::nanoseconds dur) noexcept
+{
+ using namespace std::chrono;
+ const auto secs = duration_cast<seconds>(dur);
+ const auto frac = duration_cast<microseconds>(dur - secs);
+ struct timeval tval;
+ tval.tv_sec = secs.count();
+ tval.tv_usec = frac.count();
+ return tval;
+}
+
+int QNativeSocketEnginePrivate::nativeSelect(QDeadlineTimer deadline, bool selectForRead) const
{
bool readEnabled = selectForRead && readNotifier && readNotifier->isEnabled();
if (readEnabled)
@@ -1542,12 +1454,10 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) co
fds.fd_count = 1;
fds.fd_array[0] = (SOCKET)socketDescriptor;
- struct timeval tv;
- tv.tv_sec = timeout / 1000;
- tv.tv_usec = (timeout % 1000) * 1000;
+ struct timeval tv = durationToTimeval(deadline.remainingTimeAsDuration());
if (selectForRead) {
- ret = select(0, &fds, 0, 0, timeout < 0 ? 0 : &tv);
+ ret = select(0, &fds, 0, 0, &tv);
} else {
// select for write
@@ -1556,7 +1466,7 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) co
FD_ZERO(&fdexception);
FD_SET((SOCKET)socketDescriptor, &fdexception);
- ret = select(0, 0, &fds, &fdexception, timeout < 0 ? 0 : &tv);
+ ret = select(0, 0, &fds, &fdexception, &tv);
// ... but if it is actually set, pretend it did not happen
if (ret > 0 && FD_ISSET((SOCKET)socketDescriptor, &fdexception))
@@ -1569,7 +1479,7 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) co
return ret;
}
-int QNativeSocketEnginePrivate::nativeSelect(int timeout,
+int QNativeSocketEnginePrivate::nativeSelect(QDeadlineTimer deadline,
bool checkRead, bool checkWrite,
bool *selectForRead, bool *selectForWrite) const
{
@@ -1598,11 +1508,9 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout,
FD_SET((SOCKET)socketDescriptor, &fdexception);
}
- struct timeval tv;
- tv.tv_sec = timeout / 1000;
- tv.tv_usec = (timeout % 1000) * 1000;
+ struct timeval tv = durationToTimeval(deadline.remainingTimeAsDuration());
- ret = select(socketDescriptor + 1, &fdread, &fdwrite, &fdexception, timeout < 0 ? 0 : &tv);
+ ret = select(socketDescriptor + 1, &fdread, &fdwrite, &fdexception, &tv);
//... but if it is actually set, pretend it did not happen
if (ret > 0 && FD_ISSET((SOCKET)socketDescriptor, &fdexception))
diff --git a/src/network/socket/qnet_unix_p.h b/src/network/socket/qnet_unix_p.h
index e038352352..a172a14a10 100644
--- a/src/network/socket/qnet_unix_p.h
+++ b/src/network/socket/qnet_unix_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNET_UNIX_P_H
#define QNET_UNIX_P_H
@@ -144,7 +108,7 @@ static inline int qt_safe_connect(int sockfd, const struct sockaddr *addr, QT_SO
{
int ret;
// Solaris e.g. expects a non-const 2nd parameter
- EINTR_LOOP(ret, QT_SOCKET_CONNECT(sockfd, const_cast<struct sockaddr *>(addr), addrlen));
+ QT_EINTR_LOOP(ret, QT_SOCKET_CONNECT(sockfd, const_cast<struct sockaddr *>(addr), addrlen));
return ret;
}
#undef QT_SOCKET_CONNECT
@@ -160,15 +124,10 @@ static inline int qt_safe_connect(int sockfd, const struct sockaddr *addr, QT_SO
# undef listen
#endif
-// VxWorks' headers specify 'int' instead of '...' for the 3rd ioctl() parameter.
template <typename T>
static inline int qt_safe_ioctl(int sockfd, unsigned long request, T arg)
{
-#ifdef Q_OS_VXWORKS
- return ::ioctl(sockfd, request, (int) arg);
-#else
return ::ioctl(sockfd, request, arg);
-#endif
}
static inline int qt_safe_sendmsg(int sockfd, const struct msghdr *msg, int flags)
@@ -180,7 +139,7 @@ static inline int qt_safe_sendmsg(int sockfd, const struct msghdr *msg, int flag
#endif
int ret;
- EINTR_LOOP(ret, ::sendmsg(sockfd, msg, flags));
+ QT_EINTR_LOOP(ret, ::sendmsg(sockfd, msg, flags));
return ret;
}
@@ -188,7 +147,7 @@ static inline int qt_safe_recvmsg(int sockfd, struct msghdr *msg, int flags)
{
int ret;
- EINTR_LOOP(ret, ::recvmsg(sockfd, msg, flags));
+ QT_EINTR_LOOP(ret, ::recvmsg(sockfd, msg, flags));
return ret;
}
diff --git a/src/network/socket/qsctpserver.cpp b/src/network/socket/qsctpserver.cpp
index 2aa694b3fd..cd060d93e8 100644
--- a/src/network/socket/qsctpserver.cpp
+++ b/src/network/socket/qsctpserver.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//#define QSCTPSERVER_DEBUG
@@ -82,7 +46,7 @@
between endpoints. Call nextPendingDatagramConnection() to accept
the pending datagram-mode connection as a connected QSctpSocket.
- \note This feature is not supported on the Windows platform.
+ \note This class is not supported on the Windows platform.
\sa QTcpServer, QSctpSocket, QAbstractSocket
*/
diff --git a/src/network/socket/qsctpserver.h b/src/network/socket/qsctpserver.h
index b678ba053d..f82ae71f16 100644
--- a/src/network/socket/qsctpserver.h
+++ b/src/network/socket/qsctpserver.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSCTPSERVER_H
#define QSCTPSERVER_H
@@ -45,7 +9,7 @@
QT_BEGIN_NAMESPACE
-#if !defined(QT_NO_SCTP) || defined(Q_CLANG_QDOC)
+#if !defined(QT_NO_SCTP) || defined(Q_QDOC)
class QSctpServerPrivate;
class QSctpSocket;
diff --git a/src/network/socket/qsctpserver_p.h b/src/network/socket/qsctpserver_p.h
index 8816cc150e..a4200547ea 100644
--- a/src/network/socket/qsctpserver_p.h
+++ b/src/network/socket/qsctpserver_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSCTPSERVER_P_H
#define QSCTPSERVER_P_H
diff --git a/src/network/socket/qsctpsocket.cpp b/src/network/socket/qsctpsocket.cpp
index fe76f64c42..868c9e3785 100644
--- a/src/network/socket/qsctpsocket.cpp
+++ b/src/network/socket/qsctpsocket.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//#define QSCTPSOCKET_DEBUG
@@ -110,7 +74,7 @@
etc. is allowed in datagram mode with the same limitations as in
continuous byte stream mode.
- \note This feature is not supported on the Windows platform.
+ \note This class is not supported on the Windows platform.
\sa QSctpServer, QTcpSocket, QAbstractSocket
*/
@@ -119,7 +83,6 @@
#include "qsctpsocket_p.h"
#include "qabstractsocketengine_p.h"
-#include "private/qbytearray_p.h"
#ifdef QSCTPSOCKET_DEBUG
#include <qdebug.h>
@@ -156,7 +119,7 @@ bool QSctpSocketPrivate::canReadNotification()
const int savedCurrentChannel = currentReadChannel;
bool currentChannelRead = false;
do {
- int datagramSize = incomingDatagram.size();
+ qsizetype datagramSize = incomingDatagram.size();
QIpPacketHeader header;
do {
@@ -169,7 +132,7 @@ bool QSctpSocketPrivate::canReadNotification()
bytesToRead = 4096;
}
- Q_ASSERT((datagramSize + int(bytesToRead)) < MaxByteArraySize);
+ Q_ASSERT((datagramSize + qsizetype(bytesToRead)) < QByteArray::max_size());
incomingDatagram.resize(datagramSize + int(bytesToRead));
#if defined (QSCTPSOCKET_DEBUG)
@@ -545,3 +508,5 @@ bool QSctpSocket::writeDatagram(const QNetworkDatagram &datagram)
}
QT_END_NAMESPACE
+
+#include "moc_qsctpsocket.cpp"
diff --git a/src/network/socket/qsctpsocket.h b/src/network/socket/qsctpsocket.h
index 5288da6129..8f0578ac26 100644
--- a/src/network/socket/qsctpsocket.h
+++ b/src/network/socket/qsctpsocket.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSCTPSOCKET_H
#define QSCTPSOCKET_H
@@ -45,7 +9,7 @@
QT_BEGIN_NAMESPACE
-#if !defined(QT_NO_SCTP) || defined(Q_CLANG_QDOC)
+#if !defined(QT_NO_SCTP) || defined(Q_QDOC)
class QSctpSocketPrivate;
diff --git a/src/network/socket/qsctpsocket_p.h b/src/network/socket/qsctpsocket_p.h
index c17b9c1c9a..bcc407eb67 100644
--- a/src/network/socket/qsctpsocket_p.h
+++ b/src/network/socket/qsctpsocket_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSCTPSOCKET_P_H
#define QSCTPSOCKET_P_H
diff --git a/src/network/socket/qsocks5socketengine.cpp b/src/network/socket/qsocks5socketengine.cpp
index 3d40840c1b..0564ad7a33 100644
--- a/src/network/socket/qsocks5socketengine.cpp
+++ b/src/network/socket/qsocks5socketengine.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qsocks5socketengine_p.h"
@@ -45,6 +9,7 @@
#include "qdebug.h"
#include "qhash.h"
#include "qqueue.h"
+#include "qdeadlinetimer.h"
#include "qelapsedtimer.h"
#include "qmutex.h"
#include "qthread.h"
@@ -56,14 +21,21 @@
#include <qendian.h>
#include <qnetworkinterface.h>
+#include <QtCore/qpointer.h>
+
+#include <memory>
+
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+using namespace std::chrono_literals;
+
static const int MaxWriteBufferSize = 128*1024;
//#define QSOCKS5SOCKETLAYER_DEBUG
#define MAX_DATA_DUMP 256
-#define SOCKS5_BLOCKING_BIND_TIMEOUT 5000
+static constexpr auto Socks5BlockingBindTimeout = 5s;
#define Q_INIT_CHECK(returnValue) do { \
if (!d->data) { \
@@ -100,35 +72,35 @@ static const int MaxWriteBufferSize = 128*1024;
static QString s5StateToString(QSocks5SocketEnginePrivate::Socks5State s)
{
switch (s) {
- case QSocks5SocketEnginePrivate::Uninitialized: return QLatin1String("Uninitialized");
- case QSocks5SocketEnginePrivate::ConnectError: return QLatin1String("ConnectError");
- case QSocks5SocketEnginePrivate::AuthenticationMethodsSent: return QLatin1String("AuthenticationMethodsSent");
- case QSocks5SocketEnginePrivate::Authenticating: return QLatin1String("Authenticating");
- case QSocks5SocketEnginePrivate::AuthenticatingError: return QLatin1String("AuthenticatingError");
- case QSocks5SocketEnginePrivate::RequestMethodSent: return QLatin1String("RequestMethodSent");
- case QSocks5SocketEnginePrivate::RequestError: return QLatin1String("RequestError");
- case QSocks5SocketEnginePrivate::Connected: return QLatin1String("Connected");
- case QSocks5SocketEnginePrivate::UdpAssociateSuccess: return QLatin1String("UdpAssociateSuccess");
- case QSocks5SocketEnginePrivate::BindSuccess: return QLatin1String("BindSuccess");
- case QSocks5SocketEnginePrivate::ControlSocketError: return QLatin1String("ControlSocketError");
- case QSocks5SocketEnginePrivate::SocksError: return QLatin1String("SocksError");
- case QSocks5SocketEnginePrivate::HostNameLookupError: return QLatin1String("HostNameLookupError");
+ case QSocks5SocketEnginePrivate::Uninitialized: return "Uninitialized"_L1;
+ case QSocks5SocketEnginePrivate::ConnectError: return "ConnectError"_L1;
+ case QSocks5SocketEnginePrivate::AuthenticationMethodsSent: return "AuthenticationMethodsSent"_L1;
+ case QSocks5SocketEnginePrivate::Authenticating: return "Authenticating"_L1;
+ case QSocks5SocketEnginePrivate::AuthenticatingError: return "AuthenticatingError"_L1;
+ case QSocks5SocketEnginePrivate::RequestMethodSent: return "RequestMethodSent"_L1;
+ case QSocks5SocketEnginePrivate::RequestError: return "RequestError"_L1;
+ case QSocks5SocketEnginePrivate::Connected: return "Connected"_L1;
+ case QSocks5SocketEnginePrivate::UdpAssociateSuccess: return "UdpAssociateSuccess"_L1;
+ case QSocks5SocketEnginePrivate::BindSuccess: return "BindSuccess"_L1;
+ case QSocks5SocketEnginePrivate::ControlSocketError: return "ControlSocketError"_L1;
+ case QSocks5SocketEnginePrivate::SocksError: return "SocksError"_L1;
+ case QSocks5SocketEnginePrivate::HostNameLookupError: return "HostNameLookupError"_L1;
default: break;
}
- return QLatin1String("unknown state");
+ return "unknown state"_L1;
}
static QString dump(const QByteArray &buf)
{
QString data;
for (int i = 0; i < qMin<int>(MAX_DATA_DUMP, buf.size()); ++i) {
- if (i) data += QLatin1Char(' ');
+ if (i) data += u' ';
uint val = (unsigned char)buf.at(i);
- // data += QString("0x%1").arg(val, 3, 16, QLatin1Char('0'));
+ // data += QString("0x%1").arg(val, 3, 16, u'0');
data += QString::number(val);
}
if (buf.size() > MAX_DATA_DUMP)
- data += QLatin1String(" ...");
+ data += " ..."_L1;
return QString::fromLatin1("size: %1 data: { %2 }").arg(buf.size()).arg(data);
}
@@ -144,7 +116,7 @@ static inline QString dump(const QByteArray &) { return QString(); }
/*
inserts the host address in buf at pos and updates pos.
- if the func fails the data in buf and the vallue of pos is undefined
+ if the func fails the data in buf and the value of pos is undefined
*/
static bool qt_socks5_set_host_address_and_port(const QHostAddress &address, quint16 port, QByteArray *pBuf)
{
@@ -186,11 +158,11 @@ static bool qt_socks5_set_host_name_and_port(const QString &hostname, quint16 po
QByteArray encodedHostName = QUrl::toAce(hostname);
QByteArray &buf = *pBuf;
- if (encodedHostName.length() > 255)
+ if (encodedHostName.size() > 255)
return false;
buf.append(S5_DOMAINNAME);
- buf.append(uchar(encodedHostName.length()));
+ buf.append(uchar(encodedHostName.size()));
buf.append(encodedHostName);
// add port
@@ -206,7 +178,7 @@ static bool qt_socks5_set_host_name_and_port(const QString &hostname, quint16 po
/*
- retrives the host address in buf at pos and updates pos.
+ retrieves the host address in buf at pos and updates pos.
return 1 if OK, 0 if need more data, -1 if error
if the func fails the value of the address and the pos is undefined
*/
@@ -325,7 +297,7 @@ protected:
QRecursiveMutex mutex;
int sweepTimerId = -1;
//socket descriptor, data, timestamp
- QHash<int, QSocks5BindData *> store;
+ QHash<qintptr, QSocks5BindData *> store;
};
Q_GLOBAL_STATIC(QSocks5BindStore, socks5BindStore)
@@ -349,9 +321,10 @@ void QSocks5BindStore::add(qintptr socketDescriptor, QSocks5BindData *bindData)
}
bindData->timeStamp.start();
store.insert(socketDescriptor, bindData);
+
// start sweep timer if not started
if (sweepTimerId == -1)
- sweepTimerId = startTimer(60000);
+ sweepTimerId = startTimer(1min);
}
bool QSocks5BindStore::contains(qintptr socketDescriptor)
@@ -492,7 +465,7 @@ bool QSocks5PasswordAuthenticator::continueAuthenticate(QTcpSocket *socket, bool
QString QSocks5PasswordAuthenticator::errorString()
{
- return QLatin1String("Socks5 user name or password incorrect");
+ return "Socks5 user name or password incorrect"_L1;
}
@@ -747,7 +720,7 @@ void QSocks5SocketEnginePrivate::parseAuthenticationMethodReply()
return;
} else if (buf.at(1) != data->authenticator->methodId()
|| !data->authenticator->beginAuthenticate(data->controlSocket, &authComplete)) {
- setErrorState(AuthenticatingError, QLatin1String("Socks5 host did not support authentication method."));
+ setErrorState(AuthenticatingError, "Socks5 host did not support authentication method."_L1);
socketError = QAbstractSocket::SocketAccessError; // change the socket error
emitConnectionNotification();
return;
@@ -1100,7 +1073,7 @@ bool QSocks5SocketEngine::connectInternal()
} else if (socketType() == QAbstractSocket::UdpSocket) {
d->initialize(QSocks5SocketEnginePrivate::UdpAssociateMode);
// all udp needs to be bound
- if (!bind(QHostAddress(QLatin1String("0.0.0.0")), 0))
+ if (!bind(QHostAddress("0.0.0.0"_L1), 0))
return false;
setState(QAbstractSocket::ConnectedState);
@@ -1190,7 +1163,7 @@ void QSocks5SocketEnginePrivate::_q_controlSocketReadNotification()
}
if (buf.size()) {
QSOCKS5_DEBUG << dump(buf);
- connectData->readBuffer.append(buf);
+ connectData->readBuffer.append(std::move(buf));
emitReadNotification();
}
break;
@@ -1290,7 +1263,7 @@ void QSocks5SocketEnginePrivate::_q_udpSocketReadNotification()
int pos = 0;
const char *buf = inBuf.constData();
if (inBuf.size() < 4) {
- QSOCKS5_D_DEBUG << "bugus udp data, discarding";
+ QSOCKS5_D_DEBUG << "bogus udp data, discarding";
return;
}
QSocks5RevivedDatagram datagram;
@@ -1317,7 +1290,7 @@ bool QSocks5SocketEngine::bind(const QHostAddress &addr, quint16 port)
{
Q_D(QSocks5SocketEngine);
- // when bind wee will block until the bind is finished as the info from the proxy server is needed
+ // when bind we will block until the bind is finished as the info from the proxy server is needed
QHostAddress address;
if (addr.protocol() == QAbstractSocket::AnyIPProtocol)
@@ -1357,11 +1330,8 @@ bool QSocks5SocketEngine::bind(const QHostAddress &addr, quint16 port)
return false;
}
- int msecs = SOCKS5_BLOCKING_BIND_TIMEOUT;
- QElapsedTimer stopWatch;
- stopWatch.start();
d->data->controlSocket->connectToHost(d->proxyInfo.hostName(), d->proxyInfo.port());
- if (!d->waitForConnected(msecs, nullptr) ||
+ if (!d->waitForConnected(QDeadlineTimer{Socks5BlockingBindTimeout}, nullptr) ||
d->data->controlSocket->state() == QAbstractSocket::UnconnectedState) {
// waitForConnected sets the error state and closes the socket
QSOCKS5_Q_DEBUG << "waitForConnected to proxy server" << d->data->controlSocket->errorString();
@@ -1383,7 +1353,7 @@ bool QSocks5SocketEngine::bind(const QHostAddress &addr, quint16 port)
// binding timed out
setError(QAbstractSocket::SocketTimeoutError,
- QLatin1String(QT_TRANSLATE_NOOP("QSocks5SocketEngine", "Network operation timed out")));
+ QLatin1StringView(QT_TRANSLATE_NOOP("QSocks5SocketEngine", "Network operation timed out")));
///### delete d->udpSocket;
///### d->udpSocket = 0;
@@ -1391,9 +1361,10 @@ bool QSocks5SocketEngine::bind(const QHostAddress &addr, quint16 port)
}
-bool QSocks5SocketEngine::listen()
+bool QSocks5SocketEngine::listen(int backlog)
{
Q_D(QSocks5SocketEngine);
+ Q_UNUSED(backlog);
QSOCKS5_Q_DEBUG << "listen()";
@@ -1410,7 +1381,7 @@ bool QSocks5SocketEngine::listen()
return false;
}
-int QSocks5SocketEngine::accept()
+qintptr QSocks5SocketEngine::accept()
{
Q_D(QSocks5SocketEngine);
// check we are listing ---
@@ -1436,10 +1407,10 @@ int QSocks5SocketEngine::accept()
d->socketState = QAbstractSocket::UnconnectedState;
break;
case QSocks5SocketEnginePrivate::ControlSocketError:
- setError(QAbstractSocket::ProxyProtocolError, QLatin1String("Control socket error"));
+ setError(QAbstractSocket::ProxyProtocolError, "Control socket error"_L1);
break;
default:
- setError(QAbstractSocket::ProxyProtocolError, QLatin1String("SOCKS5 proxy error"));
+ setError(QAbstractSocket::ProxyProtocolError, "SOCKS5 proxy error"_L1);
break;
}
return sd;
@@ -1451,11 +1422,9 @@ void QSocks5SocketEngine::close()
Q_D(QSocks5SocketEngine);
if (d->data && d->data->controlSocket) {
if (d->data->controlSocket->state() == QAbstractSocket::ConnectedState) {
- int msecs = 100;
- QElapsedTimer stopWatch;
- stopWatch.start();
+ QDeadlineTimer deadline(100ms);
while (!d->data->controlSocket->bytesToWrite()) {
- if (!d->data->controlSocket->waitForBytesWritten(qt_subtract_from_timeout(msecs, stopWatch.elapsed())))
+ if (!d->data->controlSocket->waitForBytesWritten(deadline.remainingTime()))
break;
}
}
@@ -1476,7 +1445,7 @@ qint64 QSocks5SocketEngine::bytesAvailable() const
#ifndef QT_NO_UDPSOCKET
else if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode
&& !d->udpData->pendingDatagrams.isEmpty())
- return d->udpData->pendingDatagrams.first().data.size();
+ return d->udpData->pendingDatagrams.constFirst().data.size();
#endif
return 0;
}
@@ -1491,7 +1460,7 @@ qint64 QSocks5SocketEngine::read(char *data, qint64 maxlen)
//imitate remote closed
close();
setError(QAbstractSocket::RemoteHostClosedError,
- QLatin1String("Remote host closed connection###"));
+ "Remote host closed connection###"_L1);
setState(QAbstractSocket::UnconnectedState);
return -1;
} else {
@@ -1525,8 +1494,12 @@ qint64 QSocks5SocketEngine::write(const char *data, qint64 len)
if (!d->data->authenticator->seal(buf, &sealedBuf)) {
// ### Handle this error.
}
+ // We pass pointer and size because 'sealedBuf' is (most definitely) raw data:
+ // QIODevice might have to cache the byte array if the socket cannot write the data.
+ // If the _whole_ array needs to be cached then it would simply store a copy of the
+ // array whose data will go out of scope and be deallocated before it can be used.
+ qint64 written = d->data->controlSocket->write(sealedBuf.constData(), sealedBuf.size());
- qint64 written = d->data->controlSocket->write(sealedBuf);
if (written <= 0) {
QSOCKS5_Q_DEBUG << "native write returned" << written;
return written;
@@ -1550,7 +1523,7 @@ bool QSocks5SocketEngine::joinMulticastGroup(const QHostAddress &,
const QNetworkInterface &)
{
setError(QAbstractSocket::UnsupportedSocketOperationError,
- QLatin1String("Operation on socket is not supported"));
+ "Operation on socket is not supported"_L1);
return false;
}
@@ -1558,7 +1531,7 @@ bool QSocks5SocketEngine::leaveMulticastGroup(const QHostAddress &,
const QNetworkInterface &)
{
setError(QAbstractSocket::UnsupportedSocketOperationError,
- QLatin1String("Operation on socket is not supported"));
+ "Operation on socket is not supported"_L1);
return false;
}
@@ -1571,7 +1544,7 @@ QNetworkInterface QSocks5SocketEngine::multicastInterface() const
bool QSocks5SocketEngine::setMulticastInterface(const QNetworkInterface &)
{
setError(QAbstractSocket::UnsupportedSocketOperationError,
- QLatin1String("Operation on socket is not supported"));
+ "Operation on socket is not supported"_L1);
return false;
}
#endif // QT_NO_NETWORKINTERFACE
@@ -1627,7 +1600,7 @@ qint64 QSocks5SocketEngine::writeDatagram(const char *data, qint64 len, const QI
if (!d->data) {
d->initialize(QSocks5SocketEnginePrivate::UdpAssociateMode);
// all udp needs to be bound
- if (!bind(QHostAddress(QLatin1String("0.0.0.0")), 0)) {
+ if (!bind(QHostAddress("0.0.0.0"_L1), 0)) {
//### set error
return -1;
}
@@ -1635,10 +1608,12 @@ qint64 QSocks5SocketEngine::writeDatagram(const char *data, qint64 len, const QI
QByteArray outBuf;
outBuf.reserve(270 + len);
- outBuf[0] = 0x00;
- outBuf[1] = 0x00;
- outBuf[2] = 0x00;
+ outBuf.append(3, '\0');
if (!qt_socks5_set_host_address_and_port(header.destinationAddress, header.destinationPort, &outBuf)) {
+ QSOCKS5_DEBUG << "error setting address" << header.destinationAddress << " : "
+ << header.destinationPort;
+ //### set error code ....
+ return -1;
}
outBuf += QByteArray(data, len);
QSOCKS5_DEBUG << "sending" << dump(outBuf);
@@ -1702,7 +1677,7 @@ bool QSocks5SocketEngine::setOption(SocketOption option, int value)
return false;
}
-bool QSocks5SocketEnginePrivate::waitForConnected(int msecs, bool *timedOut)
+bool QSocks5SocketEnginePrivate::waitForConnected(QDeadlineTimer deadline, bool *timedOut)
{
if (data->controlSocket->state() == QAbstractSocket::UnconnectedState)
return false;
@@ -1712,11 +1687,8 @@ bool QSocks5SocketEnginePrivate::waitForConnected(int msecs, bool *timedOut)
mode == BindMode ? BindSuccess :
UdpAssociateSuccess;
- QElapsedTimer stopWatch;
- stopWatch.start();
-
while (socks5State != wantedState) {
- if (!data->controlSocket->waitForReadyRead(qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) {
+ if (!data->controlSocket->waitForReadyRead(deadline.remainingTime())) {
if (data->controlSocket->state() == QAbstractSocket::UnconnectedState)
return true;
@@ -1730,18 +1702,15 @@ bool QSocks5SocketEnginePrivate::waitForConnected(int msecs, bool *timedOut)
return true;
}
-bool QSocks5SocketEngine::waitForRead(int msecs, bool *timedOut)
+bool QSocks5SocketEngine::waitForRead(QDeadlineTimer deadline, bool *timedOut)
{
Q_D(QSocks5SocketEngine);
- QSOCKS5_DEBUG << "waitForRead" << msecs;
+ QSOCKS5_DEBUG << "waitForRead" << deadline.remainingTimeAsDuration();
d->readNotificationActivated = false;
- QElapsedTimer stopWatch;
- stopWatch.start();
-
// are we connected yet?
- if (!d->waitForConnected(msecs, timedOut))
+ if (!d->waitForConnected(deadline, timedOut))
return false;
if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState)
return true;
@@ -1755,7 +1724,7 @@ bool QSocks5SocketEngine::waitForRead(int msecs, bool *timedOut)
if (d->mode == QSocks5SocketEnginePrivate::ConnectMode ||
d->mode == QSocks5SocketEnginePrivate::BindMode) {
while (!d->readNotificationActivated) {
- if (!d->data->controlSocket->waitForReadyRead(qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) {
+ if (!d->data->controlSocket->waitForReadyRead(deadline.remainingTime())) {
if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState)
return true;
@@ -1768,7 +1737,7 @@ bool QSocks5SocketEngine::waitForRead(int msecs, bool *timedOut)
#ifndef QT_NO_UDPSOCKET
} else {
while (!d->readNotificationActivated) {
- if (!d->udpData->udpSocket->waitForReadyRead(qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) {
+ if (!d->udpData->udpSocket->waitForReadyRead(deadline.remainingTime())) {
setError(d->udpData->udpSocket->error(), d->udpData->udpSocket->errorString());
if (timedOut && d->udpData->udpSocket->error() == QAbstractSocket::SocketTimeoutError)
*timedOut = true;
@@ -1787,16 +1756,13 @@ bool QSocks5SocketEngine::waitForRead(int msecs, bool *timedOut)
}
-bool QSocks5SocketEngine::waitForWrite(int msecs, bool *timedOut)
+bool QSocks5SocketEngine::waitForWrite(QDeadlineTimer deadline, bool *timedOut)
{
Q_D(QSocks5SocketEngine);
- QSOCKS5_DEBUG << "waitForWrite" << msecs;
-
- QElapsedTimer stopWatch;
- stopWatch.start();
+ QSOCKS5_DEBUG << "waitForWrite" << deadline.remainingTimeAsDuration();
// are we connected yet?
- if (!d->waitForConnected(msecs, timedOut))
+ if (!d->waitForConnected(deadline, timedOut))
return false;
if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState)
return true;
@@ -1805,27 +1771,32 @@ bool QSocks5SocketEngine::waitForWrite(int msecs, bool *timedOut)
// flush any bytes we may still have buffered in the time that we have left
if (d->data->controlSocket->bytesToWrite())
- d->data->controlSocket->waitForBytesWritten(qt_subtract_from_timeout(msecs, stopWatch.elapsed()));
- while ((msecs == -1 || stopWatch.elapsed() < msecs)
- && d->data->controlSocket->state() == QAbstractSocket::ConnectedState
- && d->data->controlSocket->bytesToWrite() >= MaxWriteBufferSize)
- d->data->controlSocket->waitForBytesWritten(qt_subtract_from_timeout(msecs, stopWatch.elapsed()));
+ d->data->controlSocket->waitForBytesWritten(deadline.remainingTime());
+
+ auto shouldWriteBytes = [&]() {
+ return d->data->controlSocket->state() == QAbstractSocket::ConnectedState
+ && d->data->controlSocket->bytesToWrite() >= MaxWriteBufferSize;
+ };
+
+ qint64 remainingTime = deadline.remainingTime();
+ for (; remainingTime > 0 && shouldWriteBytes(); remainingTime = deadline.remainingTime())
+ d->data->controlSocket->waitForBytesWritten(remainingTime);
return d->data->controlSocket->bytesToWrite() < MaxWriteBufferSize;
}
bool QSocks5SocketEngine::waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
bool checkRead, bool checkWrite,
- int msecs, bool *timedOut)
+ QDeadlineTimer deadline, bool *timedOut)
{
Q_UNUSED(checkRead);
if (!checkWrite) {
- bool canRead = waitForRead(msecs, timedOut);
+ bool canRead = waitForRead(deadline, timedOut);
if (readyToRead)
*readyToRead = canRead;
return canRead;
}
- bool canWrite = waitForWrite(msecs, timedOut);
+ bool canWrite = waitForWrite(deadline, timedOut);
if (readyToWrite)
*readyToWrite = canWrite;
return canWrite;
@@ -1905,9 +1876,9 @@ QSocks5SocketEngineHandler::createSocketEngine(QAbstractSocket::SocketType socke
QSOCKS5_DEBUG << "not proxying";
return nullptr;
}
- QScopedPointer<QSocks5SocketEngine> engine(new QSocks5SocketEngine(parent));
+ auto engine = std::make_unique<QSocks5SocketEngine>(parent);
engine->setProxy(proxy);
- return engine.take();
+ return engine.release();
}
QAbstractSocketEngine *QSocks5SocketEngineHandler::createSocketEngine(qintptr socketDescriptor, QObject *parent)
diff --git a/src/network/socket/qsocks5socketengine_p.h b/src/network/socket/qsocks5socketengine_p.h
index 77b461b944..3a169812df 100644
--- a/src/network/socket/qsocks5socketengine_p.h
+++ b/src/network/socket/qsocks5socketengine_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSOCKS5SOCKETENGINE_P_H
#define QSOCKS5SOCKETENGINE_P_H
@@ -52,8 +16,10 @@
//
#include <QtNetwork/private/qtnetworkglobal_p.h>
+
+#include <QtNetwork/qnetworkproxy.h>
+
#include "qabstractsocketengine_p.h"
-#include "qnetworkproxy.h"
QT_REQUIRE_CONFIG(socks5);
@@ -81,8 +47,8 @@ public:
bool connectToHost(const QHostAddress &address, quint16 port) override;
bool connectToHostByName(const QString &name, quint16 port) override;
bool bind(const QHostAddress &address, quint16 port) override;
- bool listen() override;
- int accept() override;
+ bool listen(int backlog) override;
+ qintptr accept() override;
void close() override;
qint64 bytesAvailable() const override;
@@ -112,11 +78,14 @@ public:
int option(SocketOption option) const override;
bool setOption(SocketOption option, int value) override;
- bool waitForRead(int msecs = 30000, bool *timedOut = nullptr) override;
- bool waitForWrite(int msecs = 30000, bool *timedOut = nullptr) override;
+ bool waitForRead(QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout},
+ bool *timedOut = nullptr) override;
+ bool waitForWrite(QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout},
+ bool *timedOut = nullptr) override;
bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
bool checkRead, bool checkWrite,
- int msecs = 30000, bool *timedOut = nullptr) override;
+ QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout},
+ bool *timedOut = nullptr) override;
bool isReadNotificationEnabled() const override;
void setReadNotificationEnabled(bool enable) override;
@@ -155,9 +124,9 @@ public:
virtual bool beginAuthenticate(QTcpSocket *socket, bool *completed);
virtual bool continueAuthenticate(QTcpSocket *socket, bool *completed);
- virtual bool seal(const QByteArray &buf, QByteArray *sealedBuf);
- virtual bool unSeal(const QByteArray &sealedBuf, QByteArray *buf);
- virtual bool unSeal(QTcpSocket *sealedSocket, QByteArray *buf);
+ bool seal(const QByteArray &buf, QByteArray *sealedBuf);
+ bool unSeal(const QByteArray &sealedBuf, QByteArray *buf);
+ bool unSeal(QTcpSocket *sealedSocket, QByteArray *buf);
virtual QString errorString() { return QString(); }
};
@@ -242,7 +211,7 @@ public:
void parseRequestMethodReply();
void parseNewConnection();
- bool waitForConnected(int msecs, bool *timedOut);
+ bool waitForConnected(QDeadlineTimer deadline, bool *timedOut);
void _q_controlSocketConnected();
void _q_controlSocketReadNotification();
diff --git a/src/network/socket/qtcpserver.cpp b/src/network/socket/qtcpserver.cpp
index a404350d98..a0c0f00aaa 100644
--- a/src/network/socket/qtcpserver.cpp
+++ b/src/network/socket/qtcpserver.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//#define QTCPSERVER_DEBUG
@@ -54,7 +18,9 @@
Call listen() to have the server listen for incoming connections.
The newConnection() signal is then emitted each time a client
- connects to the server.
+ connects to the server. When the client connection has been added
+ to the pending connection queue using the addPendingConnection()
+ function, the pendingConnectionAvailable() signal is emitted.
Call nextPendingConnection() to accept the pending connection as
a connected QTcpSocket. The function returns a pointer to a
@@ -77,17 +43,27 @@
use waitForNewConnection(), which blocks until either a
connection is available or a timeout expires.
- \sa QTcpSocket, {Fortune Server Example}, {Threaded Fortune Server Example},
- {Loopback Example}, {Torrent Example}
+ \sa QTcpSocket, {Fortune Server}, {Threaded Fortune Server},
+ {Torrent Example}
*/
/*! \fn void QTcpServer::newConnection()
- This signal is emitted every time a new connection is available.
+ This signal is emitted every time a new connection is available, regardless
+ of whether it has been added to the pending connections queue or not.
\sa hasPendingConnections(), nextPendingConnection()
*/
+/*! \fn void QTcpServer::pendingConnectionAvailable()
+
+ This signal is emitted every time a new connection has been added to the
+ pending connections queue.
+
+ \sa hasPendingConnections(), nextPendingConnection()
+ \since 6.4
+*/
+
/*! \fn void QTcpServer::acceptError(QAbstractSocket::SocketError socketError)
\since 5.0
@@ -157,7 +133,7 @@ QNetworkProxy QTcpServerPrivate::resolveProxy(const QHostAddress &address, quint
}
// return the first that we can use
- for (const QNetworkProxy &p : qAsConst(proxies)) {
+ for (const QNetworkProxy &p : std::as_const(proxies)) {
if (socketType == QAbstractSocket::TcpSocket &&
(p.capabilities() & QNetworkProxy::ListeningCapability) != 0)
return p;
@@ -196,7 +172,7 @@ void QTcpServerPrivate::readNotification()
{
Q_Q(QTcpServer);
for (;;) {
- if (pendingConnections.count() >= maxConnections) {
+ if (totalPendingConnections() >= maxConnections) {
#if defined (QTCPSERVER_DEBUG)
qDebug("QTcpServerPrivate::_q_processIncomingConnection() too many connections");
#endif
@@ -205,7 +181,7 @@ void QTcpServerPrivate::readNotification()
return;
}
- int descriptor = socketEngine->accept();
+ qintptr descriptor = socketEngine->accept();
if (descriptor == -1) {
if (socketEngine->error() != QAbstractSocket::TemporaryError) {
q->pauseAccepting();
@@ -218,16 +194,32 @@ void QTcpServerPrivate::readNotification()
#if defined (QTCPSERVER_DEBUG)
qDebug("QTcpServerPrivate::_q_processIncomingConnection() accepted socket %i", descriptor);
#endif
+ QPointer<QTcpServer> that = q;
q->incomingConnection(descriptor);
- QPointer<QTcpServer> that = q;
- emit q->newConnection();
+ if (that)
+ emit q->newConnection();
+
if (!that || !q->isListening())
return;
}
}
/*!
+ \internal
+ Return the amount of sockets currently in queue for the server.
+ This is to make maxPendingConnections work properly with servers that don't
+ necessarily have 'ready-to-go' sockets as soon as they connect,
+ e.g. QSslServer.
+ By default we just return pendingConnections.size(), which is equivalent to
+ what it did before.
+*/
+int QTcpServerPrivate::totalPendingConnections() const
+{
+ return int(pendingConnections.size());
+}
+
+/*!
Constructs a QTcpServer object.
\a parent is passed to the QObject constructor.
@@ -331,7 +323,7 @@ bool QTcpServer::listen(const QHostAddress &address, quint16 port)
return false;
}
- if (!d->socketEngine->listen()) {
+ if (!d->socketEngine->listen(d->listenBacklog)) {
d->serverSocketError = d->socketEngine->error();
d->serverSocketErrorString = d->socketEngine->errorString();
return false;
@@ -506,7 +498,7 @@ bool QTcpServer::waitForNewConnection(int msec, bool *timedOut)
if (d->state != QAbstractSocket::ListeningState)
return false;
- if (!d->socketEngine->waitForRead(msec, timedOut)) {
+ if (!d->socketEngine->waitForRead(QDeadlineTimer(msec), timedOut)) {
d->serverSocketError = d->socketEngine->error();
d->serverSocketErrorString = d->socketEngine->errorString();
return false;
@@ -608,14 +600,17 @@ void QTcpServer::incomingConnection(qintptr socketDescriptor)
\note Don't forget to call this member from reimplemented
incomingConnection() if you do not want to break the
- Pending Connections mechanism.
+ Pending Connections mechanism. This function emits the
+ pendingConnectionAvailable() signal after the socket has been
+ added.
- \sa incomingConnection()
+ \sa incomingConnection(), pendingConnectionAvailable()
\since 4.7
*/
void QTcpServer::addPendingConnection(QTcpSocket* socket)
{
d_func()->pendingConnections.append(socket);
+ emit pendingConnectionAvailable(QPrivateSignal());
}
/*!
@@ -650,6 +645,34 @@ int QTcpServer::maxPendingConnections() const
}
/*!
+ Sets the backlog queue size of to be accepted connections to \a
+ size. The operating system might reduce or ignore this value.
+ By default, the queue size is 50.
+
+ \note This property must be set prior to calling listen().
+
+ \since 6.3
+
+ \sa listenBacklogSize()
+*/
+void QTcpServer::setListenBacklogSize(int size)
+{
+ d_func()->listenBacklog = size;
+}
+
+/*!
+ Returns the backlog queue size of to be accepted connections.
+
+ \since 6.3
+
+ \sa setListenBacklogSize()
+*/
+int QTcpServer::listenBacklogSize() const
+{
+ return d_func()->listenBacklog;
+}
+
+/*!
Returns an error code for the last error that occurred.
\sa errorString()
diff --git a/src/network/socket/qtcpserver.h b/src/network/socket/qtcpserver.h
index 37df12919f..6177a3b0aa 100644
--- a/src/network/socket/qtcpserver.h
+++ b/src/network/socket/qtcpserver.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QTCPSERVER_H
#define QTCPSERVER_H
@@ -69,6 +33,9 @@ public:
void setMaxPendingConnections(int numConnections);
int maxPendingConnections() const;
+ void setListenBacklogSize(int size);
+ int listenBacklogSize() const;
+
quint16 serverPort() const;
QHostAddress serverAddress() const;
@@ -99,6 +66,7 @@ protected:
Q_SIGNALS:
void newConnection();
+ void pendingConnectionAvailable(QPrivateSignal);
void acceptError(QAbstractSocket::SocketError socketError);
private:
diff --git a/src/network/socket/qtcpserver_p.h b/src/network/socket/qtcpserver_p.h
index 6ee8c5f0b1..853a4aaf96 100644
--- a/src/network/socket/qtcpserver_p.h
+++ b/src/network/socket/qtcpserver_p.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QTCPSERVER_P_H
#define QTCPSERVER_P_H
@@ -83,6 +47,7 @@ public:
QAbstractSocket::SocketError serverSocketError;
QString serverSocketErrorString;
+ int listenBacklog = 50;
int maxConnections;
#ifndef QT_NO_NETWORKPROXY
@@ -91,6 +56,7 @@ public:
#endif
virtual void configureCreatedSocket();
+ virtual int totalPendingConnections() const;
// from QAbstractSocketEngineReceiver
void readNotification() override;
diff --git a/src/network/socket/qtcpsocket.cpp b/src/network/socket/qtcpsocket.cpp
index 85d425055b..979382f26c 100644
--- a/src/network/socket/qtcpsocket.cpp
+++ b/src/network/socket/qtcpsocket.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//#define QTCPSOCKET_DEBUG
@@ -59,9 +23,9 @@
\note TCP sockets cannot be opened in QIODevice::Unbuffered mode.
\sa QTcpServer, QUdpSocket, QNetworkAccessManager,
- {Fortune Server Example}, {Fortune Client Example},
- {Threaded Fortune Server Example}, {Blocking Fortune Client Example},
- {Loopback Example}, {Torrent Example}
+ {Fortune Server}, {Fortune Client},
+ {Threaded Fortune Server}, {Blocking Fortune Client},
+ {Torrent Example}
*/
#include "qtcpsocket.h"
@@ -119,3 +83,5 @@ QTcpSocket::QTcpSocket(QAbstractSocket::SocketType socketType,
}
QT_END_NAMESPACE
+
+#include "moc_qtcpsocket.cpp"
diff --git a/src/network/socket/qtcpsocket.h b/src/network/socket/qtcpsocket.h
index e52eddfdbd..a1c610b69b 100644
--- a/src/network/socket/qtcpsocket.h
+++ b/src/network/socket/qtcpsocket.h
@@ -1,47 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QTCPSOCKET_H
#define QTCPSOCKET_H
#include <QtNetwork/qtnetworkglobal.h>
#include <QtNetwork/qabstractsocket.h>
+#include <QtNetwork/qhostaddress.h>
#include <QtCore/qvariant.h>
QT_BEGIN_NAMESPACE
@@ -56,6 +21,13 @@ public:
explicit QTcpSocket(QObject *parent = nullptr);
virtual ~QTcpSocket();
+#if QT_VERSION < QT_VERSION_CHECK(7,0,0) && !defined(Q_QDOC)
+ // ### Qt7: move into QAbstractSocket
+ using QAbstractSocket::bind;
+ bool bind(QHostAddress::SpecialAddress addr, quint16 port = 0, BindMode mode = DefaultForPlatform)
+ { return bind(QHostAddress(addr), port, mode); }
+#endif
+
protected:
QTcpSocket(QTcpSocketPrivate &dd, QObject *parent = nullptr);
QTcpSocket(QAbstractSocket::SocketType socketType, QTcpSocketPrivate &dd,
diff --git a/src/network/socket/qtcpsocket_p.h b/src/network/socket/qtcpsocket_p.h
index ba1a0aa920..5823342f22 100644
--- a/src/network/socket/qtcpsocket_p.h
+++ b/src/network/socket/qtcpsocket_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QTCPSOCKET_P_H
#define QTCPSOCKET_P_H
diff --git a/src/network/socket/qudpsocket.cpp b/src/network/socket/qudpsocket.cpp
index 9694dfa507..bfeea307b2 100644
--- a/src/network/socket/qudpsocket.cpp
+++ b/src/network/socket/qudpsocket.cpp
@@ -1,42 +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 QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//#define QUDPSOCKET_DEBUG
@@ -418,7 +382,7 @@ qint64 QUdpSocket::writeDatagram(const QNetworkDatagram &datagram)
if (state() == UnconnectedState)
bind();
- qint64 sent = d->socketEngine->writeDatagram(datagram.d->data,
+ qint64 sent = d->socketEngine->writeDatagram(datagram.d->data.constData(),
datagram.d->data.size(),
datagram.d->header);
d->cachedSocketDescriptor = d->socketEngine->socketDescriptor();
@@ -466,6 +430,7 @@ QNetworkDatagram QUdpSocket::receiveDatagram(qint64 maxSize)
qint64 readBytes = d->socketEngine->readDatagram(result.d->data.data(), maxSize, &result.d->header,
QAbstractSocketEngine::WantAll);
d->hasPendingData = false;
+ d->hasPendingDatagram = false;
d->socketEngine->setReadNotificationEnabled(true);
if (readBytes < 0) {
d->setErrorAndEmit(d->socketEngine->error(), d->socketEngine->errorString());
@@ -515,6 +480,7 @@ qint64 QUdpSocket::readDatagram(char *data, qint64 maxSize, QHostAddress *addres
}
d->hasPendingData = false;
+ d->hasPendingDatagram = false;
d->socketEngine->setReadNotificationEnabled(true);
if (readBytes < 0) {
if (readBytes == -2) {
@@ -531,3 +497,5 @@ qint64 QUdpSocket::readDatagram(char *data, qint64 maxSize, QHostAddress *addres
#endif // QT_NO_UDPSOCKET
QT_END_NAMESPACE
+
+#include "moc_qudpsocket.cpp"
diff --git a/src/network/socket/qudpsocket.h b/src/network/socket/qudpsocket.h
index e2ddba1362..3fd1d3710a 100644
--- a/src/network/socket/qudpsocket.h
+++ b/src/network/socket/qudpsocket.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QUDPSOCKET_H
#define QUDPSOCKET_H
@@ -60,6 +24,13 @@ public:
explicit QUdpSocket(QObject *parent = nullptr);
virtual ~QUdpSocket();
+#if QT_VERSION < QT_VERSION_CHECK(7,0,0) && !defined(Q_QDOC)
+ // ### Qt7: move into QAbstractSocket
+ using QAbstractSocket::bind;
+ bool bind(QHostAddress::SpecialAddress addr, quint16 port = 0, BindMode mode = DefaultForPlatform)
+ { return bind(QHostAddress(addr), port, mode); }
+#endif
+
#ifndef QT_NO_NETWORKINTERFACE
bool joinMulticastGroup(const QHostAddress &groupAddress);
bool joinMulticastGroup(const QHostAddress &groupAddress,
diff --git a/src/network/socket/socket.pri b/src/network/socket/socket.pri
deleted file mode 100644
index 67325ac70f..0000000000
--- a/src/network/socket/socket.pri
+++ /dev/null
@@ -1,84 +0,0 @@
-# Qt network socket
-
-HEADERS += socket/qabstractsocketengine_p.h \
- socket/qabstractsocket.h \
- socket/qabstractsocket_p.h \
- socket/qtcpsocket.h \
- socket/qudpsocket.h \
- socket/qtcpserver.h \
- socket/qtcpsocket_p.h \
- socket/qtcpserver_p.h
-
-SOURCES += socket/qabstractsocketengine.cpp \
- socket/qabstractsocket.cpp \
- socket/qtcpsocket.cpp \
- socket/qudpsocket.cpp \
- socket/qtcpserver.cpp
-
-# SOCK5 support.
-
-qtConfig(socks5) {
- HEADERS += \
- socket/qsocks5socketengine_p.h
- SOURCES += \
- socket/qsocks5socketengine.cpp
-}
-
-qtConfig(http) {
- HEADERS += \
- socket/qhttpsocketengine_p.h
- SOURCES += \
- socket/qhttpsocketengine.cpp
-}
-
-# SCTP support.
-
-qtConfig(sctp) {
- HEADERS += socket/qsctpserver.h \
- socket/qsctpserver_p.h \
- socket/qsctpsocket.h \
- socket/qsctpsocket_p.h
-
- SOURCES += socket/qsctpserver.cpp \
- socket/qsctpsocket.cpp
-}
-
-SOURCES += socket/qnativesocketengine.cpp
-HEADERS += socket/qnativesocketengine_p.h
-
-unix {
- SOURCES += socket/qnativesocketengine_unix.cpp
- HEADERS += socket/qnet_unix_p.h
-}
-
-# Suppress deprecation warnings with moc because MS headers have
-# invalid C/C++ code otherwise.
-msvc: QMAKE_MOC_OPTIONS += -D_WINSOCK_DEPRECATED_NO_WARNINGS
-
-win32: SOURCES += socket/qnativesocketengine_win.cpp
-win32: QMAKE_USE_PRIVATE += advapi32
-
-qtConfig(localserver) {
- HEADERS += socket/qlocalserver.h \
- socket/qlocalserver_p.h \
- socket/qlocalsocket.h \
- socket/qlocalsocket_p.h
- SOURCES += socket/qlocalsocket.cpp \
- socket/qlocalserver.cpp
-
- integrity {
- SOURCES += socket/qlocalsocket_tcp.cpp \
- socket/qlocalserver_tcp.cpp
- DEFINES += QT_LOCALSOCKET_TCP
- } else: unix {
- SOURCES += socket/qlocalsocket_unix.cpp \
- socket/qlocalserver_unix.cpp
- } else: win32 {
- SOURCES += socket/qlocalsocket_win.cpp \
- socket/qlocalserver_win.cpp
- }
-}
-
-qtConfig(system-proxies) {
- DEFINES += QT_USE_SYSTEM_PROXIES
-}
diff --git a/src/network/ssl/qasn1element.cpp b/src/network/ssl/qasn1element.cpp
deleted file mode 100644
index 65a0e08961..0000000000
--- a/src/network/ssl/qasn1element.cpp
+++ /dev/null
@@ -1,391 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Jeremy Lainé <jeremy.laine@m4x.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-
-#include "qasn1element_p.h"
-
-#include <QtCore/qdatastream.h>
-#include <QtCore/qdatetime.h>
-#include <QtCore/qlist.h>
-#include <QDebug>
-
-#include <limits>
-
-QT_BEGIN_NAMESPACE
-
-typedef QMap<QByteArray, QByteArray> OidNameMap;
-static OidNameMap createOidMap()
-{
- OidNameMap oids;
- // used by unit tests
- oids.insert(oids.cend(), QByteArrayLiteral("0.9.2342.19200300.100.1.5"), QByteArrayLiteral("favouriteDrink"));
- oids.insert(oids.cend(), QByteArrayLiteral("1.2.840.113549.1.9.1"), QByteArrayLiteral("emailAddress"));
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.6.1.5.5.7.1.1"), QByteArrayLiteral("authorityInfoAccess"));
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.6.1.5.5.7.48.1"), QByteArrayLiteral("OCSP"));
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.6.1.5.5.7.48.2"), QByteArrayLiteral("caIssuers"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.29.14"), QByteArrayLiteral("subjectKeyIdentifier"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.29.15"), QByteArrayLiteral("keyUsage"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.29.17"), QByteArrayLiteral("subjectAltName"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.29.19"), QByteArrayLiteral("basicConstraints"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.29.35"), QByteArrayLiteral("authorityKeyIdentifier"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.10"), QByteArrayLiteral("O"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.11"), QByteArrayLiteral("OU"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.12"), QByteArrayLiteral("title"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.13"), QByteArrayLiteral("description"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.17"), QByteArrayLiteral("postalCode"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.3"), QByteArrayLiteral("CN"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.4"), QByteArrayLiteral("SN"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.41"), QByteArrayLiteral("name"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.42"), QByteArrayLiteral("GN"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.43"), QByteArrayLiteral("initials"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.46"), QByteArrayLiteral("dnQualifier"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.5"), QByteArrayLiteral("serialNumber"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.6"), QByteArrayLiteral("C"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.7"), QByteArrayLiteral("L"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.8"), QByteArrayLiteral("ST"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.9"), QByteArrayLiteral("street"));
- return oids;
-}
-Q_GLOBAL_STATIC_WITH_ARGS(OidNameMap, oidNameMap, (createOidMap()))
-
-QAsn1Element::QAsn1Element(quint8 type, const QByteArray &value)
- : mType(type)
- , mValue(value)
-{
-}
-
-bool QAsn1Element::read(QDataStream &stream)
-{
- // type
- quint8 tmpType;
- stream >> tmpType;
- if (!tmpType)
- return false;
-
- // length
- quint64 length = 0;
- quint8 first;
- stream >> first;
- if (first & 0x80) {
- // long form
- const quint8 bytes = (first & 0x7f);
- if (bytes > 7)
- return false;
-
- quint8 b;
- for (int i = 0; i < bytes; i++) {
- stream >> b;
- length = (length << 8) | b;
- }
- } else {
- // short form
- length = (first & 0x7f);
- }
-
- if (length > quint64(std::numeric_limits<int>::max()))
- return false;
- // value
- QByteArray tmpValue;
- tmpValue.resize(length);
- int count = stream.readRawData(tmpValue.data(), tmpValue.size());
- if (count != int(length))
- return false;
-
- mType = tmpType;
- mValue.swap(tmpValue);
- return true;
-}
-
-bool QAsn1Element::read(const QByteArray &data)
-{
- QDataStream stream(data);
- return read(stream);
-}
-
-void QAsn1Element::write(QDataStream &stream) const
-{
- // type
- stream << mType;
-
- // length
- qint64 length = mValue.size();
- if (length >= 128) {
- // long form
- quint8 encodedLength = 0x80;
- QByteArray ba;
- while (length) {
- ba.prepend(quint8((length & 0xff)));
- length >>= 8;
- encodedLength += 1;
- }
- stream << encodedLength;
- stream.writeRawData(ba.data(), ba.size());
- } else {
- // short form
- stream << quint8(length);
- }
-
- // value
- stream.writeRawData(mValue.data(), mValue.size());
-}
-
-QAsn1Element QAsn1Element::fromBool(bool val)
-{
- return QAsn1Element(QAsn1Element::BooleanType,
- QByteArray(1, val ? 0xff : 0x00));
-}
-
-QAsn1Element QAsn1Element::fromInteger(unsigned int val)
-{
- QAsn1Element elem(QAsn1Element::IntegerType);
- while (val > 127) {
- elem.mValue.prepend(val & 0xff);
- val >>= 8;
- }
- elem.mValue.prepend(val & 0x7f);
- return elem;
-}
-
-QAsn1Element QAsn1Element::fromVector(const QList<QAsn1Element> &items)
-{
- QAsn1Element seq;
- seq.mType = SequenceType;
- QDataStream stream(&seq.mValue, QDataStream::WriteOnly);
- for (auto it = items.cbegin(), end = items.cend(); it != end; ++it)
- it->write(stream);
- return seq;
-}
-
-QAsn1Element QAsn1Element::fromObjectId(const QByteArray &id)
-{
- QAsn1Element elem;
- elem.mType = ObjectIdentifierType;
- const QList<QByteArray> bits = id.split('.');
- Q_ASSERT(bits.size() > 2);
- elem.mValue += quint8((bits[0].toUInt() * 40 + bits[1].toUInt()));
- for (int i = 2; i < bits.size(); ++i) {
- char buffer[std::numeric_limits<unsigned int>::digits / 7 + 2];
- char *pBuffer = buffer + sizeof(buffer);
- *--pBuffer = '\0';
- unsigned int node = bits[i].toUInt();
- *--pBuffer = quint8((node & 0x7f));
- node >>= 7;
- while (node) {
- *--pBuffer = quint8(((node & 0x7f) | 0x80));
- node >>= 7;
- }
- elem.mValue += pBuffer;
- }
- return elem;
-}
-
-bool QAsn1Element::toBool(bool *ok) const
-{
- if (*this == fromBool(true)) {
- if (ok)
- *ok = true;
- return true;
- } else if (*this == fromBool(false)) {
- if (ok)
- *ok = true;
- return false;
- } else {
- if (ok)
- *ok = false;
- return false;
- }
-}
-
-QDateTime QAsn1Element::toDateTime() const
-{
- QDateTime result;
-
- if (mValue.size() != 13 && mValue.size() != 15)
- return result;
-
- // QDateTime::fromString is lenient and accepts +- signs in front
- // of the year; but ASN.1 doesn't allow them.
- const auto isAsciiDigit = [](char c)
- {
- return c >= '0' && c <= '9';
- };
-
- if (!isAsciiDigit(mValue[0]))
- return result;
-
- // Timezone must be present, and UTC
- if (mValue.back() != 'Z')
- return result;
-
- // In addition, check that we only have digits representing the
- // date/time. This should not really be necessary (there's no such
- // thing as negative months/days/etc.); it's a workaround for
- // QTBUG-84349.
- if (!std::all_of(mValue.begin(), mValue.end() - 1, isAsciiDigit))
- return result;
-
- if (mType == UtcTimeType && mValue.size() == 13) {
- result = QDateTime::fromString(QString::fromLatin1(mValue),
- QStringLiteral("yyMMddHHmmsst"));
- if (!result.isValid())
- return result;
-
- Q_ASSERT(result.timeSpec() == Qt::UTC);
-
- QDate date = result.date();
-
- // RFC 2459:
- // Where YY is greater than or equal to 50, the year shall be
- // interpreted as 19YY; and
- //
- // Where YY is less than 50, the year shall be interpreted as 20YY.
- //
- // QDateTime interprets the 'yy' format as 19yy, so we may need to adjust
- // the year (bring it in the [1950, 2049] range).
- if (date.year() < 1950)
- result.setDate(date.addYears(100));
-
- Q_ASSERT(result.date().year() >= 1950);
- Q_ASSERT(result.date().year() <= 2049);
- } else if (mType == GeneralizedTimeType && mValue.size() == 15) {
- result = QDateTime::fromString(QString::fromLatin1(mValue),
- QStringLiteral("yyyyMMddHHmmsst"));
- }
-
- return result;
-}
-
-QMultiMap<QByteArray, QString> QAsn1Element::toInfo() const
-{
- QMultiMap<QByteArray, QString> info;
- QAsn1Element elem;
- QDataStream issuerStream(mValue);
- while (elem.read(issuerStream) && elem.mType == QAsn1Element::SetType) {
- QAsn1Element issuerElem;
- QDataStream setStream(elem.mValue);
- if (issuerElem.read(setStream) && issuerElem.mType == QAsn1Element::SequenceType) {
- const auto elems = issuerElem.toList();
- if (elems.size() == 2) {
- const QByteArray key = elems.front().toObjectName();
- if (!key.isEmpty())
- info.insert(key, elems.back().toString());
- }
- }
- }
- return info;
-}
-
-qint64 QAsn1Element::toInteger(bool *ok) const
-{
- if (mType != QAsn1Element::IntegerType || mValue.isEmpty()) {
- if (ok)
- *ok = false;
- return 0;
- }
-
- // NOTE: negative numbers are not handled
- if (mValue.at(0) & 0x80) {
- if (ok)
- *ok = false;
- return 0;
- }
-
- qint64 value = mValue.at(0) & 0x7f;
- for (int i = 1; i < mValue.size(); ++i)
- value = (value << 8) | quint8(mValue.at(i));
-
- if (ok)
- *ok = true;
- return value;
-}
-
-QList<QAsn1Element> QAsn1Element::toList() const
-{
- QList<QAsn1Element> items;
- if (mType == SequenceType) {
- QAsn1Element elem;
- QDataStream stream(mValue);
- while (elem.read(stream))
- items << elem;
- }
- return items;
-}
-
-QByteArray QAsn1Element::toObjectId() const
-{
- QByteArray key;
- if (mType == ObjectIdentifierType && !mValue.isEmpty()) {
- quint8 b = mValue.at(0);
- key += QByteArray::number(b / 40) + '.' + QByteArray::number (b % 40);
- unsigned int val = 0;
- for (int i = 1; i < mValue.size(); ++i) {
- b = mValue.at(i);
- val = (val << 7) | (b & 0x7f);
- if (!(b & 0x80)) {
- key += '.' + QByteArray::number(val);
- val = 0;
- }
- }
- }
- return key;
-}
-
-QByteArray QAsn1Element::toObjectName() const
-{
- QByteArray key = toObjectId();
- return oidNameMap->value(key, key);
-}
-
-QString QAsn1Element::toString() const
-{
- // Detect embedded NULs and reject
- if (qstrlen(mValue) < uint(mValue.size()))
- return QString();
-
- if (mType == PrintableStringType || mType == TeletexStringType
- || mType == Rfc822NameType || mType == DnsNameType
- || mType == UniformResourceIdentifierType)
- return QString::fromLatin1(mValue, mValue.size());
- if (mType == Utf8StringType)
- return QString::fromUtf8(mValue, mValue.size());
-
- return QString();
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qasn1element_p.h b/src/network/ssl/qasn1element_p.h
deleted file mode 100644
index c0dfc9db7e..0000000000
--- a/src/network/ssl/qasn1element_p.h
+++ /dev/null
@@ -1,188 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Jeremy Lainé <jeremy.laine@m4x.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-
-#ifndef QASN1ELEMENT_P_H
-#define QASN1ELEMENT_P_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.
-//
-
-#include <QtNetwork/private/qtnetworkglobal_p.h>
-#include <QtCore/qdatetime.h>
-#include <QtCore/qmap.h>
-
-QT_BEGIN_NAMESPACE
-
-// General
-#define RSADSI_OID "1.2.840.113549."
-
-#define RSA_ENCRYPTION_OID QByteArrayLiteral(RSADSI_OID "1.1.1")
-#define DSA_ENCRYPTION_OID QByteArrayLiteral("1.2.840.10040.4.1")
-#define EC_ENCRYPTION_OID QByteArrayLiteral("1.2.840.10045.2.1")
-#define DH_ENCRYPTION_OID QByteArrayLiteral(RSADSI_OID "1.3.1")
-
-// These are mostly from the RFC for PKCS#5
-// PKCS#5: https://tools.ietf.org/html/rfc8018#appendix-B
-#define PKCS5_OID RSADSI_OID "1.5."
-// PKCS#12: https://tools.ietf.org/html/rfc7292#appendix-D)
-#define PKCS12_OID RSADSI_OID "1.12."
-
-// -PBES1
-#define PKCS5_MD2_DES_CBC_OID QByteArrayLiteral(PKCS5_OID "1") // Not (yet) implemented
-#define PKCS5_MD2_RC2_CBC_OID QByteArrayLiteral(PKCS5_OID "4") // Not (yet) implemented
-#define PKCS5_MD5_DES_CBC_OID QByteArrayLiteral(PKCS5_OID "3")
-#define PKCS5_MD5_RC2_CBC_OID QByteArrayLiteral(PKCS5_OID "6")
-#define PKCS5_SHA1_DES_CBC_OID QByteArrayLiteral(PKCS5_OID "10")
-#define PKCS5_SHA1_RC2_CBC_OID QByteArrayLiteral(PKCS5_OID "11")
-#define PKCS12_SHA1_RC4_128_OID QByteArrayLiteral(PKCS12_OID "1.1") // Not (yet) implemented
-#define PKCS12_SHA1_RC4_40_OID QByteArrayLiteral(PKCS12_OID "1.2") // Not (yet) implemented
-#define PKCS12_SHA1_3KEY_3DES_CBC_OID QByteArrayLiteral(PKCS12_OID "1.3")
-#define PKCS12_SHA1_2KEY_3DES_CBC_OID QByteArrayLiteral(PKCS12_OID "1.4")
-#define PKCS12_SHA1_RC2_128_CBC_OID QByteArrayLiteral(PKCS12_OID "1.5")
-#define PKCS12_SHA1_RC2_40_CBC_OID QByteArrayLiteral(PKCS12_OID "1.6")
-
-// -PBKDF2
-#define PKCS5_PBKDF2_ENCRYPTION_OID QByteArrayLiteral(PKCS5_OID "12")
-
-// -PBES2
-#define PKCS5_PBES2_ENCRYPTION_OID QByteArrayLiteral(PKCS5_OID "13")
-
-// Digest
-#define DIGEST_ALGORITHM_OID RSADSI_OID "2."
-// -HMAC-SHA-1
-#define HMAC_WITH_SHA1 QByteArrayLiteral(DIGEST_ALGORITHM_OID "7")
-// -HMAC-SHA-2
-#define HMAC_WITH_SHA224 QByteArrayLiteral(DIGEST_ALGORITHM_OID "8")
-#define HMAC_WITH_SHA256 QByteArrayLiteral(DIGEST_ALGORITHM_OID "9")
-#define HMAC_WITH_SHA384 QByteArrayLiteral(DIGEST_ALGORITHM_OID "10")
-#define HMAC_WITH_SHA512 QByteArrayLiteral(DIGEST_ALGORITHM_OID "11")
-#define HMAC_WITH_SHA512_224 QByteArrayLiteral(DIGEST_ALGORITHM_OID "12")
-#define HMAC_WITH_SHA512_256 QByteArrayLiteral(DIGEST_ALGORITHM_OID "13")
-
-// Encryption algorithms
-#define ENCRYPTION_ALGORITHM_OID RSADSI_OID "3."
-#define DES_CBC_ENCRYPTION_OID QByteArrayLiteral("1.3.14.3.2.7")
-#define DES_EDE3_CBC_ENCRYPTION_OID QByteArrayLiteral(ENCRYPTION_ALGORITHM_OID "7")
-#define RC2_CBC_ENCRYPTION_OID QByteArrayLiteral(ENCRYPTION_ALGORITHM_OID "2")
-#define RC5_CBC_ENCRYPTION_OID QByteArrayLiteral(ENCRYPTION_ALGORITHM_OID "9") // Not (yet) implemented
-#define AES_OID "2.16.840.1.101.3.4.1."
-#define AES128_CBC_ENCRYPTION_OID QByteArrayLiteral(AES_OID "2")
-#define AES192_CBC_ENCRYPTION_OID QByteArrayLiteral(AES_OID "22") // Not (yet) implemented
-#define AES256_CBC_ENCRYPTION_OID QByteArrayLiteral(AES_OID "42") // Not (yet) implemented
-
-class Q_AUTOTEST_EXPORT QAsn1Element
-{
-public:
- enum ElementType {
- // universal
- BooleanType = 0x01,
- IntegerType = 0x02,
- BitStringType = 0x03,
- OctetStringType = 0x04,
- NullType = 0x05,
- ObjectIdentifierType = 0x06,
- Utf8StringType = 0x0c,
- PrintableStringType = 0x13,
- TeletexStringType = 0x14,
- UtcTimeType = 0x17,
- GeneralizedTimeType = 0x18,
- SequenceType = 0x30,
- SetType = 0x31,
-
- // GeneralNameTypes
- Rfc822NameType = 0x81,
- DnsNameType = 0x82,
- UniformResourceIdentifierType = 0x86,
- IpAddressType = 0x87,
-
- // context specific
- Context0Type = 0xA0,
- Context1Type = 0xA1,
- Context3Type = 0xA3
- };
-
- explicit QAsn1Element(quint8 type = 0, const QByteArray &value = QByteArray());
- bool read(QDataStream &data);
- bool read(const QByteArray &data);
- void write(QDataStream &data) const;
-
- static QAsn1Element fromBool(bool val);
- static QAsn1Element fromInteger(unsigned int val);
- static QAsn1Element fromVector(const QList<QAsn1Element> &items);
- static QAsn1Element fromObjectId(const QByteArray &id);
-
- bool toBool(bool *ok = nullptr) const;
- QDateTime toDateTime() const;
- QMultiMap<QByteArray, QString> toInfo() const;
- qint64 toInteger(bool *ok = nullptr) const;
- QList<QAsn1Element> toList() const;
- QByteArray toObjectId() const;
- QByteArray toObjectName() const;
- QString toString() const;
-
- quint8 type() const { return mType; }
- QByteArray value() const { return mValue; }
-
- friend inline bool operator==(const QAsn1Element &, const QAsn1Element &);
- friend inline bool operator!=(const QAsn1Element &, const QAsn1Element &);
-
-private:
- quint8 mType;
- QByteArray mValue;
-};
-Q_DECLARE_TYPEINFO(QAsn1Element, Q_MOVABLE_TYPE);
-
-inline bool operator==(const QAsn1Element &e1, const QAsn1Element &e2)
-{ return e1.mType == e2.mType && e1.mValue == e2.mValue; }
-
-inline bool operator!=(const QAsn1Element &e1, const QAsn1Element &e2)
-{ return e1.mType != e2.mType || e1.mValue != e2.mValue; }
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/network/ssl/qdtls.cpp b/src/network/ssl/qdtls.cpp
index af89740898..38ce144c8a 100644
--- a/src/network/ssl/qdtls.cpp
+++ b/src/network/ssl/qdtls.cpp
@@ -1,45 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qsslconfiguration.h"
-#include "qdtls_openssl_p.h"
+#include "qsslsocket_p.h"
#include "qudpsocket.h"
+#include "qsslcipher.h"
#include "qdtls_p.h"
#include "qssl_p.h"
#include "qdtls.h"
@@ -57,7 +22,7 @@
The QDtlsClientVerifier class implements server-side DTLS cookie generation
and verification. Datagram security protocols are highly susceptible to a
- variety of Denial-of-Service attacks. According to \l {https://tools.ietf.org/html/rfc6347#section-4.2.1}{RFC 6347, section 4.2.1},
+ variety of Denial-of-Service attacks. According to \l {RFC 6347, section 4.2.1},
these are two of the more common types of attack:
\list
@@ -70,7 +35,7 @@
which can be quite large, thus flooding the victim machine with datagrams.
\endlist
- As a countermeasure to these attacks, \l {https://tools.ietf.org/html/rfc6347#section-4.2.1}{RFC 6347, section 4.2.1}
+ As a countermeasure to these attacks, \l {RFC 6347, section 4.2.1}
proposes a stateless cookie technique that a server may deploy:
\list
@@ -118,7 +83,7 @@
\note The default secret is shared by all objects of the classes QDtlsClientVerifier
and QDtls. Since this can impose security risks, RFC 6347 recommends to change
- the server's secret frequently. Please see \l {https://tools.ietf.org/html/rfc6347}{RFC 6347, section 4.2.1}
+ the server's secret frequently. Please see \l {RFC 6347, section 4.2.1}
for hints about possible server implementations. Cookie generator parameters
can be set using the class QDtlsClientVerifier::GeneratorParameters and
setCookieGeneratorParameters():
@@ -249,7 +214,7 @@
\warning It's recommended to call shutdown() before destroying the client's QDtls
object if you are planning to re-use the same port number to connect to the
server later. Otherwise, the server may drop incoming ClientHello messages,
- see \l{https://tools.ietf.org/html/rfc6347#page-25}{RFC 6347, section 4.2.8}
+ see \l {RFC 6347, section 4.2.8}
for more details and implementation hints.
If the server does not use QDtlsClientVerifier, it \e must configure its
@@ -337,72 +302,6 @@
QT_BEGIN_NAMESPACE
-QSslConfiguration QDtlsBasePrivate::configuration() const
-{
- auto copyPrivate = new QSslConfigurationPrivate(dtlsConfiguration);
- copyPrivate->ref.storeRelaxed(0); // the QSslConfiguration constructor refs up
- QSslConfiguration copy(copyPrivate);
- copyPrivate->sessionCipher = sessionCipher;
- copyPrivate->sessionProtocol = sessionProtocol;
-
- return copy;
-}
-
-void QDtlsBasePrivate::setConfiguration(const QSslConfiguration &configuration)
-{
- dtlsConfiguration.localCertificateChain = configuration.localCertificateChain();
- dtlsConfiguration.privateKey = configuration.privateKey();
- dtlsConfiguration.ciphers = configuration.ciphers();
- dtlsConfiguration.ellipticCurves = configuration.ellipticCurves();
- dtlsConfiguration.preSharedKeyIdentityHint = configuration.preSharedKeyIdentityHint();
- dtlsConfiguration.dhParams = configuration.diffieHellmanParameters();
- dtlsConfiguration.caCertificates = configuration.caCertificates();
- dtlsConfiguration.peerVerifyDepth = configuration.peerVerifyDepth();
- dtlsConfiguration.peerVerifyMode = configuration.peerVerifyMode();
- dtlsConfiguration.protocol = configuration.protocol();
- dtlsConfiguration.sslOptions = configuration.d->sslOptions;
- dtlsConfiguration.sslSession = configuration.sessionTicket();
- dtlsConfiguration.sslSessionTicketLifeTimeHint = configuration.sessionTicketLifeTimeHint();
- dtlsConfiguration.nextAllowedProtocols = configuration.allowedNextProtocols();
- dtlsConfiguration.nextNegotiatedProtocol = configuration.nextNegotiatedProtocol();
- dtlsConfiguration.nextProtocolNegotiationStatus = configuration.nextProtocolNegotiationStatus();
- dtlsConfiguration.dtlsCookieEnabled = configuration.dtlsCookieVerificationEnabled();
- dtlsConfiguration.allowRootCertOnDemandLoading = configuration.d->allowRootCertOnDemandLoading;
- dtlsConfiguration.backendConfig = configuration.backendConfiguration();
-
- clearDtlsError();
-}
-
-bool QDtlsBasePrivate::setCookieGeneratorParameters(QCryptographicHash::Algorithm alg,
- const QByteArray &key)
-{
- if (!key.size()) {
- setDtlsError(QDtlsError::InvalidInputParameters,
- QDtls::tr("Invalid (empty) secret"));
- return false;
- }
-
- clearDtlsError();
-
- hashAlgorithm = alg;
- secret = key;
-
- return true;
-}
-
-bool QDtlsBasePrivate::isDtlsProtocol(QSsl::SslProtocol protocol)
-{
- switch (protocol) {
- case QSsl::DtlsV1_0:
- case QSsl::DtlsV1_0OrLater:
- case QSsl::DtlsV1_2:
- case QSsl::DtlsV1_2OrLater:
- return true;
- default:
- return false;
- }
-}
-
static QString msgUnsupportedMulticastAddress()
{
return QDtls::tr("Multicast and broadcast addresses are not supported");
@@ -434,22 +333,37 @@ QDtlsClientVerifier::GeneratorParameters::GeneratorParameters(QCryptographicHash
{
}
+QDtlsClientVerifierPrivate::QDtlsClientVerifierPrivate()
+{
+ const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse();
+ if (!tlsBackend) {
+ qCWarning(lcSsl, "No TLS backend is available, cannot verify DTLS client");
+ return;
+ }
+ backend.reset(tlsBackend->createDtlsCookieVerifier());
+ if (!backend.get())
+ qCWarning(lcSsl) << "The backend" << tlsBackend->backendName() << "does not support DTLS cookies";
+}
+
+QDtlsClientVerifierPrivate::~QDtlsClientVerifierPrivate() = default;
+
/*!
Constructs a QDtlsClientVerifier object, \a parent is passed to QObject's
constructor.
*/
QDtlsClientVerifier::QDtlsClientVerifier(QObject *parent)
- : QObject(*new QDtlsClientVerifierOpenSSL, parent)
+ : QObject(*new QDtlsClientVerifierPrivate, parent)
{
Q_D(QDtlsClientVerifier);
- d->mode = QSslSocket::SslServerMode;
- // The default configuration suffices: verifier never does a full
- // handshake and upon verifying a cookie in a client hello message,
- // it reports success.
- auto conf = QSslConfiguration::defaultDtlsConfiguration();
- conf.setPeerVerifyMode(QSslSocket::VerifyNone);
- d->setConfiguration(conf);
+ if (auto *backend = d->backend.get()) {
+ // The default configuration suffices: verifier never does a full
+ // handshake and upon verifying a cookie in a client hello message,
+ // it reports success.
+ auto conf = QSslConfiguration::defaultDtlsConfiguration();
+ conf.setPeerVerifyMode(QSslSocket::VerifyNone);
+ backend->setConfiguration(conf);
+ }
}
/*!
@@ -473,8 +387,10 @@ QDtlsClientVerifier::~QDtlsClientVerifier()
bool QDtlsClientVerifier::setCookieGeneratorParameters(const GeneratorParameters &params)
{
Q_D(QDtlsClientVerifier);
+ if (auto *backend = d->backend.get())
+ return backend->setCookieGeneratorParameters(params);
- return d->setCookieGeneratorParameters(params.hash, params.secret);
+ return false;
}
/*!
@@ -491,7 +407,10 @@ QDtlsClientVerifier::GeneratorParameters QDtlsClientVerifier::cookieGeneratorPar
{
Q_D(const QDtlsClientVerifier);
- return {d->hashAlgorithm, d->secret};
+ if (const auto *backend = d->backend.get())
+ return backend->cookieGeneratorParameters();
+
+ return {};
}
/*!
@@ -514,19 +433,23 @@ bool QDtlsClientVerifier::verifyClient(QUdpSocket *socket, const QByteArray &dgr
{
Q_D(QDtlsClientVerifier);
+ auto *backend = d->backend.get();
+ if (!backend)
+ return false;
+
if (!socket || address.isNull() || !dgram.size()) {
- d->setDtlsError(QDtlsError::InvalidInputParameters,
- tr("A valid UDP socket, non-empty datagram, valid address/port were expected"));
+ backend->setDtlsError(QDtlsError::InvalidInputParameters,
+ tr("A valid UDP socket, non-empty datagram, and valid address/port were expected"));
return false;
}
if (address.isBroadcast() || address.isMulticast()) {
- d->setDtlsError(QDtlsError::InvalidInputParameters,
- msgUnsupportedMulticastAddress());
+ backend->setDtlsError(QDtlsError::InvalidInputParameters,
+ msgUnsupportedMulticastAddress());
return false;
}
- return d->verifyClient(socket, dgram, address, port);
+ return backend->verifyClient(socket, dgram, address, port);
}
/*!
@@ -539,7 +462,10 @@ QByteArray QDtlsClientVerifier::verifiedHello() const
{
Q_D(const QDtlsClientVerifier);
- return d->verifiedClientHello;
+ if (const auto *backend = d->backend.get())
+ return backend->verifiedHello();
+
+ return {};
}
/*!
@@ -551,7 +477,10 @@ QDtlsError QDtlsClientVerifier::dtlsError() const
{
Q_D(const QDtlsClientVerifier);
- return d->errorCode;
+ if (const auto *backend = d->backend.get())
+ return backend->error();
+
+ return QDtlsError::TlsInitializationError;
}
/*!
@@ -561,11 +490,17 @@ QDtlsError QDtlsClientVerifier::dtlsError() const
*/
QString QDtlsClientVerifier::dtlsErrorString() const
{
- Q_D(const QDtlsBase);
+ Q_D(const QDtlsClientVerifier);
+
+ if (const auto *backend = d->backend.get())
+ return backend->errorString();
- return d->errorDescription;
+ return QStringLiteral("No TLS backend is available, no client verification");
}
+QDtlsPrivate::QDtlsPrivate() = default;
+QDtlsPrivate::~QDtlsPrivate() = default;
+
/*!
Creates a QDtls object, \a parent is passed to the QObject constructor.
\a mode is QSslSocket::SslServerMode for a server-side DTLS connection or
@@ -574,11 +509,19 @@ QString QDtlsClientVerifier::dtlsErrorString() const
\sa sslMode(), QSslSocket::SslMode
*/
QDtls::QDtls(QSslSocket::SslMode mode, QObject *parent)
- : QObject(*new QDtlsPrivateOpenSSL, parent)
+ : QObject(*new QDtlsPrivate, parent)
{
Q_D(QDtls);
-
- d->mode = mode;
+ const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse();
+ if (!tlsBackend) {
+ qCWarning(lcSsl, "No TLS backend found, QDtls is unsupported");
+ return;
+ }
+ d->backend.reset(tlsBackend->createDtlsCryptograph(this, mode));
+ if (!d->backend.get()) {
+ qCWarning(lcSsl) << "TLS backend" << tlsBackend->backendName()
+ << "does not support the protocol DTLS";
+ }
setDtlsConfiguration(QSslConfiguration::defaultDtlsConfiguration());
}
@@ -601,29 +544,30 @@ bool QDtls::setPeer(const QHostAddress &address, quint16 port,
{
Q_D(QDtls);
- if (d->handshakeState != HandshakeNotStarted) {
- d->setDtlsError(QDtlsError::InvalidOperation,
- tr("Cannot set peer after handshake started"));
+ auto *backend = d->backend.get();
+ if (!backend)
+ return false;
+
+ if (backend->state() != HandshakeNotStarted) {
+ backend->setDtlsError(QDtlsError::InvalidOperation,
+ tr("Cannot set peer after handshake started"));
return false;
}
if (address.isNull()) {
- d->setDtlsError(QDtlsError::InvalidInputParameters,
- tr("Invalid address"));
+ backend->setDtlsError(QDtlsError::InvalidInputParameters,
+ tr("Invalid address"));
return false;
}
if (address.isBroadcast() || address.isMulticast()) {
- d->setDtlsError(QDtlsError::InvalidInputParameters,
- msgUnsupportedMulticastAddress());
+ backend->setDtlsError(QDtlsError::InvalidInputParameters,
+ msgUnsupportedMulticastAddress());
return false;
}
- d->clearDtlsError();
-
- d->remoteAddress = address;
- d->remotePort = port;
- d->peerVerificationName = verificationName;
+ backend->clearDtlsError();
+ backend->setPeer(address, port, verificationName);
return true;
}
@@ -640,14 +584,18 @@ bool QDtls::setPeerVerificationName(const QString &name)
{
Q_D(QDtls);
- if (d->handshakeState != HandshakeNotStarted) {
- d->setDtlsError(QDtlsError::InvalidOperation,
+ auto *backend = d->backend.get();
+ if (!backend)
+ return false;
+
+ if (backend->state() != HandshakeNotStarted) {
+ backend->setDtlsError(QDtlsError::InvalidOperation,
tr("Cannot set verification name after handshake started"));
return false;
}
- d->clearDtlsError();
- d->peerVerificationName = name;
+ backend->clearDtlsError();
+ backend->setPeerVerificationName(name);
return true;
}
@@ -661,7 +609,10 @@ QHostAddress QDtls::peerAddress() const
{
Q_D(const QDtls);
- return d->remoteAddress;
+ if (const auto *backend = d->backend.get())
+ return backend->peerAddress();
+
+ return {};
}
/*!
@@ -671,9 +622,12 @@ QHostAddress QDtls::peerAddress() const
*/
quint16 QDtls::peerPort() const
{
- Q_D(const QDtlsBase);
+ Q_D(const QDtls);
+
+ if (const auto *backend = d->backend.get())
+ return backend->peerPort();
- return d->remotePort;
+ return 0;
}
/*!
@@ -686,7 +640,10 @@ QString QDtls::peerVerificationName() const
{
Q_D(const QDtls);
- return d->peerVerificationName;
+ if (const auto *backend = d->backend.get())
+ return backend->peerVerificationName();
+
+ return {};
}
/*!
@@ -699,7 +656,10 @@ QSslSocket::SslMode QDtls::sslMode() const
{
Q_D(const QDtls);
- return d->mode;
+ if (const auto *backend = d->backend.get())
+ return backend->cryptographMode();
+
+ return QSslSocket::UnencryptedMode;
}
/*!
@@ -712,7 +672,8 @@ void QDtls::setMtuHint(quint16 mtuHint)
{
Q_D(QDtls);
- d->mtuHint = mtuHint;
+ if (auto *backend = d->backend.get())
+ backend->setDtlsMtuHint(mtuHint);
}
/*!
@@ -724,7 +685,10 @@ quint16 QDtls::mtuHint() const
{
Q_D(const QDtls);
- return d->mtuHint;
+ if (const auto *backend = d->backend.get())
+ return backend->dtlsMtuHint();
+
+ return 0;
}
/*!
@@ -741,7 +705,10 @@ bool QDtls::setCookieGeneratorParameters(const GeneratorParameters &params)
{
Q_D(QDtls);
- return d->setCookieGeneratorParameters(params.hash, params.secret);
+ if (auto *backend = d->backend.get())
+ backend->setCookieGeneratorParameters(params);
+
+ return false;
}
/*!
@@ -759,7 +726,10 @@ QDtls::GeneratorParameters QDtls::cookieGeneratorParameters() const
{
Q_D(const QDtls);
- return {d->hashAlgorithm, d->secret};
+ if (const auto *backend = d->backend.get())
+ return backend->cookieGeneratorParameters();
+
+ return {};
}
/*!
@@ -774,13 +744,17 @@ bool QDtls::setDtlsConfiguration(const QSslConfiguration &configuration)
{
Q_D(QDtls);
- if (d->handshakeState != HandshakeNotStarted) {
- d->setDtlsError(QDtlsError::InvalidOperation,
- tr("Cannot set configuration after handshake started"));
+ auto *backend = d->backend.get();
+ if (!backend)
+ return false;
+
+ if (backend->state() != HandshakeNotStarted) {
+ backend->setDtlsError(QDtlsError::InvalidOperation,
+ tr("Cannot set configuration after handshake started"));
return false;
}
- d->setConfiguration(configuration);
+ backend->setConfiguration(configuration);
return true;
}
@@ -793,8 +767,10 @@ bool QDtls::setDtlsConfiguration(const QSslConfiguration &configuration)
QSslConfiguration QDtls::dtlsConfiguration() const
{
Q_D(const QDtls);
+ if (const auto *backend = d->backend.get())
+ return backend->configuration();
- return d->configuration();
+ return {};
}
/*!
@@ -806,7 +782,10 @@ QDtls::HandshakeState QDtls::handshakeState()const
{
Q_D(const QDtls);
- return d->handshakeState;
+ if (const auto *backend = d->backend.get())
+ return backend->state();
+
+ return QDtls::HandshakeNotStarted;
}
/*!
@@ -832,13 +811,17 @@ bool QDtls::doHandshake(QUdpSocket *socket, const QByteArray &dgram)
{
Q_D(QDtls);
- if (d->handshakeState == HandshakeNotStarted)
+ auto *backend = d->backend.get();
+ if (!backend)
+ return false;
+
+ if (backend->state() == HandshakeNotStarted)
return startHandshake(socket, dgram);
- else if (d->handshakeState == HandshakeInProgress)
+ else if (backend->state() == HandshakeInProgress)
return continueHandshake(socket, dgram);
- d->setDtlsError(QDtlsError::InvalidOperation,
- tr("Cannot start/continue handshake, invalid handshake state"));
+ backend->setDtlsError(QDtlsError::InvalidOperation,
+ tr("Cannot start/continue handshake, invalid handshake state"));
return false;
}
@@ -849,34 +832,38 @@ bool QDtls::startHandshake(QUdpSocket *socket, const QByteArray &datagram)
{
Q_D(QDtls);
+ auto *backend = d->backend.get();
+ if (!backend)
+ return false;
+
if (!socket) {
- d->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
+ backend->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
return false;
}
- if (d->remoteAddress.isNull()) {
- d->setDtlsError(QDtlsError::InvalidOperation,
- tr("To start a handshake you must set peer's address and port first"));
+ if (backend->peerAddress().isNull()) {
+ backend->setDtlsError(QDtlsError::InvalidOperation,
+ tr("To start a handshake you must set peer's address and port first"));
return false;
}
if (sslMode() == QSslSocket::SslServerMode && !datagram.size()) {
- d->setDtlsError(QDtlsError::InvalidInputParameters,
- tr("To start a handshake, DTLS server requires non-empty datagram (client hello)"));
+ backend->setDtlsError(QDtlsError::InvalidInputParameters,
+ tr("To start a handshake, DTLS server requires non-empty datagram (client hello)"));
return false;
}
- if (d->handshakeState != HandshakeNotStarted) {
- d->setDtlsError(QDtlsError::InvalidOperation,
- tr("Cannot start handshake, already done/in progress"));
+ if (backend->state() != HandshakeNotStarted) {
+ backend->setDtlsError(QDtlsError::InvalidOperation,
+ tr("Cannot start handshake, already done/in progress"));
return false;
}
- return d->startHandshake(socket, datagram);
+ return backend->startHandshake(socket, datagram);
}
/*!
- If a timeout occures during the handshake, the handshakeTimeout() signal
+ If a timeout occurs during the handshake, the handshakeTimeout() signal
is emitted. The application must call handleTimeout() to retransmit handshake
messages; handleTimeout() returns \c true if a timeout has occurred, false
otherwise. \a socket must be a valid pointer.
@@ -887,12 +874,16 @@ bool QDtls::handleTimeout(QUdpSocket *socket)
{
Q_D(QDtls);
+ auto *backend = d->backend.get();
+ if (!backend)
+ return false;
+
if (!socket) {
- d->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
+ backend->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
return false;
}
- return d->handleTimeout(socket);
+ return backend->handleTimeout(socket);
}
/*!
@@ -902,19 +893,23 @@ bool QDtls::continueHandshake(QUdpSocket *socket, const QByteArray &datagram)
{
Q_D(QDtls);
+ auto *backend = d->backend.get();
+ if (!backend)
+ return false;
+
if (!socket || !datagram.size()) {
- d->setDtlsError(QDtlsError::InvalidInputParameters,
- tr("A valid QUdpSocket and non-empty datagram are needed to continue the handshake"));
+ backend->setDtlsError(QDtlsError::InvalidInputParameters,
+ tr("A valid QUdpSocket and non-empty datagram are needed to continue the handshake"));
return false;
}
- if (d->handshakeState != HandshakeInProgress) {
- d->setDtlsError(QDtlsError::InvalidOperation,
- tr("Cannot continue handshake, not in InProgress state"));
+ if (backend->state() != HandshakeInProgress) {
+ backend->setDtlsError(QDtlsError::InvalidOperation,
+ tr("Cannot continue handshake, not in InProgress state"));
return false;
}
- return d->continueHandshake(socket, datagram);
+ return backend->continueHandshake(socket, datagram);
}
/*!
@@ -929,18 +924,22 @@ bool QDtls::resumeHandshake(QUdpSocket *socket)
{
Q_D(QDtls);
+ auto *backend = d->backend.get();
+ if (!backend)
+ return false;
+
if (!socket) {
- d->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
+ backend->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
return false;
}
- if (d->handshakeState != PeerVerificationFailed) {
- d->setDtlsError(QDtlsError::InvalidOperation,
- tr("Cannot resume, not in VerificationError state"));
+ if (backend->state() != PeerVerificationFailed) {
+ backend->setDtlsError(QDtlsError::InvalidOperation,
+ tr("Cannot resume, not in VerificationError state"));
return false;
}
- return d->resumeHandshake(socket);
+ return backend->resumeHandshake(socket);
}
/*!
@@ -953,18 +952,22 @@ bool QDtls::abortHandshake(QUdpSocket *socket)
{
Q_D(QDtls);
+ auto *backend = d->backend.get();
+ if (!backend)
+ return false;
+
if (!socket) {
- d->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
+ backend->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
return false;
}
- if (d->handshakeState != PeerVerificationFailed && d->handshakeState != HandshakeInProgress) {
- d->setDtlsError(QDtlsError::InvalidOperation,
- tr("No handshake in progress, nothing to abort"));
+ if (backend->state() != PeerVerificationFailed && backend->state() != HandshakeInProgress) {
+ backend->setDtlsError(QDtlsError::InvalidOperation,
+ tr("No handshake in progress, nothing to abort"));
return false;
}
- d->abortHandshake(socket);
+ backend->abortHandshake(socket);
return true;
}
@@ -979,19 +982,23 @@ bool QDtls::shutdown(QUdpSocket *socket)
{
Q_D(QDtls);
+ auto *backend = d->backend.get();
+ if (!backend)
+ return false;
+
if (!socket) {
- d->setDtlsError(QDtlsError::InvalidInputParameters,
- tr("Invalid (nullptr) socket"));
+ backend->setDtlsError(QDtlsError::InvalidInputParameters,
+ tr("Invalid (nullptr) socket"));
return false;
}
- if (!d->connectionEncrypted) {
- d->setDtlsError(QDtlsError::InvalidOperation,
- tr("Cannot send shutdown alert, not encrypted"));
+ if (!backend->isConnectionEncrypted()) {
+ backend->setDtlsError(QDtlsError::InvalidOperation,
+ tr("Cannot send shutdown alert, not encrypted"));
return false;
}
- d->sendShutdownAlert(socket);
+ backend->sendShutdownAlert(socket);
return true;
}
@@ -1004,7 +1011,11 @@ bool QDtls::isConnectionEncrypted() const
{
Q_D(const QDtls);
- return d->connectionEncrypted;
+
+ if (const auto *backend = d->backend.get())
+ return backend->isConnectionEncrypted();
+
+ return false;
}
/*!
@@ -1023,7 +1034,10 @@ QSslCipher QDtls::sessionCipher() const
{
Q_D(const QDtls);
- return d->sessionCipher;
+ if (const auto *backend = d->backend.get())
+ return backend->dtlsSessionCipher();
+
+ return {};
}
/*!
@@ -1040,7 +1054,10 @@ QSsl::SslProtocol QDtls::sessionProtocol() const
{
Q_D(const QDtls);
- return d->sessionProtocol;
+ if (const auto *backend = d->backend.get())
+ return backend->dtlsSessionProtocol();
+
+ return QSsl::UnknownProtocol;
}
/*!
@@ -1055,18 +1072,22 @@ qint64 QDtls::writeDatagramEncrypted(QUdpSocket *socket, const QByteArray &dgram
{
Q_D(QDtls);
+ auto *backend = d->backend.get();
+ if (!backend)
+ return -1;
+
if (!socket) {
- d->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
+ backend->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
return -1;
}
if (!isConnectionEncrypted()) {
- d->setDtlsError(QDtlsError::InvalidOperation,
- tr("Cannot write a datagram, not in encrypted state"));
+ backend->setDtlsError(QDtlsError::InvalidOperation,
+ tr("Cannot write a datagram, not in encrypted state"));
return -1;
}
- return d->writeDatagramEncrypted(socket, dgram);
+ return backend->writeDatagramEncrypted(socket, dgram);
}
/*!
@@ -1079,21 +1100,25 @@ QByteArray QDtls::decryptDatagram(QUdpSocket *socket, const QByteArray &dgram)
{
Q_D(QDtls);
+ auto *backend = d->backend.get();
+ if (!backend)
+ return {};
+
if (!socket) {
- d->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
+ backend->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
return {};
}
if (!isConnectionEncrypted()) {
- d->setDtlsError(QDtlsError::InvalidOperation,
- tr("Cannot read a datagram, not in encrypted state"));
+ backend->setDtlsError(QDtlsError::InvalidOperation,
+ tr("Cannot read a datagram, not in encrypted state"));
return {};
}
if (!dgram.size())
return {};
- return d->decryptDatagram(socket, dgram);
+ return backend->decryptDatagram(socket, dgram);
}
/*!
@@ -1105,7 +1130,10 @@ QDtlsError QDtls::dtlsError() const
{
Q_D(const QDtls);
- return d->errorCode;
+ if (const auto *backend = d->backend.get())
+ return backend->error();
+
+ return QDtlsError::NoError;
}
/*!
@@ -1118,7 +1146,10 @@ QString QDtls::dtlsErrorString() const
{
Q_D(const QDtls);
- return d->errorDescription;
+ if (const auto *backend = d->backend.get())
+ return backend->errorString();
+
+ return {};
}
/*!
@@ -1131,7 +1162,11 @@ QList<QSslError> QDtls::peerVerificationErrors() const
{
Q_D(const QDtls);
- return d->tlsErrors;
+ if (const auto *backend = d->backend.get())
+ return backend->peerVerificationErrors();
+
+ //return d->tlsErrors;
+ return {};
}
/*!
@@ -1156,7 +1191,10 @@ void QDtls::ignoreVerificationErrors(const QList<QSslError> &errorsToIgnore)
{
Q_D(QDtls);
- d->tlsErrorsToIgnore = errorsToIgnore;
+ if (auto *backend = d->backend.get())
+ backend->ignoreVerificationErrors(errorsToIgnore);
}
QT_END_NAMESPACE
+
+#include "moc_qdtls.cpp"
diff --git a/src/network/ssl/qdtls.h b/src/network/ssl/qdtls.h
index aee8dc0f87..dd24aa219a 100644
--- a/src/network/ssl/qdtls.h
+++ b/src/network/ssl/qdtls.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDTLS_H
#define QDTLS_H
@@ -51,7 +15,7 @@
Q_MOC_INCLUDE(<QtNetwork/QSslPreSharedKeyAuthenticator>)
-#ifndef Q_CLANG_QDOC
+#ifndef Q_QDOC
QT_REQUIRE_CONFIG(dtls);
#endif
diff --git a/src/network/ssl/qdtls_openssl.cpp b/src/network/ssl/qdtls_openssl.cpp
deleted file mode 100644
index c5891390a7..0000000000
--- a/src/network/ssl/qdtls_openssl.cpp
+++ /dev/null
@@ -1,1401 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef NOMINMAX
-#define NOMINMAX
-#endif // NOMINMAX
-#include "private/qnativesocketengine_p.h"
-
-#include "qsslpresharedkeyauthenticator_p.h"
-#include "qsslsocket_openssl_symbols_p.h"
-#include "qsslsocket_openssl_p.h"
-#include "qsslcertificate_p.h"
-#include "qdtls_openssl_p.h"
-#include "qudpsocket.h"
-#include "qssl_p.h"
-
-#include "qmessageauthenticationcode.h"
-#include "qcryptographichash.h"
-
-#include "qdebug.h"
-
-#include <cstring>
-#include <cstddef>
-
-QT_BEGIN_NAMESPACE
-
-#define QT_DTLS_VERBOSE 0
-
-#if QT_DTLS_VERBOSE
-
-#define qDtlsWarning(arg) qWarning(arg)
-#define qDtlsDebug(arg) qDebug(arg)
-
-#else
-
-#define qDtlsWarning(arg)
-#define qDtlsDebug(arg)
-
-#endif // QT_DTLS_VERBOSE
-
-namespace dtlsutil
-{
-
-QByteArray cookie_for_peer(SSL *ssl)
-{
- Q_ASSERT(ssl);
-
- // SSL_get_rbio does not increment the reference count
- BIO *readBIO = q_SSL_get_rbio(ssl);
- if (!readBIO) {
- qCWarning(lcSsl, "No BIO (dgram) found in SSL object");
- return {};
- }
-
- auto listener = static_cast<dtlsopenssl::DtlsState *>(q_BIO_get_app_data(readBIO));
- if (!listener) {
- qCWarning(lcSsl, "BIO_get_app_data returned invalid (nullptr) value");
- return {};
- }
-
- const QHostAddress peerAddress(listener->remoteAddress);
- const quint16 peerPort(listener->remotePort);
- QByteArray peerData;
- if (peerAddress.protocol() == QAbstractSocket::IPv6Protocol) {
- const Q_IPV6ADDR sin6_addr(peerAddress.toIPv6Address());
- peerData.resize(int(sizeof sin6_addr + sizeof peerPort));
- char *dst = peerData.data();
- std::memcpy(dst, &peerPort, sizeof peerPort);
- dst += sizeof peerPort;
- std::memcpy(dst, &sin6_addr, sizeof sin6_addr);
- } else if (peerAddress.protocol() == QAbstractSocket::IPv4Protocol) {
- const quint32 sin_addr(peerAddress.toIPv4Address());
- peerData.resize(int(sizeof sin_addr + sizeof peerPort));
- char *dst = peerData.data();
- std::memcpy(dst, &peerPort, sizeof peerPort);
- dst += sizeof peerPort;
- std::memcpy(dst, &sin_addr, sizeof sin_addr);
- } else {
- Q_UNREACHABLE();
- }
-
- return peerData;
-}
-
-struct FallbackCookieSecret
-{
- FallbackCookieSecret()
- {
- key.resize(32);
- const int status = q_RAND_bytes(reinterpret_cast<unsigned char *>(key.data()),
- key.size());
- if (status <= 0)
- key.clear();
- }
-
- QByteArray key;
-
- Q_DISABLE_COPY_MOVE(FallbackCookieSecret)
-};
-
-QByteArray fallbackSecret()
-{
- static const FallbackCookieSecret generator;
- return generator.key;
-}
-
-int next_timeoutMs(SSL *tlsConnection)
-{
- Q_ASSERT(tlsConnection);
- timeval timeLeft = {};
- q_DTLSv1_get_timeout(tlsConnection, &timeLeft);
- return timeLeft.tv_sec * 1000;
-}
-
-
-void delete_connection(SSL *ssl)
-{
- // The 'deleter' for QSharedPointer<SSL>.
- if (ssl)
- q_SSL_free(ssl);
-}
-
-void delete_BIO_ADDR(BIO_ADDR *bio)
-{
- // A deleter for QSharedPointer<BIO_ADDR>
- if (bio)
- q_BIO_ADDR_free(bio);
-}
-
-void delete_bio_method(BIO_METHOD *method)
-{
- // The 'deleter' for QSharedPointer<BIO_METHOD>.
- if (method)
- q_BIO_meth_free(method);
-}
-
-// The 'deleter' for QScopedPointer<BIO>.
-struct bio_deleter
-{
- static void cleanup(BIO *bio)
- {
- if (bio)
- q_BIO_free(bio);
- }
-};
-
-// The path MTU discovery is non-trivial: it's a mix of getsockopt/setsockopt
-// (IP_MTU/IP6_MTU/IP_MTU_DISCOVER) and fallback MTU values. It's not
-// supported on all platforms, worse so - imposes specific requirements on
-// underlying UDP socket etc. So for now, we either try a user-proposed MTU
-// hint or rely on our own fallback value. As a fallback mtu OpenSSL uses 576
-// for IPv4 and 1280 for IPv6 (RFC 791, RFC 2460). To KIS we use 576. This
-// rather small MTU value does not affect the size that can be read/written
-// by QDtls, only a handshake (which is allowed to fragment).
-enum class MtuGuess : long
-{
- defaultMtu = 576
-};
-
-} // namespace dtlsutil
-
-namespace dtlscallbacks
-{
-
-extern "C" int q_generate_cookie_callback(SSL *ssl, unsigned char *dst,
- unsigned *cookieLength)
-{
- if (!ssl || !dst || !cookieLength) {
- qCWarning(lcSsl,
- "Failed to generate cookie - invalid (nullptr) parameter(s)");
- return 0;
- }
-
- void *generic = q_SSL_get_ex_data(ssl, QSslSocketBackendPrivate::s_indexForSSLExtraData);
- if (!generic) {
- qCWarning(lcSsl, "SSL_get_ex_data returned nullptr, cannot generate cookie");
- return 0;
- }
-
- *cookieLength = 0;
-
- auto dtls = static_cast<dtlsopenssl::DtlsState *>(generic);
- if (!dtls->secret.size())
- return 0;
-
- const QByteArray peerData(dtlsutil::cookie_for_peer(ssl));
- if (!peerData.size())
- return 0;
-
- QMessageAuthenticationCode hmac(dtls->hashAlgorithm, dtls->secret);
- hmac.addData(peerData);
- const QByteArray cookie = hmac.result();
- Q_ASSERT(cookie.size() >= 0);
- // DTLS1_COOKIE_LENGTH is erroneously 256 bytes long, must be 255 - RFC 6347, 4.2.1.
- *cookieLength = qMin(DTLS1_COOKIE_LENGTH - 1, cookie.size());
- std::memcpy(dst, cookie.constData(), *cookieLength);
-
- return 1;
-}
-
-extern "C" int q_verify_cookie_callback(SSL *ssl, const unsigned char *cookie,
- unsigned cookieLength)
-{
- if (!ssl || !cookie || !cookieLength) {
- qCWarning(lcSsl, "Could not verify cookie, invalid (nullptr or zero) parameters");
- return 0;
- }
-
- unsigned char newCookie[DTLS1_COOKIE_LENGTH] = {};
- unsigned newCookieLength = 0;
- if (q_generate_cookie_callback(ssl, newCookie, &newCookieLength) != 1)
- return 0;
-
- return newCookieLength == cookieLength
- && !std::memcmp(cookie, newCookie, cookieLength);
-}
-
-extern "C" int q_X509DtlsCallback(int ok, X509_STORE_CTX *ctx)
-{
- if (!ok) {
- // Store the error and at which depth the error was detected.
- SSL *ssl = static_cast<SSL *>(q_X509_STORE_CTX_get_ex_data(ctx, q_SSL_get_ex_data_X509_STORE_CTX_idx()));
- if (!ssl) {
- qCWarning(lcSsl, "X509_STORE_CTX_get_ex_data returned nullptr, handshake failure");
- return 0;
- }
-
- void *generic = q_SSL_get_ex_data(ssl, QSslSocketBackendPrivate::s_indexForSSLExtraData);
- if (!generic) {
- qCWarning(lcSsl, "SSL_get_ex_data returned nullptr, handshake failure");
- return 0;
- }
-
- auto dtls = static_cast<dtlsopenssl::DtlsState *>(generic);
- dtls->x509Errors.append(QSslErrorEntry::fromStoreContext(ctx));
- }
-
- // Always return 1 (OK) to allow verification to continue. We handle the
- // errors gracefully after collecting all errors, after verification has
- // completed.
- return 1;
-}
-
-extern "C" unsigned q_PSK_client_callback(SSL *ssl, const char *hint, char *identity,
- unsigned max_identity_len, unsigned char *psk,
- unsigned max_psk_len)
-{
- auto *dtls = static_cast<dtlsopenssl::DtlsState *>(q_SSL_get_ex_data(ssl,
- QSslSocketBackendPrivate::s_indexForSSLExtraData));
- if (!dtls)
- return 0;
-
- Q_ASSERT(dtls->dtlsPrivate);
- return dtls->dtlsPrivate->pskClientCallback(hint, identity, max_identity_len, psk, max_psk_len);
-}
-
-extern "C" unsigned q_PSK_server_callback(SSL *ssl, const char *identity, unsigned char *psk,
- unsigned max_psk_len)
-{
- auto *dtls = static_cast<dtlsopenssl::DtlsState *>(q_SSL_get_ex_data(ssl,
- QSslSocketBackendPrivate::s_indexForSSLExtraData));
- if (!dtls)
- return 0;
-
- Q_ASSERT(dtls->dtlsPrivate);
- return dtls->dtlsPrivate->pskServerCallback(identity, psk, max_psk_len);
-}
-
-} // namespace dtlscallbacks
-
-namespace dtlsbio
-{
-
-extern "C" int q_dgram_read(BIO *bio, char *dst, int bytesToRead)
-{
- if (!bio || !dst || bytesToRead <= 0) {
- qCWarning(lcSsl, "invalid input parameter(s)");
- return 0;
- }
-
- q_BIO_clear_retry_flags(bio);
-
- auto dtls = static_cast<dtlsopenssl::DtlsState *>(q_BIO_get_app_data(bio));
- // It's us who set data, if OpenSSL does too, the logic here is wrong
- // then and we have to use BIO_set_app_data then!
- Q_ASSERT(dtls);
- int bytesRead = 0;
- if (dtls->dgram.size()) {
- bytesRead = qMin(dtls->dgram.size(), bytesToRead);
- std::memcpy(dst, dtls->dgram.constData(), bytesRead);
-
- if (!dtls->peeking)
- dtls->dgram = dtls->dgram.mid(bytesRead);
- } else {
- bytesRead = -1;
- }
-
- if (bytesRead <= 0)
- q_BIO_set_retry_read(bio);
-
- return bytesRead;
-}
-
-extern "C" int q_dgram_write(BIO *bio, const char *src, int bytesToWrite)
-{
- if (!bio || !src || bytesToWrite <= 0) {
- qCWarning(lcSsl, "invalid input parameter(s)");
- return 0;
- }
-
- q_BIO_clear_retry_flags(bio);
-
- auto dtls = static_cast<dtlsopenssl::DtlsState *>(q_BIO_get_app_data(bio));
- Q_ASSERT(dtls);
- if (dtls->writeSuppressed) {
- // See the comment in QDtls::startHandshake.
- return bytesToWrite;
- }
-
- QUdpSocket *udpSocket = dtls->udpSocket;
- Q_ASSERT(udpSocket);
-
- const QByteArray dgram(QByteArray::fromRawData(src, bytesToWrite));
- qint64 bytesWritten = -1;
- if (udpSocket->state() == QAbstractSocket::ConnectedState) {
- bytesWritten = udpSocket->write(dgram);
- } else {
- bytesWritten = udpSocket->writeDatagram(dgram, dtls->remoteAddress,
- dtls->remotePort);
- }
-
- if (bytesWritten <= 0)
- q_BIO_set_retry_write(bio);
-
- Q_ASSERT(bytesWritten <= std::numeric_limits<int>::max());
- return int(bytesWritten);
-}
-
-extern "C" int q_dgram_puts(BIO *bio, const char *src)
-{
- if (!bio || !src) {
- qCWarning(lcSsl, "invalid input parameter(s)");
- return 0;
- }
-
- return q_dgram_write(bio, src, int(std::strlen(src)));
-}
-
-extern "C" long q_dgram_ctrl(BIO *bio, int cmd, long num, void *ptr)
-{
- // This is our custom BIO_ctrl. bio.h defines a lot of BIO_CTRL_*
- // and BIO_* constants and BIO_somename macros that expands to BIO_ctrl
- // call with one of those constants as argument. What exactly BIO_ctrl
- // does - depends on the 'cmd' and the type of BIO (so BIO_ctrl does
- // not even have a single well-defined value meaning success or failure).
- // We handle only the most generic commands - the ones documented for
- // BIO_ctrl - and also DGRAM specific ones. And even for them - in most
- // cases we do nothing but report a success or some non-error value.
- // Documents also state: "Source/sink BIOs return an 0 if they do not
- // recognize the BIO_ctrl() operation." - these are covered by 'default'
- // label in the switch-statement below. Debug messages in the switch mean:
- // 1) we got a command that is unexpected for dgram BIO, or:
- // 2) we do not call any function that would lead to OpenSSL using this
- // command.
-
- if (!bio) {
- qDebug(lcSsl, "invalid 'bio' parameter (nullptr)");
- return -1;
- }
-
- auto dtls = static_cast<dtlsopenssl::DtlsState *>(q_BIO_get_app_data(bio));
- Q_ASSERT(dtls);
-
- switch (cmd) {
- // Let's start from the most generic ones, in the order in which they are
- // documented (as BIO_ctrl):
- case BIO_CTRL_RESET:
- // BIO_reset macro.
- // From documentation:
- // "BIO_reset() normally returns 1 for success and 0 or -1 for failure.
- // File BIOs are an exception, they return 0 for success and -1 for
- // failure."
- // We have nothing to reset and we are not file BIO.
- return 1;
- case BIO_C_FILE_SEEK:
- case BIO_C_FILE_TELL:
- qDtlsWarning("Unexpected cmd (BIO_C_FILE_SEEK/BIO_C_FILE_TELL)");
- // These are for BIO_seek, BIO_tell. We are not a file BIO.
- // Non-negative return value means success.
- return 0;
- case BIO_CTRL_FLUSH:
- // BIO_flush, nothing to do, we do not buffer any data.
- // 0 or -1 means error, 1 - success.
- return 1;
- case BIO_CTRL_EOF:
- qDtlsWarning("Unexpected cmd (BIO_CTRL_EOF)");
- // BIO_eof, 1 means EOF read. Makes no sense for us.
- return 0;
- case BIO_CTRL_SET_CLOSE:
- // BIO_set_close with BIO_CLOSE/BIO_NOCLOSE flags. Documented as
- // always returning 1.
- // From the documentation:
- // "Typically BIO_CLOSE is used in a source/sink BIO to indicate that
- // the underlying I/O stream should be closed when the BIO is freed."
- //
- // QUdpSocket we work with is not BIO's business, ignoring.
- return 1;
- case BIO_CTRL_GET_CLOSE:
- // BIO_get_close. No, never, see the comment above.
- return 0;
- case BIO_CTRL_PENDING:
- qDtlsWarning("Unexpected cmd (BIO_CTRL_PENDING)");
- // BIO_pending. Not used by DTLS/OpenSSL (we are not buffering).
- return 0;
- case BIO_CTRL_WPENDING:
- // No, we have nothing buffered.
- return 0;
- // The constants below are not documented as a part BIO_ctrl documentation,
- // but they are also not type-specific.
- case BIO_CTRL_DUP:
- qDtlsWarning("Unexpected cmd (BIO_CTRL_DUP)");
- // BIO_dup_state, not used by DTLS (and socket-related BIOs in general).
- // For some very specific BIO type this 'cmd' would copy some state
- // from 'bio' to (BIO*)'ptr'. 1 means success.
- return 0;
- case BIO_CTRL_SET_CALLBACK:
- qDtlsWarning("Unexpected cmd (BIO_CTRL_SET_CALLBACK)");
- // BIO_set_info_callback. We never call this, OpenSSL does not do this
- // on its own (normally it's used if client code wants to have some
- // debug information, for example, dumping handshake state via
- // BIO_printf from SSL info_callback).
- return 0;
- case BIO_CTRL_GET_CALLBACK:
- qDtlsWarning("Unexpected cmd (BIO_CTRL_GET_CALLBACK)");
- // BIO_get_info_callback. We never call this.
- if (ptr)
- *static_cast<bio_info_cb **>(ptr) = nullptr;
- return 0;
- case BIO_CTRL_SET:
- case BIO_CTRL_GET:
- qDtlsWarning("Unexpected cmd (BIO_CTRL_SET/BIO_CTRL_GET)");
- // Somewhat 'documented' as setting/getting IO type. Not used anywhere
- // except BIO_buffer_get_num_lines (which contradics 'get IO type').
- // Ignoring.
- return 0;
- // DGRAM-specific operation, we have to return some reasonable value
- // (so far, I've encountered only peek mode switching, connect).
- case BIO_CTRL_DGRAM_CONNECT:
- // BIO_ctrl_dgram_connect. Not needed. Our 'dtls' already knows
- // the peer's address/port. Report success though.
- return 1;
- case BIO_CTRL_DGRAM_SET_CONNECTED:
- qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_SET_CONNECTED)");
- // BIO_ctrl_dgram_set_connected. We never call it, OpenSSL does
- // not call it on its own (so normally it's done by client code).
- // Similar to BIO_CTRL_DGRAM_CONNECT, but it also informs the BIO
- // that its UDP socket is connected. We never need it though.
- return -1;
- case BIO_CTRL_DGRAM_SET_RECV_TIMEOUT:
- qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_SET_RECV_TIMEOUT)");
- // Essentially setsockopt with SO_RCVTIMEO, not needed, our sockets
- // are non-blocking.
- return -1;
- case BIO_CTRL_DGRAM_GET_RECV_TIMEOUT:
- qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_GET_RECV_TIMEOUT)");
- // getsockopt with SO_RCVTIMEO, not needed, our sockets are
- // non-blocking. ptr is timeval *.
- return -1;
- case BIO_CTRL_DGRAM_SET_SEND_TIMEOUT:
- qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_SET_SEND_TIMEOUT)");
- // setsockopt, SO_SNDTIMEO, cannot happen.
- return -1;
- case BIO_CTRL_DGRAM_GET_SEND_TIMEOUT:
- qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_GET_SEND_TIMEOUT)");
- // getsockopt, SO_SNDTIMEO, cannot happen.
- return -1;
- case BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP:
- // BIO_dgram_recv_timedout. No, we are non-blocking.
- return 0;
- case BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP:
- // BIO_dgram_send_timedout. No, we are non-blocking.
- return 0;
- case BIO_CTRL_DGRAM_MTU_DISCOVER:
- qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_MTU_DISCOVER)");
- // setsockopt, IP_MTU_DISCOVER/IP6_MTU_DISCOVER, to be done
- // in QUdpSocket instead. OpenSSL never calls it, only client
- // code.
- return 1;
- case BIO_CTRL_DGRAM_QUERY_MTU:
- qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_QUERY_MTU)");
- // To be done in QUdpSocket instead.
- return 1;
- case BIO_CTRL_DGRAM_GET_FALLBACK_MTU:
- qDtlsWarning("Unexpected command *BIO_CTRL_DGRAM_GET_FALLBACK_MTU)");
- // Without SSL_OP_NO_QUERY_MTU set on SSL, OpenSSL can request for
- // fallback MTU after several re-transmissions.
- // Should never happen in our case.
- return long(dtlsutil::MtuGuess::defaultMtu);
- case BIO_CTRL_DGRAM_GET_MTU:
- qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_GET_MTU)");
- return -1;
- case BIO_CTRL_DGRAM_SET_MTU:
- qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_SET_MTU)");
- // Should not happen (we don't call BIO_ctrl with this parameter)
- // and set MTU on SSL instead.
- return -1; // num is mtu and it's a return value meaning success.
- case BIO_CTRL_DGRAM_MTU_EXCEEDED:
- qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_MTU_EXCEEDED)");
- return 0;
- case BIO_CTRL_DGRAM_GET_PEER:
- qDtlsDebug("BIO_CTRL_DGRAM_GET_PEER");
- // BIO_dgram_get_peer. We do not return a real address (DTLS is not
- // using this address), but let's pretend a success.
- switch (dtls->remoteAddress.protocol()) {
- case QAbstractSocket::IPv6Protocol:
- return sizeof(sockaddr_in6);
- case QAbstractSocket::IPv4Protocol:
- return sizeof(sockaddr_in);
- default:
- return -1;
- }
- case BIO_CTRL_DGRAM_SET_PEER:
- // Similar to BIO_CTRL_DGRAM_CONNECTED.
- return 1;
- case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT:
- // DTLSTODO: I'm not sure yet, how it's used by OpenSSL.
- return 1;
- case BIO_CTRL_DGRAM_SET_DONT_FRAG:
- qDtlsDebug("BIO_CTRL_DGRAM_SET_DONT_FRAG");
- // To be done in QUdpSocket, it's about IP_DONTFRAG etc.
- return 1;
- case BIO_CTRL_DGRAM_GET_MTU_OVERHEAD:
- // AFAIK it's 28 for IPv4 and 48 for IPv6, but let's pretend it's 0
- // so that OpenSSL does not start suddenly fragmenting the first
- // client hello (which will result in DTLSv1_listen rejecting it).
- return 0;
- case BIO_CTRL_DGRAM_SET_PEEK_MODE:
- dtls->peeking = num;
- return 1;
- default:;
-#if QT_DTLS_VERBOSE
- qWarning() << "Unexpected cmd (" << cmd << ")";
-#endif
- }
-
- return 0;
-}
-
-extern "C" int q_dgram_create(BIO *bio)
-{
-
- q_BIO_set_init(bio, 1);
- // With a custom BIO you'd normally allocate some implementation-specific
- // data and append it to this new BIO using BIO_set_data. We don't need
- // it and thus q_dgram_destroy below is a noop.
- return 1;
-}
-
-extern "C" int q_dgram_destroy(BIO *bio)
-{
- Q_UNUSED(bio);
- return 1;
-}
-
-const char * const qdtlsMethodName = "qdtlsbio";
-
-} // namespace dtlsbio
-
-namespace dtlsopenssl
-{
-
-bool DtlsState::init(QDtlsBasePrivate *dtlsBase, QUdpSocket *socket,
- const QHostAddress &remote, quint16 port,
- const QByteArray &receivedMessage)
-{
- Q_ASSERT(dtlsBase);
- Q_ASSERT(socket);
-
- if (!tlsContext.data() && !initTls(dtlsBase))
- return false;
-
- udpSocket = socket;
-
- setLinkMtu(dtlsBase);
-
- dgram = receivedMessage;
- remoteAddress = remote;
- remotePort = port;
-
- // SSL_get_rbio does not increment a reference count.
- BIO *bio = q_SSL_get_rbio(tlsConnection.data());
- Q_ASSERT(bio);
- q_BIO_set_app_data(bio, this);
-
- return true;
-}
-
-void DtlsState::reset()
-{
- tlsConnection.reset();
- tlsContext.reset();
-}
-
-bool DtlsState::initTls(QDtlsBasePrivate *dtlsBase)
-{
- if (tlsContext.data())
- return true;
-
- if (!QSslSocket::supportsSsl())
- return false;
-
- if (!initCtxAndConnection(dtlsBase))
- return false;
-
- if (!initBIO(dtlsBase)) {
- tlsConnection.reset();
- tlsContext.reset();
- return false;
- }
-
- return true;
-}
-
-static QString msgFunctionFailed(const char *function)
-{
- //: %1: Some function
- return QDtls::tr("%1 failed").arg(QLatin1String(function));
-}
-
-bool DtlsState::initCtxAndConnection(QDtlsBasePrivate *dtlsBase)
-{
- Q_ASSERT(dtlsBase);
- Q_ASSERT(QSslSocket::supportsSsl());
-
- if (dtlsBase->mode == QSslSocket::UnencryptedMode) {
- dtlsBase->setDtlsError(QDtlsError::TlsInitializationError,
- QDtls::tr("Invalid SslMode, SslServerMode or SslClientMode expected"));
- return false;
- }
-
- if (!QDtlsBasePrivate::isDtlsProtocol(dtlsBase->dtlsConfiguration.protocol)) {
- dtlsBase->setDtlsError(QDtlsError::TlsInitializationError,
- QDtls::tr("Invalid protocol version, DTLS protocol expected"));
- return false;
- }
-
- // Create a deep copy of our configuration
- auto configurationCopy = new QSslConfigurationPrivate(dtlsBase->dtlsConfiguration);
- configurationCopy->ref.storeRelaxed(0); // the QSslConfiguration constructor refs up
-
- // DTLSTODO: check we do not set something DTLS-incompatible there ...
- TlsContext newContext(QSslContext::sharedFromConfiguration(dtlsBase->mode,
- configurationCopy,
- dtlsBase->dtlsConfiguration.allowRootCertOnDemandLoading));
-
- if (newContext->error() != QSslError::NoError) {
- dtlsBase->setDtlsError(QDtlsError::TlsInitializationError, newContext->errorString());
- return false;
- }
-
- TlsConnection newConnection(newContext->createSsl(), dtlsutil::delete_connection);
- if (!newConnection.data()) {
- dtlsBase->setDtlsError(QDtlsError::TlsInitializationError,
- msgFunctionFailed("SSL_new"));
- return false;
- }
-
- const int set = q_SSL_set_ex_data(newConnection.data(),
- QSslSocketBackendPrivate::s_indexForSSLExtraData,
- this);
-
- if (set != 1 && configurationCopy->peerVerifyMode != QSslSocket::VerifyNone) {
- dtlsBase->setDtlsError(QDtlsError::TlsInitializationError,
- msgFunctionFailed("SSL_set_ex_data"));
- return false;
- }
-
- if (dtlsBase->mode == QSslSocket::SslServerMode) {
- if (dtlsBase->dtlsConfiguration.dtlsCookieEnabled)
- q_SSL_set_options(newConnection.data(), SSL_OP_COOKIE_EXCHANGE);
- q_SSL_set_psk_server_callback(newConnection.data(), dtlscallbacks::q_PSK_server_callback);
- } else {
- q_SSL_set_psk_client_callback(newConnection.data(), dtlscallbacks::q_PSK_client_callback);
- }
-
- tlsContext.swap(newContext);
- tlsConnection.swap(newConnection);
-
- return true;
-}
-
-bool DtlsState::initBIO(QDtlsBasePrivate *dtlsBase)
-{
- Q_ASSERT(dtlsBase);
- Q_ASSERT(tlsContext.data() && tlsConnection.data());
-
- BioMethod customMethod(q_BIO_meth_new(BIO_TYPE_DGRAM, dtlsbio::qdtlsMethodName),
- dtlsutil::delete_bio_method);
- if (!customMethod.data()) {
- dtlsBase->setDtlsError(QDtlsError::TlsInitializationError,
- msgFunctionFailed("BIO_meth_new"));
- return false;
- }
-
- BIO_METHOD *biom = customMethod.data();
- q_BIO_meth_set_create(biom, dtlsbio::q_dgram_create);
- q_BIO_meth_set_destroy(biom, dtlsbio::q_dgram_destroy);
- q_BIO_meth_set_read(biom, dtlsbio::q_dgram_read);
- q_BIO_meth_set_write(biom, dtlsbio::q_dgram_write);
- q_BIO_meth_set_puts(biom, dtlsbio::q_dgram_puts);
- q_BIO_meth_set_ctrl(biom, dtlsbio::q_dgram_ctrl);
-
- QScopedPointer<BIO, dtlsutil::bio_deleter> newBio(q_BIO_new(biom));
- BIO *bio = newBio.data();
- if (!bio) {
- dtlsBase->setDtlsError(QDtlsError::TlsInitializationError,
- msgFunctionFailed("BIO_new"));
- return false;
- }
-
- q_SSL_set_bio(tlsConnection.data(), bio, bio);
- newBio.take();
-
- bioMethod.swap(customMethod);
-
- return true;
-}
-
-void DtlsState::setLinkMtu(QDtlsBasePrivate *dtlsBase)
-{
- Q_ASSERT(dtlsBase);
- Q_ASSERT(udpSocket);
- Q_ASSERT(tlsConnection.data());
-
- long mtu = dtlsBase->mtuHint;
- if (!mtu) {
- // If the underlying QUdpSocket was connected, getsockopt with
- // IP_MTU/IP6_MTU can give us some hint:
- bool optionFound = false;
- if (udpSocket->state() == QAbstractSocket::ConnectedState) {
- const QVariant val(udpSocket->socketOption(QAbstractSocket::PathMtuSocketOption));
- if (val.isValid() && val.canConvert<int>())
- mtu = val.toInt(&optionFound);
- }
-
- if (!optionFound || mtu <= 0) {
- // OK, our own initial guess.
- mtu = long(dtlsutil::MtuGuess::defaultMtu);
- }
- }
-
- // For now, we disable this option.
- q_SSL_set_options(tlsConnection.data(), SSL_OP_NO_QUERY_MTU);
-
- q_DTLS_set_link_mtu(tlsConnection.data(), mtu);
-}
-
-} // namespace dtlsopenssl
-
-QDtlsClientVerifierOpenSSL::QDtlsClientVerifierOpenSSL()
-{
- secret = dtlsutil::fallbackSecret();
-}
-
-bool QDtlsClientVerifierOpenSSL::verifyClient(QUdpSocket *socket, const QByteArray &dgram,
- const QHostAddress &address, quint16 port)
-{
- Q_ASSERT(socket);
- Q_ASSERT(dgram.size());
- Q_ASSERT(!address.isNull());
- Q_ASSERT(port);
-
- clearDtlsError();
- verifiedClientHello.clear();
-
- if (!dtls.init(this, socket, address, port, dgram))
- return false;
-
- dtls.secret = secret;
- dtls.hashAlgorithm = hashAlgorithm;
-
- Q_ASSERT(dtls.tlsConnection.data());
- QSharedPointer<BIO_ADDR> peer(q_BIO_ADDR_new(), dtlsutil::delete_BIO_ADDR);
- if (!peer.data()) {
- setDtlsError(QDtlsError::TlsInitializationError,
- QDtlsClientVerifier::tr("BIO_ADDR_new failed, ignoring client hello"));
- return false;
- }
-
- const int ret = q_DTLSv1_listen(dtls.tlsConnection.data(), peer.data());
- if (ret < 0) {
- // Since 1.1 - it's a fatal error (not so in 1.0.2 for non-blocking socket)
- setDtlsError(QDtlsError::TlsFatalError, QSslSocketBackendPrivate::getErrorsFromOpenSsl());
- return false;
- }
-
- if (ret > 0) {
- verifiedClientHello = dgram;
- return true;
- }
-
- return false;
-}
-
-void QDtlsPrivateOpenSSL::TimeoutHandler::start(int hintMs)
-{
- Q_ASSERT(timerId == -1);
- timerId = startTimer(hintMs > 0 ? hintMs : timeoutMs, Qt::PreciseTimer);
-}
-
-void QDtlsPrivateOpenSSL::TimeoutHandler::doubleTimeout()
-{
- if (timeoutMs * 2 < 60000)
- timeoutMs *= 2;
- else
- timeoutMs = 60000;
-}
-
-void QDtlsPrivateOpenSSL::TimeoutHandler::stop()
-{
- if (timerId != -1) {
- killTimer(timerId);
- timerId = -1;
- }
-}
-
-void QDtlsPrivateOpenSSL::TimeoutHandler::timerEvent(QTimerEvent *event)
-{
- Q_UNUSED(event);
- Q_ASSERT(timerId != -1);
-
- killTimer(timerId);
- timerId = -1;
-
- Q_ASSERT(dtlsConnection);
- dtlsConnection->reportTimeout();
-}
-
-QDtlsPrivateOpenSSL::QDtlsPrivateOpenSSL()
-{
- secret = dtlsutil::fallbackSecret();
- dtls.dtlsPrivate = this;
-}
-
-bool QDtlsPrivateOpenSSL::startHandshake(QUdpSocket *socket, const QByteArray &dgram)
-{
- Q_ASSERT(socket);
- Q_ASSERT(handshakeState == QDtls::HandshakeNotStarted);
-
- clearDtlsError();
- connectionEncrypted = false;
-
- if (!dtls.init(this, socket, remoteAddress, remotePort, dgram))
- return false;
-
- if (mode == QSslSocket::SslServerMode && dtlsConfiguration.dtlsCookieEnabled) {
- dtls.secret = secret;
- dtls.hashAlgorithm = hashAlgorithm;
- // Let's prepare the state machine so that message sequence 1 does not
- // surprise DTLS/OpenSSL (such a message would be disregarded as
- // 'stale or future' in SSL_accept otherwise):
- int result = 0;
- QSharedPointer<BIO_ADDR> peer(q_BIO_ADDR_new(), dtlsutil::delete_BIO_ADDR);
- if (!peer.data()) {
- setDtlsError(QDtlsError::TlsInitializationError,
- QDtls::tr("BIO_ADD_new failed, cannot start handshake"));
- return false;
- }
-
- // If it's an invalid/unexpected ClientHello, we don't want to send
- // VerifyClientRequest - it's a job of QDtlsClientVerifier - so we
- // suppress any attempts to write into socket:
- dtls.writeSuppressed = true;
- result = q_DTLSv1_listen(dtls.tlsConnection.data(), peer.data());
- dtls.writeSuppressed = false;
-
- if (result <= 0) {
- setDtlsError(QDtlsError::TlsFatalError,
- QDtls::tr("Cannot start the handshake, verified client hello expected"));
- dtls.reset();
- return false;
- }
- }
-
- handshakeState = QDtls::HandshakeInProgress;
- opensslErrors.clear();
- tlsErrors.clear();
-
- return continueHandshake(socket, dgram);
-}
-
-bool QDtlsPrivateOpenSSL::continueHandshake(QUdpSocket *socket, const QByteArray &dgram)
-{
- Q_ASSERT(socket);
-
- Q_ASSERT(handshakeState == QDtls::HandshakeInProgress);
-
- clearDtlsError();
-
- if (timeoutHandler.data())
- timeoutHandler->stop();
-
- if (!dtls.init(this, socket, remoteAddress, remotePort, dgram))
- return false;
-
- dtls.x509Errors.clear();
-
- int result = 0;
- if (mode == QSslSocket::SslServerMode)
- result = q_SSL_accept(dtls.tlsConnection.data());
- else
- result = q_SSL_connect(dtls.tlsConnection.data());
-
- // DTLSTODO: Investigate/test if it makes sense - QSslSocket can emit
- // peerVerifyError at this point (and thus potentially client code
- // will close the underlying TCP connection immediately), but we are using
- // QUdpSocket, no connection to close, our verification callback returns 1
- // (verified OK) and this probably means OpenSSL has already sent a reply
- // to the server's hello/certificate.
-
- opensslErrors << dtls.x509Errors;
-
- if (result <= 0) {
- const auto code = q_SSL_get_error(dtls.tlsConnection.data(), result);
- switch (code) {
- case SSL_ERROR_WANT_READ:
- case SSL_ERROR_WANT_WRITE:
- // DTLSTODO: to be tested - in principle, if it was the first call to
- // continueHandshake and server for some reason discards the client
- // hello message (even the verified one) - our 'this' will probably
- // forever stay in this strange InProgress state? (the client
- // will dully re-transmit the same hello and we discard it again?)
- // SSL_get_state can provide more information about state
- // machine and we can switch to NotStarted (since we have not
- // replied with our hello ...)
- if (!timeoutHandler.data()) {
- timeoutHandler.reset(new TimeoutHandler);
- timeoutHandler->dtlsConnection = this;
- } else {
- // Back to 1s.
- timeoutHandler->resetTimeout();
- }
-
- timeoutHandler->start();
-
- return true; // The handshake is not yet complete.
- default:
- storePeerCertificates();
- setDtlsError(QDtlsError::TlsFatalError,
- QSslSocketBackendPrivate::msgErrorsDuringHandshake());
- dtls.reset();
- handshakeState = QDtls::HandshakeNotStarted;
- return false;
- }
- }
-
- storePeerCertificates();
- fetchNegotiatedParameters();
-
- const bool doVerifyPeer = dtlsConfiguration.peerVerifyMode == QSslSocket::VerifyPeer
- || (dtlsConfiguration.peerVerifyMode == QSslSocket::AutoVerifyPeer
- && mode == QSslSocket::SslClientMode);
-
- if (!doVerifyPeer || verifyPeer() || tlsErrorsWereIgnored()) {
- connectionEncrypted = true;
- handshakeState = QDtls::HandshakeComplete;
- return true;
- }
-
- setDtlsError(QDtlsError::PeerVerificationError, QDtls::tr("Peer verification failed"));
- handshakeState = QDtls::PeerVerificationFailed;
- return false;
-}
-
-
-bool QDtlsPrivateOpenSSL::handleTimeout(QUdpSocket *socket)
-{
- Q_ASSERT(socket);
-
- Q_ASSERT(timeoutHandler.data());
- Q_ASSERT(dtls.tlsConnection.data());
-
- clearDtlsError();
-
- dtls.udpSocket = socket;
-
- if (q_DTLSv1_handle_timeout(dtls.tlsConnection.data()) > 0) {
- timeoutHandler->doubleTimeout();
- timeoutHandler->start();
- } else {
- timeoutHandler->start(dtlsutil::next_timeoutMs(dtls.tlsConnection.data()));
- }
-
- return true;
-}
-
-bool QDtlsPrivateOpenSSL::resumeHandshake(QUdpSocket *socket)
-{
- Q_UNUSED(socket);
- Q_ASSERT(socket);
- Q_ASSERT(handshakeState == QDtls::PeerVerificationFailed);
-
- clearDtlsError();
-
- if (tlsErrorsWereIgnored()) {
- handshakeState = QDtls::HandshakeComplete;
- connectionEncrypted = true;
- tlsErrors.clear();
- tlsErrorsToIgnore.clear();
- return true;
- }
-
- return false;
-}
-
-void QDtlsPrivateOpenSSL::abortHandshake(QUdpSocket *socket)
-{
- Q_ASSERT(socket);
- Q_ASSERT(handshakeState == QDtls::PeerVerificationFailed
- || handshakeState == QDtls::HandshakeInProgress);
-
- clearDtlsError();
-
- if (handshakeState == QDtls::PeerVerificationFailed) {
- // Yes, while peer verification failed, we were actually encrypted.
- // Let's play it nice - inform our peer about connection shut down.
- sendShutdownAlert(socket);
- } else {
- resetDtls();
- }
-}
-
-void QDtlsPrivateOpenSSL::sendShutdownAlert(QUdpSocket *socket)
-{
- Q_ASSERT(socket);
-
- clearDtlsError();
-
- if (connectionEncrypted && !connectionWasShutdown) {
- dtls.udpSocket = socket;
- Q_ASSERT(dtls.tlsConnection.data());
- q_SSL_shutdown(dtls.tlsConnection.data());
- }
-
- resetDtls();
-}
-
-qint64 QDtlsPrivateOpenSSL::writeDatagramEncrypted(QUdpSocket *socket,
- const QByteArray &dgram)
-{
- Q_ASSERT(socket);
- Q_ASSERT(dtls.tlsConnection.data());
- Q_ASSERT(connectionEncrypted);
-
- clearDtlsError();
-
- dtls.udpSocket = socket;
- const int written = q_SSL_write(dtls.tlsConnection.data(),
- dgram.constData(), dgram.size());
- if (written > 0)
- return written;
-
- const unsigned long errorCode = q_ERR_get_error();
- if (!dgram.size() && errorCode == SSL_ERROR_NONE) {
- // With OpenSSL <= 1.1 this can happen. For example, DTLS client
- // tries to reconnect (while re-using the same address/port) -
- // DTLS server drops a message with unexpected epoch but says - no
- // error. We leave to client code to resolve such problems until
- // OpenSSL provides something better.
- return 0;
- }
-
- switch (errorCode) {
- case SSL_ERROR_WANT_WRITE:
- case SSL_ERROR_WANT_READ:
- // We do not set any error/description ... a user can probably re-try
- // sending a datagram.
- break;
- case SSL_ERROR_ZERO_RETURN:
- connectionWasShutdown = true;
- setDtlsError(QDtlsError::TlsFatalError, QDtls::tr("The DTLS connection has been closed"));
- handshakeState = QDtls::HandshakeNotStarted;
- dtls.reset();
- break;
- case SSL_ERROR_SYSCALL:
- case SSL_ERROR_SSL:
- default:
- // DTLSTODO: we don't know yet what to do. Tests needed - probably,
- // some errors can be just ignored (it's UDP, not TCP after all).
- // Unlike QSslSocket we do not abort though.
- QString description(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
- if (socket->error() != QAbstractSocket::UnknownSocketError && description.isEmpty()) {
- setDtlsError(QDtlsError::UnderlyingSocketError, socket->errorString());
- } else {
- setDtlsError(QDtlsError::TlsFatalError,
- QDtls::tr("Error while writing: %1").arg(description));
- }
- }
-
- return -1;
-}
-
-QByteArray QDtlsPrivateOpenSSL::decryptDatagram(QUdpSocket *socket, const QByteArray &tlsdgram)
-{
- Q_ASSERT(socket);
- Q_ASSERT(tlsdgram.size());
-
- Q_ASSERT(dtls.tlsConnection.data());
- Q_ASSERT(connectionEncrypted);
-
- dtls.dgram = tlsdgram;
- dtls.udpSocket = socket;
-
- clearDtlsError();
-
- QByteArray dgram;
- dgram.resize(tlsdgram.size());
- const int read = q_SSL_read(dtls.tlsConnection.data(), dgram.data(),
- dgram.size());
-
- if (read > 0) {
- dgram.resize(read);
- return dgram;
- }
-
- dgram.clear();
- unsigned long errorCode = q_ERR_get_error();
- if (errorCode == SSL_ERROR_NONE) {
- const int shutdown = q_SSL_get_shutdown(dtls.tlsConnection.data());
- if (shutdown & SSL_RECEIVED_SHUTDOWN)
- errorCode = SSL_ERROR_ZERO_RETURN;
- else
- return dgram;
- }
-
- switch (errorCode) {
- case SSL_ERROR_WANT_READ:
- case SSL_ERROR_WANT_WRITE:
- return dgram;
- case SSL_ERROR_ZERO_RETURN:
- // "The connection was shut down cleanly" ... hmm, whatever,
- // needs testing (DTLSTODO).
- connectionWasShutdown = true;
- setDtlsError(QDtlsError::RemoteClosedConnectionError,
- QDtls::tr("The DTLS connection has been shutdown"));
- dtls.reset();
- connectionEncrypted = false;
- handshakeState = QDtls::HandshakeNotStarted;
- return dgram;
- case SSL_ERROR_SYSCALL: // some IO error
- case SSL_ERROR_SSL: // error in the SSL library
- // DTLSTODO: Apparently, some errors can be ignored, for example,
- // ECONNRESET etc. This all needs a lot of testing!!!
- default:
- setDtlsError(QDtlsError::TlsNonFatalError,
- QDtls::tr("Error while reading: %1")
- .arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl()));
- return dgram;
- }
-}
-
-unsigned QDtlsPrivateOpenSSL::pskClientCallback(const char *hint, char *identity,
- unsigned max_identity_len,
- unsigned char *psk,
- unsigned max_psk_len)
-{
- // The code below is taken (with some modifications) from qsslsocket_openssl
- // - alas, we cannot simply re-use it, it's in QSslSocketPrivate.
-
- Q_Q(QDtls);
-
- {
- QSslPreSharedKeyAuthenticator authenticator;
- // Fill in some read-only fields (for client code)
- if (hint) {
- identityHint.clear();
- identityHint.append(hint);
- // From the original code in QSslSocket:
- // "it's NULL terminated, but do not include the NULL" == this fromRawData(ptr/size).
- authenticator.d->identityHint = QByteArray::fromRawData(identityHint.constData(),
- int(std::strlen(hint)));
- }
-
- authenticator.d->maximumIdentityLength = int(max_identity_len) - 1; // needs to be NULL terminated
- authenticator.d->maximumPreSharedKeyLength = int(max_psk_len);
-
- pskAuthenticator.swap(authenticator);
- }
-
- // Let the client provide the remaining bits...
- emit q->pskRequired(&pskAuthenticator);
-
- // No PSK set? Return now to make the handshake fail
- if (pskAuthenticator.preSharedKey().isEmpty())
- return 0;
-
- // Copy data back into OpenSSL
- const int identityLength = qMin(pskAuthenticator.identity().length(),
- pskAuthenticator.maximumIdentityLength());
- std::memcpy(identity, pskAuthenticator.identity().constData(), identityLength);
- identity[identityLength] = 0;
-
- const int pskLength = qMin(pskAuthenticator.preSharedKey().length(),
- pskAuthenticator.maximumPreSharedKeyLength());
- std::memcpy(psk, pskAuthenticator.preSharedKey().constData(), pskLength);
-
- return pskLength;
-}
-
-unsigned QDtlsPrivateOpenSSL::pskServerCallback(const char *identity, unsigned char *psk,
- unsigned max_psk_len)
-{
- Q_Q(QDtls);
-
- {
- QSslPreSharedKeyAuthenticator authenticator;
- // Fill in some read-only fields (for the user)
- authenticator.d->identityHint = dtlsConfiguration.preSharedKeyIdentityHint;
- authenticator.d->identity = identity;
- authenticator.d->maximumIdentityLength = 0; // user cannot set an identity
- authenticator.d->maximumPreSharedKeyLength = int(max_psk_len);
-
- pskAuthenticator.swap(authenticator);
- }
-
- // Let the client provide the remaining bits...
- emit q->pskRequired(&pskAuthenticator);
-
- // No PSK set? Return now to make the handshake fail
- if (pskAuthenticator.preSharedKey().isEmpty())
- return 0;
-
- // Copy data back into OpenSSL
- const int pskLength = qMin(pskAuthenticator.preSharedKey().length(),
- pskAuthenticator.maximumPreSharedKeyLength());
-
- std::memcpy(psk, pskAuthenticator.preSharedKey().constData(), pskLength);
-
- return pskLength;
-}
-
-// The definition is located in qsslsocket_openssl.cpp.
-QSslError _q_OpenSSL_to_QSslError(int errorCode, const QSslCertificate &cert);
-
-bool QDtlsPrivateOpenSSL::verifyPeer()
-{
- // DTLSTODO: Windows-specific code for CA fetcher is not here yet.
- QList<QSslError> errors;
-
- // Check the whole chain for blacklisting (including root, as we check for
- // subjectInfo and issuer)
- for (const QSslCertificate &cert : qAsConst(dtlsConfiguration.peerCertificateChain)) {
- if (QSslCertificatePrivate::isBlacklisted(cert))
- errors << QSslError(QSslError::CertificateBlacklisted, cert);
- }
-
- if (dtlsConfiguration.peerCertificate.isNull()) {
- errors << QSslError(QSslError::NoPeerCertificate);
- } else if (mode == QSslSocket::SslClientMode) {
- // Check the peer certificate itself. First try the subject's common name
- // (CN) as a wildcard, then try all alternate subject name DNS entries the
- // same way.
-
- // QSslSocket has a rather twisted logic: if verificationPeerName
- // is empty, we call QAbstractSocket::peerName(), which returns
- // either peerName (can be set by setPeerName) or host name
- // (can be set as a result of connectToHost).
- QString name = peerVerificationName;
- if (name.isEmpty()) {
- Q_ASSERT(dtls.udpSocket);
- name = dtls.udpSocket->peerName();
- }
-
- if (!QSslSocketPrivate::isMatchingHostname(dtlsConfiguration.peerCertificate, name))
- errors << QSslError(QSslError::HostNameMismatch, dtlsConfiguration.peerCertificate);
- }
-
- // Translate errors from the error list into QSslErrors
- errors.reserve(errors.size() + opensslErrors.size());
- for (const auto &error : qAsConst(opensslErrors)) {
- errors << _q_OpenSSL_to_QSslError(error.code,
- dtlsConfiguration.peerCertificateChain.value(error.depth));
- }
-
- tlsErrors = errors;
- return tlsErrors.isEmpty();
-}
-
-void QDtlsPrivateOpenSSL::storePeerCertificates()
-{
- Q_ASSERT(dtls.tlsConnection.data());
- // Store the peer certificate and chain. For clients, the peer certificate
- // chain includes the peer certificate; for servers, it doesn't. Both the
- // peer certificate and the chain may be empty if the peer didn't present
- // any certificate.
- X509 *x509 = q_SSL_get_peer_certificate(dtls.tlsConnection.data());
- dtlsConfiguration.peerCertificate = QSslCertificatePrivate::QSslCertificate_from_X509(x509);
- q_X509_free(x509);
- if (dtlsConfiguration.peerCertificateChain.isEmpty()) {
- auto stack = q_SSL_get_peer_cert_chain(dtls.tlsConnection.data());
- dtlsConfiguration.peerCertificateChain = QSslSocketBackendPrivate::STACKOFX509_to_QSslCertificates(stack);
- if (!dtlsConfiguration.peerCertificate.isNull() && mode == QSslSocket::SslServerMode)
- dtlsConfiguration.peerCertificateChain.prepend(dtlsConfiguration.peerCertificate);
- }
-}
-
-bool QDtlsPrivateOpenSSL::tlsErrorsWereIgnored() const
-{
- // check whether the errors we got are all in the list of expected errors
- // (applies only if the method QDtlsConnection::ignoreTlsErrors(const
- // QList<QSslError> &errors) was called)
- for (const QSslError &error : tlsErrors) {
- if (!tlsErrorsToIgnore.contains(error))
- return false;
- }
-
- return !tlsErrorsToIgnore.empty();
-}
-
-void QDtlsPrivateOpenSSL::fetchNegotiatedParameters()
-{
- Q_ASSERT(dtls.tlsConnection.data());
-
- const SSL_CIPHER *cipher = q_SSL_get_current_cipher(dtls.tlsConnection.data());
- sessionCipher = cipher ? QSslSocketBackendPrivate::QSslCipher_from_SSL_CIPHER(cipher)
- : QSslCipher();
-
- // Note: cipher's protocol version will be reported as either TLS 1.0 or
- // TLS 1.2, that's how it's set by OpenSSL (and that's what they are?).
-
- switch (q_SSL_version(dtls.tlsConnection.data())) {
- case DTLS1_VERSION:
- sessionProtocol = QSsl::DtlsV1_0;
- break;
- case DTLS1_2_VERSION:
- sessionProtocol = QSsl::DtlsV1_2;
- break;
- default:
- qCWarning(lcSsl, "unknown protocol version");
- sessionProtocol = QSsl::UnknownProtocol;
- }
-}
-
-void QDtlsPrivateOpenSSL::reportTimeout()
-{
- Q_Q(QDtls);
-
- emit q->handshakeTimeout();
-}
-
-void QDtlsPrivateOpenSSL::resetDtls()
-{
- dtls.reset();
- connectionEncrypted = false;
- tlsErrors.clear();
- tlsErrorsToIgnore.clear();
- dtlsConfiguration.peerCertificate.clear();
- dtlsConfiguration.peerCertificateChain.clear();
- connectionWasShutdown = false;
- handshakeState = QDtls::HandshakeNotStarted;
- sessionCipher = {};
- sessionProtocol = QSsl::UnknownProtocol;
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qdtls_openssl_p.h b/src/network/ssl/qdtls_openssl_p.h
deleted file mode 100644
index b1fcc99d5a..0000000000
--- a/src/network/ssl/qdtls_openssl_p.h
+++ /dev/null
@@ -1,212 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QDTLS_OPENSSL_P_H
-#define QDTLS_OPENSSL_P_H
-
-#include <private/qtnetworkglobal_p.h>
-
-#include <QtCore/qglobal.h>
-
-#include <openssl/ossl_typ.h>
-
-#include "qdtls_p.h"
-
-#include <private/qsslcontext_openssl_p.h>
-#include <private/qsslsocket_openssl_p.h>
-
-#include <QtNetwork/qsslpresharedkeyauthenticator.h>
-#include <QtNetwork/qhostaddress.h>
-
-#include <QtCore/qbytearray.h>
-#include <QtCore/qcryptographichash.h>
-#include <QtCore/qlist.h>
-#include <QtCore/qsharedpointer.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.
-//
-
-QT_REQUIRE_CONFIG(openssl);
-QT_REQUIRE_CONFIG(dtls);
-
-QT_BEGIN_NAMESPACE
-
-class QDtlsPrivateOpenSSL;
-class QUdpSocket;
-
-namespace dtlsopenssl
-{
-
-class DtlsState
-{
-public:
- // Note, bioMethod _must_ outlive BIOs it was used to create. Thus
- // the order of declarations here matters.
- using BioMethod = QSharedPointer<BIO_METHOD>;
- BioMethod bioMethod;
-
- using TlsContext = QSharedPointer<QSslContext>;
- TlsContext tlsContext;
-
- using TlsConnection = QSharedPointer<SSL>;
- TlsConnection tlsConnection;
-
- QByteArray dgram;
-
- QHostAddress remoteAddress;
- quint16 remotePort = 0;
-
- QList<QSslErrorEntry> x509Errors;
-
- long peeking = false;
- QUdpSocket *udpSocket = nullptr;
- bool writeSuppressed = false;
-
- bool init(QDtlsBasePrivate *dtlsBase, QUdpSocket *socket,
- const QHostAddress &remote, quint16 port,
- const QByteArray &receivedMessage);
-
- void reset();
-
- QDtlsPrivateOpenSSL *dtlsPrivate = nullptr;
- QByteArray secret;
-
-#ifdef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
- QCryptographicHash::Algorithm hashAlgorithm = QCryptographicHash::Sha1;
-#else
- QCryptographicHash::Algorithm hashAlgorithm = QCryptographicHash::Sha256;
-#endif
-
-private:
-
- bool initTls(QDtlsBasePrivate *dtlsBase);
- bool initCtxAndConnection(QDtlsBasePrivate *dtlsBase);
- bool initBIO(QDtlsBasePrivate *dtlsBase);
- void setLinkMtu(QDtlsBasePrivate *dtlsBase);
-};
-
-} // namespace dtlsopenssl
-
-class QDtlsClientVerifierOpenSSL : public QDtlsClientVerifierPrivate
-{
-public:
-
- QDtlsClientVerifierOpenSSL();
-
- bool verifyClient(QUdpSocket *socket, const QByteArray &dgram,
- const QHostAddress &address, quint16 port) override;
-
-private:
- dtlsopenssl::DtlsState dtls;
-};
-
-class QDtlsPrivateOpenSSL : public QDtlsPrivate
-{
-public:
- QDtlsPrivateOpenSSL();
-
- bool startHandshake(QUdpSocket *socket, const QByteArray &datagram) override;
- bool continueHandshake(QUdpSocket *socket, const QByteArray &datagram) override;
- bool resumeHandshake(QUdpSocket *socket) override;
- void abortHandshake(QUdpSocket *socket) override;
- bool handleTimeout(QUdpSocket *socket) override;
- void sendShutdownAlert(QUdpSocket *socket) override;
-
- qint64 writeDatagramEncrypted(QUdpSocket *socket, const QByteArray &datagram) override;
- QByteArray decryptDatagram(QUdpSocket *socket, const QByteArray &tlsdgram) override;
-
- unsigned pskClientCallback(const char *hint, char *identity, unsigned max_identity_len,
- unsigned char *psk, unsigned max_psk_len);
- unsigned pskServerCallback(const char *identity, unsigned char *psk,
- unsigned max_psk_len);
-
-private:
-
- bool verifyPeer();
- void storePeerCertificates();
- bool tlsErrorsWereIgnored() const;
- void fetchNegotiatedParameters();
- void reportTimeout();
- void resetDtls();
-
- QList<QSslErrorEntry> opensslErrors;
- dtlsopenssl::DtlsState dtls;
-
- // We have to externally handle timeouts since we have non-blocking
- // sockets and OpenSSL(DTLS) with non-blocking UDP sockets does not
- // know if a timeout has occurred.
- struct TimeoutHandler : QObject
- {
- TimeoutHandler() = default;
-
- void start(int hintMs = 0);
- void doubleTimeout();
- void resetTimeout() {timeoutMs = 1000;}
- void stop();
- void timerEvent(QTimerEvent *event) override;
-
- int timerId = -1;
- int timeoutMs = 1000;
-
- QDtlsPrivateOpenSSL *dtlsConnection = nullptr;
- };
-
- // We will initialize it 'lazily', just in case somebody wants to move
- // QDtls to another thread.
- QScopedPointer<TimeoutHandler> timeoutHandler;
- bool connectionWasShutdown = false;
- QSslPreSharedKeyAuthenticator pskAuthenticator;
- QByteArray identityHint;
-
- Q_DECLARE_PUBLIC(QDtls)
-};
-
-
-
-QT_END_NAMESPACE
-
-#endif // QDTLS_OPENSSL_P_H
diff --git a/src/network/ssl/qdtls_p.h b/src/network/ssl/qdtls_p.h
index be54c0e06e..5d519e2344 100644
--- a/src/network/ssl/qdtls_p.h
+++ b/src/network/ssl/qdtls_p.h
@@ -1,62 +1,14 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDTLS_P_H
#define QDTLS_P_H
#include <private/qtnetworkglobal_p.h>
-#include "qdtls.h"
-
-#include <private/qsslconfiguration_p.h>
-#include <private/qobject_p.h>
-
-#include <QtNetwork/qabstractsocket.h>
-#include <QtNetwork/qhostaddress.h>
-#include <QtNetwork/qsslsocket.h>
-#include <QtNetwork/qsslcipher.h>
-#include <QtNetwork/qssl.h>
-
-#include <QtCore/qcryptographichash.h>
-#include <QtCore/qbytearray.h>
-#include <QtCore/qstring.h>
+#include "qtlsbackend_p.h"
+#include <QtCore/private/qobject_p.h>
//
// W A R N I N G
// -------------
@@ -74,80 +26,20 @@ QT_BEGIN_NAMESPACE
class QHostAddress;
-class QDtlsBasePrivate : public QObjectPrivate
-{
-public:
-
- void setDtlsError(QDtlsError code, const QString &description)
- {
- errorCode = code;
- errorDescription = description;
- }
-
- void clearDtlsError()
- {
- errorCode = QDtlsError::NoError;
- errorDescription.clear();
- }
-
- void setConfiguration(const QSslConfiguration &configuration);
- QSslConfiguration configuration() const;
-
- bool setCookieGeneratorParameters(QCryptographicHash::Algorithm alg,
- const QByteArray &secret);
-
- static bool isDtlsProtocol(QSsl::SslProtocol protocol);
-
- QHostAddress remoteAddress;
- quint16 remotePort = 0;
- quint16 mtuHint = 0;
-
- QDtlsError errorCode = QDtlsError::NoError;
- QString errorDescription;
- QSslConfigurationPrivate dtlsConfiguration;
- QSslSocket::SslMode mode = QSslSocket::SslClientMode;
- QSslCipher sessionCipher;
- QSsl::SslProtocol sessionProtocol = QSsl::UnknownProtocol;
- QString peerVerificationName;
- QByteArray secret;
-
-#ifdef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
- QCryptographicHash::Algorithm hashAlgorithm = QCryptographicHash::Sha1;
-#else
- QCryptographicHash::Algorithm hashAlgorithm = QCryptographicHash::Sha256;
-#endif
-};
-
-class QDtlsClientVerifierPrivate : public QDtlsBasePrivate
+class QDtlsClientVerifierPrivate : public QObjectPrivate
{
public:
-
- QByteArray verifiedClientHello;
-
- virtual bool verifyClient(QUdpSocket *socket, const QByteArray &dgram,
- const QHostAddress &address, quint16 port) = 0;
+ QDtlsClientVerifierPrivate();
+ ~QDtlsClientVerifierPrivate();
+ std::unique_ptr<QTlsPrivate::DtlsCookieVerifier> backend;
};
-class QDtlsPrivate : public QDtlsBasePrivate
+class QDtlsPrivate : public QObjectPrivate
{
public:
-
- virtual bool startHandshake(QUdpSocket *socket, const QByteArray &dgram) = 0;
- virtual bool handleTimeout(QUdpSocket *socket) = 0;
- virtual bool continueHandshake(QUdpSocket *socket, const QByteArray &dgram) = 0;
- virtual bool resumeHandshake(QUdpSocket *socket) = 0;
- virtual void abortHandshake(QUdpSocket *socket) = 0;
- virtual void sendShutdownAlert(QUdpSocket *socket) = 0;
-
- virtual qint64 writeDatagramEncrypted(QUdpSocket *socket, const QByteArray &dgram) = 0;
- virtual QByteArray decryptDatagram(QUdpSocket *socket, const QByteArray &dgram) = 0;
-
- QDtls::HandshakeState handshakeState = QDtls::HandshakeNotStarted;
-
- QList<QSslError> tlsErrors;
- QList<QSslError> tlsErrorsToIgnore;
-
- bool connectionEncrypted = false;
+ QDtlsPrivate();
+ ~QDtlsPrivate();
+ std::unique_ptr<QTlsPrivate::DtlsCryptograph> backend;
};
QT_END_NAMESPACE
diff --git a/src/network/ssl/qocsp_p.h b/src/network/ssl/qocsp_p.h
index 71f59da0b4..596cb1357f 100644
--- a/src/network/ssl/qocsp_p.h
+++ b/src/network/ssl/qocsp_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QOCSP_P_H
#define QOCSP_P_H
diff --git a/src/network/ssl/qocspresponse.cpp b/src/network/ssl/qocspresponse.cpp
index ab046b74c1..74e2c814fd 100644
--- a/src/network/ssl/qocspresponse.cpp
+++ b/src/network/ssl/qocspresponse.cpp
@@ -1,41 +1,6 @@
-/****************************************************************************
-** Copyright (C) 2011 Richard J. Moore <rich@kde.org>
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2011 Richard J. Moore <rich@kde.org>
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qocspresponse_p.h"
#include "qocspresponse.h"
@@ -44,6 +9,8 @@
QT_BEGIN_NAMESPACE
+QT_IMPL_METATYPE_EXTERN(QOcspResponse)
+
/*!
\class QOcspResponse
\brief This class represents Online Certificate Status Protocol response.
@@ -53,7 +20,7 @@ QT_BEGIN_NAMESPACE
\ingroup ssl
\inmodule QtNetwork
- The QOcspResponse class represents the revocation status of a server's certficate,
+ The QOcspResponse class represents the revocation status of a server's certificate,
received by the client-side socket during the TLS handshake. QSslSocket must be
configured with OCSP stapling enabled.
@@ -95,7 +62,7 @@ QT_BEGIN_NAMESPACE
\inmodule QtNetwork
- This enumeration describes revocation reasons, defined in \l{https://tools.ietf.org/html/rfc5280#section-5.3.1}{RFC 5280, section 5.3.1}
+ This enumeration describes revocation reasons, defined in \l{RFC 5280, section 5.3.1}
\value None
\value Unspecified
@@ -206,34 +173,34 @@ QSslCertificate QOcspResponse::subject() const
}
/*!
- \fn bool operator==(const QOcspResponse &lhs, const QOcspResponse &rhs)
+ \fn bool QOcspResponse::operator==(const QOcspResponse &lhs, const QOcspResponse &rhs)
Returns \c true if \a lhs and \a rhs are the responses for the same
certificate, signed by the same responder, have the same
revocation reason and the same certificate status.
\since 5.13
- \relates QOcspResponse
- */
-Q_NETWORK_EXPORT bool operator==(const QOcspResponse &lhs, const QOcspResponse &rhs)
-{
- return lhs.d == rhs.d || *lhs.d == *rhs.d;
-}
+*/
/*!
- \fn bool operator != (const QOcspResponse &lhs, const QOcspResponse &rhs)
+ \fn bool QOcspResponse::operator!=(const QOcspResponse &lhs, const QOcspResponse &rhs)
- Returns \c true if \a lhs and \a rhs are responses for different certificates,
- or signed by different responders, or have different revocation reasons, or different
- certificate statuses.
+ Returns \c true if \a lhs and \a rhs are responses for different certificates,
+ or signed by different responders, or have different revocation reasons, or different
+ certificate statuses.
- \since 5.13
- \relates QOcspResponse
+ \since 5.13
*/
/*!
- \fn size_t qHash(const QOcspResponse &response, size_t seed)
+ \internal
+*/
+bool QOcspResponse::isEqual(const QOcspResponse &other) const
+{
+ return d == other.d || *d == *other.d;
+}
+/*!
Returns the hash value for the \a response, using \a seed to seed the calculation.
\since 5.13
diff --git a/src/network/ssl/qocspresponse.h b/src/network/ssl/qocspresponse.h
index 1fc3377d58..68251a1547 100644
--- a/src/network/ssl/qocspresponse.h
+++ b/src/network/ssl/qocspresponse.h
@@ -1,41 +1,6 @@
-/****************************************************************************
-** Copyright (C) 2011 Richard J. Moore <rich@kde.org>
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2011 Richard J. Moore <rich@kde.org>
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QOCSPRESPONSE_H
#define QOCSPRESPONSE_H
@@ -46,7 +11,7 @@
#include <QtCore/qmetatype.h>
#include <QtCore/qobject.h>
-#ifndef Q_CLANG_QDOC
+#ifndef Q_QDOC
QT_REQUIRE_CONFIG(ssl);
#endif
@@ -72,6 +37,10 @@ enum class QOcspRevocationReason
RemoveFromCRL
};
+namespace QTlsPrivate {
+class TlsCryptographOpenSSL;
+}
+
class QOcspResponse;
Q_NETWORK_EXPORT size_t qHash(const QOcspResponse &response, size_t seed = 0) noexcept;
@@ -97,20 +66,23 @@ public:
void swap(QOcspResponse &other) noexcept { d.swap(other.d); }
private:
+ bool isEqual(const QOcspResponse &other) const;
+
+ friend class QTlsPrivate::TlsCryptographOpenSSL;
+ friend bool operator==(const QOcspResponse &lhs, const QOcspResponse &rhs)
+ { return lhs.isEqual(rhs); }
+ friend bool operator!=(const QOcspResponse &lhs, const QOcspResponse &rhs)
+ { return !lhs.isEqual(rhs); }
- friend class QSslSocketBackendPrivate;
- friend Q_NETWORK_EXPORT bool operator==(const QOcspResponse &lhs, const QOcspResponse &rhs);
friend Q_NETWORK_EXPORT size_t qHash(const QOcspResponse &response, size_t seed) noexcept;
QSharedDataPointer<QOcspResponsePrivate> d;
};
-inline bool operator!=(const QOcspResponse &lhs, const QOcspResponse &rhs) { return !(lhs == rhs); }
-
Q_DECLARE_SHARED(QOcspResponse)
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QOcspResponse)
+QT_DECL_METATYPE_EXTERN(QOcspResponse, Q_NETWORK_EXPORT)
#endif // QOCSPRESPONSE_H
diff --git a/src/network/ssl/qocspresponse_p.h b/src/network/ssl/qocspresponse_p.h
index e421b76899..5f08e306cd 100644
--- a/src/network/ssl/qocspresponse_p.h
+++ b/src/network/ssl/qocspresponse_p.h
@@ -1,41 +1,6 @@
-/****************************************************************************
-** Copyright (C) 2011 Richard J. Moore <rich@kde.org>
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2011 Richard J. Moore <rich@kde.org>
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QOCSPRESPONSE_P_H
#define QOCSPRESPONSE_P_H
diff --git a/src/network/ssl/qpassworddigestor.cpp b/src/network/ssl/qpassworddigestor.cpp
index 706fa1de05..94de14abd4 100644
--- a/src/network/ssl/qpassworddigestor.cpp
+++ b/src/network/ssl/qpassworddigestor.cpp
@@ -1,50 +1,25 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qpassworddigestor.h"
#include <QtCore/QDebug>
#include <QtCore/QMessageAuthenticationCode>
#include <QtCore/QtEndian>
+#include <QtCore/QList>
+
+#include "qtcore-config_p.h"
#include <limits>
+#if QT_CONFIG(opensslv30) && QT_CONFIG(openssl_linked)
+#define USING_OPENSSL30
+#include <openssl/core_names.h>
+#include <openssl/kdf.h>
+#include <openssl/params.h>
+#include <openssl/provider.h>
+#endif
+
QT_BEGIN_NAMESPACE
namespace QPasswordDigestor {
@@ -60,7 +35,7 @@ namespace QPasswordDigestor {
\since 5.12
Returns a hash computed using the PBKDF1-algorithm as defined in
- \l {https://tools.ietf.org/html/rfc8018#section-5.1} {RFC 8018}.
+ \l {RFC 8018, section 5.1}.
The function takes the \a data and \a salt, and then hashes it repeatedly
for \a iterations iterations using the specified hash \a algorithm. If the
@@ -122,11 +97,90 @@ Q_NETWORK_EXPORT QByteArray deriveKeyPbkdf1(QCryptographicHash::Algorithm algori
return key.left(dkLen);
}
+#ifdef USING_OPENSSL30
+// Copied from QCryptographicHashPrivate
+static constexpr const char * methodToName(QCryptographicHash::Algorithm method) noexcept
+{
+ switch (method) {
+#define CASE(Enum, Name) \
+ case QCryptographicHash:: Enum : \
+ return Name \
+ /*end*/
+ CASE(Sha1, "SHA1");
+ CASE(Md4, "MD4");
+ CASE(Md5, "MD5");
+ CASE(Sha224, "SHA224");
+ CASE(Sha256, "SHA256");
+ CASE(Sha384, "SHA384");
+ CASE(Sha512, "SHA512");
+ CASE(RealSha3_224, "SHA3-224");
+ CASE(RealSha3_256, "SHA3-256");
+ CASE(RealSha3_384, "SHA3-384");
+ CASE(RealSha3_512, "SHA3-512");
+ CASE(Keccak_224, "SHA3-224");
+ CASE(Keccak_256, "SHA3-256");
+ CASE(Keccak_384, "SHA3-384");
+ CASE(Keccak_512, "SHA3-512");
+ CASE(Blake2b_512, "BLAKE2B512");
+ CASE(Blake2s_256, "BLAKE2S256");
+#undef CASE
+ default: return nullptr;
+ }
+}
+
+static QByteArray opensslDeriveKeyPbkdf2(QCryptographicHash::Algorithm algorithm,
+ const QByteArray &data, const QByteArray &salt,
+ uint64_t iterations, quint64 dkLen)
+{
+ EVP_KDF *kdf = EVP_KDF_fetch(nullptr, "PBKDF2", nullptr);
+
+ if (!kdf)
+ return QByteArray();
+
+ auto cleanUpKdf = qScopeGuard([kdf] {
+ EVP_KDF_free(kdf);
+ });
+
+ EVP_KDF_CTX *ctx = EVP_KDF_CTX_new(kdf);
+
+ if (!ctx)
+ return QByteArray();
+
+ auto cleanUpCtx = qScopeGuard([ctx] {
+ EVP_KDF_CTX_free(ctx);
+ });
+
+ // Do not enable SP800-132 compliance check, otherwise we will require:
+ // - the iteration count is at least 1000
+ // - the salt length is at least 128 bits
+ // - the derived key length is at least 112 bits
+ // This would be a different behavior from the original implementation.
+ int checkDisabled = 1;
+ QList<OSSL_PARAM> params;
+ params.append(OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST, const_cast<char*>(methodToName(algorithm)), 0));
+ params.append(OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT, const_cast<char*>(salt.data()), salt.size()));
+ params.append(OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_PASSWORD, const_cast<char*>(data.data()), data.size()));
+ params.append(OSSL_PARAM_construct_uint64(OSSL_KDF_PARAM_ITER, &iterations));
+ params.append(OSSL_PARAM_construct_int(OSSL_KDF_PARAM_PKCS5, &checkDisabled));
+ params.append(OSSL_PARAM_construct_end());
+
+ if (EVP_KDF_CTX_set_params(ctx, params.data()) <= 0)
+ return QByteArray();
+
+ QByteArray derived(dkLen, '\0');
+
+ if (!EVP_KDF_derive(ctx, reinterpret_cast<unsigned char*>(derived.data()), derived.size(), nullptr))
+ return QByteArray();
+
+ return derived;
+}
+#endif
+
/*!
\since 5.12
Derive a key using the PBKDF2-algorithm as defined in
- \l {https://tools.ietf.org/html/rfc8018#section-5.2} {RFC 8018}.
+ \l {RFC 8018, section 5.2}.
This function takes the \a data and \a salt, and then applies HMAC-X, where
the X is \a algorithm, repeatedly. It internally concatenates intermediate
@@ -143,8 +197,6 @@ Q_NETWORK_EXPORT QByteArray deriveKeyPbkdf2(QCryptographicHash::Algorithm algori
const QByteArray &data, const QByteArray &salt,
int iterations, quint64 dkLen)
{
- // https://tools.ietf.org/html/rfc8018#section-5.2
-
// The RFC recommends checking that 'dkLen' is not greater than '(2^32 - 1) * hLen'
int hashLen = QCryptographicHash::hashLength(algorithm);
const quint64 maxLen = quint64(std::numeric_limits<quint32>::max() - 1) * hashLen;
@@ -158,11 +210,17 @@ Q_NETWORK_EXPORT QByteArray deriveKeyPbkdf2(QCryptographicHash::Algorithm algori
if (iterations < 1 || dkLen < 1)
return QByteArray();
+#ifdef USING_OPENSSL30
+ if (methodToName(algorithm))
+ return opensslDeriveKeyPbkdf2(algorithm, data, salt, iterations, dkLen);
+#endif
+
+ // https://tools.ietf.org/html/rfc8018#section-5.2
QByteArray key;
quint32 currentIteration = 1;
QMessageAuthenticationCode hmac(algorithm, data);
QByteArray index(4, Qt::Uninitialized);
- while (quint64(key.length()) < dkLen) {
+ while (quint64(key.size()) < dkLen) {
hmac.addData(salt);
qToBigEndian(currentIteration, index.data());
diff --git a/src/network/ssl/qpassworddigestor.h b/src/network/ssl/qpassworddigestor.h
index 0f88643298..279450178b 100644
--- a/src/network/ssl/qpassworddigestor.h
+++ b/src/network/ssl/qpassworddigestor.h
@@ -1,45 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPASSWORDDIGESTOR_H
#define QPASSWORDDIGESTOR_H
+#if 0
+#pragma qt_class(QPasswordDigestor)
+#endif
+
#include <QtNetwork/qtnetworkglobal.h>
#include <QtCore/QByteArray>
#include <QtCore/QCryptographicHash>
diff --git a/src/network/ssl/qssl.cpp b/src/network/ssl/qssl.cpp
index ffa211630e..dfd3745d3e 100644
--- a/src/network/ssl/qssl.cpp
+++ b/src/network/ssl/qssl.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qsslkey.h"
@@ -204,7 +168,7 @@ Q_LOGGING_CATEGORY(lcSsl, "qt.network.ssl");
\ingroup ssl
\inmodule QtNetwork
- See \l{https://tools.ietf.org/html/rfc8446#page-85}{RFC 8446, section 6}
+ See \l{RFC 8446, section 6}
for the possible values and their meaning.
\value CloseNotify,
@@ -243,4 +207,54 @@ Q_LOGGING_CATEGORY(lcSsl, "qt.network.ssl");
\value UnknownAlertMessage
*/
+/*!
+ \enum QSsl::ImplementedClass
+ \brief Enumerates classes that a TLS backend implements
+ \relates QSslSocket
+ \since 6.1
+
+ \ingroup network
+ \ingroup ssl
+ \inmodule QtNetwork
+
+ In QtNetwork, some classes have backend-specific implementation and thus
+ can be left unimplemented. Enumerators in this enum indicate, which class
+ has a working implementation in the backend.
+
+ \value Key Class QSslKey.
+ \value Certificate Class QSslCertificate.
+ \value Socket Class QSslSocket.
+ \value DiffieHellman Class QSslDiffieHellmanParameters.
+ \value EllipticCurve Class QSslEllipticCurve.
+ \value Dtls Class QDtls.
+ \value DtlsCookie Class QDtlsClientVerifier.
+*/
+
+/*!
+ \enum QSsl::SupportedFeature
+ \brief Enumerates possible features that a TLS backend supports
+ \relates QSslSocket
+ \since 6.1
+
+ \ingroup network
+ \ingroup ssl
+ \inmodule QtNetwork
+
+ In QtNetwork TLS-related classes have public API, that may be left unimplemented
+ by some backend, for example, our SecureTransport backend does not support
+ server-side ALPN. Enumerators from SupportedFeature enum indicate that a particular
+ feature is supported.
+
+ \value CertificateVerification Indicates that QSslCertificate::verify() is
+ implemented by the backend.
+ \value ClientSideAlpn Client-side ALPN (Application Layer Protocol Negotiation).
+ \value ServerSideAlpn Server-side ALPN.
+ \value Ocsp OCSP stapling (Online Certificate Status Protocol).
+ \value Psk Pre-shared keys.
+ \value SessionTicket Session tickets.
+ \value Alerts Information about alert messages sent and received.
+*/
+
QT_END_NAMESPACE
+
+#include "moc_qssl.cpp"
diff --git a/src/network/ssl/qssl.h b/src/network/ssl/qssl.h
index 3c0415a2e4..e52b8c6361 100644
--- a/src/network/ssl/qssl.h
+++ b/src/network/ssl/qssl.h
@@ -1,62 +1,35 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSSL_H
#define QSSL_H
+#if 0
+#pragma qt_class(QSsl)
+#endif
+
#include <QtNetwork/qtnetworkglobal.h>
+#include <QtCore/qobjectdefs.h>
#include <QtCore/QFlags>
QT_BEGIN_NAMESPACE
namespace QSsl {
+ Q_NAMESPACE_EXPORT(Q_NETWORK_EXPORT)
+
enum KeyType {
PrivateKey,
PublicKey
};
+ Q_ENUM_NS(KeyType)
enum EncodingFormat {
Pem,
Der
};
+ Q_ENUM_NS(EncodingFormat)
enum KeyAlgorithm {
Opaque,
@@ -65,26 +38,28 @@ namespace QSsl {
Ec,
Dh,
};
+ Q_ENUM_NS(KeyAlgorithm)
enum AlternativeNameEntryType {
EmailEntry,
DnsEntry,
IpAddressEntry
};
+ Q_ENUM_NS(AlternativeNameEntryType)
enum SslProtocol {
- TlsV1_0,
- TlsV1_1,
+ TlsV1_0 QT_DEPRECATED_VERSION_X_6_3("Use TlsV1_2OrLater instead."),
+ TlsV1_1 QT_DEPRECATED_VERSION_X_6_3("Use TlsV1_2OrLater instead."),
TlsV1_2,
AnyProtocol,
SecureProtocols,
- TlsV1_0OrLater,
- TlsV1_1OrLater,
+ TlsV1_0OrLater QT_DEPRECATED_VERSION_X_6_3("Use TlsV1_2OrLater instead."),
+ TlsV1_1OrLater QT_DEPRECATED_VERSION_X_6_3("Use TlsV1_2OrLater instead."),
TlsV1_2OrLater,
- DtlsV1_0,
- DtlsV1_0OrLater,
+ DtlsV1_0 QT_DEPRECATED_VERSION_X_6_3("Use DtlsV1_2OrLater instead."),
+ DtlsV1_0OrLater QT_DEPRECATED_VERSION_X_6_3("Use DtlsV1_2OrLater instead."),
DtlsV1_2,
DtlsV1_2OrLater,
@@ -93,6 +68,7 @@ namespace QSsl {
UnknownProtocol = -1
};
+ Q_ENUM_NS(SslProtocol)
enum SslOption {
SslOptionDisableEmptyFragments = 0x01,
@@ -104,6 +80,7 @@ namespace QSsl {
SslOptionDisableSessionPersistence = 0x40,
SslOptionDisableServerCipherPreference = 0x80
};
+ Q_ENUM_NS(SslOption)
Q_DECLARE_FLAGS(SslOptions, SslOption)
enum class AlertLevel {
@@ -111,6 +88,7 @@ namespace QSsl {
Fatal,
Unknown
};
+ Q_ENUM_NS(AlertLevel)
enum class AlertType {
CloseNotify,
@@ -148,7 +126,31 @@ namespace QSsl {
NoApplicationProtocol = 120,
UnknownAlertMessage = 255
};
-
+ Q_ENUM_NS(AlertType)
+
+ enum class ImplementedClass
+ {
+ Key,
+ Certificate,
+ Socket,
+ DiffieHellman,
+ EllipticCurve,
+ Dtls,
+ DtlsCookie
+ };
+ Q_ENUM_NS(ImplementedClass)
+
+ enum class SupportedFeature
+ {
+ CertificateVerification,
+ ClientSideAlpn,
+ ServerSideAlpn,
+ Ocsp,
+ Psk,
+ SessionTicket,
+ Alerts
+ };
+ Q_ENUM_NS(SupportedFeature)
}
Q_DECLARE_OPERATORS_FOR_FLAGS(QSsl::SslOptions)
diff --git a/src/network/ssl/qssl_p.h b/src/network/ssl/qssl_p.h
index 83ccdc7fc3..ccbcf87029 100644
--- a/src/network/ssl/qssl_p.h
+++ b/src/network/ssl/qssl_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSSL_P_H
@@ -60,6 +24,19 @@ QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcSsl)
+namespace QTlsPrivate {
+
+enum class Cipher {
+ DesCbc,
+ DesEde3Cbc,
+ Rc2Cbc,
+ Aes128Cbc,
+ Aes192Cbc,
+ Aes256Cbc
+};
+
+} // namespace QTlsPrivate
+
QT_END_NAMESPACE
#endif // QSSL_P_H
diff --git a/src/network/ssl/qsslcertificate.cpp b/src/network/ssl/qsslcertificate.cpp
index 956a1df29c..9878c603b6 100644
--- a/src/network/ssl/qsslcertificate.cpp
+++ b/src/network/ssl/qsslcertificate.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/*!
@@ -121,8 +85,7 @@
\value Wildcard This provides a simple pattern matching syntax
similar to that used by shells (command interpreters) for "file
- globbing". See \l {QRegularExpression#Wildcard matching}
- {QRegularExpression Wildcard Matching}.
+ globbing". See \l {QRegularExpression::fromWildcard()}.
\value FixedString The pattern is a fixed string. This is
equivalent to using the RegularExpression pattern on a string in
@@ -131,31 +94,46 @@
*/
#include <QtNetwork/qtnetworkglobal.h>
-#ifndef QT_NO_OPENSSL
-#include "qsslsocket_openssl_symbols_p.h"
-#endif
-#ifdef QT_SECURETRANSPORT
-#include "qsslsocket_mac_p.h"
-#endif
-#if QT_CONFIG(schannel)
-#include "qsslsocket_schannel_p.h"
-#endif
+
#if QT_CONFIG(regularexpression)
#include "qregularexpression.h"
#endif
-#include "qssl_p.h"
-#include "qsslcertificate.h"
+
+#include "qsslcertificateextension_p.h"
#include "qsslcertificate_p.h"
+#include "qsslcertificate.h"
+#include "qssl_p.h"
+
#ifndef QT_NO_SSL
+#include "qsslsocket_p.h"
#include "qsslkey_p.h"
#endif
#include <QtCore/qdir.h>
-#include <QtCore/qdiriterator.h>
+#include <QtCore/qdirlisting.h>
#include <QtCore/qfile.h>
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
+QT_IMPL_METATYPE_EXTERN(QSslCertificate)
+
+QSslCertificatePrivate::QSslCertificatePrivate()
+{
+#ifndef QT_NO_SSL
+ QSslSocketPrivate::ensureInitialized();
+#endif
+
+ const QTlsBackend *tlsBackend = QTlsBackend::activeOrAnyBackend();
+ if (tlsBackend)
+ backend.reset(tlsBackend->createCertificate());
+ else
+ qCWarning(lcSsl, "No TLS backend is available");
+}
+
+QSslCertificatePrivate::~QSslCertificatePrivate() = default;
+
/*!
Constructs a QSslCertificate by reading \a format encoded data
from \a device and using the first certificate found. You can
@@ -165,13 +143,25 @@ QT_BEGIN_NAMESPACE
QSslCertificate::QSslCertificate(QIODevice *device, QSsl::EncodingFormat format)
: d(new QSslCertificatePrivate)
{
-#ifndef QT_NO_OPENSSL
- QSslSocketPrivate::ensureInitialized();
- if (device && QSslSocket::supportsSsl())
-#else
- if (device)
-#endif
- d->init(device->readAll(), format);
+ if (device) {
+ const auto data = device->readAll();
+ if (data.isEmpty())
+ return;
+
+ const auto *tlsBackend = QTlsBackend::activeOrAnyBackend();
+ if (!tlsBackend)
+ return;
+
+ auto *X509Reader = format == QSsl::Pem ? tlsBackend->X509PemReader() : tlsBackend->X509DerReader();
+ if (!X509Reader) {
+ qCWarning(lcSsl, "Current TLS plugin does not support reading from PEM/DER");
+ return;
+ }
+
+ QList<QSslCertificate> certs = X509Reader(data, 1);
+ if (!certs.isEmpty())
+ d = certs.first().d;
+ }
}
/*!
@@ -183,11 +173,22 @@ QSslCertificate::QSslCertificate(QIODevice *device, QSsl::EncodingFormat format)
QSslCertificate::QSslCertificate(const QByteArray &data, QSsl::EncodingFormat format)
: d(new QSslCertificatePrivate)
{
-#ifndef QT_NO_OPENSSL
- QSslSocketPrivate::ensureInitialized();
- if (QSslSocket::supportsSsl())
-#endif
- d->init(data, format);
+ if (data.isEmpty())
+ return;
+
+ const auto *tlsBackend = QTlsBackend::activeOrAnyBackend();
+ if (!tlsBackend)
+ return;
+
+ auto *X509Reader = format == QSsl::Pem ? tlsBackend->X509PemReader() : tlsBackend->X509DerReader();
+ if (!X509Reader) {
+ qCWarning(lcSsl, "Current TLS plugin does not support reading from PEM/DER");
+ return;
+ }
+
+ const QList<QSslCertificate> certs = X509Reader(data, 1);
+ if (!certs.isEmpty())
+ d = certs.first().d;
}
/*!
@@ -229,6 +230,20 @@ QSslCertificate &QSslCertificate::operator=(const QSslCertificate &other)
returns \c false.
*/
+bool QSslCertificate::operator==(const QSslCertificate &other) const
+{
+ if (d == other.d)
+ return true;
+
+ if (isNull() && other.isNull())
+ return true;
+
+ if (d->backend.get() && other.d->backend.get())
+ return d->backend->isEqual(*other.d->backend.get());
+
+ return false;
+}
+
/*!
\fn bool QSslCertificate::operator!=(const QSslCertificate &other) const
@@ -246,25 +261,13 @@ QSslCertificate &QSslCertificate::operator=(const QSslCertificate &other)
\sa clear()
*/
+bool QSslCertificate::isNull() const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->isNull();
-#if QT_DEPRECATED_SINCE(5,0)
-/*!
- \fn bool QSslCertificate::isValid() const
- \obsolete
-
- To verify a certificate, use verify().
- To check if a certificate is blacklisted, use isBlacklisted().
- To check if a certificate has expired or is not yet valid, compare
- expiryDate() and effectiveDate() with QDateTime::currentDateTime()
-
- This function checks that the current
- date-time is within the date-time range during which the
- certificate is considered valid, and checks that the
- certificate is not in a blacklist of fraudulent certificates.
-
- \sa isNull(), verify(), isBlacklisted(), expiryDate(), effectiveDate()
-*/
-#endif
+ return true;
+}
/*!
Returns \c true if this certificate is blacklisted; otherwise
@@ -287,6 +290,13 @@ bool QSslCertificate::isBlacklisted() const
A certificate is considered self-signed its issuer and subject
are identical.
*/
+bool QSslCertificate::isSelfSigned() const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->isSelfSigned();
+
+ return false;
+}
/*!
Clears the contents of this certificate, making it a null
@@ -305,12 +315,26 @@ void QSslCertificate::clear()
\fn QByteArray QSslCertificate::version() const
Returns the certificate's version string.
*/
+QByteArray QSslCertificate::version() const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->version();
+
+ return {};
+}
/*!
\fn QByteArray QSslCertificate::serialNumber() const
Returns the certificate's serial number string in hexadecimal format.
*/
+QByteArray QSslCertificate::serialNumber() const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->serialNumber();
+
+ return {};
+}
/*!
Returns a cryptographic digest of this certificate. By default,
@@ -332,6 +356,13 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
\sa subjectInfo()
*/
+QStringList QSslCertificate::issuerInfo(SubjectInfo info) const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->issuerInfo(info);
+
+ return {};
+}
/*!
\fn QStringList QSslCertificate::issuerInfo(const QByteArray &attribute) const
@@ -342,6 +373,13 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
\sa subjectInfo()
*/
+QStringList QSslCertificate::issuerInfo(const QByteArray &attribute) const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->issuerInfo(attribute);
+
+ return {};
+}
/*!
\fn QString QSslCertificate::subjectInfo(SubjectInfo subject) const
@@ -352,6 +390,13 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
\sa issuerInfo()
*/
+QStringList QSslCertificate::subjectInfo(SubjectInfo info) const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->subjectInfo(info);
+
+ return {};
+}
/*!
\fn QStringList QSslCertificate::subjectInfo(const QByteArray &attribute) const
@@ -362,6 +407,13 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
\sa issuerInfo()
*/
+QStringList QSslCertificate::subjectInfo(const QByteArray &attribute) const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->subjectInfo(attribute);
+
+ return {};
+}
/*!
\fn QList<QByteArray> QSslCertificate::subjectInfoAttributes() const
@@ -375,6 +427,13 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
\sa subjectInfo()
*/
+QList<QByteArray> QSslCertificate::subjectInfoAttributes() const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->subjectInfoAttributes();
+
+ return {};
+}
/*!
\fn QList<QByteArray> QSslCertificate::issuerInfoAttributes() const
@@ -388,6 +447,13 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
\sa subjectInfo()
*/
+QList<QByteArray> QSslCertificate::issuerInfoAttributes() const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->issuerInfoAttributes();
+
+ return {};
+}
/*!
\fn QMultiMap<QSsl::AlternativeNameEntryType, QString> QSslCertificate::subjectAlternativeNames() const
@@ -404,6 +470,13 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
\sa subjectInfo()
*/
+QMultiMap<QSsl::AlternativeNameEntryType, QString> QSslCertificate::subjectAlternativeNames() const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->subjectAlternativeNames();
+
+ return {};
+}
/*!
\fn QDateTime QSslCertificate::effectiveDate() const
@@ -413,6 +486,13 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
\sa expiryDate()
*/
+QDateTime QSslCertificate::effectiveDate() const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->effectiveDate();
+
+ return {};
+}
/*!
\fn QDateTime QSslCertificate::expiryDate() const
@@ -422,6 +502,13 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
\sa effectiveDate()
*/
+QDateTime QSslCertificate::expiryDate() const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->expiryDate();
+
+ return {};
+}
/*!
\fn Qt::HANDLE QSslCertificate::handle() const
@@ -435,11 +522,29 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
non-portable, and its return value may vary from platform to
platform or change from minor release to minor release.
*/
+Qt::HANDLE QSslCertificate::handle() const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->handle();
+ return {};
+}
+
+#ifndef QT_NO_SSL
/*!
\fn QSslKey QSslCertificate::publicKey() const
Returns the certificate subject's public key.
*/
+QSslKey QSslCertificate::publicKey() const
+{
+ QSslKey key;
+ if (const auto *backend = d->backend.get())
+ QTlsBackend::resetBackend(key, backend->publicKey());
+
+ return key;
+}
+#endif // QT_NO_SSL
+
/*!
\fn QList<QSslCertificateExtension> QSslCertificate::extensions() const
@@ -447,6 +552,10 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
Returns a list containing the X509 extensions of this certificate.
\since 5.0
*/
+QList<QSslCertificateExtension> QSslCertificate::extensions() const
+{
+ return d->extensions();
+}
/*!
\fn QByteArray QSslCertificate::toPem() const
@@ -454,6 +563,13 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
Returns this certificate converted to a PEM (Base64) encoded
representation.
*/
+QByteArray QSslCertificate::toPem() const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->toPem();
+
+ return {};
+}
/*!
\fn QByteArray QSslCertificate::toDer() const
@@ -461,6 +577,13 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
Returns this certificate converted to a DER (binary) encoded
representation.
*/
+QByteArray QSslCertificate::toDer() const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->toDer();
+
+ return {};
+}
/*!
\fn QString QSslCertificate::toText() const
@@ -470,6 +593,13 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
\since 5.0
*/
+QString QSslCertificate::toText() const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->toText();
+
+ return {};
+}
/*!
\since 5.15
@@ -494,16 +624,16 @@ QList<QSslCertificate> QSslCertificate::fromPath(const QString &path,
QString sourcePath = QDir::fromNativeSeparators(path);
// Find the path without the filename
- QString pathPrefix = sourcePath.left(sourcePath.lastIndexOf(QLatin1Char('/')));
+ QStringView pathPrefix = QStringView(sourcePath).left(sourcePath.lastIndexOf(u'/'));
// Check if the path contains any special chars
int pos = -1;
#if QT_CONFIG(regularexpression)
if (syntax == PatternSyntax::Wildcard)
- pos = pathPrefix.indexOf(QRegularExpression(QLatin1String("[*?[]")));
+ pos = pathPrefix.indexOf(QRegularExpression("[*?[]"_L1));
else if (syntax == PatternSyntax::RegularExpression)
- pos = sourcePath.indexOf(QRegularExpression(QLatin1String("[\\$\\(\\)\\*\\+\\.\\?\\[\\]\\^\\{\\}\\|]")));
+ pos = sourcePath.indexOf(QRegularExpression("[\\$\\(\\)\\*\\+\\.\\?\\[\\]\\^\\{\\}\\|]"_L1));
#else
if (syntax == PatternSyntax::Wildcard || syntax == PatternSyntax::RegExp)
qWarning("Regular expression support is disabled in this build. Only fixed string can be searched");
@@ -513,11 +643,11 @@ QList<QSslCertificate> QSslCertificate::fromPath(const QString &path,
if (pos != -1) {
// there was a special char in the path so cut of the part containing that char.
pathPrefix = pathPrefix.left(pos);
- const int lastIndexOfSlash = pathPrefix.lastIndexOf(QLatin1Char('/'));
+ const qsizetype lastIndexOfSlash = pathPrefix.lastIndexOf(u'/');
if (lastIndexOfSlash != -1)
pathPrefix = pathPrefix.left(lastIndexOfSlash);
else
- pathPrefix.clear();
+ pathPrefix = {};
} else {
// Check if the path is a file.
if (QFileInfo(sourcePath).isFile()) {
@@ -534,10 +664,12 @@ QList<QSslCertificate> QSslCertificate::fromPath(const QString &path,
// Special case - if the prefix ends up being nothing, use "." instead.
int startIndex = 0;
if (pathPrefix.isEmpty()) {
- pathPrefix = QLatin1String(".");
+ pathPrefix = u".";
startIndex = 2;
}
+ const QString pathPrefixString = pathPrefix.toString();
+
// The path can be a file or directory.
QList<QSslCertificate> certs;
@@ -548,9 +680,12 @@ QList<QSslCertificate> QSslCertificate::fromPath(const QString &path,
QRegularExpression pattern(QRegularExpression::anchoredPattern(sourcePath));
#endif
- QDirIterator it(pathPrefix, QDir::Files, QDirIterator::FollowSymlinks | QDirIterator::Subdirectories);
- while (it.hasNext()) {
- QString filePath = startIndex == 0 ? it.next() : it.next().mid(startIndex);
+ using F = QDirListing::IteratorFlag;
+ constexpr auto iterFlags = F::FollowSymlinks | F::Recursive;
+ for (const auto &dirEntry : QDirListing(pathPrefixString, QDir::Files, iterFlags)) {
+ QString filePath = dirEntry.filePath();
+ if (startIndex > 0)
+ filePath.remove(0, startIndex);
#if QT_CONFIG(regularexpression)
if (!pattern.match(filePath).hasMatch())
@@ -595,13 +730,22 @@ QList<QSslCertificate> QSslCertificate::fromDevice(QIODevice *device, QSsl::Enco
*/
QList<QSslCertificate> QSslCertificate::fromData(const QByteArray &data, QSsl::EncodingFormat format)
{
- return (format == QSsl::Pem)
- ? QSslCertificatePrivate::certificatesFromPem(data)
- : QSslCertificatePrivate::certificatesFromDer(data);
+ const auto *tlsBackend = QTlsBackend::activeOrAnyBackend();
+ if (!tlsBackend) {
+ qCWarning(lcSsl, "No TLS backend is available");
+ return {};
+ }
+
+ auto reader = format == QSsl::Pem ? tlsBackend->X509PemReader() : tlsBackend->X509DerReader();
+ if (!reader) {
+ qCWarning(lcSsl, "The available TLS backend does not support reading PEM/DER");
+ return {};
+ }
+
+ return reader(data, -1);
}
#ifndef QT_NO_SSL
-
/*!
Verifies a certificate chain. The chain to be verified is passed in the
\a certificateChain parameter. The first certificate in the list should
@@ -610,19 +754,25 @@ QList<QSslCertificate> QSslCertificate::fromData(const QByteArray &data, QSsl::E
the specified host name.
Note that the root (CA) certificate should not be included in the list to be verified,
- this will be looked up automatically either using the CA list specified by
- QSslSocket::defaultCaCertificates() or, if possible, it will be loaded on demand
- on Unix.
+ this will be looked up automatically using the CA list specified in the
+ default QSslConfiguration, and, in addition, if possible, CA certificates loaded on
+ demand on Unix and Windows.
\since 5.0
*/
-#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
QList<QSslError> QSslCertificate::verify(const QList<QSslCertificate> &certificateChain, const QString &hostName)
-#else
-QList<QSslError> QSslCertificate::verify(QList<QSslCertificate> certificateChain, const QString &hostName)
-#endif
{
- return QSslSocketBackendPrivate::verify(certificateChain, hostName);
+ const auto *tlsBackend = QTlsBackend::activeOrAnyBackend();
+ if (!tlsBackend) {
+ qCWarning(lcSsl, "No TLS backend is available");
+ return {};
+ }
+ auto verifyPtr = tlsBackend->X509Verifier();
+ if (!verifyPtr) {
+ qCWarning(lcSsl, "Available TLS backend does not support manual certificate verification");
+ return {};
+ }
+ return verifyPtr(certificateChain, hostName);
}
/*!
@@ -642,10 +792,43 @@ bool QSslCertificate::importPkcs12(QIODevice *device,
QList<QSslCertificate> *caCertificates,
const QByteArray &passPhrase)
{
- return QSslSocketBackendPrivate::importPkcs12(device, key, certificate, caCertificates, passPhrase);
+ if (!device || !key || !certificate)
+ return false;
+
+ const auto *tlsBackend = QTlsBackend::activeOrAnyBackend();
+ if (!tlsBackend) {
+ qCWarning(lcSsl, "No TLS backend is available");
+ return false;
+ }
+
+ if (auto reader = tlsBackend->X509Pkcs12Reader())
+ return reader(device, key, certificate, caCertificates, passPhrase);
+
+ qCWarning(lcSsl, "Available TLS backend does not support PKCS12");
+
+ return false;
}
+#endif // QT_NO_SSL
-#endif
+QList<QSslCertificateExtension> QSslCertificatePrivate::extensions() const
+{
+ QList<QSslCertificateExtension> result;
+
+ if (backend.get()) {
+ auto nExt = backend->numberOfExtensions();
+ for (decltype (nExt) i = 0; i < nExt; ++i) {
+ QSslCertificateExtension ext;
+ ext.d->oid = backend->oidForExtension(i);
+ ext.d->name = backend->nameForExtension(i);
+ ext.d->value = backend->valueForExtension(i);
+ ext.d->critical = backend->isExtensionCritical(i);
+ ext.d->supported = backend->isExtensionSupported(i);
+ result << ext;
+ }
+ }
+
+ return result;
+}
// These certificates are known to be fraudulent and were created during the comodo
// compromise. See http://www.comodo.com/Comodo-Fraud-Incident-2011-03-23.html
@@ -700,7 +883,7 @@ static const char *const certificate_blacklist[] = {
bool QSslCertificatePrivate::isBlacklisted(const QSslCertificate &certificate)
{
for (int a = 0; certificate_blacklist[a] != nullptr; a++) {
- QString blacklistedCommonName = QString::fromUtf8(certificate_blacklist[(a+1)]);
+ auto blacklistedCommonName = QAnyStringView(QUtf8StringView(certificate_blacklist[(a+1)]));
if (certificate.serialNumber() == certificate_blacklist[a++] &&
(certificate.subjectInfo(QSslCertificate::CommonName).contains(blacklistedCommonName) ||
certificate.issuerInfo(QSslCertificate::CommonName).contains(blacklistedCommonName)))
@@ -711,19 +894,18 @@ bool QSslCertificatePrivate::isBlacklisted(const QSslCertificate &certificate)
QByteArray QSslCertificatePrivate::subjectInfoToString(QSslCertificate::SubjectInfo info)
{
- QByteArray str;
switch (info) {
- case QSslCertificate::Organization: str = QByteArray("O"); break;
- case QSslCertificate::CommonName: str = QByteArray("CN"); break;
- case QSslCertificate::LocalityName: str = QByteArray("L"); break;
- case QSslCertificate::OrganizationalUnitName: str = QByteArray("OU"); break;
- case QSslCertificate::CountryName: str = QByteArray("C"); break;
- case QSslCertificate::StateOrProvinceName: str = QByteArray("ST"); break;
- case QSslCertificate::DistinguishedNameQualifier: str = QByteArray("dnQualifier"); break;
- case QSslCertificate::SerialNumber: str = QByteArray("serialNumber"); break;
- case QSslCertificate::EmailAddress: str = QByteArray("emailAddress"); break;
+ case QSslCertificate::Organization: return "O"_ba;
+ case QSslCertificate::CommonName: return "CN"_ba;
+ case QSslCertificate::LocalityName: return"L"_ba;
+ case QSslCertificate::OrganizationalUnitName: return "OU"_ba;
+ case QSslCertificate::CountryName: return "C"_ba;
+ case QSslCertificate::StateOrProvinceName: return "ST"_ba;
+ case QSslCertificate::DistinguishedNameQualifier: return "dnQualifier"_ba;
+ case QSslCertificate::SerialNumber: return "serialNumber"_ba;
+ case QSslCertificate::EmailAddress: return "emailAddress"_ba;
}
- return str;
+ return QByteArray();
}
/*!
@@ -740,13 +922,13 @@ QString QSslCertificate::issuerDisplayName() const
QStringList names;
names = issuerInfo(QSslCertificate::CommonName);
if (!names.isEmpty())
- return names.first();
+ return names.constFirst();
names = issuerInfo(QSslCertificate::Organization);
if (!names.isEmpty())
- return names.first();
+ return names.constFirst();
names = issuerInfo(QSslCertificate::OrganizationalUnitName);
if (!names.isEmpty())
- return names.first();
+ return names.constFirst();
return QString();
}
@@ -765,24 +947,30 @@ QString QSslCertificate::subjectDisplayName() const
QStringList names;
names = subjectInfo(QSslCertificate::CommonName);
if (!names.isEmpty())
- return names.first();
+ return names.constFirst();
names = subjectInfo(QSslCertificate::Organization);
if (!names.isEmpty())
- return names.first();
+ return names.constFirst();
names = subjectInfo(QSslCertificate::OrganizationalUnitName);
if (!names.isEmpty())
- return names.first();
+ return names.constFirst();
return QString();
}
/*!
- \fn size_t qHash(const QSslCertificate &key, size_t seed)
-
Returns the hash value for the \a key, using \a seed to seed the calculation.
\since 5.4
\relates QHash
*/
+size_t qHash(const QSslCertificate &key, size_t seed) noexcept
+{
+ if (const auto *backend = key.d->backend.get())
+ return backend->hash(seed);
+
+ return seed;
+
+}
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug debug, const QSslCertificate &certificate)
@@ -790,15 +978,15 @@ QDebug operator<<(QDebug debug, const QSslCertificate &certificate)
QDebugStateSaver saver(debug);
debug.resetFormat().nospace();
debug << "QSslCertificate("
- << certificate.version()
- << ", " << certificate.serialNumber()
- << ", " << certificate.digest().toBase64()
- << ", " << certificate.issuerDisplayName()
- << ", " << certificate.subjectDisplayName()
- << ", " << certificate.subjectAlternativeNames()
+ << "Version=" << certificate.version()
+ << ", SerialNumber=" << certificate.serialNumber()
+ << ", Digest=" << certificate.digest().toBase64()
+ << ", Issuer=" << certificate.issuerDisplayName()
+ << ", Subject=" << certificate.subjectDisplayName()
+ << ", AlternativeSubjectNames=" << certificate.subjectAlternativeNames()
#if QT_CONFIG(datestring)
- << ", " << certificate.effectiveDate()
- << ", " << certificate.expiryDate()
+ << ", EffectiveDate=" << certificate.effectiveDate()
+ << ", ExpiryDate=" << certificate.expiryDate()
#endif
<< ')';
return debug;
diff --git a/src/network/ssl/qsslcertificate.h b/src/network/ssl/qsslcertificate.h
index 8cfeaeb273..cdf11b28b0 100644
--- a/src/network/ssl/qsslcertificate.h
+++ b/src/network/ssl/qsslcertificate.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSSLCERTIFICATE_H
@@ -50,8 +14,8 @@
#include <QtCore/qbytearray.h>
#include <QtCore/qcryptographichash.h>
#include <QtCore/qdatetime.h>
-#include <QtCore/qsharedpointer.h>
#include <QtCore/qmap.h>
+#include <QtCore/qshareddata.h>
#include <QtNetwork/qssl.h>
QT_BEGIN_NAMESPACE
@@ -97,20 +61,12 @@ public:
QSslCertificate &operator=(const QSslCertificate &other);
void swap(QSslCertificate &other) noexcept
- { qSwap(d, other.d); }
+ { d.swap(other.d); }
bool operator==(const QSslCertificate &other) const;
inline bool operator!=(const QSslCertificate &other) const { return !operator==(other); }
bool isNull() const;
-#if QT_DEPRECATED_SINCE(5,0)
- QT_DEPRECATED inline bool isValid() const {
- const QDateTime currentTime = QDateTime::currentDateTimeUtc();
- return currentTime >= effectiveDate() &&
- currentTime <= expiryDate() &&
- !isBlacklisted();
- }
-#endif
bool isBlacklisted() const;
bool isSelfSigned() const;
void clear();
@@ -150,12 +106,7 @@ public:
const QByteArray &data, QSsl::EncodingFormat format = QSsl::Pem);
#ifndef QT_NO_SSL
-#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
static QList<QSslError> verify(const QList<QSslCertificate> &certificateChain, const QString &hostName = QString());
-#else
- static QList<QSslError> verify(QList<QSslCertificate> certificateChain, const QString &hostName = QString());
-#endif
-
static bool importPkcs12(QIODevice *device,
QSslKey *key, QSslCertificate *cert,
QList<QSslCertificate> *caCertificates = nullptr,
@@ -166,8 +117,7 @@ public:
private:
QExplicitlySharedDataPointer<QSslCertificatePrivate> d;
- friend class QSslCertificatePrivate;
- friend class QSslSocketBackendPrivate;
+ friend class QTlsBackend;
friend Q_NETWORK_EXPORT size_t qHash(const QSslCertificate &key, size_t seed) noexcept;
};
@@ -181,6 +131,6 @@ Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, QSslCertificate::SubjectInfo in
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QSslCertificate)
+QT_DECL_METATYPE_EXTERN(QSslCertificate, Q_NETWORK_EXPORT)
#endif
diff --git a/src/network/ssl/qsslcertificate_openssl.cpp b/src/network/ssl/qsslcertificate_openssl.cpp
deleted file mode 100644
index 35521427b2..0000000000
--- a/src/network/ssl/qsslcertificate_openssl.cpp
+++ /dev/null
@@ -1,766 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Copyright (C) 2016 Richard J. Moore <rich@kde.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qssl_p.h"
-#include "qsslsocket_openssl_symbols_p.h"
-#include "qsslcertificate_p.h"
-#include "qsslkey_p.h"
-#include "qsslcertificateextension_p.h"
-
-#include <QtCore/qendian.h>
-#include <QtCore/qmutex.h>
-
-QT_BEGIN_NAMESPACE
-
-constexpr int MutexPoolSize = 17;
-static QBasicMutex mutexPool[MutexPoolSize];
-namespace QMutexPool {
- static QBasicMutex *globalInstanceGet(const void *addr)
- {
- return mutexPool + (quintptr(addr) % MutexPoolSize);
- }
-}
-
-// forward declaration
-static QMultiMap<QByteArray, QString> _q_mapFromX509Name(X509_NAME *name);
-
-bool QSslCertificate::operator==(const QSslCertificate &other) const
-{
- if (d == other.d)
- return true;
- if (d->null && other.d->null)
- return true;
- if (d->x509 && other.d->x509)
- return q_X509_cmp(d->x509, other.d->x509) == 0;
- return false;
-}
-
-size_t qHash(const QSslCertificate &key, size_t seed) noexcept
-{
- if (X509 * const x509 = key.d->x509) {
- const EVP_MD *sha1 = q_EVP_sha1();
- unsigned int len = 0;
- unsigned char md[EVP_MAX_MD_SIZE];
- q_X509_digest(x509, sha1, md, &len);
- return qHashBits(md, len, seed);
- }
-
- return seed;
-}
-
-bool QSslCertificate::isNull() const
-{
- return d->null;
-}
-
-bool QSslCertificate::isSelfSigned() const
-{
- if (!d->x509)
- return false;
-
- return (q_X509_check_issued(d->x509, d->x509) == X509_V_OK);
-}
-
-QByteArray QSslCertificate::version() const
-{
-#if QT_CONFIG(thread)
- QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
-#endif
- if (d->versionString.isEmpty() && d->x509)
- d->versionString = QByteArray::number(qlonglong(q_X509_get_version(d->x509)) + 1);
-
- return d->versionString;
-}
-
-QByteArray QSslCertificate::serialNumber() const
-{
-#if QT_CONFIG(thread)
- QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
-#endif
- if (d->serialNumberString.isEmpty() && d->x509) {
- ASN1_INTEGER *serialNumber = q_X509_get_serialNumber(d->x509);
- QByteArray hexString;
- hexString.reserve(serialNumber->length * 3);
- for (int a = 0; a < serialNumber->length; ++a) {
- hexString += QByteArray::number(serialNumber->data[a], 16).rightJustified(2, '0');
- hexString += ':';
- }
- hexString.chop(1);
- d->serialNumberString = hexString;
- }
- return d->serialNumberString;
-}
-
-QStringList QSslCertificate::issuerInfo(SubjectInfo info) const
-{
-#if QT_CONFIG(thread)
- QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
-#endif
- // lazy init
- if (d->issuerInfo.isEmpty() && d->x509)
- d->issuerInfo =
- _q_mapFromX509Name(q_X509_get_issuer_name(d->x509));
-
- return d->issuerInfo.values(d->subjectInfoToString(info));
-}
-
-QStringList QSslCertificate::issuerInfo(const QByteArray &attribute) const
-{
-#if QT_CONFIG(thread)
- QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
-#endif
- // lazy init
- if (d->issuerInfo.isEmpty() && d->x509)
- d->issuerInfo =
- _q_mapFromX509Name(q_X509_get_issuer_name(d->x509));
-
- return d->issuerInfo.values(attribute);
-}
-
-QStringList QSslCertificate::subjectInfo(SubjectInfo info) const
-{
-#if QT_CONFIG(thread)
- QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
-#endif
- // lazy init
- if (d->subjectInfo.isEmpty() && d->x509)
- d->subjectInfo =
- _q_mapFromX509Name(q_X509_get_subject_name(d->x509));
-
- return d->subjectInfo.values(d->subjectInfoToString(info));
-}
-
-QStringList QSslCertificate::subjectInfo(const QByteArray &attribute) const
-{
-#if QT_CONFIG(thread)
- QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
-#endif
- // lazy init
- if (d->subjectInfo.isEmpty() && d->x509)
- d->subjectInfo =
- _q_mapFromX509Name(q_X509_get_subject_name(d->x509));
-
- return d->subjectInfo.values(attribute);
-}
-
-QList<QByteArray> QSslCertificate::subjectInfoAttributes() const
-{
-#if QT_CONFIG(thread)
- QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
-#endif
- // lazy init
- if (d->subjectInfo.isEmpty() && d->x509)
- d->subjectInfo =
- _q_mapFromX509Name(q_X509_get_subject_name(d->x509));
-
- return d->subjectInfo.uniqueKeys();
-}
-
-QList<QByteArray> QSslCertificate::issuerInfoAttributes() const
-{
-#if QT_CONFIG(thread)
- QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
-#endif
- // lazy init
- if (d->issuerInfo.isEmpty() && d->x509)
- d->issuerInfo =
- _q_mapFromX509Name(q_X509_get_issuer_name(d->x509));
-
- return d->issuerInfo.uniqueKeys();
-}
-
-QMultiMap<QSsl::AlternativeNameEntryType, QString> QSslCertificate::subjectAlternativeNames() const
-{
- QMultiMap<QSsl::AlternativeNameEntryType, QString> result;
-
- if (!d->x509)
- return result;
-
- STACK_OF(GENERAL_NAME) *altNames = (STACK_OF(GENERAL_NAME) *)q_X509_get_ext_d2i(
- d->x509, NID_subject_alt_name, nullptr, nullptr);
-
- auto altName = [](ASN1_IA5STRING *ia5, int len) {
- const char *altNameStr = reinterpret_cast<const char *>(q_ASN1_STRING_get0_data(ia5));
- return QString::fromLatin1(altNameStr, len);
- };
- if (altNames) {
- for (int i = 0; i < q_sk_GENERAL_NAME_num(altNames); ++i) {
- const GENERAL_NAME *genName = q_sk_GENERAL_NAME_value(altNames, i);
- if (genName->type != GEN_DNS && genName->type != GEN_EMAIL && genName->type != GEN_IPADD)
- continue;
-
- int len = q_ASN1_STRING_length(genName->d.ia5);
- if (len < 0 || len >= 8192) {
- // broken name
- continue;
- }
-
- switch (genName->type) {
- case GEN_DNS:
- result.insert(QSsl::DnsEntry, altName(genName->d.ia5, len));
- break;
- case GEN_EMAIL:
- result.insert(QSsl::EmailEntry, altName(genName->d.ia5, len));
- break;
- case GEN_IPADD: {
- QHostAddress ipAddress;
- switch (len) {
- case 4: // IPv4
- ipAddress = QHostAddress(qFromBigEndian(*reinterpret_cast<quint32 *>(genName->d.iPAddress->data)));
- break;
- case 16: // IPv6
- ipAddress = QHostAddress(reinterpret_cast<quint8 *>(genName->d.iPAddress->data));
- break;
- default: // Unknown IP address format
- break;
- }
- if (!ipAddress.isNull())
- result.insert(QSsl::IpAddressEntry, ipAddress.toString());
- break;
- }
- default:
- break;
- }
- }
-
- q_OPENSSL_sk_pop_free((OPENSSL_STACK*)altNames, reinterpret_cast<void(*)(void*)>(q_GENERAL_NAME_free));
- }
-
- return result;
-}
-
-QDateTime QSslCertificate::effectiveDate() const
-{
- return d->notValidBefore;
-}
-
-QDateTime QSslCertificate::expiryDate() const
-{
- return d->notValidAfter;
-}
-
-Qt::HANDLE QSslCertificate::handle() const
-{
- return Qt::HANDLE(d->x509);
-}
-
-QSslKey QSslCertificate::publicKey() const
-{
- if (!d->x509)
- return QSslKey();
-
- QSslKey key;
-
- key.d->type = QSsl::PublicKey;
-
- EVP_PKEY *pkey = q_X509_get_pubkey(d->x509);
- Q_ASSERT(pkey);
- const int keyType = q_EVP_PKEY_type(q_EVP_PKEY_base_id(pkey));
-
- if (keyType == EVP_PKEY_RSA) {
- key.d->rsa = q_EVP_PKEY_get1_RSA(pkey);
- key.d->algorithm = QSsl::Rsa;
- key.d->isNull = false;
- } else if (keyType == EVP_PKEY_DSA) {
- key.d->dsa = q_EVP_PKEY_get1_DSA(pkey);
- key.d->algorithm = QSsl::Dsa;
- key.d->isNull = false;
-#ifndef OPENSSL_NO_EC
- } else if (keyType == EVP_PKEY_EC) {
- key.d->ec = q_EVP_PKEY_get1_EC_KEY(pkey);
- key.d->algorithm = QSsl::Ec;
- key.d->isNull = false;
-#endif
- } else if (keyType == EVP_PKEY_DH) {
- // DH unsupported
- } else {
- // error?
- }
-
- q_EVP_PKEY_free(pkey);
- return key;
-}
-
-/*
- * Convert unknown extensions to a QVariant.
- */
-static QVariant x509UnknownExtensionToValue(X509_EXTENSION *ext)
-{
- // Get the extension specific method object if available
- // we cast away the const-ness here because some versions of openssl
- // don't use const for the parameters in the functions pointers stored
- // in the object.
- X509V3_EXT_METHOD *meth = const_cast<X509V3_EXT_METHOD *>(q_X509V3_EXT_get(ext));
- if (!meth) {
- ASN1_OCTET_STRING *value = q_X509_EXTENSION_get_data(ext);
- QByteArray result( reinterpret_cast<const char *>(q_ASN1_STRING_get0_data(value)),
- q_ASN1_STRING_length(value));
- return result;
- }
-
- //const unsigned char *data = ext->value->data;
- void *ext_internal = q_X509V3_EXT_d2i(ext);
-
- // If this extension can be converted
- if (meth->i2v && ext_internal) {
- STACK_OF(CONF_VALUE) *val = meth->i2v(meth, ext_internal, nullptr);
-
- QVariantMap map;
- QVariantList list;
- bool isMap = false;
-
- for (int j = 0; j < q_SKM_sk_num(CONF_VALUE, val); j++) {
- CONF_VALUE *nval = q_SKM_sk_value(CONF_VALUE, val, j);
- if (nval->name && nval->value) {
- isMap = true;
- map[QString::fromUtf8(nval->name)] = QString::fromUtf8(nval->value);
- } else if (nval->name) {
- list << QString::fromUtf8(nval->name);
- } else if (nval->value) {
- list << QString::fromUtf8(nval->value);
- }
- }
-
- if (isMap)
- return map;
- else
- return list;
- } else if (meth->i2s && ext_internal) {
- //qCDebug(lcSsl) << meth->i2s(meth, ext_internal);
- QVariant result(QString::fromUtf8(meth->i2s(meth, ext_internal)));
- return result;
- } else if (meth->i2r && ext_internal) {
- QByteArray result;
-
- BIO *bio = q_BIO_new(q_BIO_s_mem());
- if (!bio)
- return result;
-
- meth->i2r(meth, ext_internal, bio, 0);
-
- char *bio_buffer;
- long bio_size = q_BIO_get_mem_data(bio, &bio_buffer);
- result = QByteArray(bio_buffer, bio_size);
-
- q_BIO_free(bio);
- return result;
- }
-
- return QVariant();
-}
-
-/*
- * Convert extensions to a variant. The naming of the keys of the map are
- * taken from RFC 5280, however we decided the capitalisation in the RFC
- * was too silly for the real world.
- */
-static QVariant x509ExtensionToValue(X509_EXTENSION *ext)
-{
- ASN1_OBJECT *obj = q_X509_EXTENSION_get_object(ext);
- int nid = q_OBJ_obj2nid(obj);
-
- switch (nid) {
- case NID_basic_constraints:
- {
- BASIC_CONSTRAINTS *basic = reinterpret_cast<BASIC_CONSTRAINTS *>(q_X509V3_EXT_d2i(ext));
-
- QVariantMap result;
- result[QLatin1String("ca")] = basic->ca ? true : false;
- if (basic->pathlen)
- result[QLatin1String("pathLenConstraint")] = (qlonglong)q_ASN1_INTEGER_get(basic->pathlen);
-
- q_BASIC_CONSTRAINTS_free(basic);
- return result;
- }
- break;
- case NID_info_access:
- {
- AUTHORITY_INFO_ACCESS *info = reinterpret_cast<AUTHORITY_INFO_ACCESS *>(q_X509V3_EXT_d2i(ext));
-
- QVariantMap result;
- for (int i=0; i < q_SKM_sk_num(ACCESS_DESCRIPTION, info); i++) {
- ACCESS_DESCRIPTION *ad = q_SKM_sk_value(ACCESS_DESCRIPTION, info, i);
-
- GENERAL_NAME *name = ad->location;
- if (name->type == GEN_URI) {
- int len = q_ASN1_STRING_length(name->d.uniformResourceIdentifier);
- if (len < 0 || len >= 8192) {
- // broken name
- continue;
- }
-
- const char *uriStr = reinterpret_cast<const char *>(q_ASN1_STRING_get0_data(name->d.uniformResourceIdentifier));
- const QString uri = QString::fromUtf8(uriStr, len);
-
- result[QString::fromUtf8(QSslCertificatePrivate::asn1ObjectName(ad->method))] = uri;
- } else {
- qCWarning(lcSsl) << "Strange location type" << name->type;
- }
- }
-
- q_OPENSSL_sk_pop_free((OPENSSL_STACK*)info, reinterpret_cast<void(*)(void *)>(q_OPENSSL_sk_free));
- return result;
- }
- break;
- case NID_subject_key_identifier:
- {
- void *ext_internal = q_X509V3_EXT_d2i(ext);
-
- // we cast away the const-ness here because some versions of openssl
- // don't use const for the parameters in the functions pointers stored
- // in the object.
- X509V3_EXT_METHOD *meth = const_cast<X509V3_EXT_METHOD *>(q_X509V3_EXT_get(ext));
-
- return QVariant(QString::fromUtf8(meth->i2s(meth, ext_internal)));
- }
- break;
- case NID_authority_key_identifier:
- {
- AUTHORITY_KEYID *auth_key = reinterpret_cast<AUTHORITY_KEYID *>(q_X509V3_EXT_d2i(ext));
-
- QVariantMap result;
-
- // keyid
- if (auth_key->keyid) {
- QByteArray keyid(reinterpret_cast<const char *>(auth_key->keyid->data),
- auth_key->keyid->length);
- result[QLatin1String("keyid")] = keyid.toHex();
- }
-
- // issuer
- // TODO: GENERAL_NAMES
-
- // serial
- if (auth_key->serial)
- result[QLatin1String("serial")] = (qlonglong)q_ASN1_INTEGER_get(auth_key->serial);
-
- q_AUTHORITY_KEYID_free(auth_key);
- return result;
- }
- break;
- }
-
- return QVariant();
-}
-
-QSslCertificateExtension QSslCertificatePrivate::convertExtension(X509_EXTENSION *ext)
-{
- QSslCertificateExtension result;
-
- ASN1_OBJECT *obj = q_X509_EXTENSION_get_object(ext);
- QByteArray oid = QSslCertificatePrivate::asn1ObjectId(obj);
- QByteArray name = QSslCertificatePrivate::asn1ObjectName(obj);
-
- result.d->oid = QString::fromUtf8(oid);
- result.d->name = QString::fromUtf8(name);
-
- bool critical = q_X509_EXTENSION_get_critical(ext);
- result.d->critical = critical;
-
- // Lets see if we have custom support for this one
- QVariant extensionValue = x509ExtensionToValue(ext);
- if (extensionValue.isValid()) {
- result.d->value = extensionValue;
- result.d->supported = true;
-
- return result;
- }
-
- extensionValue = x509UnknownExtensionToValue(ext);
- if (extensionValue.isValid()) {
- result.d->value = extensionValue;
- result.d->supported = false;
- return result;
- }
-
- return result;
-}
-
-QList<QSslCertificateExtension> QSslCertificate::extensions() const
-{
- QList<QSslCertificateExtension> result;
-
- if (!d->x509)
- return result;
-
- int count = q_X509_get_ext_count(d->x509);
- result.reserve(count);
-
- for (int i = 0; i < count; i++) {
- X509_EXTENSION *ext = q_X509_get_ext(d->x509, i);
- result << QSslCertificatePrivate::convertExtension(ext);
- }
-
- // Converting an extension may result in an error(s), clean them up.
- Q_UNUSED(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
-
- return result;
-}
-
-QByteArray QSslCertificate::toPem() const
-{
- if (!d->x509)
- return QByteArray();
- return d->QByteArray_from_X509(d->x509, QSsl::Pem);
-}
-
-QByteArray QSslCertificate::toDer() const
-{
- if (!d->x509)
- return QByteArray();
- return d->QByteArray_from_X509(d->x509, QSsl::Der);
-}
-
-QString QSslCertificate::toText() const
-{
- if (!d->x509)
- return QString();
- return d->text_from_X509(d->x509);
-}
-
-#define BEGINCERTSTRING "-----BEGIN CERTIFICATE-----"
-#define ENDCERTSTRING "-----END CERTIFICATE-----"
-
-void QSslCertificatePrivate::init(const QByteArray &data, QSsl::EncodingFormat format)
-{
- if (!data.isEmpty()) {
- const QList<QSslCertificate> certs = (format == QSsl::Pem)
- ? certificatesFromPem(data, 1)
- : certificatesFromDer(data, 1);
- if (!certs.isEmpty()) {
- *this = *certs.first().d;
- if (x509)
- x509 = q_X509_dup(x509);
- }
- }
-}
-
-// ### refactor against QSsl::pemFromDer() etc. (to avoid redundant implementations)
-QByteArray QSslCertificatePrivate::QByteArray_from_X509(X509 *x509, QSsl::EncodingFormat format)
-{
- if (!x509) {
- qCWarning(lcSsl, "QSslSocketBackendPrivate::X509_to_QByteArray: null X509");
- return QByteArray();
- }
-
- // Use i2d_X509 to convert the X509 to an array.
- int length = q_i2d_X509(x509, nullptr);
- QByteArray array;
- array.resize(length);
- char *data = array.data();
- char **dataP = &data;
- unsigned char **dataPu = (unsigned char **)dataP;
- if (q_i2d_X509(x509, dataPu) < 0)
- return QByteArray();
-
- if (format == QSsl::Der)
- return array;
-
- // Convert to Base64 - wrap at 64 characters.
- array = array.toBase64();
- QByteArray tmp;
- for (int i = 0; i <= array.size() - 64; i += 64) {
- tmp += QByteArray::fromRawData(array.data() + i, 64);
- tmp += '\n';
- }
- if (int remainder = array.size() % 64) {
- tmp += QByteArray::fromRawData(array.data() + array.size() - remainder, remainder);
- tmp += '\n';
- }
-
- return BEGINCERTSTRING "\n" + tmp + ENDCERTSTRING "\n";
-}
-
-QString QSslCertificatePrivate::text_from_X509(X509 *x509)
-{
- if (!x509) {
- qCWarning(lcSsl, "QSslSocketBackendPrivate::text_from_X509: null X509");
- return QString();
- }
-
- QByteArray result;
- BIO *bio = q_BIO_new(q_BIO_s_mem());
- if (!bio)
- return QString();
-
- q_X509_print(bio, x509);
-
- QVarLengthArray<char, 16384> data;
- int count = q_BIO_read(bio, data.data(), 16384);
- if ( count > 0 ) {
- result = QByteArray( data.data(), count );
- }
-
- q_BIO_free(bio);
-
- return QString::fromLatin1(result);
-}
-
-QByteArray QSslCertificatePrivate::asn1ObjectId(ASN1_OBJECT *object)
-{
- char buf[80]; // The openssl docs a buffer length of 80 should be more than enough
- q_OBJ_obj2txt(buf, sizeof(buf), object, 1); // the 1 says always use the oid not the long name
-
- return QByteArray(buf);
-}
-
-
-QByteArray QSslCertificatePrivate::asn1ObjectName(ASN1_OBJECT *object)
-{
- int nid = q_OBJ_obj2nid(object);
- if (nid != NID_undef)
- return QByteArray(q_OBJ_nid2sn(nid));
-
- return asn1ObjectId(object);
-}
-
-static QMultiMap<QByteArray, QString> _q_mapFromX509Name(X509_NAME *name)
-{
- QMultiMap<QByteArray, QString> info;
- for (int i = 0; i < q_X509_NAME_entry_count(name); ++i) {
- X509_NAME_ENTRY *e = q_X509_NAME_get_entry(name, i);
-
- QByteArray name = QSslCertificatePrivate::asn1ObjectName(q_X509_NAME_ENTRY_get_object(e));
- unsigned char *data = nullptr;
- int size = q_ASN1_STRING_to_UTF8(&data, q_X509_NAME_ENTRY_get_data(e));
- info.insert(name, QString::fromUtf8((char*)data, size));
-#if QT_CONFIG(opensslv11)
- q_CRYPTO_free(data, nullptr, 0);
-#else
- q_CRYPTO_free(data);
-#endif
- }
-
- return info;
-}
-
-QSslCertificate QSslCertificatePrivate::QSslCertificate_from_X509(X509 *x509)
-{
- QSslCertificate certificate;
- if (!x509 || !QSslSocket::supportsSsl())
- return certificate;
-
- ASN1_TIME *nbef = q_X509_getm_notBefore(x509);
- ASN1_TIME *naft = q_X509_getm_notAfter(x509);
-
- certificate.d->notValidBefore = q_getTimeFromASN1(nbef);
- certificate.d->notValidAfter = q_getTimeFromASN1(naft);
- certificate.d->null = false;
- certificate.d->x509 = q_X509_dup(x509);
-
- return certificate;
-}
-
-static bool matchLineFeed(const QByteArray &pem, int *offset)
-{
- char ch = 0;
-
- // ignore extra whitespace at the end of the line
- while (*offset < pem.size() && (ch = pem.at(*offset)) == ' ')
- ++*offset;
-
- if (ch == '\n') {
- *offset += 1;
- return true;
- }
- if (ch == '\r' && pem.size() > (*offset + 1) && pem.at(*offset + 1) == '\n') {
- *offset += 2;
- return true;
- }
- return false;
-}
-
-QList<QSslCertificate> QSslCertificatePrivate::certificatesFromPem(const QByteArray &pem, int count)
-{
- QList<QSslCertificate> certificates;
- QSslSocketPrivate::ensureInitialized();
-
- int offset = 0;
- while (count == -1 || certificates.size() < count) {
- int startPos = pem.indexOf(BEGINCERTSTRING, offset);
- if (startPos == -1)
- break;
- startPos += sizeof(BEGINCERTSTRING) - 1;
- if (!matchLineFeed(pem, &startPos))
- break;
-
- int endPos = pem.indexOf(ENDCERTSTRING, startPos);
- if (endPos == -1)
- break;
-
- offset = endPos + sizeof(ENDCERTSTRING) - 1;
- if (offset < pem.size() && !matchLineFeed(pem, &offset))
- break;
-
- QByteArray decoded = QByteArray::fromBase64(
- QByteArray::fromRawData(pem.data() + startPos, endPos - startPos));
- const unsigned char *data = (const unsigned char *)decoded.data();
-
- if (X509 *x509 = q_d2i_X509(nullptr, &data, decoded.size())) {
- certificates << QSslCertificate_from_X509(x509);
- q_X509_free(x509);
- }
- }
-
- return certificates;
-}
-
-QList<QSslCertificate> QSslCertificatePrivate::certificatesFromDer(const QByteArray &der, int count)
-{
- QList<QSslCertificate> certificates;
- QSslSocketPrivate::ensureInitialized();
-
- const unsigned char *data = (const unsigned char *)der.data();
- int size = der.size();
-
- while (size > 0 && (count == -1 || certificates.size() < count)) {
- if (X509 *x509 = q_d2i_X509(nullptr, &data, size)) {
- certificates << QSslCertificate_from_X509(x509);
- q_X509_free(x509);
- } else {
- break;
- }
- size -= ((const char *)data - der.data());
- }
-
- return certificates;
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslcertificate_p.h b/src/network/ssl/qsslcertificate_p.h
index 4588aa7d6f..ca59abae82 100644
--- a/src/network/ssl/qsslcertificate_p.h
+++ b/src/network/ssl/qsslcertificate_p.h
@@ -1,48 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#ifndef QSSLCERTIFICATE_OPENSSL_P_H
-#define QSSLCERTIFICATE_OPENSSL_P_H
-
-#include <QtNetwork/private/qtnetworkglobal_p.h>
-#include "qsslcertificate.h"
+#ifndef QSSLCERTIFICATE_P_H
+#define QSSLCERTIFICATE_P_H
//
// W A R N I N G
@@ -55,99 +16,32 @@
// We mean it.
//
-#ifndef QT_NO_SSL
-#include "qsslsocket_p.h"
-#endif
+#include <QtNetwork/private/qtnetworkglobal_p.h>
+
#include "qsslcertificateextension.h"
-#include <QtCore/qdatetime.h>
-#include <QtCore/qmap.h>
+#include "qsslcertificate.h"
+#include "qtlsbackend_p.h"
-#ifndef QT_NO_OPENSSL
-#include <openssl/x509.h>
-#else
-struct X509;
-struct X509_EXTENSION;
-struct ASN1_OBJECT;
-#endif
+#include <qlist.h>
-#if QT_CONFIG(schannel)
-#include <wincrypt.h>
-#endif
+#include <memory>
QT_BEGIN_NAMESPACE
-// forward declaration
-
class QSslCertificatePrivate
{
public:
- QSslCertificatePrivate()
- : null(true), x509(nullptr)
- {
-#ifndef QT_NO_SSL
- QSslSocketPrivate::ensureInitialized();
-#endif
- }
-
- ~QSslCertificatePrivate()
- {
-#ifndef QT_NO_OPENSSL
- if (x509)
- q_X509_free(x509);
-#endif
-#if QT_CONFIG(schannel)
- if (certificateContext)
- CertFreeCertificateContext(certificateContext);
-#endif
- }
-
- bool null;
- QByteArray versionString;
- QByteArray serialNumberString;
+ QSslCertificatePrivate();
+ ~QSslCertificatePrivate();
- QMultiMap<QByteArray, QString> issuerInfo;
- QMultiMap<QByteArray, QString> subjectInfo;
- QDateTime notValidAfter;
- QDateTime notValidBefore;
-
-#ifdef QT_NO_OPENSSL
- bool subjectMatchesIssuer;
- QSsl::KeyAlgorithm publicKeyAlgorithm;
- QByteArray publicKeyDerData;
- QMultiMap<QSsl::AlternativeNameEntryType, QString> subjectAlternativeNames;
- QList<QSslCertificateExtension> extensions;
-
- QByteArray derData;
-
- bool parse(const QByteArray &data);
- bool parseExtension(const QByteArray &data, QSslCertificateExtension *extension);
-#endif
- X509 *x509;
-
- void init(const QByteArray &data, QSsl::EncodingFormat format);
-
- static QByteArray asn1ObjectId(ASN1_OBJECT *object);
- static QByteArray asn1ObjectName(ASN1_OBJECT *object);
- static QByteArray QByteArray_from_X509(X509 *x509, QSsl::EncodingFormat format);
- static QString text_from_X509(X509 *x509);
- static QSslCertificate QSslCertificate_from_X509(X509 *x509);
- static QList<QSslCertificate> certificatesFromPem(const QByteArray &pem, int count = -1);
- static QList<QSslCertificate> certificatesFromDer(const QByteArray &der, int count = -1);
- static bool isBlacklisted(const QSslCertificate &certificate);
- static QSslCertificateExtension convertExtension(X509_EXTENSION *ext);
- static QByteArray subjectInfoToString(QSslCertificate::SubjectInfo info);
-
- friend class QSslSocketBackendPrivate;
+ QList<QSslCertificateExtension> extensions() const;
+ Q_NETWORK_EXPORT static bool isBlacklisted(const QSslCertificate &certificate);
+ Q_NETWORK_EXPORT static QByteArray subjectInfoToString(QSslCertificate::SubjectInfo info);
QAtomicInt ref;
-
-#if QT_CONFIG(schannel)
- const CERT_CONTEXT *certificateContext = nullptr;
-
- static QSslCertificate QSslCertificate_from_CERT_CONTEXT(const CERT_CONTEXT *certificateContext);
-#endif
+ std::unique_ptr<QTlsPrivate::X509Certificate> backend;
};
QT_END_NAMESPACE
-#endif // QSSLCERTIFICATE_OPENSSL_P_H
+#endif // QSSLCERTIFICATE_P_H
diff --git a/src/network/ssl/qsslcertificate_qt.cpp b/src/network/ssl/qsslcertificate_qt.cpp
deleted file mode 100644
index c0f3710a9a..0000000000
--- a/src/network/ssl/qsslcertificate_qt.cpp
+++ /dev/null
@@ -1,557 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qsslcertificate.h"
-#include "qsslcertificate_p.h"
-
-#include "qssl_p.h"
-#ifndef QT_NO_SSL
-#include "qsslkey.h"
-#include "qsslkey_p.h"
-#endif
-#include "qsslcertificateextension.h"
-#include "qsslcertificateextension_p.h"
-#include "qasn1element_p.h"
-
-#include <QtCore/qdatastream.h>
-#include <QtCore/qendian.h>
-#include <QtNetwork/qhostaddress.h>
-
-QT_BEGIN_NAMESPACE
-
-bool QSslCertificate::operator==(const QSslCertificate &other) const
-{
- if (d == other.d)
- return true;
- if (d->null && other.d->null)
- return true;
- return d->derData == other.d->derData;
-}
-
-size_t qHash(const QSslCertificate &key, size_t seed) noexcept
-{
- // DER is the native encoding here, so toDer() is just "return d->derData":
- return qHash(key.toDer(), seed);
-}
-
-bool QSslCertificate::isNull() const
-{
- return d->null;
-}
-
-bool QSslCertificate::isSelfSigned() const
-{
- if (d->null)
- return false;
-
- qCWarning(lcSsl,
- "QSslCertificate::isSelfSigned: This function does not check, whether the certificate "
- "is actually signed. It just checks whether issuer and subject are identical");
- return d->subjectMatchesIssuer;
-}
-
-QByteArray QSslCertificate::version() const
-{
- return d->versionString;
-}
-
-QByteArray QSslCertificate::serialNumber() const
-{
- return d->serialNumberString;
-}
-
-QStringList QSslCertificate::issuerInfo(SubjectInfo info) const
-{
- return issuerInfo(QSslCertificatePrivate::subjectInfoToString(info));
-}
-
-QStringList QSslCertificate::issuerInfo(const QByteArray &attribute) const
-{
- return d->issuerInfo.values(attribute);
-}
-
-QStringList QSslCertificate::subjectInfo(SubjectInfo info) const
-{
- return subjectInfo(QSslCertificatePrivate::subjectInfoToString(info));
-}
-
-QStringList QSslCertificate::subjectInfo(const QByteArray &attribute) const
-{
- return d->subjectInfo.values(attribute);
-}
-
-QList<QByteArray> QSslCertificate::subjectInfoAttributes() const
-{
- return d->subjectInfo.uniqueKeys();
-}
-
-QList<QByteArray> QSslCertificate::issuerInfoAttributes() const
-{
- return d->issuerInfo.uniqueKeys();
-}
-
-QMultiMap<QSsl::AlternativeNameEntryType, QString> QSslCertificate::subjectAlternativeNames() const
-{
- return d->subjectAlternativeNames;
-}
-
-QDateTime QSslCertificate::effectiveDate() const
-{
- return d->notValidBefore;
-}
-
-QDateTime QSslCertificate::expiryDate() const
-{
- return d->notValidAfter;
-}
-
-#if !QT_CONFIG(schannel) // implemented in qsslcertificate_schannel.cpp
-Qt::HANDLE QSslCertificate::handle() const
-{
- Q_UNIMPLEMENTED();
- return nullptr;
-}
-#endif
-
-#ifndef QT_NO_SSL
-QSslKey QSslCertificate::publicKey() const
-{
- QSslKey key;
- key.d->type = QSsl::PublicKey;
- if (d->publicKeyAlgorithm != QSsl::Opaque) {
- key.d->algorithm = d->publicKeyAlgorithm;
- key.d->decodeDer(d->publicKeyDerData);
- }
- return key;
-}
-#endif
-
-QList<QSslCertificateExtension> QSslCertificate::extensions() const
-{
- return d->extensions;
-}
-
-#define BEGINCERTSTRING "-----BEGIN CERTIFICATE-----"
-#define ENDCERTSTRING "-----END CERTIFICATE-----"
-
-QByteArray QSslCertificate::toPem() const
-{
- QByteArray array = toDer();
-
- // Convert to Base64 - wrap at 64 characters.
- array = array.toBase64();
- QByteArray tmp;
- for (int i = 0; i <= array.size() - 64; i += 64) {
- tmp += QByteArray::fromRawData(array.data() + i, 64);
- tmp += '\n';
- }
- if (int remainder = array.size() % 64) {
- tmp += QByteArray::fromRawData(array.data() + array.size() - remainder, remainder);
- tmp += '\n';
- }
-
- return BEGINCERTSTRING "\n" + tmp + ENDCERTSTRING "\n";
-}
-
-QByteArray QSslCertificate::toDer() const
-{
- return d->derData;
-}
-
-QString QSslCertificate::toText() const
-{
- Q_UNIMPLEMENTED();
- return QString();
-}
-
-void QSslCertificatePrivate::init(const QByteArray &data, QSsl::EncodingFormat format)
-{
- if (!data.isEmpty()) {
- const QList<QSslCertificate> certs = (format == QSsl::Pem)
- ? certificatesFromPem(data, 1)
- : certificatesFromDer(data, 1);
- if (!certs.isEmpty()) {
- *this = *certs.first().d;
-#if QT_CONFIG(schannel)
- if (certificateContext)
- certificateContext = CertDuplicateCertificateContext(certificateContext);
-#endif
- }
- }
-}
-
-static bool matchLineFeed(const QByteArray &pem, int *offset)
-{
- char ch = 0;
-
- // ignore extra whitespace at the end of the line
- while (*offset < pem.size() && (ch = pem.at(*offset)) == ' ')
- ++*offset;
-
- if (ch == '\n') {
- *offset += 1;
- return true;
- }
- if (ch == '\r' && pem.size() > (*offset + 1) && pem.at(*offset + 1) == '\n') {
- *offset += 2;
- return true;
- }
- return false;
-}
-
-QList<QSslCertificate> QSslCertificatePrivate::certificatesFromPem(const QByteArray &pem, int count)
-{
- QList<QSslCertificate> certificates;
- int offset = 0;
- while (count == -1 || certificates.size() < count) {
- int startPos = pem.indexOf(BEGINCERTSTRING, offset);
- if (startPos == -1)
- break;
- startPos += sizeof(BEGINCERTSTRING) - 1;
- if (!matchLineFeed(pem, &startPos))
- break;
-
- int endPos = pem.indexOf(ENDCERTSTRING, startPos);
- if (endPos == -1)
- break;
-
- offset = endPos + sizeof(ENDCERTSTRING) - 1;
- if (offset < pem.size() && !matchLineFeed(pem, &offset))
- break;
-
- QByteArray decoded = QByteArray::fromBase64(
- QByteArray::fromRawData(pem.data() + startPos, endPos - startPos));
- certificates << certificatesFromDer(decoded, 1);;
- }
-
- return certificates;
-}
-
-QList<QSslCertificate> QSslCertificatePrivate::certificatesFromDer(const QByteArray &der, int count)
-{
- QList<QSslCertificate> certificates;
-
- QByteArray data = der;
- while (count == -1 || certificates.size() < count) {
- QSslCertificate cert;
- if (!cert.d->parse(data))
- break;
-
- certificates << cert;
- data.remove(0, cert.d->derData.size());
- }
-
- return certificates;
-}
-
-static QByteArray colonSeparatedHex(const QByteArray &value)
-{
- const int size = value.size();
- int i = 0;
- while (i < size && !value.at(i)) // skip leading zeros
- ++i;
-
- return value.mid(i).toHex(':');
-}
-
-bool QSslCertificatePrivate::parse(const QByteArray &data)
-{
- QAsn1Element root;
-
- QDataStream dataStream(data);
- if (!root.read(dataStream) || root.type() != QAsn1Element::SequenceType)
- return false;
-
- QDataStream rootStream(root.value());
- QAsn1Element cert;
- if (!cert.read(rootStream) || cert.type() != QAsn1Element::SequenceType)
- return false;
-
- // version or serial number
- QAsn1Element elem;
- QDataStream certStream(cert.value());
- if (!elem.read(certStream))
- return false;
-
- if (elem.type() == QAsn1Element::Context0Type) {
- QDataStream versionStream(elem.value());
- if (!elem.read(versionStream) || elem.type() != QAsn1Element::IntegerType)
- return false;
-
- versionString = QByteArray::number(elem.value().at(0) + 1);
- if (!elem.read(certStream))
- return false;
- } else {
- versionString = QByteArray::number(1);
- }
-
- // serial number
- if (elem.type() != QAsn1Element::IntegerType)
- return false;
- serialNumberString = colonSeparatedHex(elem.value());
-
- // algorithm ID
- if (!elem.read(certStream) || elem.type() != QAsn1Element::SequenceType)
- return false;
-
- // issuer info
- if (!elem.read(certStream) || elem.type() != QAsn1Element::SequenceType)
- return false;
-
- QByteArray issuerDer = data.mid(dataStream.device()->pos() - elem.value().length(), elem.value().length());
- issuerInfo = elem.toInfo();
-
- // validity period
- if (!elem.read(certStream) || elem.type() != QAsn1Element::SequenceType)
- return false;
-
- QDataStream validityStream(elem.value());
- if (!elem.read(validityStream) || (elem.type() != QAsn1Element::UtcTimeType && elem.type() != QAsn1Element::GeneralizedTimeType))
- return false;
-
- notValidBefore = elem.toDateTime();
- if (!notValidBefore.isValid())
- return false;
-
- if (!elem.read(validityStream) || (elem.type() != QAsn1Element::UtcTimeType && elem.type() != QAsn1Element::GeneralizedTimeType))
- return false;
-
- notValidAfter = elem.toDateTime();
- if (!notValidAfter.isValid())
- return false;
-
-
- // subject name
- if (!elem.read(certStream) || elem.type() != QAsn1Element::SequenceType)
- return false;
-
- QByteArray subjectDer = data.mid(dataStream.device()->pos() - elem.value().length(), elem.value().length());
- subjectInfo = elem.toInfo();
- subjectMatchesIssuer = issuerDer == subjectDer;
-
- // public key
- qint64 keyStart = certStream.device()->pos();
- if (!elem.read(certStream) || elem.type() != QAsn1Element::SequenceType)
- return false;
-
- publicKeyDerData.resize(certStream.device()->pos() - keyStart);
- QDataStream keyStream(elem.value());
- if (!elem.read(keyStream) || elem.type() != QAsn1Element::SequenceType)
- return false;
-
-
- // key algorithm
- if (!elem.read(elem.value()) || elem.type() != QAsn1Element::ObjectIdentifierType)
- return false;
-
- const QByteArray oid = elem.toObjectId();
- if (oid == RSA_ENCRYPTION_OID)
- publicKeyAlgorithm = QSsl::Rsa;
- else if (oid == DSA_ENCRYPTION_OID)
- publicKeyAlgorithm = QSsl::Dsa;
- else if (oid == EC_ENCRYPTION_OID)
- publicKeyAlgorithm = QSsl::Ec;
- else
- publicKeyAlgorithm = QSsl::Opaque;
-
- certStream.device()->seek(keyStart);
- certStream.readRawData(publicKeyDerData.data(), publicKeyDerData.size());
-
- // extensions
- while (elem.read(certStream)) {
- if (elem.type() == QAsn1Element::Context3Type) {
- if (elem.read(elem.value()) && elem.type() == QAsn1Element::SequenceType) {
- QDataStream extStream(elem.value());
- while (elem.read(extStream) && elem.type() == QAsn1Element::SequenceType) {
- QSslCertificateExtension extension;
- if (!parseExtension(elem.value(), &extension))
- return false;
- extensions << extension;
-
- if (extension.oid() == QLatin1String("2.5.29.17")) {
- // subjectAltName
- QAsn1Element sanElem;
- if (sanElem.read(extension.value().toByteArray()) && sanElem.type() == QAsn1Element::SequenceType) {
- QDataStream nameStream(sanElem.value());
- QAsn1Element nameElem;
- while (nameElem.read(nameStream)) {
- switch (nameElem.type()) {
- case QAsn1Element::Rfc822NameType:
- subjectAlternativeNames.insert(QSsl::EmailEntry, nameElem.toString());
- break;
- case QAsn1Element::DnsNameType:
- subjectAlternativeNames.insert(QSsl::DnsEntry, nameElem.toString());
- break;
- case QAsn1Element::IpAddressType: {
- QHostAddress ipAddress;
- QByteArray ipAddrValue = nameElem.value();
- switch (ipAddrValue.length()) {
- case 4: // IPv4
- ipAddress = QHostAddress(qFromBigEndian(*reinterpret_cast<quint32 *>(ipAddrValue.data())));
- break;
- case 16: // IPv6
- ipAddress = QHostAddress(reinterpret_cast<quint8 *>(ipAddrValue.data()));
- break;
- default: // Unknown IP address format
- break;
- }
- if (!ipAddress.isNull())
- subjectAlternativeNames.insert(QSsl::IpAddressEntry, ipAddress.toString());
- break;
- }
- default:
- break;
- }
- }
- }
- }
- }
- }
- }
- }
-
- derData = data.left(dataStream.device()->pos());
- null = false;
- return true;
-}
-
-bool QSslCertificatePrivate::parseExtension(const QByteArray &data, QSslCertificateExtension *extension)
-{
- bool ok;
- bool critical = false;
- QAsn1Element oidElem, valElem;
-
- QDataStream seqStream(data);
-
- // oid
- if (!oidElem.read(seqStream) || oidElem.type() != QAsn1Element::ObjectIdentifierType)
- return false;
- const QByteArray oid = oidElem.toObjectId();
-
- // critical and value
- if (!valElem.read(seqStream))
- return false;
- if (valElem.type() == QAsn1Element::BooleanType) {
- critical = valElem.toBool(&ok);
- if (!ok || !valElem.read(seqStream))
- return false;
- }
- if (valElem.type() != QAsn1Element::OctetStringType)
- return false;
-
- // interpret value
- QAsn1Element val;
- bool supported = true;
- QVariant value;
- if (oid == "1.3.6.1.5.5.7.1.1") {
- // authorityInfoAccess
- if (!val.read(valElem.value()) || val.type() != QAsn1Element::SequenceType)
- return false;
- QVariantMap result;
- const auto elems = val.toList();
- for (const QAsn1Element &el : elems) {
- const auto items = el.toList();
- if (items.size() != 2)
- return false;
- const QString key = QString::fromLatin1(items.at(0).toObjectName());
- switch (items.at(1).type()) {
- case QAsn1Element::Rfc822NameType:
- case QAsn1Element::DnsNameType:
- case QAsn1Element::UniformResourceIdentifierType:
- result[key] = items.at(1).toString();
- break;
- }
- }
- value = result;
- } else if (oid == "2.5.29.14") {
- // subjectKeyIdentifier
- if (!val.read(valElem.value()) || val.type() != QAsn1Element::OctetStringType)
- return false;
- value = colonSeparatedHex(val.value()).toUpper();
- } else if (oid == "2.5.29.19") {
- // basicConstraints
- if (!val.read(valElem.value()) || val.type() != QAsn1Element::SequenceType)
- return false;
-
- QVariantMap result;
- const auto items = val.toList();
- if (items.size() > 0) {
- result[QStringLiteral("ca")] = items.at(0).toBool(&ok);
- if (!ok)
- return false;
- } else {
- result[QStringLiteral("ca")] = false;
- }
- if (items.size() > 1) {
- result[QStringLiteral("pathLenConstraint")] = items.at(1).toInteger(&ok);
- if (!ok)
- return false;
- }
- value = result;
- } else if (oid == "2.5.29.35") {
- // authorityKeyIdentifier
- if (!val.read(valElem.value()) || val.type() != QAsn1Element::SequenceType)
- return false;
- QVariantMap result;
- const auto elems = val.toList();
- for (const QAsn1Element &el : elems) {
- if (el.type() == 0x80) {
- const QString key = QStringLiteral("keyid");
- result[key] = el.value().toHex();
- } else if (el.type() == 0x82) {
- const QString serial = QStringLiteral("serial");
- result[serial] = colonSeparatedHex(el.value());
- }
- }
- value = result;
- } else {
- supported = false;
- value = valElem.value();
- }
-
- extension->d->critical = critical;
- extension->d->supported = supported;
- extension->d->oid = QString::fromLatin1(oid);
- extension->d->name = QString::fromLatin1(oidElem.toObjectName());
- extension->d->value = value;
-
- return true;
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslcertificate_schannel.cpp b/src/network/ssl/qsslcertificate_schannel.cpp
deleted file mode 100644
index 5ea713612a..0000000000
--- a/src/network/ssl/qsslcertificate_schannel.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qsslcertificate.h"
-#include "qsslcertificate_p.h"
-
-#include <wincrypt.h>
-
-QT_BEGIN_NAMESPACE
-
-QSslCertificate QSslCertificatePrivate::QSslCertificate_from_CERT_CONTEXT(const CERT_CONTEXT *certificateContext)
-{
- QByteArray derData = QByteArray((const char *)certificateContext->pbCertEncoded,
- certificateContext->cbCertEncoded);
-
- QSslCertificate certificate(derData, QSsl::Der);
- certificate.d->certificateContext = CertDuplicateCertificateContext(certificateContext);
- return certificate;
-}
-
-Qt::HANDLE QSslCertificate::handle() const
-{
- return Qt::HANDLE(d->certificateContext);
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslcertificateextension.cpp b/src/network/ssl/qsslcertificateextension.cpp
index 4896d3909a..3f583e2e2f 100644
--- a/src/network/ssl/qsslcertificateextension.cpp
+++ b/src/network/ssl/qsslcertificateextension.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2011 Richard J. Moore <rich@kde.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2011 Richard J. Moore <rich@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/*!
\class QSslCertificateExtension
diff --git a/src/network/ssl/qsslcertificateextension.h b/src/network/ssl/qsslcertificateextension.h
index 7cc8a888be..c639d2fa45 100644
--- a/src/network/ssl/qsslcertificateextension.h
+++ b/src/network/ssl/qsslcertificateextension.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2011 Richard J. Moore <rich@kde.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2011 Richard J. Moore <rich@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSSLCERTIFICATEEXTENSION_H
#define QSSLCERTIFICATEEXTENSION_H
@@ -59,7 +23,7 @@ public:
QSslCertificateExtension &operator=(const QSslCertificateExtension &other);
~QSslCertificateExtension();
- void swap(QSslCertificateExtension &other) noexcept { qSwap(d, other.d); }
+ void swap(QSslCertificateExtension &other) noexcept { d.swap(other.d); }
QString oid() const;
QString name() const;
diff --git a/src/network/ssl/qsslcertificateextension_p.h b/src/network/ssl/qsslcertificateextension_p.h
index 373f92a5cf..3f5d1e373e 100644
--- a/src/network/ssl/qsslcertificateextension_p.h
+++ b/src/network/ssl/qsslcertificateextension_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2011 Richard J. Moore <rich@kde.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2011 Richard J. Moore <rich@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSSLCERTIFICATEEXTENSION_P_H
#define QSSLCERTIFICATEEXTENSION_P_H
diff --git a/src/network/ssl/qsslcipher.cpp b/src/network/ssl/qsslcipher.cpp
index 738d521a38..2a4da7991a 100644
--- a/src/network/ssl/qsslcipher.cpp
+++ b/src/network/ssl/qsslcipher.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/*!
@@ -68,6 +32,9 @@
QT_BEGIN_NAMESPACE
+static_assert(QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+ && sizeof(QScopedPointer<QSslCipherPrivate>) == sizeof(std::unique_ptr<QSslCipherPrivate>));
+
/*!
Constructs an empty QSslCipher object.
*/
@@ -127,7 +94,7 @@ QSslCipher::QSslCipher(const QString &name, QSsl::SslProtocol protocol)
QSslCipher::QSslCipher(const QSslCipher &other)
: d(new QSslCipherPrivate)
{
- *d.data() = *other.d.data();
+ *d.get() = *other.d.get();
}
/*!
@@ -143,7 +110,7 @@ QSslCipher::~QSslCipher()
*/
QSslCipher &QSslCipher::operator=(const QSslCipher &other)
{
- *d.data() = *other.d.data();
+ *d.get() = *other.d.get();
return *this;
}
diff --git a/src/network/ssl/qsslcipher.h b/src/network/ssl/qsslcipher.h
index 6994f590ae..ed727947f5 100644
--- a/src/network/ssl/qsslcipher.h
+++ b/src/network/ssl/qsslcipher.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSSLCIPHER_H
@@ -46,6 +10,8 @@
#include <QtCore/qscopedpointer.h>
#include <QtNetwork/qssl.h>
+#include <memory>
+
QT_BEGIN_NAMESPACE
@@ -64,7 +30,7 @@ public:
~QSslCipher();
void swap(QSslCipher &other) noexcept
- { qSwap(d, other.d); }
+ { d.swap(other.d); }
bool operator==(const QSslCipher &other) const;
inline bool operator!=(const QSslCipher &other) const { return !operator==(other); }
@@ -81,8 +47,9 @@ public:
QSsl::SslProtocol protocol() const;
private:
- QScopedPointer<QSslCipherPrivate> d;
- friend class QSslSocketBackendPrivate;
+ // ### Qt 7: make implicitly shared
+ std::unique_ptr<QSslCipherPrivate> d;
+ friend class QTlsBackend;
};
Q_DECLARE_SHARED(QSslCipher)
diff --git a/src/network/ssl/qsslcipher_p.h b/src/network/ssl/qsslcipher_p.h
index b8629f9f96..d7f5e7c471 100644
--- a/src/network/ssl/qsslcipher_p.h
+++ b/src/network/ssl/qsslcipher_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSSLCIPHER_P_H
#define QSSLCIPHER_P_H
diff --git a/src/network/ssl/qsslconfiguration.cpp b/src/network/ssl/qsslconfiguration.cpp
index 4b41d84633..fd308d7037 100644
--- a/src/network/ssl/qsslconfiguration.cpp
+++ b/src/network/ssl/qsslconfiguration.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2014 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qssl_p.h"
#include "qsslconfiguration.h"
@@ -48,6 +12,8 @@
QT_BEGIN_NAMESPACE
+QT_IMPL_METATYPE_EXTERN(QSslConfiguration)
+
const QSsl::SslOptions QSslConfigurationPrivate::defaultSslOptions = QSsl::SslOptionDisableEmptyFragments
|QSsl::SslOptionDisableLegacyRenegotiation
|QSsl::SslOptionDisableCompression
@@ -107,7 +73,7 @@ const char QSslConfiguration::NextProtocolHttp1_1[] = "http/1.1";
change the settings in the related SSL connection. You must call
setSslConfiguration on a modified QSslConfiguration object to
achieve that. The following example illustrates how to change the
- protocol to TLSv1_0 in a QSslSocket object:
+ protocol to TLSv1_2 in a QSslSocket object:
\snippet code/src_network_ssl_qsslconfiguration.cpp 0
@@ -139,6 +105,12 @@ const char QSslConfiguration::NextProtocolHttp1_1[] = "http/1.1";
*/
/*!
+ \variable QSslConfiguration::ALPNProtocolHTTP2
+ \brief The value used for negotiating HTTP 2 during the Application-Layer
+ Protocol Negotiation.
+*/
+
+/*!
Constructs an empty SSL configuration. This configuration contains
no valid settings and the state will be empty. isNull() will
return true after this constructor is called.
@@ -252,15 +224,15 @@ bool QSslConfiguration::isNull() const
d->peerVerifyMode == QSslSocket::AutoVerifyPeer &&
d->peerVerifyDepth == 0 &&
d->allowRootCertOnDemandLoading == true &&
- d->caCertificates.count() == 0 &&
- d->ciphers.count() == 0 &&
+ d->caCertificates.size() == 0 &&
+ d->ciphers.size() == 0 &&
d->ellipticCurves.isEmpty() &&
d->ephemeralServerKey.isNull() &&
d->dhParams == QSslDiffieHellmanParameters::defaultParameters() &&
d->localCertificateChain.isEmpty() &&
d->privateKey.isNull() &&
d->peerCertificate.isNull() &&
- d->peerCertificateChain.count() == 0 &&
+ d->peerCertificateChain.size() == 0 &&
d->backendConfig.isEmpty() &&
d->sslOptions == QSslConfigurationPrivate::defaultSslOptions &&
d->sslSession.isNull() &&
@@ -584,8 +556,6 @@ void QSslConfiguration::setPrivateKey(const QSslKey &key)
ciphers. You can revert to using the entire set by calling
setCiphers() with the list returned by supportedCiphers().
- \note This is not currently supported in the Schannel backend.
-
\sa setCiphers(), supportedCiphers()
*/
QList<QSslCipher> QSslConfiguration::ciphers() const
@@ -601,8 +571,6 @@ QList<QSslCipher> QSslConfiguration::ciphers() const
Restricting the cipher suite must be done before the handshake
phase, where the session cipher is chosen.
- \note This is not currently supported in the Schannel backend.
-
\sa ciphers(), supportedCiphers()
*/
void QSslConfiguration::setCiphers(const QList<QSslCipher> &ciphers)
@@ -615,27 +583,26 @@ void QSslConfiguration::setCiphers(const QList<QSslCipher> &ciphers)
Sets the cryptographic cipher suite for this configuration to \a ciphers,
which is a colon-separated list of cipher suite names. The ciphers are listed
- in order of preference, starting with the most preferred cipher. For example:
-
- \snippet code/src_network_ssl_qsslconfiguration.cpp 1
-
+ in order of preference, starting with the most preferred cipher.
Each cipher name in \a ciphers must be the name of a cipher in the
list returned by supportedCiphers(). Restricting the cipher suite
must be done before the handshake phase, where the session cipher
is chosen.
- \note This is not currently supported in the Schannel backend.
+ \note With the Schannel backend the order of the ciphers is ignored and Schannel
+ picks the most secure one during the handshake.
\sa ciphers()
*/
void QSslConfiguration::setCiphers(const QString &ciphers)
{
- d->ciphers.clear();
- const auto cipherNames = ciphers.split(QLatin1Char(':'), Qt::SkipEmptyParts);
+ auto *p = d.data();
+ p->ciphers.clear();
+ const auto cipherNames = ciphers.split(u':', Qt::SkipEmptyParts);
for (const QString &cipherName : cipherNames) {
QSslCipher cipher(cipherName);
if (!cipher.isNull())
- d->ciphers << cipher;
+ p->ciphers << cipher;
}
}
@@ -955,7 +922,11 @@ void QSslConfiguration::setPreSharedKeyIdentityHint(const QByteArray &hint)
Retrieves the current set of Diffie-Hellman parameters.
If no Diffie-Hellman parameters have been set, the QSslConfiguration object
- defaults to using the 1024-bit MODP group from RFC 2409.
+ defaults to using the 2048-bit MODP group from RFC 3526.
+
+ \note The default parameters may change in future Qt versions.
+ Please check the documentation of the \e{exact Qt version} that you
+ are using in order to know what defaults that version uses.
*/
QSslDiffieHellmanParameters QSslConfiguration::diffieHellmanParameters() const
{
@@ -969,7 +940,14 @@ QSslDiffieHellmanParameters QSslConfiguration::diffieHellmanParameters() const
a server to \a dhparams.
If no Diffie-Hellman parameters have been set, the QSslConfiguration object
- defaults to using the 1024-bit MODP group from RFC 2409.
+ defaults to using the 2048-bit MODP group from RFC 3526.
+
+ Since 6.7 you can provide an empty Diffie-Hellman parameter to use auto selection
+ (see SSL_CTX_set_dh_auto of openssl) if the tls backend supports it.
+
+ \note The default parameters may change in future Qt versions.
+ Please check the documentation of the \e{exact Qt version} that you
+ are using in order to know what defaults that version uses.
*/
void QSslConfiguration::setDiffieHellmanParameters(const QSslDiffieHellmanParameters &dhparams)
{
@@ -1131,7 +1109,7 @@ void QSslConfiguration::setDefaultConfiguration(const QSslConfiguration &configu
QSslConfigurationPrivate::setDefaultConfiguration(configuration);
}
-#if QT_CONFIG(dtls) || defined(Q_CLANG_QDOC)
+#if QT_CONFIG(dtls) || defined(Q_QDOC)
/*!
This function returns true if DTLS cookie verification was enabled on a
diff --git a/src/network/ssl/qsslconfiguration.h b/src/network/ssl/qsslconfiguration.h
index 116920950e..dd2dd2a97c 100644
--- a/src/network/ssl/qsslconfiguration.h
+++ b/src/network/ssl/qsslconfiguration.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2014 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/****************************************************************************
**
@@ -72,11 +36,6 @@ class QSslKey;
class QSslEllipticCurve;
class QSslDiffieHellmanParameters;
-namespace dtlsopenssl
-{
-class DtlsState;
-}
-
class QSslConfigurationPrivate;
class Q_NETWORK_EXPORT QSslConfiguration
{
@@ -88,7 +47,7 @@ public:
QSslConfiguration &operator=(const QSslConfiguration &other);
void swap(QSslConfiguration &other) noexcept
- { qSwap(d, other.d); }
+ { d.swap(other.d); }
bool operator==(const QSslConfiguration &other) const;
inline bool operator!=(const QSslConfiguration &other) const
@@ -166,7 +125,7 @@ public:
static QSslConfiguration defaultConfiguration();
static void setDefaultConfiguration(const QSslConfiguration &configuration);
-#if QT_CONFIG(dtls) || defined(Q_CLANG_QDOC)
+#if QT_CONFIG(dtls) || defined(Q_QDOC)
bool dtlsCookieVerificationEnabled() const;
void setDtlsCookieVerificationEnabled(bool enable);
@@ -201,10 +160,8 @@ public:
private:
friend class QSslSocket;
friend class QSslConfigurationPrivate;
- friend class QSslSocketBackendPrivate;
friend class QSslContext;
- friend class QDtlsBasePrivate;
- friend class dtlsopenssl::DtlsState;
+ friend class QTlsBackend;
QSslConfiguration(QSslConfigurationPrivate *dd);
QSharedDataPointer<QSslConfigurationPrivate> d;
};
@@ -213,7 +170,7 @@ Q_DECLARE_SHARED(QSslConfiguration)
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QSslConfiguration)
+QT_DECL_METATYPE_EXTERN(QSslConfiguration, Q_NETWORK_EXPORT)
#endif // QT_NO_SSL
diff --git a/src/network/ssl/qsslconfiguration_p.h b/src/network/ssl/qsslconfiguration_p.h
index 3d416b42d7..a31e7e1f04 100644
--- a/src/network/ssl/qsslconfiguration_p.h
+++ b/src/network/ssl/qsslconfiguration_p.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2014 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/****************************************************************************
**
@@ -118,7 +82,7 @@ public:
QSsl::SslOptions sslOptions;
- Q_AUTOTEST_EXPORT static const QSsl::SslOptions defaultSslOptions;
+ static const QSsl::SslOptions defaultSslOptions;
QList<QSslEllipticCurve> ellipticCurves;
diff --git a/src/network/ssl/qsslcontext_openssl.cpp b/src/network/ssl/qsslcontext_openssl.cpp
deleted file mode 100644
index 5fb7172583..0000000000
--- a/src/network/ssl/qsslcontext_openssl.cpp
+++ /dev/null
@@ -1,767 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
-** Copyright (C) 2014 Governikus GmbH & Co. KG.
-** Copyright (C) 2016 Richard J. Moore <rich@kde.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtNetwork/qsslsocket.h>
-#include <QtNetwork/qssldiffiehellmanparameters.h>
-
-#include "private/qssl_p.h"
-#include "private/qsslsocket_p.h"
-#include "private/qsslcontext_openssl_p.h"
-#include "private/qsslsocket_openssl_p.h"
-#include "private/qsslsocket_openssl_symbols_p.h"
-#include "private/qssldiffiehellmanparameters_p.h"
-
-#include <vector>
-
-QT_BEGIN_NAMESPACE
-
-Q_GLOBAL_STATIC(bool, forceSecurityLevel)
-
-Q_NETWORK_EXPORT void qt_ForceTlsSecurityLevel()
-{
- *forceSecurityLevel() = true;
-}
-
-// defined in qsslsocket_openssl.cpp:
-extern int q_X509Callback(int ok, X509_STORE_CTX *ctx);
-extern "C" int q_X509CallbackDirect(int ok, X509_STORE_CTX *ctx);
-extern QString getErrorsFromOpenSsl();
-
-#if QT_CONFIG(dtls)
-// defined in qdtls_openssl.cpp:
-namespace dtlscallbacks
-{
-extern "C" int q_X509DtlsCallback(int ok, X509_STORE_CTX *ctx);
-extern "C" int q_generate_cookie_callback(SSL *ssl, unsigned char *dst,
- unsigned *cookieLength);
-extern "C" int q_verify_cookie_callback(SSL *ssl, const unsigned char *cookie,
- unsigned cookieLength);
-}
-#endif // dtls
-
-#ifdef TLS1_3_VERSION
-extern "C" int q_ssl_sess_set_new_cb(SSL *context, SSL_SESSION *session);
-#endif // TLS1_3_VERSION
-
-// Defined in qsslsocket.cpp
-QList<QSslCipher> q_getDefaultDtlsCiphers();
-
-static inline QString msgErrorSettingBackendConfig(const QString &why)
-{
- return QSslSocket::tr("Error when setting the OpenSSL configuration (%1)").arg(why);
-}
-
-static inline QString msgErrorSettingEllipticCurves(const QString &why)
-{
- return QSslSocket::tr("Error when setting the elliptic curves (%1)").arg(why);
-}
-
-QSslContext::QSslContext()
- : ctx(nullptr),
- pkey(nullptr),
- session(nullptr),
- m_sessionTicketLifeTimeHint(-1)
-{
-}
-
-QSslContext::~QSslContext()
-{
- if (ctx)
- // This will decrement the reference count by 1 and free the context eventually when possible
- q_SSL_CTX_free(ctx);
-
- if (pkey)
- q_EVP_PKEY_free(pkey);
-
- if (session)
- q_SSL_SESSION_free(session);
-}
-
-QSslContext* QSslContext::fromConfiguration(QSslSocket::SslMode mode, const QSslConfiguration &configuration, bool allowRootCertOnDemandLoading)
-{
- QSslContext *sslContext = new QSslContext();
- initSslContext(sslContext, mode, configuration, allowRootCertOnDemandLoading);
- return sslContext;
-}
-
-QSharedPointer<QSslContext> QSslContext::sharedFromConfiguration(QSslSocket::SslMode mode, const QSslConfiguration &configuration, bool allowRootCertOnDemandLoading)
-{
- QSharedPointer<QSslContext> sslContext = QSharedPointer<QSslContext>::create();
- initSslContext(sslContext.data(), mode, configuration, allowRootCertOnDemandLoading);
- return sslContext;
-}
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
-
-static int next_proto_cb(SSL *, unsigned char **out, unsigned char *outlen,
- const unsigned char *in, unsigned int inlen, void *arg)
-{
- QSslContext::NPNContext *ctx = reinterpret_cast<QSslContext::NPNContext *>(arg);
-
- // comment out to debug:
-// QList<QByteArray> supportedVersions;
-// for (unsigned int i = 0; i < inlen; ) {
-// QByteArray version(reinterpret_cast<const char *>(&in[i+1]), in[i]);
-// supportedVersions << version;
-// i += in[i] + 1;
-// }
-
- int proto = q_SSL_select_next_proto(out, outlen, in, inlen, ctx->data, ctx->len);
- switch (proto) {
- case OPENSSL_NPN_UNSUPPORTED:
- ctx->status = QSslConfiguration::NextProtocolNegotiationNone;
- break;
- case OPENSSL_NPN_NEGOTIATED:
- ctx->status = QSslConfiguration::NextProtocolNegotiationNegotiated;
- break;
- case OPENSSL_NPN_NO_OVERLAP:
- ctx->status = QSslConfiguration::NextProtocolNegotiationUnsupported;
- break;
- default:
- qCWarning(lcSsl, "OpenSSL sent unknown NPN status");
- }
-
- return SSL_TLSEXT_ERR_OK;
-}
-
-QSslContext::NPNContext QSslContext::npnContext() const
-{
- return m_npnContext;
-}
-#endif // !OPENSSL_NO_NEXTPROTONEG
-
-
-
-// Needs to be deleted by caller
-SSL* QSslContext::createSsl()
-{
- SSL* ssl = q_SSL_new(ctx);
- q_SSL_clear(ssl);
-
- if (!session && !sessionASN1().isEmpty()
- && !sslConfiguration.testSslOption(QSsl::SslOptionDisableSessionPersistence)) {
- const unsigned char *data = reinterpret_cast<const unsigned char *>(m_sessionASN1.constData());
- session = q_d2i_SSL_SESSION(nullptr, &data, m_sessionASN1.size());
- // 'session' has refcount 1 already, set by the function above
- }
-
- if (session) {
- // Try to resume the last session we cached
- if (!q_SSL_set_session(ssl, session)) {
- qCWarning(lcSsl, "could not set SSL session");
- q_SSL_SESSION_free(session);
- session = nullptr;
- }
- }
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
- QList<QByteArray> protocols = sslConfiguration.d->nextAllowedProtocols;
- if (!protocols.isEmpty()) {
- m_supportedNPNVersions.clear();
- for (int a = 0; a < protocols.count(); ++a) {
- if (protocols.at(a).size() > 255) {
- qCWarning(lcSsl) << "TLS NPN extension" << protocols.at(a)
- << "is too long and will be ignored.";
- continue;
- } else if (protocols.at(a).isEmpty()) {
- continue;
- }
- m_supportedNPNVersions.append(protocols.at(a).size()).append(protocols.at(a));
- }
- if (m_supportedNPNVersions.size()) {
- m_npnContext.data = reinterpret_cast<unsigned char *>(m_supportedNPNVersions.data());
- m_npnContext.len = m_supportedNPNVersions.count();
- m_npnContext.status = QSslConfiguration::NextProtocolNegotiationNone;
- // Callback's type has a parameter 'const unsigned char ** out'
- // since it was introduced in 1.0.2. Internally, OpenSSL's own code
- // (tests/examples) cast it to unsigned char * (since it's 'out').
- // We just re-use our NPN callback and cast here:
- typedef int (*alpn_callback_t) (SSL *, const unsigned char **, unsigned char *,
- const unsigned char *, unsigned int, void *);
- // With ALPN callback is for a server side only, for a client m_npnContext.status
- // will stay in NextProtocolNegotiationNone.
- q_SSL_CTX_set_alpn_select_cb(ctx, alpn_callback_t(next_proto_cb), &m_npnContext);
- // Client:
- q_SSL_set_alpn_protos(ssl, m_npnContext.data, m_npnContext.len);
- // And in case our peer does not support ALPN, but supports NPN:
- q_SSL_CTX_set_next_proto_select_cb(ctx, next_proto_cb, &m_npnContext);
- }
- }
-#endif // !OPENSSL_NO_NEXTPROTONEG
-
- return ssl;
-}
-
-// We cache exactly one session here
-bool QSslContext::cacheSession(SSL* ssl)
-{
- // don't cache the same session again
- if (session && session == q_SSL_get_session(ssl))
- return true;
-
- // decrease refcount of currently stored session
- // (this might happen if there are several concurrent handshakes in flight)
- if (session)
- q_SSL_SESSION_free(session);
-
- // cache the session the caller gave us and increase reference count
- session = q_SSL_get1_session(ssl);
-
- if (session && !sslConfiguration.testSslOption(QSsl::SslOptionDisableSessionPersistence)) {
- int sessionSize = q_i2d_SSL_SESSION(session, nullptr);
- if (sessionSize > 0) {
- m_sessionASN1.resize(sessionSize);
- unsigned char *data = reinterpret_cast<unsigned char *>(m_sessionASN1.data());
- if (!q_i2d_SSL_SESSION(session, &data))
- qCWarning(lcSsl, "could not store persistent version of SSL session");
- m_sessionTicketLifeTimeHint = q_SSL_SESSION_get_ticket_lifetime_hint(session);
- }
- }
-
- return (session != nullptr);
-}
-
-QByteArray QSslContext::sessionASN1() const
-{
- return m_sessionASN1;
-}
-
-void QSslContext::setSessionASN1(const QByteArray &session)
-{
- m_sessionASN1 = session;
-}
-
-int QSslContext::sessionTicketLifeTimeHint() const
-{
- return m_sessionTicketLifeTimeHint;
-}
-
-QSslError::SslError QSslContext::error() const
-{
- return errorCode;
-}
-
-QString QSslContext::errorString() const
-{
- return errorStr;
-}
-
-void QSslContext::initSslContext(QSslContext *sslContext, QSslSocket::SslMode mode,
- const QSslConfiguration &configuration,
- bool allowRootCertOnDemandLoading)
-{
- sslContext->sslConfiguration = configuration;
- sslContext->errorCode = QSslError::NoError;
-
- bool client = (mode == QSslSocket::SslClientMode);
-
- bool reinitialized = false;
- bool unsupportedProtocol = false;
- bool isDtls = false;
-init_context:
- switch (sslContext->sslConfiguration.protocol()) {
- case QSsl::DtlsV1_0:
- case QSsl::DtlsV1_0OrLater:
- case QSsl::DtlsV1_2:
- case QSsl::DtlsV1_2OrLater:
-#if QT_CONFIG(dtls)
- isDtls = true;
- sslContext->ctx = q_SSL_CTX_new(client ? q_DTLS_client_method() : q_DTLS_server_method());
-#else // dtls
- sslContext->ctx = nullptr;
- unsupportedProtocol = true;
- qCWarning(lcSsl, "DTLS protocol requested, but feature 'dtls' is disabled");
-#endif // dtls
- break;
- case QSsl::TlsV1_3:
- case QSsl::TlsV1_3OrLater:
-#if !defined(TLS1_3_VERSION)
- qCWarning(lcSsl, "TLS 1.3 is not supported");
- sslContext->ctx = nullptr;
- unsupportedProtocol = true;
- break;
-#endif // TLS1_3_VERSION
- default:
- // The ssl options will actually control the supported methods
- sslContext->ctx = q_SSL_CTX_new(client ? q_TLS_client_method() : q_TLS_server_method());
- }
-
- if (!sslContext->ctx) {
- // After stopping Flash 10 the SSL library loses its ciphers. Try re-adding them
- // by re-initializing the library.
- if (!reinitialized) {
- reinitialized = true;
- if (q_OPENSSL_init_ssl(0, nullptr) == 1)
- goto init_context;
- }
-
- sslContext->errorStr = QSslSocket::tr("Error creating SSL context (%1)").arg(
- unsupportedProtocol ? QSslSocket::tr("unsupported protocol") : QSslSocketBackendPrivate::getErrorsFromOpenSsl()
- );
- sslContext->errorCode = QSslError::UnspecifiedError;
- return;
- }
-
- // A nasty hacked OpenSSL using a level that will make our auto-tests fail:
- if (q_SSL_CTX_get_security_level(sslContext->ctx) > 1 && *forceSecurityLevel())
- q_SSL_CTX_set_security_level(sslContext->ctx, 1);
-
- const long anyVersion =
-#if QT_CONFIG(dtls)
- isDtls ? DTLS_ANY_VERSION : TLS_ANY_VERSION;
-#else
- TLS_ANY_VERSION;
-#endif // dtls
- long minVersion = anyVersion;
- long maxVersion = anyVersion;
-
- switch (sslContext->sslConfiguration.protocol()) {
- case QSsl::TlsV1_0:
- minVersion = TLS1_VERSION;
- maxVersion = TLS1_VERSION;
- break;
- case QSsl::TlsV1_1:
- minVersion = TLS1_1_VERSION;
- maxVersion = TLS1_1_VERSION;
- break;
- case QSsl::TlsV1_2:
- minVersion = TLS1_2_VERSION;
- maxVersion = TLS1_2_VERSION;
- break;
- case QSsl::TlsV1_3:
-#ifdef TLS1_3_VERSION
- minVersion = TLS1_3_VERSION;
- maxVersion = TLS1_3_VERSION;
-#else
- // This protocol is not supported by OpenSSL 1.1 and we handle
- // it as an error (see the code above).
- Q_UNREACHABLE();
-#endif // TLS1_3_VERSION
- break;
- // Ranges:
- case QSsl::AnyProtocol:
- case QSsl::SecureProtocols:
- case QSsl::TlsV1_0OrLater:
- minVersion = TLS1_VERSION;
- maxVersion = 0;
- break;
- case QSsl::TlsV1_1OrLater:
- minVersion = TLS1_1_VERSION;
- maxVersion = 0;
- break;
- case QSsl::TlsV1_2OrLater:
- minVersion = TLS1_2_VERSION;
- maxVersion = 0;
- break;
- case QSsl::DtlsV1_0:
- minVersion = DTLS1_VERSION;
- maxVersion = DTLS1_VERSION;
- break;
- case QSsl::DtlsV1_0OrLater:
- minVersion = DTLS1_VERSION;
- maxVersion = DTLS_MAX_VERSION;
- break;
- case QSsl::DtlsV1_2:
- minVersion = DTLS1_2_VERSION;
- maxVersion = DTLS1_2_VERSION;
- break;
- case QSsl::DtlsV1_2OrLater:
- minVersion = DTLS1_2_VERSION;
- maxVersion = DTLS_MAX_VERSION;
- break;
- case QSsl::TlsV1_3OrLater:
-#ifdef TLS1_3_VERSION
- minVersion = TLS1_3_VERSION;
- maxVersion = 0;
- break;
-#else
- // This protocol is not supported by OpenSSL 1.1 and we handle
- // it as an error (see the code above).
- Q_UNREACHABLE();
- break;
-#endif // TLS1_3_VERSION
- case QSsl::UnknownProtocol:
- break;
- }
-
- if (minVersion != anyVersion
- && !q_SSL_CTX_set_min_proto_version(sslContext->ctx, minVersion)) {
- sslContext->errorStr = QSslSocket::tr("Error while setting the minimal protocol version");
- sslContext->errorCode = QSslError::UnspecifiedError;
- return;
- }
-
- if (maxVersion != anyVersion
- && !q_SSL_CTX_set_max_proto_version(sslContext->ctx, maxVersion)) {
- sslContext->errorStr = QSslSocket::tr("Error while setting the maximum protocol version");
- sslContext->errorCode = QSslError::UnspecifiedError;
- return;
- }
-
- // Enable bug workarounds.
- long options = QSslSocketBackendPrivate::setupOpenSslOptions(configuration.protocol(), configuration.d->sslOptions);
- q_SSL_CTX_set_options(sslContext->ctx, options);
-
- // Tell OpenSSL to release memory early
- // http://www.openssl.org/docs/ssl/SSL_CTX_set_mode.html
- q_SSL_CTX_set_mode(sslContext->ctx, SSL_MODE_RELEASE_BUFFERS);
-
- auto filterCiphers = [](const QList<QSslCipher> &ciphers, bool selectTls13)
- {
- QByteArray cipherString;
-
- for (const QSslCipher &cipher : ciphers) {
- const bool isTls13Cipher = cipher.protocol() == QSsl::TlsV1_3 || cipher.protocol() == QSsl::TlsV1_3OrLater;
- if (selectTls13 != isTls13Cipher)
- continue;
-
- if (cipherString.size())
- cipherString.append(':');
- cipherString.append(cipher.name().toLatin1());
- }
- return cipherString;
- };
-
- // Initialize ciphers
- QList<QSslCipher> ciphers = sslContext->sslConfiguration.ciphers();
- if (ciphers.isEmpty())
- ciphers = isDtls ? q_getDefaultDtlsCiphers() : QSslSocketPrivate::defaultCiphers();
-
- const QByteArray preTls13Ciphers = filterCiphers(ciphers, false);
-
- if (preTls13Ciphers.size()) {
- if (!q_SSL_CTX_set_cipher_list(sslContext->ctx, preTls13Ciphers.data())) {
- sslContext->errorStr = QSslSocket::tr("Invalid or empty cipher list (%1)").arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
- sslContext->errorCode = QSslError::UnspecifiedError;
- return;
- }
- }
-
- const QByteArray tls13Ciphers = filterCiphers(ciphers, true);
-#ifdef TLS1_3_VERSION
- if (tls13Ciphers.size()) {
- if (!q_SSL_CTX_set_ciphersuites(sslContext->ctx, tls13Ciphers.data())) {
- sslContext->errorStr = QSslSocket::tr("Invalid or empty cipher list (%1)").arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
- sslContext->errorCode = QSslError::UnspecifiedError;
- return;
- }
- }
-#endif // TLS1_3_VERSION
- if (!preTls13Ciphers.size() && !tls13Ciphers.size()) {
- sslContext->errorStr = QSslSocket::tr("Invalid or empty cipher list (%1)").arg(QStringLiteral(""));
- sslContext->errorCode = QSslError::UnspecifiedError;
- return;
- }
-
- const QDateTime now = QDateTime::currentDateTimeUtc();
-
- // Add all our CAs to this store.
- const auto caCertificates = sslContext->sslConfiguration.caCertificates();
- for (const QSslCertificate &caCertificate : caCertificates) {
- // From https://www.openssl.org/docs/ssl/SSL_CTX_load_verify_locations.html:
- //
- // If several CA certificates matching the name, key identifier, and
- // serial number condition are available, only the first one will be
- // examined. This may lead to unexpected results if the same CA
- // certificate is available with different expiration dates. If a
- // ``certificate expired'' verification error occurs, no other
- // certificate will be searched. Make sure to not have expired
- // certificates mixed with valid ones.
- //
- // See also: QSslSocketBackendPrivate::verify()
- if (caCertificate.expiryDate() >= now) {
- q_X509_STORE_add_cert(q_SSL_CTX_get_cert_store(sslContext->ctx), (X509 *)caCertificate.handle());
- }
- }
-
- if (QSslSocketPrivate::s_loadRootCertsOnDemand && allowRootCertOnDemandLoading) {
- // tell OpenSSL the directories where to look up the root certs on demand
- const QList<QByteArray> unixDirs = QSslSocketPrivate::unixRootCertDirectories();
- int success = 1;
-#if OPENSSL_VERSION_MAJOR < 3
- for (const QByteArray &unixDir : unixDirs) {
- if ((success = q_SSL_CTX_load_verify_locations(sslContext->ctx, nullptr, unixDir.constData())) != 1)
- break;
- }
-#else
- for (const QByteArray &unixDir : unixDirs) {
- if ((success = q_SSL_CTX_load_verify_dir(sslContext->ctx, unixDir.constData())) != 1)
- break;
- }
-#endif // OPENSSL_VERSION_MAJOR
- if (success != 1) {
- const auto qtErrors = QSslSocketBackendPrivate::getErrorsFromOpenSsl();
- qCWarning(lcSsl) << "An error encountered while to set root certificates location:"
- << qtErrors;
- }
- }
-
- if (!sslContext->sslConfiguration.localCertificate().isNull()) {
- // Require a private key as well.
- if (sslContext->sslConfiguration.privateKey().isNull()) {
- sslContext->errorStr = QSslSocket::tr("Cannot provide a certificate with no key");
- sslContext->errorCode = QSslError::UnspecifiedError;
- return;
- }
-
- // Load certificate
- if (!q_SSL_CTX_use_certificate(sslContext->ctx, (X509 *)sslContext->sslConfiguration.localCertificate().handle())) {
- sslContext->errorStr = QSslSocket::tr("Error loading local certificate, %1").arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
- sslContext->errorCode = QSslError::UnspecifiedError;
- return;
- }
-
- if (configuration.d->privateKey.algorithm() == QSsl::Opaque) {
- sslContext->pkey = reinterpret_cast<EVP_PKEY *>(configuration.d->privateKey.handle());
- } else {
- // Load private key
- sslContext->pkey = q_EVP_PKEY_new();
- // before we were using EVP_PKEY_assign_R* functions and did not use EVP_PKEY_free.
- // this lead to a memory leak. Now we use the *_set1_* functions which do not
- // take ownership of the RSA/DSA key instance because the QSslKey already has ownership.
- if (configuration.d->privateKey.algorithm() == QSsl::Rsa)
- q_EVP_PKEY_set1_RSA(sslContext->pkey, reinterpret_cast<RSA *>(configuration.d->privateKey.handle()));
- else if (configuration.d->privateKey.algorithm() == QSsl::Dsa)
- q_EVP_PKEY_set1_DSA(sslContext->pkey, reinterpret_cast<DSA *>(configuration.d->privateKey.handle()));
-#ifndef OPENSSL_NO_EC
- else if (configuration.d->privateKey.algorithm() == QSsl::Ec)
- q_EVP_PKEY_set1_EC_KEY(sslContext->pkey, reinterpret_cast<EC_KEY *>(configuration.d->privateKey.handle()));
-#endif
- }
- auto pkey = sslContext->pkey;
- if (configuration.d->privateKey.algorithm() == QSsl::Opaque)
- sslContext->pkey = nullptr; // Don't free the private key, it belongs to QSslKey
-
- if (!q_SSL_CTX_use_PrivateKey(sslContext->ctx, pkey)) {
- sslContext->errorStr = QSslSocket::tr("Error loading private key, %1").arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
- sslContext->errorCode = QSslError::UnspecifiedError;
- return;
- }
-
- // Check if the certificate matches the private key.
- if (!q_SSL_CTX_check_private_key(sslContext->ctx)) {
- sslContext->errorStr = QSslSocket::tr("Private key does not certify public key, %1").arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
- sslContext->errorCode = QSslError::UnspecifiedError;
- return;
- }
-
- // If we have any intermediate certificates then we need to add them to our chain
- bool first = true;
- for (const QSslCertificate &cert : qAsConst(configuration.d->localCertificateChain)) {
- if (first) {
- first = false;
- continue;
- }
- q_SSL_CTX_ctrl(sslContext->ctx, SSL_CTRL_EXTRA_CHAIN_CERT, 0,
- q_X509_dup(reinterpret_cast<X509 *>(cert.handle())));
- }
- }
-
- // Initialize peer verification, different callbacks, TLS/DTLS verification first
- // (note, all these set_some_callback do not have return value):
- if (sslContext->sslConfiguration.peerVerifyMode() == QSslSocket::VerifyNone) {
- q_SSL_CTX_set_verify(sslContext->ctx, SSL_VERIFY_NONE, nullptr);
- } else {
- auto verificationCallback =
- #if QT_CONFIG(dtls)
- isDtls ? dtlscallbacks::q_X509DtlsCallback :
- #endif // dtls
- q_X509Callback;
-
- if (!isDtls && configuration.handshakeMustInterruptOnError())
- verificationCallback = q_X509CallbackDirect;
-
- auto verificationMode = SSL_VERIFY_PEER;
- if (!isDtls && sslContext->sslConfiguration.missingCertificateIsFatal())
- verificationMode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
-
- q_SSL_CTX_set_verify(sslContext->ctx, verificationMode, verificationCallback);
- }
-
-#ifdef TLS1_3_VERSION
- // NewSessionTicket callback:
- if (mode == QSslSocket::SslClientMode && !isDtls) {
- q_SSL_CTX_sess_set_new_cb(sslContext->ctx, q_ssl_sess_set_new_cb);
- q_SSL_CTX_set_session_cache_mode(sslContext->ctx, SSL_SESS_CACHE_CLIENT);
- }
-
-#endif // TLS1_3_VERSION
-
-#if QT_CONFIG(dtls)
- // DTLS cookies:
- if (mode == QSslSocket::SslServerMode && isDtls && configuration.dtlsCookieVerificationEnabled()) {
- q_SSL_CTX_set_cookie_generate_cb(sslContext->ctx, dtlscallbacks::q_generate_cookie_callback);
- q_SSL_CTX_set_cookie_verify_cb(sslContext->ctx, dtlscallbacks::q_verify_cookie_callback);
- }
-#endif // dtls
-
- // Set verification depth.
- if (sslContext->sslConfiguration.peerVerifyDepth() != 0)
- q_SSL_CTX_set_verify_depth(sslContext->ctx, sslContext->sslConfiguration.peerVerifyDepth());
-
- // set persisted session if the user set it
- if (!configuration.sessionTicket().isEmpty())
- sslContext->setSessionASN1(configuration.sessionTicket());
-
- // Set temp DH params
- QSslDiffieHellmanParameters dhparams = configuration.diffieHellmanParameters();
-
- if (!dhparams.isValid()) {
- sslContext->errorStr = QSslSocket::tr("Diffie-Hellman parameters are not valid");
- sslContext->errorCode = QSslError::UnspecifiedError;
- return;
- }
-
- if (!dhparams.isEmpty()) {
- const QByteArray &params = dhparams.d->derData;
- const char *ptr = params.constData();
- DH *dh = q_d2i_DHparams(nullptr, reinterpret_cast<const unsigned char **>(&ptr),
- params.length());
- if (dh == nullptr)
- qFatal("q_d2i_DHparams failed to convert QSslDiffieHellmanParameters to DER form");
- q_SSL_CTX_set_tmp_dh(sslContext->ctx, dh);
- q_DH_free(dh);
- }
-
-#ifndef OPENSSL_NO_PSK
- if (!client)
- q_SSL_CTX_use_psk_identity_hint(sslContext->ctx, sslContext->sslConfiguration.preSharedKeyIdentityHint().constData());
-#endif // !OPENSSL_NO_PSK
-
- const auto qcurves = sslContext->sslConfiguration.ellipticCurves();
- if (!qcurves.isEmpty()) {
-#ifdef OPENSSL_NO_EC
- sslContext->errorStr = msgErrorSettingEllipticCurves(QSslSocket::tr("OpenSSL version with disabled elliptic curves"));
- sslContext->errorCode = QSslError::UnspecifiedError;
- return;
-#else
- // Set the curves to be used.
- std::vector<int> curves;
- curves.reserve(qcurves.size());
- for (const auto &sslCurve : qcurves)
- curves.push_back(sslCurve.id);
- if (!q_SSL_CTX_ctrl(sslContext->ctx, SSL_CTRL_SET_CURVES, long(curves.size()), &curves[0])) {
- sslContext->errorStr = msgErrorSettingEllipticCurves(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
- sslContext->errorCode = QSslError::UnspecifiedError;
- return;
- }
-#endif
- }
-
- applyBackendConfig(sslContext);
-}
-
-#if QT_CONFIG(ocsp)
-extern "C" int qt_OCSP_status_server_callback(SSL *ssl, void *); // Defined in qsslsocket_openssl.cpp.
-#endif // ocsp
-// static
-void QSslContext::applyBackendConfig(QSslContext *sslContext)
-{
- const QMap<QByteArray, QVariant> &conf = sslContext->sslConfiguration.backendConfiguration();
- if (conf.isEmpty())
- return;
-
-#if QT_CONFIG(ocsp)
- auto ocspResponsePos = conf.find("Qt-OCSP-response");
- if (ocspResponsePos != conf.end()) {
- // This is our private, undocumented configuration option, existing only for
- // the purpose of testing OCSP status responses. We don't even check this
- // callback was set. If no - the test must fail.
- q_SSL_CTX_set_tlsext_status_cb(sslContext->ctx, qt_OCSP_status_server_callback);
- if (conf.size() == 1)
- return;
- }
-#endif // ocsp
-
- QSharedPointer<SSL_CONF_CTX> cctx(q_SSL_CONF_CTX_new(), &q_SSL_CONF_CTX_free);
- if (cctx) {
- q_SSL_CONF_CTX_set_ssl_ctx(cctx.data(), sslContext->ctx);
- q_SSL_CONF_CTX_set_flags(cctx.data(), SSL_CONF_FLAG_FILE);
-
- for (auto i = conf.constBegin(); i != conf.constEnd(); ++i) {
- if (i.key() == "Qt-OCSP-response") // This never goes to SSL_CONF_cmd().
- continue;
-
- if (!i.value().canConvert(QMetaType(QMetaType::QByteArray))) {
- sslContext->errorCode = QSslError::UnspecifiedError;
- sslContext->errorStr = msgErrorSettingBackendConfig(
- QSslSocket::tr("Expecting QByteArray for %1").arg(
- QString::fromUtf8(i.key())));
- return;
- }
-
- const QByteArray &value = i.value().toByteArray();
- const int result = q_SSL_CONF_cmd(cctx.data(), i.key().constData(), value.constData());
- if (result == 2)
- continue;
-
- sslContext->errorCode = QSslError::UnspecifiedError;
- switch (result) {
- case 0:
- sslContext->errorStr = msgErrorSettingBackendConfig(
- QSslSocket::tr("An error occurred attempting to set %1 to %2").arg(
- QString::fromUtf8(i.key()), QString::fromUtf8(value)));
- return;
- case 1:
- sslContext->errorStr = msgErrorSettingBackendConfig(
- QSslSocket::tr("Wrong value for %1 (%2)").arg(
- QString::fromUtf8(i.key()), QString::fromUtf8(value)));
- return;
- default:
- sslContext->errorStr = msgErrorSettingBackendConfig(
- QSslSocket::tr("Unrecognized command %1 = %2").arg(
- QString::fromUtf8(i.key()), QString::fromUtf8(value)));
- return;
- }
- }
-
- if (q_SSL_CONF_CTX_finish(cctx.data()) == 0) {
- sslContext->errorStr = msgErrorSettingBackendConfig(QSslSocket::tr("SSL_CONF_finish() failed"));
- sslContext->errorCode = QSslError::UnspecifiedError;
- }
- } else {
- sslContext->errorStr = msgErrorSettingBackendConfig(QSslSocket::tr("SSL_CONF_CTX_new() failed"));
- sslContext->errorCode = QSslError::UnspecifiedError;
- }
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslcontext_openssl_p.h b/src/network/ssl/qsslcontext_openssl_p.h
deleted file mode 100644
index 5385c42240..0000000000
--- a/src/network/ssl/qsslcontext_openssl_p.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-
-#ifndef QSSLCONTEXT_OPENSSL_P_H
-#define QSSLCONTEXT_OPENSSL_P_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.
-//
-
-#include <QtNetwork/private/qtnetworkglobal_p.h>
-#include <QtCore/qvariant.h>
-#include <QtNetwork/qsslcertificate.h>
-#include <QtNetwork/qsslconfiguration.h>
-#include <openssl/ssl.h>
-
-QT_BEGIN_NAMESPACE
-
-#ifndef QT_NO_SSL
-
-class QSslContext
-{
-public:
-
- ~QSslContext();
-
- static QSslContext* fromConfiguration(QSslSocket::SslMode mode, const QSslConfiguration &configuration,
- bool allowRootCertOnDemandLoading);
- static QSharedPointer<QSslContext> sharedFromConfiguration(QSslSocket::SslMode mode, const QSslConfiguration &configuration,
- bool allowRootCertOnDemandLoading);
-
- QSslError::SslError error() const;
- QString errorString() const;
-
- SSL* createSsl();
- bool cacheSession(SSL*); // should be called when handshake completed
-
- QByteArray sessionASN1() const;
- void setSessionASN1(const QByteArray &sessionASN1);
- int sessionTicketLifeTimeHint() const;
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
- // must be public because we want to use it from an OpenSSL callback
- struct NPNContext {
- NPNContext() : data(nullptr),
- len(0),
- status(QSslConfiguration::NextProtocolNegotiationNone)
- { }
- unsigned char *data;
- unsigned short len;
- QSslConfiguration::NextProtocolNegotiationStatus status;
- };
- NPNContext npnContext() const;
-#endif // !OPENSSL_NO_NEXTPROTONEG
-
-protected:
- QSslContext();
- friend class QSharedPointer<QSslContext>;
-
-private:
- static void initSslContext(QSslContext* sslContext, QSslSocket::SslMode mode, const QSslConfiguration &configuration,
- bool allowRootCertOnDemandLoading);
- static void applyBackendConfig(QSslContext *sslContext);
-
-private:
- SSL_CTX* ctx;
- EVP_PKEY *pkey;
- SSL_SESSION *session;
- QByteArray m_sessionASN1;
- int m_sessionTicketLifeTimeHint;
- QSslError::SslError errorCode;
- QString errorStr;
- QSslConfiguration sslConfiguration;
-#ifndef OPENSSL_NO_NEXTPROTONEG
- QByteArray m_supportedNPNVersions;
- NPNContext m_npnContext;
-#endif // !OPENSSL_NO_NEXTPROTONEG
-};
-
-#endif // QT_NO_SSL
-
-QT_END_NAMESPACE
-
-#endif // QSSLCONTEXT_OPENSSL_P_H
diff --git a/src/network/ssl/qssldiffiehellmanparameters.cpp b/src/network/ssl/qssldiffiehellmanparameters.cpp
index c8f3e564a5..7da14f3536 100644
--- a/src/network/ssl/qssldiffiehellmanparameters.cpp
+++ b/src/network/ssl/qssldiffiehellmanparameters.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 Mikkel Krautz <mikkel@krautz.dk>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2015 Mikkel Krautz <mikkel@krautz.dk>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/*!
@@ -56,6 +20,7 @@
#include "qssldiffiehellmanparameters.h"
#include "qssldiffiehellmanparameters_p.h"
+#include "qtlsbackend_p.h"
#include "qsslsocket.h"
#include "qsslsocket_p.h"
@@ -68,17 +33,18 @@
QT_BEGIN_NAMESPACE
-// The 1024-bit MODP group from RFC 2459 (Second Oakley Group)
+// The 2048-bit MODP group from RFC 3526
Q_AUTOTEST_EXPORT const char *qssl_dhparams_default_base64 =
- "MIGHAoGBAP//////////yQ/aoiFowjTExmKLgNwc0SkCTgiKZ8x0Agu+pjsTmyJR"
- "Sgh5jjQE3e+VGbPNOkMbMCsKbfJfFDdP4TVtbVHCReSFtXZiXn7G9ExC6aY37WsL"
- "/1y29Aa37e44a/taiZ+lrp8kEXxLH+ZJKGZR7OZTgf//////////AgEC";
+ "MIIBCAKCAQEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxObIlFKCHmO"
+ "NATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjftawv/XLb0Brft7jhr"
+ "+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXTmmkWP6j9JM9fg2VdI9yjrZYc"
+ "YvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhghfDKQXkYuNs474553LBgOhgObJ4Oi7Aei"
+ "j7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq5RXSJhiY+gUQFXKOWoqsqmj//////////wIBAg==";
/*!
Returns the default QSslDiffieHellmanParameters used by QSslSocket.
- This is currently the 1024-bit MODP group from RFC 2459, also
- known as the Second Oakley Group.
+ This is currently the 2048-bit MODP group from RFC 3526.
*/
QSslDiffieHellmanParameters QSslDiffieHellmanParameters::defaultParameters()
{
@@ -117,12 +83,15 @@ QSslDiffieHellmanParameters::QSslDiffieHellmanParameters()
QSslDiffieHellmanParameters QSslDiffieHellmanParameters::fromEncoded(const QByteArray &encoded, QSsl::EncodingFormat encoding)
{
QSslDiffieHellmanParameters result;
+ const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse();
+ if (!tlsBackend)
+ return result;
switch (encoding) {
case QSsl::Der:
- result.d->decodeDer(encoded);
+ result.d->initFromDer(encoded);
break;
case QSsl::Pem:
- result.d->decodePem(encoded);
+ result.d->initFromPem(encoded);
break;
}
return result;
@@ -273,19 +242,47 @@ QString QSslDiffieHellmanParameters::errorString() const noexcept
return QCoreApplication::translate("QSslDiffieHellmanParameter", "The given Diffie-Hellman parameters are deemed unsafe");
}
- Q_UNREACHABLE();
- return QString();
+ Q_UNREACHABLE_RETURN(QString());
}
/*!
+ \fn bool QSslDiffieHellmanParameters::operator==(const QSslDiffieHellmanParameters &lhs, const QSslDiffieHellmanParameters &rhs) noexcept
\since 5.8
- \relates QSslDiffieHellmanParameters
Returns \c true if \a lhs is equal to \a rhs; otherwise returns \c false.
*/
-bool operator==(const QSslDiffieHellmanParameters &lhs, const QSslDiffieHellmanParameters &rhs) noexcept
+
+/*!
+ \fn bool QSslDiffieHellmanParameters::operator!=(const QSslDiffieHellmanParameters &lhs, const QSslDiffieHellmanParameters &rhs) noexcept
+ \since 5.8
+
+ Returns \c true if \a lhs is not equal to \a rhs; otherwise returns \c false.
+*/
+
+/*!
+ \internal
+*/
+bool QSslDiffieHellmanParameters::isEqual(const QSslDiffieHellmanParameters &other) const noexcept
+{
+ return d->derData == other.d->derData;
+}
+
+/*!
+ \internal
+*/
+void QSslDiffieHellmanParametersPrivate::initFromDer(const QByteArray &der)
+{
+ if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse())
+ error = QSslDiffieHellmanParameters::Error(tlsBackend->dhParametersFromDer(der, &derData));
+}
+
+/*!
+ \internal
+*/
+void QSslDiffieHellmanParametersPrivate::initFromPem(const QByteArray &pem)
{
- return lhs.d->derData == rhs.d->derData;
+ if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse())
+ error = QSslDiffieHellmanParameters::Error(tlsBackend->dhParametersFromPem(pem, &derData));
}
#ifndef QT_NO_DEBUG_STREAM
diff --git a/src/network/ssl/qssldiffiehellmanparameters.h b/src/network/ssl/qssldiffiehellmanparameters.h
index 6a3cf01ddc..d1a525ba26 100644
--- a/src/network/ssl/qssldiffiehellmanparameters.h
+++ b/src/network/ssl/qssldiffiehellmanparameters.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 Mikkel Krautz <mikkel@krautz.dk>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2015 Mikkel Krautz <mikkel@krautz.dk>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSSLDIFFIEHELLMANPARAMETERS_H
@@ -63,14 +27,7 @@ class QDebug;
Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, const QSslDiffieHellmanParameters &dhparams);
#endif
-Q_NETWORK_EXPORT bool operator==(const QSslDiffieHellmanParameters &lhs, const QSslDiffieHellmanParameters &rhs) noexcept;
-
-inline bool operator!=(const QSslDiffieHellmanParameters &lhs, const QSslDiffieHellmanParameters &rhs) noexcept
-{
- return !operator==(lhs, rhs);
-}
-
-class QSslDiffieHellmanParameters
+class Q_NETWORK_EXPORT QSslDiffieHellmanParameters
{
public:
enum Error {
@@ -79,30 +36,36 @@ public:
UnsafeParametersError
};
- Q_NETWORK_EXPORT static QSslDiffieHellmanParameters defaultParameters();
+ static QSslDiffieHellmanParameters defaultParameters();
- Q_NETWORK_EXPORT QSslDiffieHellmanParameters();
- Q_NETWORK_EXPORT QSslDiffieHellmanParameters(const QSslDiffieHellmanParameters &other);
+ QSslDiffieHellmanParameters();
+ QSslDiffieHellmanParameters(const QSslDiffieHellmanParameters &other);
QSslDiffieHellmanParameters(QSslDiffieHellmanParameters &&other) noexcept : d(other.d) { other.d = nullptr; }
- Q_NETWORK_EXPORT ~QSslDiffieHellmanParameters();
+ ~QSslDiffieHellmanParameters();
- Q_NETWORK_EXPORT QSslDiffieHellmanParameters &operator=(const QSslDiffieHellmanParameters &other);
+ QSslDiffieHellmanParameters &operator=(const QSslDiffieHellmanParameters &other);
QSslDiffieHellmanParameters &operator=(QSslDiffieHellmanParameters &&other) noexcept { swap(other); return *this; }
- void swap(QSslDiffieHellmanParameters &other) noexcept { qSwap(d, other.d); }
+ void swap(QSslDiffieHellmanParameters &other) noexcept { qt_ptr_swap(d, other.d); }
- Q_NETWORK_EXPORT static QSslDiffieHellmanParameters fromEncoded(const QByteArray &encoded, QSsl::EncodingFormat format = QSsl::Pem);
- Q_NETWORK_EXPORT static QSslDiffieHellmanParameters fromEncoded(QIODevice *device, QSsl::EncodingFormat format = QSsl::Pem);
+ static QSslDiffieHellmanParameters fromEncoded(const QByteArray &encoded, QSsl::EncodingFormat format = QSsl::Pem);
+ static QSslDiffieHellmanParameters fromEncoded(QIODevice *device, QSsl::EncodingFormat format = QSsl::Pem);
- Q_NETWORK_EXPORT bool isEmpty() const noexcept;
- Q_NETWORK_EXPORT bool isValid() const noexcept;
- Q_NETWORK_EXPORT Error error() const noexcept;
- Q_NETWORK_EXPORT QString errorString() const noexcept;
+ bool isEmpty() const noexcept;
+ bool isValid() const noexcept;
+ Error error() const noexcept;
+ QString errorString() const noexcept;
private:
QSslDiffieHellmanParametersPrivate *d;
friend class QSslContext;
- friend Q_NETWORK_EXPORT bool operator==(const QSslDiffieHellmanParameters &lhs, const QSslDiffieHellmanParameters &rhs) noexcept;
+
+ bool isEqual(const QSslDiffieHellmanParameters &other) const noexcept;
+ friend bool operator==(const QSslDiffieHellmanParameters &lhs, const QSslDiffieHellmanParameters &rhs) noexcept
+ { return lhs.isEqual(rhs); }
+ friend bool operator!=(const QSslDiffieHellmanParameters &lhs, const QSslDiffieHellmanParameters &rhs) noexcept
+ { return !lhs.isEqual(rhs); }
+
#ifndef QT_NO_DEBUG_STREAM
friend Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, const QSslDiffieHellmanParameters &dhparam);
#endif
diff --git a/src/network/ssl/qssldiffiehellmanparameters_dummy.cpp b/src/network/ssl/qssldiffiehellmanparameters_dummy.cpp
deleted file mode 100644
index 8fcf141f73..0000000000
--- a/src/network/ssl/qssldiffiehellmanparameters_dummy.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 Mikkel Krautz <mikkel@krautz.dk>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-
-#include "qssldiffiehellmanparameters.h"
-#include "qssldiffiehellmanparameters_p.h"
-
-#include <QtCore/qglobal.h>
-#include <QtCore/qbytearray.h>
-
-QT_BEGIN_NAMESPACE
-
-void QSslDiffieHellmanParametersPrivate::decodeDer(const QByteArray &)
-{
-}
-
-void QSslDiffieHellmanParametersPrivate::decodePem(const QByteArray &)
-{
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qssldiffiehellmanparameters_openssl.cpp b/src/network/ssl/qssldiffiehellmanparameters_openssl.cpp
deleted file mode 100644
index 05b3408b75..0000000000
--- a/src/network/ssl/qssldiffiehellmanparameters_openssl.cpp
+++ /dev/null
@@ -1,224 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 Mikkel Krautz <mikkel@krautz.dk>
-** Copyright (C) 2016 Richard J. Moore <rich@kde.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qssldiffiehellmanparameters.h"
-#include "qssldiffiehellmanparameters_p.h"
-#include "qsslsocket_openssl_symbols_p.h"
-#include "qsslsocket.h"
-#include "qsslsocket_p.h"
-
-#include "private/qssl_p.h"
-
-#include <QtCore/qatomic.h>
-#include <QtCore/qbytearray.h>
-#include <QtCore/qiodevice.h>
-#include <QtCore/qscopeguard.h>
-#ifndef QT_NO_DEBUG_STREAM
-#include <QtCore/qdebug.h>
-#endif
-
-#include <openssl/bn.h>
-#include <openssl/dh.h>
-
-QT_BEGIN_NAMESPACE
-
-#ifdef OPENSSL_NO_DEPRECATED_3_0
-
-static int q_DH_check(DH *dh, int *status)
-{
- // DH_check was first deprecated in OpenSSL 3.0.0, as low-level
- // API; the EVP_PKEY family of functions was advised as an alternative.
- // As of now EVP_PKEY_params_check ends up calling ... DH_check,
- // which is good enough.
-
- Q_ASSERT(dh);
- Q_ASSERT(status);
-
- EVP_PKEY *key = q_EVP_PKEY_new();
- if (!key) {
- qCWarning(lcSsl, "EVP_PKEY_new failed");
- QSslSocketBackendPrivate::logAndClearErrorQueue();
- return 0;
- }
- const auto keyDeleter = qScopeGuard([key](){
- q_EVP_PKEY_free(key);
- });
- if (!q_EVP_PKEY_set1_DH(key, dh)) {
- qCWarning(lcSsl, "EVP_PKEY_set1_DH failed");
- QSslSocketBackendPrivate::logAndClearErrorQueue();
- return 0;
- }
-
- EVP_PKEY_CTX *keyCtx = q_EVP_PKEY_CTX_new(key, nullptr);
- if (!keyCtx) {
- qCWarning(lcSsl, "EVP_PKEY_CTX_new failed");
- QSslSocketBackendPrivate::logAndClearErrorQueue();
- return 0;
- }
- const auto ctxDeleter = qScopeGuard([keyCtx]{
- q_EVP_PKEY_CTX_free(keyCtx);
- });
-
- const int result = q_EVP_PKEY_param_check(keyCtx);
- QSslSocketBackendPrivate::logAndClearErrorQueue();
- // Note: unlike DH_check, we cannot obtain the 'status',
- // if the 'result' is 0 (actually the result is 1 only
- // if this 'status' was 0). We could probably check the
- // errors from the error queue, but it's not needed anyway
- // - see the 'isSafeDH' below, how it returns immediately
- // on 0.
- Q_UNUSED(status);
-
- return result;
-}
-#endif // OPENSSL_NO_DEPRECATED_3_0
-
-static bool isSafeDH(DH *dh)
-{
- int status = 0;
- int bad = 0;
-
- QSslSocketPrivate::ensureInitialized();
-
-
- // From https://wiki.openssl.org/index.php/Diffie-Hellman_parameters:
- //
- // The additional call to BN_mod_word(dh->p, 24)
- // (and unmasking of DH_NOT_SUITABLE_GENERATOR)
- // is performed to ensure your program accepts
- // IETF group parameters. OpenSSL checks the prime
- // is congruent to 11 when g = 2; while the IETF's
- // primes are congruent to 23 when g = 2.
- // Without the test, the IETF parameters would
- // fail validation. For details, see Diffie-Hellman
- // Parameter Check (when g = 2, must p mod 24 == 11?).
- // Mark p < 1024 bits as unsafe.
- if (q_DH_bits(dh) < 1024)
- return false;
-
- if (q_DH_check(dh, &status) != 1)
- return false;
-
- const BIGNUM *p = nullptr;
- const BIGNUM *q = nullptr;
- const BIGNUM *g = nullptr;
- q_DH_get0_pqg(dh, &p, &q, &g);
-
- if (q_BN_is_word(const_cast<BIGNUM *>(g), DH_GENERATOR_2)) {
- const unsigned long residue = q_BN_mod_word(p, 24);
- if (residue == 11 || residue == 23)
- status &= ~DH_NOT_SUITABLE_GENERATOR;
- }
-
- bad |= DH_CHECK_P_NOT_PRIME;
- bad |= DH_CHECK_P_NOT_SAFE_PRIME;
- bad |= DH_NOT_SUITABLE_GENERATOR;
-
- return !(status & bad);
-}
-
-void QSslDiffieHellmanParametersPrivate::decodeDer(const QByteArray &der)
-{
- if (der.isEmpty()) {
- error = QSslDiffieHellmanParameters::InvalidInputDataError;
- return;
- }
-
- const unsigned char *data = reinterpret_cast<const unsigned char *>(der.data());
- int len = der.size();
-
- QSslSocketPrivate::ensureInitialized();
-
- DH *dh = q_d2i_DHparams(nullptr, &data, len);
- if (dh) {
- if (isSafeDH(dh))
- derData = der;
- else
- error = QSslDiffieHellmanParameters::UnsafeParametersError;
- } else {
- error = QSslDiffieHellmanParameters::InvalidInputDataError;
- }
-
- q_DH_free(dh);
-}
-
-void QSslDiffieHellmanParametersPrivate::decodePem(const QByteArray &pem)
-{
- if (pem.isEmpty()) {
- error = QSslDiffieHellmanParameters::InvalidInputDataError;
- return;
- }
-
- if (!QSslSocket::supportsSsl()) {
- error = QSslDiffieHellmanParameters::InvalidInputDataError;
- return;
- }
-
- QSslSocketPrivate::ensureInitialized();
-
- BIO *bio = q_BIO_new_mem_buf(const_cast<char *>(pem.data()), pem.size());
- if (!bio) {
- error = QSslDiffieHellmanParameters::InvalidInputDataError;
- return;
- }
-
- DH *dh = nullptr;
- q_PEM_read_bio_DHparams(bio, &dh, nullptr, nullptr);
-
- if (dh) {
- if (isSafeDH(dh)) {
- char *buf = nullptr;
- int len = q_i2d_DHparams(dh, reinterpret_cast<unsigned char **>(&buf));
- if (len > 0)
- derData = QByteArray(buf, len);
- else
- error = QSslDiffieHellmanParameters::InvalidInputDataError;
- } else {
- error = QSslDiffieHellmanParameters::UnsafeParametersError;
- }
- } else {
- error = QSslDiffieHellmanParameters::InvalidInputDataError;
- }
-
- q_DH_free(dh);
- q_BIO_free(bio);
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qssldiffiehellmanparameters_p.h b/src/network/ssl/qssldiffiehellmanparameters_p.h
index 722c2e9cf0..705e0f007c 100644
--- a/src/network/ssl/qssldiffiehellmanparameters_p.h
+++ b/src/network/ssl/qssldiffiehellmanparameters_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 Mikkel Krautz <mikkel@krautz.dk>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2015 Mikkel Krautz <mikkel@krautz.dk>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSSLDIFFIEHELLMANPARAMETERS_P_H
@@ -53,23 +17,20 @@
//
#include <QtNetwork/private/qtnetworkglobal_p.h>
-#include <QSharedData>
-#include "qsslkey.h"
#include "qssldiffiehellmanparameters.h"
-#include "qsslsocket_p.h" // includes wincrypt.h
+
+#include <QSharedData>
QT_BEGIN_NAMESPACE
class QSslDiffieHellmanParametersPrivate : public QSharedData
{
public:
- QSslDiffieHellmanParametersPrivate() : error(QSslDiffieHellmanParameters::NoError) {}
-
- void decodeDer(const QByteArray &der);
- void decodePem(const QByteArray &pem);
+ void initFromDer(const QByteArray &der);
+ void initFromPem(const QByteArray &pem);
- QSslDiffieHellmanParameters::Error error;
+ QSslDiffieHellmanParameters::Error error = QSslDiffieHellmanParameters::NoError;
QByteArray derData;
};
diff --git a/src/network/ssl/qsslellipticcurve.cpp b/src/network/ssl/qsslellipticcurve.cpp
index f7faa607bd..77aa66f3cc 100644
--- a/src/network/ssl/qsslellipticcurve.cpp
+++ b/src/network/ssl/qsslellipticcurve.cpp
@@ -1,43 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Governikus GmbH & Co. KG.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2014 Governikus GmbH & Co. KG.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qsslellipticcurve.h"
+#include "qtlsbackend_p.h"
+#include "qsslsocket_p.h"
#ifndef QT_NO_DEBUG_STREAM
#include <QDebug>
@@ -45,6 +11,8 @@
QT_BEGIN_NAMESPACE
+QT_IMPL_METATYPE_EXTERN(QSslEllipticCurve)
+
/*!
\class QSslEllipticCurve
\since 5.5
@@ -77,8 +45,6 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn QSslEllipticCurve QSslEllipticCurve::fromShortName(const QString &name)
-
Returns an QSslEllipticCurve instance representing the
named curve \a name. The \a name is the conventional short
name for the curve, as represented by RFC 4492 (for instance \c{secp521r1}),
@@ -91,10 +57,19 @@ QT_BEGIN_NAMESPACE
\sa shortName()
*/
+QSslEllipticCurve QSslEllipticCurve::fromShortName(const QString &name)
+{
+ QSslEllipticCurve result;
+ if (name.isEmpty())
+ return result;
-/*!
- \fn QSslEllipticCurve QSslEllipticCurve::fromLongName(const QString &name)
+ if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse())
+ result.id = tlsBackend->curveIdFromShortName(name);
+ return result;
+}
+
+/*!
Returns an QSslEllipticCurve instance representing the named curve \a name.
The \a name is a long name for the curve, whose exact spelling depends on the
SSL implementation.
@@ -105,24 +80,49 @@ QT_BEGIN_NAMESPACE
\sa longName()
*/
+QSslEllipticCurve QSslEllipticCurve::fromLongName(const QString &name)
+{
+ QSslEllipticCurve result;
+ if (name.isEmpty())
+ return result;
-/*!
- \fn QString QSslEllipticCurve::shortName() const
+ if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse())
+ result.id = tlsBackend->curveIdFromLongName(name);
+
+ return result;
+}
+/*!
Returns the conventional short name for this curve. If this
curve is invalid, returns an empty string.
\sa longName()
*/
+QString QSslEllipticCurve::shortName() const
+{
+ QString name;
-/*!
- \fn QString QSslEllipticCurve::longName() const
+ if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse())
+ name = tlsBackend->shortNameForId(id);
+ return name;
+}
+
+/*!
Returns the conventional long name for this curve. If this
curve is invalid, returns an empty string.
\sa shortName()
*/
+QString QSslEllipticCurve::longName() const
+{
+ QString name;
+
+ if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse())
+ name = tlsBackend->longNameForId(id);
+
+ return name;
+}
/*!
\fn bool QSslEllipticCurve::isValid() const
@@ -131,32 +131,36 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn bool QSslEllipticCurve::isTlsNamedCurve() const
-
Returns true if this elliptic curve is one of the named curves that can be
used in the key exchange when using an elliptic curve cipher with TLS;
false otherwise.
*/
+bool QSslEllipticCurve::isTlsNamedCurve() const noexcept
+{
+ if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse())
+ return tlsBackend->isTlsNamedCurve(id);
+
+ return false;
+}
+
/*!
- \fn bool operator==(QSslEllipticCurve lhs, QSslEllipticCurve rhs)
+ \fn bool QSslEllipticCurve::operator==(QSslEllipticCurve lhs, QSslEllipticCurve rhs)
\since 5.5
- \relates QSslEllipticCurve
Returns true if the curve \a lhs represents the same curve of \a rhs;
*/
/*!
- \fn bool operator!=(QSslEllipticCurve lhs, QSslEllipticCurve rhs)
+ \fn bool QSslEllipticCurve::operator!=(QSslEllipticCurve lhs, QSslEllipticCurve rhs)
\since 5.5
- \relates QSslEllipticCurve
Returns true if the curve \a lhs represents a different curve than \a rhs;
false otherwise.
*/
/*!
- \fn size_t qHash(QSslEllipticCurve curve, size_t seed)
+ \fn size_t qHash(QSslEllipticCurve curve, size_t seed = 0)
\since 5.5
\relates QHash
diff --git a/src/network/ssl/qsslellipticcurve.h b/src/network/ssl/qsslellipticcurve.h
index 95441e75bf..0585ffbd0e 100644
--- a/src/network/ssl/qsslellipticcurve.h
+++ b/src/network/ssl/qsslellipticcurve.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Governikus GmbH & Co. KG.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2014 Governikus GmbH & Co. KG.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSSLELLIPTICCURVE_H
#define QSSLELLIPTICCURVE_H
@@ -43,9 +7,6 @@
#include <QtNetwork/qtnetworkglobal.h>
#include <QtCore/QString>
#include <QtCore/QMetaType>
-#if QT_DEPRECATED_SINCE(5, 6)
-#include <QtCore/QHash>
-#endif
#include <QtCore/qhashfunctions.h>
QT_BEGIN_NAMESPACE
@@ -77,12 +38,14 @@ public:
private:
int id;
- friend constexpr bool operator==(QSslEllipticCurve lhs, QSslEllipticCurve rhs) noexcept;
+ friend constexpr bool operator==(QSslEllipticCurve lhs, QSslEllipticCurve rhs) noexcept
+ { return lhs.id == rhs.id; }
+ friend constexpr bool operator!=(QSslEllipticCurve lhs, QSslEllipticCurve rhs) noexcept
+ { return !(lhs == rhs); }
friend constexpr size_t qHash(QSslEllipticCurve curve, size_t seed) noexcept;
friend class QSslContext;
friend class QSslSocketPrivate;
- friend class QSslSocketBackendPrivate;
};
Q_DECLARE_TYPEINFO(QSslEllipticCurve, Q_PRIMITIVE_TYPE);
@@ -90,12 +53,6 @@ Q_DECLARE_TYPEINFO(QSslEllipticCurve, Q_PRIMITIVE_TYPE);
constexpr inline size_t qHash(QSslEllipticCurve curve, size_t seed) noexcept
{ return qHash(curve.id, seed); }
-constexpr inline bool operator==(QSslEllipticCurve lhs, QSslEllipticCurve rhs) noexcept
-{ return lhs.id == rhs.id; }
-
-constexpr inline bool operator!=(QSslEllipticCurve lhs, QSslEllipticCurve rhs) noexcept
-{ return !operator==(lhs, rhs); }
-
#ifndef QT_NO_DEBUG_STREAM
class QDebug;
Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, QSslEllipticCurve curve);
@@ -103,6 +60,6 @@ Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, QSslEllipticCurve curve);
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QSslEllipticCurve)
+QT_DECL_METATYPE_EXTERN(QSslEllipticCurve, Q_NETWORK_EXPORT)
#endif // QSSLELLIPTICCURVE_H
diff --git a/src/network/ssl/qsslellipticcurve_dummy.cpp b/src/network/ssl/qsslellipticcurve_dummy.cpp
deleted file mode 100644
index 1313e06875..0000000000
--- a/src/network/ssl/qsslellipticcurve_dummy.cpp
+++ /dev/null
@@ -1,71 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Governikus GmbH & Co. KG.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qsslellipticcurve.h"
-
-QT_BEGIN_NAMESPACE
-
-QString QSslEllipticCurve::shortName() const
-{
- return QString();
-}
-
-QString QSslEllipticCurve::longName() const
-{
- return QString();
-}
-
-QSslEllipticCurve QSslEllipticCurve::fromShortName(const QString &name)
-{
- Q_UNUSED(name);
- return QSslEllipticCurve();
-}
-
-QSslEllipticCurve QSslEllipticCurve::fromLongName(const QString &name)
-{
- Q_UNUSED(name);
- return QSslEllipticCurve();
-}
-
-bool QSslEllipticCurve::isTlsNamedCurve() const noexcept
-{
- return false;
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslellipticcurve_openssl.cpp b/src/network/ssl/qsslellipticcurve_openssl.cpp
deleted file mode 100644
index bb7ad66bd2..0000000000
--- a/src/network/ssl/qsslellipticcurve_openssl.cpp
+++ /dev/null
@@ -1,177 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Governikus GmbH & Co. KG.
-** Copyright (C) 2016 Richard J. Moore <rich@kde.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qsslellipticcurve.h"
-#include "qsslsocket_p.h"
-#include "qsslsocket_openssl_symbols_p.h"
-
-#include <openssl/ssl.h>
-#include <openssl/obj_mac.h>
-
-#include <algorithm>
-
-QT_BEGIN_NAMESPACE
-
-QString QSslEllipticCurve::shortName() const
-{
- QString result;
-#ifndef OPENSSL_NO_EC
- if (id != 0)
- result = QString::fromLatin1(q_OBJ_nid2sn(id));
-#endif
- return result;
-}
-
-QString QSslEllipticCurve::longName() const
-{
- QString result;
-#ifndef OPENSSL_NO_EC
- if (id != 0)
- result = QString::fromLatin1(q_OBJ_nid2ln(id));
-#endif
- return result;
-}
-
-QSslEllipticCurve QSslEllipticCurve::fromShortName(const QString &name)
-{
- if (name.isEmpty())
- return QSslEllipticCurve();
-
- QSslSocketPrivate::ensureInitialized();
-
- QSslEllipticCurve result;
-
-#ifndef OPENSSL_NO_EC
-
- const QByteArray curveNameLatin1 = name.toLatin1();
- int nid = q_OBJ_sn2nid(curveNameLatin1.data());
-
- if (nid == 0)
- nid = q_EC_curve_nist2nid(curveNameLatin1.data());
-
- result.id = nid;
-
-#endif // !OPENSSL_NO_EC
-
- return result;
-}
-
-QSslEllipticCurve QSslEllipticCurve::fromLongName(const QString &name)
-{
- if (name.isEmpty())
- return QSslEllipticCurve();
-
- QSslSocketPrivate::ensureInitialized();
-
- QSslEllipticCurve result;
-
-#ifndef OPENSSL_NO_EC
- const QByteArray curveNameLatin1 = name.toLatin1();
-
- int nid = q_OBJ_ln2nid(curveNameLatin1.data());
- result.id = nid;
-#endif
-
- return result;
-}
-
-
-// The brainpool curve NIDs (RFC 7027) have been introduced in OpenSSL 1.0.2,
-// redefine them here to make Qt compile with previous versions of OpenSSL
-// (yet correctly recognize them as TLS named curves).
-// See crypto/objects/obj_mac.h
-#ifndef NID_brainpoolP256r1
-#define NID_brainpoolP256r1 927
-#endif
-
-#ifndef NID_brainpoolP384r1
-#define NID_brainpoolP384r1 931
-#endif
-
-#ifndef NID_brainpoolP512r1
-#define NID_brainpoolP512r1 933
-#endif
-
-// NIDs of named curves allowed in TLS as per RFCs 4492 and 7027,
-// see also https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8
-static const int tlsNamedCurveNIDs[] = {
- // RFC 4492
- NID_sect163k1,
- NID_sect163r1,
- NID_sect163r2,
- NID_sect193r1,
- NID_sect193r2,
- NID_sect233k1,
- NID_sect233r1,
- NID_sect239k1,
- NID_sect283k1,
- NID_sect283r1,
- NID_sect409k1,
- NID_sect409r1,
- NID_sect571k1,
- NID_sect571r1,
-
- NID_secp160k1,
- NID_secp160r1,
- NID_secp160r2,
- NID_secp192k1,
- NID_X9_62_prime192v1, // secp192r1
- NID_secp224k1,
- NID_secp224r1,
- NID_secp256k1,
- NID_X9_62_prime256v1, // secp256r1
- NID_secp384r1,
- NID_secp521r1,
-
- // RFC 7027
- NID_brainpoolP256r1,
- NID_brainpoolP384r1,
- NID_brainpoolP512r1
-};
-
-static const size_t tlsNamedCurveNIDCount = sizeof(tlsNamedCurveNIDs) / sizeof(tlsNamedCurveNIDs[0]);
-
-bool QSslEllipticCurve::isTlsNamedCurve() const noexcept
-{
- const int * const tlsNamedCurveNIDsEnd = tlsNamedCurveNIDs + tlsNamedCurveNIDCount;
- return std::find(tlsNamedCurveNIDs, tlsNamedCurveNIDsEnd, id) != tlsNamedCurveNIDsEnd;
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslerror.cpp b/src/network/ssl/qsslerror.cpp
index 5e935adf09..241e6291ac 100644
--- a/src/network/ssl/qsslerror.cpp
+++ b/src/network/ssl/qsslerror.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/*!
@@ -111,6 +75,16 @@
QT_BEGIN_NAMESPACE
+#ifndef QT_NO_SSL
+QT_IMPL_METATYPE_EXTERN_TAGGED(QList<QSslError>, QList_QSslError)
+#endif
+
+
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+// Avoid an ABI break due to the QScopedPointer->std::unique_ptr change
+static_assert(sizeof(QScopedPointer<QSslErrorPrivate>) == sizeof(std::unique_ptr<QSslErrorPrivate>));
+#endif
+
class QSslErrorPrivate
{
public:
@@ -163,7 +137,7 @@ QSslError::QSslError(SslError error, const QSslCertificate &certificate)
QSslError::QSslError(const QSslError &other)
: d(new QSslErrorPrivate)
{
- *d.data() = *other.d.data();
+ *d.get() = *other.d.get();
}
/*!
@@ -180,7 +154,7 @@ QSslError::~QSslError()
*/
QSslError &QSslError::operator=(const QSslError &other)
{
- *d.data() = *other.d.data();
+ *d.get() = *other.d.get();
return *this;
}
@@ -385,3 +359,5 @@ QDebug operator<<(QDebug debug, const QSslError::SslError &error)
#endif
QT_END_NAMESPACE
+
+#include "moc_qsslerror.cpp"
diff --git a/src/network/ssl/qsslerror.h b/src/network/ssl/qsslerror.h
index f135dd10b7..d82b086d39 100644
--- a/src/network/ssl/qsslerror.h
+++ b/src/network/ssl/qsslerror.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSSLERROR_H
@@ -45,6 +9,8 @@
#include <QtCore/qvariant.h>
#include <QtNetwork/qsslcertificate.h>
+#include <memory>
+
QT_BEGIN_NAMESPACE
@@ -106,7 +72,7 @@ public:
QSslError(const QSslError &other);
void swap(QSslError &other) noexcept
- { qSwap(d, other.d); }
+ { d.swap(other.d); }
~QSslError();
QSslError &operator=(QSslError &&other) noexcept { swap(other); return *this; }
@@ -120,7 +86,8 @@ public:
QSslCertificate certificate() const;
private:
- QScopedPointer<QSslErrorPrivate> d;
+ // ### Qt 7: make QSslError implicitly shared
+ std::unique_ptr<QSslErrorPrivate> d;
};
Q_DECLARE_SHARED(QSslError)
@@ -138,7 +105,7 @@ class Q_NETWORK_EXPORT QSslError {}; // dummy class so that moc has a complete t
QT_END_NAMESPACE
#ifndef QT_NO_SSL
-Q_DECLARE_METATYPE(QList<QSslError>)
+QT_DECL_METATYPE_EXTERN_TAGGED(QList<QSslError>, QList_QSslError, Q_NETWORK_EXPORT)
#endif
#endif
diff --git a/src/network/ssl/qsslkey.h b/src/network/ssl/qsslkey.h
index 9e70554716..decfc4b5a1 100644
--- a/src/network/ssl/qsslkey.h
+++ b/src/network/ssl/qsslkey.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSSLKEY_H
@@ -44,7 +8,7 @@
#include <QtNetwork/qtnetworkglobal.h>
#include <QtCore/qnamespace.h>
#include <QtCore/qbytearray.h>
-#include <QtCore/qsharedpointer.h>
+#include <QtCore/qshareddata.h>
#include <QtNetwork/qssl.h>
QT_BEGIN_NAMESPACE
@@ -74,7 +38,7 @@ public:
QSslKey &operator=(const QSslKey &other);
~QSslKey();
- void swap(QSslKey &other) noexcept { qSwap(d, other.d); }
+ void swap(QSslKey &other) noexcept { d.swap(other.d); }
bool isNull() const;
void clear();
@@ -84,6 +48,7 @@ public:
QSsl::KeyAlgorithm algorithm() const;
QByteArray toPem(const QByteArray &passPhrase = QByteArray()) const;
+ // ### Qt 7: drop passPhrase
QByteArray toDer(const QByteArray &passPhrase = QByteArray()) const;
Qt::HANDLE handle() const;
@@ -93,8 +58,7 @@ public:
private:
QExplicitlySharedDataPointer<QSslKeyPrivate> d;
- friend class QSslCertificate;
- friend class QSslSocketBackendPrivate;
+ friend class QTlsBackend;
};
Q_DECLARE_SHARED(QSslKey)
diff --git a/src/network/ssl/qsslkey_mac.cpp b/src/network/ssl/qsslkey_mac.cpp
deleted file mode 100644
index 814fe1c4bc..0000000000
--- a/src/network/ssl/qsslkey_mac.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Jeremy Lainé <jeremy.laine@m4x.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qsslkey.h"
-#include "qsslkey_p.h"
-
-#include <CommonCrypto/CommonCrypto.h>
-
-#include <cstddef>
-
-QT_BEGIN_NAMESPACE
-
-static QByteArray wrapCCCrypt(CCOperation ccOp,
- QSslKeyPrivate::Cipher cipher,
- const QByteArray &data,
- const QByteArray &key, const QByteArray &iv)
-{
- int blockSize;
- CCAlgorithm ccAlgorithm;
- switch (cipher) {
- case QSslKeyPrivate::DesCbc:
- blockSize = kCCBlockSizeDES;
- ccAlgorithm = kCCAlgorithmDES;
- break;
- case QSslKeyPrivate::DesEde3Cbc:
- blockSize = kCCBlockSize3DES;
- ccAlgorithm = kCCAlgorithm3DES;
- break;
- case QSslKeyPrivate::Rc2Cbc:
- blockSize = kCCBlockSizeRC2;
- ccAlgorithm = kCCAlgorithmRC2;
- break;
- case QSslKeyPrivate::Aes128Cbc:
- case QSslKeyPrivate::Aes192Cbc:
- case QSslKeyPrivate::Aes256Cbc:
- blockSize = kCCBlockSizeAES128;
- ccAlgorithm = kCCAlgorithmAES;
- break;
- }
- size_t plainLength = 0;
- QByteArray plain(data.size() + blockSize, 0);
- CCCryptorStatus status = CCCrypt(
- ccOp, ccAlgorithm, kCCOptionPKCS7Padding,
- key.constData(), std::size_t(key.size()),
- iv.constData(),
- data.constData(), std::size_t(data.size()),
- plain.data(), std::size_t(plain.size()), &plainLength);
- if (status == kCCSuccess)
- return plain.left(int(plainLength));
- return QByteArray();
-}
-
-QByteArray QSslKeyPrivate::decrypt(Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv)
-{
- return wrapCCCrypt(kCCDecrypt, cipher, data, key, iv);
-}
-
-QByteArray QSslKeyPrivate::encrypt(Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv)
-{
- return wrapCCCrypt(kCCEncrypt, cipher, data, key, iv);
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslkey_openssl.cpp b/src/network/ssl/qsslkey_openssl.cpp
deleted file mode 100644
index 43cb8c6de8..0000000000
--- a/src/network/ssl/qsslkey_openssl.cpp
+++ /dev/null
@@ -1,383 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Copyright (C) 2016 Richard J. Moore <rich@kde.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-
-#include "qsslkey.h"
-#include "qsslkey_p.h"
-#include "qsslsocket_openssl_symbols_p.h"
-#include "qsslsocket.h"
-#include "qsslsocket_p.h"
-
-#include <QtCore/qatomic.h>
-#include <QtCore/qbytearray.h>
-#include <QtCore/qiodevice.h>
-#ifndef QT_NO_DEBUG_STREAM
-#include <QtCore/qdebug.h>
-#endif
-
-QT_BEGIN_NAMESPACE
-
-void QSslKeyPrivate::clear(bool deep)
-{
- isNull = true;
- if (!QSslSocket::supportsSsl())
- return;
- if (algorithm == QSsl::Rsa && rsa) {
- if (deep)
- q_RSA_free(rsa);
- rsa = nullptr;
- }
- if (algorithm == QSsl::Dsa && dsa) {
- if (deep)
- q_DSA_free(dsa);
- dsa = nullptr;
- }
- if (algorithm == QSsl::Dh && dh) {
- if (deep)
- q_DH_free(dh);
- dh = nullptr;
- }
-#ifndef OPENSSL_NO_EC
- if (algorithm == QSsl::Ec && ec) {
- if (deep)
- q_EC_KEY_free(ec);
- ec = nullptr;
- }
-#endif
- if (algorithm == QSsl::Opaque && opaque) {
- if (deep)
- q_EVP_PKEY_free(opaque);
- opaque = nullptr;
- }
-}
-
-bool QSslKeyPrivate::fromEVP_PKEY(EVP_PKEY *pkey)
-{
- if (pkey == nullptr)
- return false;
-
- const int keyType = q_EVP_PKEY_type(q_EVP_PKEY_base_id(pkey));
- if (keyType == EVP_PKEY_RSA) {
- isNull = false;
- algorithm = QSsl::Rsa;
- type = QSsl::PrivateKey;
- rsa = q_EVP_PKEY_get1_RSA(pkey);
- return true;
- } else if (keyType == EVP_PKEY_DSA) {
- isNull = false;
- algorithm = QSsl::Dsa;
- type = QSsl::PrivateKey;
- dsa = q_EVP_PKEY_get1_DSA(pkey);
- return true;
- } else if (keyType == EVP_PKEY_DH) {
- isNull = false;
- algorithm = QSsl::Dh;
- type = QSsl::PrivateKey;
- dh = q_EVP_PKEY_get1_DH(pkey);
- return true;
- }
-#ifndef OPENSSL_NO_EC
- else if (keyType == EVP_PKEY_EC) {
- isNull = false;
- algorithm = QSsl::Ec;
- type = QSsl::PrivateKey;
- ec = q_EVP_PKEY_get1_EC_KEY(pkey);
- return true;
- }
-#endif
- else {
- // Unknown key type. This could be handled as opaque, but then
- // we'd eventually leak memory since we wouldn't be able to free
- // the underlying EVP_PKEY structure. For now, we won't support
- // this.
- }
-
- return false;
-}
-
-void QSslKeyPrivate::decodeDer(const QByteArray &der, const QByteArray &passPhrase, bool deepClear)
-{
- QMap<QByteArray, QByteArray> headers;
- decodePem(pemFromDer(der, headers), passPhrase, deepClear);
-}
-
-void QSslKeyPrivate::decodePem(const QByteArray &pem, const QByteArray &passPhrase,
- bool deepClear)
-{
- if (pem.isEmpty())
- return;
-
- clear(deepClear);
-
- if (!QSslSocket::supportsSsl())
- return;
-
- BIO *bio = q_BIO_new_mem_buf(const_cast<char *>(pem.data()), pem.size());
- if (!bio)
- return;
-
- void *phrase = const_cast<char *>(passPhrase.constData());
-
- if (algorithm == QSsl::Rsa) {
- RSA *result = (type == QSsl::PublicKey)
- ? q_PEM_read_bio_RSA_PUBKEY(bio, &rsa, nullptr, phrase)
- : q_PEM_read_bio_RSAPrivateKey(bio, &rsa, nullptr, phrase);
- if (rsa && rsa == result)
- isNull = false;
- } else if (algorithm == QSsl::Dsa) {
- DSA *result = (type == QSsl::PublicKey)
- ? q_PEM_read_bio_DSA_PUBKEY(bio, &dsa, nullptr, phrase)
- : q_PEM_read_bio_DSAPrivateKey(bio, &dsa, nullptr, phrase);
- if (dsa && dsa == result)
- isNull = false;
- } else if (algorithm == QSsl::Dh) {
- EVP_PKEY *result = (type == QSsl::PublicKey)
- ? q_PEM_read_bio_PUBKEY(bio, nullptr, nullptr, phrase)
- : q_PEM_read_bio_PrivateKey(bio, nullptr, nullptr, phrase);
- if (result)
- dh = q_EVP_PKEY_get1_DH(result);
- if (dh)
- isNull = false;
- q_EVP_PKEY_free(result);
-#ifndef OPENSSL_NO_EC
- } else if (algorithm == QSsl::Ec) {
- EC_KEY *result = (type == QSsl::PublicKey)
- ? q_PEM_read_bio_EC_PUBKEY(bio, &ec, nullptr, phrase)
- : q_PEM_read_bio_ECPrivateKey(bio, &ec, nullptr, phrase);
- if (ec && ec == result)
- isNull = false;
-#endif
- }
-
- q_BIO_free(bio);
-}
-
-int QSslKeyPrivate::length() const
-{
- if (isNull || algorithm == QSsl::Opaque)
- return -1;
-
- switch (algorithm) {
- case QSsl::Rsa: return q_RSA_bits(rsa);
- case QSsl::Dsa: return q_DSA_bits(dsa);
- case QSsl::Dh: return q_DH_bits(dh);
-#ifndef OPENSSL_NO_EC
- case QSsl::Ec: return q_EC_GROUP_get_degree(q_EC_KEY_get0_group(ec));
-#endif
- default: return -1;
- }
-}
-
-QByteArray QSslKeyPrivate::toPem(const QByteArray &passPhrase) const
-{
- if (!QSslSocket::supportsSsl() || isNull || algorithm == QSsl::Opaque)
- return QByteArray();
-
- // ### the cipher should be selectable in the API:
- const EVP_CIPHER *cipher = nullptr;
- if (type == QSsl::PrivateKey && !passPhrase.isEmpty()) {
-#ifndef OPENSSL_NO_DES
- cipher = q_EVP_des_ede3_cbc();
-#else
- return QByteArray();
-#endif
- }
-
- BIO *bio = q_BIO_new(q_BIO_s_mem());
- if (!bio)
- return QByteArray();
-
- bool fail = false;
-
- if (algorithm == QSsl::Rsa) {
- if (type == QSsl::PublicKey) {
- if (!q_PEM_write_bio_RSA_PUBKEY(bio, rsa))
- fail = true;
- } else {
- if (!q_PEM_write_bio_RSAPrivateKey(
- bio, rsa, cipher, (uchar *)passPhrase.data(),
- passPhrase.size(), nullptr, nullptr)) {
- fail = true;
- }
- }
- } else if (algorithm == QSsl::Dsa) {
- if (type == QSsl::PublicKey) {
- if (!q_PEM_write_bio_DSA_PUBKEY(bio, dsa))
- fail = true;
- } else {
- if (!q_PEM_write_bio_DSAPrivateKey(
- bio, dsa, cipher, (uchar *)passPhrase.data(),
- passPhrase.size(), nullptr, nullptr)) {
- fail = true;
- }
- }
- } else if (algorithm == QSsl::Dh) {
- EVP_PKEY *result = q_EVP_PKEY_new();
- if (!result || !q_EVP_PKEY_set1_DH(result, dh)) {
- fail = true;
- } else if (type == QSsl::PublicKey) {
- if (!q_PEM_write_bio_PUBKEY(bio, result))
- fail = true;
- } else if (!q_PEM_write_bio_PrivateKey(
- bio, result, cipher, (uchar *)passPhrase.data(),
- passPhrase.size(), nullptr, nullptr)) {
- fail = true;
- }
- q_EVP_PKEY_free(result);
-#ifndef OPENSSL_NO_EC
- } else if (algorithm == QSsl::Ec) {
- if (type == QSsl::PublicKey) {
- if (!q_PEM_write_bio_EC_PUBKEY(bio, ec))
- fail = true;
- } else {
- if (!q_PEM_write_bio_ECPrivateKey(
- bio, ec, cipher, (uchar *)passPhrase.data(),
- passPhrase.size(), nullptr, nullptr)) {
- fail = true;
- }
- }
-#endif
- } else {
- fail = true;
- }
-
- QByteArray pem;
- if (!fail) {
- char *data;
- long size = q_BIO_get_mem_data(bio, &data);
- pem = QByteArray(data, size);
- }
- q_BIO_free(bio);
- return pem;
-}
-
-Qt::HANDLE QSslKeyPrivate::handle() const
-{
- switch (algorithm) {
- case QSsl::Opaque:
- return Qt::HANDLE(opaque);
- case QSsl::Rsa:
- return Qt::HANDLE(rsa);
- case QSsl::Dsa:
- return Qt::HANDLE(dsa);
- case QSsl::Dh:
- return Qt::HANDLE(dh);
-#ifndef OPENSSL_NO_EC
- case QSsl::Ec:
- return Qt::HANDLE(ec);
-#endif
- default:
- return Qt::HANDLE(nullptr);
- }
-}
-
-static QByteArray doCrypt(QSslKeyPrivate::Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv, int enc)
-{
- const EVP_CIPHER* type = nullptr;
- int i = 0, len = 0;
-
- switch (cipher) {
- case QSslKeyPrivate::DesCbc:
-#ifndef OPENSSL_NO_DES
- type = q_EVP_des_cbc();
-#endif
- break;
- case QSslKeyPrivate::DesEde3Cbc:
-#ifndef OPENSSL_NO_DES
- type = q_EVP_des_ede3_cbc();
-#endif
- break;
- case QSslKeyPrivate::Rc2Cbc:
-#ifndef OPENSSL_NO_RC2
- type = q_EVP_rc2_cbc();
-#endif
- break;
- case QSslKeyPrivate::Aes128Cbc:
- type = q_EVP_aes_128_cbc();
- break;
- case QSslKeyPrivate::Aes192Cbc:
- type = q_EVP_aes_192_cbc();
- break;
- case QSslKeyPrivate::Aes256Cbc:
- type = q_EVP_aes_256_cbc();
- break;
- }
-
- if (type == nullptr)
- return QByteArray();
-
- QByteArray output;
- output.resize(data.size() + EVP_MAX_BLOCK_LENGTH);
-
- EVP_CIPHER_CTX *ctx = q_EVP_CIPHER_CTX_new();
- q_EVP_CIPHER_CTX_reset(ctx);
- q_EVP_CipherInit(ctx, type, nullptr, nullptr, enc);
- q_EVP_CIPHER_CTX_set_key_length(ctx, key.size());
- if (cipher == QSslKeyPrivate::Rc2Cbc)
- q_EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_SET_RC2_KEY_BITS, 8 * key.size(), nullptr);
-
- q_EVP_CipherInit_ex(ctx, nullptr, nullptr,
- reinterpret_cast<const unsigned char *>(key.constData()),
- reinterpret_cast<const unsigned char *>(iv.constData()),
- enc);
- q_EVP_CipherUpdate(ctx,
- reinterpret_cast<unsigned char *>(output.data()), &len,
- reinterpret_cast<const unsigned char *>(data.constData()), data.size());
- q_EVP_CipherFinal(ctx,
- reinterpret_cast<unsigned char *>(output.data()) + len, &i);
- len += i;
-
- q_EVP_CIPHER_CTX_reset(ctx);
- q_EVP_CIPHER_CTX_free(ctx);
-
- return output.left(len);
-}
-
-QByteArray QSslKeyPrivate::decrypt(Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv)
-{
- return doCrypt(cipher, data, key, iv, 0);
-}
-
-QByteArray QSslKeyPrivate::encrypt(Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv)
-{
- return doCrypt(cipher, data, key, iv, 1);
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslkey_p.cpp b/src/network/ssl/qsslkey_p.cpp
index ce12f49989..55cb2b0436 100644
--- a/src/network/ssl/qsslkey_p.cpp
+++ b/src/network/ssl/qsslkey_p.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/*!
@@ -54,14 +18,12 @@
\sa QSslSocket, QSslCertificate, QSslCipher
*/
+#include "qssl_p.h"
#include "qsslkey.h"
#include "qsslkey_p.h"
-#ifndef QT_NO_OPENSSL
-#include "qsslsocket_openssl_symbols_p.h"
-#endif
#include "qsslsocket.h"
#include "qsslsocket_p.h"
-#include "qasn1element_p.h"
+#include "qtlsbackend_p.h"
#include <QtCore/qatomic.h>
#include <QtCore/qbytearray.h>
@@ -73,11 +35,6 @@
QT_BEGIN_NAMESPACE
/*!
- \fn void QSslKeyPrivate::clear(bool deep)
- \internal
- */
-
-/*!
\fn void QSslKeyPrivate::decodePem(const QByteArray &pem, const QByteArray &passPhrase,
bool deepClear)
\internal
@@ -94,210 +51,57 @@ QT_BEGIN_NAMESPACE
*/
/*!
- Constructs a null key.
-
- \sa isNull()
-*/
-QSslKey::QSslKey()
- : d(new QSslKeyPrivate)
-{
-}
-
-/*!
\internal
*/
-QByteArray QSslKeyPrivate::pemHeader() const
+QSslKeyPrivate::QSslKeyPrivate()
{
- if (type == QSsl::PublicKey)
- return QByteArrayLiteral("-----BEGIN PUBLIC KEY-----");
- else if (algorithm == QSsl::Rsa)
- return QByteArrayLiteral("-----BEGIN RSA PRIVATE KEY-----");
- else if (algorithm == QSsl::Dsa)
- return QByteArrayLiteral("-----BEGIN DSA PRIVATE KEY-----");
- else if (algorithm == QSsl::Ec)
- return QByteArrayLiteral("-----BEGIN EC PRIVATE KEY-----");
- else if (algorithm == QSsl::Dh)
- return QByteArrayLiteral("-----BEGIN PRIVATE KEY-----");
-
- Q_UNREACHABLE();
- return QByteArray();
-}
-
-static QByteArray pkcs8Header(bool encrypted)
-{
- return encrypted
- ? QByteArrayLiteral("-----BEGIN ENCRYPTED PRIVATE KEY-----")
- : QByteArrayLiteral("-----BEGIN PRIVATE KEY-----");
+ const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse();
+ if (!tlsBackend)
+ return;
+ backend.reset(tlsBackend->createKey());
+ if (backend.get())
+ backend->clear(false /*not deep clear*/);
+ else
+ qCWarning(lcSsl, "Active TLS backend does not support key creation");
}
/*!
\internal
*/
-QByteArray QSslKeyPrivate::pemFooter() const
+QSslKeyPrivate::~QSslKeyPrivate()
{
- if (type == QSsl::PublicKey)
- return QByteArrayLiteral("-----END PUBLIC KEY-----");
- else if (algorithm == QSsl::Rsa)
- return QByteArrayLiteral("-----END RSA PRIVATE KEY-----");
- else if (algorithm == QSsl::Dsa)
- return QByteArrayLiteral("-----END DSA PRIVATE KEY-----");
- else if (algorithm == QSsl::Ec)
- return QByteArrayLiteral("-----END EC PRIVATE KEY-----");
- else if (algorithm == QSsl::Dh)
- return QByteArrayLiteral("-----END PRIVATE KEY-----");
-
- Q_UNREACHABLE();
- return QByteArray();
+ if (backend.get())
+ backend->clear(true /*deep clear*/);
}
-static QByteArray pkcs8Footer(bool encrypted)
+QByteArray QSslKeyPrivate::decrypt(Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv)
{
- return encrypted
- ? QByteArrayLiteral("-----END ENCRYPTED PRIVATE KEY-----")
- : QByteArrayLiteral("-----END PRIVATE KEY-----");
-}
+ if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse()) {
+ const std::unique_ptr<QTlsPrivate::TlsKey> cryptor(tlsBackend->createKey());
+ return cryptor->decrypt(cipher, data, key, iv);
+ }
-/*!
- \internal
+ return {};
+}
- Returns a DER key formatted as PEM.
-*/
-QByteArray QSslKeyPrivate::pemFromDer(const QByteArray &der, const QMap<QByteArray, QByteArray> &headers) const
+QByteArray QSslKeyPrivate::encrypt(Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv)
{
- QByteArray pem(der.toBase64());
-
- const int lineWidth = 64; // RFC 1421
- const int newLines = pem.size() / lineWidth;
- const bool rem = pem.size() % lineWidth;
-
- // ### optimize
- for (int i = 0; i < newLines; ++i)
- pem.insert((i + 1) * lineWidth + i, '\n');
- if (rem)
- pem.append('\n'); // ###
-
- QByteArray extra;
- if (!headers.isEmpty()) {
- QMap<QByteArray, QByteArray>::const_iterator it = headers.constEnd();
- do {
- --it;
- extra += it.key() + ": " + it.value() + '\n';
- } while (it != headers.constBegin());
- extra += '\n';
+ if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse()) {
+ const std::unique_ptr<QTlsPrivate::TlsKey> cryptor(tlsBackend->createKey());
+ return cryptor->encrypt(cipher, data, key, iv);
}
- if (isEncryptedPkcs8(der)) {
- pem.prepend(pkcs8Header(true) + '\n' + extra);
- pem.append(pkcs8Footer(true) + '\n');
-#if !QT_CONFIG(openssl)
- } else if (isPkcs8) {
- pem.prepend(pkcs8Header(false) + '\n' + extra);
- pem.append(pkcs8Footer(false) + '\n');
-#endif
- } else {
- pem.prepend(pemHeader() + '\n' + extra);
- pem.append(pemFooter() + '\n');
- }
-
- return pem;
+ return {};
}
/*!
- \internal
+ Constructs a null key.
- Returns a PEM key formatted as DER.
+ \sa isNull()
*/
-QByteArray QSslKeyPrivate::derFromPem(const QByteArray &pem, QMap<QByteArray, QByteArray> *headers) const
-{
- QByteArray header = pemHeader();
- QByteArray footer = pemFooter();
-
- QByteArray der(pem);
-
- int headerIndex = der.indexOf(header);
- int footerIndex = der.indexOf(footer, headerIndex + header.length());
- if (type != QSsl::PublicKey) {
- if (headerIndex == -1 || footerIndex == -1) {
- header = pkcs8Header(true);
- footer = pkcs8Footer(true);
- headerIndex = der.indexOf(header);
- footerIndex = der.indexOf(footer, headerIndex + header.length());
- }
- if (headerIndex == -1 || footerIndex == -1) {
- header = pkcs8Header(false);
- footer = pkcs8Footer(false);
- headerIndex = der.indexOf(header);
- footerIndex = der.indexOf(footer, headerIndex + header.length());
- }
- }
- if (headerIndex == -1 || footerIndex == -1)
- return QByteArray();
-
- der = der.mid(headerIndex + header.size(), footerIndex - (headerIndex + header.size()));
-
- if (der.contains("Proc-Type:")) {
- // taken from QHttpNetworkReplyPrivate::parseHeader
- int i = 0;
- while (i < der.count()) {
- int j = der.indexOf(':', i); // field-name
- if (j == -1)
- break;
- const QByteArray field = der.mid(i, j - i).trimmed();
- j++;
- // any number of LWS is allowed before and after the value
- QByteArray value;
- do {
- i = der.indexOf('\n', j);
- if (i == -1)
- break;
- if (!value.isEmpty())
- value += ' ';
- // check if we have CRLF or only LF
- bool hasCR = (i && der[i-1] == '\r');
- int length = i -(hasCR ? 1: 0) - j;
- value += der.mid(j, length).trimmed();
- j = ++i;
- } while (i < der.count() && (der.at(i) == ' ' || der.at(i) == '\t'));
- if (i == -1)
- break; // something is wrong
-
- headers->insert(field, value);
- }
- der = der.mid(i);
- }
-
- return QByteArray::fromBase64(der); // ignores newlines
-}
-
-bool QSslKeyPrivate::isEncryptedPkcs8(const QByteArray &der) const
+QSslKey::QSslKey()
+ : d(new QSslKeyPrivate)
{
- static const QList<QByteArray> pbes1OIds {
- // PKCS5
- { PKCS5_MD2_DES_CBC_OID }, { PKCS5_MD2_RC2_CBC_OID }, { PKCS5_MD5_DES_CBC_OID },
- { PKCS5_MD5_RC2_CBC_OID }, { PKCS5_SHA1_DES_CBC_OID }, { PKCS5_SHA1_RC2_CBC_OID },
- };
- QAsn1Element elem;
- if (!elem.read(der) || elem.type() != QAsn1Element::SequenceType)
- return false;
-
- const auto items = elem.toList();
- if (items.size() != 2
- || items[0].type() != QAsn1Element::SequenceType
- || items[1].type() != QAsn1Element::OctetStringType) {
- return false;
- }
-
- const auto encryptionSchemeContainer = items[0].toList();
- if (encryptionSchemeContainer.size() != 2
- || encryptionSchemeContainer[0].type() != QAsn1Element::ObjectIdentifierType
- || encryptionSchemeContainer[1].type() != QAsn1Element::SequenceType) {
- return false;
- }
-
- const QByteArray encryptionScheme = encryptionSchemeContainer[0].toObjectId();
- return encryptionScheme == PKCS5_PBES2_ENCRYPTION_OID
- || pbes1OIds.contains(encryptionScheme)
- || encryptionScheme.startsWith(PKCS12_OID);
}
/*!
@@ -314,12 +118,12 @@ QSslKey::QSslKey(const QByteArray &encoded, QSsl::KeyAlgorithm algorithm,
QSsl::EncodingFormat encoding, QSsl::KeyType type, const QByteArray &passPhrase)
: d(new QSslKeyPrivate)
{
- d->type = type;
- d->algorithm = algorithm;
- if (encoding == QSsl::Der)
- d->decodeDer(encoded, passPhrase);
- else
- d->decodePem(encoded, passPhrase);
+ if (auto *tlsKey = d->backend.get()) {
+ if (encoding == QSsl::Der)
+ tlsKey->decodeDer(type, algorithm, encoded, passPhrase, true /*deep clear*/);
+ else
+ tlsKey->decodePem(type, algorithm, encoded, passPhrase, true /*deep clear*/);
+ }
}
/*!
@@ -339,12 +143,13 @@ QSslKey::QSslKey(QIODevice *device, QSsl::KeyAlgorithm algorithm, QSsl::Encoding
QByteArray encoded;
if (device)
encoded = device->readAll();
- d->type = type;
- d->algorithm = algorithm;
- if (encoding == QSsl::Der)
- d->decodeDer(encoded, passPhrase);
- else
- d->decodePem(encoded, passPhrase);
+
+ if (auto *tlsKey = d->backend.get()) {
+ if (encoding == QSsl::Der)
+ tlsKey->decodeDer(type, algorithm, encoded, passPhrase, true /*deep clear*/);
+ else
+ tlsKey->decodePem(type, algorithm, encoded, passPhrase, true /*deep clear*/);
+ }
}
/*!
@@ -358,20 +163,8 @@ QSslKey::QSslKey(QIODevice *device, QSsl::KeyAlgorithm algorithm, QSsl::Encoding
QSslKey::QSslKey(Qt::HANDLE handle, QSsl::KeyType type)
: d(new QSslKeyPrivate)
{
-#ifndef QT_NO_OPENSSL
- EVP_PKEY *evpKey = reinterpret_cast<EVP_PKEY *>(handle);
- if (!evpKey || !d->fromEVP_PKEY(evpKey)) {
- d->opaque = evpKey;
- d->algorithm = QSsl::Opaque;
- } else {
- q_EVP_PKEY_free(evpKey);
- }
-#else
- d->opaque = handle;
- d->algorithm = QSsl::Opaque;
-#endif
- d->type = type;
- d->isNull = !d->opaque;
+ if (auto *tlsKey = d->backend.get())
+ tlsKey->fromHandle(handle, type);
}
/*!
@@ -433,7 +226,10 @@ QSslKey &QSslKey::operator=(const QSslKey &other)
*/
bool QSslKey::isNull() const
{
- return d->isNull;
+ if (const auto *tlsKey = d->backend.get())
+ return tlsKey->isNull();
+
+ return true;
}
/*!
@@ -451,7 +247,10 @@ void QSslKey::clear()
*/
int QSslKey::length() const
{
- return d->length();
+ if (const auto *tlsKey = d->backend.get())
+ return tlsKey->length();
+
+ return -1;
}
/*!
@@ -459,7 +258,10 @@ int QSslKey::length() const
*/
QSsl::KeyType QSslKey::type() const
{
- return d->type;
+ if (const auto *tlsKey = d->backend.get())
+ return tlsKey->type();
+
+ return QSsl::PublicKey;
}
/*!
@@ -467,7 +269,10 @@ QSsl::KeyType QSslKey::type() const
*/
QSsl::KeyAlgorithm QSslKey::algorithm() const
{
- return d->algorithm;
+ if (const auto *tlsKey = d->backend.get())
+ return tlsKey->algorithm();
+
+ return QSsl::Opaque;
}
/*!
@@ -478,19 +283,18 @@ QSsl::KeyAlgorithm QSslKey::algorithm() const
*/
QByteArray QSslKey::toDer(const QByteArray &passPhrase) const
{
- if (d->isNull || d->algorithm == QSsl::Opaque)
- return QByteArray();
+ if (isNull() || algorithm() == QSsl::Opaque)
+ return {};
// Encrypted DER is nonsense, see QTBUG-41038.
- if (d->type == QSsl::PrivateKey && !passPhrase.isEmpty())
- return QByteArray();
+ if (type() == QSsl::PrivateKey && !passPhrase.isEmpty())
+ return {};
-#ifndef QT_NO_OPENSSL
QMap<QByteArray, QByteArray> headers;
- return d->derFromPem(toPem(passPhrase), &headers);
-#else
- return d->derData;
-#endif
+ if (const auto *tlsKey = d->backend.get())
+ return tlsKey->derFromPem(toPem(passPhrase), &headers);
+
+ return {};
}
/*!
@@ -500,7 +304,10 @@ QByteArray QSslKey::toDer(const QByteArray &passPhrase) const
*/
QByteArray QSslKey::toPem(const QByteArray &passPhrase) const
{
- return d->toPem(passPhrase);
+ if (const auto *tlsKey = d->backend.get())
+ return tlsKey->toPem(passPhrase);
+
+ return {};
}
/*!
@@ -516,7 +323,10 @@ QByteArray QSslKey::toPem(const QByteArray &passPhrase) const
*/
Qt::HANDLE QSslKey::handle() const
{
- return d->handle();
+ if (d->backend.get())
+ return d->backend->handle();
+
+ return nullptr;
}
/*!
diff --git a/src/network/ssl/qsslkey_p.h b/src/network/ssl/qsslkey_p.h
index dd1a31b0e5..d28ee5ad11 100644
--- a/src/network/ssl/qsslkey_p.h
+++ b/src/network/ssl/qsslkey_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSSLKEY_OPENSSL_P_H
@@ -53,83 +17,30 @@
//
#include <QtNetwork/private/qtnetworkglobal_p.h>
+
#include "qsslkey.h"
-#include "qsslsocket_p.h" // includes wincrypt.h
+#include "qssl_p.h"
-#ifndef QT_NO_OPENSSL
-#include <openssl/rsa.h>
-#include <openssl/dsa.h>
-#endif
+#include <memory>
QT_BEGIN_NAMESPACE
+namespace QTlsPrivate {
+class TlsKey;
+}
+
class QSslKeyPrivate
{
public:
- inline QSslKeyPrivate()
- : algorithm(QSsl::Opaque)
- , opaque(nullptr)
- {
- clear(false);
- }
-
- inline ~QSslKeyPrivate()
- { clear(); }
-
- void clear(bool deep = true);
-
-#ifndef QT_NO_OPENSSL
- bool fromEVP_PKEY(EVP_PKEY *pkey);
-#endif
- void decodeDer(const QByteArray &der, const QByteArray &passPhrase = {}, bool deepClear = true);
- void decodePem(const QByteArray &pem, const QByteArray &passPhrase, bool deepClear = true);
- QByteArray pemHeader() const;
- QByteArray pemFooter() const;
- QByteArray pemFromDer(const QByteArray &der, const QMap<QByteArray, QByteArray> &headers) const;
- QByteArray derFromPem(const QByteArray &pem, QMap<QByteArray, QByteArray> *headers) const;
-
- int length() const;
- QByteArray toPem(const QByteArray &passPhrase) const;
- Qt::HANDLE handle() const;
-
- bool isEncryptedPkcs8(const QByteArray &der) const;
-#if !QT_CONFIG(openssl)
- QByteArray decryptPkcs8(const QByteArray &encrypted, const QByteArray &passPhrase);
- bool isPkcs8 = false;
-#endif
-
- bool isNull;
- QSsl::KeyType type;
- QSsl::KeyAlgorithm algorithm;
-
- enum Cipher {
- DesCbc,
- DesEde3Cbc,
- Rc2Cbc,
- Aes128Cbc,
- Aes192Cbc,
- Aes256Cbc
- };
+ QSslKeyPrivate();
+ ~QSslKeyPrivate();
- Q_AUTOTEST_EXPORT static QByteArray decrypt(Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv);
- Q_AUTOTEST_EXPORT static QByteArray encrypt(Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv);
+ using Cipher = QTlsPrivate::Cipher;
-#ifndef QT_NO_OPENSSL
- union {
- EVP_PKEY *opaque;
- RSA *rsa;
- DSA *dsa;
- DH *dh;
-#ifndef OPENSSL_NO_EC
- EC_KEY *ec;
-#endif
- };
-#else
- Qt::HANDLE opaque;
- QByteArray derData;
- int keyLength;
-#endif
+ Q_NETWORK_EXPORT static QByteArray decrypt(Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv);
+ Q_NETWORK_EXPORT static QByteArray encrypt(Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv);
+ std::unique_ptr<QTlsPrivate::TlsKey> backend;
QAtomicInt ref;
private:
diff --git a/src/network/ssl/qsslkey_qt.cpp b/src/network/ssl/qsslkey_qt.cpp
deleted file mode 100644
index 3b8fada8fc..0000000000
--- a/src/network/ssl/qsslkey_qt.cpp
+++ /dev/null
@@ -1,785 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Jeremy Lainé <jeremy.laine@m4x.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qsslkey.h"
-#include "qsslkey_p.h"
-#include "qasn1element_p.h"
-
-#include <QtCore/qdatastream.h>
-#include <QtCore/qcryptographichash.h>
-#include <QtCore/QMessageAuthenticationCode>
-#include <QtCore/qrandom.h>
-
-#include <QtNetwork/qpassworddigestor.h>
-
-#include <cstring>
-
-QT_USE_NAMESPACE
-
-static const quint8 bits_table[256] = {
- 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,
- 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
- 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
- 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
- 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
- 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
- 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
- 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
-};
-
-// OIDs of named curves allowed in TLS as per RFCs 4492 and 7027,
-// see also https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8
-
-typedef QMap<QByteArray, int> OidLengthMap;
-static OidLengthMap createOidMap()
-{
- OidLengthMap oids;
- oids.insert(oids.cend(), QByteArrayLiteral("1.2.840.10045.3.1.1"), 192); // secp192r1 a.k.a prime192v1
- oids.insert(oids.cend(), QByteArrayLiteral("1.2.840.10045.3.1.7"), 256); // secp256r1 a.k.a prime256v1
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.1"), 193); // sect193r2
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.10"), 256); // secp256k1
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.16"), 283); // sect283k1
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.17"), 283); // sect283r1
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.26"), 233); // sect233k1
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.27"), 233); // sect233r1
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.3"), 239); // sect239k1
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.30"), 160); // secp160r2
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.31"), 192); // secp192k1
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.32"), 224); // secp224k1
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.33"), 224); // secp224r1
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.34"), 384); // secp384r1
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.35"), 521); // secp521r1
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.36"), 409); // sect409k1
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.37"), 409); // sect409r1
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.38"), 571); // sect571k1
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.39"), 571); // sect571r1
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.8"), 160); // secp160r1
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.9"), 160); // secp160k1
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.36.3.3.2.8.1.1.11"), 384); // brainpoolP384r1
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.36.3.3.2.8.1.1.13"), 512); // brainpoolP512r1
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.36.3.3.2.8.1.1.7"), 256); // brainpoolP256r1
- return oids;
-}
-Q_GLOBAL_STATIC_WITH_ARGS(OidLengthMap, oidLengthMap, (createOidMap()))
-
-static int curveBits(const QByteArray &oid)
-{
- const int length = oidLengthMap->value(oid);
- return length ? length : -1;
-}
-
-static int numberOfBits(const QByteArray &modulus)
-{
- int bits = modulus.size() * 8;
- for (int i = 0; i < modulus.size(); ++i) {
- quint8 b = modulus[i];
- bits -= 8;
- if (b != 0) {
- bits += bits_table[b];
- break;
- }
- }
- return bits;
-}
-
-static QByteArray deriveAesKey(QSslKeyPrivate::Cipher cipher, const QByteArray &passPhrase, const QByteArray &iv)
-{
- // This is somewhat simplified and shortened version of what OpenSSL does.
- // See, for example, EVP_BytesToKey for the "algorithm" itself and elsewhere
- // in their code for what they pass as arguments to EVP_BytesToKey when
- // deriving encryption keys (when reading/writing pems files with encrypted
- // keys).
-
- Q_ASSERT(iv.size() >= 8);
-
- QCryptographicHash hash(QCryptographicHash::Md5);
-
- QByteArray data(passPhrase);
- data.append(iv.data(), 8); // AKA PKCS5_SALT_LEN in OpenSSL.
-
- hash.addData(data);
-
- if (cipher == QSslKeyPrivate::Aes128Cbc)
- return hash.result();
-
- QByteArray key(hash.result());
- hash.reset();
- hash.addData(key);
- hash.addData(data);
-
- if (cipher == QSslKeyPrivate::Aes192Cbc)
- return key.append(hash.result().constData(), 8);
-
- return key.append(hash.result());
-}
-
-static QByteArray deriveKey(QSslKeyPrivate::Cipher cipher, const QByteArray &passPhrase, const QByteArray &iv)
-{
- QByteArray key;
- QCryptographicHash hash(QCryptographicHash::Md5);
- hash.addData(passPhrase);
- hash.addData(iv);
- switch (cipher) {
- case QSslKeyPrivate::DesCbc:
- key = hash.result().left(8);
- break;
- case QSslKeyPrivate::DesEde3Cbc:
- key = hash.result();
- hash.reset();
- hash.addData(key);
- hash.addData(passPhrase);
- hash.addData(iv);
- key += hash.result().left(8);
- break;
- case QSslKeyPrivate::Rc2Cbc:
- key = hash.result();
- break;
- case QSslKeyPrivate::Aes128Cbc:
- case QSslKeyPrivate::Aes192Cbc:
- case QSslKeyPrivate::Aes256Cbc:
- return deriveAesKey(cipher, passPhrase, iv);
- }
- return key;
-}
-
-void QSslKeyPrivate::clear(bool deep)
-{
- isNull = true;
- if (deep)
- std::memset(derData.data(), 0, derData.size());
- derData.clear();
- keyLength = -1;
-}
-
-static int extractPkcs8KeyLength(const QList<QAsn1Element> &items, QSslKeyPrivate *that)
-{
- Q_ASSERT(items.size() == 3);
- int keyLength;
-
- auto getName = [](QSsl::KeyAlgorithm algorithm) {
- switch (algorithm){
- case QSsl::Rsa: return "RSA";
- case QSsl::Dsa: return "DSA";
- case QSsl::Dh: return "DH";
- case QSsl::Ec: return "EC";
- case QSsl::Opaque: return "Opaque";
- }
- Q_UNREACHABLE();
- };
-
- const auto pkcs8Info = items[1].toList();
- if (pkcs8Info.size() != 2 || pkcs8Info[0].type() != QAsn1Element::ObjectIdentifierType)
- return -1;
- const QByteArray value = pkcs8Info[0].toObjectId();
- if (value == RSA_ENCRYPTION_OID) {
- if (Q_UNLIKELY(that->algorithm != QSsl::Rsa)) {
- // We could change the 'algorithm' of QSslKey here and continue loading, but
- // this is not supported in the openssl back-end, so we'll fail here and give
- // the user some feedback.
- qWarning() << "QSslKey: Found RSA key when asked to use" << getName(that->algorithm)
- << "\nLoading will fail.";
- return -1;
- }
- // Luckily it contains the 'normal' RSA-key format inside, so we can just recurse
- // and read the key's info.
- that->decodeDer(items[2].value());
- // The real info has been filled out in the call above, so return as if it was invalid
- // to avoid overwriting the data.
- return -1;
- } else if (value == EC_ENCRYPTION_OID) {
- if (Q_UNLIKELY(that->algorithm != QSsl::Ec)) {
- // As above for RSA.
- qWarning() << "QSslKey: Found EC key when asked to use" << getName(that->algorithm)
- << "\nLoading will fail.";
- return -1;
- }
- // I don't know where this is documented, but the elliptic-curve identifier has been
- // moved into the "pkcs#8 wrapper", which is what we're interested in.
- if (pkcs8Info[1].type() != QAsn1Element::ObjectIdentifierType)
- return -1;
- keyLength = curveBits(pkcs8Info[1].toObjectId());
- } else if (value == DSA_ENCRYPTION_OID) {
- if (Q_UNLIKELY(that->algorithm != QSsl::Dsa)) {
- // As above for RSA.
- qWarning() << "QSslKey: Found DSA when asked to use" << getName(that->algorithm)
- << "\nLoading will fail.";
- return -1;
- }
- // DSA's structure is documented here:
- // https://www.cryptsoft.com/pkcs11doc/STANDARD/v201-95.pdf in section 11.9.
- if (pkcs8Info[1].type() != QAsn1Element::SequenceType)
- return -1;
- const auto dsaInfo = pkcs8Info[1].toList();
- if (dsaInfo.size() != 3 || dsaInfo[0].type() != QAsn1Element::IntegerType)
- return -1;
- keyLength = numberOfBits(dsaInfo[0].value());
- } else if (value == DH_ENCRYPTION_OID) {
- if (Q_UNLIKELY(that->algorithm != QSsl::Dh)) {
- // As above for RSA.
- qWarning() << "QSslKey: Found DH when asked to use" << getName(that->algorithm)
- << "\nLoading will fail.";
- return -1;
- }
- // DH's structure is documented here:
- // https://www.cryptsoft.com/pkcs11doc/STANDARD/v201-95.pdf in section 11.9.
- if (pkcs8Info[1].type() != QAsn1Element::SequenceType)
- return -1;
- const auto dhInfo = pkcs8Info[1].toList();
- if (dhInfo.size() < 2 || dhInfo.size() > 3 || dhInfo[0].type() != QAsn1Element::IntegerType)
- return -1;
- keyLength = numberOfBits(dhInfo[0].value());
- } else {
- // in case of unexpected formats:
- qWarning() << "QSslKey: Unsupported PKCS#8 key algorithm:" << value
- << "\nFile a bugreport to Qt (include the line above).";
- return -1;
- }
- return keyLength;
-}
-
-void QSslKeyPrivate::decodeDer(const QByteArray &der, const QByteArray &passPhrase, bool deepClear)
-{
- clear(deepClear);
-
- if (der.isEmpty())
- return;
- // decryptPkcs8 decrypts if necessary or returns 'der' unaltered
- QByteArray decryptedDer = decryptPkcs8(der, passPhrase);
-
- QAsn1Element elem;
- if (!elem.read(decryptedDer) || elem.type() != QAsn1Element::SequenceType)
- return;
-
- if (type == QSsl::PublicKey) {
- // key info
- QDataStream keyStream(elem.value());
- if (!elem.read(keyStream) || elem.type() != QAsn1Element::SequenceType)
- return;
- const auto infoItems = elem.toList();
- if (infoItems.size() < 2 || infoItems[0].type() != QAsn1Element::ObjectIdentifierType)
- return;
- if (algorithm == QSsl::Rsa) {
- if (infoItems[0].toObjectId() != RSA_ENCRYPTION_OID)
- return;
- // key data
- if (!elem.read(keyStream) || elem.type() != QAsn1Element::BitStringType || elem.value().isEmpty())
- return;
- if (!elem.read(elem.value().mid(1)) || elem.type() != QAsn1Element::SequenceType)
- return;
- if (!elem.read(elem.value()) || elem.type() != QAsn1Element::IntegerType)
- return;
- keyLength = numberOfBits(elem.value());
- } else if (algorithm == QSsl::Dsa) {
- if (infoItems[0].toObjectId() != DSA_ENCRYPTION_OID)
- return;
- if (infoItems[1].type() != QAsn1Element::SequenceType)
- return;
- // key params
- const auto params = infoItems[1].toList();
- if (params.isEmpty() || params[0].type() != QAsn1Element::IntegerType)
- return;
- keyLength = numberOfBits(params[0].value());
- } else if (algorithm == QSsl::Dh) {
- if (infoItems[0].toObjectId() != DH_ENCRYPTION_OID)
- return;
- if (infoItems[1].type() != QAsn1Element::SequenceType)
- return;
- // key params
- const auto params = infoItems[1].toList();
- if (params.isEmpty() || params[0].type() != QAsn1Element::IntegerType)
- return;
- keyLength = numberOfBits(params[0].value());
- } else if (algorithm == QSsl::Ec) {
- if (infoItems[0].toObjectId() != EC_ENCRYPTION_OID)
- return;
- if (infoItems[1].type() != QAsn1Element::ObjectIdentifierType)
- return;
- keyLength = curveBits(infoItems[1].toObjectId());
- }
-
- } else {
- const auto items = elem.toList();
- if (items.isEmpty())
- return;
-
- // version
- if (items[0].type() != QAsn1Element::IntegerType)
- return;
- const QByteArray versionHex = items[0].value().toHex();
-
- if (items.size() == 3 && items[1].type() == QAsn1Element::SequenceType
- && items[2].type() == QAsn1Element::OctetStringType) {
- if (versionHex != "00" && versionHex != "01")
- return;
- int pkcs8KeyLength = extractPkcs8KeyLength(items, this);
- if (pkcs8KeyLength == -1)
- return;
- isPkcs8 = true;
- keyLength = pkcs8KeyLength;
- } else if (algorithm == QSsl::Rsa) {
- if (versionHex != "00")
- return;
- if (items.size() != 9 || items[1].type() != QAsn1Element::IntegerType)
- return;
- keyLength = numberOfBits(items[1].value());
- } else if (algorithm == QSsl::Dsa) {
- if (versionHex != "00")
- return;
- if (items.size() != 6 || items[1].type() != QAsn1Element::IntegerType)
- return;
- keyLength = numberOfBits(items[1].value());
- } else if (algorithm == QSsl::Dh) {
- if (versionHex != "00")
- return;
- if (items.size() < 5 || items.size() > 6 || items[1].type() != QAsn1Element::IntegerType)
- return;
- keyLength = numberOfBits(items[1].value());
- } else if (algorithm == QSsl::Ec) {
- if (versionHex != "01")
- return;
- if (items.size() != 4
- || items[1].type() != QAsn1Element::OctetStringType
- || items[2].type() != QAsn1Element::Context0Type
- || items[3].type() != QAsn1Element::Context1Type)
- return;
- QAsn1Element oidElem;
- if (!oidElem.read(items[2].value())
- || oidElem.type() != QAsn1Element::ObjectIdentifierType)
- return;
- keyLength = curveBits(oidElem.toObjectId());
- }
- }
-
- derData = decryptedDer;
- isNull = false;
-}
-
-void QSslKeyPrivate::decodePem(const QByteArray &pem, const QByteArray &passPhrase,
- bool deepClear)
-{
- QMap<QByteArray, QByteArray> headers;
- QByteArray data = derFromPem(pem, &headers);
- if (headers.value("Proc-Type") == "4,ENCRYPTED") {
- const QList<QByteArray> dekInfo = headers.value("DEK-Info").split(',');
- if (dekInfo.size() != 2) {
- clear(deepClear);
- return;
- }
-
- Cipher cipher;
- if (dekInfo.first() == "DES-CBC") {
- cipher = DesCbc;
- } else if (dekInfo.first() == "DES-EDE3-CBC") {
- cipher = DesEde3Cbc;
- } else if (dekInfo.first() == "RC2-CBC") {
- cipher = Rc2Cbc;
- } else if (dekInfo.first() == "AES-128-CBC") {
- cipher = Aes128Cbc;
- } else if (dekInfo.first() == "AES-192-CBC") {
- cipher = Aes192Cbc;
- } else if (dekInfo.first() == "AES-256-CBC") {
- cipher = Aes256Cbc;
- } else {
- clear(deepClear);
- return;
- }
-
- const QByteArray iv = QByteArray::fromHex(dekInfo.last());
- const QByteArray key = deriveKey(cipher, passPhrase, iv);
- data = decrypt(cipher, data, key, iv);
- }
- decodeDer(data, passPhrase, deepClear);
-}
-
-int QSslKeyPrivate::length() const
-{
- return keyLength;
-}
-
-QByteArray QSslKeyPrivate::toPem(const QByteArray &passPhrase) const
-{
- QByteArray data;
- QMap<QByteArray, QByteArray> headers;
-
- if (type == QSsl::PrivateKey && !passPhrase.isEmpty()) {
- // ### use a cryptographically secure random number generator
- quint64 random = QRandomGenerator::system()->generate64();
- QByteArray iv = QByteArray::fromRawData(reinterpret_cast<const char *>(&random), sizeof(random));
-
- Cipher cipher = DesEde3Cbc;
- const QByteArray key = deriveKey(cipher, passPhrase, iv);
- data = encrypt(cipher, derData, key, iv);
-
- headers.insert("Proc-Type", "4,ENCRYPTED");
- headers.insert("DEK-Info", "DES-EDE3-CBC," + iv.toHex());
- } else {
- data = derData;
- }
-
- return pemFromDer(data, headers);
-}
-
-Qt::HANDLE QSslKeyPrivate::handle() const
-{
- return opaque;
-}
-
-// Maps OIDs to the encryption cipher they specify
-static const QMap<QByteArray, QSslKeyPrivate::Cipher> oidCipherMap {
- {DES_CBC_ENCRYPTION_OID, QSslKeyPrivate::Cipher::DesCbc},
- {DES_EDE3_CBC_ENCRYPTION_OID, QSslKeyPrivate::Cipher::DesEde3Cbc},
- // {PKCS5_MD2_DES_CBC_OID, QSslKeyPrivate::Cipher::DesCbc}, // No MD2
- {PKCS5_MD5_DES_CBC_OID, QSslKeyPrivate::Cipher::DesCbc},
- {PKCS5_SHA1_DES_CBC_OID, QSslKeyPrivate::Cipher::DesCbc},
- // {PKCS5_MD2_RC2_CBC_OID, QSslKeyPrivate::Cipher::Rc2Cbc}, // No MD2
- {PKCS5_MD5_RC2_CBC_OID, QSslKeyPrivate::Cipher::Rc2Cbc},
- {PKCS5_SHA1_RC2_CBC_OID, QSslKeyPrivate::Cipher::Rc2Cbc},
- {RC2_CBC_ENCRYPTION_OID, QSslKeyPrivate::Cipher::Rc2Cbc}
- // {RC5_CBC_ENCRYPTION_OID, QSslKeyPrivate::Cipher::Rc5Cbc}, // No RC5
- // {AES128_CBC_ENCRYPTION_OID, QSslKeyPrivate::Cipher::Aes128}, // no AES
- // {AES192_CBC_ENCRYPTION_OID, QSslKeyPrivate::Cipher::Aes192},
- // {AES256_CBC_ENCRYPTION_OID, QSslKeyPrivate::Cipher::Aes256}
-};
-
-struct EncryptionData
-{
- EncryptionData() : initialized(false)
- {}
- EncryptionData(QSslKeyPrivate::Cipher cipher, QByteArray key, QByteArray iv)
- : initialized(true), cipher(cipher), key(key), iv(iv)
- {}
- bool initialized;
- QSslKeyPrivate::Cipher cipher;
- QByteArray key;
- QByteArray iv;
-};
-
-static EncryptionData readPbes2(const QList<QAsn1Element> &element, const QByteArray &passPhrase)
-{
- // RFC 8018: https://tools.ietf.org/html/rfc8018#section-6.2
- /*** Scheme: ***
- * Sequence (scheme-specific info..)
- * Sequence (key derivation info)
- * Object Identifier (Key derivation algorithm (e.g. PBKDF2))
- * Sequence (salt)
- * CHOICE (this entry can be either of the types it contains)
- * Octet string (actual salt)
- * Object identifier (Anything using this is deferred to a later version of PKCS #5)
- * Integer (iteration count)
- * Sequence (encryption algorithm info)
- * Object identifier (identifier for the algorithm)
- * Algorithm dependent, is covered in the switch further down
- */
-
- static const QMap<QByteArray, QCryptographicHash::Algorithm> pbes2OidHashFunctionMap {
- // PBES2/PBKDF2
- {HMAC_WITH_SHA1, QCryptographicHash::Sha1},
- {HMAC_WITH_SHA224, QCryptographicHash::Sha224},
- {HMAC_WITH_SHA256, QCryptographicHash::Sha256},
- {HMAC_WITH_SHA512, QCryptographicHash::Sha512},
- {HMAC_WITH_SHA512_224, QCryptographicHash::Sha512},
- {HMAC_WITH_SHA512_256, QCryptographicHash::Sha512},
- {HMAC_WITH_SHA384, QCryptographicHash::Sha384}
- };
-
- // Values from their respective sections here: https://tools.ietf.org/html/rfc8018#appendix-B.2
- static const QMap<QSslKeyPrivate::Cipher, int> cipherKeyLengthMap {
- {QSslKeyPrivate::Cipher::DesCbc, 8},
- {QSslKeyPrivate::Cipher::DesEde3Cbc, 24},
- // @note: variable key-length (https://tools.ietf.org/html/rfc8018#appendix-B.2.3)
- {QSslKeyPrivate::Cipher::Rc2Cbc, 4}
- // @todo: AES(, rc5?)
- };
-
- const QList<QAsn1Element> keyDerivationContainer = element[0].toList();
- if (keyDerivationContainer.size() != 2
- || keyDerivationContainer[0].type() != QAsn1Element::ObjectIdentifierType
- || keyDerivationContainer[1].type() != QAsn1Element::SequenceType) {
- return {};
- }
-
- const QByteArray keyDerivationAlgorithm = keyDerivationContainer[0].toObjectId();
- const auto keyDerivationParams = keyDerivationContainer[1].toList();
-
- const auto encryptionAlgorithmContainer = element[1].toList();
- if (encryptionAlgorithmContainer.size() != 2
- || encryptionAlgorithmContainer[0].type() != QAsn1Element::ObjectIdentifierType) {
- return {};
- }
-
- auto iterator = oidCipherMap.constFind(encryptionAlgorithmContainer[0].toObjectId());
- if (iterator == oidCipherMap.cend()) {
- qWarning()
- << "QSslKey: Unsupported encryption cipher OID:" << encryptionAlgorithmContainer[0].toObjectId()
- << "\nFile a bugreport to Qt (include the line above).";
- return {};
- }
-
- QSslKeyPrivate::Cipher cipher = *iterator;
- QByteArray key;
- QByteArray iv;
- switch (cipher) {
- case QSslKeyPrivate::Cipher::DesCbc:
- case QSslKeyPrivate::Cipher::DesEde3Cbc:
- // https://tools.ietf.org/html/rfc8018#appendix-B.2.1 (DES-CBC-PAD)
- // https://tools.ietf.org/html/rfc8018#appendix-B.2.2 (DES-EDE3-CBC-PAD)
- // @todo https://tools.ietf.org/html/rfc8018#appendix-B.2.5 (AES-CBC-PAD)
- /*** Scheme: ***
- * Octet string (IV)
- */
- if (encryptionAlgorithmContainer[1].type() != QAsn1Element::OctetStringType)
- return {};
-
- // @note: All AES identifiers should be able to use this branch!!
- iv = encryptionAlgorithmContainer[1].value();
-
- if (iv.size() != 8) // @note: AES needs 16 bytes
- return {};
- break;
- case QSslKeyPrivate::Cipher::Rc2Cbc: {
- // https://tools.ietf.org/html/rfc8018#appendix-B.2.3
- /*** Scheme: ***
- * Sequence (rc2 parameters)
- * Integer (rc2 parameter version)
- * Octet string (IV)
- */
- if (encryptionAlgorithmContainer[1].type() != QAsn1Element::SequenceType)
- return {};
- const auto rc2ParametersContainer = encryptionAlgorithmContainer[1].toList();
- if ((rc2ParametersContainer.size() != 1 && rc2ParametersContainer.size() != 2)
- || rc2ParametersContainer.back().type() != QAsn1Element::OctetStringType) {
- return {};
- }
- iv = rc2ParametersContainer.back().value();
- if (iv.size() != 8)
- return {};
- break;
- } // @todo(?): case (RC5 , AES)
- case QSslKeyPrivate::Cipher::Aes128Cbc:
- case QSslKeyPrivate::Cipher::Aes192Cbc:
- case QSslKeyPrivate::Cipher::Aes256Cbc:
- Q_UNREACHABLE();
- }
-
- if (Q_LIKELY(keyDerivationAlgorithm == PKCS5_PBKDF2_ENCRYPTION_OID)) {
- // Definition: https://tools.ietf.org/html/rfc8018#appendix-A.2
- QByteArray salt;
- if (keyDerivationParams[0].type() == QAsn1Element::OctetStringType) {
- salt = keyDerivationParams[0].value();
- } else if (keyDerivationParams[0].type() == QAsn1Element::ObjectIdentifierType) {
- Q_UNIMPLEMENTED();
- /* See paragraph from https://tools.ietf.org/html/rfc8018#appendix-A.2
- which ends with: "such facilities are deferred to a future version of PKCS #5"
- */
- return {};
- } else {
- return {};
- }
-
- // Iterations needed to derive the key
- int iterationCount = keyDerivationParams[1].toInteger();
- // Optional integer
- int keyLength = -1;
- int vectorPos = 2;
- if (keyDerivationParams.size() > vectorPos
- && keyDerivationParams[vectorPos].type() == QAsn1Element::IntegerType) {
- keyLength = keyDerivationParams[vectorPos].toInteger(nullptr);
- ++vectorPos;
- } else {
- keyLength = cipherKeyLengthMap[cipher];
- }
-
- // Optional algorithm identifier (default: HMAC-SHA-1)
- QCryptographicHash::Algorithm hashAlgorithm = QCryptographicHash::Sha1;
- if (keyDerivationParams.size() > vectorPos
- && keyDerivationParams[vectorPos].type() == QAsn1Element::SequenceType) {
- const auto hashAlgorithmContainer = keyDerivationParams[vectorPos].toList();
- hashAlgorithm = pbes2OidHashFunctionMap[hashAlgorithmContainer.front().toObjectId()];
- Q_ASSERT(hashAlgorithmContainer[1].type() == QAsn1Element::NullType);
- ++vectorPos;
- }
- Q_ASSERT(keyDerivationParams.size() == vectorPos);
-
- key = QPasswordDigestor::deriveKeyPbkdf2(hashAlgorithm, passPhrase, salt, iterationCount, keyLength);
- } else {
- qWarning()
- << "QSslKey: Unsupported key derivation algorithm OID:" << keyDerivationAlgorithm
- << "\nFile a bugreport to Qt (include the line above).";
- return {};
- }
- return {cipher, key, iv};
-}
-
-// Maps OIDs to the hash function it specifies
-static const QMap<QByteArray, QCryptographicHash::Algorithm> pbes1OidHashFunctionMap {
-#ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
- // PKCS5
- //{PKCS5_MD2_DES_CBC_OID, QCryptographicHash::Md2}, No MD2
- //{PKCS5_MD2_RC2_CBC_OID, QCryptographicHash::Md2},
- {PKCS5_MD5_DES_CBC_OID, QCryptographicHash::Md5},
- {PKCS5_MD5_RC2_CBC_OID, QCryptographicHash::Md5},
-#endif
- {PKCS5_SHA1_DES_CBC_OID, QCryptographicHash::Sha1},
- {PKCS5_SHA1_RC2_CBC_OID, QCryptographicHash::Sha1},
- // PKCS12 (unimplemented)
- // {PKCS12_SHA1_RC4_128_OID, QCryptographicHash::Sha1}, // No RC4
- // {PKCS12_SHA1_RC4_40_OID, QCryptographicHash::Sha1},
- // @todo: lacking support. @note: there might be code to do this inside qsslsocket_mac...
- // further note that more work may be required for the 3DES variations listed to be available.
- // {PKCS12_SHA1_3KEY_3DES_CBC_OID, QCryptographicHash::Sha1},
- // {PKCS12_SHA1_2KEY_3DES_CBC_OID, QCryptographicHash::Sha1},
- // {PKCS12_SHA1_RC2_128_CBC_OID, QCryptographicHash::Sha1},
- // {PKCS12_SHA1_RC2_40_CBC_OID, QCryptographicHash::Sha1}
-};
-
-static EncryptionData readPbes1(const QList<QAsn1Element> &element,
- const QByteArray &encryptionScheme, const QByteArray &passPhrase)
-{
- // RFC 8018: https://tools.ietf.org/html/rfc8018#section-6.1
- // Steps refer to this section: https://tools.ietf.org/html/rfc8018#section-6.1.2
- /*** Scheme: ***
- * Sequence (PBE Parameter)
- * Octet string (salt)
- * Integer (iteration counter)
- */
- // Step 1
- if (element.size() != 2
- || element[0].type() != QAsn1Element::ElementType::OctetStringType
- || element[1].type() != QAsn1Element::ElementType::IntegerType) {
- return {};
- }
- QByteArray salt = element[0].value();
- if (salt.size() != 8)
- return {};
-
- int iterationCount = element[1].toInteger();
- if (iterationCount < 0)
- return {};
-
- // Step 2
- auto iterator = pbes1OidHashFunctionMap.constFind(encryptionScheme);
- if (iterator == pbes1OidHashFunctionMap.cend()) {
- // Qt was compiled with ONLY_SHA1 (or it's MD2)
- return {};
- }
- QCryptographicHash::Algorithm hashAlgorithm = *iterator;
- QByteArray key = QPasswordDigestor::deriveKeyPbkdf1(hashAlgorithm, passPhrase, salt, iterationCount, 16);
- if (key.size() != 16)
- return {};
-
- // Step 3
- QByteArray iv = key.right(8); // last 8 bytes are used as IV
- key.truncate(8); // first 8 bytes are used for the key
-
- QSslKeyPrivate::Cipher cipher = oidCipherMap[encryptionScheme];
- // Steps 4-6 are done after returning
- return {cipher, key, iv};
-}
-
-QByteArray QSslKeyPrivate::decryptPkcs8(const QByteArray &encrypted, const QByteArray &passPhrase)
-{
- // RFC 5958: https://tools.ietf.org/html/rfc5958
- /*** Scheme: ***
- * Sequence
- * Sequence
- * Object Identifier (encryption scheme (currently PBES2, PBES1, @todo PKCS12))
- * Sequence (scheme parameters)
- * Octet String (the encrypted data)
- */
- QAsn1Element elem;
- if (!elem.read(encrypted) || elem.type() != QAsn1Element::SequenceType)
- return encrypted;
-
- const auto items = elem.toList();
- if (items.size() != 2
- || items[0].type() != QAsn1Element::SequenceType
- || items[1].type() != QAsn1Element::OctetStringType) {
- return encrypted;
- }
-
- const auto encryptionSchemeContainer = items[0].toList();
-
- if (encryptionSchemeContainer.size() != 2
- || encryptionSchemeContainer[0].type() != QAsn1Element::ObjectIdentifierType
- || encryptionSchemeContainer[1].type() != QAsn1Element::SequenceType) {
- return encrypted;
- }
-
- const QByteArray encryptionScheme = encryptionSchemeContainer[0].toObjectId();
- const auto schemeParameterContainer = encryptionSchemeContainer[1].toList();
-
- if (schemeParameterContainer.size() != 2
- && schemeParameterContainer[0].type() != QAsn1Element::SequenceType
- && schemeParameterContainer[1].type() != QAsn1Element::SequenceType) {
- return encrypted;
- }
-
- EncryptionData data;
- if (encryptionScheme == PKCS5_PBES2_ENCRYPTION_OID) {
- data = readPbes2(schemeParameterContainer, passPhrase);
- } else if (pbes1OidHashFunctionMap.contains(encryptionScheme)) {
- data = readPbes1(schemeParameterContainer, encryptionScheme, passPhrase);
- } else if (encryptionScheme.startsWith(PKCS12_OID)) {
- Q_UNIMPLEMENTED(); // this isn't some 'unknown', I know these aren't implemented
- return encrypted;
- } else {
- qWarning()
- << "QSslKey: Unsupported encryption scheme OID:" << encryptionScheme
- << "\nFile a bugreport to Qt (include the line above).";
- return encrypted;
- }
-
- if (!data.initialized) {
- // something went wrong, return
- return encrypted;
- }
-
- QByteArray decryptedKey = decrypt(data.cipher, items[1].value(), data.key, data.iv);
- // The data is still wrapped in a octet string, so let's unwrap it
- QAsn1Element decryptedKeyElement(QAsn1Element::ElementType::OctetStringType, decryptedKey);
- return decryptedKeyElement.value();
-}
diff --git a/src/network/ssl/qsslkey_schannel.cpp b/src/network/ssl/qsslkey_schannel.cpp
deleted file mode 100644
index 1e21d123f4..0000000000
--- a/src/network/ssl/qsslkey_schannel.cpp
+++ /dev/null
@@ -1,178 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qssl_p.h"
-#include "qsslkey.h"
-#include "qsslkey_p.h"
-#include "qsslcertificate_p.h"
-
-#include <QtCore/qbytearray.h>
-#include <QtCore/qscopeguard.h>
-
-QT_BEGIN_NAMESPACE
-
-namespace {
-const wchar_t *getName(QSslKeyPrivate::Cipher cipher)
-{
- switch (cipher) {
- case QSslKeyPrivate::Cipher::DesCbc:
- return BCRYPT_DES_ALGORITHM;
- case QSslKeyPrivate::Cipher::DesEde3Cbc:
- return BCRYPT_3DES_ALGORITHM;
- case QSslKeyPrivate::Cipher::Rc2Cbc:
- return BCRYPT_RC2_ALGORITHM;
- case QSslKeyPrivate::Cipher::Aes128Cbc:
- case QSslKeyPrivate::Cipher::Aes192Cbc:
- case QSslKeyPrivate::Cipher::Aes256Cbc:
- return BCRYPT_AES_ALGORITHM;
- }
- Q_UNREACHABLE();
-}
-
-BCRYPT_ALG_HANDLE getHandle(QSslKeyPrivate::Cipher cipher)
-{
- BCRYPT_ALG_HANDLE handle;
- NTSTATUS status = BCryptOpenAlgorithmProvider(
- &handle, // phAlgorithm
- getName(cipher), // pszAlgId
- nullptr, // pszImplementation
- 0 // dwFlags
- );
- if (status < 0) {
- qCWarning(lcSsl, "Failed to open algorithm handle (%ld)!", status);
- return nullptr;
- }
-
- return handle;
-}
-
-BCRYPT_KEY_HANDLE generateSymmetricKey(BCRYPT_ALG_HANDLE handle,
- const QByteArray &key)
-{
- BCRYPT_KEY_HANDLE keyHandle;
- NTSTATUS status = BCryptGenerateSymmetricKey(
- handle, // hAlgorithm
- &keyHandle, // phKey
- nullptr, // pbKeyObject (can ignore)
- 0, // cbKeyObject (also ignoring)
- reinterpret_cast<unsigned char *>(const_cast<char *>(key.data())), // pbSecret
- ULONG(key.length()), // cbSecret
- 0 // dwFlags
- );
- if (status < 0) {
- qCWarning(lcSsl, "Failed to generate symmetric key (%ld)!", status);
- return nullptr;
- }
-
- status = BCryptSetProperty(
- keyHandle, // hObject
- BCRYPT_CHAINING_MODE, // pszProperty
- reinterpret_cast<UCHAR *>(const_cast<wchar_t *>(BCRYPT_CHAIN_MODE_CBC)), // pbInput
- ARRAYSIZE(BCRYPT_CHAIN_MODE_CBC), // cbInput
- 0 // dwFlags
- );
- if (status < 0) {
- BCryptDestroyKey(keyHandle);
- qCWarning(lcSsl, "Failed to change the symmetric key's chaining mode (%ld)!", status);
- return nullptr;
- }
- return keyHandle;
-}
-
-QByteArray doCrypt(QSslKeyPrivate::Cipher cipher, const QByteArray &data, const QByteArray &key,
- const QByteArray &iv, bool encrypt)
-{
- BCRYPT_ALG_HANDLE handle = getHandle(cipher);
- if (!handle)
- return {};
- auto handleDealloc = qScopeGuard([&handle]() {
- BCryptCloseAlgorithmProvider(handle, 0);
- });
-
- BCRYPT_KEY_HANDLE keyHandle = generateSymmetricKey(handle, key);
- if (!keyHandle)
- return {};
- auto keyHandleDealloc = qScopeGuard([&keyHandle]() {
- BCryptDestroyKey(keyHandle);
- });
-
- QByteArray ivCopy = iv; // This gets modified, so we take a copy
-
- ULONG sizeNeeded = 0;
- QVarLengthArray<unsigned char> output;
- auto cryptFunction = encrypt ? BCryptEncrypt : BCryptDecrypt;
- for (int i = 0; i < 2; i++) {
- output.resize(int(sizeNeeded));
- auto input = reinterpret_cast<unsigned char *>(const_cast<char *>(data.data()));
- // Need to call it twice because the first iteration lets us know the size needed.
- NTSTATUS status = cryptFunction(
- keyHandle, // hKey
- input, // pbInput
- ULONG(data.length()), // cbInput
- nullptr, // pPaddingInfo
- reinterpret_cast<unsigned char *>(ivCopy.data()), // pbIV
- ULONG(ivCopy.length()), // cbIV
- sizeNeeded ? output.data() : nullptr, // pbOutput
- ULONG(output.length()), // cbOutput
- &sizeNeeded, // pcbResult
- BCRYPT_BLOCK_PADDING // dwFlags
- );
- if (status < 0) {
- qCWarning(lcSsl, "%s failed (%ld)!", encrypt ? "Encrypt" : "Decrypt", status);
- return {};
- }
- }
-
- return QByteArray(reinterpret_cast<const char *>(output.constData()), int(sizeNeeded));
-}
-} // anonymous namespace
-
-QByteArray QSslKeyPrivate::decrypt(Cipher cipher, const QByteArray &data, const QByteArray &key,
- const QByteArray &iv)
-{
- return doCrypt(cipher, data, key, iv, false);
-}
-
-QByteArray QSslKeyPrivate::encrypt(Cipher cipher, const QByteArray &data, const QByteArray &key,
- const QByteArray &iv)
-{
- return doCrypt(cipher, data, key, iv, true);
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslpresharedkeyauthenticator.cpp b/src/network/ssl/qsslpresharedkeyauthenticator.cpp
index ed6dbb87cf..0045a83bea 100644
--- a/src/network/ssl/qsslpresharedkeyauthenticator.cpp
+++ b/src/network/ssl/qsslpresharedkeyauthenticator.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Governikus GmbH & Co. KG.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2014 Governikus GmbH & Co. KG.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qsslpresharedkeyauthenticator.h"
#include "qsslpresharedkeyauthenticator_p.h"
@@ -44,6 +8,9 @@
QT_BEGIN_NAMESPACE
+QT_IMPL_METATYPE_EXTERN(QSslPreSharedKeyAuthenticator)
+QT_IMPL_METATYPE_EXTERN_TAGGED(QSslPreSharedKeyAuthenticator*, QSslPreSharedKeyAuthenticator_ptr)
+
/*!
\internal
*/
@@ -240,35 +207,36 @@ int QSslPreSharedKeyAuthenticator::maximumPreSharedKeyLength() const
}
/*!
- \relates QSslPreSharedKeyAuthenticator
+ \fn bool QSslPreSharedKeyAuthenticator::operator==(const QSslPreSharedKeyAuthenticator &lhs, const QSslPreSharedKeyAuthenticator &rhs)
\since 5.5
- Returns true if the authenticator object \a lhs is equal to \a rhs; false
- otherwise.
+ Returns \c true if the authenticator object \a lhs is equal to \a rhs;
+ \c false otherwise.
Two authenticator objects are equal if and only if they have the same
identity hint, identity, pre shared key, maximum length for the identity
and maximum length for the pre shared key.
-
*/
-bool operator==(const QSslPreSharedKeyAuthenticator &lhs, const QSslPreSharedKeyAuthenticator &rhs)
-{
- return ((lhs.d == rhs.d) ||
- (lhs.d->identityHint == rhs.d->identityHint &&
- lhs.d->identity == rhs.d->identity &&
- lhs.d->maximumIdentityLength == rhs.d->maximumIdentityLength &&
- lhs.d->preSharedKey == rhs.d->preSharedKey &&
- lhs.d->maximumPreSharedKeyLength == rhs.d->maximumPreSharedKeyLength));
-}
/*!
- \fn bool operator!=(const QSslPreSharedKeyAuthenticator &lhs, const QSslPreSharedKeyAuthenticator &rhs)
- \relates QSslPreSharedKeyAuthenticator
+ \fn bool QSslPreSharedKeyAuthenticator::operator!=(const QSslPreSharedKeyAuthenticator &lhs, const QSslPreSharedKeyAuthenticator &rhs)
\since 5.5
- Returns true if the authenticator object \a lhs is different than \a rhs;
- false otherwise.
+ Returns \c true if the authenticator object \a lhs is not equal to \a rhs;
+ \c false otherwise.
+*/
+/*!
+ \internal
*/
+bool QSslPreSharedKeyAuthenticator::isEqual(const QSslPreSharedKeyAuthenticator &other) const
+{
+ return ((d == other.d) ||
+ (d->identityHint == other.d->identityHint &&
+ d->identity == other.d->identity &&
+ d->maximumIdentityLength == other.d->maximumIdentityLength &&
+ d->preSharedKey == other.d->preSharedKey &&
+ d->maximumPreSharedKeyLength == other.d->maximumPreSharedKeyLength));
+}
QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslpresharedkeyauthenticator.h b/src/network/ssl/qsslpresharedkeyauthenticator.h
index 5d714dc34e..a3912406d3 100644
--- a/src/network/ssl/qsslpresharedkeyauthenticator.h
+++ b/src/network/ssl/qsslpresharedkeyauthenticator.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Governikus GmbH & Co. KG.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2014 Governikus GmbH & Co. KG.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSSLPRESHAREDKEYAUTHENTICATOR_H
#define QSSLPRESHAREDKEYAUTHENTICATOR_H
@@ -50,9 +14,9 @@ QT_REQUIRE_CONFIG(ssl);
QT_BEGIN_NAMESPACE
class QSslPreSharedKeyAuthenticatorPrivate;
-
class QSslPreSharedKeyAuthenticator
{
+ Q_GADGET_EXPORT(Q_NETWORK_EXPORT)
public:
Q_NETWORK_EXPORT QSslPreSharedKeyAuthenticator();
Q_NETWORK_EXPORT ~QSslPreSharedKeyAuthenticator();
@@ -61,7 +25,7 @@ public:
QSslPreSharedKeyAuthenticator &operator=(QSslPreSharedKeyAuthenticator &&other) noexcept { swap(other); return *this; }
- void swap(QSslPreSharedKeyAuthenticator &other) noexcept { qSwap(d, other.d); }
+ void swap(QSslPreSharedKeyAuthenticator &other) noexcept { d.swap(other.d); }
Q_NETWORK_EXPORT QByteArray identityHint() const;
@@ -74,23 +38,24 @@ public:
Q_NETWORK_EXPORT int maximumPreSharedKeyLength() const;
private:
- friend Q_NETWORK_EXPORT bool operator==(const QSslPreSharedKeyAuthenticator &lhs, const QSslPreSharedKeyAuthenticator &rhs);
- friend class QSslSocketBackendPrivate;
- friend class QDtlsPrivateOpenSSL;
+ Q_NETWORK_EXPORT bool isEqual(const QSslPreSharedKeyAuthenticator &other) const;
+
+ friend class QTlsBackend;
+
+ friend bool operator==(const QSslPreSharedKeyAuthenticator &lhs, const QSslPreSharedKeyAuthenticator &rhs)
+ { return lhs.isEqual(rhs); }
+ friend bool operator!=(const QSslPreSharedKeyAuthenticator &lhs, const QSslPreSharedKeyAuthenticator &rhs)
+ { return !lhs.isEqual(rhs); }
QSharedDataPointer<QSslPreSharedKeyAuthenticatorPrivate> d;
};
-inline bool operator!=(const QSslPreSharedKeyAuthenticator &lhs, const QSslPreSharedKeyAuthenticator &rhs)
-{
- return !operator==(lhs, rhs);
-}
Q_DECLARE_SHARED(QSslPreSharedKeyAuthenticator)
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QSslPreSharedKeyAuthenticator)
-Q_DECLARE_METATYPE(QSslPreSharedKeyAuthenticator*)
+QT_DECL_METATYPE_EXTERN(QSslPreSharedKeyAuthenticator, Q_NETWORK_EXPORT)
+QT_DECL_METATYPE_EXTERN_TAGGED(QSslPreSharedKeyAuthenticator*, QSslPreSharedKeyAuthenticator_ptr, Q_NETWORK_EXPORT)
#endif // QSSLPRESHAREDKEYAUTHENTICATOR_H
diff --git a/src/network/ssl/qsslpresharedkeyauthenticator_p.h b/src/network/ssl/qsslpresharedkeyauthenticator_p.h
index e5566c3b3c..0075579074 100644
--- a/src/network/ssl/qsslpresharedkeyauthenticator_p.h
+++ b/src/network/ssl/qsslpresharedkeyauthenticator_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Governikus GmbH & Co. KG.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2014 Governikus GmbH & Co. KG.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSSLPRESHAREDKEYAUTHENTICATOR_P_H
#define QSSLPRESHAREDKEYAUTHENTICATOR_P_H
diff --git a/src/network/ssl/qsslserver.cpp b/src/network/ssl/qsslserver.cpp
new file mode 100644
index 0000000000..40a6a6f526
--- /dev/null
+++ b/src/network/ssl/qsslserver.cpp
@@ -0,0 +1,412 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2016 Kurt Pattyn <pattyn.kurt@gmail.com>.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+/*!
+ \class QSslServer
+
+ \ingroup network
+ \ingroup ssl
+ \inmodule QtNetwork
+ \since 6.4
+
+ \brief Implements an encrypted, secure TCP server over TLS.
+
+ Class to use in place of QTcpServer to implement TCP server using
+ Transport Layer Security (TLS).
+
+ To configure the secure handshake settings, use the applicable setter
+ functions on a QSslConfiguration object, and then use it as an argument
+ to the setSslConfiguration() function. All following incoming
+ connections handled will use these settings.
+
+ To start listening to incoming connections use the listen() function
+ inherited from QTcpServer. Other settings can be configured by using the
+ setter functions inherited from the QTcpServer class.
+
+ Connect to the signals of this class to respond to the incoming connection
+ attempts. They are the same as the signals on QSslSocket, but also
+ passes a pointer to the socket in question.
+
+ When responding to the pendingConnectionAvailable() signal, use the
+ nextPendingConnection() function to fetch the next incoming connection and
+ take it out of the pending connection queue. The QSslSocket is a child of
+ the QSslServer and will be deleted when the QSslServer is deleted. It is
+ still a good idea to destroy the object explicitly when you are done
+ with it, to avoid wasting memory.
+
+ \sa QTcpServer, QSslConfiguration, QSslSocket
+*/
+
+/*!
+ \fn void QSslServer::peerVerifyError(QSslSocket *socket, const QSslError &error)
+
+ QSslServer can emit this signal several times during the SSL handshake,
+ before encryption has been established, to indicate that an error has
+ occurred while establishing the identity of the peer. The \a error is
+ usually an indication that \a socket is unable to securely identify the
+ peer.
+
+ This signal provides you with an early indication when something's wrong.
+ By connecting to this signal, you can manually choose to tear down the
+ connection from inside the connected slot before the handshake has
+ completed. If no action is taken, QSslServer will proceed to emitting
+ sslErrors().
+
+ \sa sslErrors()
+*/
+
+/*!
+ \fn void QSslServer::sslErrors(QSslSocket *socket, const QList<QSslError> &errors);
+
+ QSslServer emits this signal after the SSL handshake to indicate that one
+ or more errors have occurred while establishing the identity of the
+ peer. The errors are usually an indication that \a socket is unable to
+ securely identify the peer. Unless any action is taken, the connection
+ will be dropped after this signal has been emitted.
+
+ If you want to continue connecting despite the errors that have occurred,
+ you must call QSslSocket::ignoreSslErrors() from inside a slot connected to
+ this signal. If you need to access the error list at a later point, you
+ can call sslHandshakeErrors().
+
+ \a errors contains one or more errors that prevent QSslSocket from
+ verifying the identity of the peer.
+
+ \note You cannot use Qt::QueuedConnection when connecting to this signal,
+ or calling QSslSocket::ignoreSslErrors() will have no effect.
+
+ \sa peerVerifyError()
+*/
+
+/*!
+ \fn void QSslServer::errorOccurred(QSslSocket *socket, QAbstractSocket::SocketError socketError)
+
+ This signal is emitted after an error occurred during handshake. The
+ \a socketError parameter describes the type of error that occurred.
+
+ The \a socket is automatically deleted after this signal is emitted if the
+ socket handshake has not reached encrypted state. But if the \a socket is
+ successfully encrypted, it is inserted into the QSslServer's pending
+ connections queue. When the user has called
+ QTcpServer::nextPendingConnection() it is the user's responsibility to
+ destroy the \a socket or the \a socket will not be destroyed until the
+ QSslServer object is destroyed. If an error occurs on a \a socket after
+ it has been inserted into the pending connections queue, this signal
+ will not be emitted, and the \a socket will not be removed or destroyed.
+
+ \note You cannot use Qt::QueuedConnection when connecting to this signal,
+ or the \a socket will have been already destroyed when the signal is
+ handled.
+
+ \sa QSslSocket::error(), errorString()
+*/
+
+/*!
+ \fn void QSslServer::preSharedKeyAuthenticationRequired(QSslSocket *socket,
+ QSslPreSharedKeyAuthenticator *authenticator)
+
+ QSslServer emits this signal when \a socket negotiates a PSK ciphersuite,
+ and therefore PSK authentication is then required.
+
+ When using PSK, the server must supply a valid identity and a valid pre
+ shared key, in order for the SSL handshake to continue.
+ Applications can provide this information in a slot connected to this
+ signal, by filling in the passed \a authenticator object according to their
+ needs.
+
+ \note Ignoring this signal, or failing to provide the required credentials,
+ will cause the handshake to fail, and therefore the connection to be aborted.
+
+ \note The \a authenticator object is owned by the \a socket and must not be
+ deleted by the application.
+
+ \sa QSslPreSharedKeyAuthenticator
+*/
+
+/*!
+ \fn void QSslServer::alertSent(QSslSocket *socket, QSsl::AlertLevel level, QSsl::AlertType type,
+ const QString &description)
+
+ QSslServer emits this signal if an alert message was sent from \a socket
+ to a peer. \a level describes if it was a warning or a fatal error.
+ \a type gives the code of the alert message. When a textual description
+ of the alert message is available, it is supplied in \a description.
+
+ \note This signal is mostly informational and can be used for debugging
+ purposes, normally it does not require any actions from the application.
+ \note Not all backends support this functionality.
+
+ \sa alertReceived(), QSsl::AlertLevel, QSsl::AlertType
+*/
+
+/*!
+ \fn void QSslServer::alertReceived(QSslSocket *socket, QSsl::AlertLevel level, QSsl::AlertType
+ type, const QString &description)
+
+ QSslServer emits this signal if an alert message was received by the
+ \a socket from a peer. \a level tells if the alert was fatal or it was a
+ warning. \a type is the code explaining why the alert was sent.
+ When a textual description of the alert message is available, it is
+ supplied in \a description.
+
+ \note The signal is mostly for informational and debugging purposes and does not
+ require any handling in the application. If the alert was fatal, underlying
+ backend will handle it and close the connection.
+ \note Not all backends support this functionality.
+
+ \sa alertSent(), QSsl::AlertLevel, QSsl::AlertType
+*/
+
+/*!
+ \fn void QSslServer::handshakeInterruptedOnError(QSslSocket *socket, const QSslError &error)
+
+ QSslServer emits this signal if a certificate verification error was found
+ by \a socket and if early error reporting was enabled in QSslConfiguration.
+ An application is expected to inspect the \a error and decide if it wants
+ to continue the handshake, or abort it and send an alert message to the
+ peer. The signal-slot connection must be direct.
+
+ \sa QSslSocket::continueInterruptedHandshake(), sslErrors(),
+ QSslConfiguration::setHandshakeMustInterruptOnError()
+*/
+
+/*!
+ \fn void QSslServer::startedEncryptionHandshake(QSslSocket *socket)
+
+ This signal is emitted when the client, connected to \a socket,
+ initiates the TLS handshake.
+*/
+
+#include "qsslserver.h"
+#include "qsslserver_p.h"
+
+#include <QtNetwork/QSslSocket>
+#include <QtNetwork/QSslCipher>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \internal
+*/
+QSslServerPrivate::QSslServerPrivate() :
+ sslConfiguration(QSslConfiguration::defaultConfiguration())
+{
+}
+
+/*!
+ Constructs a new QSslServer with the given \a parent.
+*/
+QSslServer::QSslServer(QObject *parent) :
+ QTcpServer(QAbstractSocket::TcpSocket, *new QSslServerPrivate, parent)
+{
+}
+
+/*!
+ Destroys the QSslServer.
+
+ All open connections are closed.
+*/
+QSslServer::~QSslServer()
+{
+}
+
+/*!
+ Sets the \a sslConfiguration to use for all following incoming connections.
+
+ This must be called before listen() to ensure that the desired
+ configuration was in use during all handshakes.
+
+ \sa QSslSocket::setSslConfiguration()
+*/
+void QSslServer::setSslConfiguration(const QSslConfiguration &sslConfiguration)
+{
+ Q_D(QSslServer);
+ d->sslConfiguration = sslConfiguration;
+}
+
+/*!
+ Returns the current ssl configuration.
+*/
+QSslConfiguration QSslServer::sslConfiguration() const
+{
+ const Q_D(QSslServer);
+ return d->sslConfiguration;
+}
+
+/*!
+ Sets the \a timeout to use for all incoming handshakes, in milliseconds.
+
+ This is relevant in the scenario where a client, whether malicious or
+ accidental, connects to the server but makes no attempt at communicating or
+ initiating a handshake. QSslServer will then automatically end the
+ connection after \a timeout milliseconds have elapsed.
+
+ By default the timeout is 5000 milliseconds (5 seconds).
+
+ \note The underlying TLS framework may have their own timeout logic now or
+ in the future, this function does not affect that.
+
+ \note The \a timeout passed to this function will only apply to \e{new}
+ connections. If a client is already connected it will use the timeout which
+ was set when it connected.
+
+ \sa handshakeTimeout()
+*/
+void QSslServer::setHandshakeTimeout(int timeout)
+{
+ Q_D(QSslServer);
+ d->handshakeTimeout = timeout;
+}
+
+/*!
+ Returns the currently configured handshake timeout.
+
+ \sa setHandshakeTimeout()
+*/
+int QSslServer::handshakeTimeout() const
+{
+ const Q_D(QSslServer);
+ return d->handshakeTimeout;
+}
+
+/*!
+ Called when a new connection is established.
+
+ Converts \a socket to a QSslSocket.
+
+ \reimp
+*/
+void QSslServer::incomingConnection(qintptr socket)
+{
+ QSslSocket *pSslSocket = new QSslSocket(this);
+
+ pSslSocket->setSslConfiguration(sslConfiguration());
+
+ if (Q_LIKELY(pSslSocket->setSocketDescriptor(socket))) {
+ connect(pSslSocket, &QSslSocket::peerVerifyError, this,
+ [this, pSslSocket](const QSslError &error) {
+ Q_EMIT peerVerifyError(pSslSocket, error);
+ });
+ connect(pSslSocket, &QSslSocket::sslErrors, this,
+ [this, pSslSocket](const QList<QSslError> &errors) {
+ Q_EMIT sslErrors(pSslSocket, errors);
+ });
+ connect(pSslSocket, &QAbstractSocket::errorOccurred, this,
+ [this, pSslSocket](QAbstractSocket::SocketError error) {
+ Q_EMIT errorOccurred(pSslSocket, error);
+ if (!pSslSocket->isEncrypted())
+ pSslSocket->deleteLater();
+ });
+ connect(pSslSocket, &QSslSocket::encrypted, this, [this, pSslSocket]() {
+ Q_D(QSslServer);
+ d->removeSocketData(quintptr(pSslSocket));
+ pSslSocket->disconnect(this);
+ addPendingConnection(pSslSocket);
+ });
+ connect(pSslSocket, &QSslSocket::preSharedKeyAuthenticationRequired, this,
+ [this, pSslSocket](QSslPreSharedKeyAuthenticator *authenticator) {
+ Q_EMIT preSharedKeyAuthenticationRequired(pSslSocket, authenticator);
+ });
+ connect(pSslSocket, &QSslSocket::alertSent, this,
+ [this, pSslSocket](QSsl::AlertLevel level, QSsl::AlertType type,
+ const QString &description) {
+ Q_EMIT alertSent(pSslSocket, level, type, description);
+ });
+ connect(pSslSocket, &QSslSocket::alertReceived, this,
+ [this, pSslSocket](QSsl::AlertLevel level, QSsl::AlertType type,
+ const QString &description) {
+ Q_EMIT alertReceived(pSslSocket, level, type, description);
+ });
+ connect(pSslSocket, &QSslSocket::handshakeInterruptedOnError, this,
+ [this, pSslSocket](const QSslError &error) {
+ Q_EMIT handshakeInterruptedOnError(pSslSocket, error);
+ });
+
+ d_func()->initializeHandshakeProcess(pSslSocket);
+ }
+}
+
+void QSslServerPrivate::initializeHandshakeProcess(QSslSocket *socket)
+{
+ Q_Q(QSslServer);
+ QMetaObject::Connection readyRead = QObject::connect(
+ socket, &QSslSocket::readyRead, q, [this]() { checkClientHelloAndContinue(); });
+
+ QMetaObject::Connection destroyed =
+ QObject::connect(socket, &QSslSocket::destroyed, q, [this](QObject *obj) {
+ // This cast is not safe to use since the socket is inside the
+ // QObject dtor, but we only use the pointer value!
+ removeSocketData(quintptr(obj));
+ });
+ auto it = socketData.emplace(quintptr(socket), readyRead, destroyed, std::make_shared<QTimer>());
+ it->timeoutTimer->setSingleShot(true);
+ it->timeoutTimer->callOnTimeout(q, [this, socket]() { handleHandshakeTimedOut(socket); });
+ it->timeoutTimer->setInterval(handshakeTimeout);
+ it->timeoutTimer->start();
+}
+
+// This function may be called while in the socket's QObject dtor, __never__ use
+// the socket for anything other than a lookup!
+void QSslServerPrivate::removeSocketData(quintptr socket)
+{
+ auto it = socketData.find(socket);
+ if (it != socketData.end()) {
+ it->disconnectSignals();
+ socketData.erase(it);
+ }
+}
+
+int QSslServerPrivate::totalPendingConnections() const
+{
+ // max pending connections is int, so this cannot exceed that
+ return QTcpServerPrivate::totalPendingConnections() + int(socketData.size());
+}
+
+void QSslServerPrivate::checkClientHelloAndContinue()
+{
+ Q_Q(QSslServer);
+ QSslSocket *socket = qobject_cast<QSslSocket *>(q->sender());
+ if (Q_UNLIKELY(!socket) || socket->bytesAvailable() <= 0)
+ return;
+
+ char byte = '\0';
+ if (socket->peek(&byte, 1) != 1) {
+ socket->deleteLater();
+ return;
+ }
+
+ auto it = socketData.find(quintptr(socket));
+ const bool foundData = it != socketData.end();
+ if (foundData && it->readyReadConnection)
+ QObject::disconnect(std::exchange(it->readyReadConnection, {}));
+
+ constexpr char CLIENT_HELLO = 0x16;
+ if (byte != CLIENT_HELLO) {
+ socket->disconnectFromHost();
+ socket->deleteLater();
+ return;
+ }
+
+ // Be nice and restart the timeout timer since some progress was made
+ if (foundData)
+ it->timeoutTimer->start();
+
+ socket->startServerEncryption();
+ Q_EMIT q->startedEncryptionHandshake(socket);
+}
+
+void QSslServerPrivate::handleHandshakeTimedOut(QSslSocket *socket)
+{
+ Q_Q(QSslServer);
+ removeSocketData(quintptr(socket));
+ socket->disconnectFromHost();
+ Q_EMIT q->errorOccurred(socket, QAbstractSocket::SocketTimeoutError);
+ socket->deleteLater();
+ if (!socketEngine->isReadNotificationEnabled() && totalPendingConnections() < maxConnections)
+ q->resumeAccepting();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qsslserver.cpp"
diff --git a/src/network/ssl/qsslserver.h b/src/network/ssl/qsslserver.h
new file mode 100644
index 0000000000..aaa0f43c35
--- /dev/null
+++ b/src/network/ssl/qsslserver.h
@@ -0,0 +1,61 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2016 Kurt Pattyn <pattyn.kurt@gmail.com>.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QSSLSERVER_H
+#define QSSLSERVER_H
+
+#include <QtNetwork/QTcpServer>
+
+QT_REQUIRE_CONFIG(ssl);
+
+#include <QtNetwork/QSslError>
+#include <QtNetwork/QSslConfiguration>
+#include <QtNetwork/QSslPreSharedKeyAuthenticator>
+#include <QtNetwork/QSslSocket>
+
+#include <QtCore/QList>
+
+QT_BEGIN_NAMESPACE
+
+class QSslSocket;
+class QSslServerPrivate;
+
+class Q_NETWORK_EXPORT QSslServer : public QTcpServer
+{
+ Q_OBJECT
+ Q_DISABLE_COPY_MOVE(QSslServer)
+
+public:
+ explicit QSslServer(QObject *parent = nullptr);
+ ~QSslServer() override;
+
+ void setSslConfiguration(const QSslConfiguration &sslConfiguration);
+ QSslConfiguration sslConfiguration() const;
+
+ void setHandshakeTimeout(int timeout);
+ int handshakeTimeout() const;
+
+Q_SIGNALS:
+ void sslErrors(QSslSocket *socket, const QList<QSslError> &errors);
+ void peerVerifyError(QSslSocket *socket, const QSslError &error);
+ void errorOccurred(QSslSocket *socket, QAbstractSocket::SocketError error);
+ void preSharedKeyAuthenticationRequired(QSslSocket *socket,
+ QSslPreSharedKeyAuthenticator *authenticator);
+ void alertSent(QSslSocket *socket, QSsl::AlertLevel level,
+ QSsl::AlertType type, const QString &description);
+ void alertReceived(QSslSocket *socket, QSsl::AlertLevel level,
+ QSsl::AlertType type, const QString &description);
+ void handshakeInterruptedOnError(QSslSocket *socket, const QSslError &error);
+ void startedEncryptionHandshake(QSslSocket *socket);
+
+protected:
+ void incomingConnection(qintptr socket) override;
+
+private:
+ Q_DECLARE_PRIVATE(QSslServer)
+};
+
+QT_END_NAMESPACE
+
+#endif // QSSLSERVER_H
diff --git a/src/network/ssl/qsslserver_p.h b/src/network/ssl/qsslserver_p.h
new file mode 100644
index 0000000000..1b90d35d48
--- /dev/null
+++ b/src/network/ssl/qsslserver_p.h
@@ -0,0 +1,71 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2016 Kurt Pattyn <pattyn.kurt@gmail.com>.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QSSLSERVER_P_H
+#define QSSLSERVER_P_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.
+//
+
+#include <QtNetwork/private/qtnetworkglobal_p.h>
+
+#include <QtCore/qhash.h>
+#include <QtCore/qtimer.h>
+
+#include <QtNetwork/QSslConfiguration>
+#include <QtNetwork/private/qtcpserver_p.h>
+#include <utility>
+
+QT_BEGIN_NAMESPACE
+
+class Q_NETWORK_EXPORT QSslServerPrivate : public QTcpServerPrivate
+{
+ static constexpr int DefaultHandshakeTimeout = 5'000; // 5 seconds
+public:
+ Q_DECLARE_PUBLIC(QSslServer)
+
+ QSslServerPrivate();
+ void checkClientHelloAndContinue();
+ void initializeHandshakeProcess(QSslSocket *socket);
+ void removeSocketData(quintptr socket);
+ void handleHandshakeTimedOut(QSslSocket *socket);
+ int totalPendingConnections() const override;
+
+ struct SocketData {
+ QMetaObject::Connection readyReadConnection;
+ QMetaObject::Connection destroyedConnection;
+ std::shared_ptr<QTimer> timeoutTimer; // shared_ptr because QHash demands copying
+
+ SocketData(QMetaObject::Connection readyRead, QMetaObject::Connection destroyed,
+ std::shared_ptr<QTimer> &&timer)
+ : readyReadConnection(readyRead),
+ destroyedConnection(destroyed),
+ timeoutTimer(std::move(timer))
+ {
+ }
+
+ void disconnectSignals()
+ {
+ QObject::disconnect(std::exchange(readyReadConnection, {}));
+ QObject::disconnect(std::exchange(destroyedConnection, {}));
+ }
+ };
+ QHash<quintptr, SocketData> socketData;
+
+ QSslConfiguration sslConfiguration;
+ int handshakeTimeout = DefaultHandshakeTimeout;
+};
+
+
+QT_END_NAMESPACE
+
+#endif // QSSLSERVER_P_H
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
index c5444b139e..395394d432 100644
--- a/src/network/ssl/qsslsocket.cpp
+++ b/src/network/ssl/qsslsocket.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2014 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//#define QSSLSOCKET_DEBUG
@@ -54,10 +18,10 @@
QSslSocket establishes a secure, encrypted TCP connection you can
use for transmitting encrypted data. It can operate in both client
- and server mode, and it supports modern SSL protocols, including
- SSL 3 and TLS 1.2. By default, QSslSocket uses only SSL protocols
+ and server mode, and it supports modern TLS protocols, including
+ TLS 1.3. By default, QSslSocket uses only TLS protocols
which are considered to be secure (QSsl::SecureProtocols), but you can
- change the SSL protocol by calling setProtocol() as long as you do
+ change the TLS protocol by calling setProtocol() as long as you do
it before the handshake has started.
SSL encryption operates on top of the existing TCP stream after
@@ -133,8 +97,7 @@
\list
\li The socket's cryptographic cipher suite can be customized before
- the handshake phase with QSslConfiguration::setCiphers()
- and QSslConfiguration::setDefaultCiphers().
+ the handshake phase with QSslConfiguration::setCiphers().
\li The socket's local certificate and private key can be customized
before the handshake phase with setLocalCertificate() and
setPrivateKey().
@@ -188,7 +151,7 @@
behavior is identical to QTcpSocket.
\value SslClientMode The socket is a client-side SSL socket.
- It is either alreayd encrypted, or it is in the SSL handshake
+ It is either already encrypted, or it is in the SSL handshake
phase (see QSslSocket::isEncrypted()).
\value SslServerMode The socket is a server-side SSL socket.
@@ -385,16 +348,9 @@
#include "qsslsocket.h"
#include "qsslcipher.h"
#include "qocspresponse.h"
-#ifndef QT_NO_OPENSSL
-#include "qsslsocket_openssl_p.h"
-#endif
-#ifdef QT_SECURETRANSPORT
-#include "qsslsocket_mac_p.h"
-#endif
-#if QT_CONFIG(schannel)
-#include "qsslsocket_schannel_p.h"
-#endif
+#include "qtlsbackend_p.h"
#include "qsslconfiguration_p.h"
+#include "qsslsocket_p.h"
#include <QtCore/qdebug.h>
#include <QtCore/qdir.h>
@@ -406,6 +362,14 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
+#ifdef Q_OS_VXWORKS
+constexpr auto isVxworks = true;
+#else
+constexpr auto isVxworks = false;
+#endif
+
class QSslSocketGlobalData
{
public:
@@ -432,7 +396,7 @@ Q_GLOBAL_STATIC(QSslSocketGlobalData, globalData)
set to the one returned by the static method defaultCiphers().
*/
QSslSocket::QSslSocket(QObject *parent)
- : QTcpSocket(*new QSslSocketBackendPrivate, parent)
+ : QTcpSocket(*new QSslSocketPrivate, parent)
{
Q_D(QSslSocket);
#ifdef QSSLSOCKET_DEBUG
@@ -902,7 +866,8 @@ void QSslSocket::close()
// On Windows, CertGetCertificateChain is probably still doing its
// job, if the socket is re-used, we want to ignore its reported
// root CA.
- d->caToFetch = QSslCertificate{};
+ if (auto *backend = d->backend.get())
+ backend->cancelCAFetch();
if (!d->abortCalled && (encryptedBytesToWrite() || !d->writeBuffer.isEmpty()))
flush();
@@ -1209,7 +1174,9 @@ QSsl::SslProtocol QSslSocket::sessionProtocol() const
QList<QOcspResponse> QSslSocket::ocspResponses() const
{
Q_D(const QSslSocket);
- return d->ocspResponses;
+ if (const auto *backend = d->backend.get())
+ return backend->ocsps();
+ return {};
}
/*!
@@ -1484,7 +1451,9 @@ bool QSslSocket::waitForDisconnected(int msecs)
QList<QSslError> QSslSocket::sslHandshakeErrors() const
{
Q_D(const QSslSocket);
- return d->sslErrors;
+ if (const auto *backend = d->backend.get())
+ return backend->tlsErrors();
+ return {};
}
/*!
@@ -1501,12 +1470,14 @@ bool QSslSocket::supportsSsl()
\since 5.0
Returns the version number of the SSL library in use. Note that
this is the version of the library in use at run-time not compile
- time. If no SSL support is available then this will return an
- undefined value.
+ time. If no SSL support is available then this will return -1.
*/
long QSslSocket::sslLibraryVersionNumber()
{
- return QSslSocketPrivate::sslLibraryVersionNumber();
+ if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse())
+ return tlsBackend->tlsLibraryVersionNumber();
+
+ return -1;
}
/*!
@@ -1517,20 +1488,23 @@ long QSslSocket::sslLibraryVersionNumber()
*/
QString QSslSocket::sslLibraryVersionString()
{
- return QSslSocketPrivate::sslLibraryVersionString();
+ if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse())
+ return tlsBackend->tlsLibraryVersionString();
+ return {};
}
/*!
\since 5.4
Returns the version number of the SSL library in use at compile
- time. If no SSL support is available then this will return an
- undefined value.
+ time. If no SSL support is available then this will return -1.
\sa sslLibraryVersionNumber()
*/
long QSslSocket::sslLibraryBuildVersionNumber()
{
- return QSslSocketPrivate::sslLibraryBuildVersionNumber();
+ if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse())
+ return tlsBackend->tlsLibraryBuildVersionNumber();
+ return -1;
}
/*!
@@ -1543,7 +1517,166 @@ long QSslSocket::sslLibraryBuildVersionNumber()
*/
QString QSslSocket::sslLibraryBuildVersionString()
{
- return QSslSocketPrivate::sslLibraryBuildVersionString();
+ if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse())
+ return tlsBackend->tlsLibraryBuildVersionString();
+
+ return {};
+}
+
+/*!
+ \since 6.1
+ Returns the names of the currently available backends. These names
+ are in lower case, e.g. "openssl", "securetransport", "schannel"
+ (similar to the already existing feature names for TLS backends in Qt).
+
+ \sa activeBackend()
+*/
+QList<QString> QSslSocket::availableBackends()
+{
+ return QTlsBackend::availableBackendNames();
+}
+
+/*!
+ \since 6.1
+ Returns the name of the backend that QSslSocket and related classes
+ use. If the active backend was not set explicitly, this function
+ returns the name of a default backend that QSslSocket selects implicitly
+ from the list of available backends.
+
+ \note When selecting a default backend implicitly, QSslSocket prefers
+ the OpenSSL backend if available. If it's not available, the Schannel backend
+ is implicitly selected on Windows, and Secure Transport on Darwin platforms.
+ Failing these, if a custom TLS backend is found, it is used.
+ If no other backend is found, the "certificate only" backend is selected.
+ For more information about TLS plugins, please see
+ \l {Enabling and Disabling SSL Support when Building Qt from Source}.
+
+ \sa setActiveBackend(), availableBackends()
+*/
+QString QSslSocket::activeBackend()
+{
+ const QMutexLocker locker(&QSslSocketPrivate::backendMutex);
+
+ if (!QSslSocketPrivate::activeBackendName.size())
+ QSslSocketPrivate::activeBackendName = QTlsBackend::defaultBackendName();
+
+ return QSslSocketPrivate::activeBackendName;
+}
+
+/*!
+ \since 6.1
+ Returns true if a backend with name \a backendName was set as
+ active backend. \a backendName must be one of names returned
+ by availableBackends().
+
+ \note An application cannot mix different backends simultaneously.
+ This implies that a non-default backend must be selected prior
+ to any use of QSslSocket or related classes, e.g. QSslCertificate
+ or QSslKey.
+
+ \sa activeBackend(), availableBackends()
+*/
+bool QSslSocket::setActiveBackend(const QString &backendName)
+{
+ if (!backendName.size()) {
+ qCWarning(lcSsl, "Invalid parameter (backend name cannot be an empty string)");
+ return false;
+ }
+
+ QMutexLocker locker(&QSslSocketPrivate::backendMutex);
+ if (QSslSocketPrivate::tlsBackend) {
+ qCWarning(lcSsl) << "Cannot set backend named" << backendName
+ << "as active, another backend is already in use";
+ locker.unlock();
+ return activeBackend() == backendName;
+ }
+
+ if (!QTlsBackend::availableBackendNames().contains(backendName)) {
+ qCWarning(lcSsl) << "Cannot set unavailable backend named" << backendName
+ << "as active";
+ return false;
+ }
+
+ QSslSocketPrivate::activeBackendName = backendName;
+
+ return true;
+}
+
+/*!
+ \since 6.1
+ If a backend with name \a backendName is available, this function returns the
+ list of TLS protocol versions supported by this backend. An empty \a backendName
+ is understood as a query about the currently active backend. Otherwise, this
+ function returns an empty list.
+
+ \sa availableBackends(), activeBackend(), isProtocolSupported()
+*/
+QList<QSsl::SslProtocol> QSslSocket::supportedProtocols(const QString &backendName)
+{
+ return QTlsBackend::supportedProtocols(backendName.size() ? backendName : activeBackend());
+}
+
+/*!
+ \since 6.1
+ Returns true if \a protocol is supported by a backend named \a backendName. An empty
+ \a backendName is understood as a query about the currently active backend.
+
+ \sa supportedProtocols()
+*/
+bool QSslSocket::isProtocolSupported(QSsl::SslProtocol protocol, const QString &backendName)
+{
+ const auto versions = supportedProtocols(backendName);
+ return versions.contains(protocol);
+}
+
+/*!
+ \since 6.1
+ This function returns backend-specific classes implemented by the backend named
+ \a backendName. An empty \a backendName is understood as a query about the
+ currently active backend.
+
+ \sa QSsl::ImplementedClass, activeBackend(), isClassImplemented()
+*/
+QList<QSsl::ImplementedClass> QSslSocket::implementedClasses(const QString &backendName)
+{
+ return QTlsBackend::implementedClasses(backendName.size() ? backendName : activeBackend());
+}
+
+/*!
+ \since 6.1
+ Returns true if a class \a cl is implemented by the backend named \a backendName. An empty
+ \a backendName is understood as a query about the currently active backend.
+
+ \sa implementedClasses()
+*/
+
+bool QSslSocket::isClassImplemented(QSsl::ImplementedClass cl, const QString &backendName)
+{
+ return implementedClasses(backendName).contains(cl);
+}
+
+/*!
+ \since 6.1
+ This function returns features supported by a backend named \a backendName.
+ An empty \a backendName is understood as a query about the currently active backend.
+
+ \sa QSsl::SupportedFeature, activeBackend()
+*/
+QList<QSsl::SupportedFeature> QSslSocket::supportedFeatures(const QString &backendName)
+{
+ return QTlsBackend::supportedFeatures(backendName.size() ? backendName : activeBackend());
+}
+
+/*!
+ \since 6.1
+ Returns true if a feature \a ft is supported by a backend named \a backendName. An empty
+ \a backendName is understood as a query about the currently active backend.
+
+ \sa QSsl::SupportedFeature, supportedFeatures()
+*/
+bool QSslSocket::isFeatureSupported(QSsl::SupportedFeature ft, const QString &backendName)
+{
+ return supportedFeatures(backendName).contains(ft);
}
/*!
@@ -1705,7 +1838,8 @@ void QSslSocket::ignoreSslErrors(const QList<QSslError> &errors)
void QSslSocket::continueInterruptedHandshake()
{
Q_D(QSslSocket);
- d->handshakeInterrupted = false;
+ if (auto *backend = d->backend.get())
+ backend->enableHandshakeContinuation();
}
/*!
@@ -1762,7 +1896,8 @@ void QSslSocket::disconnectFromHost()
}
// Make sure we don't process any signal from the CA fetcher
// (Windows):
- d->caToFetch = QSslCertificate{};
+ if (auto *backend = d->backend.get())
+ backend->cancelCAFetch();
// Perhaps emit closing()
if (d->state != ClosingState) {
@@ -1798,7 +1933,7 @@ qint64 QSslSocket::readData(char *data, qint64 maxlen)
#endif
} else {
// possibly trigger another transmit() to decrypt more data from the socket
- if (d->plainSocket->bytesAvailable())
+ if (d->plainSocket->bytesAvailable() || d->hasUndecryptedData())
QMetaObject::invokeMethod(this, "_q_flushReadBuffer", Qt::QueuedConnection);
else if (d->state != QAbstractSocket::ConnectedState)
return maxlen ? qint64(-1) : qint64(0);
@@ -1830,6 +1965,8 @@ qint64 QSslSocket::writeData(const char *data, qint64 len)
return len;
}
+bool QSslSocketPrivate::s_loadRootCertsOnDemand = false;
+
/*!
\internal
*/
@@ -1838,7 +1975,6 @@ QSslSocketPrivate::QSslSocketPrivate()
, mode(QSslSocket::UnencryptedMode)
, autoStartHandshake(false)
, connectionEncrypted(false)
- , shutdown(false)
, ignoreAllSslErrors(false)
, readyReadEmittedPointer(nullptr)
, allowRootCertOnDemandLoading(true)
@@ -1847,6 +1983,21 @@ QSslSocketPrivate::QSslSocketPrivate()
, flushTriggered(false)
{
QSslConfigurationPrivate::deepCopyDefaultConfiguration(&configuration);
+ // If the global configuration doesn't allow root certificates to be loaded
+ // on demand then we have to disable it for this socket as well.
+ if (!configuration.allowRootCertOnDemandLoading)
+ allowRootCertOnDemandLoading = false;
+
+ const auto *tlsBackend = tlsBackendInUse();
+ if (!tlsBackend) {
+ qCWarning(lcSsl, "No TLS backend is available");
+ return;
+ }
+ backend.reset(tlsBackend->createTlsCryptograph());
+ if (!backend.get()) {
+ qCWarning(lcSsl) << "The backend named" << tlsBackend->backendName()
+ << "does not support TLS";
+ }
}
/*!
@@ -1859,28 +2010,54 @@ QSslSocketPrivate::~QSslSocketPrivate()
/*!
\internal
*/
+bool QSslSocketPrivate::supportsSsl()
+{
+ if (const auto *tlsBackend = tlsBackendInUse())
+ return tlsBackend->implementedClasses().contains(QSsl::ImplementedClass::Socket);
+ return false;
+}
+
+/*!
+ \internal
+
+ Declared static in QSslSocketPrivate, makes sure the SSL libraries have
+ been initialized.
+*/
+void QSslSocketPrivate::ensureInitialized()
+{
+ if (!supportsSsl())
+ return;
+
+ const auto *tlsBackend = tlsBackendInUse();
+ Q_ASSERT(tlsBackend);
+ tlsBackend->ensureInitialized();
+}
+
+/*!
+ \internal
+*/
void QSslSocketPrivate::init()
{
+ // TLSTODO: delete those data members.
mode = QSslSocket::UnencryptedMode;
autoStartHandshake = false;
connectionEncrypted = false;
ignoreAllSslErrors = false;
- shutdown = false;
abortCalled = false;
pendingClose = false;
flushTriggered = false;
- ocspResponses.clear();
- systemOrSslErrorDetected = false;
- // we don't want to clear the ignoreErrorsList, so
- // that it is possible setting it before connecting
-// ignoreErrorsList.clear();
+ // We don't want to clear the ignoreErrorsList, so
+ // that it is possible setting it before connecting.
buffer.clear();
writeBuffer.clear();
configuration.peerCertificate.clear();
configuration.peerCertificateChain.clear();
- fetchAuthorityInformation = false;
- caToFetch = QSslCertificate{};
+
+ if (backend.get()) {
+ Q_ASSERT(q_ptr);
+ backend->init(static_cast<QSslSocket *>(q_ptr), this);
+ }
}
/*!
@@ -1888,13 +2065,15 @@ void QSslSocketPrivate::init()
*/
bool QSslSocketPrivate::verifyProtocolSupported(const char *where)
{
- QLatin1String protocolName("DTLS");
+ auto protocolName = "DTLS"_L1;
switch (configuration.protocol) {
case QSsl::UnknownProtocol:
// UnknownProtocol, according to our docs, is for cipher whose protocol is unknown.
// Should not be used when configuring QSslSocket.
- protocolName = QLatin1String("UnknownProtocol");
+ protocolName = "UnknownProtocol"_L1;
Q_FALLTHROUGH();
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
case QSsl::DtlsV1_0:
case QSsl::DtlsV1_2:
case QSsl::DtlsV1_0OrLater:
@@ -1903,6 +2082,7 @@ bool QSslSocketPrivate::verifyProtocolSupported(const char *where)
setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError,
QSslSocket::tr("Attempted to use an unsupported protocol."));
return false;
+QT_WARNING_POP
default:
return true;
}
@@ -1951,7 +2131,35 @@ void QSslSocketPrivate::setDefaultSupportedCiphers(const QList<QSslCipher> &ciph
/*!
\internal
*/
-void q_setDefaultDtlsCiphers(const QList<QSslCipher> &ciphers)
+void QSslSocketPrivate::resetDefaultEllipticCurves()
+{
+ const auto *tlsBackend = tlsBackendInUse();
+ if (!tlsBackend)
+ return;
+
+ auto ids = tlsBackend->ellipticCurvesIds();
+ if (!ids.size())
+ return;
+
+ QList<QSslEllipticCurve> curves;
+ curves.reserve(ids.size());
+ for (int id : ids) {
+ QSslEllipticCurve curve;
+ curve.id = id;
+ curves.append(curve);
+ }
+
+ // Set the list of supported ECs, but not the list
+ // of *default* ECs. OpenSSL doesn't like forcing an EC for the wrong
+ // ciphersuite, so don't try it -- leave the empty list to mean
+ // "the implementation will choose the most suitable one".
+ setDefaultSupportedEllipticCurves(curves);
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::setDefaultDtlsCiphers(const QList<QSslCipher> &ciphers)
{
QMutexLocker locker(&globalData()->mutex);
globalData()->dtlsConfig.detach();
@@ -1961,7 +2169,7 @@ void q_setDefaultDtlsCiphers(const QList<QSslCipher> &ciphers)
/*!
\internal
*/
-QList<QSslCipher> q_getDefaultDtlsCiphers()
+QList<QSslCipher> QSslSocketPrivate::defaultDtlsCiphers()
{
QSslSocketPrivate::ensureInitialized();
QMutexLocker locker(&globalData()->mutex);
@@ -2087,6 +2295,7 @@ void QSslConfigurationPrivate::deepCopyDefaultConfiguration(QSslConfigurationPri
ptr->sessionProtocol = global->sessionProtocol;
ptr->ciphers = global->ciphers;
ptr->caCertificates = global->caCertificates;
+ ptr->allowRootCertOnDemandLoading = global->allowRootCertOnDemandLoading;
ptr->protocol = global->protocol;
ptr->peerVerifyMode = global->peerVerifyMode;
ptr->peerVerifyDepth = global->peerVerifyDepth;
@@ -2208,6 +2417,11 @@ bool QSslSocketPrivate::isPaused() const
return paused;
}
+void QSslSocketPrivate::setPaused(bool p)
+{
+ paused = p;
+}
+
bool QSslSocketPrivate::bind(const QHostAddress &address, quint16 port, QAbstractSocket::BindMode mode)
{
// this function is called from QAbstractSocket::bind
@@ -2326,7 +2540,7 @@ void QSslSocketPrivate::_q_errorSlot(QAbstractSocket::SocketError error)
qCDebug(lcSsl) << "\terrorString =" << q->errorString();
#endif
// this moves encrypted bytes from plain socket into our buffer
- if (plainSocket->bytesAvailable()) {
+ if (plainSocket->bytesAvailable() && mode != QSslSocket::UnencryptedMode) {
qint64 tmpReadBufferMaxSize = readBufferMaxSize;
readBufferMaxSize = 0; // reset temporarily so the plain sockets completely drained drained
transmit();
@@ -2438,6 +2652,7 @@ void QSslSocketPrivate::_q_resumeImplementation()
if (verifyErrorsHaveBeenIgnored()) {
continueHandshake();
} else {
+ const auto sslErrors = backend->tlsErrors();
Q_ASSERT(!sslErrors.isEmpty());
setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError, sslErrors.constFirst().errorString());
plainSocket->disconnectFromHost();
@@ -2452,13 +2667,16 @@ void QSslSocketPrivate::_q_resumeImplementation()
*/
bool QSslSocketPrivate::verifyErrorsHaveBeenIgnored()
{
+ Q_ASSERT(backend.get());
+
bool doEmitSslError;
if (!ignoreErrorsList.empty()) {
// check whether the errors we got are all in the list of expected errors
// (applies only if the method QSslSocket::ignoreSslErrors(const QList<QSslError> &errors)
// was called)
+ const auto &sslErrors = backend->tlsErrors();
doEmitSslError = false;
- for (int a = 0; a < sslErrors.count(); a++) {
+ for (int a = 0; a < sslErrors.size(); a++) {
if (!ignoreErrorsList.contains(sslErrors.at(a))) {
doEmitSslError = true;
break;
@@ -2476,6 +2694,91 @@ bool QSslSocketPrivate::verifyErrorsHaveBeenIgnored()
/*!
\internal
*/
+bool QSslSocketPrivate::isAutoStartingHandshake() const
+{
+ return autoStartHandshake;
+}
+
+/*!
+ \internal
+*/
+bool QSslSocketPrivate::isPendingClose() const
+{
+ return pendingClose;
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::setPendingClose(bool pc)
+{
+ pendingClose = pc;
+}
+
+/*!
+ \internal
+*/
+qint64 QSslSocketPrivate::maxReadBufferSize() const
+{
+ return readBufferMaxSize;
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::setMaxReadBufferSize(qint64 maxSize)
+{
+ readBufferMaxSize = maxSize;
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::setEncrypted(bool enc)
+{
+ connectionEncrypted = enc;
+}
+
+/*!
+ \internal
+*/
+QIODevicePrivate::QRingBufferRef &QSslSocketPrivate::tlsWriteBuffer()
+{
+ return writeBuffer;
+}
+
+/*!
+ \internal
+*/
+QIODevicePrivate::QRingBufferRef &QSslSocketPrivate::tlsBuffer()
+{
+ return buffer;
+}
+
+/*!
+ \internal
+*/
+bool &QSslSocketPrivate::tlsEmittedBytesWritten()
+{
+ return emittedBytesWritten;
+}
+
+/*!
+ \internal
+*/
+bool *QSslSocketPrivate::readyReadPointer()
+{
+ return readyReadEmittedPointer;
+}
+
+bool QSslSocketPrivate::hasUndecryptedData() const
+{
+ return backend.get() && backend->hasUndecryptedData();
+}
+
+/*!
+ \internal
+*/
qint64 QSslSocketPrivate::peek(char *data, qint64 maxSize)
{
if (mode == QSslSocket::UnencryptedMode && !autoStartHandshake) {
@@ -2491,9 +2794,9 @@ qint64 QSslSocketPrivate::peek(char *data, qint64 maxSize)
if (r2 < 0)
return (r > 0 ? r : r2);
return r + r2;
- } else {
- return -1;
}
+
+ return -1;
} else {
//encrypted mode - the socket engine will read and decrypt data into the QIODevice buffer
return QTcpSocketPrivate::peek(data, maxSize);
@@ -2511,13 +2814,13 @@ QByteArray QSslSocketPrivate::peek(qint64 maxSize)
QByteArray ret;
ret.reserve(maxSize);
ret.resize(buffer.peek(ret.data(), maxSize, transactionPos));
- if (ret.length() == maxSize)
+ if (ret.size() == maxSize)
return ret;
//peek at data in the plain socket
if (plainSocket)
- return ret + plainSocket->peek(maxSize - ret.length());
- else
- return QByteArray();
+ return ret + plainSocket->peek(maxSize - ret.size());
+
+ return QByteArray();
} else {
//encrypted mode - the socket engine will read and decrypt data into the QIODevice buffer
return QTcpSocketPrivate::peek(maxSize);
@@ -2559,6 +2862,82 @@ bool QSslSocketPrivate::flush()
/*!
\internal
*/
+void QSslSocketPrivate::startClientEncryption()
+{
+ if (backend.get())
+ backend->startClientEncryption();
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::startServerEncryption()
+{
+ if (backend.get())
+ backend->startServerEncryption();
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::transmit()
+{
+ if (backend.get())
+ backend->transmit();
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::disconnectFromHost()
+{
+ if (backend.get())
+ backend->disconnectFromHost();
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::disconnected()
+{
+ if (backend.get())
+ backend->disconnected();
+}
+
+/*!
+ \internal
+*/
+QSslCipher QSslSocketPrivate::sessionCipher() const
+{
+ if (backend.get())
+ return backend->sessionCipher();
+
+ return {};
+}
+
+/*!
+ \internal
+*/
+QSsl::SslProtocol QSslSocketPrivate::sessionProtocol() const
+{
+ if (backend.get())
+ return backend->sessionProtocol();
+
+ return QSsl::UnknownProtocol;
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::continueHandshake()
+{
+ if (backend.get())
+ backend->continueHandshake();
+}
+
+/*!
+ \internal
+*/
bool QSslSocketPrivate::rootCertOnDemandLoadingSupported()
{
return s_loadRootCertsOnDemand;
@@ -2567,34 +2946,63 @@ bool QSslSocketPrivate::rootCertOnDemandLoadingSupported()
/*!
\internal
*/
+void QSslSocketPrivate::setRootCertOnDemandLoadingSupported(bool supported)
+{
+ s_loadRootCertsOnDemand = supported;
+}
+
+/*!
+ \internal
+*/
QList<QByteArray> QSslSocketPrivate::unixRootCertDirectories()
{
- return QList<QByteArray>() << "/etc/ssl/certs/" // (K)ubuntu, OpenSUSE, Mandriva ...
- << "/usr/lib/ssl/certs/" // Gentoo, Mandrake
- << "/usr/share/ssl/" // Centos, Redhat, SuSE
- << "/usr/local/ssl/" // Normal OpenSSL Tarball
- << "/var/ssl/certs/" // AIX
- << "/usr/local/ssl/certs/" // Solaris
- << "/etc/openssl/certs/" // BlackBerry
- << "/opt/openssl/certs/" // HP-UX
- << "/etc/ssl/"; // OpenBSD
+ const auto ba = [](const auto &cstr) constexpr {
+ return QByteArray::fromRawData(std::begin(cstr), std::size(cstr) - 1);
+ };
+ static const QByteArray dirs[] = {
+ ba("/etc/ssl/certs/"), // (K)ubuntu, OpenSUSE, Mandriva ...
+ ba("/usr/lib/ssl/certs/"), // Gentoo, Mandrake
+ ba("/usr/share/ssl/"), // Centos, Redhat, SuSE
+ ba("/usr/local/ssl/"), // Normal OpenSSL Tarball
+ ba("/var/ssl/certs/"), // AIX
+ ba("/usr/local/ssl/certs/"), // Solaris
+ ba("/etc/openssl/certs/"), // BlackBerry
+ ba("/opt/openssl/certs/"), // HP-UX
+ ba("/etc/ssl/"), // OpenBSD
+ };
+ QList<QByteArray> result = QList<QByteArray>::fromReadOnlyData(dirs);
+ if constexpr (isVxworks) {
+ static QByteArray vxworksCertsDir = qgetenv("VXWORKS_CERTS_DIR");
+ if (!vxworksCertsDir.isEmpty())
+ result.push_back(vxworksCertsDir);
+ }
+ return result;
}
/*!
\internal
*/
-void QSslSocketPrivate::checkSettingSslContext(QSslSocket* socket, QSharedPointer<QSslContext> sslContext)
+void QSslSocketPrivate::checkSettingSslContext(QSslSocket* socket, std::shared_ptr<QSslContext> tlsContext)
{
- if (socket->d_func()->sslContextPointer.isNull())
- socket->d_func()->sslContextPointer = sslContext;
+ if (!socket)
+ return;
+
+ if (auto *backend = socket->d_func()->backend.get())
+ backend->checkSettingSslContext(tlsContext);
}
/*!
\internal
*/
-QSharedPointer<QSslContext> QSslSocketPrivate::sslContext(QSslSocket *socket)
+std::shared_ptr<QSslContext> QSslSocketPrivate::sslContext(QSslSocket *socket)
{
- return (socket) ? socket->d_func()->sslContextPointer : QSharedPointer<QSslContext>();
+ if (!socket)
+ return {};
+
+ if (const auto *backend = socket->d_func()->backend.get())
+ return backend->sslContext();
+
+ return {};
}
bool QSslSocketPrivate::isMatchingHostname(const QSslCertificate &cert, const QString &peerName)
@@ -2634,17 +3042,17 @@ bool QSslSocketPrivate::isMatchingHostname(const QSslCertificate &cert, const QS
*/
bool QSslSocketPrivate::isMatchingHostname(const QString &cn, const QString &hostname)
{
- int wildcard = cn.indexOf(QLatin1Char('*'));
+ qsizetype wildcard = cn.indexOf(u'*');
// Check this is a wildcard cert, if not then just compare the strings
if (wildcard < 0)
- return QLatin1String(QUrl::toAce(cn)) == hostname;
+ return QLatin1StringView(QUrl::toAce(cn)) == hostname;
- int firstCnDot = cn.indexOf(QLatin1Char('.'));
- int secondCnDot = cn.indexOf(QLatin1Char('.'), firstCnDot+1);
+ qsizetype firstCnDot = cn.indexOf(u'.');
+ qsizetype secondCnDot = cn.indexOf(u'.', firstCnDot+1);
// Check at least 3 components
- if ((-1 == secondCnDot) || (secondCnDot+1 >= cn.length()))
+ if ((-1 == secondCnDot) || (secondCnDot+1 >= cn.size()))
return false;
// Check * is last character of 1st component (ie. there's a following .)
@@ -2652,12 +3060,12 @@ bool QSslSocketPrivate::isMatchingHostname(const QString &cn, const QString &hos
return false;
// Check only one star
- if (cn.lastIndexOf(QLatin1Char('*')) != wildcard)
+ if (cn.lastIndexOf(u'*') != wildcard)
return false;
// Reject wildcard character embedded within the A-labels or U-labels of an internationalized
// domain name (RFC6125 section 7.2)
- if (cn.startsWith(QLatin1String("xn--"), Qt::CaseInsensitive))
+ if (cn.startsWith("xn--"_L1, Qt::CaseInsensitive))
return false;
// Check characters preceding * (if any) match
@@ -2665,9 +3073,9 @@ bool QSslSocketPrivate::isMatchingHostname(const QString &cn, const QString &hos
return false;
// Check characters following first . match
- int hnDot = hostname.indexOf(QLatin1Char('.'));
+ qsizetype hnDot = hostname.indexOf(u'.');
if (QStringView{hostname}.mid(hnDot + 1) != QStringView{cn}.mid(firstCnDot + 1)
- && QStringView{hostname}.mid(hnDot + 1) != QLatin1String(QUrl::toAce(cn.mid(firstCnDot + 1)))) {
+ && QStringView{hostname}.mid(hnDot + 1) != QLatin1StringView(QUrl::toAce(cn.mid(firstCnDot + 1)))) {
return false;
}
@@ -2680,6 +3088,81 @@ bool QSslSocketPrivate::isMatchingHostname(const QString &cn, const QString &hos
return true;
}
+/*!
+ \internal
+*/
+QTlsBackend *QSslSocketPrivate::tlsBackendInUse()
+{
+ const QMutexLocker locker(&backendMutex);
+ if (tlsBackend)
+ return tlsBackend;
+
+ if (!activeBackendName.size())
+ activeBackendName = QTlsBackend::defaultBackendName();
+
+ if (!activeBackendName.size()) {
+ qCWarning(lcSsl, "No functional TLS backend was found");
+ return nullptr;
+ }
+
+ tlsBackend = QTlsBackend::findBackend(activeBackendName);
+ if (tlsBackend) {
+ QObject::connect(tlsBackend, &QObject::destroyed, tlsBackend, [] {
+ const QMutexLocker locker(&backendMutex);
+ tlsBackend = nullptr;
+ },
+ Qt::DirectConnection);
+ }
+ return tlsBackend;
+}
+
+/*!
+ \internal
+*/
+QSslSocket::SslMode QSslSocketPrivate::tlsMode() const
+{
+ return mode;
+}
+
+/*!
+ \internal
+*/
+bool QSslSocketPrivate::isRootsOnDemandAllowed() const
+{
+ return allowRootCertOnDemandLoading;
+}
+
+/*!
+ \internal
+*/
+QString QSslSocketPrivate::verificationName() const
+{
+ return verificationPeerName;
+}
+
+/*!
+ \internal
+*/
+QString QSslSocketPrivate::tlsHostName() const
+{
+ return hostName;
+}
+
+QTcpSocket *QSslSocketPrivate::plainTcpSocket() const
+{
+ return plainSocket;
+}
+
+/*!
+ \internal
+*/
+QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
+{
+ if (const auto *tlsBackend = tlsBackendInUse())
+ return tlsBackend->systemCaCertificates();
+ return {};
+}
+
QT_END_NAMESPACE
#include "moc_qsslsocket.cpp"
diff --git a/src/network/ssl/qsslsocket.h b/src/network/ssl/qsslsocket.h
index a808efbfdf..3ed1bc45cc 100644
--- a/src/network/ssl/qsslsocket.h
+++ b/src/network/ssl/qsslsocket.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSSLSOCKET_H
@@ -71,6 +35,7 @@ public:
SslClientMode,
SslServerMode
};
+ Q_ENUM(SslMode)
enum PeerVerifyMode {
VerifyNone,
@@ -78,6 +43,7 @@ public:
VerifyPeer,
AutoVerifyPeer
};
+ Q_ENUM(PeerVerifyMode)
explicit QSslSocket(QObject *parent = nullptr);
~QSslSocket();
@@ -163,6 +129,16 @@ public:
static long sslLibraryBuildVersionNumber();
static QString sslLibraryBuildVersionString();
+ static QList<QString> availableBackends();
+ static QString activeBackend();
+ static bool setActiveBackend(const QString &backendName);
+ static QList<QSsl::SslProtocol> supportedProtocols(const QString &backendName = {});
+ static bool isProtocolSupported(QSsl::SslProtocol protocol, const QString &backendName = {});
+ static QList<QSsl::ImplementedClass> implementedClasses(const QString &backendName = {});
+ static bool isClassImplemented(QSsl::ImplementedClass cl, const QString &backendName = {});
+ static QList<QSsl::SupportedFeature> supportedFeatures(const QString &backendName = {});
+ static bool isFeatureSupported(QSsl::SupportedFeature feat, const QString &backendName = {});
+
void ignoreSslErrors(const QList<QSslError> &errors);
void continueInterruptedHandshake();
@@ -191,6 +167,7 @@ protected:
private:
Q_DECLARE_PRIVATE(QSslSocket)
Q_DISABLE_COPY_MOVE(QSslSocket)
+
Q_PRIVATE_SLOT(d_func(), void _q_connectedSlot())
Q_PRIVATE_SLOT(d_func(), void _q_hostFoundSlot())
Q_PRIVATE_SLOT(d_func(), void _q_disconnectedSlot())
@@ -204,10 +181,6 @@ private:
Q_PRIVATE_SLOT(d_func(), void _q_flushWriteBuffer())
Q_PRIVATE_SLOT(d_func(), void _q_flushReadBuffer())
Q_PRIVATE_SLOT(d_func(), void _q_resumeImplementation())
-#if defined(Q_OS_WIN) && !QT_CONFIG(schannel)
- Q_PRIVATE_SLOT(d_func(), void _q_caRootLoaded(QSslCertificate,QSslCertificate))
-#endif
- friend class QSslSocketBackendPrivate;
};
#endif // QT_NO_SSL
diff --git a/src/network/ssl/qsslsocket_mac.cpp b/src/network/ssl/qsslsocket_mac.cpp
deleted file mode 100644
index 4096fb68c6..0000000000
--- a/src/network/ssl/qsslsocket_mac.cpp
+++ /dev/null
@@ -1,1554 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Jeremy Lainé <jeremy.laine@m4x.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qsslsocket.h"
-
-#include "qssl_p.h"
-#include "qsslsocket_mac_p.h"
-#include "qasn1element_p.h"
-#include "qsslcertificate_p.h"
-#include "qsslcipher_p.h"
-#include "qsslkey_p.h"
-
-#include <QtCore/qmessageauthenticationcode.h>
-#include <QtCore/qoperatingsystemversion.h>
-#include <QtCore/qscopedvaluerollback.h>
-#include <QtCore/qcryptographichash.h>
-#include <QtCore/qsystemdetection.h>
-#include <QtCore/qdatastream.h>
-#include <QtCore/qsysinfo.h>
-#include <QtCore/qlist.h>
-#include <QtCore/qmutex.h>
-#include <QtCore/qdebug.h>
-#include <QtCore/quuid.h>
-#include <QtCore/qdir.h>
-
-#include <algorithm>
-#include <cstddef>
-#include <limits>
-#include <vector>
-
-#include <QtCore/private/qcore_mac_p.h>
-
-#ifdef Q_OS_MACOS
-#include <CoreServices/CoreServices.h>
-#endif
-
-QT_BEGIN_NAMESPACE
-
-namespace
-{
-#ifdef Q_OS_MACOS
-/*
-
-Our own temporarykeychain is needed only on macOS where SecPKCS12Import changes
-the default keychain and where we see annoying pop-ups asking about accessing a
-private key.
-
-*/
-
-struct EphemeralSecKeychain
-{
- EphemeralSecKeychain();
- ~EphemeralSecKeychain();
-
- SecKeychainRef keychain = nullptr;
- Q_DISABLE_COPY_MOVE(EphemeralSecKeychain)
-};
-
-EphemeralSecKeychain::EphemeralSecKeychain()
-{
- const auto uuid = QUuid::createUuid();
- if (uuid.isNull()) {
- qCWarning(lcSsl) << "Failed to create a unique keychain name";
- return;
- }
-
- const QByteArray uuidAsByteArray = uuid.toByteArray();
- Q_ASSERT(uuidAsByteArray.size() > 2);
- Q_ASSERT(uuidAsByteArray.startsWith('{'));
- Q_ASSERT(uuidAsByteArray.endsWith('}'));
- const auto uuidAsString = QLatin1String(uuidAsByteArray.data(), uuidAsByteArray.size()).mid(1, uuidAsByteArray.size() - 2);
-
- const QString keychainName
- = QDir::tempPath() + QDir::separator() + uuidAsString + QLatin1String(".keychain");
- // SecKeychainCreate, pathName parameter:
- //
- // "A constant character string representing the POSIX path indicating where
- // to store the keychain."
- //
- // Internally they seem to use std::string, but this does not really help.
- // Fortunately, CFString has a convenient API.
- QCFType<CFStringRef> cfName = keychainName.toCFString();
- std::vector<char> posixPath;
- // "Extracts the contents of a string as a NULL-terminated 8-bit string
- // appropriate for passing to POSIX APIs."
- posixPath.resize(CFStringGetMaximumSizeOfFileSystemRepresentation(cfName));
- const auto ok = CFStringGetFileSystemRepresentation(cfName, &posixPath[0],
- CFIndex(posixPath.size()));
- if (!ok) {
- qCWarning(lcSsl) << "Failed to create a unique keychain name from"
- << "QDir::tempPath()";
- return;
- }
-
- std::vector<uint8_t> passUtf8(256);
- if (SecRandomCopyBytes(kSecRandomDefault, passUtf8.size(), &passUtf8[0])) {
- qCWarning(lcSsl) << "SecRandomCopyBytes: failed to create a key";
- return;
- }
-
- const OSStatus status = SecKeychainCreate(&posixPath[0], passUtf8.size(),
- &passUtf8[0], FALSE, nullptr,
- &keychain);
- if (status != errSecSuccess || !keychain) {
- qCWarning(lcSsl) << "SecKeychainCreate: failed to create a custom keychain";
- if (keychain) {
- SecKeychainDelete(keychain);
- CFRelease(keychain);
- keychain = nullptr;
- }
- }
-
- if (keychain) {
- SecKeychainSettings settings = {};
- settings.version = SEC_KEYCHAIN_SETTINGS_VERS1;
- // Strange, huh? But that's what their docs say to do! With lockOnSleep
- // == false, set interval to INT_MAX to never lock ...
- settings.lockInterval = INT_MAX;
- if (SecKeychainSetSettings(keychain, &settings) != errSecSuccess)
- qCWarning(lcSsl) << "SecKeychainSettings: failed to disable lock on sleep";
- }
-
-#ifdef QSSLSOCKET_DEBUG
- if (keychain) {
- qCDebug(lcSsl) << "Custom keychain with name" << keychainName << "was created"
- << "successfully";
- }
-#endif
-}
-
-EphemeralSecKeychain::~EphemeralSecKeychain()
-{
- if (keychain) {
- // clear file off disk
- SecKeychainDelete(keychain);
- CFRelease(keychain);
- }
-}
-
-#endif // Q_OS_MACOS
-
-} // unnamed namespace
-
-static SSLContextRef qt_createSecureTransportContext(QSslSocket::SslMode mode)
-{
- const bool isServer = mode == QSslSocket::SslServerMode;
- const SSLProtocolSide side = isServer ? kSSLServerSide : kSSLClientSide;
- // We never use kSSLDatagramType, so it's kSSLStreamType unconditionally.
- SSLContextRef context = SSLCreateContext(nullptr, side, kSSLStreamType);
- if (!context)
- qCWarning(lcSsl) << "SSLCreateContext failed";
- return context;
-}
-
-static void qt_releaseSecureTransportContext(SSLContextRef context)
-{
- if (context)
- CFRelease(context);
-}
-
-QSecureTransportContext::QSecureTransportContext(SSLContextRef c)
- : context(c)
-{
-}
-
-QSecureTransportContext::~QSecureTransportContext()
-{
- qt_releaseSecureTransportContext(context);
-}
-
-QSecureTransportContext::operator SSLContextRef()const
-{
- return context;
-}
-
-void QSecureTransportContext::reset(SSLContextRef newContext)
-{
- qt_releaseSecureTransportContext(context);
- context = newContext;
-}
-
-Q_GLOBAL_STATIC(QRecursiveMutex, qt_securetransport_mutex)
-
-//#define QSSLSOCKET_DEBUG
-
-bool QSslSocketPrivate::s_libraryLoaded = false;
-bool QSslSocketPrivate::s_loadedCiphersAndCerts = false;
-bool QSslSocketPrivate::s_loadRootCertsOnDemand = false;
-
-
-#if !defined(QT_PLATFORM_UIKIT) // dhparam is only used on macOS. (see the SSLSetDiffieHellmanParams call below)
-static const uint8_t dhparam[] =
- "\x30\x82\x01\x08\x02\x82\x01\x01\x00\x97\xea\xd0\x46\xf7\xae\xa7\x76\x80"
- "\x9c\x74\x56\x98\xd8\x56\x97\x2b\x20\x6c\x77\xe2\x82\xbb\xc8\x84\xbe\xe7"
- "\x63\xaf\xcc\x30\xd0\x67\x97\x7d\x1b\xab\x59\x30\xa9\x13\x67\x21\xd7\xd4"
- "\x0e\x46\xcf\xe5\x80\xdf\xc9\xb9\xba\x54\x9b\x46\x2f\x3b\x45\xfc\x2f\xaf"
- "\xad\xc0\x17\x56\xdd\x52\x42\x57\x45\x70\x14\xe5\xbe\x67\xaa\xde\x69\x75"
- "\x30\x0d\xf9\xa2\xc4\x63\x4d\x7a\x39\xef\x14\x62\x18\x33\x44\xa1\xf9\xc1"
- "\x52\xd1\xb6\x72\x21\x98\xf8\xab\x16\x1b\x7b\x37\x65\xe3\xc5\x11\x00\xf6"
- "\x36\x1f\xd8\x5f\xd8\x9f\x43\xa8\xce\x9d\xbf\x5e\xd6\x2d\xfa\x0a\xc2\x01"
- "\x54\xc2\xd9\x81\x54\x55\xb5\x26\xf8\x88\x37\xf5\xfe\xe0\xef\x4a\x34\x81"
- "\xdc\x5a\xb3\x71\x46\x27\xe3\xcd\x24\xf6\x1b\xf1\xe2\x0f\xc2\xa1\x39\x53"
- "\x5b\xc5\x38\x46\x8e\x67\x4c\xd9\xdd\xe4\x37\x06\x03\x16\xf1\x1d\x7a\xba"
- "\x2d\xc1\xe4\x03\x1a\x58\xe5\x29\x5a\x29\x06\x69\x61\x7a\xd8\xa9\x05\x9f"
- "\xc1\xa2\x45\x9c\x17\xad\x52\x69\x33\xdc\x18\x8d\x15\xa6\x5e\xcd\x94\xf4"
- "\x45\xbb\x9f\xc2\x7b\x85\x00\x61\xb0\x1a\xdc\x3c\x86\xaa\x9f\x5c\x04\xb3"
- "\x90\x0b\x35\x64\xff\xd9\xe3\xac\xf2\xf2\xeb\x3a\x63\x02\x01\x02";
-#endif
-
-OSStatus QSslSocketBackendPrivate::ReadCallback(QSslSocketBackendPrivate *socket,
- char *data, size_t *dataLength)
-{
- Q_ASSERT(socket);
- Q_ASSERT(data);
- Q_ASSERT(dataLength);
-
- QTcpSocket *plainSocket = socket->plainSocket;
- Q_ASSERT(plainSocket);
-
- if (socket->isHandshakeComplete()) {
- // Check if it's a renegotiation attempt, when the handshake is complete, the
- // session state is 'kSSLConnected':
- SSLSessionState currentState = kSSLConnected;
- const OSStatus result = SSLGetSessionState(socket->context, &currentState);
- if (result != noErr) {
- *dataLength = 0;
- return result;
- }
-
- if (currentState == kSSLHandshake) {
- // Renegotiation detected, don't allow read more yet - 'transmit'
- // will notice this and will call 'startHandshake':
- *dataLength = 0;
- socket->renegotiating = true;
- return errSSLWouldBlock;
- }
- }
-
- const qint64 bytes = plainSocket->read(data, *dataLength);
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "read" << bytes;
-#endif
- if (bytes < 0) {
- *dataLength = 0;
- return errSecIO;
- }
-
- const OSStatus err = (size_t(bytes) < *dataLength) ? errSSLWouldBlock : errSecSuccess;
- *dataLength = bytes;
-
- return err;
-}
-
-OSStatus QSslSocketBackendPrivate::WriteCallback(QSslSocketBackendPrivate *socket,
- const char *data, size_t *dataLength)
-{
- Q_ASSERT(socket);
- Q_ASSERT(data);
- Q_ASSERT(dataLength);
-
- QTcpSocket *plainSocket = socket->plainSocket;
- Q_ASSERT(plainSocket);
-
- const qint64 bytes = plainSocket->write(data, *dataLength);
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "write" << bytes;
-#endif
- if (bytes < 0) {
- *dataLength = 0;
- return errSecIO;
- }
-
- const OSStatus err = (size_t(bytes) < *dataLength) ? errSSLWouldBlock : errSecSuccess;
- *dataLength = bytes;
-
- return err;
-}
-
-void QSslSocketPrivate::ensureInitialized()
-{
- const QMutexLocker locker(qt_securetransport_mutex);
- if (s_loadedCiphersAndCerts)
- return;
-
- // We have to set it before setDefaultSupportedCiphers,
- // since this function can trigger static (global)'s initialization
- // and as a result - recursive ensureInitialized call
- // from QSslCertificatePrivate's ctor.
- s_loadedCiphersAndCerts = true;
-
- const QSecureTransportContext context(qt_createSecureTransportContext(QSslSocket::SslClientMode));
- if (context) {
- QList<QSslCipher> ciphers;
- QList<QSslCipher> defaultCiphers;
-
- size_t numCiphers = 0;
- // Fails only if any of parameters is null.
- SSLGetNumberSupportedCiphers(context, &numCiphers);
- QList<SSLCipherSuite> cfCiphers(numCiphers);
- // Fails only if any of parameter is null or number of ciphers is wrong.
- SSLGetSupportedCiphers(context, cfCiphers.data(), &numCiphers);
-
- for (size_t i = 0; i < size_t(cfCiphers.size()); ++i) {
- const QSslCipher ciph(QSslSocketBackendPrivate::QSslCipher_from_SSLCipherSuite(cfCiphers.at(i)));
- if (!ciph.isNull()) {
- ciphers << ciph;
- if (ciph.usedBits() >= 128)
- defaultCiphers << ciph;
- }
- }
-
- setDefaultSupportedCiphers(ciphers);
- setDefaultCiphers(defaultCiphers);
-
- if (!s_loadRootCertsOnDemand)
- setDefaultCaCertificates(systemCaCertificates());
- } else {
- s_loadedCiphersAndCerts = false;
- }
-
-}
-
-long QSslSocketPrivate::sslLibraryVersionNumber()
-{
- return 0;
-}
-
-QString QSslSocketPrivate::sslLibraryVersionString()
-{
- return QLatin1String("Secure Transport, ") + QSysInfo::prettyProductName();
-}
-
-long QSslSocketPrivate::sslLibraryBuildVersionNumber()
-{
- return 0;
-}
-
-QString QSslSocketPrivate::sslLibraryBuildVersionString()
-{
- return sslLibraryVersionString();
-}
-
-bool QSslSocketPrivate::supportsSsl()
-{
- return true;
-}
-
-void QSslSocketPrivate::resetDefaultCiphers()
-{
- Q_UNIMPLEMENTED();
-}
-
-void QSslSocketPrivate::resetDefaultEllipticCurves()
-{
- // No public API for this (?).
- Q_UNIMPLEMENTED();
-}
-
-QSslSocketBackendPrivate::QSslSocketBackendPrivate()
- : context(nullptr)
-{
-}
-
-QSslSocketBackendPrivate::~QSslSocketBackendPrivate()
-{
- destroySslContext();
-}
-
-void QSslSocketBackendPrivate::continueHandshake()
-{
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "connection encrypted";
-#endif
- Q_Q(QSslSocket);
- connectionEncrypted = true;
-
-#if QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_13_4, __IPHONE_11_0, __TVOS_11_0, __WATCHOS_4_0)
- // Unlike OpenSSL, Secure Transport does not allow to negotiate protocols via
- // a callback during handshake. We can only set our list of preferred protocols
- // (and send it during handshake) and then receive what our peer has sent to us.
- // And here we can finally try to find a match (if any).
- if (__builtin_available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *)) {
- const auto &requestedProtocols = configuration.nextAllowedProtocols;
- if (const int requestedCount = requestedProtocols.size()) {
- configuration.nextProtocolNegotiationStatus = QSslConfiguration::NextProtocolNegotiationNone;
- configuration.nextNegotiatedProtocol.clear();
-
- QCFType<CFArrayRef> cfArray;
- const OSStatus result = SSLCopyALPNProtocols(context, &cfArray);
- if (result == errSecSuccess && cfArray && CFArrayGetCount(cfArray)) {
- const int size = CFArrayGetCount(cfArray);
- QList<QString> peerProtocols(size);
- for (int i = 0; i < size; ++i)
- peerProtocols[i] = QString::fromCFString((CFStringRef)CFArrayGetValueAtIndex(cfArray, i));
-
- for (int i = 0; i < requestedCount; ++i) {
- const auto requestedName = QString::fromLatin1(requestedProtocols[i]);
- for (int j = 0; j < size; ++j) {
- if (requestedName == peerProtocols[j]) {
- configuration.nextNegotiatedProtocol = requestedName.toLatin1();
- configuration.nextProtocolNegotiationStatus = QSslConfiguration::NextProtocolNegotiationNegotiated;
- break;
- }
- }
- if (configuration.nextProtocolNegotiationStatus == QSslConfiguration::NextProtocolNegotiationNegotiated)
- break;
- }
- }
- }
- }
-#endif // QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE
-
- if (!renegotiating)
- emit q->encrypted();
-
- if (autoStartHandshake && pendingClose) {
- pendingClose = false;
- q->disconnectFromHost();
- }
-}
-
-void QSslSocketBackendPrivate::disconnected()
-{
- if (plainSocket->bytesAvailable() <= 0)
- destroySslContext();
- // If there is still buffered data in the plain socket, don't destroy the ssl context yet.
- // It will be destroyed when the socket is deleted.
-}
-
-void QSslSocketBackendPrivate::disconnectFromHost()
-{
- if (context) {
- if (!shutdown) {
- SSLClose(context);
- shutdown = true;
- }
- }
- plainSocket->disconnectFromHost();
-}
-
-QSslCipher QSslSocketBackendPrivate::sessionCipher() const
-{
- SSLCipherSuite cipher = 0;
- if (context && SSLGetNegotiatedCipher(context, &cipher) == errSecSuccess)
- return QSslCipher_from_SSLCipherSuite(cipher);
-
- return QSslCipher();
-}
-
-QSsl::SslProtocol QSslSocketBackendPrivate::sessionProtocol() const
-{
- if (!context)
- return QSsl::UnknownProtocol;
-
- SSLProtocol protocol = kSSLProtocolUnknown;
- const OSStatus err = SSLGetNegotiatedProtocolVersion(context, &protocol);
- if (err != errSecSuccess) {
- qCWarning(lcSsl) << "SSLGetNegotiatedProtocolVersion failed:" << err;
- return QSsl::UnknownProtocol;
- }
-
- switch (protocol) {
- case kTLSProtocol1:
- return QSsl::TlsV1_0;
- case kTLSProtocol11:
- return QSsl::TlsV1_1;
- case kTLSProtocol12:
- return QSsl::TlsV1_2;
- case kTLSProtocol13:
- return QSsl::TlsV1_3;
- default:
- return QSsl::UnknownProtocol;
- }
-}
-
-void QSslSocketBackendPrivate::startClientEncryption()
-{
- if (!initSslContext()) {
- // Error description/code were set, 'error' emitted
- // by initSslContext, but OpenSSL socket also sets error
- // emits a signal twice, so ...
- setErrorAndEmit(QAbstractSocket::SslInternalError, QStringLiteral("Unable to init SSL Context"));
- return;
- }
-
- startHandshake();
-}
-
-void QSslSocketBackendPrivate::startServerEncryption()
-{
- if (!initSslContext()) {
- // Error description/code were set, 'error' emitted
- // by initSslContext, but OpenSSL socket also sets error
- // emits a signal twice, so ...
- setErrorAndEmit(QAbstractSocket::SslInternalError, QStringLiteral("Unable to init SSL Context"));
- return;
- }
-
- startHandshake();
-}
-
-void QSslSocketBackendPrivate::transmit()
-{
- Q_Q(QSslSocket);
-
- // If we don't have any SSL context, don't bother transmitting.
- // Edit: if SSL session closed, don't bother either.
- if (!context || shutdown)
- return;
-
- if (!isHandshakeComplete())
- startHandshake();
-
- if (isHandshakeComplete() && !writeBuffer.isEmpty()) {
- qint64 totalBytesWritten = 0;
- while (writeBuffer.nextDataBlockSize() > 0 && context) {
- const size_t nextDataBlockSize = writeBuffer.nextDataBlockSize();
- size_t writtenBytes = 0;
- const OSStatus err = SSLWrite(context, writeBuffer.readPointer(), nextDataBlockSize, &writtenBytes);
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "SSLWrite returned" << err;
-#endif
- if (err != errSecSuccess && err != errSSLWouldBlock) {
- setErrorAndEmit(QAbstractSocket::SslInternalError,
- QStringLiteral("SSLWrite failed: %1").arg(err));
- break;
- }
-
- if (writtenBytes) {
- writeBuffer.free(writtenBytes);
- totalBytesWritten += writtenBytes;
- }
-
- if (writtenBytes < nextDataBlockSize)
- break;
- }
-
- if (totalBytesWritten > 0) {
- // Don't emit bytesWritten() recursively.
- if (!emittedBytesWritten) {
- emittedBytesWritten = true;
- emit q->bytesWritten(totalBytesWritten);
- emittedBytesWritten = false;
- }
- emit q->channelBytesWritten(0, totalBytesWritten);
- }
- }
-
- if (isHandshakeComplete()) {
- QVarLengthArray<char, 4096> data;
- while (context && (!readBufferMaxSize || buffer.size() < readBufferMaxSize)) {
- size_t readBytes = 0;
- data.resize(4096);
- const OSStatus err = SSLRead(context, data.data(), data.size(), &readBytes);
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "SSLRead returned" << err;
-#endif
- if (err == errSSLClosedGraceful) {
- shutdown = true; // the other side shut down, make sure we do not send shutdown ourselves
- setErrorAndEmit(QAbstractSocket::RemoteHostClosedError,
- QSslSocket::tr("The TLS/SSL connection has been closed"));
- break;
- } else if (err != errSecSuccess && err != errSSLWouldBlock) {
- setErrorAndEmit(QAbstractSocket::SslInternalError,
- QStringLiteral("SSLRead failed: %1").arg(err));
- break;
- }
-
- if (err == errSSLWouldBlock && renegotiating) {
- startHandshake();
- break;
- }
-
- if (readBytes) {
- buffer.append(data.constData(), readBytes);
- if (readyReadEmittedPointer)
- *readyReadEmittedPointer = true;
- emit q->readyRead();
- emit q->channelReadyRead(0);
- }
-
- if (err == errSSLWouldBlock)
- break;
- }
- }
-}
-
-
-QList<QSslError> (QSslSocketBackendPrivate::verify)(QList<QSslCertificate> certificateChain, const QString &hostName)
-{
- Q_UNIMPLEMENTED();
- Q_UNUSED(certificateChain);
- Q_UNUSED(hostName);
-
- QList<QSslError> errors;
- errors << QSslError(QSslError::UnspecifiedError);
-
- return errors;
-}
-
-bool QSslSocketBackendPrivate::importPkcs12(QIODevice *device,
- QSslKey *key, QSslCertificate *cert,
- QList<QSslCertificate> *caCertificates,
- const QByteArray &passPhrase)
-{
- Q_UNIMPLEMENTED();
- Q_UNUSED(device);
- Q_UNUSED(key);
- Q_UNUSED(cert);
- Q_UNUSED(caCertificates);
- Q_UNUSED(passPhrase);
- return false;
-}
-
-QSslCipher QSslSocketBackendPrivate::QSslCipher_from_SSLCipherSuite(SSLCipherSuite cipher)
-{
- QSslCipher ciph;
- switch (cipher) {
- // Sorted as in CipherSuite.h (and groupped by their RFC)
- // TLS addenda using AES, per RFC 3268
- case TLS_RSA_WITH_AES_128_CBC_SHA:
- ciph.d->name = QLatin1String("AES128-SHA");
- break;
- case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
- ciph.d->name = QLatin1String("DHE-RSA-AES128-SHA");
- break;
- case TLS_RSA_WITH_AES_256_CBC_SHA:
- ciph.d->name = QLatin1String("AES256-SHA");
- break;
- case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
- ciph.d->name = QLatin1String("DHE-RSA-AES256-SHA");
- break;
-
- // ECDSA addenda, RFC 4492
- case TLS_ECDH_ECDSA_WITH_NULL_SHA:
- ciph.d->name = QLatin1String("ECDH-ECDSA-NULL-SHA");
- break;
- case TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
- ciph.d->name = QLatin1String("ECDH-ECDSA-RC4-SHA");
- break;
- case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
- ciph.d->name = QLatin1String("ECDH-ECDSA-DES-CBC3-SHA");
- break;
- case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
- ciph.d->name = QLatin1String("ECDH-ECDSA-AES128-SHA");
- break;
- case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
- ciph.d->name = QLatin1String("ECDH-ECDSA-AES256-SHA");
- break;
- case TLS_ECDHE_ECDSA_WITH_NULL_SHA:
- ciph.d->name = QLatin1String("ECDHE-ECDSA-NULL-SHA");
- break;
- case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
- ciph.d->name = QLatin1String("ECDHE-ECDSA-RC4-SHA");
- break;
- case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
- ciph.d->name = QLatin1String("ECDHE-ECDSA-DES-CBC3-SHA");
- break;
- case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
- ciph.d->name = QLatin1String("ECDHE-ECDSA-AES128-SHA");
- break;
- case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
- ciph.d->name = QLatin1String("ECDHE-ECDSA-AES256-SHA");
- break;
- case TLS_ECDH_RSA_WITH_NULL_SHA:
- ciph.d->name = QLatin1String("ECDH-RSA-NULL-SHA");
- break;
- case TLS_ECDH_RSA_WITH_RC4_128_SHA:
- ciph.d->name = QLatin1String("ECDH-RSA-RC4-SHA");
- break;
- case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
- ciph.d->name = QLatin1String("ECDH-RSA-DES-CBC3-SHA");
- break;
- case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
- ciph.d->name = QLatin1String("ECDH-RSA-AES128-SHA");
- break;
- case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
- ciph.d->name = QLatin1String("ECDH-RSA-AES256-SHA");
- break;
- case TLS_ECDHE_RSA_WITH_NULL_SHA:
- ciph.d->name = QLatin1String("ECDHE-RSA-NULL-SHA");
- break;
- case TLS_ECDHE_RSA_WITH_RC4_128_SHA:
- ciph.d->name = QLatin1String("ECDHE-RSA-RC4-SHA");
- break;
- case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
- ciph.d->name = QLatin1String("ECDHE-RSA-DES-CBC3-SHA");
- break;
- case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
- ciph.d->name = QLatin1String("ECDHE-RSA-AES128-SHA");
- break;
- case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
- ciph.d->name = QLatin1String("ECDHE-RSA-AES256-SHA");
- break;
-
- // TLS 1.2 addenda, RFC 5246
- case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
- ciph.d->name = QLatin1String("DES-CBC3-SHA");
- break;
- case TLS_RSA_WITH_AES_128_CBC_SHA256:
- ciph.d->name = QLatin1String("AES128-SHA256");
- break;
- case TLS_RSA_WITH_AES_256_CBC_SHA256:
- ciph.d->name = QLatin1String("AES256-SHA256");
- break;
- case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
- ciph.d->name = QLatin1String("DHE-RSA-DES-CBC3-SHA");
- break;
- case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
- ciph.d->name = QLatin1String("DHE-RSA-AES128-SHA256");
- break;
- case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
- ciph.d->name = QLatin1String("DHE-RSA-AES256-SHA256");
- break;
-
- // Addendum from RFC 4279, TLS PSK
- // all missing atm.
-
- // RFC 4785 - Pre-Shared Key (PSK) Ciphersuites with NULL Encryption
- // all missing atm.
-
- // Addenda from rfc 5288 AES Galois Counter Mode (CGM) Cipher Suites for TLS
- case TLS_RSA_WITH_AES_256_GCM_SHA384:
- ciph.d->name = QLatin1String("AES256-GCM-SHA384");
- break;
-
- // RFC 5487 - PSK with SHA-256/384 and AES GCM
- // all missing atm.
-
- // Addenda from rfc 5289 Elliptic Curve Cipher Suites with HMAC SHA-256/384
- case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
- ciph.d->name = QLatin1String("ECDHE-ECDSA-AES128-SHA256");
- break;
- case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
- ciph.d->name = QLatin1String("ECDHE-ECDSA-AES256-SHA384");
- break;
- case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
- ciph.d->name = QLatin1String("ECDH-ECDSA-AES128-SHA256");
- break;
- case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
- ciph.d->name = QLatin1String("ECDH-ECDSA-AES256-SHA384");
- break;
- case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
- ciph.d->name = QLatin1String("ECDHE-RSA-AES128-SHA256");
- break;
- case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
- ciph.d->name = QLatin1String("ECDHE-RSA-AES256-SHA384");
- break;
- case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
- ciph.d->name = QLatin1String("ECDH-RSA-AES128-SHA256");
- break;
- case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
- ciph.d->name = QLatin1String("ECDH-RSA-AES256-SHA384");
- break;
-
- // Addenda from rfc 5289 Elliptic Curve Cipher Suites
- // with SHA-256/384 and AES Galois Counter Mode (GCM)
- case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
- ciph.d->name = QLatin1String("ECDHE-RSA-AES256-GCM-SHA384");
- break;
-
- default:
- return ciph;
- }
- ciph.d->isNull = false;
-
- // protocol
- ciph.d->protocol = QSsl::TlsV1_2;
- ciph.d->protocolString = QLatin1String("TLSv1.2");
-
- const auto bits = QStringView{ciph.d->name}.split(QLatin1Char('-'));
- if (bits.size() >= 2) {
- if (bits.size() == 2 || bits.size() == 3) {
- ciph.d->keyExchangeMethod = QLatin1String("RSA");
- } else if (bits.front() == QLatin1String("DH") || bits.front() == QLatin1String("DHE")) {
- ciph.d->keyExchangeMethod = QLatin1String("DH");
- } else if (bits.front() == QLatin1String("ECDH") || bits.front() == QLatin1String("ECDHE")) {
- ciph.d->keyExchangeMethod = QLatin1String("ECDH");
- } else {
- qCWarning(lcSsl) << "Unknown Kx" << ciph.d->name;
- }
-
- if (bits.size() == 2 || bits.size() == 3) {
- ciph.d->authenticationMethod = QLatin1String("RSA");
- } else if (ciph.d->name.contains(QLatin1String("-ECDSA-"))) {
- ciph.d->authenticationMethod = QLatin1String("ECDSA");
- } else if (ciph.d->name.contains(QLatin1String("-RSA-"))) {
- ciph.d->authenticationMethod = QLatin1String("RSA");
- } else {
- qCWarning(lcSsl) << "Unknown Au" << ciph.d->name;
- }
-
- if (ciph.d->name.contains(QLatin1String("RC4-"))) {
- ciph.d->encryptionMethod = QLatin1String("RC4(128)");
- ciph.d->bits = 128;
- ciph.d->supportedBits = 128;
- } else if (ciph.d->name.contains(QLatin1String("DES-CBC3-"))) {
- ciph.d->encryptionMethod = QLatin1String("3DES(168)");
- ciph.d->bits = 168;
- ciph.d->supportedBits = 168;
- } else if (ciph.d->name.contains(QLatin1String("AES128-"))) {
- ciph.d->encryptionMethod = QLatin1String("AES(128)");
- ciph.d->bits = 128;
- ciph.d->supportedBits = 128;
- } else if (ciph.d->name.contains(QLatin1String("AES256-GCM"))) {
- ciph.d->encryptionMethod = QLatin1String("AESGCM(256)");
- ciph.d->bits = 256;
- ciph.d->supportedBits = 256;
- } else if (ciph.d->name.contains(QLatin1String("AES256-"))) {
- ciph.d->encryptionMethod = QLatin1String("AES(256)");
- ciph.d->bits = 256;
- ciph.d->supportedBits = 256;
- } else if (ciph.d->name.contains(QLatin1String("NULL-"))) {
- ciph.d->encryptionMethod = QLatin1String("NULL");
- } else {
- qCWarning(lcSsl) << "Unknown Enc" << ciph.d->name;
- }
- }
- return ciph;
-}
-SSLCipherSuite QSslSocketBackendPrivate::SSLCipherSuite_from_QSslCipher(const QSslCipher &ciph)
-{
- if (ciph.d->name == QLatin1String("AES128-SHA"))
- return TLS_RSA_WITH_AES_128_CBC_SHA;
- if (ciph.d->name == QLatin1String("DHE-RSA-AES128-SHA"))
- return TLS_DHE_RSA_WITH_AES_128_CBC_SHA;
- if (ciph.d->name == QLatin1String("AES256-SHA"))
- return TLS_RSA_WITH_AES_256_CBC_SHA;
- if (ciph.d->name == QLatin1String("DHE-RSA-AES256-SHA"))
- return TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
- if (ciph.d->name == QLatin1String("ECDH-ECDSA-NULL-SHA"))
- return TLS_ECDH_ECDSA_WITH_NULL_SHA;
- if (ciph.d->name == QLatin1String("ECDH-ECDSA-RC4-SHA"))
- return TLS_ECDH_ECDSA_WITH_RC4_128_SHA;
- if (ciph.d->name == QLatin1String("ECDH-ECDSA-DES-CBC3-SHA"))
- return TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA;
- if (ciph.d->name == QLatin1String("ECDH-ECDSA-AES128-SHA"))
- return TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA;
- if (ciph.d->name == QLatin1String("ECDH-ECDSA-AES256-SHA"))
- return TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA;
- if (ciph.d->name == QLatin1String("ECDH-ECDSA-RC4-SHA"))
- return TLS_ECDHE_ECDSA_WITH_RC4_128_SHA;
- if (ciph.d->name == QLatin1String("ECDH-ECDSA-DES-CBC3-SHA"))
- return TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA;
- if (ciph.d->name == QLatin1String("ECDH-ECDSA-AES128-SHA"))
- return TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA;
- if (ciph.d->name == QLatin1String("ECDH-ECDSA-AES256-SHA"))
- return TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA;
- if (ciph.d->name == QLatin1String("ECDH-RSA-NULL-SHA"))
- return TLS_ECDH_RSA_WITH_NULL_SHA;
- if (ciph.d->name == QLatin1String("ECDH-RSA-RC4-SHA"))
- return TLS_ECDH_RSA_WITH_RC4_128_SHA;
- if (ciph.d->name == QLatin1String("ECDH-RSA-DES-CBC3-SHA"))
- return TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA;
- if (ciph.d->name == QLatin1String("ECDH-RSA-AES128-SHA"))
- return TLS_ECDH_RSA_WITH_AES_128_CBC_SHA;
- if (ciph.d->name == QLatin1String("ECDH-RSA-AES256-SHA"))
- return TLS_ECDH_RSA_WITH_AES_256_CBC_SHA;
- if (ciph.d->name == QLatin1String("ECDH-RSA-RC4-SHA"))
- return TLS_ECDHE_RSA_WITH_RC4_128_SHA;
- if (ciph.d->name == QLatin1String("ECDH-RSA-DES-CBC3-SHA"))
- return TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA;
- if (ciph.d->name == QLatin1String("ECDH-RSA-AES128-SHA"))
- return TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA;
- if (ciph.d->name == QLatin1String("ECDH-RSA-AES256-SHA"))
- return TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA;
- if (ciph.d->name == QLatin1String("DES-CBC3-SHA"))
- return TLS_RSA_WITH_3DES_EDE_CBC_SHA;
- if (ciph.d->name == QLatin1String("AES128-SHA256"))
- return TLS_RSA_WITH_AES_128_CBC_SHA256;
- if (ciph.d->name == QLatin1String("AES256-SHA256"))
- return TLS_RSA_WITH_AES_256_CBC_SHA256;
- if (ciph.d->name == QLatin1String("DHE-RSA-DES-CBC3-SHA"))
- return TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA;
- if (ciph.d->name == QLatin1String("DHE-RSA-AES128-SHA256"))
- return TLS_DHE_RSA_WITH_AES_128_CBC_SHA256;
- if (ciph.d->name == QLatin1String("DHE-RSA-AES256-SHA256"))
- return TLS_DHE_RSA_WITH_AES_256_CBC_SHA256;
- if (ciph.d->name == QLatin1String("AES256-GCM-SHA384"))
- return TLS_RSA_WITH_AES_256_GCM_SHA384;
- if (ciph.d->name == QLatin1String("ECDHE-ECDSA-AES128-SHA256"))
- return TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256;
- if (ciph.d->name == QLatin1String("ECDHE-ECDSA-AES256-SHA384"))
- return TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384;
- if (ciph.d->name == QLatin1String("ECDH-ECDSA-AES128-SHA256"))
- return TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256;
- if (ciph.d->name == QLatin1String("ECDH-ECDSA-AES256-SHA384"))
- return TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384;
- if (ciph.d->name == QLatin1String("ECDHE-RSA-AES128-SHA256"))
- return TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256;
- if (ciph.d->name == QLatin1String("ECDHE-RSA-AES256-SHA384"))
- return TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384;
- if (ciph.d->name == QLatin1String("ECDHE-RSA-AES256-SHA384"))
- return TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256;
- if (ciph.d->name == QLatin1String("ECDHE-RSA-AES256-GCM-SHA384"))
- return TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384;
- return 0;
-}
-
-bool QSslSocketBackendPrivate::initSslContext()
-{
- Q_Q(QSslSocket);
-
- Q_ASSERT_X(!context, Q_FUNC_INFO, "invalid socket state, context is not null");
- Q_ASSERT(plainSocket);
-
- context.reset(qt_createSecureTransportContext(mode));
- if (!context) {
- setErrorAndEmit(QAbstractSocket::SslInternalError, QStringLiteral("SSLCreateContext failed"));
- return false;
- }
-
- const OSStatus err = SSLSetIOFuncs(context,
- reinterpret_cast<SSLReadFunc>(&QSslSocketBackendPrivate::ReadCallback),
- reinterpret_cast<SSLWriteFunc>(&QSslSocketBackendPrivate::WriteCallback));
- if (err != errSecSuccess) {
- destroySslContext();
- setErrorAndEmit(QAbstractSocket::SslInternalError,
- QStringLiteral("SSLSetIOFuncs failed: %1").arg(err));
- return false;
- }
-
- SSLSetConnection(context, this);
-
- if (mode == QSslSocket::SslServerMode
- && !configuration.localCertificateChain.isEmpty()) {
- QString errorDescription;
- QAbstractSocket::SocketError errorCode = QAbstractSocket::UnknownSocketError;
- if (!setSessionCertificate(errorDescription, errorCode)) {
- destroySslContext();
- setErrorAndEmit(errorCode, errorDescription);
- return false;
- }
- }
-
- if (!setSessionProtocol()) {
- destroySslContext();
- setErrorAndEmit(QAbstractSocket::SslInternalError, QStringLiteral("Failed to set protocol version"));
- return false;
- }
-
-#if QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_13_4, __IPHONE_11_0, __TVOS_11_0, __WATCHOS_4_0)
- if (__builtin_available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *)) {
- const auto protocolNames = configuration.nextAllowedProtocols;
- QCFType<CFMutableArrayRef> cfNames(CFArrayCreateMutable(nullptr, 0, &kCFTypeArrayCallBacks));
- if (cfNames) {
- for (const QByteArray &name : protocolNames) {
- if (name.size() > 255) {
- qCWarning(lcSsl) << "TLS ALPN extension" << name
- << "is too long and will be ignored.";
- continue;
- } else if (name.isEmpty()) {
- continue;
- }
- QCFString cfName(QString::fromLatin1(name).toCFString());
- CFArrayAppendValue(cfNames, cfName);
- }
-
- if (CFArrayGetCount(cfNames)) {
- // Up to the application layer to check that negotiation
- // failed, and handle this non-TLS error, we do not handle
- // the result of this call as an error:
- if (SSLSetALPNProtocols(context, cfNames) != errSecSuccess)
- qCWarning(lcSsl) << "SSLSetALPNProtocols failed - too long protocol names?";
- }
- } else {
- qCWarning(lcSsl) << "failed to allocate ALPN names array";
- }
- }
-#endif // QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE
-
- if (mode == QSslSocket::SslClientMode) {
- // enable Server Name Indication (SNI)
- QString tlsHostName(verificationPeerName.isEmpty() ? q->peerName() : verificationPeerName);
- if (tlsHostName.isEmpty())
- tlsHostName = hostName;
-
- const QByteArray ace(QUrl::toAce(tlsHostName));
- SSLSetPeerDomainName(context, ace.data(), ace.size());
- // tell SecureTransport we handle peer verification ourselves
- OSStatus err = SSLSetSessionOption(context, kSSLSessionOptionBreakOnServerAuth, true);
- if (err == errSecSuccess)
- err = SSLSetSessionOption(context, kSSLSessionOptionBreakOnCertRequested, true);
-
- if (err != errSecSuccess) {
- destroySslContext();
- setErrorAndEmit(QSslSocket::SslInternalError,
- QStringLiteral("SSLSetSessionOption failed: %1").arg(err));
- return false;
- }
- //
- } else {
- if (configuration.peerVerifyMode != QSslSocket::VerifyNone) {
- // kAlwaysAuthenticate - always fails even if we set break on client auth.
- OSStatus err = SSLSetClientSideAuthenticate(context, kTryAuthenticate);
- if (err == errSecSuccess) {
- // We'd like to verify peer ourselves, otherwise handshake will
- // most probably fail before we can do anything.
- err = SSLSetSessionOption(context, kSSLSessionOptionBreakOnClientAuth, true);
- }
-
- if (err != errSecSuccess) {
- destroySslContext();
- setErrorAndEmit(QAbstractSocket::SslInternalError,
- QStringLiteral("failed to set SSL context option in server mode: %1").arg(err));
- return false;
- }
- }
-#if !defined(QT_PLATFORM_UIKIT)
- // No SSLSetDiffieHellmanParams on iOS; calling it is optional according to docs.
- SSLSetDiffieHellmanParams(context, dhparam, sizeof(dhparam));
-#endif
- }
- if (configuration.ciphers.size() > 0) {
- QVector<SSLCipherSuite> cfCiphers;
- for (const QSslCipher &cipher : configuration.ciphers) {
- if (auto sslCipher = QSslSocketBackendPrivate::SSLCipherSuite_from_QSslCipher(cipher))
- cfCiphers << sslCipher;
- }
- if (cfCiphers.size() == 0) {
- qCWarning(lcSsl) << "failed to add any of the requested ciphers from the configuration";
- return false;
- }
- OSStatus err = SSLSetEnabledCiphers(context, cfCiphers.data(), cfCiphers.size());
- if (err != errSecSuccess) {
- qCWarning(lcSsl) << "failed to set the ciphers from the configuration";
- return false;
- }
- }
- return true;
-}
-
-void QSslSocketBackendPrivate::destroySslContext()
-{
- context.reset(nullptr);
-}
-
-bool QSslSocketBackendPrivate::setSessionCertificate(QString &errorDescription, QAbstractSocket::SocketError &errorCode)
-{
- Q_ASSERT_X(context, Q_FUNC_INFO, "invalid SSL context (null)");
-
- QSslCertificate localCertificate;
- if (!configuration.localCertificateChain.isEmpty())
- localCertificate = configuration.localCertificateChain.at(0);
-
- if (!localCertificate.isNull()) {
- // Require a private key as well.
- if (configuration.privateKey.isNull()) {
- errorCode = QAbstractSocket::SslInvalidUserDataError;
- errorDescription = QStringLiteral("Cannot provide a certificate with no key");
- return false;
- }
-
- // import certificates and key
- const QString passPhrase(QString::fromLatin1("foobar"));
- QCFType<CFDataRef> pkcs12 = _q_makePkcs12(configuration.localCertificateChain,
- configuration.privateKey, passPhrase).toCFData();
- QCFType<CFStringRef> password = passPhrase.toCFString();
- const void *keys[2] = { kSecImportExportPassphrase };
- const void *values[2] = { password };
- CFIndex nKeys = 1;
-#ifdef Q_OS_MACOS
- bool envOk = false;
- const int env = qEnvironmentVariableIntValue("QT_SSL_USE_TEMPORARY_KEYCHAIN", &envOk);
- if (envOk && env) {
- static const EphemeralSecKeychain temporaryKeychain;
- if (temporaryKeychain.keychain) {
- nKeys = 2;
- keys[1] = kSecImportExportKeychain;
- values[1] = temporaryKeychain.keychain;
- }
- }
-#endif
- QCFType<CFDictionaryRef> options = CFDictionaryCreate(nullptr, keys, values, nKeys,
- nullptr, nullptr);
- QCFType<CFArrayRef> items;
- OSStatus err = SecPKCS12Import(pkcs12, options, &items);
- if (err != errSecSuccess) {
-#ifdef QSSLSOCKET_DEBUG
- qCWarning(lcSsl) << plainSocket
- << QStringLiteral("SecPKCS12Import failed: %1").arg(err);
-#endif
- errorCode = QAbstractSocket::SslInvalidUserDataError;
- errorDescription = QStringLiteral("SecPKCS12Import failed: %1").arg(err);
- return false;
- }
-
- if (!CFArrayGetCount(items)) {
-#ifdef QSSLSOCKET_DEBUG
- qCWarning(lcSsl) << plainSocket << "SecPKCS12Import returned no items";
-#endif
- errorCode = QAbstractSocket::SslInvalidUserDataError;
- errorDescription = QStringLiteral("SecPKCS12Import returned no items");
- return false;
- }
-
- CFDictionaryRef import = (CFDictionaryRef)CFArrayGetValueAtIndex(items, 0);
- SecIdentityRef identity = (SecIdentityRef)CFDictionaryGetValue(import, kSecImportItemIdentity);
- if (!identity) {
-#ifdef QSSLSOCKET_DEBUG
- qCWarning(lcSsl) << plainSocket << "SecPKCS12Import returned no identity";
-#endif
- errorCode = QAbstractSocket::SslInvalidUserDataError;
- errorDescription = QStringLiteral("SecPKCS12Import returned no identity");
- return false;
- }
-
- QCFType<CFMutableArrayRef> certs = CFArrayCreateMutable(nullptr, 0, &kCFTypeArrayCallBacks);
- if (!certs) {
- errorCode = QAbstractSocket::SslInternalError;
- errorDescription = QStringLiteral("Failed to allocate certificates array");
- return false;
- }
-
- CFArrayAppendValue(certs, identity);
-
- CFArrayRef chain = (CFArrayRef)CFDictionaryGetValue(import, kSecImportItemCertChain);
- if (chain) {
- for (CFIndex i = 1, e = CFArrayGetCount(chain); i < e; ++i)
- CFArrayAppendValue(certs, CFArrayGetValueAtIndex(chain, i));
- }
-
- err = SSLSetCertificate(context, certs);
- if (err != errSecSuccess) {
-#ifdef QSSLSOCKET_DEBUG
- qCWarning(lcSsl) << plainSocket
- << QStringLiteral("Cannot set certificate and key: %1").arg(err);
-#endif
- errorCode = QAbstractSocket::SslInvalidUserDataError;
- errorDescription = QStringLiteral("Cannot set certificate and key: %1").arg(err);
- return false;
- }
- }
-
- return true;
-}
-
-bool QSslSocketBackendPrivate::setSessionProtocol()
-{
- Q_ASSERT_X(context, Q_FUNC_INFO, "invalid SSL context (null)");
-
- // SecureTransport has kTLSProtocol13 constant and also, kTLSProtocolMaxSupported.
- // Calling SSLSetProtocolVersionMax/Min with any of these two constants results
- // in errInvalidParam and a failure to set the protocol version. This means
- // no TLS 1.3 on macOS and iOS.
- switch (configuration.protocol) {
- case QSsl::TlsV1_3:
- case QSsl::TlsV1_3OrLater:
- qCWarning(lcSsl) << plainSocket << "SecureTransport does not support TLS 1.3";
- return false;
- default:;
- }
-
- OSStatus err = errSecSuccess;
-
- if (configuration.protocol == QSsl::TlsV1_0) {
- #ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "requesting : TLSv1.0";
- #endif
- err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
- if (err == errSecSuccess)
- err = SSLSetProtocolVersionMax(context, kTLSProtocol1);
- } else if (configuration.protocol == QSsl::TlsV1_1) {
- #ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "requesting : TLSv1.1";
- #endif
- err = SSLSetProtocolVersionMin(context, kTLSProtocol11);
- if (err == errSecSuccess)
- err = SSLSetProtocolVersionMax(context, kTLSProtocol11);
- } else if (configuration.protocol == QSsl::TlsV1_2) {
- #ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "requesting : TLSv1.2";
- #endif
- err = SSLSetProtocolVersionMin(context, kTLSProtocol12);
- if (err == errSecSuccess)
- err = SSLSetProtocolVersionMax(context, kTLSProtocol12);
- } else if (configuration.protocol == QSsl::AnyProtocol) {
- #ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "requesting : any";
- #endif
- err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
- } else if (configuration.protocol == QSsl::SecureProtocols) {
- #ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "requesting : TLSv1 - TLSv1.2";
- #endif
- err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
- } else if (configuration.protocol == QSsl::TlsV1_0OrLater) {
- #ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "requesting : TLSv1 - TLSv1.2";
- #endif
- err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
- } else if (configuration.protocol == QSsl::TlsV1_1OrLater) {
- #ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "requesting : TLSv1.1 - TLSv1.2";
- #endif
- err = SSLSetProtocolVersionMin(context, kTLSProtocol11);
- } else if (configuration.protocol == QSsl::TlsV1_2OrLater) {
- #ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "requesting : TLSv1.2";
- #endif
- err = SSLSetProtocolVersionMin(context, kTLSProtocol12);
- } else {
- #ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "no protocol version found in the configuration";
- #endif
- return false;
- }
-
- return err == errSecSuccess;
-}
-
-bool QSslSocketBackendPrivate::canIgnoreTrustVerificationFailure() const
-{
- const QSslSocket::PeerVerifyMode verifyMode = configuration.peerVerifyMode;
- return mode == QSslSocket::SslServerMode
- && (verifyMode == QSslSocket::QueryPeer
- || verifyMode == QSslSocket::AutoVerifyPeer
- || verifyMode == QSslSocket::VerifyNone);
-}
-
-bool QSslSocketBackendPrivate::verifySessionProtocol() const
-{
- bool protocolOk = false;
- if (configuration.protocol == QSsl::AnyProtocol)
- protocolOk = true;
- else if (configuration.protocol == QSsl::SecureProtocols)
- protocolOk = (sessionProtocol() >= QSsl::TlsV1_0);
- else if (configuration.protocol == QSsl::TlsV1_0OrLater)
- protocolOk = (sessionProtocol() >= QSsl::TlsV1_0);
- else if (configuration.protocol == QSsl::TlsV1_1OrLater)
- protocolOk = (sessionProtocol() >= QSsl::TlsV1_1);
- else if (configuration.protocol == QSsl::TlsV1_2OrLater)
- protocolOk = (sessionProtocol() >= QSsl::TlsV1_2);
- else if (configuration.protocol == QSsl::TlsV1_3OrLater)
- protocolOk = (sessionProtocol() >= QSsl::TlsV1_3OrLater);
- else
- protocolOk = (sessionProtocol() == configuration.protocol);
-
- return protocolOk;
-}
-
-bool QSslSocketBackendPrivate::verifyPeerTrust()
-{
- Q_Q(QSslSocket);
-
- const QSslSocket::PeerVerifyMode verifyMode = configuration.peerVerifyMode;
- const bool canIgnoreVerify = canIgnoreTrustVerificationFailure();
-
- Q_ASSERT_X(context, Q_FUNC_INFO, "invalid SSL context (null)");
- Q_ASSERT(plainSocket);
-
- QCFType<SecTrustRef> trust;
- OSStatus err = SSLCopyPeerTrust(context, &trust);
- // !trust - SSLCopyPeerTrust can return errSecSuccess but null trust.
- if (err != errSecSuccess || !trust) {
- if (!canIgnoreVerify) {
- setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
- QStringLiteral("Failed to obtain peer trust: %1").arg(err));
- plainSocket->disconnectFromHost();
- return false;
- } else {
- return true;
- }
- }
-
- QList<QSslError> errors;
-
- // Store certificates.
- // Apple's docs say SetTrustEvaluate must be called before
- // SecTrustGetCertificateAtIndex, but this results
- // in 'kSecTrustResultRecoverableTrustFailure', so
- // here we just ignore 'res' (later we'll use SetAnchor etc.
- // and evaluate again).
- SecTrustResultType res = kSecTrustResultInvalid;
- err = SecTrustEvaluate(trust, &res);
- if (err != errSecSuccess) {
- // We can not ignore this, it's not even about trust verification
- // probably ...
- setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
- QStringLiteral("SecTrustEvaluate failed: %1").arg(err));
- plainSocket->disconnectFromHost();
- return false;
- }
-
- configuration.peerCertificate.clear();
- configuration.peerCertificateChain.clear();
-
- const CFIndex certCount = SecTrustGetCertificateCount(trust);
- for (CFIndex i = 0; i < certCount; ++i) {
- SecCertificateRef cert = SecTrustGetCertificateAtIndex(trust, i);
- QCFType<CFDataRef> derData = SecCertificateCopyData(cert);
- configuration.peerCertificateChain << QSslCertificate(QByteArray::fromCFData(derData), QSsl::Der);
- }
-
- if (configuration.peerCertificateChain.size())
- configuration.peerCertificate = configuration.peerCertificateChain.at(0);
-
- // Check the whole chain for blacklisting (including root, as we check for subjectInfo and issuer):
- for (const QSslCertificate &cert : qAsConst(configuration.peerCertificateChain)) {
- if (QSslCertificatePrivate::isBlacklisted(cert) && !canIgnoreVerify) {
- const QSslError error(QSslError::CertificateBlacklisted, cert);
- errors << error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
- }
-
- const bool doVerifyPeer = verifyMode == QSslSocket::VerifyPeer
- || (verifyMode == QSslSocket::AutoVerifyPeer
- && mode == QSslSocket::SslClientMode);
- // Check the peer certificate itself. First try the subject's common name
- // (CN) as a wildcard, then try all alternate subject name DNS entries the
- // same way.
- if (!configuration.peerCertificate.isNull()) {
- // but only if we're a client connecting to a server
- // if we're the server, don't check CN
- if (mode == QSslSocket::SslClientMode) {
- const QString peerName(verificationPeerName.isEmpty () ? q->peerName() : verificationPeerName);
- if (!isMatchingHostname(configuration.peerCertificate, peerName) && !canIgnoreVerify) {
- // No matches in common names or alternate names.
- const QSslError error(QSslError::HostNameMismatch, configuration.peerCertificate);
- errors << error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
- }
- } else {
- // No peer certificate presented. Report as error if the socket
- // expected one.
- if (doVerifyPeer && !canIgnoreVerify) {
- const QSslError error(QSslError::NoPeerCertificate);
- errors << error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
- }
-
- // verify certificate chain
- QCFType<CFMutableArrayRef> certArray = CFArrayCreateMutable(nullptr, 0, &kCFTypeArrayCallBacks);
- for (const QSslCertificate &cert : qAsConst(configuration.caCertificates)) {
- QCFType<CFDataRef> certData = cert.d->derData.toCFData();
- if (QCFType<SecCertificateRef> secRef = SecCertificateCreateWithData(nullptr, certData))
- CFArrayAppendValue(certArray, secRef);
- else
- qCWarning(lcSsl, "Failed to create SecCertificate from QSslCertificate");
- }
-
- SecTrustSetAnchorCertificates(trust, certArray);
-
- // By default SecTrustEvaluate uses both CA certificates provided in
- // QSslConfiguration and the ones from the system database. This behavior can
- // be unexpected if a user's code tries to limit the trusted CAs to those
- // explicitly set in QSslConfiguration.
- // Since on macOS we initialize the default QSslConfiguration copying the
- // system CA certificates (using SecTrustSettingsCopyCertificates) we can
- // call SecTrustSetAnchorCertificatesOnly(trust, true) to force SecTrustEvaluate
- // to use anchors only from our QSslConfiguration.
- // Unfortunately, SecTrustSettingsCopyCertificates is not available on iOS
- // and the default QSslConfiguration always has an empty list of system CA
- // certificates. This leaves no way to provide client code with access to the
- // actual system CA certificate list (which most use-cases need) other than
- // by letting SecTrustEvaluate fall through to the system list; so, in this case
- // (even though the client code may have provided its own certs), we retain
- // the default behavior. Note, with macOS SDK below 10.12 using 'trust my
- // anchors only' may result in some valid chains rejected, apparently the
- // ones containing intermediated certificates; so we use this functionality
- // on more recent versions only.
-
- bool anchorsFromConfigurationOnly = false;
-
-#ifdef Q_OS_MACOS
- if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSSierra)
- anchorsFromConfigurationOnly = true;
-#endif // Q_OS_MACOS
-
- SecTrustSetAnchorCertificatesOnly(trust, anchorsFromConfigurationOnly);
-
- SecTrustResultType trustResult = kSecTrustResultInvalid;
- SecTrustEvaluate(trust, &trustResult);
- switch (trustResult) {
- case kSecTrustResultUnspecified:
- case kSecTrustResultProceed:
- break;
- default:
- if (!canIgnoreVerify) {
- const QSslError error(QSslError::CertificateUntrusted, configuration.peerCertificate);
- errors << error;
- emit q->peerVerifyError(error);
- }
- }
-
- // report errors
- if (!errors.isEmpty() && !canIgnoreVerify) {
- sslErrors = errors;
- // checkSslErrors unconditionally emits sslErrors:
- // a user's slot can abort/close/disconnect on this
- // signal, so we also test the socket's state:
- if (!checkSslErrors() || q->state() != QAbstractSocket::ConnectedState)
- return false;
- } else {
- sslErrors.clear();
- }
-
- return true;
-}
-
-/*
- Copied verbatim from qsslsocket_openssl.cpp
-*/
-bool QSslSocketBackendPrivate::checkSslErrors()
-{
- Q_Q(QSslSocket);
- if (sslErrors.isEmpty())
- return true;
-
- emit q->sslErrors(sslErrors);
-
- const bool doVerifyPeer = configuration.peerVerifyMode == QSslSocket::VerifyPeer
- || (configuration.peerVerifyMode == QSslSocket::AutoVerifyPeer
- && mode == QSslSocket::SslClientMode);
- const bool doEmitSslError = !verifyErrorsHaveBeenIgnored();
- // check whether we need to emit an SSL handshake error
- if (doVerifyPeer && doEmitSslError) {
- if (q->pauseMode() & QAbstractSocket::PauseOnSslErrors) {
- pauseSocketNotifiers(q);
- paused = true;
- } else {
- setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
- sslErrors.constFirst().errorString());
- plainSocket->disconnectFromHost();
- }
- return false;
- }
-
- return true;
-}
-
-bool QSslSocketBackendPrivate::startHandshake()
-{
- Q_ASSERT(context);
- Q_Q(QSslSocket);
-
- OSStatus err = SSLHandshake(context);
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "SSLHandhake returned" << err;
-#endif
-
- if (err == errSSLWouldBlock) {
- // startHandshake has to be called again ... later.
- return false;
- } else if (err == errSSLServerAuthCompleted) {
- // errSSLServerAuthCompleted is a define for errSSLPeerAuthCompleted,
- // it works for both server/client modes.
- // In future we'll evaluate peer's trust at this point,
- // for now we just continue.
- // if (!verifyPeerTrust())
- // ...
- return startHandshake();
- } else if (err == errSSLClientCertRequested) {
- Q_ASSERT(mode == QSslSocket::SslClientMode);
- QString errorDescription;
- QAbstractSocket::SocketError errorCode = QAbstractSocket::UnknownSocketError;
- // setSessionCertificate does not fail if we have no certificate.
- // Failure means a real error (invalid certificate, no private key, etc).
- if (!setSessionCertificate(errorDescription, errorCode)) {
- setErrorAndEmit(errorCode, errorDescription);
- renegotiating = false;
- return false;
- } else {
- // We try to resume a handshake, even if have no
- // local certificates ... (up to server to deal with our failure).
- return startHandshake();
- }
- } else if (err != errSecSuccess) {
- if (err == errSSLBadCert && canIgnoreTrustVerificationFailure()) {
- // We're on the server side and client did not provide any
- // certificate. This is the new 'nice' error returned by
- // Security Framework after it was recently updated.
- return startHandshake();
- }
-
- renegotiating = false;
- setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
- QStringLiteral("SSLHandshake failed: %1").arg(err));
- plainSocket->disconnectFromHost();
- return false;
- }
-
- // Connection aborted during handshake phase.
- if (q->state() != QAbstractSocket::ConnectedState) {
- qCDebug(lcSsl) << "connection aborted";
- renegotiating = false;
- return false;
- }
-
- // check protocol version ourselves, as Secure Transport does not enforce
- // the requested min / max versions.
- if (!verifySessionProtocol()) {
- setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError, QStringLiteral("Protocol version mismatch"));
- plainSocket->disconnectFromHost();
- renegotiating = false;
- return false;
- }
-
- if (verifyPeerTrust()) {
- continueHandshake();
- renegotiating = false;
- return true;
- } else {
- renegotiating = false;
- return false;
- }
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslsocket_mac_p.h b/src/network/ssl/qsslsocket_mac_p.h
deleted file mode 100644
index dcd4f4de72..0000000000
--- a/src/network/ssl/qsslsocket_mac_p.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Jeremy Lainé <jeremy.laine@m4x.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QSSLSOCKET_MAC_P_H
-#define QSSLSOCKET_MAC_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists for the convenience
-// of the QtNetwork library. This header file may change from
-// version to version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtNetwork/private/qtnetworkglobal_p.h>
-#include <QtCore/qstring.h>
-#include <QtCore/qglobal.h>
-#include <QtCore/qlist.h>
-
-#include "qabstractsocket.h"
-#include "qsslsocket_p.h"
-
-#include <Security/Security.h>
-#include <Security/SecureTransport.h>
-
-QT_BEGIN_NAMESPACE
-
-class QSecureTransportContext
-{
-public:
- explicit QSecureTransportContext(SSLContextRef context);
- ~QSecureTransportContext();
-
- operator SSLContextRef () const;
- void reset(SSLContextRef newContext);
-private:
- SSLContextRef context;
-
- Q_DISABLE_COPY_MOVE(QSecureTransportContext)
-};
-
-class QSslSocketBackendPrivate : public QSslSocketPrivate
-{
- Q_DECLARE_PUBLIC(QSslSocket)
-public:
- QSslSocketBackendPrivate();
- virtual ~QSslSocketBackendPrivate();
-
- // Final-overriders (QSslSocketPrivate):
- void continueHandshake() override;
- void disconnected() override;
- void disconnectFromHost() override;
- QSslCipher sessionCipher() const override;
- QSsl::SslProtocol sessionProtocol() const override;
- void startClientEncryption() override;
- void startServerEncryption() override;
- void transmit() override;
-
- static QList<QSslError> verify(QList<QSslCertificate> certificateChain,
- const QString &hostName);
-
- static bool importPkcs12(QIODevice *device,
- QSslKey *key, QSslCertificate *cert,
- QList<QSslCertificate> *caCertificates,
- const QByteArray &passPhrase);
-
- static QSslCipher QSslCipher_from_SSLCipherSuite(SSLCipherSuite cipher);
- static SSLCipherSuite SSLCipherSuite_from_QSslCipher(const QSslCipher &cipher);
-
-private:
- // SSL context management/properties:
- bool initSslContext();
- void destroySslContext();
- bool setSessionCertificate(QString &errorDescription,
- QAbstractSocket::SocketError &errorCode);
- bool setSessionProtocol();
- // Aux. functions to do a verification during handshake phase:
- bool canIgnoreTrustVerificationFailure() const;
- bool verifySessionProtocol() const;
- bool verifyPeerTrust();
-
- bool checkSslErrors();
- bool startHandshake();
-
- bool isHandshakeComplete() const {return connectionEncrypted && !renegotiating;}
-
- // IO callbacks:
- static OSStatus ReadCallback(QSslSocketBackendPrivate *socket, char *data, size_t *dataLength);
- static OSStatus WriteCallback(QSslSocketBackendPrivate *plainSocket, const char *data, size_t *dataLength);
-
- QSecureTransportContext context;
- bool renegotiating = false;
-
- Q_DISABLE_COPY_MOVE(QSslSocketBackendPrivate)
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/network/ssl/qsslsocket_mac_shared.cpp b/src/network/ssl/qsslsocket_mac_shared.cpp
deleted file mode 100644
index 0bc4647e8b..0000000000
--- a/src/network/ssl/qsslsocket_mac_shared.cpp
+++ /dev/null
@@ -1,155 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2015 ownCloud Inc
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//#define QSSLSOCKET_DEBUG
-//#define QT_DECRYPT_SSL_TRAFFIC
-
-#include "qssl_p.h"
-#include "qsslsocket.h"
-
-#ifndef QT_NO_OPENSSL
-# include "qsslsocket_openssl_p.h"
-# include "qsslsocket_openssl_symbols_p.h"
-#endif
-
-#include "qsslcertificate_p.h"
-
-#ifdef Q_OS_DARWIN
-# include <private/qcore_mac_p.h>
-#endif
-
-#include <QtCore/qdebug.h>
-
-#ifdef Q_OS_MACOS
-# include <Security/Security.h>
-#endif
-
-
-QT_BEGIN_NAMESPACE
-
-#ifdef Q_OS_MACOS
-namespace {
-
-bool hasTrustedSslServerPolicy(SecPolicyRef policy, CFDictionaryRef props) {
- QCFType<CFDictionaryRef> policyProps = SecPolicyCopyProperties(policy);
- // only accept certificates with policies for SSL server validation for now
- if (CFEqual(CFDictionaryGetValue(policyProps, kSecPolicyOid), kSecPolicyAppleSSL)) {
- CFBooleanRef policyClient;
- if (CFDictionaryGetValueIfPresent(policyProps, kSecPolicyClient, reinterpret_cast<const void**>(&policyClient)) &&
- CFEqual(policyClient, kCFBooleanTrue)) {
- return false; // no client certs
- }
- if (!CFDictionaryContainsKey(props, kSecTrustSettingsResult)) {
- // as per the docs, no trust settings result implies full trust
- return true;
- }
- CFNumberRef number = static_cast<CFNumberRef>(CFDictionaryGetValue(props, kSecTrustSettingsResult));
- SecTrustSettingsResult settingsResult;
- CFNumberGetValue(number, kCFNumberSInt32Type, &settingsResult);
- switch (settingsResult) {
- case kSecTrustSettingsResultTrustRoot:
- case kSecTrustSettingsResultTrustAsRoot:
- return true;
- default:
- return false;
- }
- }
- return false;
-}
-
-bool isCaCertificateTrusted(SecCertificateRef cfCert, int domain)
-{
- QCFType<CFArrayRef> cfTrustSettings;
- OSStatus status = SecTrustSettingsCopyTrustSettings(cfCert, SecTrustSettingsDomain(domain), &cfTrustSettings);
- if (status == noErr) {
- CFIndex size = CFArrayGetCount(cfTrustSettings);
- // if empty, trust for everything (as per the Security Framework documentation)
- if (size == 0) {
- return true;
- } else {
- for (CFIndex i = 0; i < size; ++i) {
- CFDictionaryRef props = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(cfTrustSettings, i));
- if (CFDictionaryContainsKey(props, kSecTrustSettingsPolicy)) {
- if (hasTrustedSslServerPolicy((SecPolicyRef)CFDictionaryGetValue(props, kSecTrustSettingsPolicy), props))
- return true;
- }
- }
- }
- } else {
- qCWarning(lcSsl, "Error receiving trust for a CA certificate");
- }
- return false;
-}
-
-} // anon namespace
-#endif // Q_OS_MACOS
-
-QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
-{
- ensureInitialized();
-
- QList<QSslCertificate> systemCerts;
- // SecTrustSettingsCopyCertificates is not defined on iOS.
-#ifdef Q_OS_MACOS
- // iterate through all enum members, order:
- // kSecTrustSettingsDomainUser, kSecTrustSettingsDomainAdmin, kSecTrustSettingsDomainSystem
- for (int dom = kSecTrustSettingsDomainUser; dom <= int(kSecTrustSettingsDomainSystem); dom++) {
- QCFType<CFArrayRef> cfCerts;
- OSStatus status = SecTrustSettingsCopyCertificates(SecTrustSettingsDomain(dom), &cfCerts);
- if (status == noErr) {
- const CFIndex size = CFArrayGetCount(cfCerts);
- for (CFIndex i = 0; i < size; ++i) {
- SecCertificateRef cfCert = (SecCertificateRef)CFArrayGetValueAtIndex(cfCerts, i);
- QCFType<CFDataRef> derData = SecCertificateCopyData(cfCert);
- if (isCaCertificateTrusted(cfCert, dom)) {
- if (derData == NULL) {
- qCWarning(lcSsl, "Error retrieving a CA certificate from the system store");
- } else {
- systemCerts << QSslCertificate(QByteArray::fromCFData(derData), QSsl::Der);
- }
- }
- }
- }
- }
-#endif
- return systemCerts;
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
deleted file mode 100644
index c5f82502fc..0000000000
--- a/src/network/ssl/qsslsocket_openssl.cpp
+++ /dev/null
@@ -1,2508 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Copyright (C) 2014 Governikus GmbH & Co. KG
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-/****************************************************************************
-**
-** 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.
-**
-****************************************************************************/
-
-//#define QSSLSOCKET_DEBUG
-
-#include "qssl_p.h"
-#include "qsslsocket_openssl_p.h"
-#include "qsslsocket_openssl_symbols_p.h"
-#include "qsslsocket.h"
-#include "qsslcertificate_p.h"
-#include "qsslcipher_p.h"
-#include "qsslkey_p.h"
-#include "qsslellipticcurve.h"
-#include "qsslpresharedkeyauthenticator.h"
-#include "qsslpresharedkeyauthenticator_p.h"
-#include "qocspresponse_p.h"
-#include "qsslkey.h"
-
-#ifdef Q_OS_WIN
-#include "qwindowscarootfetcher_p.h"
-#endif
-
-#include <QtCore/qdatetime.h>
-#include <QtCore/qdebug.h>
-#include <QtCore/qdir.h>
-#include <QtCore/qdiriterator.h>
-#include <QtCore/qelapsedtimer.h>
-#include <QtCore/qfile.h>
-#include <QtCore/qfileinfo.h>
-#include <QtCore/qmutex.h>
-#include <QtCore/qthread.h>
-#include <QtCore/qurl.h>
-#include <QtCore/qvarlengtharray.h>
-#include <QtCore/qscopedvaluerollback.h>
-#include <QtCore/qscopeguard.h>
-#include <QtCore/qlibrary.h>
-#include <QtCore/qoperatingsystemversion.h>
-
-#if QT_CONFIG(ocsp)
-#include "qocsp_p.h"
-#endif
-
-#include <algorithm>
-#include <memory>
-
-#include <string.h>
-
-QT_BEGIN_NAMESPACE
-
-namespace {
-
-QSsl::AlertLevel tlsAlertLevel(int value)
-{
- using QSsl::AlertLevel;
-
- if (const char *typeString = q_SSL_alert_type_string(value)) {
- // Documented to return 'W' for warning, 'F' for fatal,
- // 'U' for unknown.
- switch (typeString[0]) {
- case 'W':
- return AlertLevel::Warning;
- case 'F':
- return AlertLevel::Fatal;
- default:;
- }
- }
-
- return AlertLevel::Unknown;
-}
-
-QString tlsAlertDescription(int value)
-{
- QString description = QLatin1String(q_SSL_alert_desc_string_long(value));
- if (!description.size())
- description = QLatin1String("no description provided");
- return description;
-}
-
-QSsl::AlertType tlsAlertType(int value)
-{
- // In case for some reason openssl gives us a value,
- // which is not in our enum actually, we leave it to
- // an application to handle (supposedly they have
- // if or switch-statements).
- return QSsl::AlertType(value & 0xff);
-}
-
-#ifdef Q_OS_WIN
-
-QSslCertificate findCertificateToFetch(const QList<QSslError> &tlsErrors, bool checkAIA)
-{
- QSslCertificate certToFetch;
-
- for (const auto &tlsError : tlsErrors) {
- switch (tlsError.error()) {
- case QSslError::UnableToGetLocalIssuerCertificate: // site presented intermediate cert, but root is unknown
- case QSslError::SelfSignedCertificateInChain: // site presented a complete chain, but root is unknown
- certToFetch = tlsError.certificate();
- break;
- case QSslError::SelfSignedCertificate:
- case QSslError::CertificateBlacklisted:
- //With these errors, we know it will be untrusted so save time by not asking windows
- return QSslCertificate{};
- default:
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << tlsError.errorString();
-#endif
- //TODO - this part is strange.
- break;
- }
- }
-
- if (checkAIA) {
- const auto extensions = certToFetch.extensions();
- for (const auto &ext : extensions) {
- if (ext.oid() == QStringLiteral("1.3.6.1.5.5.7.1.1")) // See RFC 4325
- return certToFetch;
- }
- //The only reason we check this extensions is because an application set trusted
- //CA certificates explicitly, thus technically disabling CA fetch. So, if it's
- //the case and an intermediate certificate is missing, and no extensions is
- //present on the leaf certificate - we fail the handshake immediately.
- return QSslCertificate{};
- }
-
- return certToFetch;
-}
-
-#endif // Q_OS_WIN
-
-} // Unnamed namespace
-
-extern "C"
-{
-
-void qt_AlertInfoCallback(const SSL *connection, int from, int value)
-{
- // Passed to SSL_set_info_callback()
- // https://www.openssl.org/docs/man1.1.1/man3/SSL_set_info_callback.html
-
- if (!connection) {
-#ifdef QSSLSOCKET_DEBUG
- qCWarning(lcSsl, "Invalid 'connection' parameter (nullptr)");
-#endif // QSSLSOCKET_DEBUG
- return;
- }
-
- const auto offset = QSslSocketBackendPrivate::s_indexForSSLExtraData
- + QSslSocketBackendPrivate::socketOffsetInExData;
- auto privateSocket =
- static_cast<QSslSocketBackendPrivate *>(q_SSL_get_ex_data(connection, offset));
- if (!privateSocket) {
- // SSL_set_ex_data can fail:
-#ifdef QSSLSOCKET_DEBUG
- qCWarning(lcSsl, "No external data (socket backend) found for parameter 'connection'");
-#endif // QSSLSOCKET_DEBUG
- return;
- }
-
- if (!(from & SSL_CB_ALERT)) {
- // We only want to know about alerts (at least for now).
- return;
- }
-
- if (from & SSL_CB_WRITE)
- privateSocket->alertMessageSent(value);
- else
- privateSocket->alertMessageReceived(value);
-}
-
-int q_X509CallbackDirect(int ok, X509_STORE_CTX *ctx)
-{
- // Passed to SSL_CTX_set_verify()
- // https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_verify.html
- // Returns 0 to abort verification, 1 to continue.
-
- // This is a new, experimental verification callback, reporting
- // errors immediately and returning 0 or 1 depending on an application
- // either ignoring or not ignoring verification errors as they come.
- if (!ctx) {
- qCWarning(lcSsl, "Invalid store context (nullptr)");
- return 0;
- }
-
- if (!ok) {
- // "Whenever a X509_STORE_CTX object is created for the verification of the
- // peer's certificate during a handshake, a pointer to the SSL object is
- // stored into the X509_STORE_CTX object to identify the connection affected.
- // To retrieve this pointer the X509_STORE_CTX_get_ex_data() function can be
- // used with the correct index."
- SSL *ssl = static_cast<SSL *>(q_X509_STORE_CTX_get_ex_data(ctx, q_SSL_get_ex_data_X509_STORE_CTX_idx()));
- if (!ssl) {
- qCWarning(lcSsl, "No external data (SSL) found in X509 store object");
- return 0;
- }
-
- const auto offset = QSslSocketBackendPrivate::s_indexForSSLExtraData
- + QSslSocketBackendPrivate::socketOffsetInExData;
- auto privateSocket = static_cast<QSslSocketBackendPrivate *>(q_SSL_get_ex_data(ssl, offset));
- if (!privateSocket) {
- qCWarning(lcSsl, "No external data (QSslSocketBackendPrivate) found in SSL object");
- return 0;
- }
-
- return privateSocket->emitErrorFromCallback(ctx);
- }
- return 1;
-}
-
-} // extern "C"
-
-Q_GLOBAL_STATIC(QRecursiveMutex, qt_opensslInitMutex)
-
-bool QSslSocketPrivate::s_libraryLoaded = false;
-bool QSslSocketPrivate::s_loadedCiphersAndCerts = false;
-bool QSslSocketPrivate::s_loadRootCertsOnDemand = false;
-int QSslSocketBackendPrivate::s_indexForSSLExtraData = -1;
-
-QString QSslSocketBackendPrivate::getErrorsFromOpenSsl()
-{
- QString errorString;
- char buf[256] = {}; // OpenSSL docs claim both 120 and 256; use the larger.
- unsigned long errNum;
- while ((errNum = q_ERR_get_error())) {
- if (!errorString.isEmpty())
- errorString.append(QLatin1String(", "));
- q_ERR_error_string_n(errNum, buf, sizeof buf);
- errorString.append(QString::fromLatin1(buf)); // error is ascii according to man ERR_error_string
- }
- return errorString;
-}
-
-void QSslSocketBackendPrivate::logAndClearErrorQueue()
-{
- const auto errors = getErrorsFromOpenSsl();
- if (errors.size())
- qCWarning(lcSsl) << "Discarding errors:" << errors;
-}
-
-extern "C" {
-
-#ifndef OPENSSL_NO_PSK
-static unsigned int q_ssl_psk_client_callback(SSL *ssl,
- const char *hint,
- char *identity, unsigned int max_identity_len,
- unsigned char *psk, unsigned int max_psk_len)
-{
- QSslSocketBackendPrivate *d = reinterpret_cast<QSslSocketBackendPrivate *>(q_SSL_get_ex_data(ssl, QSslSocketBackendPrivate::s_indexForSSLExtraData));
- Q_ASSERT(d);
- return d->tlsPskClientCallback(hint, identity, max_identity_len, psk, max_psk_len);
-}
-
-static unsigned int q_ssl_psk_server_callback(SSL *ssl,
- const char *identity,
- unsigned char *psk, unsigned int max_psk_len)
-{
- QSslSocketBackendPrivate *d = reinterpret_cast<QSslSocketBackendPrivate *>(q_SSL_get_ex_data(ssl, QSslSocketBackendPrivate::s_indexForSSLExtraData));
- Q_ASSERT(d);
- return d->tlsPskServerCallback(identity, psk, max_psk_len);
-}
-
-#ifdef TLS1_3_VERSION
-static unsigned int q_ssl_psk_restore_client(SSL *ssl,
- const char *hint,
- char *identity, unsigned int max_identity_len,
- unsigned char *psk, unsigned int max_psk_len)
-{
- Q_UNUSED(hint);
- Q_UNUSED(identity);
- Q_UNUSED(max_identity_len);
- Q_UNUSED(psk);
- Q_UNUSED(max_psk_len);
-
-#ifdef QT_DEBUG
- QSslSocketBackendPrivate *d = reinterpret_cast<QSslSocketBackendPrivate *>(q_SSL_get_ex_data(ssl, QSslSocketBackendPrivate::s_indexForSSLExtraData));
- Q_ASSERT(d);
- Q_ASSERT(d->mode == QSslSocket::SslClientMode);
-#endif
- q_SSL_set_psk_client_callback(ssl, &q_ssl_psk_client_callback);
-
- return 0;
-}
-
-static int q_ssl_psk_use_session_callback(SSL *ssl, const EVP_MD *md, const unsigned char **id,
- size_t *idlen, SSL_SESSION **sess)
-{
- Q_UNUSED(ssl);
- Q_UNUSED(md);
- Q_UNUSED(id);
- Q_UNUSED(idlen);
- Q_UNUSED(sess);
-
-#ifdef QT_DEBUG
- QSslSocketBackendPrivate *d = reinterpret_cast<QSslSocketBackendPrivate *>(q_SSL_get_ex_data(ssl, QSslSocketBackendPrivate::s_indexForSSLExtraData));
- Q_ASSERT(d);
- Q_ASSERT(d->mode == QSslSocket::SslClientMode);
-#endif
-
- // Temporarily rebind the psk because it will be called next. The function will restore it.
- q_SSL_set_psk_client_callback(ssl, &q_ssl_psk_restore_client);
-
- return 1; // need to return 1 or else "the connection setup fails."
-}
-
-int q_ssl_sess_set_new_cb(SSL *ssl, SSL_SESSION *session)
-{
- if (!ssl) {
- qCWarning(lcSsl, "Invalid SSL (nullptr)");
- return 0;
- }
- if (!session) {
- qCWarning(lcSsl, "Invalid SSL_SESSION (nullptr)");
- return 0;
- }
-
- auto socketPrivate = static_cast<QSslSocketBackendPrivate *>(q_SSL_get_ex_data(ssl,
- QSslSocketBackendPrivate::s_indexForSSLExtraData));
- return socketPrivate->handleNewSessionTicket(ssl);
-}
-#endif // TLS1_3_VERSION
-
-#endif // !OPENSSL_NO_PSK
-
-#if QT_CONFIG(ocsp)
-
-int qt_OCSP_status_server_callback(SSL *ssl, void *ocspRequest)
-{
- Q_UNUSED(ocspRequest);
- if (!ssl)
- return SSL_TLSEXT_ERR_ALERT_FATAL;
-
- auto d = static_cast<QSslSocketBackendPrivate *>(q_SSL_get_ex_data(ssl, QSslSocketBackendPrivate::s_indexForSSLExtraData));
- if (!d)
- return SSL_TLSEXT_ERR_ALERT_FATAL;
-
- Q_ASSERT(d->mode == QSslSocket::SslServerMode);
- const QByteArray &response = d->ocspResponseDer;
- Q_ASSERT(response.size());
-
- unsigned char *derCopy = static_cast<unsigned char *>(q_OPENSSL_malloc(size_t(response.size())));
- if (!derCopy)
- return SSL_TLSEXT_ERR_ALERT_FATAL;
-
- std::copy(response.data(), response.data() + response.size(), derCopy);
- // We don't check the return value: internally OpenSSL simply assignes the
- // pointer (it assumes it now owns this memory btw!) and the length.
- q_SSL_set_tlsext_status_ocsp_resp(ssl, derCopy, response.size());
-
- return SSL_TLSEXT_ERR_OK;
-}
-
-#endif // ocsp
-
-} // extern "C"
-
-QSslSocketBackendPrivate::QSslSocketBackendPrivate()
- : ssl(nullptr),
- readBio(nullptr),
- writeBio(nullptr),
- session(nullptr)
-{
- // Calls SSL_library_init().
- ensureInitialized();
-}
-
-QSslSocketBackendPrivate::~QSslSocketBackendPrivate()
-{
- destroySslContext();
-}
-
-QSslCipher QSslSocketBackendPrivate::QSslCipher_from_SSL_CIPHER(const SSL_CIPHER *cipher)
-{
- QSslCipher ciph;
-
- char buf [256];
- QString descriptionOneLine = QString::fromLatin1(q_SSL_CIPHER_description(cipher, buf, sizeof(buf)));
-
- const auto descriptionList = QStringView{descriptionOneLine}.split(QLatin1Char(' '), Qt::SkipEmptyParts);
- if (descriptionList.size() > 5) {
- // ### crude code.
- ciph.d->isNull = false;
- ciph.d->name = descriptionList.at(0).toString();
-
- QString protoString = descriptionList.at(1).toString();
- ciph.d->protocolString = protoString;
- ciph.d->protocol = QSsl::UnknownProtocol;
- if (protoString == QLatin1String("TLSv1"))
- ciph.d->protocol = QSsl::TlsV1_0;
- else if (protoString == QLatin1String("TLSv1.1"))
- ciph.d->protocol = QSsl::TlsV1_1;
- else if (protoString == QLatin1String("TLSv1.2"))
- ciph.d->protocol = QSsl::TlsV1_2;
- else if (protoString == QLatin1String("TLSv1.3"))
- ciph.d->protocol = QSsl::TlsV1_3;
-
- if (descriptionList.at(2).startsWith(QLatin1String("Kx=")))
- ciph.d->keyExchangeMethod = descriptionList.at(2).mid(3).toString();
- if (descriptionList.at(3).startsWith(QLatin1String("Au=")))
- ciph.d->authenticationMethod = descriptionList.at(3).mid(3).toString();
- if (descriptionList.at(4).startsWith(QLatin1String("Enc=")))
- ciph.d->encryptionMethod = descriptionList.at(4).mid(4).toString();
- ciph.d->exportable = (descriptionList.size() > 6 && descriptionList.at(6) == QLatin1String("export"));
-
- ciph.d->bits = q_SSL_CIPHER_get_bits(cipher, &ciph.d->supportedBits);
- }
- return ciph;
-}
-
-QSslErrorEntry QSslErrorEntry::fromStoreContext(X509_STORE_CTX *ctx)
-{
- return {
- q_X509_STORE_CTX_get_error(ctx),
- q_X509_STORE_CTX_get_error_depth(ctx)
- };
-}
-
-#if QT_CONFIG(ocsp)
-
-QSslError::SslError qt_OCSP_response_status_to_SslError(long code)
-{
- switch (code) {
- case OCSP_RESPONSE_STATUS_MALFORMEDREQUEST:
- return QSslError::OcspMalformedRequest;
- case OCSP_RESPONSE_STATUS_INTERNALERROR:
- return QSslError::OcspInternalError;
- case OCSP_RESPONSE_STATUS_TRYLATER:
- return QSslError::OcspTryLater;
- case OCSP_RESPONSE_STATUS_SIGREQUIRED:
- return QSslError::OcspSigRequred;
- case OCSP_RESPONSE_STATUS_UNAUTHORIZED:
- return QSslError::OcspUnauthorized;
- case OCSP_RESPONSE_STATUS_SUCCESSFUL:
- default:
- return {};
- }
- Q_UNREACHABLE();
-}
-
-QOcspRevocationReason qt_OCSP_revocation_reason(int reason)
-{
- switch (reason) {
- case OCSP_REVOKED_STATUS_NOSTATUS:
- return QOcspRevocationReason::None;
- case OCSP_REVOKED_STATUS_UNSPECIFIED:
- return QOcspRevocationReason::Unspecified;
- case OCSP_REVOKED_STATUS_KEYCOMPROMISE:
- return QOcspRevocationReason::KeyCompromise;
- case OCSP_REVOKED_STATUS_CACOMPROMISE:
- return QOcspRevocationReason::CACompromise;
- case OCSP_REVOKED_STATUS_AFFILIATIONCHANGED:
- return QOcspRevocationReason::AffiliationChanged;
- case OCSP_REVOKED_STATUS_SUPERSEDED:
- return QOcspRevocationReason::Superseded;
- case OCSP_REVOKED_STATUS_CESSATIONOFOPERATION:
- return QOcspRevocationReason::CessationOfOperation;
- case OCSP_REVOKED_STATUS_CERTIFICATEHOLD:
- return QOcspRevocationReason::CertificateHold;
- case OCSP_REVOKED_STATUS_REMOVEFROMCRL:
- return QOcspRevocationReason::RemoveFromCRL;
- default:
- return QOcspRevocationReason::None;
- }
-
- Q_UNREACHABLE();
-}
-
-bool qt_OCSP_certificate_match(OCSP_SINGLERESP *singleResponse, X509 *peerCert, X509 *issuer)
-{
- // OCSP_basic_verify does verify that the responder is legit, the response is
- // correctly signed, CertID is correct. But it does not know which certificate
- // we were presented with by our peer, so it does not check if it's a response
- // for our peer's certificate.
- Q_ASSERT(singleResponse && peerCert && issuer);
-
- const OCSP_CERTID *certId = q_OCSP_SINGLERESP_get0_id(singleResponse); // Does not increment refcount.
- if (!certId) {
- qCWarning(lcSsl, "A SingleResponse without CertID");
- return false;
- }
-
- ASN1_OBJECT *md = nullptr;
- ASN1_INTEGER *reportedSerialNumber = nullptr;
- const int result = q_OCSP_id_get0_info(nullptr, &md, nullptr, &reportedSerialNumber, const_cast<OCSP_CERTID *>(certId));
- if (result != 1 || !md || !reportedSerialNumber) {
- qCWarning(lcSsl, "Failed to extract a hash and serial number from CertID structure");
- return false;
- }
-
- if (!q_X509_get_serialNumber(peerCert)) {
- // Is this possible at all? But we have to check this,
- // ASN1_INTEGER_cmp (called from OCSP_id_cmp) dereferences
- // without any checks at all.
- qCWarning(lcSsl, "No serial number in peer's ceritificate");
- return false;
- }
-
- const int nid = q_OBJ_obj2nid(md);
- if (nid == NID_undef) {
- qCWarning(lcSsl, "Unknown hash algorithm in CertID");
- return false;
- }
-
- const EVP_MD *digest = q_EVP_get_digestbynid(nid); // Does not increment refcount.
- if (!digest) {
- qCWarning(lcSsl) << "No digest for nid" << nid;
- return false;
- }
-
- OCSP_CERTID *recreatedId = q_OCSP_cert_to_id(digest, peerCert, issuer);
- if (!recreatedId) {
- qCWarning(lcSsl, "Failed to re-create CertID");
- return false;
- }
- const QSharedPointer<OCSP_CERTID> guard(recreatedId, q_OCSP_CERTID_free);
-
- if (q_OCSP_id_cmp(const_cast<OCSP_CERTID *>(certId), recreatedId)) {
- qDebug(lcSsl, "Certificate ID mismatch");
- return false;
- }
- // Bingo!
- return true;
-}
-
-#endif // ocsp
-
-int q_X509Callback(int ok, X509_STORE_CTX *ctx)
-{
- if (!ok) {
- // Store the error and at which depth the error was detected.
-
- using ErrorListPtr = QList<QSslErrorEntry> *;
- ErrorListPtr errors = nullptr;
-
- // Error list is attached to either 'SSL' or 'X509_STORE'.
- if (X509_STORE *store = q_X509_STORE_CTX_get0_store(ctx)) // We try store first:
- errors = ErrorListPtr(q_X509_STORE_get_ex_data(store, 0));
-
- if (!errors) {
- // Not found on store? Try SSL and its external data then. According to the OpenSSL's
- // documentation:
- //
- // "Whenever a X509_STORE_CTX object is created for the verification of the
- // peer's certificate during a handshake, a pointer to the SSL object is
- // stored into the X509_STORE_CTX object to identify the connection affected.
- // To retrieve this pointer the X509_STORE_CTX_get_ex_data() function can be
- // used with the correct index."
- const auto offset = QSslSocketBackendPrivate::s_indexForSSLExtraData
- + QSslSocketBackendPrivate::errorOffsetInExData;
- if (SSL *ssl = static_cast<SSL *>(q_X509_STORE_CTX_get_ex_data(ctx, q_SSL_get_ex_data_X509_STORE_CTX_idx())))
- errors = ErrorListPtr(q_SSL_get_ex_data(ssl, offset));
- }
-
- if (!errors) {
- qCWarning(lcSsl, "Neither X509_STORE, nor SSL contains error list, handshake failure");
- return 0;
- }
-
- errors->append(QSslErrorEntry::fromStoreContext(ctx));
- }
- // Always return OK to allow verification to continue. We handle the
- // errors gracefully after collecting all errors, after verification has
- // completed.
- return 1;
-}
-
-static void q_loadCiphersForConnection(SSL *connection, QList<QSslCipher> &ciphers,
- QList<QSslCipher> &defaultCiphers)
-{
- Q_ASSERT(connection);
-
- STACK_OF(SSL_CIPHER) *supportedCiphers = q_SSL_get_ciphers(connection);
- for (int i = 0; i < q_sk_SSL_CIPHER_num(supportedCiphers); ++i) {
- if (SSL_CIPHER *cipher = q_sk_SSL_CIPHER_value(supportedCiphers, i)) {
- QSslCipher ciph = QSslSocketBackendPrivate::QSslCipher_from_SSL_CIPHER(cipher);
- if (!ciph.isNull()) {
- // Unconditionally exclude ADH and AECDH ciphers since they offer no MITM protection
- if (!ciph.name().toLower().startsWith(QLatin1String("adh")) &&
- !ciph.name().toLower().startsWith(QLatin1String("exp-adh")) &&
- !ciph.name().toLower().startsWith(QLatin1String("aecdh"))) {
- ciphers << ciph;
-
- if (ciph.usedBits() >= 128)
- defaultCiphers << ciph;
- }
- }
- }
- }
-}
-
-// Defined in qsslsocket.cpp
-void q_setDefaultDtlsCiphers(const QList<QSslCipher> &ciphers);
-
-long QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SslProtocol protocol, QSsl::SslOptions sslOptions)
-{
- long options;
- switch (protocol) {
- case QSsl::SecureProtocols:
- case QSsl::TlsV1_0OrLater:
- options = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
- break;
- case QSsl::TlsV1_1OrLater:
- options = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1;
- break;
- case QSsl::TlsV1_2OrLater:
- options = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1;
- break;
- case QSsl::TlsV1_3OrLater:
- options = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2;
- break;
- default:
- options = SSL_OP_ALL;
- }
-
- // This option is disabled by default, so we need to be able to clear it
- if (sslOptions & QSsl::SslOptionDisableEmptyFragments)
- options |= SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
- else
- options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
-
-#ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
- // This option is disabled by default, so we need to be able to clear it
- if (sslOptions & QSsl::SslOptionDisableLegacyRenegotiation)
- options &= ~SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
- else
- options |= SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
-#endif
-
-#ifdef SSL_OP_NO_TICKET
- if (sslOptions & QSsl::SslOptionDisableSessionTickets)
- options |= SSL_OP_NO_TICKET;
-#endif
-#ifdef SSL_OP_NO_COMPRESSION
- if (sslOptions & QSsl::SslOptionDisableCompression)
- options |= SSL_OP_NO_COMPRESSION;
-#endif
-
- if (!(sslOptions & QSsl::SslOptionDisableServerCipherPreference))
- options |= SSL_OP_CIPHER_SERVER_PREFERENCE;
-
- return options;
-}
-
-bool QSslSocketBackendPrivate::initSslContext()
-{
- Q_Q(QSslSocket);
-
- // If no external context was set (e.g. by QHttpNetworkConnection) we will
- // create a default context
- if (!sslContextPointer) {
- // create a deep copy of our configuration
- QSslConfigurationPrivate *configurationCopy = new QSslConfigurationPrivate(configuration);
- configurationCopy->ref.storeRelaxed(0); // the QSslConfiguration constructor refs up
- sslContextPointer = QSslContext::sharedFromConfiguration(mode, configurationCopy, allowRootCertOnDemandLoading);
- }
-
- if (sslContextPointer->error() != QSslError::NoError) {
- setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError, sslContextPointer->errorString());
- sslContextPointer.clear(); // deletes the QSslContext
- return false;
- }
-
- // Create and initialize SSL session
- if (!(ssl = sslContextPointer->createSsl())) {
- // ### Bad error code
- setErrorAndEmit(QAbstractSocket::SslInternalError,
- QSslSocket::tr("Error creating SSL session, %1").arg(getErrorsFromOpenSsl()));
- return false;
- }
-
- if (configuration.protocol != QSsl::UnknownProtocol && mode == QSslSocket::SslClientMode) {
- // Set server hostname on TLS extension. RFC4366 section 3.1 requires it in ACE format.
- QString tlsHostName = verificationPeerName.isEmpty() ? q->peerName() : verificationPeerName;
- if (tlsHostName.isEmpty())
- tlsHostName = hostName;
- QByteArray ace = QUrl::toAce(tlsHostName);
- // only send the SNI header if the URL is valid and not an IP
- if (!ace.isEmpty()
- && !QHostAddress().setAddress(tlsHostName)
- && !(configuration.sslOptions & QSsl::SslOptionDisableServerNameIndication)) {
- // We don't send the trailing dot from the host header if present see
- // https://tools.ietf.org/html/rfc6066#section-3
- if (ace.endsWith('.'))
- ace.chop(1);
- if (!q_SSL_ctrl(ssl, SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name, ace.data()))
- qCWarning(lcSsl, "could not set SSL_CTRL_SET_TLSEXT_HOSTNAME, Server Name Indication disabled");
- }
- }
-
- // Clear the session.
- errorList.clear();
-
- // Initialize memory BIOs for encryption and decryption.
- readBio = q_BIO_new(q_BIO_s_mem());
- writeBio = q_BIO_new(q_BIO_s_mem());
- if (!readBio || !writeBio) {
- setErrorAndEmit(QAbstractSocket::SslInternalError,
- QSslSocket::tr("Error creating SSL session: %1").arg(getErrorsFromOpenSsl()));
- if (readBio)
- q_BIO_free(readBio);
- if (writeBio)
- q_BIO_free(writeBio);
- return false;
- }
-
- // Assign the bios.
- q_SSL_set_bio(ssl, readBio, writeBio);
-
- if (mode == QSslSocket::SslClientMode)
- q_SSL_set_connect_state(ssl);
- else
- q_SSL_set_accept_state(ssl);
-
- q_SSL_set_ex_data(ssl, s_indexForSSLExtraData, this);
-
-#ifndef OPENSSL_NO_PSK
- // Set the client callback for PSK
- if (mode == QSslSocket::SslClientMode)
- q_SSL_set_psk_client_callback(ssl, &q_ssl_psk_client_callback);
- else if (mode == QSslSocket::SslServerMode)
- q_SSL_set_psk_server_callback(ssl, &q_ssl_psk_server_callback);
-
-#if OPENSSL_VERSION_NUMBER >= 0x10101006L
- // Set the client callback for TLSv1.3 PSK
- if (mode == QSslSocket::SslClientMode
- && QSslSocket::sslLibraryBuildVersionNumber() >= 0x10101006L) {
- q_SSL_set_psk_use_session_callback(ssl, &q_ssl_psk_use_session_callback);
- }
-#endif // openssl version >= 0x10101006L
-
-#endif // OPENSSL_NO_PSK
-
-
-#if QT_CONFIG(ocsp)
- if (configuration.ocspStaplingEnabled) {
- if (mode == QSslSocket::SslServerMode) {
- setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError,
- QSslSocket::tr("Server-side QSslSocket does not support OCSP stapling"));
- return false;
- }
- if (q_SSL_set_tlsext_status_type(ssl, TLSEXT_STATUSTYPE_ocsp) != 1) {
- setErrorAndEmit(QAbstractSocket::SslInternalError,
- QSslSocket::tr("Failed to enable OCSP stapling"));
- return false;
- }
- }
-
- ocspResponseDer.clear();
- auto responsePos = configuration.backendConfig.find("Qt-OCSP-response");
- if (responsePos != configuration.backendConfig.end()) {
- // This is our private, undocumented 'API' we use for the auto-testing of
- // OCSP-stapling. It must be a der-encoded OCSP response, presumably set
- // by tst_QOcsp.
- const QVariant data(responsePos.value());
- if (data.canConvert<QByteArray>())
- ocspResponseDer = data.toByteArray();
- }
-
- if (ocspResponseDer.size()) {
- if (mode != QSslSocket::SslServerMode) {
- setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError,
- QSslSocket::tr("Client-side sockets do not send OCSP responses"));
- return false;
- }
- }
-#endif // ocsp
-
- return true;
-}
-
-void QSslSocketBackendPrivate::destroySslContext()
-{
- if (ssl) {
- if (!q_SSL_in_init(ssl) && !systemOrSslErrorDetected) {
- // We do not send a shutdown alert here. Just mark the session as
- // resumable for qhttpnetworkconnection's "optimization", otherwise
- // OpenSSL won't start a session resumption.
- if (q_SSL_shutdown(ssl) != 1) {
- // Some error may be queued, clear it.
- const auto errors = getErrorsFromOpenSsl();
- Q_UNUSED(errors);
- }
- }
- q_SSL_free(ssl);
- ssl = nullptr;
- }
- sslContextPointer.clear();
-}
-
-/*!
- \internal
-
- Does the minimum amount of initialization to determine whether SSL
- is supported or not.
-*/
-
-bool QSslSocketPrivate::supportsSsl()
-{
- return ensureLibraryLoaded();
-}
-
-
-/*!
- \internal
-
- Returns the version number of the SSL library in use. Note that
- this is the version of the library in use at run-time, not compile
- time.
-*/
-long QSslSocketPrivate::sslLibraryVersionNumber()
-{
- if (!supportsSsl())
- return 0;
-
- return q_OpenSSL_version_num();
-}
-
-/*!
- \internal
-
- Returns the version string of the SSL library in use. Note that
- this is the version of the library in use at run-time, not compile
- time. If no SSL support is available then this will return an empty value.
-*/
-QString QSslSocketPrivate::sslLibraryVersionString()
-{
- if (!supportsSsl())
- return QString();
-
- const char *versionString = q_OpenSSL_version(OPENSSL_VERSION);
- if (!versionString)
- return QString();
-
- return QString::fromLatin1(versionString);
-}
-
-/*!
- \internal
-
- Declared static in QSslSocketPrivate, makes sure the SSL libraries have
- been initialized.
-*/
-void QSslSocketPrivate::ensureInitialized()
-{
- if (!supportsSsl())
- return;
-
- ensureCiphersAndCertsLoaded();
-}
-
-/*!
- \internal
-
- Returns the version number of the SSL library in use at compile
- time.
-*/
-long QSslSocketPrivate::sslLibraryBuildVersionNumber()
-{
- return OPENSSL_VERSION_NUMBER;
-}
-
-/*!
- \internal
-
- Returns the version string of the SSL library in use at compile
- time.
-*/
-QString QSslSocketPrivate::sslLibraryBuildVersionString()
-{
- // Using QStringLiteral to store the version string as unicode and
- // avoid false positives from Google searching the playstore for old
- // SSL versions. See QTBUG-46265
- return QStringLiteral(OPENSSL_VERSION_TEXT);
-}
-
-/*!
- \internal
-
- Declared static in QSslSocketPrivate, backend-dependent loading of
- application-wide global ciphers.
-*/
-void QSslSocketPrivate::resetDefaultCiphers()
-{
- SSL_CTX *myCtx = q_SSL_CTX_new(q_TLS_client_method());
- // Note, we assert, not just silently return/bail out early:
- // this should never happen and problems with OpenSSL's initialization
- // must be caught before this (see supportsSsl()).
- Q_ASSERT(myCtx);
- SSL *mySsl = q_SSL_new(myCtx);
- Q_ASSERT(mySsl);
-
- QList<QSslCipher> ciphers;
- QList<QSslCipher> defaultCiphers;
-
- q_loadCiphersForConnection(mySsl, ciphers, defaultCiphers);
-
- q_SSL_CTX_free(myCtx);
- q_SSL_free(mySsl);
-
- setDefaultSupportedCiphers(ciphers);
- setDefaultCiphers(defaultCiphers);
-
-#if QT_CONFIG(dtls)
- ciphers.clear();
- defaultCiphers.clear();
- myCtx = q_SSL_CTX_new(q_DTLS_client_method());
- if (myCtx) {
- mySsl = q_SSL_new(myCtx);
- if (mySsl) {
- q_loadCiphersForConnection(mySsl, ciphers, defaultCiphers);
- q_setDefaultDtlsCiphers(defaultCiphers);
- q_SSL_free(mySsl);
- }
- q_SSL_CTX_free(myCtx);
- }
-#endif // dtls
-}
-
-void QSslSocketPrivate::resetDefaultEllipticCurves()
-{
- QList<QSslEllipticCurve> curves;
-
-#ifndef OPENSSL_NO_EC
- const size_t curveCount = q_EC_get_builtin_curves(nullptr, 0);
-
- QVarLengthArray<EC_builtin_curve> builtinCurves(static_cast<int>(curveCount));
-
- if (q_EC_get_builtin_curves(builtinCurves.data(), curveCount) == curveCount) {
- curves.reserve(int(curveCount));
- for (size_t i = 0; i < curveCount; ++i) {
- QSslEllipticCurve curve;
- curve.id = builtinCurves[int(i)].nid;
- curves.append(curve);
- }
- }
-#endif // OPENSSL_NO_EC
-
- // set the list of supported ECs, but not the list
- // of *default* ECs. OpenSSL doesn't like forcing an EC for the wrong
- // ciphersuite, so don't try it -- leave the empty list to mean
- // "the implementation will choose the most suitable one".
- setDefaultSupportedEllipticCurves(curves);
-}
-
-#ifndef Q_OS_DARWIN // Apple implementation in qsslsocket_mac_shared.cpp
-QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
-{
- ensureInitialized();
-#ifdef QSSLSOCKET_DEBUG
- QElapsedTimer timer;
- timer.start();
-#endif
- QList<QSslCertificate> systemCerts;
-#if defined(Q_OS_WIN)
- HCERTSTORE hSystemStore;
- hSystemStore = CertOpenSystemStoreW(0, L"ROOT");
- if (hSystemStore) {
- PCCERT_CONTEXT pc = nullptr;
- while (1) {
- pc = CertFindCertificateInStore(hSystemStore, X509_ASN_ENCODING, 0, CERT_FIND_ANY, nullptr, pc);
- if (!pc)
- break;
- QByteArray der(reinterpret_cast<const char *>(pc->pbCertEncoded),
- static_cast<int>(pc->cbCertEncoded));
- QSslCertificate cert(der, QSsl::Der);
- systemCerts.append(cert);
- }
- CertCloseStore(hSystemStore, 0);
- }
-#elif defined(Q_OS_UNIX)
- QSet<QString> certFiles;
- QDir currentDir;
- QStringList nameFilters;
- QList<QByteArray> directories;
- QSsl::EncodingFormat platformEncodingFormat;
-# ifndef Q_OS_ANDROID
- directories = unixRootCertDirectories();
- nameFilters << QLatin1String("*.pem") << QLatin1String("*.crt");
- platformEncodingFormat = QSsl::Pem;
-# else
- // Q_OS_ANDROID
- QByteArray ministroPath = qgetenv("MINISTRO_SSL_CERTS_PATH"); // Set by Ministro
- directories << ministroPath;
- nameFilters << QLatin1String("*.der");
- platformEncodingFormat = QSsl::Der;
-# ifndef Q_OS_ANDROID_EMBEDDED
- if (ministroPath.isEmpty()) {
- QList<QByteArray> certificateData = fetchSslCertificateData();
- for (int i = 0; i < certificateData.size(); ++i) {
- systemCerts.append(QSslCertificate::fromData(certificateData.at(i), QSsl::Der));
- }
- } else
-# endif //Q_OS_ANDROID_EMBEDDED
-# endif //Q_OS_ANDROID
- {
- currentDir.setNameFilters(nameFilters);
- for (int a = 0; a < directories.count(); a++) {
- currentDir.setPath(QLatin1String(directories.at(a)));
- QDirIterator it(currentDir);
- while (it.hasNext()) {
- it.next();
- // use canonical path here to not load the same certificate twice if symlinked
- certFiles.insert(it.fileInfo().canonicalFilePath());
- }
- }
- for (const QString& file : qAsConst(certFiles))
- systemCerts.append(QSslCertificate::fromPath(file, platformEncodingFormat));
-# ifndef Q_OS_ANDROID
- systemCerts.append(QSslCertificate::fromPath(QLatin1String("/etc/pki/tls/certs/ca-bundle.crt"), QSsl::Pem)); // Fedora, Mandriva
- systemCerts.append(QSslCertificate::fromPath(QLatin1String("/usr/local/share/certs/ca-root-nss.crt"), QSsl::Pem)); // FreeBSD's ca_root_nss
-# endif
- }
-#endif
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << "systemCaCertificates retrieval time " << timer.elapsed() << "ms";
- qCDebug(lcSsl) << "imported " << systemCerts.count() << " certificates";
-#endif
-
- return systemCerts;
-}
-#endif // Q_OS_DARWIN
-
-void QSslSocketBackendPrivate::startClientEncryption()
-{
- if (!initSslContext()) {
- setErrorAndEmit(QAbstractSocket::SslInternalError,
- QSslSocket::tr("Unable to init SSL Context: %1").arg(getErrorsFromOpenSsl()));
- return;
- }
-
- // Start connecting. This will place outgoing data in the BIO, so we
- // follow up with calling transmit().
- startHandshake();
- transmit();
-}
-
-void QSslSocketBackendPrivate::startServerEncryption()
-{
- if (!initSslContext()) {
- setErrorAndEmit(QAbstractSocket::SslInternalError,
- QSslSocket::tr("Unable to init SSL Context: %1").arg(getErrorsFromOpenSsl()));
- return;
- }
-
- // Start connecting. This will place outgoing data in the BIO, so we
- // follow up with calling transmit().
- startHandshake();
- transmit();
-}
-
-/*!
- \internal
-
- Transmits encrypted data between the BIOs and the socket.
-*/
-void QSslSocketBackendPrivate::transmit()
-{
- Q_Q(QSslSocket);
-
- using ScopedBool = QScopedValueRollback<bool>;
-
- if (inSetAndEmitError)
- return;
-
- // If we don't have any SSL context, don't bother transmitting.
- if (!ssl)
- return;
-
- bool transmitting;
- do {
- transmitting = false;
-
- // If the connection is secure, we can transfer data from the write
- // buffer (in plain text) to the write BIO through SSL_write.
- if (connectionEncrypted && !writeBuffer.isEmpty()) {
- qint64 totalBytesWritten = 0;
- int nextDataBlockSize;
- while ((nextDataBlockSize = writeBuffer.nextDataBlockSize()) > 0) {
- int writtenBytes = q_SSL_write(ssl, writeBuffer.readPointer(), nextDataBlockSize);
- if (writtenBytes <= 0) {
- int error = q_SSL_get_error(ssl, writtenBytes);
- //write can result in a want_write_error - not an error - continue transmitting
- if (error == SSL_ERROR_WANT_WRITE) {
- transmitting = true;
- break;
- } else if (error == SSL_ERROR_WANT_READ) {
- //write can result in a want_read error, possibly due to renegotiation - not an error - stop transmitting
- transmitting = false;
- break;
- } else {
- // ### Better error handling.
- const ScopedBool bg(inSetAndEmitError, true);
- setErrorAndEmit(QAbstractSocket::SslInternalError,
- QSslSocket::tr("Unable to write data: %1").arg(
- getErrorsFromOpenSsl()));
- return;
- }
- }
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << "QSslSocketBackendPrivate::transmit: encrypted" << writtenBytes << "bytes";
-#endif
- writeBuffer.free(writtenBytes);
- totalBytesWritten += writtenBytes;
-
- if (writtenBytes < nextDataBlockSize) {
- // break out of the writing loop and try again after we had read
- transmitting = true;
- break;
- }
- }
-
- if (totalBytesWritten > 0) {
- // Don't emit bytesWritten() recursively.
- if (!emittedBytesWritten) {
- emittedBytesWritten = true;
- emit q->bytesWritten(totalBytesWritten);
- emittedBytesWritten = false;
- }
- emit q->channelBytesWritten(0, totalBytesWritten);
- }
- }
-
- // Check if we've got any data to be written to the socket.
- QVarLengthArray<char, 4096> data;
- int pendingBytes;
- while (plainSocket->isValid() && (pendingBytes = q_BIO_pending(writeBio)) > 0
- && plainSocket->openMode() != QIODevice::NotOpen) {
- // Read encrypted data from the write BIO into a buffer.
- data.resize(pendingBytes);
- int encryptedBytesRead = q_BIO_read(writeBio, data.data(), pendingBytes);
-
- // Write encrypted data from the buffer to the socket.
- qint64 actualWritten = plainSocket->write(data.constData(), encryptedBytesRead);
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << "QSslSocketBackendPrivate::transmit: wrote" << encryptedBytesRead << "encrypted bytes to the socket" << actualWritten << "actual.";
-#endif
- if (actualWritten < 0) {
- //plain socket write fails if it was in the pending close state.
- const ScopedBool bg(inSetAndEmitError, true);
- setErrorAndEmit(plainSocket->error(), plainSocket->errorString());
- return;
- }
- transmitting = true;
- }
-
- // Check if we've got any data to be read from the socket.
- if (!connectionEncrypted || !readBufferMaxSize || buffer.size() < readBufferMaxSize)
- while ((pendingBytes = plainSocket->bytesAvailable()) > 0) {
- // Read encrypted data from the socket into a buffer.
- data.resize(pendingBytes);
- // just peek() here because q_BIO_write could write less data than expected
- int encryptedBytesRead = plainSocket->peek(data.data(), pendingBytes);
-
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << "QSslSocketBackendPrivate::transmit: read" << encryptedBytesRead << "encrypted bytes from the socket";
-#endif
- // Write encrypted data from the buffer into the read BIO.
- int writtenToBio = q_BIO_write(readBio, data.constData(), encryptedBytesRead);
-
- // Throw away the results.
- if (writtenToBio > 0) {
- plainSocket->skip(writtenToBio);
- } else {
- // ### Better error handling.
- const ScopedBool bg(inSetAndEmitError, true);
- setErrorAndEmit(QAbstractSocket::SslInternalError,
- QSslSocket::tr("Unable to decrypt data: %1").arg(
- getErrorsFromOpenSsl()));
- return;
- }
-
- transmitting = true;
- }
-
- // If the connection isn't secured yet, this is the time to retry the
- // connect / accept.
- if (!connectionEncrypted) {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << "QSslSocketBackendPrivate::transmit: testing encryption";
-#endif
- if (startHandshake()) {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << "QSslSocketBackendPrivate::transmit: encryption established";
-#endif
- connectionEncrypted = true;
- transmitting = true;
- } else if (plainSocket->state() != QAbstractSocket::ConnectedState) {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << "QSslSocketBackendPrivate::transmit: connection lost";
-#endif
- break;
- } else if (paused) {
- // just wait until the user continues
- return;
- } else {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << "QSslSocketBackendPrivate::transmit: encryption not done yet";
-#endif
- }
- }
-
- // If the request is small and the remote host closes the transmission
- // after sending, there's a chance that startHandshake() will already
- // have triggered a shutdown.
- if (!ssl)
- continue;
-
- // We always read everything from the SSL decryption buffers, even if
- // we have a readBufferMaxSize. There's no point in leaving data there
- // just so that readBuffer.size() == readBufferMaxSize.
- int readBytes = 0;
- const int bytesToRead = 4096;
- do {
- if (readChannelCount == 0) {
- // The read buffer is deallocated, don't try resize or write to it.
- break;
- }
- // Don't use SSL_pending(). It's very unreliable.
- readBytes = q_SSL_read(ssl, buffer.reserve(bytesToRead), bytesToRead);
- if (readBytes > 0) {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << "QSslSocketBackendPrivate::transmit: decrypted" << readBytes << "bytes";
-#endif
- buffer.chop(bytesToRead - readBytes);
-
- if (readyReadEmittedPointer)
- *readyReadEmittedPointer = true;
- emit q->readyRead();
- emit q->channelReadyRead(0);
- transmitting = true;
- continue;
- }
- buffer.chop(bytesToRead);
-
- // Error.
- switch (q_SSL_get_error(ssl, readBytes)) {
- case SSL_ERROR_WANT_READ:
- case SSL_ERROR_WANT_WRITE:
- // Out of data.
- break;
- case SSL_ERROR_ZERO_RETURN:
- // The remote host closed the connection.
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << "QSslSocketBackendPrivate::transmit: remote disconnect";
-#endif
- shutdown = true; // the other side shut down, make sure we do not send shutdown ourselves
- {
- const ScopedBool bg(inSetAndEmitError, true);
- setErrorAndEmit(QAbstractSocket::RemoteHostClosedError,
- QSslSocket::tr("The TLS/SSL connection has been closed"));
- }
- return;
- case SSL_ERROR_SYSCALL: // some IO error
- case SSL_ERROR_SSL: // error in the SSL library
- // we do not know exactly what the error is, nor whether we can recover from it,
- // so just return to prevent an endless loop in the outer "while" statement
- systemOrSslErrorDetected = true;
- {
- const ScopedBool bg(inSetAndEmitError, true);
- setErrorAndEmit(QAbstractSocket::SslInternalError,
- QSslSocket::tr("Error while reading: %1").arg(getErrorsFromOpenSsl()));
- }
- return;
- default:
- // SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT: can only happen with a
- // BIO_s_connect() or BIO_s_accept(), which we do not call.
- // SSL_ERROR_WANT_X509_LOOKUP: can only happen with a
- // SSL_CTX_set_client_cert_cb(), which we do not call.
- // So this default case should never be triggered.
- {
- const ScopedBool bg(inSetAndEmitError, true);
- setErrorAndEmit(QAbstractSocket::SslInternalError,
- QSslSocket::tr("Error while reading: %1").arg(getErrorsFromOpenSsl()));
- }
- break;
- }
- } while (ssl && readBytes > 0);
- } while (ssl && transmitting);
-}
-
-QSslError _q_OpenSSL_to_QSslError(int errorCode, const QSslCertificate &cert)
-{
- QSslError error;
- switch (errorCode) {
- case X509_V_OK:
- // X509_V_OK is also reported if the peer had no certificate.
- break;
- case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
- error = QSslError(QSslError::UnableToGetIssuerCertificate, cert); break;
- case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
- error = QSslError(QSslError::UnableToDecryptCertificateSignature, cert); break;
- case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
- error = QSslError(QSslError::UnableToDecodeIssuerPublicKey, cert); break;
- case X509_V_ERR_CERT_SIGNATURE_FAILURE:
- error = QSslError(QSslError::CertificateSignatureFailed, cert); break;
- case X509_V_ERR_CERT_NOT_YET_VALID:
- error = QSslError(QSslError::CertificateNotYetValid, cert); break;
- case X509_V_ERR_CERT_HAS_EXPIRED:
- error = QSslError(QSslError::CertificateExpired, cert); break;
- case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
- error = QSslError(QSslError::InvalidNotBeforeField, cert); break;
- case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
- error = QSslError(QSslError::InvalidNotAfterField, cert); break;
- case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
- error = QSslError(QSslError::SelfSignedCertificate, cert); break;
- case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
- error = QSslError(QSslError::SelfSignedCertificateInChain, cert); break;
- case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
- error = QSslError(QSslError::UnableToGetLocalIssuerCertificate, cert); break;
- case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
- error = QSslError(QSslError::UnableToVerifyFirstCertificate, cert); break;
- case X509_V_ERR_CERT_REVOKED:
- error = QSslError(QSslError::CertificateRevoked, cert); break;
- case X509_V_ERR_INVALID_CA:
- error = QSslError(QSslError::InvalidCaCertificate, cert); break;
- case X509_V_ERR_PATH_LENGTH_EXCEEDED:
- error = QSslError(QSslError::PathLengthExceeded, cert); break;
- case X509_V_ERR_INVALID_PURPOSE:
- error = QSslError(QSslError::InvalidPurpose, cert); break;
- case X509_V_ERR_CERT_UNTRUSTED:
- error = QSslError(QSslError::CertificateUntrusted, cert); break;
- case X509_V_ERR_CERT_REJECTED:
- error = QSslError(QSslError::CertificateRejected, cert); break;
- default:
- error = QSslError(QSslError::UnspecifiedError, cert); break;
- }
- return error;
-}
-
-QString QSslSocketBackendPrivate::msgErrorsDuringHandshake()
-{
- return QSslSocket::tr("Error during SSL handshake: %1")
- .arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
-}
-
-bool QSslSocketBackendPrivate::startHandshake()
-{
- Q_Q(QSslSocket);
-
- // Check if the connection has been established. Get all errors from the
- // verification stage.
-
- using ScopedBool = QScopedValueRollback<bool>;
-
- if (inSetAndEmitError)
- return false;
-
- pendingFatalAlert = false;
- errorsReportedFromCallback = false;
- QList<QSslErrorEntry> lastErrors;
- q_SSL_set_ex_data(ssl, s_indexForSSLExtraData + errorOffsetInExData, &lastErrors);
-
- // SSL_set_ex_data can fail, but see the callback's code - we handle this there.
- q_SSL_set_ex_data(ssl, s_indexForSSLExtraData + socketOffsetInExData, this);
- q_SSL_set_info_callback(ssl, qt_AlertInfoCallback);
-
- int result = (mode == QSslSocket::SslClientMode) ? q_SSL_connect(ssl) : q_SSL_accept(ssl);
- q_SSL_set_ex_data(ssl, s_indexForSSLExtraData + errorOffsetInExData, nullptr);
- // Note, unlike errors as external data on SSL object, we do not unset
- // a callback/ex-data if alert notifications are enabled: an alert can
- // arrive after the handshake, for example, this happens when the server
- // does not find a ClientCert or does not like it.
-
- if (!lastErrors.isEmpty() || errorsReportedFromCallback)
- storePeerCertificates();
-
- if (!errorsReportedFromCallback) {
- for (const auto &currentError : qAsConst(lastErrors)) {
- emit q->peerVerifyError(_q_OpenSSL_to_QSslError(currentError.code,
- configuration.peerCertificateChain.value(currentError.depth)));
- if (q->state() != QAbstractSocket::ConnectedState)
- break;
- }
- }
-
- errorList << lastErrors;
-
- // Connection aborted during handshake phase.
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
-
- // Check if we're encrypted or not.
- if (result <= 0) {
- switch (q_SSL_get_error(ssl, result)) {
- case SSL_ERROR_WANT_READ:
- case SSL_ERROR_WANT_WRITE:
- // The handshake is not yet complete.
- break;
- default:
- QString errorString = QSslSocketBackendPrivate::msgErrorsDuringHandshake();
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << "QSslSocketBackendPrivate::startHandshake: error!" << errorString;
-#endif
- {
- const ScopedBool bg(inSetAndEmitError, true);
- setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError, errorString);
- if (pendingFatalAlert) {
- trySendFatalAlert();
- pendingFatalAlert = false;
- }
- }
- q->abort();
- }
- return false;
- }
-
- // store peer certificate chain
- storePeerCertificates();
-
- // Start translating errors.
- QList<QSslError> errors;
-
- // check the whole chain for blacklisting (including root, as we check for subjectInfo and issuer)
- for (const QSslCertificate &cert : qAsConst(configuration.peerCertificateChain)) {
- if (QSslCertificatePrivate::isBlacklisted(cert)) {
- QSslError error(QSslError::CertificateBlacklisted, cert);
- errors << error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
- }
-
- const bool doVerifyPeer = configuration.peerVerifyMode == QSslSocket::VerifyPeer
- || (configuration.peerVerifyMode == QSslSocket::AutoVerifyPeer
- && mode == QSslSocket::SslClientMode);
-
-#if QT_CONFIG(ocsp)
- // For now it's always QSslSocket::SslClientMode - initSslContext() will bail out early,
- // if it's enabled in QSslSocket::SslServerMode. This can change.
- if (!configuration.peerCertificate.isNull() && configuration.ocspStaplingEnabled && doVerifyPeer) {
- if (!checkOcspStatus()) {
- if (ocspErrors.isEmpty()) {
- {
- const ScopedBool bg(inSetAndEmitError, true);
- setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError, ocspErrorDescription);
- }
- q->abort();
- return false;
- }
-
- for (const QSslError &error : ocspErrors) {
- errors << error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
- }
- }
-#endif // ocsp
-
- // Check the peer certificate itself. First try the subject's common name
- // (CN) as a wildcard, then try all alternate subject name DNS entries the
- // same way.
- if (!configuration.peerCertificate.isNull()) {
- // but only if we're a client connecting to a server
- // if we're the server, don't check CN
- if (mode == QSslSocket::SslClientMode) {
- QString peerName = (verificationPeerName.isEmpty () ? q->peerName() : verificationPeerName);
-
- if (!isMatchingHostname(configuration.peerCertificate, peerName)) {
- // No matches in common names or alternate names.
- QSslError error(QSslError::HostNameMismatch, configuration.peerCertificate);
- errors << error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
- }
- } else {
- // No peer certificate presented. Report as error if the socket
- // expected one.
- if (doVerifyPeer) {
- QSslError error(QSslError::NoPeerCertificate);
- errors << error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
- }
-
- // Translate errors from the error list into QSslErrors.
- errors.reserve(errors.size() + errorList.size());
- for (const auto &error : qAsConst(errorList))
- errors << _q_OpenSSL_to_QSslError(error.code, configuration.peerCertificateChain.value(error.depth));
-
- if (!errors.isEmpty()) {
- sslErrors = errors;
-
-#ifdef Q_OS_WIN
- const bool fetchEnabled = s_loadRootCertsOnDemand
- && allowRootCertOnDemandLoading;
- // !fetchEnabled is a special case scenario, when we potentially have a missing
- // intermediate certificate and a recoverable chain, but on demand cert loading
- // was disabled by setCaCertificates call. For this scenario we check if "Authority
- // Information Access" is present - wincrypt can deal with such certificates.
- QSslCertificate certToFetch;
- if (doVerifyPeer && !verifyErrorsHaveBeenIgnored())
- certToFetch = findCertificateToFetch(sslErrors, !fetchEnabled);
-
- //Skip this if not using system CAs, or if the SSL errors are configured in advance to be ignorable
- if (!certToFetch.isNull()) {
- fetchAuthorityInformation = !fetchEnabled;
- //Windows desktop versions starting from vista ship with minimal set of roots and download on demand
- //from the windows update server CA roots that are trusted by MS. It also can fetch a missing intermediate
- //in case "Authority Information Access" extension is present.
- //
- //However, this is only transparent if using WinINET - we have to trigger it
- //ourselves.
- fetchCaRootForCert(certToFetch);
- return false;
- }
-#endif
- if (!checkSslErrors())
- return false;
- // A slot, attached to sslErrors signal can call
- // abort/close/disconnetFromHost/etc; no need to
- // continue handshake then.
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- } else {
- sslErrors.clear();
- }
-
- continueHandshake();
- return true;
-}
-
-void QSslSocketBackendPrivate::storePeerCertificates()
-{
- // Store the peer certificate and chain. For clients, the peer certificate
- // chain includes the peer certificate; for servers, it doesn't. Both the
- // peer certificate and the chain may be empty if the peer didn't present
- // any certificate.
- X509 *x509 = q_SSL_get_peer_certificate(ssl);
- configuration.peerCertificate = QSslCertificatePrivate::QSslCertificate_from_X509(x509);
- q_X509_free(x509);
- if (configuration.peerCertificateChain.isEmpty()) {
- configuration.peerCertificateChain = STACKOFX509_to_QSslCertificates(q_SSL_get_peer_cert_chain(ssl));
- if (!configuration.peerCertificate.isNull() && mode == QSslSocket::SslServerMode)
- configuration.peerCertificateChain.prepend(configuration.peerCertificate);
- }
-}
-
-int QSslSocketBackendPrivate::handleNewSessionTicket(SSL *connection)
-{
- // If we return 1, this means we own the session, but we don't.
- // 0 would tell OpenSSL to deref (but they still have it in the
- // internal cache).
- Q_Q(QSslSocket);
-
- Q_ASSERT(connection);
-
- if (q->sslConfiguration().testSslOption(QSsl::SslOptionDisableSessionPersistence)) {
- // We silently ignore, do nothing, remove from cache.
- return 0;
- }
-
- SSL_SESSION *currentSession = q_SSL_get_session(connection);
- if (!currentSession) {
- qCWarning(lcSsl,
- "New session ticket callback, the session is invalid (nullptr)");
- return 0;
- }
-
- if (q_SSL_version(connection) < 0x304) {
- // We only rely on this mechanics with TLS >= 1.3
- return 0;
- }
-
-#ifdef TLS1_3_VERSION
- if (!q_SSL_SESSION_is_resumable(currentSession)) {
- qCDebug(lcSsl, "New session ticket, but the session is non-resumable");
- return 0;
- }
-#endif // TLS1_3_VERSION
-
- const int sessionSize = q_i2d_SSL_SESSION(currentSession, nullptr);
- if (sessionSize <= 0) {
- qCWarning(lcSsl, "could not store persistent version of SSL session");
- return 0;
- }
-
- // We have somewhat perverse naming, it's not a ticket, it's a session.
- QByteArray sessionTicket(sessionSize, 0);
- auto data = reinterpret_cast<unsigned char *>(sessionTicket.data());
- if (!q_i2d_SSL_SESSION(currentSession, &data)) {
- qCWarning(lcSsl, "could not store persistent version of SSL session");
- return 0;
- }
-
- configuration.sslSession = sessionTicket;
- configuration.sslSessionTicketLifeTimeHint = int(q_SSL_SESSION_get_ticket_lifetime_hint(currentSession));
-
- emit q->newSessionTicketReceived();
- return 0;
-}
-
-bool QSslSocketBackendPrivate::checkSslErrors()
-{
- Q_Q(QSslSocket);
- if (sslErrors.isEmpty())
- return true;
-
- emit q->sslErrors(sslErrors);
-
- bool doVerifyPeer = configuration.peerVerifyMode == QSslSocket::VerifyPeer
- || (configuration.peerVerifyMode == QSslSocket::AutoVerifyPeer
- && mode == QSslSocket::SslClientMode);
- bool doEmitSslError = !verifyErrorsHaveBeenIgnored();
- // check whether we need to emit an SSL handshake error
- if (doVerifyPeer && doEmitSslError) {
- if (q->pauseMode() & QAbstractSocket::PauseOnSslErrors) {
- pauseSocketNotifiers(q);
- paused = true;
- } else {
- setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError, sslErrors.constFirst().errorString());
- plainSocket->disconnectFromHost();
- }
- return false;
- }
- return true;
-}
-
-unsigned int QSslSocketBackendPrivate::tlsPskClientCallback(const char *hint,
- char *identity, unsigned int max_identity_len,
- unsigned char *psk, unsigned int max_psk_len)
-{
- QSslPreSharedKeyAuthenticator authenticator;
-
- // Fill in some read-only fields (for the user)
- if (hint)
- authenticator.d->identityHint = QByteArray::fromRawData(hint, int(::strlen(hint))); // it's NUL terminated, but do not include the NUL
-
- authenticator.d->maximumIdentityLength = int(max_identity_len) - 1; // needs to be NUL terminated
- authenticator.d->maximumPreSharedKeyLength = int(max_psk_len);
-
- // Let the client provide the remaining bits...
- Q_Q(QSslSocket);
- emit q->preSharedKeyAuthenticationRequired(&authenticator);
-
- // No PSK set? Return now to make the handshake fail
- if (authenticator.preSharedKey().isEmpty())
- return 0;
-
- // Copy data back into OpenSSL
- const int identityLength = qMin(authenticator.identity().length(), authenticator.maximumIdentityLength());
- ::memcpy(identity, authenticator.identity().constData(), identityLength);
- identity[identityLength] = 0;
-
- const int pskLength = qMin(authenticator.preSharedKey().length(), authenticator.maximumPreSharedKeyLength());
- ::memcpy(psk, authenticator.preSharedKey().constData(), pskLength);
- return pskLength;
-}
-
-unsigned int QSslSocketBackendPrivate::tlsPskServerCallback(const char *identity,
- unsigned char *psk, unsigned int max_psk_len)
-{
- QSslPreSharedKeyAuthenticator authenticator;
-
- // Fill in some read-only fields (for the user)
- authenticator.d->identityHint = configuration.preSharedKeyIdentityHint;
- authenticator.d->identity = identity;
- authenticator.d->maximumIdentityLength = 0; // user cannot set an identity
- authenticator.d->maximumPreSharedKeyLength = int(max_psk_len);
-
- // Let the client provide the remaining bits...
- Q_Q(QSslSocket);
- emit q->preSharedKeyAuthenticationRequired(&authenticator);
-
- // No PSK set? Return now to make the handshake fail
- if (authenticator.preSharedKey().isEmpty())
- return 0;
-
- // Copy data back into OpenSSL
- const int pskLength = qMin(authenticator.preSharedKey().length(), authenticator.maximumPreSharedKeyLength());
- ::memcpy(psk, authenticator.preSharedKey().constData(), pskLength);
- return pskLength;
-}
-
-#ifdef Q_OS_WIN
-
-void QSslSocketBackendPrivate::fetchCaRootForCert(const QSslCertificate &cert)
-{
- Q_Q(QSslSocket);
- //The root certificate is downloaded from windows update, which blocks for 15 seconds in the worst case
- //so the request is done in a worker thread.
- QList<QSslCertificate> customRoots;
- if (fetchAuthorityInformation)
- customRoots = configuration.caCertificates;
-
- //Remember we are fetching and what we are fetching:
- caToFetch = cert;
-
- QWindowsCaRootFetcher *fetcher = new QWindowsCaRootFetcher(cert, mode, customRoots, q->peerVerifyName());
- QObjectPrivate::connect(fetcher, &QWindowsCaRootFetcher::finished,
- this, &QSslSocketBackendPrivate::_q_caRootLoaded,
- Qt::QueuedConnection);
- QMetaObject::invokeMethod(fetcher, "start", Qt::QueuedConnection);
- pauseSocketNotifiers(q);
- paused = true;
-}
-
-//This is the callback from QWindowsCaRootFetcher, trustedRoot will be invalid (default constructed) if it failed.
-void QSslSocketBackendPrivate::_q_caRootLoaded(QSslCertificate cert, QSslCertificate trustedRoot)
-{
- if (caToFetch != cert) {
- //Ooops, something from the previous connection attempt, ignore!
- return;
- }
-
- //Done, fetched already:
- caToFetch = QSslCertificate{};
-
- if (fetchAuthorityInformation) {
- if (!configuration.caCertificates.contains(trustedRoot))
- trustedRoot = QSslCertificate{};
- fetchAuthorityInformation = false;
- }
-
- if (!trustedRoot.isNull() && !trustedRoot.isBlacklisted()) {
- if (s_loadRootCertsOnDemand) {
- //Add the new root cert to default cert list for use by future sockets
- auto defaultConfig = QSslConfiguration::defaultConfiguration();
- defaultConfig.addCaCertificate(trustedRoot);
- QSslConfiguration::setDefaultConfiguration(defaultConfig);
- }
- //Add the new root cert to this socket for future connections
- if (!configuration.caCertificates.contains(trustedRoot))
- configuration.caCertificates += trustedRoot;
- //Remove the broken chain ssl errors (as chain is verified by windows)
- for (int i=sslErrors.count() - 1; i >= 0; --i) {
- if (sslErrors.at(i).certificate() == cert) {
- switch (sslErrors.at(i).error()) {
- case QSslError::UnableToGetLocalIssuerCertificate:
- case QSslError::CertificateUntrusted:
- case QSslError::UnableToVerifyFirstCertificate:
- case QSslError::SelfSignedCertificateInChain:
- // error can be ignored if OS says the chain is trusted
- sslErrors.removeAt(i);
- break;
- default:
- // error cannot be ignored
- break;
- }
- }
- }
- }
-
- // Continue with remaining errors
- if (plainSocket)
- plainSocket->resume();
- paused = false;
- if (checkSslErrors() && ssl) {
- bool willClose = (autoStartHandshake && pendingClose);
- continueHandshake();
- if (!willClose)
- transmit();
- }
-}
-
-#endif
-
-#if QT_CONFIG(ocsp)
-
-bool QSslSocketBackendPrivate::checkOcspStatus()
-{
- Q_ASSERT(ssl);
- Q_ASSERT(mode == QSslSocket::SslClientMode); // See initSslContext() for SslServerMode
- Q_ASSERT(configuration.peerVerifyMode != QSslSocket::VerifyNone);
-
- const auto clearErrorQueue = qScopeGuard([] {
- logAndClearErrorQueue();
- });
-
- ocspResponses.clear();
- ocspErrorDescription.clear();
- ocspErrors.clear();
-
- const unsigned char *responseData = nullptr;
- const long responseLength = q_SSL_get_tlsext_status_ocsp_resp(ssl, &responseData);
- if (responseLength <= 0 || !responseData) {
- ocspErrors.push_back(QSslError(QSslError::OcspNoResponseFound));
- return false;
- }
-
- OCSP_RESPONSE *response = q_d2i_OCSP_RESPONSE(nullptr, &responseData, responseLength);
- if (!response) {
- // Treat this as a fatal SslHandshakeError.
- ocspErrorDescription = QSslSocket::tr("Failed to decode OCSP response");
- return false;
- }
- const QSharedPointer<OCSP_RESPONSE> responseGuard(response, q_OCSP_RESPONSE_free);
-
- const int ocspStatus = q_OCSP_response_status(response);
- if (ocspStatus != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
- // It's not a definitive response, it's an error message (not signed by the responder).
- ocspErrors.push_back(QSslError(qt_OCSP_response_status_to_SslError(ocspStatus)));
- return false;
- }
-
- OCSP_BASICRESP *basicResponse = q_OCSP_response_get1_basic(response);
- if (!basicResponse) {
- // SslHandshakeError.
- ocspErrorDescription = QSslSocket::tr("Failed to extract basic OCSP response");
- return false;
- }
- const QSharedPointer<OCSP_BASICRESP> basicResponseGuard(basicResponse, q_OCSP_BASICRESP_free);
-
- SSL_CTX *ctx = q_SSL_get_SSL_CTX(ssl); // Does not increment refcount.
- Q_ASSERT(ctx);
- X509_STORE *store = q_SSL_CTX_get_cert_store(ctx); // Does not increment refcount.
- if (!store) {
- // SslHandshakeError.
- ocspErrorDescription = QSslSocket::tr("No certificate verification store, cannot verify OCSP response");
- return false;
- }
-
- STACK_OF(X509) *peerChain = q_SSL_get_peer_cert_chain(ssl); // Does not increment refcount.
- X509 *peerX509 = q_SSL_get_peer_certificate(ssl);
- Q_ASSERT(peerChain || peerX509);
- const QSharedPointer<X509> peerX509Guard(peerX509, q_X509_free);
- // OCSP_basic_verify with 0 as verificationFlags:
- //
- // 0) Tries to find the OCSP responder's certificate in either peerChain
- // or basicResponse->certs. If not found, verification fails.
- // 1) It checks the signature using the responder's public key.
- // 2) Then it tries to validate the responder's cert (building a chain
- // etc.)
- // 3) It checks CertID in response.
- // 4) Ensures the responder is authorized to sign the status respond.
- //
- // Note, OpenSSL prior to 1.0.2b would only use bs->certs to
- // verify the responder's chain (see their commit 4ba9a4265bd).
- // Working this around - is too much fuss for ancient versions we
- // are dropping quite soon anyway.
- const unsigned long verificationFlags = 0;
- const int success = q_OCSP_basic_verify(basicResponse, peerChain, store, verificationFlags);
- if (success <= 0)
- ocspErrors.push_back(QSslError(QSslError::OcspResponseCannotBeTrusted));
-
- if (q_OCSP_resp_count(basicResponse) != 1) {
- ocspErrors.push_back(QSslError(QSslError::OcspMalformedResponse));
- return false;
- }
-
- OCSP_SINGLERESP *singleResponse = q_OCSP_resp_get0(basicResponse, 0);
- if (!singleResponse) {
- ocspErrors.clear();
- // A fatal problem -> SslHandshakeError.
- ocspErrorDescription = QSslSocket::tr("Failed to decode a SingleResponse from OCSP status response");
- return false;
- }
-
- // Let's make sure the response is for the correct certificate - we
- // can re-create this CertID using our peer's certificate and its
- // issuer's public key.
- ocspResponses.push_back(QOcspResponse());
- QOcspResponsePrivate *dResponse = ocspResponses.back().d.data();
- dResponse->subjectCert = configuration.peerCertificate;
- bool matchFound = false;
- if (configuration.peerCertificate.isSelfSigned()) {
- dResponse->signerCert = configuration.peerCertificate;
- matchFound = qt_OCSP_certificate_match(singleResponse, peerX509, peerX509);
- } else {
- const STACK_OF(X509) *certs = q_SSL_get_peer_cert_chain(ssl);
- if (!certs) // Oh, what a cataclysm! Last try:
- certs = q_OCSP_resp_get0_certs(basicResponse);
- if (certs) {
- // It could be the first certificate in 'certs' is our peer's
- // certificate. Since it was not captured by the 'self-signed' branch
- // above, the CertID will not match and we'll just iterate on to the
- // next certificate. So we start from 0, not 1.
- for (int i = 0, e = q_sk_X509_num(certs); i < e; ++i) {
- X509 *issuer = q_sk_X509_value(certs, i);
- matchFound = qt_OCSP_certificate_match(singleResponse, peerX509, issuer);
- if (matchFound) {
- if (q_X509_check_issued(issuer, peerX509) == X509_V_OK) {
- dResponse->signerCert = QSslCertificatePrivate::QSslCertificate_from_X509(issuer);
- break;
- }
- matchFound = false;
- }
- }
- }
- }
-
- if (!matchFound) {
- dResponse->signerCert.clear();
- ocspErrors.push_back({QSslError::OcspResponseCertIdUnknown, configuration.peerCertificate});
- }
-
- // Check if the response is valid time-wise:
- ASN1_GENERALIZEDTIME *revTime = nullptr;
- ASN1_GENERALIZEDTIME *thisUpdate = nullptr;
- ASN1_GENERALIZEDTIME *nextUpdate = nullptr;
- int reason;
- const int certStatus = q_OCSP_single_get0_status(singleResponse, &reason, &revTime, &thisUpdate, &nextUpdate);
- if (!thisUpdate) {
- // This is unexpected, treat as SslHandshakeError, OCSP_check_validity assumes this pointer
- // to be != nullptr.
- ocspErrors.clear();
- ocspResponses.clear();
- ocspErrorDescription = QSslSocket::tr("Failed to extract 'this update time' from the SingleResponse");
- return false;
- }
-
- // OCSP_check_validity(this, next, nsec, maxsec) does this check:
- // this <= now <= next. They allow some freedom to account
- // for delays/time inaccuracy.
- // this > now + nsec ? -> NOT_YET_VALID
- // if maxsec >= 0:
- // now - maxsec > this ? -> TOO_OLD
- // now - nsec > next ? -> EXPIRED
- // next < this ? -> NEXT_BEFORE_THIS
- // OK.
- if (!q_OCSP_check_validity(thisUpdate, nextUpdate, 60, -1))
- ocspErrors.push_back({QSslError::OcspResponseExpired, configuration.peerCertificate});
-
- // And finally, the status:
- switch (certStatus) {
- case V_OCSP_CERTSTATUS_GOOD:
- // This certificate was not found among the revoked ones.
- dResponse->certificateStatus = QOcspCertificateStatus::Good;
- break;
- case V_OCSP_CERTSTATUS_REVOKED:
- dResponse->certificateStatus = QOcspCertificateStatus::Revoked;
- dResponse->revocationReason = qt_OCSP_revocation_reason(reason);
- ocspErrors.push_back({QSslError::CertificateRevoked, configuration.peerCertificate});
- break;
- case V_OCSP_CERTSTATUS_UNKNOWN:
- dResponse->certificateStatus = QOcspCertificateStatus::Unknown;
- ocspErrors.push_back({QSslError::OcspStatusUnknown, configuration.peerCertificate});
- }
-
- return !ocspErrors.size();
-}
-
-#endif // ocsp
-
-void QSslSocketBackendPrivate::alertMessageSent(int value)
-{
- Q_Q(QSslSocket);
-
- const auto level = tlsAlertLevel(value);
- if (level == QSsl::AlertLevel::Fatal && !connectionEncrypted) {
- // Note, this logic is handshake-time only:
- pendingFatalAlert = true;
- }
-
- emit q->alertSent(level, tlsAlertType(value), tlsAlertDescription(value));
-}
-
-void QSslSocketBackendPrivate::alertMessageReceived(int value)
-{
- Q_Q(QSslSocket);
-
- emit q->alertReceived(tlsAlertLevel(value), tlsAlertType(value), tlsAlertDescription(value));
-}
-
-int QSslSocketBackendPrivate::emitErrorFromCallback(X509_STORE_CTX *ctx)
-{
- // Returns 0 to abort verification, 1 to continue despite error (as
- // OpenSSL expects from the verification callback).
- Q_Q(QSslSocket);
-
- Q_ASSERT(ctx);
-
- using ScopedBool = QScopedValueRollback<bool>;
- // While we are not setting, we are emitting and in general -
- // we want to prevent accidental recursive startHandshake()
- // calls:
- const ScopedBool bg(inSetAndEmitError, true);
-
- X509 *x509 = q_X509_STORE_CTX_get_current_cert(ctx);
- if (!x509) {
- qCWarning(lcSsl, "Could not obtain the certificate (that failed to verify)");
- return 0;
- }
- const QSslCertificate certificate = QSslCertificatePrivate::QSslCertificate_from_X509(x509);
-
- const auto errorAndDepth = QSslErrorEntry::fromStoreContext(ctx);
- const QSslError tlsError = _q_OpenSSL_to_QSslError(errorAndDepth.code, certificate);
-
- errorsReportedFromCallback = true;
- handshakeInterrupted = true;
- emit q->handshakeInterruptedOnError(tlsError);
-
- // Conveniently so, we also can access 'lastErrors' external data set
- // in startHandshake, we store it for the case an application later
- // wants to check errors (ignored or not):
- const auto offset = QSslSocketBackendPrivate::s_indexForSSLExtraData
- + QSslSocketBackendPrivate::errorOffsetInExData;
- if (auto errorList = static_cast<QList<QSslErrorEntry> *>(q_SSL_get_ex_data(ssl, offset)))
- errorList->append(errorAndDepth);
-
- // An application is expected to ignore this error (by calling ignoreSslErrors)
- // in its directly connected slot:
- return !handshakeInterrupted;
-}
-
-void QSslSocketBackendPrivate::trySendFatalAlert()
-{
- Q_ASSERT(pendingFatalAlert);
-
- pendingFatalAlert = false;
- QVarLengthArray<char, 4096> data;
- int pendingBytes = 0;
- while (plainSocket->isValid() && (pendingBytes = q_BIO_pending(writeBio)) > 0
- && plainSocket->openMode() != QIODevice::NotOpen) {
- // Read encrypted data from the write BIO into a buffer.
- data.resize(pendingBytes);
- const int bioReadBytes = q_BIO_read(writeBio, data.data(), pendingBytes);
-
- // Write encrypted data from the buffer to the socket.
- qint64 actualWritten = plainSocket->write(data.constData(), bioReadBytes);
- if (actualWritten < 0)
- return;
- plainSocket->flush();
- }
-}
-
-void QSslSocketBackendPrivate::disconnectFromHost()
-{
- if (ssl) {
- if (!shutdown && !q_SSL_in_init(ssl) && !systemOrSslErrorDetected) {
- if (q_SSL_shutdown(ssl) != 1) {
- // Some error may be queued, clear it.
- const auto errors = getErrorsFromOpenSsl();
- Q_UNUSED(errors);
- }
- shutdown = true;
- transmit();
- }
- }
- plainSocket->disconnectFromHost();
-}
-
-void QSslSocketBackendPrivate::disconnected()
-{
- if (plainSocket->bytesAvailable() <= 0)
- destroySslContext();
- else {
- // Move all bytes into the plain buffer
- qint64 tmpReadBufferMaxSize = readBufferMaxSize;
- readBufferMaxSize = 0; // reset temporarily so the plain socket buffer is completely drained
- transmit();
- readBufferMaxSize = tmpReadBufferMaxSize;
- }
- //if there is still buffered data in the plain socket, don't destroy the ssl context yet.
- //it will be destroyed when the socket is deleted.
-}
-
-QSslCipher QSslSocketBackendPrivate::sessionCipher() const
-{
- if (!ssl)
- return QSslCipher();
-
- const SSL_CIPHER *sessionCipher = q_SSL_get_current_cipher(ssl);
- return sessionCipher ? QSslCipher_from_SSL_CIPHER(sessionCipher) : QSslCipher();
-}
-
-QSsl::SslProtocol QSslSocketBackendPrivate::sessionProtocol() const
-{
- if (!ssl)
- return QSsl::UnknownProtocol;
- int ver = q_SSL_version(ssl);
-
- switch (ver) {
- case 0x301:
- return QSsl::TlsV1_0;
- case 0x302:
- return QSsl::TlsV1_1;
- case 0x303:
- return QSsl::TlsV1_2;
- case 0x304:
- return QSsl::TlsV1_3;
- }
-
- return QSsl::UnknownProtocol;
-}
-
-
-void QSslSocketBackendPrivate::continueHandshake()
-{
- Q_Q(QSslSocket);
- // if we have a max read buffer size, reset the plain socket's to match
- if (readBufferMaxSize)
- plainSocket->setReadBufferSize(readBufferMaxSize);
-
- if (q_SSL_session_reused(ssl))
- configuration.peerSessionShared = true;
-
-#ifdef QT_DECRYPT_SSL_TRAFFIC
- if (q_SSL_get_session(ssl)) {
- size_t master_key_len = q_SSL_SESSION_get_master_key(q_SSL_get_session(ssl), 0, 0);
- size_t client_random_len = q_SSL_get_client_random(ssl, 0, 0);
- QByteArray masterKey(int(master_key_len), 0); // Will not overflow
- QByteArray clientRandom(int(client_random_len), 0); // Will not overflow
-
- q_SSL_SESSION_get_master_key(q_SSL_get_session(ssl),
- reinterpret_cast<unsigned char*>(masterKey.data()),
- masterKey.size());
- q_SSL_get_client_random(ssl, reinterpret_cast<unsigned char *>(clientRandom.data()),
- clientRandom.size());
-
- QByteArray debugLineClientRandom("CLIENT_RANDOM ");
- debugLineClientRandom.append(clientRandom.toHex().toUpper());
- debugLineClientRandom.append(" ");
- debugLineClientRandom.append(masterKey.toHex().toUpper());
- debugLineClientRandom.append("\n");
-
- QString sslKeyFile = QDir::tempPath() + QLatin1String("/qt-ssl-keys");
- QFile file(sslKeyFile);
- if (!file.open(QIODevice::Append))
- qCWarning(lcSsl) << "could not open file" << sslKeyFile << "for appending";
- if (!file.write(debugLineClientRandom))
- qCWarning(lcSsl) << "could not write to file" << sslKeyFile;
- file.close();
- } else {
- qCWarning(lcSsl, "could not decrypt SSL traffic");
- }
-#endif
-
- // Cache this SSL session inside the QSslContext
- if (!(configuration.sslOptions & QSsl::SslOptionDisableSessionSharing)) {
- if (!sslContextPointer->cacheSession(ssl)) {
- sslContextPointer.clear(); // we could not cache the session
- } else {
- // Cache the session for permanent usage as well
- if (!(configuration.sslOptions & QSsl::SslOptionDisableSessionPersistence)) {
- if (!sslContextPointer->sessionASN1().isEmpty())
- configuration.sslSession = sslContextPointer->sessionASN1();
- configuration.sslSessionTicketLifeTimeHint = sslContextPointer->sessionTicketLifeTimeHint();
- }
- }
- }
-
-#if !defined(OPENSSL_NO_NEXTPROTONEG)
-
- configuration.nextProtocolNegotiationStatus = sslContextPointer->npnContext().status;
- if (sslContextPointer->npnContext().status == QSslConfiguration::NextProtocolNegotiationUnsupported) {
- // we could not agree -> be conservative and use HTTP/1.1
- configuration.nextNegotiatedProtocol = QByteArrayLiteral("http/1.1");
- } else {
- const unsigned char *proto = nullptr;
- unsigned int proto_len = 0;
-
- q_SSL_get0_alpn_selected(ssl, &proto, &proto_len);
- if (proto_len && mode == QSslSocket::SslClientMode) {
- // Client does not have a callback that sets it ...
- configuration.nextProtocolNegotiationStatus = QSslConfiguration::NextProtocolNegotiationNegotiated;
- }
-
- if (!proto_len) { // Test if NPN was more lucky ...
- q_SSL_get0_next_proto_negotiated(ssl, &proto, &proto_len);
- }
-
- if (proto_len)
- configuration.nextNegotiatedProtocol = QByteArray(reinterpret_cast<const char *>(proto), proto_len);
- else
- configuration.nextNegotiatedProtocol.clear();
- }
-#endif // !defined(OPENSSL_NO_NEXTPROTONEG)
-
- if (mode == QSslSocket::SslClientMode) {
- EVP_PKEY *key;
- if (q_SSL_get_server_tmp_key(ssl, &key))
- configuration.ephemeralServerKey = QSslKey(key, QSsl::PublicKey);
- }
-
- connectionEncrypted = true;
- emit q->encrypted();
- if (autoStartHandshake && pendingClose) {
- pendingClose = false;
- q->disconnectFromHost();
- }
-}
-
-bool QSslSocketPrivate::ensureLibraryLoaded()
-{
- if (!q_resolveOpenSslSymbols())
- return false;
-
- const QMutexLocker locker(qt_opensslInitMutex);
-
- if (!s_libraryLoaded) {
- // Initialize OpenSSL.
- if (q_OPENSSL_init_ssl(0, nullptr) != 1)
- return false;
-
- if (q_OpenSSL_version_num() < 0x10101000L) {
- qCWarning(lcSsl, "QSslSocket: OpenSSL >= 1.1.1 is required; %s was found instead", q_OpenSSL_version(OPENSSL_VERSION));
- return false;
- }
-
- q_SSL_load_error_strings();
- q_OpenSSL_add_all_algorithms();
-
- QSslSocketBackendPrivate::s_indexForSSLExtraData
- = q_CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL, 0L, nullptr, nullptr,
- nullptr, nullptr);
-
- // Initialize OpenSSL's random seed.
- if (!q_RAND_status()) {
- qWarning("Random number generator not seeded, disabling SSL support");
- return false;
- }
-
- s_libraryLoaded = true;
- }
- return true;
-}
-
-void QSslSocketPrivate::ensureCiphersAndCertsLoaded()
-{
- const QMutexLocker locker(qt_opensslInitMutex);
-
- if (s_loadedCiphersAndCerts)
- return;
- s_loadedCiphersAndCerts = true;
-
- resetDefaultCiphers();
- resetDefaultEllipticCurves();
-
-#if QT_CONFIG(library)
- //load symbols needed to receive certificates from system store
-#if defined(Q_OS_QNX)
- s_loadRootCertsOnDemand = true;
-#elif defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
- // check whether we can enable on-demand root-cert loading (i.e. check whether the sym links are there)
- QList<QByteArray> dirs = unixRootCertDirectories();
- QStringList symLinkFilter;
- symLinkFilter << QLatin1String("[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f].[0-9]");
- for (int a = 0; a < dirs.count(); ++a) {
- QDirIterator iterator(QLatin1String(dirs.at(a)), symLinkFilter, QDir::Files);
- if (iterator.hasNext()) {
- s_loadRootCertsOnDemand = true;
- break;
- }
- }
-#endif
-#endif // QT_CONFIG(library)
- // if on-demand loading was not enabled, load the certs now
- if (!s_loadRootCertsOnDemand)
- setDefaultCaCertificates(systemCaCertificates());
-#ifdef Q_OS_WIN
- //Enabled for fetching additional root certs from windows update on windows.
- //This flag is set false by setDefaultCaCertificates() indicating the app uses
- //its own cert bundle rather than the system one.
- //Same logic that disables the unix on demand cert loading.
- //Unlike unix, we do preload the certificates from the cert store.
- s_loadRootCertsOnDemand = true;
-#endif
-}
-
-QList<QSslCertificate> QSslSocketBackendPrivate::STACKOFX509_to_QSslCertificates(STACK_OF(X509) *x509)
-{
- ensureInitialized();
- QList<QSslCertificate> certificates;
- for (int i = 0; i < q_sk_X509_num(x509); ++i) {
- if (X509 *entry = q_sk_X509_value(x509, i))
- certificates << QSslCertificatePrivate::QSslCertificate_from_X509(entry);
- }
- return certificates;
-}
-
-QList<QSslError> QSslSocketBackendPrivate::verify(const QList<QSslCertificate> &certificateChain,
- const QString &hostName)
-{
- if (s_loadRootCertsOnDemand)
- setDefaultCaCertificates(defaultCaCertificates() + systemCaCertificates());
-
- return verify(QSslConfiguration::defaultConfiguration().caCertificates(), certificateChain, hostName);
-}
-
-QList<QSslError> QSslSocketBackendPrivate::verify(const QList<QSslCertificate> &caCertificates,
- const QList<QSslCertificate> &certificateChain,
- const QString &hostName)
-{
- if (certificateChain.count() <= 0)
- return {QSslError(QSslError::UnspecifiedError)};
-
- QList<QSslError> errors;
- // Setup the store with the default CA certificates
- X509_STORE *certStore = q_X509_STORE_new();
- if (!certStore) {
- qCWarning(lcSsl) << "Unable to create certificate store";
- errors << QSslError(QSslError::UnspecifiedError);
- return errors;
- }
- const std::unique_ptr<X509_STORE, decltype(&q_X509_STORE_free)> storeGuard(certStore, q_X509_STORE_free);
-
- const QDateTime now = QDateTime::currentDateTimeUtc();
- for (const QSslCertificate &caCertificate : caCertificates) {
- // From https://www.openssl.org/docs/ssl/SSL_CTX_load_verify_locations.html:
- //
- // If several CA certificates matching the name, key identifier, and
- // serial number condition are available, only the first one will be
- // examined. This may lead to unexpected results if the same CA
- // certificate is available with different expiration dates. If a
- // ``certificate expired'' verification error occurs, no other
- // certificate will be searched. Make sure to not have expired
- // certificates mixed with valid ones.
- //
- // See also: QSslContext::fromConfiguration()
- if (caCertificate.expiryDate() >= now) {
- q_X509_STORE_add_cert(certStore, reinterpret_cast<X509 *>(caCertificate.handle()));
- }
- }
-
- QList<QSslErrorEntry> lastErrors;
- if (!q_X509_STORE_set_ex_data(certStore, 0, &lastErrors)) {
- qCWarning(lcSsl) << "Unable to attach external data (error list) to a store";
- errors << QSslError(QSslError::UnspecifiedError);
- return errors;
- }
-
- // Register a custom callback to get all verification errors.
- q_X509_STORE_set_verify_cb(certStore, q_X509Callback);
-
- // Build the chain of intermediate certificates
- STACK_OF(X509) *intermediates = nullptr;
- if (certificateChain.length() > 1) {
- intermediates = (STACK_OF(X509) *) q_OPENSSL_sk_new_null();
-
- if (!intermediates) {
- errors << QSslError(QSslError::UnspecifiedError);
- return errors;
- }
-
- bool first = true;
- for (const QSslCertificate &cert : certificateChain) {
- if (first) {
- first = false;
- continue;
- }
-
- q_OPENSSL_sk_push((OPENSSL_STACK *)intermediates, reinterpret_cast<X509 *>(cert.handle()));
- }
- }
-
- X509_STORE_CTX *storeContext = q_X509_STORE_CTX_new();
- if (!storeContext) {
- errors << QSslError(QSslError::UnspecifiedError);
- return errors;
- }
- std::unique_ptr<X509_STORE_CTX, decltype(&q_X509_STORE_CTX_free)> ctxGuard(storeContext, q_X509_STORE_CTX_free);
-
- if (!q_X509_STORE_CTX_init(storeContext, certStore, reinterpret_cast<X509 *>(certificateChain[0].handle()), intermediates)) {
- errors << QSslError(QSslError::UnspecifiedError);
- return errors;
- }
-
- // Now we can actually perform the verification of the chain we have built.
- // We ignore the result of this function since we process errors via the
- // callback.
- (void) q_X509_verify_cert(storeContext);
- ctxGuard.reset();
- q_OPENSSL_sk_free((OPENSSL_STACK *)intermediates);
-
- // Now process the errors
-
- if (QSslCertificatePrivate::isBlacklisted(certificateChain[0])) {
- QSslError error(QSslError::CertificateBlacklisted, certificateChain[0]);
- errors << error;
- }
-
- // Check the certificate name against the hostname if one was specified
- if ((!hostName.isEmpty()) && (!isMatchingHostname(certificateChain[0], hostName))) {
- // No matches in common names or alternate names.
- QSslError error(QSslError::HostNameMismatch, certificateChain[0]);
- errors << error;
- }
-
- // Translate errors from the error list into QSslErrors.
- errors.reserve(errors.size() + lastErrors.size());
- for (const auto &error : qAsConst(lastErrors))
- errors << _q_OpenSSL_to_QSslError(error.code, certificateChain.value(error.depth));
-
- return errors;
-}
-
-bool QSslSocketBackendPrivate::importPkcs12(QIODevice *device,
- QSslKey *key, QSslCertificate *cert,
- QList<QSslCertificate> *caCertificates,
- const QByteArray &passPhrase)
-{
- if (!supportsSsl())
- return false;
-
- // These are required
- Q_ASSERT(device);
- Q_ASSERT(key);
- Q_ASSERT(cert);
-
- // Read the file into a BIO
- QByteArray pkcs12data = device->readAll();
- if (pkcs12data.size() == 0)
- return false;
-
- BIO *bio = q_BIO_new_mem_buf(const_cast<char *>(pkcs12data.constData()), pkcs12data.size());
-
- // Create the PKCS#12 object
- PKCS12 *p12 = q_d2i_PKCS12_bio(bio, nullptr);
- if (!p12) {
- qCWarning(lcSsl, "Unable to read PKCS#12 structure, %s",
- q_ERR_error_string(q_ERR_get_error(), nullptr));
- q_BIO_free(bio);
- return false;
- }
-
- // Extract the data
- EVP_PKEY *pkey = nullptr;
- X509 *x509;
- STACK_OF(X509) *ca = nullptr;
-
- if (!q_PKCS12_parse(p12, passPhrase.constData(), &pkey, &x509, &ca)) {
- qCWarning(lcSsl, "Unable to parse PKCS#12 structure, %s",
- q_ERR_error_string(q_ERR_get_error(), nullptr));
- q_PKCS12_free(p12);
- q_BIO_free(bio);
- return false;
- }
-
- // Convert to Qt types
- if (!key->d->fromEVP_PKEY(pkey)) {
- qCWarning(lcSsl, "Unable to convert private key");
- q_OPENSSL_sk_pop_free(reinterpret_cast<OPENSSL_STACK *>(ca),
- reinterpret_cast<void (*)(void *)>(q_X509_free));
- q_X509_free(x509);
- q_EVP_PKEY_free(pkey);
- q_PKCS12_free(p12);
- q_BIO_free(bio);
-
- return false;
- }
-
- *cert = QSslCertificatePrivate::QSslCertificate_from_X509(x509);
-
- if (caCertificates)
- *caCertificates = QSslSocketBackendPrivate::STACKOFX509_to_QSslCertificates(ca);
-
- // Clean up
- q_OPENSSL_sk_pop_free(reinterpret_cast<OPENSSL_STACK *>(ca),
- reinterpret_cast<void (*)(void *)>(q_X509_free));
-
- q_X509_free(x509);
- q_EVP_PKEY_free(pkey);
- q_PKCS12_free(p12);
- q_BIO_free(bio);
-
- return true;
-}
-
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslsocket_openssl_android.cpp b/src/network/ssl/qsslsocket_openssl_android.cpp
deleted file mode 100644
index b5d2458d56..0000000000
--- a/src/network/ssl/qsslsocket_openssl_android.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-/****************************************************************************
-**
-** 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.
-**
-****************************************************************************/
-
-#include "qsslsocket_openssl_p.h"
-#include <QtCore/private/qjni_p.h>
-
-QT_BEGIN_NAMESPACE
-
-QList<QByteArray> QSslSocketPrivate::fetchSslCertificateData()
-{
- QList<QByteArray> certificateData;
-
- QJNIObjectPrivate certificates = QJNIObjectPrivate::callStaticObjectMethod("org/qtproject/qt5/android/QtNative",
- "getSSLCertificates",
- "()[[B");
- if (!certificates.isValid())
- return certificateData;
-
- QJNIEnvironmentPrivate env;
- jobjectArray jcertificates = static_cast<jobjectArray>(certificates.object());
- const jint nCertificates = env->GetArrayLength(jcertificates);
- certificateData.reserve(static_cast<int>(nCertificates));
-
- for (int i = 0; i < nCertificates; ++i) {
- jbyteArray jCert = static_cast<jbyteArray>(env->GetObjectArrayElement(jcertificates, i));
- const uint sz = env->GetArrayLength(jCert);
- jbyte *buffer = env->GetByteArrayElements(jCert, 0);
- certificateData.append(QByteArray(reinterpret_cast<char*>(buffer), sz));
-
- env->ReleaseByteArrayElements(jCert, buffer, JNI_ABORT); // don't copy back the elements
- env->DeleteLocalRef(jCert);
- }
-
- return certificateData;
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslsocket_openssl_p.h b/src/network/ssl/qsslsocket_openssl_p.h
deleted file mode 100644
index b45bbb0a30..0000000000
--- a/src/network/ssl/qsslsocket_openssl_p.h
+++ /dev/null
@@ -1,197 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-/****************************************************************************
-**
-** 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 QSSLSOCKET_OPENSSL_P_H
-#define QSSLSOCKET_OPENSSL_P_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.
-//
-
-#include <QtNetwork/private/qtnetworkglobal_p.h>
-#include "qsslsocket_p.h"
-
-#include <QtCore/qlist.h>
-#include <QtCore/qstring.h>
-
-#ifdef Q_OS_WIN
-#include <qt_windows.h>
-#if defined(OCSP_RESPONSE)
-#undef OCSP_RESPONSE
-#endif
-#if defined(X509_NAME)
-#undef X509_NAME
-#endif
-#endif // Q_OS_WIN
-
-#include <openssl/asn1.h>
-#include <openssl/bio.h>
-#include <openssl/bn.h>
-#include <openssl/err.h>
-#include <openssl/evp.h>
-#include <openssl/pem.h>
-#include <openssl/pkcs12.h>
-#include <openssl/pkcs7.h>
-#include <openssl/rand.h>
-#include <openssl/ssl.h>
-#include <openssl/stack.h>
-#include <openssl/x509.h>
-#include <openssl/x509v3.h>
-#include <openssl/x509_vfy.h>
-#include <openssl/dsa.h>
-#include <openssl/rsa.h>
-#include <openssl/crypto.h>
-#include <openssl/tls1.h>
-
-#if QT_CONFIG(opensslv11)
-#include <openssl/dh.h>
-#endif
-
-QT_BEGIN_NAMESPACE
-
-struct QSslErrorEntry {
- int code;
- int depth;
-
- static QSslErrorEntry fromStoreContext(X509_STORE_CTX *ctx);
-};
-Q_DECLARE_TYPEINFO(QSslErrorEntry, Q_PRIMITIVE_TYPE);
-
-class QSslSocketBackendPrivate : public QSslSocketPrivate
-{
- Q_DECLARE_PUBLIC(QSslSocket)
-public:
- QSslSocketBackendPrivate();
- virtual ~QSslSocketBackendPrivate();
-
- // SSL context
- bool initSslContext();
- void destroySslContext();
- SSL *ssl;
- BIO *readBio;
- BIO *writeBio;
- SSL_SESSION *session;
- QList<QSslErrorEntry> errorList;
- static int s_indexForSSLExtraData; // index used in SSL_get_ex_data to get the matching QSslSocketBackendPrivate
- enum ExDataOffset {
- errorOffsetInExData = 1,
- socketOffsetInExData = 2
- };
-
- bool inSetAndEmitError = false;
-
- // Platform specific functions
- void startClientEncryption() override;
- void startServerEncryption() override;
- void transmit() override;
- bool startHandshake();
- void disconnectFromHost() override;
- void disconnected() override;
- QSslCipher sessionCipher() const override;
- QSsl::SslProtocol sessionProtocol() const override;
- void continueHandshake() override;
- bool checkSslErrors();
- void storePeerCertificates();
- int handleNewSessionTicket(SSL *context);
- unsigned int tlsPskClientCallback(const char *hint, char *identity, unsigned int max_identity_len, unsigned char *psk, unsigned int max_psk_len);
- unsigned int tlsPskServerCallback(const char *identity, unsigned char *psk, unsigned int max_psk_len);
-#ifdef Q_OS_WIN
- void fetchCaRootForCert(const QSslCertificate &cert);
- void _q_caRootLoaded(QSslCertificate,QSslCertificate) override;
-#endif
-
-#if QT_CONFIG(ocsp)
- bool checkOcspStatus();
-#endif
-
- void alertMessageSent(int encoded);
- void alertMessageReceived(int encoded);
-
- int emitErrorFromCallback(X509_STORE_CTX *ctx);
- void trySendFatalAlert();
-
- bool pendingFatalAlert = false;
- bool errorsReportedFromCallback = false;
-
- // This decription will go to setErrorAndEmit(SslHandshakeError, ocspErrorDescription)
- QString ocspErrorDescription;
- // These will go to sslErrors()
- QList<QSslError> ocspErrors;
- QByteArray ocspResponseDer;
-
- Q_AUTOTEST_EXPORT static long setupOpenSslOptions(QSsl::SslProtocol protocol, QSsl::SslOptions sslOptions);
- static QSslCipher QSslCipher_from_SSL_CIPHER(const SSL_CIPHER *cipher);
- static QList<QSslCertificate> STACKOFX509_to_QSslCertificates(STACK_OF(X509) *x509);
- static QList<QSslError> verify(const QList<QSslCertificate> &certificateChain, const QString &hostName);
- static QList<QSslError> verify(const QList<QSslCertificate> &cas, const QList<QSslCertificate> &certificateChain,
- const QString &hostName);
- static QString getErrorsFromOpenSsl();
- static void logAndClearErrorQueue();
- static bool importPkcs12(QIODevice *device,
- QSslKey *key, QSslCertificate *cert,
- QList<QSslCertificate> *caCertificates,
- const QByteArray &passPhrase);
- static QString msgErrorsDuringHandshake();
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/network/ssl/qsslsocket_openssl_symbols.cpp b/src/network/ssl/qsslsocket_openssl_symbols.cpp
deleted file mode 100644
index 9396516670..0000000000
--- a/src/network/ssl/qsslsocket_openssl_symbols.cpp
+++ /dev/null
@@ -1,1231 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
-** Copyright (C) 2016 Richard J. Moore <rich@kde.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-/****************************************************************************
-**
-** 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.
-**
-****************************************************************************/
-
-#include "qssl_p.h"
-#include "qsslsocket_openssl_symbols_p.h"
-
-#ifdef Q_OS_WIN
-# include <private/qsystemlibrary_p.h>
-#elif QT_CONFIG(library)
-# include <QtCore/qlibrary.h>
-#endif
-#include <QtCore/qmutex.h>
-#include <QtCore/qdatetime.h>
-#if defined(Q_OS_UNIX)
-#include <QtCore/qdir.h>
-#endif
-#include <QtCore/private/qmemory_p.h>
-#include <QtCore/private/qduplicatetracker_p.h>
-#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
-#include <link.h>
-#endif
-#ifdef Q_OS_DARWIN
-#include "private/qcore_mac_p.h"
-#endif
-
-#include <algorithm>
-
-QT_BEGIN_NAMESPACE
-
-/*
- Note to maintainer:
- -------------------
-
- We load OpenSSL symbols dynamically. Because symbols are known to
- disappear, and signatures sometimes change, between releases, we need to
- be careful about how this is done. To ensure we don't end up dereferencing
- null function pointers, and continue running even if certain functions are
- missing, we define helper functions for each of the symbols we load from
- OpenSSL, all prefixed with "q_" (declared in
- qsslsocket_openssl_symbols_p.h). So instead of calling SSL_connect
- directly, we call q_SSL_connect, which is a function that checks if the
- actual SSL_connect fptr is null, and returns a failure if it is, or calls
- SSL_connect if it isn't.
-
- This requires a somewhat tedious process of declaring each function we
- want to call in OpenSSL thrice: once with the q_, in _p.h, once using the
- DEFINEFUNC macros below, and once in the function that actually resolves
- the symbols, below the DEFINEFUNC declarations below.
-
- There's one DEFINEFUNC macro declared for every number of arguments
- exposed by OpenSSL (feel free to extend when needed). The easiest thing to
- do is to find an existing entry that matches the arg count of the function
- you want to import, and do the same.
-
- The first macro arg is the function return type. The second is the
- verbatim name of the function/symbol. Then follows a list of N pairs of
- argument types with a variable name, and just the variable name (char *a,
- a, char *b, b, etc). Finally there's two arguments - a suitable return
- statement for the error case (for an int function, return 0 or return -1
- is usually right). Then either just "return" or DUMMYARG, the latter being
- for void functions.
-
- Note: Take into account that these macros and declarations are processed
- at compile-time, and the result depends on the OpenSSL headers the
- compiling host has installed, but the symbols are resolved at run-time,
- possibly with a different version of OpenSSL.
-*/
-
-#ifndef QT_LINKED_OPENSSL
-
-namespace {
-void qsslSocketUnresolvedSymbolWarning(const char *functionName)
-{
- qCWarning(lcSsl, "QSslSocket: cannot call unresolved function %s", functionName);
-}
-
-#if QT_CONFIG(library)
-void qsslSocketCannotResolveSymbolWarning(const char *functionName)
-{
- qCWarning(lcSsl, "QSslSocket: cannot resolve %s", functionName);
-}
-#endif
-
-}
-
-#endif // QT_LINKED_OPENSSL
-
-DEFINEFUNC(const unsigned char *, ASN1_STRING_get0_data, const ASN1_STRING *a, a, return nullptr, return)
-DEFINEFUNC2(int, OPENSSL_init_ssl, uint64_t opts, opts, const OPENSSL_INIT_SETTINGS *settings, settings, return 0, return)
-DEFINEFUNC2(int, OPENSSL_init_crypto, uint64_t opts, opts, const OPENSSL_INIT_SETTINGS *settings, settings, return 0, return)
-DEFINEFUNC(BIO *, BIO_new, const BIO_METHOD *a, a, return nullptr, return)
-DEFINEFUNC(const BIO_METHOD *, BIO_s_mem, void, DUMMYARG, return nullptr, return)
-DEFINEFUNC2(int, BN_is_word, BIGNUM *a, a, BN_ULONG w, w, return 0, return)
-DEFINEFUNC(int, EVP_CIPHER_CTX_reset, EVP_CIPHER_CTX *c, c, return 0, return)
-DEFINEFUNC(int, EVP_PKEY_up_ref, EVP_PKEY *a, a, return 0, return)
-DEFINEFUNC2(EVP_PKEY_CTX *, EVP_PKEY_CTX_new, EVP_PKEY *pkey, pkey, ENGINE *e, e, return nullptr, return)
-DEFINEFUNC(int, EVP_PKEY_param_check, EVP_PKEY_CTX *ctx, ctx, return 0, return)
-DEFINEFUNC(void, EVP_PKEY_CTX_free, EVP_PKEY_CTX *ctx, ctx, return, return)
-DEFINEFUNC(int, EVP_PKEY_base_id, EVP_PKEY *a, a, return NID_undef, return)
-DEFINEFUNC(int, RSA_bits, RSA *a, a, return 0, return)
-DEFINEFUNC(int, DSA_bits, DSA *a, a, return 0, return)
-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)
-DEFINEFUNC(int, SSL_session_reused, SSL *a, a, return 0, return)
-DEFINEFUNC2(unsigned long, SSL_CTX_set_options, SSL_CTX *ctx, ctx, unsigned long op, op, return 0, return)
-using info_callback = void (*) (const SSL *ssl, int type, int val);
-DEFINEFUNC2(void, SSL_set_info_callback, SSL *ssl, ssl, info_callback cb, cb, return, return)
-DEFINEFUNC(const char *, SSL_alert_type_string, int value, value, return nullptr, return)
-DEFINEFUNC(const char *, SSL_alert_desc_string_long, int value, value, return nullptr, return)
-DEFINEFUNC(int, SSL_CTX_get_security_level, const SSL_CTX *ctx, ctx, return -1, return)
-DEFINEFUNC2(void, SSL_CTX_set_security_level, SSL_CTX *ctx, ctx, int level, level, return, return)
-#ifdef TLS1_3_VERSION
-DEFINEFUNC2(int, SSL_CTX_set_ciphersuites, SSL_CTX *ctx, ctx, const char *str, str, return 0, return)
-DEFINEFUNC2(void, SSL_set_psk_use_session_callback, SSL *ssl, ssl, q_SSL_psk_use_session_cb_func_t callback, callback, return, DUMMYARG)
-DEFINEFUNC2(void, SSL_CTX_sess_set_new_cb, SSL_CTX *ctx, ctx, NewSessionCallback cb, cb, return, return)
-DEFINEFUNC(int, SSL_SESSION_is_resumable, const SSL_SESSION *s, s, return 0, return)
-#endif
-DEFINEFUNC3(size_t, SSL_get_client_random, SSL *a, a, unsigned char *out, out, size_t outlen, outlen, return 0, return)
-DEFINEFUNC3(size_t, SSL_SESSION_get_master_key, const SSL_SESSION *ses, ses, unsigned char *out, out, size_t outlen, outlen, return 0, return)
-DEFINEFUNC6(int, CRYPTO_get_ex_new_index, int class_index, class_index, long argl, argl, void *argp, argp, CRYPTO_EX_new *new_func, new_func, CRYPTO_EX_dup *dup_func, dup_func, CRYPTO_EX_free *free_func, free_func, return -1, return)
-DEFINEFUNC2(unsigned long, SSL_set_options, SSL *ssl, ssl, unsigned long op, op, return 0, return)
-
-DEFINEFUNC(const SSL_METHOD *, TLS_method, DUMMYARG, DUMMYARG, return nullptr, return)
-DEFINEFUNC(const SSL_METHOD *, TLS_client_method, DUMMYARG, DUMMYARG, return nullptr, return)
-DEFINEFUNC(const SSL_METHOD *, TLS_server_method, DUMMYARG, DUMMYARG, return nullptr, return)
-DEFINEFUNC(void, X509_up_ref, X509 *a, a, return, DUMMYARG)
-DEFINEFUNC(ASN1_TIME *, X509_getm_notBefore, X509 *a, a, return nullptr, return)
-DEFINEFUNC(ASN1_TIME *, X509_getm_notAfter, X509 *a, a, return nullptr, return)
-DEFINEFUNC(long, X509_get_version, X509 *a, a, return -1, return)
-DEFINEFUNC(EVP_PKEY *, X509_get_pubkey, X509 *a, a, return nullptr, return)
-DEFINEFUNC2(void, X509_STORE_set_verify_cb, X509_STORE *a, a, X509_STORE_CTX_verify_cb verify_cb, verify_cb, return, DUMMYARG)
-DEFINEFUNC3(int, X509_STORE_set_ex_data, X509_STORE *a, a, int idx, idx, void *data, data, return 0, return)
-DEFINEFUNC2(void *, X509_STORE_get_ex_data, X509_STORE *r, r, int idx, idx, return nullptr, return)
-DEFINEFUNC(STACK_OF(X509) *, X509_STORE_CTX_get0_chain, X509_STORE_CTX *a, a, return nullptr, return)
-DEFINEFUNC3(void, CRYPTO_free, void *str, str, const char *file, file, int line, line, return, DUMMYARG)
-DEFINEFUNC(long, OpenSSL_version_num, void, DUMMYARG, return 0, return)
-DEFINEFUNC(const char *, OpenSSL_version, int a, a, return nullptr, return)
-DEFINEFUNC(unsigned long, SSL_SESSION_get_ticket_lifetime_hint, const SSL_SESSION *session, session, return 0, return)
-DEFINEFUNC4(void, DH_get0_pqg, const DH *dh, dh, const BIGNUM **p, p, const BIGNUM **q, q, const BIGNUM **g, g, return, DUMMYARG)
-DEFINEFUNC(int, DH_bits, DH *dh, dh, return 0, return)
-
-#if QT_CONFIG(dtls)
-DEFINEFUNC2(int, DTLSv1_listen, SSL *s, s, BIO_ADDR *c, c, return -1, return)
-DEFINEFUNC(BIO_ADDR *, BIO_ADDR_new, DUMMYARG, DUMMYARG, return nullptr, return)
-DEFINEFUNC(void, BIO_ADDR_free, BIO_ADDR *ap, ap, return, DUMMYARG)
-DEFINEFUNC2(BIO_METHOD *, BIO_meth_new, int type, type, const char *name, name, return nullptr, return)
-DEFINEFUNC(void, BIO_meth_free, BIO_METHOD *biom, biom, return, DUMMYARG)
-DEFINEFUNC2(int, BIO_meth_set_write, BIO_METHOD *biom, biom, DgramWriteCallback write, write, return 0, return)
-DEFINEFUNC2(int, BIO_meth_set_read, BIO_METHOD *biom, biom, DgramReadCallback read, read, return 0, return)
-DEFINEFUNC2(int, BIO_meth_set_puts, BIO_METHOD *biom, biom, DgramPutsCallback puts, puts, return 0, return)
-DEFINEFUNC2(int, BIO_meth_set_ctrl, BIO_METHOD *biom, biom, DgramCtrlCallback ctrl, ctrl, return 0, return)
-DEFINEFUNC2(int, BIO_meth_set_create, BIO_METHOD *biom, biom, DgramCreateCallback crt, crt, return 0, return)
-DEFINEFUNC2(int, BIO_meth_set_destroy, BIO_METHOD *biom, biom, DgramDestroyCallback dtr, dtr, return 0, return)
-#endif // dtls
-
-#if QT_CONFIG(ocsp)
-DEFINEFUNC(const OCSP_CERTID *, OCSP_SINGLERESP_get0_id, const OCSP_SINGLERESP *x, x, return nullptr, return)
-DEFINEFUNC3(OCSP_RESPONSE *, d2i_OCSP_RESPONSE, OCSP_RESPONSE **a, a, const unsigned char **in, in, long len, len, return nullptr, return)
-DEFINEFUNC(void, OCSP_RESPONSE_free, OCSP_RESPONSE *rs, rs, return, DUMMYARG)
-DEFINEFUNC(OCSP_BASICRESP *, OCSP_response_get1_basic, OCSP_RESPONSE *resp, resp, return nullptr, return)
-DEFINEFUNC(void, OCSP_BASICRESP_free, OCSP_BASICRESP *bs, bs, return, DUMMYARG)
-DEFINEFUNC(int, OCSP_response_status, OCSP_RESPONSE *resp, resp, return OCSP_RESPONSE_STATUS_INTERNALERROR, return)
-DEFINEFUNC4(int, OCSP_basic_verify, OCSP_BASICRESP *bs, bs, STACK_OF(X509) *certs, certs, X509_STORE *st, st, unsigned long flags, flags, return -1, return)
-DEFINEFUNC(int, OCSP_resp_count, OCSP_BASICRESP *bs, bs, return 0, return)
-DEFINEFUNC2(OCSP_SINGLERESP *, OCSP_resp_get0, OCSP_BASICRESP *bs, bs, int idx, idx, return nullptr, return)
-DEFINEFUNC5(int, OCSP_single_get0_status, OCSP_SINGLERESP *single, single, int *reason, reason, ASN1_GENERALIZEDTIME **revtime, revtime,
- ASN1_GENERALIZEDTIME **thisupd, thisupd, ASN1_GENERALIZEDTIME **nextupd, nextupd, return -1, return)
-DEFINEFUNC4(int, OCSP_check_validity, ASN1_GENERALIZEDTIME *thisupd, thisupd, ASN1_GENERALIZEDTIME *nextupd, nextupd, long nsec, nsec, long maxsec, maxsec, return 0, return)
-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)
-DEFINEFUNC5(int, OCSP_id_get0_info, ASN1_OCTET_STRING **piNameHash, piNameHash, ASN1_OBJECT **pmd, pmd,
- ASN1_OCTET_STRING **piKeyHash, piKeyHash, ASN1_INTEGER **pserial, pserial, OCSP_CERTID *cid, cid,
- return 0, return)
-DEFINEFUNC2(OCSP_RESPONSE *, OCSP_response_create, int status, status, OCSP_BASICRESP *bs, bs, return nullptr, return)
-DEFINEFUNC(const STACK_OF(X509) *, OCSP_resp_get0_certs, const OCSP_BASICRESP *bs, bs, return nullptr, return)
-DEFINEFUNC2(int, OCSP_id_cmp, OCSP_CERTID *a, a, OCSP_CERTID *b, b, return -1, return)
-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)
-DEFINEFUNC(OCSP_BASICRESP *, OCSP_BASICRESP_new, DUMMYARG, DUMMYARG, return nullptr, return)
-DEFINEFUNC2(int, i2d_OCSP_RESPONSE, OCSP_RESPONSE *r, r, unsigned char **ppout, ppout, return 0, 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)
-#endif // ocsp
-
-DEFINEFUNC2(void, BIO_set_data, BIO *a, a, void *ptr, ptr, return, DUMMYARG)
-DEFINEFUNC(void *, BIO_get_data, BIO *a, a, return nullptr, return)
-DEFINEFUNC2(void, BIO_set_init, BIO *a, a, int init, init, return, DUMMYARG)
-DEFINEFUNC(int, BIO_get_shutdown, BIO *a, a, return -1, return)
-DEFINEFUNC2(void, BIO_set_shutdown, BIO *a, a, int shut, shut, return, DUMMYARG)
-
-DEFINEFUNC(long, ASN1_INTEGER_get, ASN1_INTEGER *a, a, return 0, return)
-DEFINEFUNC2(int, ASN1_INTEGER_cmp, const ASN1_INTEGER *a, a, const ASN1_INTEGER *b, b, return 1, return)
-DEFINEFUNC(int, ASN1_STRING_length, ASN1_STRING *a, a, return 0, return)
-DEFINEFUNC2(int, ASN1_STRING_to_UTF8, unsigned char **a, a, ASN1_STRING *b, b, return 0, return)
-DEFINEFUNC2(int, ASN1_TIME_to_tm, const ASN1_TIME *s, s, struct tm *tm, tm, return 0, return)
-DEFINEFUNC4(long, BIO_ctrl, BIO *a, a, int b, b, long c, c, void *d, d, return -1, return)
-DEFINEFUNC(int, BIO_free, BIO *a, a, return 0, return)
-DEFINEFUNC2(BIO *, BIO_new_mem_buf, void *a, a, int b, b, return nullptr, return)
-DEFINEFUNC3(int, BIO_read, BIO *a, a, void *b, b, int c, c, return -1, return)
-
-DEFINEFUNC3(int, BIO_write, BIO *a, a, const void *b, b, int c, c, return -1, return)
-DEFINEFUNC(int, BN_num_bits, const BIGNUM *a, a, return 0, return)
-DEFINEFUNC2(BN_ULONG, BN_mod_word, const BIGNUM *a, a, BN_ULONG w, w, return static_cast<BN_ULONG>(-1), return)
-#ifndef OPENSSL_NO_EC
-DEFINEFUNC(const EC_GROUP*, EC_KEY_get0_group, const EC_KEY* k, k, return nullptr, return)
-DEFINEFUNC(int, EC_GROUP_get_degree, const EC_GROUP* g, g, return 0, return)
-#endif
-DEFINEFUNC(DSA *, DSA_new, DUMMYARG, DUMMYARG, return nullptr, return)
-DEFINEFUNC(void, DSA_free, DSA *a, a, return, DUMMYARG)
-DEFINEFUNC3(X509 *, d2i_X509, X509 **a, a, const unsigned char **b, b, long c, c, return nullptr, return)
-DEFINEFUNC2(char *, ERR_error_string, unsigned long a, a, char *b, b, return nullptr, return)
-DEFINEFUNC3(void, ERR_error_string_n, unsigned long e, e, char *b, b, size_t len, len, return, DUMMYARG)
-DEFINEFUNC(unsigned long, ERR_get_error, DUMMYARG, DUMMYARG, return 0, return)
-DEFINEFUNC(EVP_CIPHER_CTX *, EVP_CIPHER_CTX_new, void, DUMMYARG, return nullptr, return)
-DEFINEFUNC(void, EVP_CIPHER_CTX_free, EVP_CIPHER_CTX *a, a, return, DUMMYARG)
-DEFINEFUNC4(int, EVP_CIPHER_CTX_ctrl, EVP_CIPHER_CTX *ctx, ctx, int type, type, int arg, arg, void *ptr, ptr, return 0, return)
-DEFINEFUNC2(int, EVP_CIPHER_CTX_set_key_length, EVP_CIPHER_CTX *ctx, ctx, int keylen, keylen, return 0, return)
-DEFINEFUNC5(int, EVP_CipherInit, EVP_CIPHER_CTX *ctx, ctx, const EVP_CIPHER *type, type, const unsigned char *key, key, const unsigned char *iv, iv, int enc, enc, return 0, return)
-DEFINEFUNC6(int, EVP_CipherInit_ex, EVP_CIPHER_CTX *ctx, ctx, const EVP_CIPHER *cipher, cipher, ENGINE *impl, impl, const unsigned char *key, key, const unsigned char *iv, iv, int enc, enc, return 0, return)
-DEFINEFUNC5(int, EVP_CipherUpdate, EVP_CIPHER_CTX *ctx, ctx, unsigned char *out, out, int *outl, outl, const unsigned char *in, in, int inl, inl, return 0, return)
-DEFINEFUNC3(int, EVP_CipherFinal, EVP_CIPHER_CTX *ctx, ctx, unsigned char *out, out, int *outl, outl, return 0, return)
-DEFINEFUNC(const EVP_MD *, EVP_get_digestbyname, const char *name, name, return nullptr, return)
-#ifndef OPENSSL_NO_DES
-DEFINEFUNC(const EVP_CIPHER *, EVP_des_cbc, DUMMYARG, DUMMYARG, return nullptr, return)
-DEFINEFUNC(const EVP_CIPHER *, EVP_des_ede3_cbc, DUMMYARG, DUMMYARG, return nullptr, return)
-#endif
-#ifndef OPENSSL_NO_RC2
-DEFINEFUNC(const EVP_CIPHER *, EVP_rc2_cbc, DUMMYARG, DUMMYARG, return nullptr, return)
-#endif
-#ifndef OPENSSL_NO_AES
-DEFINEFUNC(const EVP_CIPHER *, EVP_aes_128_cbc, DUMMYARG, DUMMYARG, return nullptr, return)
-DEFINEFUNC(const EVP_CIPHER *, EVP_aes_192_cbc, DUMMYARG, DUMMYARG, return nullptr, return)
-DEFINEFUNC(const EVP_CIPHER *, EVP_aes_256_cbc, DUMMYARG, DUMMYARG, return nullptr, return)
-#endif
-DEFINEFUNC(const EVP_MD *, EVP_sha1, DUMMYARG, DUMMYARG, return nullptr, return)
-DEFINEFUNC3(int, EVP_PKEY_assign, EVP_PKEY *a, a, int b, b, void *r, r, return -1, 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)
-DEFINEFUNC(void, EVP_PKEY_free, EVP_PKEY *a, a, return, DUMMYARG)
-DEFINEFUNC(DSA *, EVP_PKEY_get1_DSA, EVP_PKEY *a, a, return nullptr, return)
-DEFINEFUNC(RSA *, EVP_PKEY_get1_RSA, EVP_PKEY *a, a, return nullptr, return)
-DEFINEFUNC(DH *, EVP_PKEY_get1_DH, EVP_PKEY *a, a, return nullptr, return)
-#ifndef OPENSSL_NO_EC
-DEFINEFUNC(EC_KEY *, EVP_PKEY_get1_EC_KEY, EVP_PKEY *a, a, return nullptr, return)
-#endif
-DEFINEFUNC(EVP_PKEY *, EVP_PKEY_new, DUMMYARG, DUMMYARG, return nullptr, return)
-DEFINEFUNC(int, EVP_PKEY_type, int a, a, return NID_undef, return)
-DEFINEFUNC2(int, i2d_X509, X509 *a, a, unsigned char **b, b, return -1, return)
-DEFINEFUNC(const char *, OBJ_nid2sn, int a, a, return nullptr, return)
-DEFINEFUNC(const char *, OBJ_nid2ln, int a, a, return nullptr, return)
-DEFINEFUNC(int, OBJ_sn2nid, const char *s, s, return 0, return)
-DEFINEFUNC(int, OBJ_ln2nid, const char *s, s, return 0, return)
-DEFINEFUNC3(int, i2t_ASN1_OBJECT, char *a, a, int b, b, ASN1_OBJECT *c, c, return -1, return)
-DEFINEFUNC4(int, OBJ_obj2txt, char *a, a, int b, b, ASN1_OBJECT *c, c, int d, d, return -1, return)
-DEFINEFUNC(int, OBJ_obj2nid, const ASN1_OBJECT *a, a, return NID_undef, 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(DSA *, PEM_read_bio_DSAPrivateKey, BIO *a, a, DSA **b, b, pem_password_cb *c, c, void *d, d, return nullptr, return)
-DEFINEFUNC4(RSA *, PEM_read_bio_RSAPrivateKey, BIO *a, a, RSA **b, b, pem_password_cb *c, c, void *d, d, return nullptr, return)
-
-#ifndef OPENSSL_NO_EC
-DEFINEFUNC4(EC_KEY *, PEM_read_bio_ECPrivateKey, BIO *a, a, EC_KEY **b, b, pem_password_cb *c, c, void *d, d, return nullptr, return)
-DEFINEFUNC7(int, PEM_write_bio_ECPrivateKey, BIO *a, a, EC_KEY *b, b, const EVP_CIPHER *c, c, unsigned char *d, d, int e, e, pem_password_cb *f, f, void *g, g, return 0, return)
-DEFINEFUNC4(EC_KEY *, PEM_read_bio_EC_PUBKEY, BIO *a, a, EC_KEY **b, b, pem_password_cb *c, c, void *d, d, return nullptr, return)
-DEFINEFUNC2(int, PEM_write_bio_EC_PUBKEY, BIO *a, a, EC_KEY *b, b, return 0, return)
-#endif // OPENSSL_NO_EC
-
-DEFINEFUNC4(DH *, PEM_read_bio_DHparams, BIO *a, a, DH **b, b, pem_password_cb *c, c, void *d, d, return nullptr, return)
-DEFINEFUNC7(int, PEM_write_bio_DSAPrivateKey, BIO *a, a, DSA *b, b, const EVP_CIPHER *c, c, unsigned char *d, d, int e, e, pem_password_cb *f, f, void *g, g, return 0, return)
-DEFINEFUNC7(int, PEM_write_bio_RSAPrivateKey, BIO *a, a, RSA *b, b, const EVP_CIPHER *c, c, unsigned char *d, d, int e, e, pem_password_cb *f, f, void *g, g, return 0, return)
-DEFINEFUNC7(int, PEM_write_bio_PrivateKey, BIO *a, a, EVP_PKEY *b, b, const EVP_CIPHER *c, c, unsigned char *d, d, int e, e, pem_password_cb *f, f, void *g, g, return 0, 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)
-DEFINEFUNC4(DSA *, PEM_read_bio_DSA_PUBKEY, BIO *a, a, DSA **b, b, pem_password_cb *c, c, void *d, d, return nullptr, return)
-DEFINEFUNC4(RSA *, PEM_read_bio_RSA_PUBKEY, BIO *a, a, RSA **b, b, pem_password_cb *c, c, void *d, d, return nullptr, return)
-DEFINEFUNC2(int, PEM_write_bio_DSA_PUBKEY, BIO *a, a, DSA *b, b, return 0, return)
-DEFINEFUNC2(int, PEM_write_bio_RSA_PUBKEY, BIO *a, a, RSA *b, b, return 0, return)
-DEFINEFUNC2(int, PEM_write_bio_PUBKEY, BIO *a, a, EVP_PKEY *b, b, return 0, return)
-DEFINEFUNC2(void, RAND_seed, const void *a, a, int b, b, return, DUMMYARG)
-DEFINEFUNC(int, RAND_status, void, DUMMYARG, return -1, return)
-DEFINEFUNC2(int, RAND_bytes, unsigned char *b, b, int n, n, return 0, return)
-DEFINEFUNC(RSA *, RSA_new, DUMMYARG, DUMMYARG, return nullptr, return)
-DEFINEFUNC(void, RSA_free, RSA *a, a, return, DUMMYARG)
-DEFINEFUNC(int, SSL_accept, SSL *a, a, return -1, return)
-DEFINEFUNC(int, SSL_clear, SSL *a, a, return -1, return)
-DEFINEFUNC3(char *, SSL_CIPHER_description, const SSL_CIPHER *a, a, char *b, b, int c, c, return nullptr, return)
-DEFINEFUNC2(int, SSL_CIPHER_get_bits, const SSL_CIPHER *a, a, int *b, b, return 0, return)
-DEFINEFUNC(BIO *, SSL_get_rbio, const SSL *s, s, return nullptr, return)
-DEFINEFUNC(int, SSL_connect, SSL *a, a, return -1, return)
-DEFINEFUNC(int, SSL_CTX_check_private_key, const SSL_CTX *a, a, return -1, return)
-DEFINEFUNC4(long, SSL_CTX_ctrl, SSL_CTX *a, a, int b, b, long c, c, void *d, d, return -1, return)
-DEFINEFUNC(void, SSL_CTX_free, SSL_CTX *a, a, return, DUMMYARG)
-DEFINEFUNC(SSL_CTX *, SSL_CTX_new, const SSL_METHOD *a, a, return nullptr, return)
-DEFINEFUNC2(int, SSL_CTX_set_cipher_list, SSL_CTX *a, a, const char *b, b, return -1, return)
-DEFINEFUNC3(long, SSL_CTX_callback_ctrl, SSL_CTX *ctx, ctx, int dst, dst, GenericCallbackType cb, cb, return 0, return)
-DEFINEFUNC(int, SSL_CTX_set_default_verify_paths, SSL_CTX *a, a, return -1, return)
-DEFINEFUNC3(void, SSL_CTX_set_verify, SSL_CTX *a, a, int b, b, int (*c)(int, X509_STORE_CTX *), c, return, DUMMYARG)
-DEFINEFUNC2(void, SSL_CTX_set_verify_depth, SSL_CTX *a, a, int b, b, return, DUMMYARG)
-DEFINEFUNC2(int, SSL_CTX_use_certificate, SSL_CTX *a, a, X509 *b, b, return -1, return)
-DEFINEFUNC3(int, SSL_CTX_use_certificate_file, SSL_CTX *a, a, const char *b, b, int c, c, return -1, return)
-DEFINEFUNC2(int, SSL_CTX_use_PrivateKey, SSL_CTX *a, a, EVP_PKEY *b, b, return -1, return)
-DEFINEFUNC2(int, SSL_CTX_use_RSAPrivateKey, SSL_CTX *a, a, RSA *b, b, return -1, return)
-DEFINEFUNC3(int, SSL_CTX_use_PrivateKey_file, SSL_CTX *a, a, const char *b, b, int c, c, return -1, return)
-DEFINEFUNC(X509_STORE *, SSL_CTX_get_cert_store, const SSL_CTX *a, a, return nullptr, return)
-DEFINEFUNC(SSL_CONF_CTX *, SSL_CONF_CTX_new, DUMMYARG, DUMMYARG, return nullptr, return);
-DEFINEFUNC(void, SSL_CONF_CTX_free, SSL_CONF_CTX *a, a, return ,return);
-DEFINEFUNC2(void, SSL_CONF_CTX_set_ssl_ctx, SSL_CONF_CTX *a, a, SSL_CTX *b, b, return, return);
-DEFINEFUNC2(unsigned int, SSL_CONF_CTX_set_flags, SSL_CONF_CTX *a, a, unsigned int b, b, return 0, return);
-DEFINEFUNC(int, SSL_CONF_CTX_finish, SSL_CONF_CTX *a, a, return 0, return);
-DEFINEFUNC3(int, SSL_CONF_cmd, SSL_CONF_CTX *a, a, const char *b, b, const char *c, c, return 0, return);
-DEFINEFUNC(void, SSL_free, SSL *a, a, return, DUMMYARG)
-DEFINEFUNC(STACK_OF(SSL_CIPHER) *, SSL_get_ciphers, const SSL *a, a, return nullptr, return)
-DEFINEFUNC(const SSL_CIPHER *, SSL_get_current_cipher, SSL *a, a, return nullptr, return)
-DEFINEFUNC(int, SSL_version, const SSL *a, a, return 0, return)
-DEFINEFUNC2(int, SSL_get_error, SSL *a, a, int b, b, return -1, return)
-DEFINEFUNC(STACK_OF(X509) *, SSL_get_peer_cert_chain, SSL *a, a, return nullptr, return)
-DEFINEFUNC(X509 *, SSL_get_peer_certificate, SSL *a, a, return nullptr, return)
-DEFINEFUNC(long, SSL_get_verify_result, const SSL *a, a, return -1, return)
-DEFINEFUNC(SSL *, SSL_new, SSL_CTX *a, a, return nullptr, return)
-DEFINEFUNC(SSL_CTX *, SSL_get_SSL_CTX, SSL *a, a, return nullptr, return)
-DEFINEFUNC4(long, SSL_ctrl, SSL *a, a, int cmd, cmd, long larg, larg, void *parg, parg, return -1, return)
-DEFINEFUNC3(int, SSL_read, SSL *a, a, void *b, b, int c, c, return -1, return)
-DEFINEFUNC3(void, SSL_set_bio, SSL *a, a, BIO *b, b, BIO *c, c, return, DUMMYARG)
-DEFINEFUNC(void, SSL_set_accept_state, SSL *a, a, return, DUMMYARG)
-DEFINEFUNC(void, SSL_set_connect_state, SSL *a, a, return, DUMMYARG)
-DEFINEFUNC(int, SSL_shutdown, SSL *a, a, return -1, return)
-DEFINEFUNC(int, SSL_in_init, const SSL *a, a, return 0, return)
-DEFINEFUNC(int, SSL_get_shutdown, const SSL *ssl, ssl, return 0, return)
-DEFINEFUNC2(int, SSL_set_session, SSL* to, to, SSL_SESSION *session, session, return -1, return)
-DEFINEFUNC(void, SSL_SESSION_free, SSL_SESSION *ses, ses, return, DUMMYARG)
-DEFINEFUNC(SSL_SESSION*, SSL_get1_session, SSL *ssl, ssl, return nullptr, return)
-DEFINEFUNC(SSL_SESSION*, SSL_get_session, const SSL *ssl, ssl, return nullptr, return)
-DEFINEFUNC3(int, SSL_set_ex_data, SSL *ssl, ssl, int idx, idx, void *arg, arg, return 0, return)
-DEFINEFUNC2(void *, SSL_get_ex_data, const SSL *ssl, ssl, int idx, idx, return nullptr, return)
-
-#ifndef OPENSSL_NO_PSK
-DEFINEFUNC2(void, SSL_set_psk_client_callback, SSL* ssl, ssl, q_psk_client_callback_t callback, callback, return, DUMMYARG)
-DEFINEFUNC2(void, SSL_set_psk_server_callback, SSL* ssl, ssl, q_psk_server_callback_t callback, callback, return, DUMMYARG)
-DEFINEFUNC2(int, SSL_CTX_use_psk_identity_hint, SSL_CTX* ctx, ctx, const char *hint, hint, return 0, return)
-#endif // !OPENSSL_NO_PSK
-
-DEFINEFUNC3(int, SSL_write, SSL *a, a, const void *b, b, int c, c, return -1, return)
-DEFINEFUNC2(int, X509_cmp, X509 *a, a, X509 *b, b, return -1, return)
-DEFINEFUNC4(int, X509_digest, const X509 *x509, x509, const EVP_MD *type, type, unsigned char *md, md, unsigned int *len, len, return -1, return)
-DEFINEFUNC(X509 *, X509_dup, X509 *a, a, return nullptr, return)
-DEFINEFUNC2(void, X509_print, BIO *a, a, X509 *b, b, return, DUMMYARG);
-DEFINEFUNC(ASN1_OBJECT *, X509_EXTENSION_get_object, X509_EXTENSION *a, a, return nullptr, return)
-DEFINEFUNC(void, X509_free, X509 *a, a, return, DUMMYARG)
-//Q_AUTOTEST_EXPORT ASN1_TIME *q_X509_gmtime_adj(ASN1_TIME *s, long adj);
-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)
-DEFINEFUNC2(X509_EXTENSION *, X509_get_ext, X509 *a, a, int b, b, return nullptr, return)
-DEFINEFUNC(int, X509_get_ext_count, X509 *a, a, return 0, return)
-DEFINEFUNC4(void *, X509_get_ext_d2i, X509 *a, a, int b, b, int *c, c, int *d, d, return nullptr, return)
-DEFINEFUNC(const X509V3_EXT_METHOD *, X509V3_EXT_get, X509_EXTENSION *a, a, return nullptr, return)
-DEFINEFUNC(void *, X509V3_EXT_d2i, X509_EXTENSION *a, a, return nullptr, return)
-DEFINEFUNC(int, X509_EXTENSION_get_critical, X509_EXTENSION *a, a, return 0, return)
-DEFINEFUNC(ASN1_OCTET_STRING *, X509_EXTENSION_get_data, X509_EXTENSION *a, a, return nullptr, return)
-DEFINEFUNC(void, BASIC_CONSTRAINTS_free, BASIC_CONSTRAINTS *a, a, return, DUMMYARG)
-DEFINEFUNC(void, AUTHORITY_KEYID_free, AUTHORITY_KEYID *a, a, return, DUMMYARG)
-DEFINEFUNC(void, GENERAL_NAME_free, GENERAL_NAME *a, a, return, DUMMYARG)
-DEFINEFUNC2(int, ASN1_STRING_print, BIO *a, a, const ASN1_STRING *b, b, return 0, return)
-DEFINEFUNC2(int, X509_check_issued, X509 *a, a, X509 *b, b, return -1, return)
-DEFINEFUNC(X509_NAME *, X509_get_issuer_name, X509 *a, a, return nullptr, return)
-DEFINEFUNC(X509_NAME *, X509_get_subject_name, X509 *a, a, return nullptr, return)
-DEFINEFUNC(ASN1_INTEGER *, X509_get_serialNumber, X509 *a, a, return nullptr, return)
-DEFINEFUNC(int, X509_verify_cert, X509_STORE_CTX *a, a, return -1, return)
-DEFINEFUNC(int, X509_NAME_entry_count, X509_NAME *a, a, return 0, return)
-DEFINEFUNC2(X509_NAME_ENTRY *, X509_NAME_get_entry, X509_NAME *a, a, int b, b, return nullptr, return)
-DEFINEFUNC(ASN1_STRING *, X509_NAME_ENTRY_get_data, X509_NAME_ENTRY *a, a, return nullptr, return)
-DEFINEFUNC(ASN1_OBJECT *, X509_NAME_ENTRY_get_object, X509_NAME_ENTRY *a, a, return nullptr, return)
-DEFINEFUNC(EVP_PKEY *, X509_PUBKEY_get, X509_PUBKEY *a, a, return nullptr, return)
-DEFINEFUNC(void, X509_STORE_free, X509_STORE *a, a, return, DUMMYARG)
-DEFINEFUNC(X509_STORE *, X509_STORE_new, DUMMYARG, DUMMYARG, return nullptr, return)
-DEFINEFUNC2(int, X509_STORE_add_cert, X509_STORE *a, a, X509 *b, b, return 0, return)
-DEFINEFUNC(void, X509_STORE_CTX_free, X509_STORE_CTX *a, a, return, DUMMYARG)
-DEFINEFUNC4(int, X509_STORE_CTX_init, X509_STORE_CTX *a, a, X509_STORE *b, b, X509 *c, c, STACK_OF(X509) *d, d, return -1, return)
-DEFINEFUNC2(int, X509_STORE_CTX_set_purpose, X509_STORE_CTX *a, a, int b, b, return -1, return)
-DEFINEFUNC(int, X509_STORE_CTX_get_error, X509_STORE_CTX *a, a, return -1, return)
-DEFINEFUNC(int, X509_STORE_CTX_get_error_depth, X509_STORE_CTX *a, a, return -1, return)
-DEFINEFUNC(X509 *, X509_STORE_CTX_get_current_cert, X509_STORE_CTX *a, a, return nullptr, return)
-DEFINEFUNC(X509_STORE *, X509_STORE_CTX_get0_store, X509_STORE_CTX *ctx, ctx, return nullptr, return)
-DEFINEFUNC(X509_STORE_CTX *, X509_STORE_CTX_new, DUMMYARG, DUMMYARG, return nullptr, return)
-DEFINEFUNC2(void *, X509_STORE_CTX_get_ex_data, X509_STORE_CTX *ctx, ctx, int idx, idx, return nullptr, return)
-DEFINEFUNC(int, SSL_get_ex_data_X509_STORE_CTX_idx, DUMMYARG, DUMMYARG, return -1, return)
-
-#if OPENSSL_VERSION_MAJOR < 3
-DEFINEFUNC3(int, SSL_CTX_load_verify_locations, SSL_CTX *ctx, ctx, const char *CAfile, CAfile, const char *CApath, CApath, return 0, return)
-#else
-DEFINEFUNC2(int, SSL_CTX_load_verify_dir, SSL_CTX *ctx, ctx, const char *CApath, CApath, return 0, return)
-#endif // OPENSSL_VERSION_MAJOR
-
-DEFINEFUNC2(int, i2d_SSL_SESSION, SSL_SESSION *in, in, unsigned char **pp, pp, return 0, return)
-DEFINEFUNC3(SSL_SESSION *, d2i_SSL_SESSION, SSL_SESSION **a, a, const unsigned char **pp, pp, long length, length, return nullptr, return)
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
-DEFINEFUNC6(int, SSL_select_next_proto, unsigned char **out, out, unsigned char *outlen, outlen,
- const unsigned char *in, in, unsigned int inlen, inlen,
- const unsigned char *client, client, unsigned int client_len, client_len,
- return -1, return)
-DEFINEFUNC3(void, SSL_CTX_set_next_proto_select_cb, SSL_CTX *s, s,
- int (*cb) (SSL *ssl, unsigned char **out,
- unsigned char *outlen,
- const unsigned char *in,
- unsigned int inlen, void *arg), cb,
- void *arg, arg, return, DUMMYARG)
-DEFINEFUNC3(void, SSL_get0_next_proto_negotiated, const SSL *s, s,
- const unsigned char **data, data, unsigned *len, len, return, DUMMYARG)
-DEFINEFUNC3(int, SSL_set_alpn_protos, SSL *s, s, const unsigned char *protos, protos,
- unsigned protos_len, protos_len, return -1, return)
-DEFINEFUNC3(void, SSL_CTX_set_alpn_select_cb, SSL_CTX *s, s,
- int (*cb) (SSL *ssl, const unsigned char **out,
- unsigned char *outlen,
- const unsigned char *in,
- unsigned int inlen, void *arg), cb,
- void *arg, arg, return, DUMMYARG)
-DEFINEFUNC3(void, SSL_get0_alpn_selected, const SSL *s, s, const unsigned char **data, data,
- unsigned *len, len, return, DUMMYARG)
-#endif // !OPENSSL_NO_NEXTPROTONEG
-
-// DTLS:
-#if QT_CONFIG(dtls)
-DEFINEFUNC2(void, SSL_CTX_set_cookie_generate_cb, SSL_CTX *ctx, ctx, CookieGenerateCallback cb, cb, return, DUMMYARG)
-DEFINEFUNC2(void, SSL_CTX_set_cookie_verify_cb, SSL_CTX *ctx, ctx, CookieVerifyCallback cb, cb, return, DUMMYARG)
-DEFINEFUNC(const SSL_METHOD *, DTLS_server_method, DUMMYARG, DUMMYARG, return nullptr, return)
-DEFINEFUNC(const SSL_METHOD *, DTLS_client_method, DUMMYARG, DUMMYARG, return nullptr, return)
-#endif // dtls
-DEFINEFUNC2(void, BIO_set_flags, BIO *b, b, int flags, flags, return, DUMMYARG)
-DEFINEFUNC2(void, BIO_clear_flags, BIO *b, b, int flags, flags, return, DUMMYARG)
-DEFINEFUNC2(void *, BIO_get_ex_data, BIO *b, b, int idx, idx, return nullptr, return)
-DEFINEFUNC3(int, BIO_set_ex_data, BIO *b, b, int idx, idx, void *data, data, return -1, return)
-
-DEFINEFUNC3(void *, CRYPTO_malloc, size_t num, num, const char *file, file, int line, line, return nullptr, return)
-DEFINEFUNC(DH *, DH_new, DUMMYARG, DUMMYARG, return nullptr, return)
-DEFINEFUNC(void, DH_free, DH *dh, dh, return, DUMMYARG)
-DEFINEFUNC3(DH *, d2i_DHparams, DH**a, a, const unsigned char **pp, pp, long length, length, return nullptr, return)
-DEFINEFUNC2(int, i2d_DHparams, DH *a, a, unsigned char **p, p, return -1, return)
-#ifndef OPENSSL_NO_DEPRECATED_3_0
-DEFINEFUNC2(int, DH_check, DH *dh, dh, int *codes, codes, return 0, return)
-#endif // OPENSSL_NO_DEPRECATED_3_0
-DEFINEFUNC3(BIGNUM *, BN_bin2bn, const unsigned char *s, s, int len, len, BIGNUM *ret, ret, return nullptr, return)
-
-#ifndef OPENSSL_NO_EC
-DEFINEFUNC(EC_KEY *, EC_KEY_dup, const EC_KEY *ec, ec, return nullptr, return)
-DEFINEFUNC(EC_KEY *, EC_KEY_new_by_curve_name, int nid, nid, return nullptr, return)
-DEFINEFUNC(void, EC_KEY_free, EC_KEY *ecdh, ecdh, return, DUMMYARG)
-DEFINEFUNC2(size_t, EC_get_builtin_curves, EC_builtin_curve * r, r, size_t nitems, nitems, return 0, return)
-DEFINEFUNC(int, EC_curve_nist2nid, const char *name, name, return 0, return)
-#endif // OPENSSL_NO_EC
-
-DEFINEFUNC5(int, PKCS12_parse, PKCS12 *p12, p12, const char *pass, pass, EVP_PKEY **pkey, pkey, \
- X509 **cert, cert, STACK_OF(X509) **ca, ca, return 1, return);
-DEFINEFUNC2(PKCS12 *, d2i_PKCS12_bio, BIO *bio, bio, PKCS12 **pkcs12, pkcs12, return nullptr, return);
-DEFINEFUNC(void, PKCS12_free, PKCS12 *pkcs12, pkcs12, return, DUMMYARG)
-
-#define RESOLVEFUNC(func) \
- if (!(_q_##func = _q_PTR_##func(libs.ssl->resolve(#func))) \
- && !(_q_##func = _q_PTR_##func(libs.crypto->resolve(#func)))) \
- qsslSocketCannotResolveSymbolWarning(#func);
-
-#if !defined QT_LINKED_OPENSSL
-
-#if !QT_CONFIG(library)
-bool q_resolveOpenSslSymbols()
-{
- qCWarning(lcSsl, "QSslSocket: unable to resolve symbols. Qt is configured without the "
- "'library' feature, which means runtime resolving of libraries won't work.");
- qCWarning(lcSsl, "Either compile Qt statically or with support for runtime resolving "
- "of libraries.");
- return false;
-}
-#else
-
-# ifdef Q_OS_UNIX
-struct NumericallyLess
-{
- typedef bool result_type;
- result_type 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
-{
- typedef bool result_type;
- result_type operator()(QStringView lhs, QStringView rhs) const
- {
- const auto lhsparts = lhs.split(QLatin1Char('.'));
- const auto rhsparts = rhs.split(QLatin1Char('.'));
- Q_ASSERT(lhsparts.count() > 1 && rhsparts.count() > 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)
-static int dlIterateCallback(struct dl_phdr_info *info, size_t size, void *data)
-{
- if (size < sizeof (info->dlpi_addr) + sizeof (info->dlpi_name))
- return 1;
- QDuplicateTracker<QString> *paths = (QDuplicateTracker<QString> *)data;
- QString path = QString::fromLocal8Bit(info->dlpi_name);
- if (!path.isEmpty()) {
- QFileInfo fi(path);
- path = fi.absolutePath();
- if (!path.isEmpty())
- (void)paths->hasSeen(std::move(path));
- }
- return 0;
-}
-#endif
-
-static 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
- paths = QString::fromLatin1(qgetenv("LD_LIBRARY_PATH"))
- .split(QLatin1Char(':'), Qt::SkipEmptyParts);
-# endif
- 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
- QDuplicateTracker<QString> loadedPaths;
- dl_iterate_phdr(dlIterateCallback, &loadedPaths);
- std::move(loadedPaths).appendTo(paths);
-#endif
-
- return paths;
-}
-
-Q_NEVER_INLINE
-static 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 : qAsConst(entryList))
- found << path + QLatin1Char('/') + entry;
- }
-
- return found;
-}
-
-static QStringList findAllLibSsl()
-{
- return findAllLibs(QLatin1String("libssl.*"));
-}
-
-static QStringList findAllLibCrypto()
-{
- return findAllLibs(QLatin1String("libcrypto.*"));
-}
-# endif
-
-#ifdef Q_OS_WIN
-
-struct LoadedOpenSsl {
- std::unique_ptr<QSystemLibrary> ssl, crypto;
-};
-
-static bool tryToLoadOpenSslWin32Library(QLatin1String ssleay32LibName, QLatin1String libeay32LibName, LoadedOpenSsl &result)
-{
- auto ssleay32 = qt_make_unique<QSystemLibrary>(ssleay32LibName);
- if (!ssleay32->load(false)) {
- return FALSE;
- }
-
- auto libeay32 = qt_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(-x64) and libcrypto-1_1(-x64), for builds using
- // MSVC and GCC, (-x64 suffix for 64-bit builds).
-
-#ifdef Q_PROCESSOR_X86_64
-#define QT_SSL_SUFFIX "-x64"
-#else // !Q_PROCESSOFR_X86_64
-#define QT_SSL_SUFFIX
-#endif // !Q_PROCESSOR_x86_64
-
- tryToLoadOpenSslWin32Library(QLatin1String("libssl-1_1" QT_SSL_SUFFIX),
- QLatin1String("libcrypto-1_1" QT_SSL_SUFFIX), result);
-
-#undef QT_SSL_SUFFIX
- return result;
-}
-#else
-
-struct LoadedOpenSsl {
- std::unique_ptr<QLibrary> ssl, crypto;
-};
-
-static LoadedOpenSsl loadOpenSsl()
-{
- LoadedOpenSsl result = {qt_make_unique<QLibrary>(), qt_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
-
-#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
- libssl->setFileNameAndVersion(QLatin1String("ssl"), -1);
- libcrypto->setFileNameAndVersion(QLatin1String("crypto"), -1);
-# endif
- if (libcrypto->load() && libssl->load()) {
- // libssl.so.0 and libcrypto.so.0 found
- return result;
- } else {
- libssl->unload();
- libcrypto->unload();
- }
-#endif
-
- // 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) {
- 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
-}
-#endif
-
-static QBasicMutex symbolResolveMutex;
-static QBasicAtomicInt symbolsResolved = Q_BASIC_ATOMIC_INITIALIZER(false);
-static bool triedToResolveSymbols = false;
-
-bool q_resolveOpenSslSymbols()
-{
- if (symbolsResolved.loadAcquire())
- return true;
- QMutexLocker locker(&symbolResolveMutex);
- if (symbolsResolved.loadRelaxed())
- return true;
- if (triedToResolveSymbols)
- return false;
- triedToResolveSymbols = true;
-
- LoadedOpenSsl libs = loadOpenSsl();
- if (!libs.ssl || !libs.crypto)
- // failed to load them
- return false;
-
- RESOLVEFUNC(OPENSSL_init_ssl)
- RESOLVEFUNC(OPENSSL_init_crypto)
- RESOLVEFUNC(ASN1_STRING_get0_data)
- RESOLVEFUNC(EVP_CIPHER_CTX_reset)
- RESOLVEFUNC(EVP_PKEY_up_ref)
- RESOLVEFUNC(EVP_PKEY_CTX_new)
- RESOLVEFUNC(EVP_PKEY_param_check)
- RESOLVEFUNC(EVP_PKEY_CTX_free)
- RESOLVEFUNC(EVP_PKEY_base_id)
- RESOLVEFUNC(RSA_bits)
- RESOLVEFUNC(OPENSSL_sk_new_null)
- RESOLVEFUNC(OPENSSL_sk_push)
- RESOLVEFUNC(OPENSSL_sk_free)
- RESOLVEFUNC(OPENSSL_sk_num)
- RESOLVEFUNC(OPENSSL_sk_pop_free)
- RESOLVEFUNC(OPENSSL_sk_value)
- RESOLVEFUNC(DH_get0_pqg)
- RESOLVEFUNC(SSL_CTX_set_options)
- RESOLVEFUNC(SSL_set_info_callback)
- RESOLVEFUNC(SSL_alert_type_string)
- RESOLVEFUNC(SSL_alert_desc_string_long)
- RESOLVEFUNC(SSL_CTX_get_security_level)
- RESOLVEFUNC(SSL_CTX_set_security_level)
-#ifdef TLS1_3_VERSION
- RESOLVEFUNC(SSL_CTX_set_ciphersuites)
- RESOLVEFUNC(SSL_set_psk_use_session_callback)
- RESOLVEFUNC(SSL_CTX_sess_set_new_cb)
- RESOLVEFUNC(SSL_SESSION_is_resumable)
-#endif // TLS 1.3 or OpenSSL > 1.1.1
-
- RESOLVEFUNC(SSL_get_client_random)
- RESOLVEFUNC(SSL_SESSION_get_master_key)
- RESOLVEFUNC(SSL_session_reused)
- RESOLVEFUNC(SSL_get_session)
- RESOLVEFUNC(SSL_set_options)
- RESOLVEFUNC(CRYPTO_get_ex_new_index)
- RESOLVEFUNC(TLS_method)
- RESOLVEFUNC(TLS_client_method)
- RESOLVEFUNC(TLS_server_method)
- RESOLVEFUNC(X509_up_ref)
- RESOLVEFUNC(X509_STORE_CTX_get0_chain)
- RESOLVEFUNC(X509_getm_notBefore)
- RESOLVEFUNC(X509_getm_notAfter)
- RESOLVEFUNC(X509_get_version)
- RESOLVEFUNC(X509_get_pubkey)
- RESOLVEFUNC(X509_STORE_set_verify_cb)
- RESOLVEFUNC(X509_STORE_set_ex_data)
- RESOLVEFUNC(X509_STORE_get_ex_data)
- RESOLVEFUNC(CRYPTO_free)
- RESOLVEFUNC(OpenSSL_version_num)
- RESOLVEFUNC(OpenSSL_version)
-
- if (!_q_OpenSSL_version) {
- // Apparently, we were built with OpenSSL 1.1 enabled but are now using
- // a wrong library.
- qCWarning(lcSsl, "Incompatible version of OpenSSL");
- return false;
- }
-
- RESOLVEFUNC(SSL_SESSION_get_ticket_lifetime_hint)
- RESOLVEFUNC(DH_bits)
- RESOLVEFUNC(DSA_bits)
-
-#if QT_CONFIG(dtls)
- RESOLVEFUNC(DTLSv1_listen)
- RESOLVEFUNC(BIO_ADDR_new)
- RESOLVEFUNC(BIO_ADDR_free)
- RESOLVEFUNC(BIO_meth_new)
- RESOLVEFUNC(BIO_meth_free)
- RESOLVEFUNC(BIO_meth_set_write)
- RESOLVEFUNC(BIO_meth_set_read)
- RESOLVEFUNC(BIO_meth_set_puts)
- RESOLVEFUNC(BIO_meth_set_ctrl)
- RESOLVEFUNC(BIO_meth_set_create)
- RESOLVEFUNC(BIO_meth_set_destroy)
-#endif // dtls
-
-#if QT_CONFIG(ocsp)
- RESOLVEFUNC(OCSP_SINGLERESP_get0_id)
- RESOLVEFUNC(d2i_OCSP_RESPONSE)
- RESOLVEFUNC(OCSP_RESPONSE_free)
- RESOLVEFUNC(OCSP_response_status)
- RESOLVEFUNC(OCSP_response_get1_basic)
- RESOLVEFUNC(OCSP_BASICRESP_free)
- RESOLVEFUNC(OCSP_basic_verify)
- RESOLVEFUNC(OCSP_resp_count)
- RESOLVEFUNC(OCSP_resp_get0)
- RESOLVEFUNC(OCSP_single_get0_status)
- RESOLVEFUNC(OCSP_check_validity)
- RESOLVEFUNC(OCSP_cert_to_id)
- RESOLVEFUNC(OCSP_id_get0_info)
- RESOLVEFUNC(OCSP_resp_get0_certs)
- RESOLVEFUNC(OCSP_basic_sign)
- RESOLVEFUNC(OCSP_response_create)
- RESOLVEFUNC(i2d_OCSP_RESPONSE)
- RESOLVEFUNC(OCSP_basic_add1_status)
- RESOLVEFUNC(OCSP_BASICRESP_new)
- RESOLVEFUNC(OCSP_CERTID_free)
- RESOLVEFUNC(OCSP_cert_to_id)
- RESOLVEFUNC(OCSP_id_cmp)
-#endif // ocsp
-
- RESOLVEFUNC(BIO_set_data)
- RESOLVEFUNC(BIO_get_data)
- RESOLVEFUNC(BIO_set_init)
- RESOLVEFUNC(BIO_get_shutdown)
- RESOLVEFUNC(BIO_set_shutdown)
- RESOLVEFUNC(ASN1_INTEGER_get)
- RESOLVEFUNC(ASN1_INTEGER_cmp)
- RESOLVEFUNC(ASN1_STRING_length)
- RESOLVEFUNC(ASN1_STRING_to_UTF8)
- RESOLVEFUNC(ASN1_TIME_to_tm)
- RESOLVEFUNC(BIO_ctrl)
- RESOLVEFUNC(BIO_free)
- RESOLVEFUNC(BIO_new)
- RESOLVEFUNC(BIO_new_mem_buf)
- RESOLVEFUNC(BIO_read)
- RESOLVEFUNC(BIO_s_mem)
- RESOLVEFUNC(BIO_write)
- RESOLVEFUNC(BIO_set_flags)
- RESOLVEFUNC(BIO_clear_flags)
- RESOLVEFUNC(BIO_set_ex_data)
- RESOLVEFUNC(BIO_get_ex_data)
-
-#ifndef OPENSSL_NO_EC
- RESOLVEFUNC(EC_KEY_get0_group)
- RESOLVEFUNC(EC_GROUP_get_degree)
-#endif
- RESOLVEFUNC(BN_num_bits)
- RESOLVEFUNC(BN_is_word)
- RESOLVEFUNC(BN_mod_word)
- RESOLVEFUNC(DSA_new)
- RESOLVEFUNC(DSA_free)
- RESOLVEFUNC(ERR_error_string)
- RESOLVEFUNC(ERR_error_string_n)
- RESOLVEFUNC(ERR_get_error)
- RESOLVEFUNC(EVP_CIPHER_CTX_new)
- RESOLVEFUNC(EVP_CIPHER_CTX_free)
- RESOLVEFUNC(EVP_CIPHER_CTX_ctrl)
- RESOLVEFUNC(EVP_CIPHER_CTX_set_key_length)
- RESOLVEFUNC(EVP_CipherInit)
- RESOLVEFUNC(EVP_CipherInit_ex)
- RESOLVEFUNC(EVP_CipherUpdate)
- RESOLVEFUNC(EVP_CipherFinal)
- RESOLVEFUNC(EVP_get_digestbyname)
-#ifndef OPENSSL_NO_DES
- RESOLVEFUNC(EVP_des_cbc)
- RESOLVEFUNC(EVP_des_ede3_cbc)
-#endif
-#ifndef OPENSSL_NO_RC2
- RESOLVEFUNC(EVP_rc2_cbc)
-#endif
-#ifndef OPENSSL_NO_AES
- RESOLVEFUNC(EVP_aes_128_cbc)
- RESOLVEFUNC(EVP_aes_192_cbc)
- RESOLVEFUNC(EVP_aes_256_cbc)
-#endif
- RESOLVEFUNC(EVP_sha1)
- RESOLVEFUNC(EVP_PKEY_assign)
- 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)
- RESOLVEFUNC(EVP_PKEY_get1_EC_KEY)
- RESOLVEFUNC(PEM_read_bio_ECPrivateKey)
- RESOLVEFUNC(PEM_write_bio_ECPrivateKey)
- RESOLVEFUNC(PEM_read_bio_EC_PUBKEY)
- RESOLVEFUNC(PEM_write_bio_EC_PUBKEY)
-#endif // OPENSSL_NO_EC
-
- RESOLVEFUNC(EVP_PKEY_cmp)
- RESOLVEFUNC(EVP_PKEY_free)
- RESOLVEFUNC(EVP_PKEY_get1_DSA)
- RESOLVEFUNC(EVP_PKEY_get1_RSA)
- RESOLVEFUNC(EVP_PKEY_get1_DH)
- RESOLVEFUNC(EVP_PKEY_new)
- RESOLVEFUNC(EVP_PKEY_type)
- RESOLVEFUNC(OBJ_nid2sn)
- RESOLVEFUNC(OBJ_nid2ln)
- RESOLVEFUNC(OBJ_sn2nid)
- RESOLVEFUNC(OBJ_ln2nid)
- RESOLVEFUNC(i2t_ASN1_OBJECT)
- RESOLVEFUNC(OBJ_obj2txt)
- RESOLVEFUNC(OBJ_obj2nid)
- RESOLVEFUNC(PEM_read_bio_PrivateKey)
- RESOLVEFUNC(PEM_read_bio_DSAPrivateKey)
- RESOLVEFUNC(PEM_read_bio_RSAPrivateKey)
- RESOLVEFUNC(PEM_read_bio_DHparams)
- RESOLVEFUNC(PEM_write_bio_DSAPrivateKey)
- RESOLVEFUNC(PEM_write_bio_RSAPrivateKey)
- RESOLVEFUNC(PEM_write_bio_PrivateKey)
- RESOLVEFUNC(PEM_read_bio_PUBKEY)
- RESOLVEFUNC(PEM_read_bio_DSA_PUBKEY)
- RESOLVEFUNC(PEM_read_bio_RSA_PUBKEY)
- RESOLVEFUNC(PEM_write_bio_DSA_PUBKEY)
- RESOLVEFUNC(PEM_write_bio_RSA_PUBKEY)
- RESOLVEFUNC(PEM_write_bio_PUBKEY)
- RESOLVEFUNC(RAND_seed)
- RESOLVEFUNC(RAND_status)
- RESOLVEFUNC(RAND_bytes)
- RESOLVEFUNC(RSA_new)
- RESOLVEFUNC(RSA_free)
- RESOLVEFUNC(SSL_CIPHER_description)
- RESOLVEFUNC(SSL_CIPHER_get_bits)
- RESOLVEFUNC(SSL_get_rbio)
- RESOLVEFUNC(SSL_CTX_check_private_key)
- RESOLVEFUNC(SSL_CTX_ctrl)
- RESOLVEFUNC(SSL_CTX_free)
- RESOLVEFUNC(SSL_CTX_new)
- RESOLVEFUNC(SSL_CTX_set_cipher_list)
- RESOLVEFUNC(SSL_CTX_callback_ctrl)
- RESOLVEFUNC(SSL_CTX_set_default_verify_paths)
- RESOLVEFUNC(SSL_CTX_set_verify)
- RESOLVEFUNC(SSL_CTX_set_verify_depth)
- RESOLVEFUNC(SSL_CTX_use_certificate)
- RESOLVEFUNC(SSL_CTX_use_certificate_file)
- RESOLVEFUNC(SSL_CTX_use_PrivateKey)
- RESOLVEFUNC(SSL_CTX_use_RSAPrivateKey)
- RESOLVEFUNC(SSL_CTX_use_PrivateKey_file)
- RESOLVEFUNC(SSL_CTX_get_cert_store);
- RESOLVEFUNC(SSL_CONF_CTX_new);
- RESOLVEFUNC(SSL_CONF_CTX_free);
- RESOLVEFUNC(SSL_CONF_CTX_set_ssl_ctx);
- RESOLVEFUNC(SSL_CONF_CTX_set_flags);
- RESOLVEFUNC(SSL_CONF_CTX_finish);
- RESOLVEFUNC(SSL_CONF_cmd);
- RESOLVEFUNC(SSL_accept)
- RESOLVEFUNC(SSL_clear)
- RESOLVEFUNC(SSL_connect)
- RESOLVEFUNC(SSL_free)
- RESOLVEFUNC(SSL_get_ciphers)
- RESOLVEFUNC(SSL_get_current_cipher)
- RESOLVEFUNC(SSL_version)
- RESOLVEFUNC(SSL_get_error)
- RESOLVEFUNC(SSL_get_peer_cert_chain)
- RESOLVEFUNC(SSL_get_peer_certificate)
- RESOLVEFUNC(SSL_get_verify_result)
- RESOLVEFUNC(SSL_new)
- RESOLVEFUNC(SSL_get_SSL_CTX)
- RESOLVEFUNC(SSL_ctrl)
- RESOLVEFUNC(SSL_read)
- RESOLVEFUNC(SSL_set_accept_state)
- RESOLVEFUNC(SSL_set_bio)
- RESOLVEFUNC(SSL_set_connect_state)
- RESOLVEFUNC(SSL_shutdown)
- RESOLVEFUNC(SSL_in_init)
- RESOLVEFUNC(SSL_get_shutdown)
- RESOLVEFUNC(SSL_set_session)
- RESOLVEFUNC(SSL_SESSION_free)
- RESOLVEFUNC(SSL_get1_session)
- RESOLVEFUNC(SSL_get_session)
- RESOLVEFUNC(SSL_set_ex_data)
- RESOLVEFUNC(SSL_get_ex_data)
- RESOLVEFUNC(SSL_get_ex_data_X509_STORE_CTX_idx)
-
-#ifndef OPENSSL_NO_PSK
- RESOLVEFUNC(SSL_set_psk_client_callback)
- RESOLVEFUNC(SSL_set_psk_server_callback)
- RESOLVEFUNC(SSL_CTX_use_psk_identity_hint)
-#endif // !OPENSSL_NO_PSK
-
- RESOLVEFUNC(SSL_write)
- RESOLVEFUNC(X509_NAME_entry_count)
- RESOLVEFUNC(X509_NAME_get_entry)
- RESOLVEFUNC(X509_NAME_ENTRY_get_data)
- RESOLVEFUNC(X509_NAME_ENTRY_get_object)
- RESOLVEFUNC(X509_PUBKEY_get)
- RESOLVEFUNC(X509_STORE_free)
- RESOLVEFUNC(X509_STORE_new)
- RESOLVEFUNC(X509_STORE_add_cert)
- RESOLVEFUNC(X509_STORE_CTX_free)
- RESOLVEFUNC(X509_STORE_CTX_init)
- RESOLVEFUNC(X509_STORE_CTX_new)
- RESOLVEFUNC(X509_STORE_CTX_set_purpose)
- RESOLVEFUNC(X509_STORE_CTX_get_error)
- RESOLVEFUNC(X509_STORE_CTX_get_error_depth)
- RESOLVEFUNC(X509_STORE_CTX_get_current_cert)
- RESOLVEFUNC(X509_STORE_CTX_get0_store)
- RESOLVEFUNC(X509_cmp)
- RESOLVEFUNC(X509_STORE_CTX_get_ex_data)
- RESOLVEFUNC(X509_dup)
- RESOLVEFUNC(X509_print)
- RESOLVEFUNC(X509_digest)
- RESOLVEFUNC(X509_EXTENSION_get_object)
- RESOLVEFUNC(X509_free)
- RESOLVEFUNC(X509_gmtime_adj)
- RESOLVEFUNC(ASN1_TIME_free)
- RESOLVEFUNC(X509_get_ext)
- RESOLVEFUNC(X509_get_ext_count)
- RESOLVEFUNC(X509_get_ext_d2i)
- RESOLVEFUNC(X509V3_EXT_get)
- RESOLVEFUNC(X509V3_EXT_d2i)
- RESOLVEFUNC(X509_EXTENSION_get_critical)
- RESOLVEFUNC(X509_EXTENSION_get_data)
- RESOLVEFUNC(BASIC_CONSTRAINTS_free)
- RESOLVEFUNC(AUTHORITY_KEYID_free)
- RESOLVEFUNC(GENERAL_NAME_free)
- RESOLVEFUNC(ASN1_STRING_print)
- RESOLVEFUNC(X509_check_issued)
- RESOLVEFUNC(X509_get_issuer_name)
- RESOLVEFUNC(X509_get_subject_name)
- RESOLVEFUNC(X509_get_serialNumber)
- RESOLVEFUNC(X509_verify_cert)
- RESOLVEFUNC(d2i_X509)
- RESOLVEFUNC(i2d_X509)
-#if OPENSSL_VERSION_MAJOR < 3
- RESOLVEFUNC(SSL_CTX_load_verify_locations)
-#else
- RESOLVEFUNC(SSL_CTX_load_verify_dir)
-#endif // OPENSSL_VERSION_MAJOR
- RESOLVEFUNC(i2d_SSL_SESSION)
- RESOLVEFUNC(d2i_SSL_SESSION)
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
- RESOLVEFUNC(SSL_select_next_proto)
- RESOLVEFUNC(SSL_CTX_set_next_proto_select_cb)
- RESOLVEFUNC(SSL_get0_next_proto_negotiated)
- RESOLVEFUNC(SSL_set_alpn_protos)
- RESOLVEFUNC(SSL_CTX_set_alpn_select_cb)
- RESOLVEFUNC(SSL_get0_alpn_selected)
-#endif // !OPENSSL_NO_NEXTPROTONEG
-
-#if QT_CONFIG(dtls)
- RESOLVEFUNC(SSL_CTX_set_cookie_generate_cb)
- RESOLVEFUNC(SSL_CTX_set_cookie_verify_cb)
- RESOLVEFUNC(DTLS_server_method)
- RESOLVEFUNC(DTLS_client_method)
-#endif // dtls
-
- RESOLVEFUNC(CRYPTO_malloc)
- RESOLVEFUNC(DH_new)
- RESOLVEFUNC(DH_free)
- RESOLVEFUNC(d2i_DHparams)
- RESOLVEFUNC(i2d_DHparams)
-#ifndef OPENSSL_NO_DEPRECATED_3_0
- RESOLVEFUNC(DH_check)
-#endif // OPENSSL_NO_DEPRECATED_3_0
- RESOLVEFUNC(BN_bin2bn)
-
-#ifndef OPENSSL_NO_EC
- RESOLVEFUNC(EC_KEY_dup)
- RESOLVEFUNC(EC_KEY_new_by_curve_name)
- RESOLVEFUNC(EC_KEY_free)
- RESOLVEFUNC(EC_get_builtin_curves)
-#endif // OPENSSL_NO_EC
-
- RESOLVEFUNC(PKCS12_parse)
- RESOLVEFUNC(d2i_PKCS12_bio)
- RESOLVEFUNC(PKCS12_free)
-
- symbolsResolved.storeRelease(true);
- return true;
-}
-#endif // QT_CONFIG(library)
-
-#else // !defined QT_LINKED_OPENSSL
-
-bool q_resolveOpenSslSymbols()
-{
-#ifdef QT_NO_OPENSSL
- return false;
-#endif
- return true;
-}
-#endif // !defined QT_LINKED_OPENSSL
-
-QDateTime q_getTimeFromASN1(const ASN1_TIME *aTime)
-{
- QDateTime result;
- tm lTime;
-
- if (q_ASN1_TIME_to_tm(aTime, &lTime)) {
- QDate resDate(lTime.tm_year + 1900, lTime.tm_mon + 1, lTime.tm_mday);
- QTime resTime(lTime.tm_hour, lTime.tm_min, lTime.tm_sec);
- result = QDateTime(resDate, resTime, Qt::UTC);
- }
-
- return result;
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslsocket_openssl_symbols_p.h b/src/network/ssl/qsslsocket_openssl_symbols_p.h
deleted file mode 100644
index 9f54efddaa..0000000000
--- a/src/network/ssl/qsslsocket_openssl_symbols_p.h
+++ /dev/null
@@ -1,761 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-/****************************************************************************
-**
-** 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 QSSLSOCKET_OPENSSL_SYMBOLS_P_H
-#define QSSLSOCKET_OPENSSL_SYMBOLS_P_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.
-//
-
-#include <QtNetwork/private/qtnetworkglobal_p.h>
-#include "qsslsocket_openssl_p.h"
-#include <QtCore/qglobal.h>
-
-#if QT_CONFIG(ocsp)
-#include "qocsp_p.h"
-#endif
-
-QT_BEGIN_NAMESPACE
-
-#define DUMMYARG
-
-#if !defined QT_LINKED_OPENSSL
-// **************** 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 = nullptr; \
- 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 = nullptr; \
- 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 = nullptr; \
- 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 = nullptr; \
- 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 = nullptr; \
- 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 = nullptr; \
- 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 = nullptr; \
- 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 = nullptr; \
- 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 ******************
-
-#else // !defined QT_LINKED_OPENSSL
-
-// **************** Static declarations ******************
-
-// ret func(arg)
-# define DEFINEFUNC(ret, func, arg, a, err, funcret) \
- ret q_##func(arg) { funcret func(a); }
-
-// ret func(arg1, arg2)
-# define DEFINEFUNC2(ret, func, arg1, a, arg2, b, err, funcret) \
- 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) \
- 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) \
- 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) \
- 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) \
- 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) \
- 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) \
- 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 ******************
-
-#endif // !defined QT_LINKED_OPENSSL
-
-// TODO: the following lines previously were a part of 1.1 - specific header.
-// To reduce the amount of the change, I'm directly copying and pasting the
-// content of the header here. Later, can be better sorted/split into groups,
-// depending on the functionality.
-
-const unsigned char * q_ASN1_STRING_get0_data(const ASN1_STRING *x);
-
-Q_AUTOTEST_EXPORT BIO *q_BIO_new(const BIO_METHOD *a);
-Q_AUTOTEST_EXPORT const BIO_METHOD *q_BIO_s_mem();
-
-int q_DSA_bits(DSA *a);
-int q_EVP_CIPHER_CTX_reset(EVP_CIPHER_CTX *c);
-Q_AUTOTEST_EXPORT int q_EVP_PKEY_up_ref(EVP_PKEY *a);
-EVP_PKEY_CTX *q_EVP_PKEY_CTX_new(EVP_PKEY *pkey, ENGINE *e);
-void q_EVP_PKEY_CTX_free(EVP_PKEY_CTX *ctx);
-int q_EVP_PKEY_param_check(EVP_PKEY_CTX *ctx);
-int q_EVP_PKEY_base_id(EVP_PKEY *a);
-int q_RSA_bits(RSA *a);
-Q_AUTOTEST_EXPORT int q_OPENSSL_sk_num(OPENSSL_STACK *a);
-Q_AUTOTEST_EXPORT void q_OPENSSL_sk_pop_free(OPENSSL_STACK *a, void (*b)(void *));
-Q_AUTOTEST_EXPORT OPENSSL_STACK *q_OPENSSL_sk_new_null();
-Q_AUTOTEST_EXPORT void q_OPENSSL_sk_push(OPENSSL_STACK *st, void *data);
-Q_AUTOTEST_EXPORT void q_OPENSSL_sk_free(OPENSSL_STACK *a);
-Q_AUTOTEST_EXPORT void * q_OPENSSL_sk_value(OPENSSL_STACK *a, int b);
-int q_SSL_session_reused(SSL *a);
-unsigned long q_SSL_CTX_set_options(SSL_CTX *ctx, unsigned long op);
-int q_OPENSSL_init_ssl(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings);
-size_t q_SSL_get_client_random(SSL *a, unsigned char *out, size_t outlen);
-size_t q_SSL_SESSION_get_master_key(const SSL_SESSION *session, unsigned char *out, size_t outlen);
-int q_CRYPTO_get_ex_new_index(int class_index, long argl, void *argp, CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
-const SSL_METHOD *q_TLS_method();
-const SSL_METHOD *q_TLS_client_method();
-const SSL_METHOD *q_TLS_server_method();
-ASN1_TIME *q_X509_getm_notBefore(X509 *a);
-ASN1_TIME *q_X509_getm_notAfter(X509 *a);
-
-Q_AUTOTEST_EXPORT void q_X509_up_ref(X509 *a);
-long q_X509_get_version(X509 *a);
-EVP_PKEY *q_X509_get_pubkey(X509 *a);
-void q_X509_STORE_set_verify_cb(X509_STORE *ctx, X509_STORE_CTX_verify_cb verify_cb);
-int q_X509_STORE_set_ex_data(X509_STORE *ctx, int idx, void *data);
-void *q_X509_STORE_get_ex_data(X509_STORE *r, int idx);
-STACK_OF(X509) *q_X509_STORE_CTX_get0_chain(X509_STORE_CTX *ctx);
-void q_DH_get0_pqg(const DH *dh, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g);
-int q_DH_bits(DH *dh);
-
-# define q_SSL_load_error_strings() q_OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS \
- | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL)
-
-#define q_SKM_sk_num(type, st) ((int (*)(const STACK_OF(type) *))q_OPENSSL_sk_num)(st)
-#define q_SKM_sk_value(type, st,i) ((type * (*)(const STACK_OF(type) *, int))q_OPENSSL_sk_value)(st, i)
-
-#define q_OPENSSL_add_all_algorithms_conf() q_OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS \
- | OPENSSL_INIT_ADD_ALL_DIGESTS \
- | OPENSSL_INIT_LOAD_CONFIG, NULL)
-#define q_OPENSSL_add_all_algorithms_noconf() q_OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS \
- | OPENSSL_INIT_ADD_ALL_DIGESTS, NULL)
-
-int q_OPENSSL_init_crypto(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings);
-void q_CRYPTO_free(void *str, const char *file, int line);
-
-long q_OpenSSL_version_num();
-const char *q_OpenSSL_version(int type);
-
-unsigned long q_SSL_SESSION_get_ticket_lifetime_hint(const SSL_SESSION *session);
-unsigned long q_SSL_set_options(SSL *s, unsigned long op);
-
-#ifdef TLS1_3_VERSION
-int q_SSL_CTX_set_ciphersuites(SSL_CTX *ctx, const char *str);
-
-// The functions below do not really have to be ifdefed like this, but for now
-// they only used in TLS 1.3 handshake (and probably future versions).
-// Plus, 'is resumalbe' is OpenSSL 1.1.1-only (and again we need it for
-// TLS 1.3-specific session management).
-
-extern "C"
-{
-using NewSessionCallback = int (*)(SSL *, SSL_SESSION *);
-}
-
-void q_SSL_CTX_sess_set_new_cb(SSL_CTX *ctx, NewSessionCallback cb);
-int q_SSL_SESSION_is_resumable(const SSL_SESSION *s);
-
-#define q_SSL_CTX_set_session_cache_mode(ctx,m) \
- q_SSL_CTX_ctrl(ctx,SSL_CTRL_SET_SESS_CACHE_MODE,m,NULL)
-
-#endif
-
-#if QT_CONFIG(dtls)
-// Functions and types required for DTLS support:
-extern "C"
-{
-
-typedef int (*CookieVerifyCallback)(SSL *, const unsigned char *, unsigned);
-typedef int (*DgramWriteCallback) (BIO *, const char *, int);
-typedef int (*DgramReadCallback) (BIO *, char *, int);
-typedef int (*DgramPutsCallback) (BIO *, const char *);
-typedef long (*DgramCtrlCallback) (BIO *, int, long, void *);
-typedef int (*DgramCreateCallback) (BIO *);
-typedef int (*DgramDestroyCallback) (BIO *);
-
-}
-
-int q_DTLSv1_listen(SSL *s, BIO_ADDR *client);
-BIO_ADDR *q_BIO_ADDR_new();
-void q_BIO_ADDR_free(BIO_ADDR *ap);
-
-// API we need for a custom dgram BIO:
-
-BIO_METHOD *q_BIO_meth_new(int type, const char *name);
-void q_BIO_meth_free(BIO_METHOD *biom);
-int q_BIO_meth_set_write(BIO_METHOD *biom, DgramWriteCallback);
-int q_BIO_meth_set_read(BIO_METHOD *biom, DgramReadCallback);
-int q_BIO_meth_set_puts(BIO_METHOD *biom, DgramPutsCallback);
-int q_BIO_meth_set_ctrl(BIO_METHOD *biom, DgramCtrlCallback);
-int q_BIO_meth_set_create(BIO_METHOD *biom, DgramCreateCallback);
-int q_BIO_meth_set_destroy(BIO_METHOD *biom, DgramDestroyCallback);
-
-#endif // dtls
-
-void q_BIO_set_data(BIO *a, void *ptr);
-void *q_BIO_get_data(BIO *a);
-void q_BIO_set_init(BIO *a, int init);
-int q_BIO_get_shutdown(BIO *a);
-void q_BIO_set_shutdown(BIO *a, int shut);
-
-#if QT_CONFIG(ocsp)
-const OCSP_CERTID *q_OCSP_SINGLERESP_get0_id(const OCSP_SINGLERESP *x);
-#endif // ocsp
-
-#define q_SSL_CTX_set_min_proto_version(ctx, version) \
- q_SSL_CTX_ctrl(ctx, SSL_CTRL_SET_MIN_PROTO_VERSION, version, nullptr)
-
-#define q_SSL_CTX_set_max_proto_version(ctx, version) \
- q_SSL_CTX_ctrl(ctx, SSL_CTRL_SET_MAX_PROTO_VERSION, version, nullptr)
-
-extern "C" {
-typedef int (*q_SSL_psk_use_session_cb_func_t)(SSL *, const EVP_MD *, const unsigned char **, size_t *,
- SSL_SESSION **);
-}
-void q_SSL_set_psk_use_session_callback(SSL *s, q_SSL_psk_use_session_cb_func_t);
-// Here the content of the 1.1 header ends.
-
-bool q_resolveOpenSslSymbols();
-long q_ASN1_INTEGER_get(ASN1_INTEGER *a);
-int q_ASN1_INTEGER_cmp(const ASN1_INTEGER *x, const ASN1_INTEGER *y);
-int q_ASN1_STRING_length(ASN1_STRING *a);
-int q_ASN1_STRING_to_UTF8(unsigned char **a, ASN1_STRING *b);
-int q_ASN1_TIME_to_tm(const ASN1_TIME *s, struct tm *tm);
-long q_BIO_ctrl(BIO *a, int b, long c, void *d);
-Q_AUTOTEST_EXPORT int q_BIO_free(BIO *a);
-BIO *q_BIO_new_mem_buf(void *a, int b);
-int q_BIO_read(BIO *a, void *b, int c);
-Q_AUTOTEST_EXPORT int q_BIO_write(BIO *a, const void *b, int c);
-int q_BN_num_bits(const BIGNUM *a);
-int q_BN_is_word(BIGNUM *a, BN_ULONG w);
-BN_ULONG q_BN_mod_word(const BIGNUM *a, BN_ULONG w);
-
-#ifndef OPENSSL_NO_EC
-const EC_GROUP* q_EC_KEY_get0_group(const EC_KEY* k);
-int q_EC_GROUP_get_degree(const EC_GROUP* g);
-#endif // OPENSSL_NO_EC
-
-DSA *q_DSA_new();
-void q_DSA_free(DSA *a);
-X509 *q_d2i_X509(X509 **a, const unsigned char **b, long c);
-char *q_ERR_error_string(unsigned long a, char *b);
-void q_ERR_error_string_n(unsigned long e, char *buf, size_t len);
-unsigned long q_ERR_get_error();
-EVP_CIPHER_CTX *q_EVP_CIPHER_CTX_new();
-void q_EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *a);
-int q_EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr);
-int q_EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *x, int keylen);
-int q_EVP_CipherInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, const unsigned char *key, const unsigned char *iv, int enc);
-int q_EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, ENGINE *impl, const unsigned char *key, const unsigned char *iv, int enc);
-int q_EVP_CipherUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl);
-int q_EVP_CipherFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl);
-const EVP_MD *q_EVP_get_digestbyname(const char *name);
-
-#ifndef OPENSSL_NO_DES
-const EVP_CIPHER *q_EVP_des_cbc();
-const EVP_CIPHER *q_EVP_des_ede3_cbc();
-#endif // OPENSSL_NO_DES
-
-#ifndef OPENSSL_NO_RC2
-const EVP_CIPHER *q_EVP_rc2_cbc();
-#endif // OPENSSL_NO_RC2
-
-#ifndef OPENSSL_NO_AES
-const EVP_CIPHER *q_EVP_aes_128_cbc();
-const EVP_CIPHER *q_EVP_aes_192_cbc();
-const EVP_CIPHER *q_EVP_aes_256_cbc();
-#endif // OPENSSL_NO_AES
-
-Q_AUTOTEST_EXPORT const EVP_MD *q_EVP_sha1();
-int q_EVP_PKEY_assign(EVP_PKEY *a, int b, void *r);
-Q_AUTOTEST_EXPORT int q_EVP_PKEY_set1_RSA(EVP_PKEY *a, RSA *b);
-Q_AUTOTEST_EXPORT int q_EVP_PKEY_set1_DSA(EVP_PKEY *a, DSA *b);
-Q_AUTOTEST_EXPORT int q_EVP_PKEY_set1_DH(EVP_PKEY *a, DH *b);
-
-#ifndef OPENSSL_NO_EC
-Q_AUTOTEST_EXPORT int q_EVP_PKEY_set1_EC_KEY(EVP_PKEY *a, EC_KEY *b);
-#endif
-
-Q_AUTOTEST_EXPORT int q_EVP_PKEY_cmp(const EVP_PKEY *a, const EVP_PKEY *b);
-Q_AUTOTEST_EXPORT void q_EVP_PKEY_free(EVP_PKEY *a);
-RSA *q_EVP_PKEY_get1_RSA(EVP_PKEY *a);
-DSA *q_EVP_PKEY_get1_DSA(EVP_PKEY *a);
-DH *q_EVP_PKEY_get1_DH(EVP_PKEY *a);
-#ifndef OPENSSL_NO_EC
-EC_KEY *q_EVP_PKEY_get1_EC_KEY(EVP_PKEY *a);
-#endif
-int q_EVP_PKEY_type(int a);
-Q_AUTOTEST_EXPORT EVP_PKEY *q_EVP_PKEY_new();
-int q_i2d_X509(X509 *a, unsigned char **b);
-const char *q_OBJ_nid2sn(int a);
-const char *q_OBJ_nid2ln(int a);
-int q_OBJ_sn2nid(const char *s);
-int q_OBJ_ln2nid(const char *s);
-int q_i2t_ASN1_OBJECT(char *buf, int buf_len, ASN1_OBJECT *obj);
-int q_OBJ_obj2txt(char *buf, int buf_len, ASN1_OBJECT *obj, int no_name);
-int q_OBJ_obj2nid(const ASN1_OBJECT *a);
-#define q_EVP_get_digestbynid(a) q_EVP_get_digestbyname(q_OBJ_nid2sn(a))
-Q_AUTOTEST_EXPORT EVP_PKEY *q_PEM_read_bio_PrivateKey(BIO *a, EVP_PKEY **b, pem_password_cb *c, void *d);
-DSA *q_PEM_read_bio_DSAPrivateKey(BIO *a, DSA **b, pem_password_cb *c, void *d);
-RSA *q_PEM_read_bio_RSAPrivateKey(BIO *a, RSA **b, pem_password_cb *c, void *d);
-
-#ifndef OPENSSL_NO_EC
-EC_KEY *q_PEM_read_bio_ECPrivateKey(BIO *a, EC_KEY **b, pem_password_cb *c, void *d);
-int q_PEM_write_bio_ECPrivateKey(BIO *a, EC_KEY *b, const EVP_CIPHER *c, unsigned char *d,
- int e, pem_password_cb *f, void *g);
-EC_KEY *q_PEM_read_bio_EC_PUBKEY(BIO *a, EC_KEY **b, pem_password_cb *c, void *d);
-int q_PEM_write_bio_EC_PUBKEY(BIO *a, EC_KEY *b);
-#endif // OPENSSL_NO_EC
-
-DH *q_PEM_read_bio_DHparams(BIO *a, DH **b, pem_password_cb *c, void *d);
-int q_PEM_write_bio_DSAPrivateKey(BIO *a, DSA *b, const EVP_CIPHER *c, unsigned char *d,
- int e, pem_password_cb *f, void *g);
-int q_PEM_write_bio_RSAPrivateKey(BIO *a, RSA *b, const EVP_CIPHER *c, unsigned char *d,
- int e, pem_password_cb *f, void *g);
-int q_PEM_write_bio_PrivateKey(BIO *a, EVP_PKEY *b, const EVP_CIPHER *c, unsigned char *d,
- int e, pem_password_cb *f, void *g);
-Q_AUTOTEST_EXPORT EVP_PKEY *q_PEM_read_bio_PUBKEY(BIO *a, EVP_PKEY **b, pem_password_cb *c, void *d);
-DSA *q_PEM_read_bio_DSA_PUBKEY(BIO *a, DSA **b, pem_password_cb *c, void *d);
-RSA *q_PEM_read_bio_RSA_PUBKEY(BIO *a, RSA **b, pem_password_cb *c, void *d);
-int q_PEM_write_bio_DSA_PUBKEY(BIO *a, DSA *b);
-int q_PEM_write_bio_RSA_PUBKEY(BIO *a, RSA *b);
-int q_PEM_write_bio_PUBKEY(BIO *a, EVP_PKEY *b);
-
-void q_RAND_seed(const void *a, int b);
-int q_RAND_status();
-int q_RAND_bytes(unsigned char *b, int n);
-RSA *q_RSA_new();
-void q_RSA_free(RSA *a);
-int q_SSL_accept(SSL *a);
-int q_SSL_clear(SSL *a);
-char *q_SSL_CIPHER_description(const SSL_CIPHER *a, char *b, int c);
-int q_SSL_CIPHER_get_bits(const SSL_CIPHER *a, int *b);
-BIO *q_SSL_get_rbio(const SSL *s);
-int q_SSL_connect(SSL *a);
-int q_SSL_CTX_check_private_key(const SSL_CTX *a);
-long q_SSL_CTX_ctrl(SSL_CTX *a, int b, long c, void *d);
-void q_SSL_CTX_free(SSL_CTX *a);
-SSL_CTX *q_SSL_CTX_new(const SSL_METHOD *a);
-int q_SSL_CTX_set_cipher_list(SSL_CTX *a, const char *b);
-int q_SSL_CTX_set_default_verify_paths(SSL_CTX *a);
-void q_SSL_CTX_set_verify(SSL_CTX *a, int b, int (*c)(int, X509_STORE_CTX *));
-void q_SSL_CTX_set_verify_depth(SSL_CTX *a, int b);
-extern "C" {
-typedef void (*GenericCallbackType)();
-}
-long q_SSL_CTX_callback_ctrl(SSL_CTX *, int, GenericCallbackType);
-int q_SSL_CTX_use_certificate(SSL_CTX *a, X509 *b);
-int q_SSL_CTX_use_certificate_file(SSL_CTX *a, const char *b, int c);
-int q_SSL_CTX_use_PrivateKey(SSL_CTX *a, EVP_PKEY *b);
-int q_SSL_CTX_use_RSAPrivateKey(SSL_CTX *a, RSA *b);
-int q_SSL_CTX_use_PrivateKey_file(SSL_CTX *a, const char *b, int c);
-X509_STORE *q_SSL_CTX_get_cert_store(const SSL_CTX *a);
-SSL_CONF_CTX *q_SSL_CONF_CTX_new();
-void q_SSL_CONF_CTX_free(SSL_CONF_CTX *a);
-void q_SSL_CONF_CTX_set_ssl_ctx(SSL_CONF_CTX *a, SSL_CTX *b);
-unsigned int q_SSL_CONF_CTX_set_flags(SSL_CONF_CTX *a, unsigned int b);
-int q_SSL_CONF_CTX_finish(SSL_CONF_CTX *a);
-int q_SSL_CONF_cmd(SSL_CONF_CTX *a, const char *b, const char *c);
-void q_SSL_free(SSL *a);
-STACK_OF(SSL_CIPHER) *q_SSL_get_ciphers(const SSL *a);
-const SSL_CIPHER *q_SSL_get_current_cipher(SSL *a);
-int q_SSL_version(const SSL *a);
-int q_SSL_get_error(SSL *a, int b);
-STACK_OF(X509) *q_SSL_get_peer_cert_chain(SSL *a);
-X509 *q_SSL_get_peer_certificate(SSL *a);
-long q_SSL_get_verify_result(const SSL *a);
-SSL *q_SSL_new(SSL_CTX *a);
-SSL_CTX *q_SSL_get_SSL_CTX(SSL *a);
-long q_SSL_ctrl(SSL *ssl,int cmd, long larg, void *parg);
-int q_SSL_read(SSL *a, void *b, int c);
-void q_SSL_set_bio(SSL *a, BIO *b, BIO *c);
-void q_SSL_set_accept_state(SSL *a);
-void q_SSL_set_connect_state(SSL *a);
-int q_SSL_shutdown(SSL *a);
-int q_SSL_in_init(const SSL *s);
-int q_SSL_get_shutdown(const SSL *ssl);
-int q_SSL_set_session(SSL *to, SSL_SESSION *session);
-void q_SSL_SESSION_free(SSL_SESSION *ses);
-SSL_SESSION *q_SSL_get1_session(SSL *ssl);
-SSL_SESSION *q_SSL_get_session(const SSL *ssl);
-int q_SSL_set_ex_data(SSL *ssl, int idx, void *arg);
-void *q_SSL_get_ex_data(const SSL *ssl, int idx);
-#ifndef OPENSSL_NO_PSK
-typedef unsigned int (*q_psk_client_callback_t)(SSL *ssl, const char *hint, char *identity, unsigned int max_identity_len, unsigned char *psk, unsigned int max_psk_len);
-void q_SSL_set_psk_client_callback(SSL *ssl, q_psk_client_callback_t callback);
-typedef unsigned int (*q_psk_server_callback_t)(SSL *ssl, const char *identity, unsigned char *psk, unsigned int max_psk_len);
-void q_SSL_set_psk_server_callback(SSL *ssl, q_psk_server_callback_t callback);
-int q_SSL_CTX_use_psk_identity_hint(SSL_CTX *ctx, const char *hint);
-#endif // !OPENSSL_NO_PSK
-int q_SSL_write(SSL *a, const void *b, int c);
-int q_X509_cmp(X509 *a, X509 *b);
-X509 *q_X509_dup(X509 *a);
-void q_X509_print(BIO *a, X509*b);
-int q_X509_digest(const X509 *x509, const EVP_MD *type, unsigned char *md, unsigned int *len);
-ASN1_OBJECT *q_X509_EXTENSION_get_object(X509_EXTENSION *a);
-Q_AUTOTEST_EXPORT void q_X509_free(X509 *a);
-Q_AUTOTEST_EXPORT ASN1_TIME *q_X509_gmtime_adj(ASN1_TIME *s, long adj);
-Q_AUTOTEST_EXPORT void q_ASN1_TIME_free(ASN1_TIME *t);
-X509_EXTENSION *q_X509_get_ext(X509 *a, int b);
-int q_X509_get_ext_count(X509 *a);
-void *q_X509_get_ext_d2i(X509 *a, int b, int *c, int *d);
-const X509V3_EXT_METHOD *q_X509V3_EXT_get(X509_EXTENSION *a);
-void *q_X509V3_EXT_d2i(X509_EXTENSION *a);
-int q_X509_EXTENSION_get_critical(X509_EXTENSION *a);
-ASN1_OCTET_STRING *q_X509_EXTENSION_get_data(X509_EXTENSION *a);
-void q_BASIC_CONSTRAINTS_free(BASIC_CONSTRAINTS *a);
-void q_AUTHORITY_KEYID_free(AUTHORITY_KEYID *a);
-int q_ASN1_STRING_print(BIO *a, const ASN1_STRING *b);
-int q_X509_check_issued(X509 *a, X509 *b);
-X509_NAME *q_X509_get_issuer_name(X509 *a);
-X509_NAME *q_X509_get_subject_name(X509 *a);
-ASN1_INTEGER *q_X509_get_serialNumber(X509 *a);
-int q_X509_verify_cert(X509_STORE_CTX *ctx);
-int q_X509_NAME_entry_count(X509_NAME *a);
-X509_NAME_ENTRY *q_X509_NAME_get_entry(X509_NAME *a,int b);
-ASN1_STRING *q_X509_NAME_ENTRY_get_data(X509_NAME_ENTRY *a);
-ASN1_OBJECT *q_X509_NAME_ENTRY_get_object(X509_NAME_ENTRY *a);
-EVP_PKEY *q_X509_PUBKEY_get(X509_PUBKEY *a);
-void q_X509_STORE_free(X509_STORE *store);
-X509_STORE *q_X509_STORE_new();
-int q_X509_STORE_add_cert(X509_STORE *ctx, X509 *x);
-void q_X509_STORE_CTX_free(X509_STORE_CTX *storeCtx);
-int q_X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store,
- X509 *x509, STACK_OF(X509) *chain);
-X509_STORE_CTX *q_X509_STORE_CTX_new();
-int q_X509_STORE_CTX_set_purpose(X509_STORE_CTX *ctx, int purpose);
-int q_X509_STORE_CTX_get_error(X509_STORE_CTX *ctx);
-int q_X509_STORE_CTX_get_error_depth(X509_STORE_CTX *ctx);
-X509 *q_X509_STORE_CTX_get_current_cert(X509_STORE_CTX *ctx);
-X509_STORE *q_X509_STORE_CTX_get0_store(X509_STORE_CTX *ctx);
-
-// Diffie-Hellman support
-DH *q_DH_new();
-void q_DH_free(DH *dh);
-DH *q_d2i_DHparams(DH **a, const unsigned char **pp, long length);
-int q_i2d_DHparams(DH *a, unsigned char **p);
-
-#ifndef OPENSSL_NO_DEPRECATED_3_0
-int q_DH_check(DH *dh, int *codes);
-#endif // OPENSSL_NO_DEPRECATED_3_0
-
-BIGNUM *q_BN_bin2bn(const unsigned char *s, int len, BIGNUM *ret);
-#define q_SSL_CTX_set_tmp_dh(ctx, dh) q_SSL_CTX_ctrl((ctx), SSL_CTRL_SET_TMP_DH, 0, (char *)dh)
-
-#ifndef OPENSSL_NO_EC
-// EC Diffie-Hellman support
-EC_KEY *q_EC_KEY_dup(const EC_KEY *src);
-EC_KEY *q_EC_KEY_new_by_curve_name(int nid);
-void q_EC_KEY_free(EC_KEY *ecdh);
-#define q_SSL_CTX_set_tmp_ecdh(ctx, ecdh) q_SSL_CTX_ctrl((ctx), SSL_CTRL_SET_TMP_ECDH, 0, (char *)ecdh)
-
-// EC curves management
-size_t q_EC_get_builtin_curves(EC_builtin_curve *r, size_t nitems);
-int q_EC_curve_nist2nid(const char *name);
-#endif // OPENSSL_NO_EC
-
-#define q_SSL_get_server_tmp_key(ssl, key) q_SSL_ctrl((ssl), SSL_CTRL_GET_SERVER_TMP_KEY, 0, (char *)key)
-
-// PKCS#12 support
-int q_PKCS12_parse(PKCS12 *p12, const char *pass, EVP_PKEY **pkey, X509 **cert, STACK_OF(X509) **ca);
-PKCS12 *q_d2i_PKCS12_bio(BIO *bio, PKCS12 **pkcs12);
-void q_PKCS12_free(PKCS12 *pkcs12);
-
-#define q_BIO_get_mem_data(b, pp) (int)q_BIO_ctrl(b,BIO_CTRL_INFO,0,(char *)pp)
-#define q_BIO_pending(b) (int)q_BIO_ctrl(b,BIO_CTRL_PENDING,0,NULL)
-#define q_SSL_CTX_set_mode(ctx,op) q_SSL_CTX_ctrl((ctx),SSL_CTRL_MODE,(op),NULL)
-#define q_sk_GENERAL_NAME_num(st) q_SKM_sk_num(GENERAL_NAME, (st))
-#define q_sk_GENERAL_NAME_value(st, i) q_SKM_sk_value(GENERAL_NAME, (st), (i))
-
-void q_GENERAL_NAME_free(GENERAL_NAME *a);
-
-#define q_sk_X509_num(st) q_SKM_sk_num(X509, (st))
-#define q_sk_X509_value(st, i) q_SKM_sk_value(X509, (st), (i))
-#define q_sk_SSL_CIPHER_num(st) q_SKM_sk_num(SSL_CIPHER, (st))
-#define q_sk_SSL_CIPHER_value(st, i) q_SKM_sk_value(SSL_CIPHER, (st), (i))
-#define q_SSL_CTX_add_extra_chain_cert(ctx,x509) \
- q_SSL_CTX_ctrl(ctx,SSL_CTRL_EXTRA_CHAIN_CERT,0,(char *)x509)
-#define q_EVP_PKEY_assign_RSA(pkey,rsa) q_EVP_PKEY_assign((pkey),EVP_PKEY_RSA,\
- (char *)(rsa))
-#define q_EVP_PKEY_assign_DSA(pkey,dsa) q_EVP_PKEY_assign((pkey),EVP_PKEY_DSA,\
- (char *)(dsa))
-#define q_OpenSSL_add_all_algorithms() q_OPENSSL_add_all_algorithms_conf()
-
-#if OPENSSL_VERSION_MAJOR < 3
-int q_SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile, const char *CApath);
-#else
-int q_SSL_CTX_load_verify_dir(SSL_CTX *ctx, const char *CApath);
-#endif // OPENSSL_VERSION_MAJOR
-
-int q_i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp);
-SSL_SESSION *q_d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp, long length);
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
-int q_SSL_select_next_proto(unsigned char **out, unsigned char *outlen,
- const unsigned char *in, unsigned int inlen,
- const unsigned char *client, unsigned int client_len);
-void q_SSL_CTX_set_next_proto_select_cb(SSL_CTX *s,
- int (*cb) (SSL *ssl, unsigned char **out,
- unsigned char *outlen,
- const unsigned char *in,
- unsigned int inlen, void *arg),
- void *arg);
-void q_SSL_get0_next_proto_negotiated(const SSL *s, const unsigned char **data,
- unsigned *len);
-int q_SSL_set_alpn_protos(SSL *ssl, const unsigned char *protos,
- unsigned protos_len);
-void q_SSL_CTX_set_alpn_select_cb(SSL_CTX *ctx,
- int (*cb) (SSL *ssl,
- const unsigned char **out,
- unsigned char *outlen,
- const unsigned char *in,
- unsigned int inlen,
- void *arg), void *arg);
-void q_SSL_get0_alpn_selected(const SSL *ssl, const unsigned char **data,
- unsigned *len);
-#endif // !OPENSSL_NO_NEXTPROTONEG
-
-
-#if QT_CONFIG(dtls)
-
-extern "C"
-{
-typedef int (*CookieGenerateCallback)(SSL *, unsigned char *, unsigned *);
-}
-
-void q_SSL_CTX_set_cookie_generate_cb(SSL_CTX *ctx, CookieGenerateCallback cb);
-void q_SSL_CTX_set_cookie_verify_cb(SSL_CTX *ctx, CookieVerifyCallback cb);
-const SSL_METHOD *q_DTLS_server_method();
-const SSL_METHOD *q_DTLS_client_method();
-
-#endif // dtls
-
-void *q_X509_STORE_CTX_get_ex_data(X509_STORE_CTX *ctx, int idx);
-int q_SSL_get_ex_data_X509_STORE_CTX_idx();
-
-#if QT_CONFIG(dtls)
-#define q_DTLS_set_link_mtu(ssl, mtu) q_SSL_ctrl((ssl), DTLS_CTRL_SET_LINK_MTU, (mtu), nullptr)
-#define q_DTLSv1_get_timeout(ssl, arg) q_SSL_ctrl(ssl, DTLS_CTRL_GET_TIMEOUT, 0, arg)
-#define q_DTLSv1_handle_timeout(ssl) q_SSL_ctrl(ssl, DTLS_CTRL_HANDLE_TIMEOUT, 0, nullptr)
-#endif // dtls
-
-void q_BIO_set_flags(BIO *b, int flags);
-void q_BIO_clear_flags(BIO *b, int flags);
-void *q_BIO_get_ex_data(BIO *b, int idx);
-int q_BIO_set_ex_data(BIO *b, int idx, void *data);
-
-#define q_BIO_set_retry_read(b) q_BIO_set_flags(b, (BIO_FLAGS_READ|BIO_FLAGS_SHOULD_RETRY))
-#define q_BIO_set_retry_write(b) q_BIO_set_flags(b, (BIO_FLAGS_WRITE|BIO_FLAGS_SHOULD_RETRY))
-#define q_BIO_clear_retry_flags(b) q_BIO_clear_flags(b, (BIO_FLAGS_RWS|BIO_FLAGS_SHOULD_RETRY))
-#define q_BIO_set_app_data(s,arg) q_BIO_set_ex_data(s,0,arg)
-#define q_BIO_get_app_data(s) q_BIO_get_ex_data(s,0)
-
-// Helper function
-class QDateTime;
-QDateTime q_getTimeFromASN1(const ASN1_TIME *aTime);
-
-#define q_SSL_set_tlsext_status_type(ssl, type) \
- q_SSL_ctrl((ssl), SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE, (type), nullptr)
-
-#if QT_CONFIG(ocsp)
-
-OCSP_RESPONSE *q_d2i_OCSP_RESPONSE(OCSP_RESPONSE **a, const unsigned char **in, long len);
-Q_AUTOTEST_EXPORT int q_i2d_OCSP_RESPONSE(OCSP_RESPONSE *r, unsigned char **ppout);
-Q_AUTOTEST_EXPORT OCSP_RESPONSE *q_OCSP_response_create(int status, OCSP_BASICRESP *bs);
-Q_AUTOTEST_EXPORT void q_OCSP_RESPONSE_free(OCSP_RESPONSE *rs);
-int q_OCSP_response_status(OCSP_RESPONSE *resp);
-OCSP_BASICRESP *q_OCSP_response_get1_basic(OCSP_RESPONSE *resp);
-Q_AUTOTEST_EXPORT 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);
-Q_AUTOTEST_EXPORT int q_OCSP_basic_sign(OCSP_BASICRESP *brsp, X509 *signer, EVP_PKEY *key, const EVP_MD *dgst,
- STACK_OF(X509) *certs, unsigned long flags);
-Q_AUTOTEST_EXPORT OCSP_BASICRESP *q_OCSP_BASICRESP_new();
-Q_AUTOTEST_EXPORT void q_OCSP_BASICRESP_free(OCSP_BASICRESP *bs);
-int q_OCSP_basic_verify(OCSP_BASICRESP *bs, STACK_OF(X509) *certs, X509_STORE *st, unsigned long flags);
-int q_OCSP_resp_count(OCSP_BASICRESP *bs);
-OCSP_SINGLERESP *q_OCSP_resp_get0(OCSP_BASICRESP *bs, int idx);
-int q_OCSP_single_get0_status(OCSP_SINGLERESP *single, int *reason, ASN1_GENERALIZEDTIME **revtime,
- ASN1_GENERALIZEDTIME **thisupd, ASN1_GENERALIZEDTIME **nextupd);
-int q_OCSP_check_validity(ASN1_GENERALIZEDTIME *thisupd, ASN1_GENERALIZEDTIME *nextupd, long nsec, long maxsec);
-int q_OCSP_id_get0_info(ASN1_OCTET_STRING **piNameHash, ASN1_OBJECT **pmd, ASN1_OCTET_STRING **pikeyHash,
- ASN1_INTEGER **pserial, OCSP_CERTID *cid);
-
-const STACK_OF(X509) *q_OCSP_resp_get0_certs(const OCSP_BASICRESP *bs);
-Q_AUTOTEST_EXPORT OCSP_CERTID *q_OCSP_cert_to_id(const EVP_MD *dgst, X509 *subject, X509 *issuer);
-Q_AUTOTEST_EXPORT void q_OCSP_CERTID_free(OCSP_CERTID *cid);
-int q_OCSP_id_cmp(OCSP_CERTID *a, OCSP_CERTID *b);
-
-#define q_SSL_get_tlsext_status_ocsp_resp(ssl, arg) \
- q_SSL_ctrl(ssl, SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP, 0, arg)
-
-#define q_SSL_CTX_set_tlsext_status_cb(ssl, cb) \
- q_SSL_CTX_callback_ctrl(ssl, SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB, GenericCallbackType(cb))
-
-# define q_SSL_set_tlsext_status_ocsp_resp(ssl, arg, arglen) \
- q_SSL_ctrl(ssl, SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP, arglen, arg)
-
-#endif // ocsp
-
-
-void *q_CRYPTO_malloc(size_t num, const char *file, int line);
-#define q_OPENSSL_malloc(num) q_CRYPTO_malloc(num, "", 0)
-
-void q_SSL_set_info_callback(SSL *ssl, void (*cb) (const SSL *ssl, int type, int val));
-const char *q_SSL_alert_type_string(int value);
-const char *q_SSL_alert_desc_string_long(int value);
-
-int q_SSL_CTX_get_security_level(const SSL_CTX *ctx);
-void q_SSL_CTX_set_security_level(SSL_CTX *ctx, int level);
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/network/ssl/qsslsocket_p.h b/src/network/ssl/qsslsocket_p.h
index 31b8b79302..9dafb36a08 100644
--- a/src/network/ssl/qsslsocket_p.h
+++ b/src/network/ssl/qsslsocket_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSSLSOCKET_P_H
@@ -55,55 +19,26 @@
//
#include <QtNetwork/private/qtnetworkglobal_p.h>
+
#include <private/qtcpsocket_p.h>
-#include "qsslkey.h"
-#include "qsslconfiguration_p.h"
+
#include "qocspresponse.h"
-#ifndef QT_NO_OPENSSL
-#include <private/qsslcontext_openssl_p.h>
-#else
-class QSslContext;
-#endif
+#include "qsslconfiguration_p.h"
+#include "qsslkey.h"
+#include "qtlsbackend_p.h"
#include <QtCore/qlist.h>
+#include <QtCore/qmutex.h>
#include <QtCore/qstringlist.h>
-#include <private/qringbuffer_p.h>
-#if defined(Q_OS_MAC)
-#include <Security/SecCertificate.h>
-#include <CoreFoundation/CFArray.h>
-#elif defined(Q_OS_WIN)
-#include <QtCore/qt_windows.h>
#include <memory>
-#include <wincrypt.h>
-#ifndef HCRYPTPROV_LEGACY
-#define HCRYPTPROV_LEGACY HCRYPTPROV
-#endif // !HCRYPTPROV_LEGACY
-#endif // Q_OS_WIN
QT_BEGIN_NAMESPACE
-#if defined(Q_OS_MACOS)
- typedef CFDataRef (*PtrSecCertificateCopyData)(SecCertificateRef);
- typedef OSStatus (*PtrSecTrustSettingsCopyCertificates)(int, CFArrayRef*);
- typedef OSStatus (*PtrSecTrustCopyAnchorCertificates)(CFArrayRef*);
-#endif
-
-#if defined(Q_OS_WIN)
-
-// Those are needed by both OpenSSL and SChannel back-ends on Windows:
-struct QHCertStoreDeleter {
- void operator()(HCERTSTORE store)
- {
- CertCloseStore(store, 0);
- }
-};
-
-using QHCertStorePointer = std::unique_ptr<void, QHCertStoreDeleter>;
-
-#endif // Q_OS_WIN
+class QSslContext;
+class QTlsBackend;
-class QSslSocketPrivate : public QTcpSocketPrivate
+class Q_NETWORK_EXPORT QSslSocketPrivate : public QTcpSocketPrivate
{
Q_DECLARE_PUBLIC(QSslSocket)
public:
@@ -117,14 +52,11 @@ public:
QSslSocket::SslMode mode;
bool autoStartHandshake;
bool connectionEncrypted;
- bool shutdown;
bool ignoreAllSslErrors;
QList<QSslError> ignoreErrorsList;
bool* readyReadEmittedPointer;
QSslConfigurationPrivate configuration;
- QList<QSslError> sslErrors;
- QSharedPointer<QSslContext> sslContextPointer;
// if set, this hostname is used for certificate validation instead of the hostname
// that was used for connecting to.
@@ -135,16 +67,14 @@ public:
static bool s_loadRootCertsOnDemand;
static bool supportsSsl();
- static long sslLibraryVersionNumber();
- static QString sslLibraryVersionString();
- static long sslLibraryBuildVersionNumber();
- static QString sslLibraryBuildVersionString();
static void ensureInitialized();
+
static QList<QSslCipher> defaultCiphers();
+ static QList<QSslCipher> defaultDtlsCiphers();
static QList<QSslCipher> supportedCiphers();
static void setDefaultCiphers(const QList<QSslCipher> &ciphers);
+ static void setDefaultDtlsCiphers(const QList<QSslCipher> &ciphers);
static void setDefaultSupportedCiphers(const QList<QSslCipher> &ciphers);
- static void resetDefaultCiphers();
static QList<QSslEllipticCurve> supportedEllipticCurves();
static void setDefaultSupportedEllipticCurves(const QList<QSslEllipticCurve> &curves);
@@ -155,19 +85,19 @@ public:
static void setDefaultCaCertificates(const QList<QSslCertificate> &certs);
static void addDefaultCaCertificate(const QSslCertificate &cert);
static void addDefaultCaCertificates(const QList<QSslCertificate> &certs);
- Q_AUTOTEST_EXPORT static bool isMatchingHostname(const QSslCertificate &cert,
- const QString &peerName);
- Q_AUTOTEST_EXPORT static bool isMatchingHostname(const QString &cn, const QString &hostname);
+ static bool isMatchingHostname(const QSslCertificate &cert, const QString &peerName);
+ static bool isMatchingHostname(const QString &cn, const QString &hostname);
// The socket itself, including private slots.
- QTcpSocket *plainSocket;
+ QTcpSocket *plainSocket = nullptr;
void createPlainSocket(QIODevice::OpenMode openMode);
static void pauseSocketNotifiers(QSslSocket*);
static void resumeSocketNotifiers(QSslSocket*);
// ### The 2 methods below should be made member methods once the QSslContext class is made public
- static void checkSettingSslContext(QSslSocket*, QSharedPointer<QSslContext>);
- static QSharedPointer<QSslContext> sslContext(QSslSocket *socket);
+ static void checkSettingSslContext(QSslSocket*, std::shared_ptr<QSslContext>);
+ static std::shared_ptr<QSslContext> sslContext(QSslSocket *socket);
bool isPaused() const;
+ void setPaused(bool p);
bool bind(const QHostAddress &address, quint16, QAbstractSocket::BindMode) override;
void _q_connectedSlot();
void _q_hostFoundSlot();
@@ -182,52 +112,57 @@ public:
void _q_flushWriteBuffer();
void _q_flushReadBuffer();
void _q_resumeImplementation();
-#if defined(Q_OS_WIN) && !QT_CONFIG(schannel)
- virtual void _q_caRootLoaded(QSslCertificate,QSslCertificate) = 0;
-#endif
static QList<QByteArray> unixRootCertDirectories(); // used also by QSslContext
- virtual qint64 peek(char *data, qint64 maxSize) override;
- virtual QByteArray peek(qint64 maxSize) override;
+ qint64 peek(char *data, qint64 maxSize) override;
+ QByteArray peek(qint64 maxSize) override;
bool flush() override;
- // Platform specific functions
- virtual void startClientEncryption() = 0;
- virtual void startServerEncryption() = 0;
- virtual void transmit() = 0;
- virtual void disconnectFromHost() = 0;
- virtual void disconnected() = 0;
- virtual QSslCipher sessionCipher() const = 0;
- virtual QSsl::SslProtocol sessionProtocol() const = 0;
- virtual void continueHandshake() = 0;
-
- Q_AUTOTEST_EXPORT static bool rootCertOnDemandLoadingSupported();
-
-private:
- static bool ensureLibraryLoaded();
- static void ensureCiphersAndCertsLoaded();
-#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
- static QList<QByteArray> fetchSslCertificateData();
-#endif
+ void startClientEncryption();
+ void startServerEncryption();
+ void transmit();
+ void disconnectFromHost();
+ void disconnected();
+ QSslCipher sessionCipher() const;
+ QSsl::SslProtocol sessionProtocol() const;
+ void continueHandshake();
+
+ static bool rootCertOnDemandLoadingSupported();
+ static void setRootCertOnDemandLoadingSupported(bool supported);
+
+ static QTlsBackend *tlsBackendInUse();
+
+ // Needed by TlsCryptograph:
+ QSslSocket::SslMode tlsMode() const;
+ bool isRootsOnDemandAllowed() const;
+ QString verificationName() const;
+ QString tlsHostName() const;
+ QTcpSocket *plainTcpSocket() const;
+ bool verifyErrorsHaveBeenIgnored();
+ bool isAutoStartingHandshake() const;
+ bool isPendingClose() const;
+ void setPendingClose(bool pc);
+ qint64 maxReadBufferSize() const;
+ void setMaxReadBufferSize(qint64 maxSize);
+ void setEncrypted(bool enc);
+ QRingBufferRef &tlsWriteBuffer();
+ QRingBufferRef &tlsBuffer();
+ bool &tlsEmittedBytesWritten();
+ bool *readyReadPointer();
- static bool s_libraryLoaded;
- static bool s_loadedCiphersAndCerts;
protected:
- bool verifyErrorsHaveBeenIgnored();
+
+ bool hasUndecryptedData() const;
bool paused;
bool flushTriggered;
- bool systemOrSslErrorDetected = false;
- QList<QOcspResponse> ocspResponses;
- bool handshakeInterrupted = false;
- bool fetchAuthorityInformation = false;
- QSslCertificate caToFetch;
-};
-#if QT_CONFIG(securetransport) || QT_CONFIG(schannel)
-// Implemented in qsslsocket_qt.cpp
-QByteArray _q_makePkcs12(const QList<QSslCertificate> &certs, const QSslKey &key, const QString &passPhrase);
-#endif
+ static inline QMutex backendMutex;
+ static inline QString activeBackendName;
+ static inline QTlsBackend *tlsBackend = nullptr;
+
+ std::unique_ptr<QTlsPrivate::TlsCryptograph> backend;
+};
QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslsocket_qt.cpp b/src/network/ssl/qsslsocket_qt.cpp
deleted file mode 100644
index a5d21bd77e..0000000000
--- a/src/network/ssl/qsslsocket_qt.cpp
+++ /dev/null
@@ -1,309 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Jeremy Lainé <jeremy.laine@m4x.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#include <QtCore/qbytearray.h>
-#include <QtCore/qdatastream.h>
-#include <QtCore/qmessageauthenticationcode.h>
-#include <QtCore/qrandom.h>
-
-#include "qsslsocket_p.h"
-#include "qasn1element_p.h"
-#include "qsslkey_p.h"
-
-QT_BEGIN_NAMESPACE
-
-/*
- PKCS12 helpers.
-*/
-
-static QAsn1Element wrap(quint8 type, const QAsn1Element &child)
-{
- QByteArray value;
- QDataStream stream(&value, QIODevice::WriteOnly);
- child.write(stream);
- return QAsn1Element(type, value);
-}
-
-static QAsn1Element _q_PKCS7_data(const QByteArray &data)
-{
- QList<QAsn1Element> items;
- items << QAsn1Element::fromObjectId("1.2.840.113549.1.7.1");
- items << wrap(QAsn1Element::Context0Type,
- QAsn1Element(QAsn1Element::OctetStringType, data));
- return QAsn1Element::fromVector(items);
-}
-
-/*!
- PKCS #12 key derivation.
-
- Some test vectors:
- http://www.drh-consultancy.demon.co.uk/test.txt
- \internal
-*/
-static QByteArray _q_PKCS12_keygen(char id, const QByteArray &salt, const QString &passPhrase, int n, int r)
-{
- const int u = 20;
- const int v = 64;
-
- // password formatting
- QByteArray passUnicode(passPhrase.size() * 2 + 2, '\0');
- char *p = passUnicode.data();
- for (int i = 0; i < passPhrase.size(); ++i) {
- quint16 ch = passPhrase[i].unicode();
- *(p++) = (ch & 0xff00) >> 8;
- *(p++) = (ch & 0xff);
- }
-
- // prepare I
- QByteArray D(64, id);
- QByteArray S, P;
- const int sSize = v * ((salt.size() + v - 1) / v);
- S.resize(sSize);
- for (int i = 0; i < sSize; ++i)
- S[i] = salt[i % salt.size()];
- const int pSize = v * ((passUnicode.size() + v - 1) / v);
- P.resize(pSize);
- for (int i = 0; i < pSize; ++i)
- P[i] = passUnicode[i % passUnicode.size()];
- QByteArray I = S + P;
-
- // apply hashing
- const int c = (n + u - 1) / u;
- QByteArray A;
- QByteArray B;
- B.resize(v);
- QCryptographicHash hash(QCryptographicHash::Sha1);
- for (int i = 0; i < c; ++i) {
- // hash r iterations
- QByteArray Ai = D + I;
- for (int j = 0; j < r; ++j) {
- hash.reset();
- hash.addData(Ai);
- Ai = hash.result();
- }
-
- for (int j = 0; j < v; ++j)
- B[j] = Ai[j % u];
-
- // modify I as Ij = (Ij + B + 1) modulo 2^v
- for (int p = 0; p < I.size(); p += v) {
- quint8 carry = 1;
- for (int j = v - 1; j >= 0; --j) {
- quint16 v = quint8(I[p + j]) + quint8(B[j]) + carry;
- I[p + j] = v & 0xff;
- carry = (v & 0xff00) >> 8;
- }
- }
- A += Ai;
- }
- return A.left(n);
-}
-
-static QByteArray _q_PKCS12_salt()
-{
- QByteArray salt;
- salt.resize(8);
- for (int i = 0; i < salt.size(); ++i)
- salt[i] = (QRandomGenerator::global()->generate() & 0xff);
- return salt;
-}
-
-static QByteArray _q_PKCS12_certBag(const QSslCertificate &cert)
-{
- QList<QAsn1Element> items;
- items << QAsn1Element::fromObjectId("1.2.840.113549.1.12.10.1.3");
-
- // certificate
- QList<QAsn1Element> certItems;
- certItems << QAsn1Element::fromObjectId("1.2.840.113549.1.9.22.1");
- certItems << wrap(QAsn1Element::Context0Type,
- QAsn1Element(QAsn1Element::OctetStringType, cert.toDer()));
- items << wrap(QAsn1Element::Context0Type,
- QAsn1Element::fromVector(certItems));
-
- // local key id
- const QByteArray localKeyId = cert.digest(QCryptographicHash::Sha1);
- QList<QAsn1Element> idItems;
- idItems << QAsn1Element::fromObjectId("1.2.840.113549.1.9.21");
- idItems << wrap(QAsn1Element::SetType,
- QAsn1Element(QAsn1Element::OctetStringType, localKeyId));
- items << wrap(QAsn1Element::SetType, QAsn1Element::fromVector(idItems));
-
- // dump
- QAsn1Element root = wrap(QAsn1Element::SequenceType, QAsn1Element::fromVector(items));
- QByteArray ba;
- QDataStream stream(&ba, QIODevice::WriteOnly);
- root.write(stream);
- return ba;
-}
-
-static QAsn1Element _q_PKCS12_key(const QSslKey &key)
-{
- Q_ASSERT(key.algorithm() == QSsl::Rsa || key.algorithm() == QSsl::Dsa);
-
- QList<QAsn1Element> keyItems;
- keyItems << QAsn1Element::fromInteger(0);
- QList<QAsn1Element> algoItems;
- if (key.algorithm() == QSsl::Rsa)
- algoItems << QAsn1Element::fromObjectId(RSA_ENCRYPTION_OID);
- else if (key.algorithm() == QSsl::Dsa)
- algoItems << QAsn1Element::fromObjectId(DSA_ENCRYPTION_OID);
- algoItems << QAsn1Element(QAsn1Element::NullType);
- keyItems << QAsn1Element::fromVector(algoItems);
- keyItems << QAsn1Element(QAsn1Element::OctetStringType, key.toDer());
- return QAsn1Element::fromVector(keyItems);
-}
-
-static QByteArray _q_PKCS12_shroudedKeyBag(const QSslKey &key, const QString &passPhrase, const QByteArray &localKeyId)
-{
- const int iterations = 2048;
- QByteArray salt = _q_PKCS12_salt();
- QByteArray cKey = _q_PKCS12_keygen(1, salt, passPhrase, 24, iterations);
- QByteArray cIv = _q_PKCS12_keygen(2, salt, passPhrase, 8, iterations);
-
- // prepare and encrypt data
- QByteArray plain;
- QDataStream plainStream(&plain, QIODevice::WriteOnly);
- _q_PKCS12_key(key).write(plainStream);
- QByteArray crypted = QSslKeyPrivate::encrypt(QSslKeyPrivate::DesEde3Cbc,
- plain, cKey, cIv);
-
- QList<QAsn1Element> items;
- items << QAsn1Element::fromObjectId("1.2.840.113549.1.12.10.1.2");
-
- // key
- QList<QAsn1Element> keyItems;
- QList<QAsn1Element> algoItems;
- algoItems << QAsn1Element::fromObjectId("1.2.840.113549.1.12.1.3");
- QList<QAsn1Element> paramItems;
- paramItems << QAsn1Element(QAsn1Element::OctetStringType, salt);
- paramItems << QAsn1Element::fromInteger(iterations);
- algoItems << QAsn1Element::fromVector(paramItems);
- keyItems << QAsn1Element::fromVector(algoItems);
- keyItems << QAsn1Element(QAsn1Element::OctetStringType, crypted);
- items << wrap(QAsn1Element::Context0Type,
- QAsn1Element::fromVector(keyItems));
-
- // local key id
- QList<QAsn1Element> idItems;
- idItems << QAsn1Element::fromObjectId("1.2.840.113549.1.9.21");
- idItems << wrap(QAsn1Element::SetType,
- QAsn1Element(QAsn1Element::OctetStringType, localKeyId));
- items << wrap(QAsn1Element::SetType,
- QAsn1Element::fromVector(idItems));
-
- // dump
- QAsn1Element root = wrap(QAsn1Element::SequenceType, QAsn1Element::fromVector(items));
- QByteArray ba;
- QDataStream stream(&ba, QIODevice::WriteOnly);
- root.write(stream);
- return ba;
-}
-
-static QByteArray _q_PKCS12_bag(const QList<QSslCertificate> &certs, const QSslKey &key, const QString &passPhrase)
-{
- QList<QAsn1Element> items;
-
- // certs
- for (int i = 0; i < certs.size(); ++i)
- items << _q_PKCS7_data(_q_PKCS12_certBag(certs[i]));
-
- // key
- if (!key.isNull()) {
- const QByteArray localKeyId = certs.first().digest(QCryptographicHash::Sha1);
- items << _q_PKCS7_data(_q_PKCS12_shroudedKeyBag(key, passPhrase, localKeyId));
- }
-
- // dump
- QAsn1Element root = QAsn1Element::fromVector(items);
- QByteArray ba;
- QDataStream stream(&ba, QIODevice::WriteOnly);
- root.write(stream);
- return ba;
-}
-
-static QAsn1Element _q_PKCS12_mac(const QByteArray &data, const QString &passPhrase)
-{
- const int iterations = 2048;
-
- // salt generation
- QByteArray macSalt = _q_PKCS12_salt();
- QByteArray key = _q_PKCS12_keygen(3, macSalt, passPhrase, 20, iterations);
-
- // HMAC calculation
- QMessageAuthenticationCode hmac(QCryptographicHash::Sha1, key);
- hmac.addData(data);
-
- QList<QAsn1Element> algoItems;
- algoItems << QAsn1Element::fromObjectId("1.3.14.3.2.26");
- algoItems << QAsn1Element(QAsn1Element::NullType);
-
- QList<QAsn1Element> digestItems;
- digestItems << QAsn1Element::fromVector(algoItems);
- digestItems << QAsn1Element(QAsn1Element::OctetStringType, hmac.result());
-
- QList<QAsn1Element> macItems;
- macItems << QAsn1Element::fromVector(digestItems);
- macItems << QAsn1Element(QAsn1Element::OctetStringType, macSalt);
- macItems << QAsn1Element::fromInteger(iterations);
- return QAsn1Element::fromVector(macItems);
-}
-
-QByteArray _q_makePkcs12(const QList<QSslCertificate> &certs, const QSslKey &key, const QString &passPhrase)
-{
- QList<QAsn1Element> items;
-
- // version
- items << QAsn1Element::fromInteger(3);
-
- // auth safe
- const QByteArray data = _q_PKCS12_bag(certs, key, passPhrase);
- items << _q_PKCS7_data(data);
-
- // HMAC
- items << _q_PKCS12_mac(data, passPhrase);
-
- // dump
- QAsn1Element root = QAsn1Element::fromVector(items);
- QByteArray ba;
- QDataStream stream(&ba, QIODevice::WriteOnly);
- root.write(stream);
- return ba;
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslsocket_schannel.cpp b/src/network/ssl/qsslsocket_schannel.cpp
deleted file mode 100644
index f0a9f6a027..0000000000
--- a/src/network/ssl/qsslsocket_schannel.cpp
+++ /dev/null
@@ -1,2064 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-// #define QSSLSOCKET_DEBUG
-
-#include "qssl_p.h"
-#include "qsslsocket.h"
-#include "qsslsocket_schannel_p.h"
-#include "qsslcertificate.h"
-#include "qsslcertificateextension.h"
-#include "qsslcertificate_p.h"
-#include "qsslcipher_p.h"
-
-#include <QtCore/qscopeguard.h>
-#include <QtCore/qoperatingsystemversion.h>
-#include <QtCore/qregularexpression.h>
-#include <QtCore/qdatastream.h>
-#include <QtCore/qmutex.h>
-
-#define SECURITY_WIN32
-#include <security.h>
-#include <schnlsp.h>
-
-#if NTDDI_VERSION >= NTDDI_WINBLUE && !defined(Q_CC_MINGW)
-// ALPN = Application Layer Protocol Negotiation
-#define SUPPORTS_ALPN 1
-#endif
-
-// Not defined in MinGW
-#ifndef SECBUFFER_ALERT
-#define SECBUFFER_ALERT 17
-#endif
-#ifndef SECPKG_ATTR_APPLICATION_PROTOCOL
-#define SECPKG_ATTR_APPLICATION_PROTOCOL 35
-#endif
-
-// Another missing MinGW define
-#ifndef SEC_E_APPLICATION_PROTOCOL_MISMATCH
-#define SEC_E_APPLICATION_PROTOCOL_MISMATCH _HRESULT_TYPEDEF_(0x80090367L)
-#endif
-
-// Also not defined in MinGW.......
-#ifndef SP_PROT_TLS1_SERVER
-#define SP_PROT_TLS1_SERVER 0x00000040
-#endif
-#ifndef SP_PROT_TLS1_CLIENT
-#define SP_PROT_TLS1_CLIENT 0x00000080
-#endif
-#ifndef SP_PROT_TLS1_0_SERVER
-#define SP_PROT_TLS1_0_SERVER SP_PROT_TLS1_SERVER
-#endif
-#ifndef SP_PROT_TLS1_0_CLIENT
-#define SP_PROT_TLS1_0_CLIENT SP_PROT_TLS1_CLIENT
-#endif
-#ifndef SP_PROT_TLS1_0
-#define SP_PROT_TLS1_0 (SP_PROT_TLS1_0_CLIENT | SP_PROT_TLS1_0_SERVER)
-#endif
-#ifndef SP_PROT_TLS1_1_SERVER
-#define SP_PROT_TLS1_1_SERVER 0x00000100
-#endif
-#ifndef SP_PROT_TLS1_1_CLIENT
-#define SP_PROT_TLS1_1_CLIENT 0x00000200
-#endif
-#ifndef SP_PROT_TLS1_1
-#define SP_PROT_TLS1_1 (SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_1_SERVER)
-#endif
-#ifndef SP_PROT_TLS1_2_SERVER
-#define SP_PROT_TLS1_2_SERVER 0x00000400
-#endif
-#ifndef SP_PROT_TLS1_2_CLIENT
-#define SP_PROT_TLS1_2_CLIENT 0x00000800
-#endif
-#ifndef SP_PROT_TLS1_2
-#define SP_PROT_TLS1_2 (SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_2_SERVER)
-#endif
-#ifndef SP_PROT_TLS1_3_SERVER
-#define SP_PROT_TLS1_3_SERVER 0x00001000
-#endif
-#ifndef SP_PROT_TLS1_3_CLIENT
-#define SP_PROT_TLS1_3_CLIENT 0x00002000
-#endif
-#ifndef SP_PROT_TLS1_3
-#define SP_PROT_TLS1_3 (SP_PROT_TLS1_3_CLIENT | SP_PROT_TLS1_3_SERVER)
-#endif
-
-/*
- @future!:
-
- - Transmitting intermediate certificates
- - Look for a way to avoid putting intermediate certificates in the certificate store
- - No documentation on how to send the chain
- - A stackoverflow question on this from 3 years ago implies schannel only sends intermediate
- certificates if it's "in the system or user certificate store".
- - https://stackoverflow.com/q/30156584/2493610
- - This can be done by users, but we shouldn't add any and all local intermediate
- certs to the stores automatically.
- - PSK support
- - Was added in Windows 10 (it seems), documentation at time of writing is sparse/non-existent.
- - Specifically about how to supply credentials when they're requested.
- - Or how to recognize that they're requested in the first place.
- - Skip certificate verification.
- - Check if "PSK-only" is still required to do PSK _at all_ (all-around bad solution).
- - Check if SEC_I_INCOMPLETE_CREDENTIALS is still returned for both "missing certificate" and
- "missing PSK" when calling InitializeSecurityContext in "performHandshake".
-
- Medium priority:
- - Setting cipher-suites (or ALG_ID)
- - People have survived without it in WinRT
-
- Low priority:
- - Possibly make RAII wrappers for SecBuffer (which I commonly create QScopeGuards for)
-
-*/
-
-QT_BEGIN_NAMESPACE
-
-namespace {
-SecBuffer createSecBuffer(void *ptr, unsigned long length, unsigned long bufferType)
-{
- return SecBuffer{ length, bufferType, ptr };
-}
-
-SecBuffer createSecBuffer(QByteArray &buffer, unsigned long bufferType)
-{
- return createSecBuffer(buffer.data(), static_cast<unsigned long>(buffer.length()), bufferType);
-}
-
-QString schannelErrorToString(qint32 status)
-{
- switch (status) {
- case SEC_E_INSUFFICIENT_MEMORY:
- return QSslSocket::tr("Insufficient memory");
- case SEC_E_INTERNAL_ERROR:
- return QSslSocket::tr("Internal error");
- case SEC_E_INVALID_HANDLE:
- return QSslSocket::tr("An internal handle was invalid");
- case SEC_E_INVALID_TOKEN:
- return QSslSocket::tr("An internal token was invalid");
- case SEC_E_LOGON_DENIED:
- // According to the link below we get this error when Schannel receives TLS1_ALERT_ACCESS_DENIED
- // https://docs.microsoft.com/en-us/windows/desktop/secauthn/schannel-error-codes-for-tls-and-ssl-alerts
- return QSslSocket::tr("Access denied");
- case SEC_E_NO_AUTHENTICATING_AUTHORITY:
- return QSslSocket::tr("No authority could be contacted for authorization");
- case SEC_E_NO_CREDENTIALS:
- return QSslSocket::tr("No credentials");
- case SEC_E_TARGET_UNKNOWN:
- return QSslSocket::tr("The target is unknown or unreachable");
- case SEC_E_UNSUPPORTED_FUNCTION:
- return QSslSocket::tr("An unsupported function was requested");
- case SEC_E_WRONG_PRINCIPAL:
- // SNI error
- return QSslSocket::tr("The hostname provided does not match the one received from the peer");
- case SEC_E_APPLICATION_PROTOCOL_MISMATCH:
- return QSslSocket::tr("No common protocol exists between the client and the server");
- case SEC_E_ILLEGAL_MESSAGE:
- return QSslSocket::tr("Unexpected or badly-formatted message received");
- case SEC_E_ENCRYPT_FAILURE:
- return QSslSocket::tr("The data could not be encrypted");
- case SEC_E_ALGORITHM_MISMATCH:
- return QSslSocket::tr("No cipher suites in common");
- case SEC_E_UNKNOWN_CREDENTIALS:
- // This can mean "invalid argument" in some cases...
- return QSslSocket::tr("The credentials were not recognized / Invalid argument");
- case SEC_E_MESSAGE_ALTERED:
- // According to the Internet it also triggers for messages that are out of order.
- // https://microsoft.public.platformsdk.security.narkive.com/4JAvlMvD/help-please-schannel-security-contexts-and-decryptmessage
- return QSslSocket::tr("The message was tampered with, damaged or out of sequence.");
- case SEC_E_OUT_OF_SEQUENCE:
- return QSslSocket::tr("A message was received out of sequence.");
- case SEC_E_CONTEXT_EXPIRED:
- return QSslSocket::tr("The TLS/SSL connection has been closed");
- default:
- return QSslSocket::tr("Unknown error occurred: %1").arg(status);
- }
-}
-
-DWORD toSchannelProtocol(QSsl::SslProtocol protocol)
-{
- DWORD protocols = SP_PROT_NONE;
- switch (protocol) {
- case QSsl::UnknownProtocol:
- return DWORD(-1);
- case QSsl::DtlsV1_0:
- case QSsl::DtlsV1_2:
- case QSsl::DtlsV1_0OrLater:
- case QSsl::DtlsV1_2OrLater:
- return DWORD(-1); // Not supported at the moment (@future)
- case QSsl::AnyProtocol:
- protocols = SP_PROT_TLS1_0 | SP_PROT_TLS1_1 | SP_PROT_TLS1_2;
- // @future Add TLS 1.3 when supported by Windows!
- break;
- case QSsl::TlsV1_0:
- protocols = SP_PROT_TLS1_0;
- break;
- case QSsl::TlsV1_1:
- protocols = SP_PROT_TLS1_1;
- break;
- case QSsl::TlsV1_2:
- protocols = SP_PROT_TLS1_2;
- break;
- case QSsl::TlsV1_3:
- if ((false)) // @future[0/1] Replace with version check once it's supported in Windows
- protocols = SP_PROT_TLS1_3;
- else
- protocols = DWORD(-1);
- break;
- case QSsl::SecureProtocols: // TLS v1.0 and later is currently considered secure
- case QSsl::TlsV1_0OrLater:
- // For the "OrLater" protocols we fall through from one to the next, adding all of them
- // in ascending order
- protocols = SP_PROT_TLS1_0;
- Q_FALLTHROUGH();
- case QSsl::TlsV1_1OrLater:
- protocols |= SP_PROT_TLS1_1;
- Q_FALLTHROUGH();
- case QSsl::TlsV1_2OrLater:
- protocols |= SP_PROT_TLS1_2;
- Q_FALLTHROUGH();
- case QSsl::TlsV1_3OrLater:
- if ((false)) // @future[1/1] Also replace this with a version check
- protocols |= SP_PROT_TLS1_3;
- else if (protocol == QSsl::TlsV1_3OrLater)
- protocols = DWORD(-1); // if TlsV1_3OrLater was specifically chosen we should fail
- break;
- }
- return protocols;
-}
-
-/*!
- \internal
- Used when converting the established session's \a protocol back to
- Qt's own SslProtocol type.
-
- Only one protocol should be passed in at a time.
-*/
-QSsl::SslProtocol toQtSslProtocol(DWORD protocol)
-{
-#define MAP_PROTOCOL(sp_protocol, q_protocol) \
- if (protocol & sp_protocol) { \
- Q_ASSERT(!(protocol & ~sp_protocol)); \
- return q_protocol; \
- }
-
- MAP_PROTOCOL(SP_PROT_TLS1_0, QSsl::TlsV1_0)
- MAP_PROTOCOL(SP_PROT_TLS1_1, QSsl::TlsV1_1)
- MAP_PROTOCOL(SP_PROT_TLS1_2, QSsl::TlsV1_2)
- MAP_PROTOCOL(SP_PROT_TLS1_3, QSsl::TlsV1_3)
-#undef MAP_PROTOCOL
- Q_UNREACHABLE();
- return QSsl::UnknownProtocol;
-}
-
-/*!
- \internal
- Used by verifyCertContext to check if a client cert is used by a server or vice versa.
-*/
-bool netscapeWrongCertType(const QList<QSslCertificateExtension> &extensions, bool isClient)
-{
- const auto netscapeIt = std::find_if(
- extensions.cbegin(), extensions.cend(),
- [](const QSslCertificateExtension &extension) {
- const auto netscapeCertType = QStringLiteral("2.16.840.1.113730.1.1");
- return extension.oid() == netscapeCertType;
- });
- if (netscapeIt != extensions.cend()) {
- const QByteArray netscapeCertTypeByte = netscapeIt->value().toByteArray();
- int netscapeCertType = 0;
- QDataStream dataStream(netscapeCertTypeByte);
- dataStream >> netscapeCertType;
- if (dataStream.status() != QDataStream::Status::Ok)
- return true;
- const int expectedPeerCertType = isClient ? NETSCAPE_SSL_SERVER_AUTH_CERT_TYPE
- : NETSCAPE_SSL_CLIENT_AUTH_CERT_TYPE;
- if ((netscapeCertType & expectedPeerCertType) == 0)
- return true;
- }
- return false;
-}
-
-/*!
- \internal
- Used by verifyCertContext to check the basicConstraints certificate
- extension to see if the certificate is a certificate authority.
- Returns false if the certificate does not have the basicConstraints
- extension or if it is not a certificate authority.
-*/
-bool isCertificateAuthority(const QList<QSslCertificateExtension> &extensions)
-{
- auto it = std::find_if(extensions.cbegin(), extensions.cend(),
- [](const QSslCertificateExtension &extension) {
- return extension.name() == QLatin1String("basicConstraints");
- });
- if (it != extensions.cend()) {
- QVariantMap basicConstraints = it->value().toMap();
- return basicConstraints.value(QLatin1String("ca"), false).toBool();
- }
- return false;
-}
-
-/*!
- \internal
- Returns true if the attributes we requested from the context/handshake have
- been given.
-*/
-bool matchesContextRequirements(DWORD attributes, DWORD requirements,
- QSslSocket::PeerVerifyMode verifyMode,
- bool isClient)
-{
-#ifdef QSSLSOCKET_DEBUG
-#define DEBUG_WARN(message) qCWarning(lcSsl, message)
-#else
-#define DEBUG_WARN(message)
-#endif
-
-#define CHECK_ATTRIBUTE(attributeName) \
- do { \
- const DWORD req##attributeName = isClient ? ISC_REQ_##attributeName : ASC_REQ_##attributeName; \
- const DWORD ret##attributeName = isClient ? ISC_RET_##attributeName : ASC_RET_##attributeName; \
- if (!(requirements & req##attributeName) != !(attributes & ret##attributeName)) { \
- DEBUG_WARN("Missing attribute \"" #attributeName "\""); \
- return false; \
- } \
- } while (false)
-
- CHECK_ATTRIBUTE(CONFIDENTIALITY);
- CHECK_ATTRIBUTE(REPLAY_DETECT);
- CHECK_ATTRIBUTE(SEQUENCE_DETECT);
- CHECK_ATTRIBUTE(STREAM);
- if (verifyMode == QSslSocket::PeerVerifyMode::VerifyPeer)
- CHECK_ATTRIBUTE(MUTUAL_AUTH);
-
- // This one is manual because there is no server / ASC_ version
- if (isClient) {
- const auto reqManualCredValidation = ISC_REQ_MANUAL_CRED_VALIDATION;
- const auto retManualCredValidation = ISC_RET_MANUAL_CRED_VALIDATION;
- if (!(requirements & reqManualCredValidation) != !(attributes & retManualCredValidation)) {
- DEBUG_WARN("Missing attribute \"MANUAL_CRED_VALIDATION\"");
- return false;
- }
- }
-
- return true;
-#undef CHECK_ATTRIBUTE
-#undef DEBUG_WARN
-}
-
-template<typename Required, typename Actual>
-Required const_reinterpret_cast(Actual *p)
-{
- return Required(p);
-}
-
-#ifdef SUPPORTS_ALPN
-bool supportsAlpn()
-{
- return QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows8_1;
-}
-
-QByteArray createAlpnString(const QByteArrayList &nextAllowedProtocols)
-{
- QByteArray alpnString;
- if (!nextAllowedProtocols.isEmpty() && supportsAlpn()) {
- const QByteArray names = [&nextAllowedProtocols]() {
- QByteArray protocolString;
- for (QByteArray proto : nextAllowedProtocols) {
- if (proto.size() > 255) {
- qCWarning(lcSsl) << "TLS ALPN extension" << proto
- << "is too long and will be ignored.";
- continue;
- } else if (proto.isEmpty()) {
- continue;
- }
- protocolString += char(proto.length()) + proto;
- }
- return protocolString;
- }();
- if (names.isEmpty())
- return alpnString;
-
- const quint16 namesSize = names.size();
- const quint32 alpnId = SecApplicationProtocolNegotiationExt_ALPN;
- const quint32 totalSize = sizeof(alpnId) + sizeof(namesSize) + namesSize;
- alpnString = QByteArray::fromRawData(reinterpret_cast<const char *>(&totalSize), sizeof(totalSize))
- + QByteArray::fromRawData(reinterpret_cast<const char *>(&alpnId), sizeof(alpnId))
- + QByteArray::fromRawData(reinterpret_cast<const char *>(&namesSize), sizeof(namesSize))
- + names;
- }
- return alpnString;
-}
-#endif // SUPPORTS_ALPN
-
-qint64 readToBuffer(QByteArray &buffer, QTcpSocket *plainSocket)
-{
- Q_ASSERT(plainSocket);
- static const qint64 shrinkCutoff = 1024 * 12;
- static const qint64 defaultRead = 1024 * 16;
- qint64 bytesRead = 0;
-
- const auto toRead = std::min(defaultRead, plainSocket->bytesAvailable());
- if (toRead > 0) {
- const auto bufferSize = buffer.size();
- buffer.reserve(bufferSize + toRead); // avoid growth strategy kicking in
- buffer.resize(bufferSize + toRead);
- bytesRead = plainSocket->read(buffer.data() + bufferSize, toRead);
- buffer.resize(bufferSize + bytesRead);
- // In case of excessive memory usage we shrink:
- if (buffer.size() < shrinkCutoff && buffer.capacity() > defaultRead)
- buffer.shrink_to_fit();
- }
-
- return bytesRead;
-}
-
-void retainExtraData(QByteArray &buffer, const SecBuffer &secBuffer)
-{
- Q_ASSERT(secBuffer.BufferType == SECBUFFER_EXTRA);
- if (int(secBuffer.cbBuffer) >= buffer.size())
- return;
-
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl, "We got SECBUFFER_EXTRA, will retain %lu bytes", secBuffer.cbBuffer);
-#endif
- std::move(buffer.end() - secBuffer.cbBuffer, buffer.end(), buffer.begin());
- buffer.resize(secBuffer.cbBuffer);
-}
-
-qint64 checkIncompleteData(const SecBuffer &secBuffer)
-{
- if (secBuffer.BufferType == SECBUFFER_MISSING) {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl, "Need %lu more bytes.", secBuffer.cbBuffer);
-#endif
- return secBuffer.cbBuffer;
-}
- return 0;
-}
-
-} // anonymous namespace
-
-bool QSslSocketPrivate::s_loadRootCertsOnDemand = true;
-bool QSslSocketPrivate::s_loadedCiphersAndCerts = false;
-Q_GLOBAL_STATIC(QRecursiveMutex, qt_schannel_mutex)
-
-void QSslSocketPrivate::ensureInitialized()
-{
- const QMutexLocker locker(qt_schannel_mutex);
- if (s_loadedCiphersAndCerts)
- return;
- s_loadedCiphersAndCerts = true;
-
- setDefaultCaCertificates(systemCaCertificates());
- s_loadRootCertsOnDemand = true; // setDefaultCaCertificates sets it to false, re-enable it.
-
- resetDefaultCiphers();
-}
-
-void QSslSocketPrivate::resetDefaultCiphers()
-{
- setDefaultSupportedCiphers(QSslSocketBackendPrivate::defaultCiphers());
- setDefaultCiphers(QSslSocketBackendPrivate::defaultCiphers());
-}
-
-void QSslSocketPrivate::resetDefaultEllipticCurves()
-{
- Q_UNIMPLEMENTED();
-}
-
-bool QSslSocketPrivate::supportsSsl()
-{
- return true;
-}
-
-QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
-{
- // Copied from qsslsocket_openssl.cpp's systemCaCertificates function.
- QList<QSslCertificate> systemCerts;
- auto hSystemStore = QHCertStorePointer(CertOpenSystemStore(0, L"ROOT"));
- if (hSystemStore) {
- PCCERT_CONTEXT pc = nullptr;
- while ((pc = CertFindCertificateInStore(hSystemStore.get(), X509_ASN_ENCODING, 0,
- CERT_FIND_ANY, nullptr, pc))) {
- systemCerts.append(QSslCertificatePrivate::QSslCertificate_from_CERT_CONTEXT(pc));
- }
- }
- return systemCerts;
-}
-
-long QSslSocketPrivate::sslLibraryVersionNumber()
-{
- const auto os = QOperatingSystemVersion::current();
- return (os.majorVersion() << 24) | ((os.minorVersion() & 0xFF) << 16) | (os.microVersion() & 0xFFFF);
-}
-
-QString QSslSocketPrivate::sslLibraryVersionString()
-{
- const auto os = QOperatingSystemVersion::current();
- return QString::fromLatin1("Secure Channel, %1 %2.%3.%4")
- .arg(os.name(),
- QString::number(os.majorVersion()),
- QString::number(os.minorVersion()),
- QString::number(os.microVersion()));
-}
-
-long QSslSocketPrivate::sslLibraryBuildVersionNumber()
-{
- // There is no separate build version
- return sslLibraryVersionNumber();
-}
-
-QString QSslSocketPrivate::sslLibraryBuildVersionString()
-{
- const auto os = QOperatingSystemVersion::current();
- return QString::fromLatin1("%1.%2.%3")
- .arg(QString::number(os.majorVersion()),
- QString::number(os.minorVersion()),
- QString::number(os.microVersion()));
-}
-
-QSslSocketBackendPrivate::QSslSocketBackendPrivate()
-{
- SecInvalidateHandle(&credentialHandle);
- SecInvalidateHandle(&contextHandle);
- ensureInitialized();
-}
-
-QSslSocketBackendPrivate::~QSslSocketBackendPrivate()
-{
- closeCertificateStores();
- deallocateContext();
- freeCredentialsHandle();
- CertFreeCertificateContext(localCertContext);
-}
-
-bool QSslSocketBackendPrivate::sendToken(void *token, unsigned long tokenLength, bool emitError)
-{
- if (tokenLength == 0)
- return true;
- const qint64 written = plainSocket->write(static_cast<const char *>(token), tokenLength);
- if (written != qint64(tokenLength)) {
- // Failed to write/buffer everything or an error occurred
- if (emitError)
- setErrorAndEmit(plainSocket->error(), plainSocket->errorString());
- return false;
- }
- return true;
-}
-
-QString QSslSocketBackendPrivate::targetName() const
-{
- // Used for SNI extension
- return verificationPeerName.isEmpty() ? q_func()->peerName() : verificationPeerName;
-}
-
-ULONG QSslSocketBackendPrivate::getContextRequirements()
-{
- const bool isClient = mode == QSslSocket::SslClientMode;
- ULONG req = 0;
-
- req |= ISC_REQ_ALLOCATE_MEMORY; // Allocate memory for buffers automatically
- req |= ISC_REQ_CONFIDENTIALITY; // Encrypt messages
- req |= ISC_REQ_REPLAY_DETECT; // Detect replayed messages
- req |= ISC_REQ_SEQUENCE_DETECT; // Detect out of sequence messages
- req |= ISC_REQ_STREAM; // Support a stream-oriented connection
-
- if (isClient) {
- req |= ISC_REQ_MANUAL_CRED_VALIDATION; // Manually validate certificate
- } else {
- switch (configuration.peerVerifyMode) {
- case QSslSocket::PeerVerifyMode::VerifyNone:
- // There doesn't seem to be a way to ask for an optional client cert :-(
- case QSslSocket::PeerVerifyMode::AutoVerifyPeer:
- case QSslSocket::PeerVerifyMode::QueryPeer:
- break;
- case QSslSocket::PeerVerifyMode::VerifyPeer:
- req |= ISC_REQ_MUTUAL_AUTH;
- break;
- }
- }
-
- return req;
-}
-
-bool QSslSocketBackendPrivate::acquireCredentialsHandle()
-{
- Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
-
- const bool isClient = mode == QSslSocket::SslClientMode;
- const DWORD protocols = toSchannelProtocol(configuration.protocol);
- if (protocols == DWORD(-1)) {
- setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError,
- QSslSocket::tr("Invalid protocol chosen"));
- return false;
- }
-
- const CERT_CHAIN_CONTEXT *chainContext = nullptr;
- auto freeCertChain = qScopeGuard([&chainContext]() {
- if (chainContext)
- CertFreeCertificateChain(chainContext);
- });
-
- DWORD certsCount = 0;
- // Set up our certificate stores before trying to use one...
- initializeCertificateStores();
-
- // Check if user has specified a certificate chain but it could not be loaded.
- // This happens if there was something wrong with the certificate chain or there was no private
- // key.
- if (!configuration.localCertificateChain.isEmpty() && !localCertificateStore)
- return true; // 'true' because "tst_QSslSocket::setEmptyKey" expects us to not disconnect
-
- if (localCertificateStore != nullptr) {
- CERT_CHAIN_FIND_BY_ISSUER_PARA findParam;
- ZeroMemory(&findParam, sizeof(findParam));
- findParam.cbSize = sizeof(findParam);
- findParam.pszUsageIdentifier = isClient ? szOID_PKIX_KP_CLIENT_AUTH : szOID_PKIX_KP_SERVER_AUTH;
-
- // There should only be one chain in our store, so.. we grab that one.
- chainContext = CertFindChainInStore(localCertificateStore.get(),
- X509_ASN_ENCODING,
- 0,
- CERT_CHAIN_FIND_BY_ISSUER,
- &findParam,
- nullptr);
- if (!chainContext) {
- const QString message = isClient
- ? QSslSocket::tr("The certificate provided cannot be used for a client.")
- : QSslSocket::tr("The certificate provided cannot be used for a server.");
- setErrorAndEmit(QAbstractSocket::SocketError::SslInvalidUserDataError, message);
- return false;
- }
- Q_ASSERT(chainContext->cChain == 1);
- Q_ASSERT(chainContext->rgpChain[0]);
- Q_ASSERT(chainContext->rgpChain[0]->cbSize >= 1);
- Q_ASSERT(chainContext->rgpChain[0]->rgpElement[0]);
- Q_ASSERT(!localCertContext);
- localCertContext = CertDuplicateCertificateContext(chainContext->rgpChain[0]
- ->rgpElement[0]
- ->pCertContext);
- certsCount = 1;
- Q_ASSERT(localCertContext);
- }
-
- SCHANNEL_CRED cred{
- SCHANNEL_CRED_VERSION, // dwVersion
- certsCount, // cCreds
- &localCertContext, // paCred (certificate(s) containing a private key for authentication)
- nullptr, // hRootStore
-
- 0, // cMappers (reserved)
- nullptr, // aphMappers (reserved)
-
- 0, // cSupportedAlgs
- nullptr, // palgSupportedAlgs (nullptr = system default) @future: QSslCipher-related
-
- protocols, // grbitEnabledProtocols
- 0, // dwMinimumCipherStrength (0 = system default)
- 0, // dwMaximumCipherStrength (0 = system default)
- 0, // dwSessionLifespan (0 = schannel default, 10 hours)
- SCH_CRED_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT
- | SCH_CRED_NO_DEFAULT_CREDS, // dwFlags
- 0 // dwCredFormat (must be 0)
- };
-
- TimeStamp expiration{};
- auto status = AcquireCredentialsHandle(nullptr, // pszPrincipal (unused)
- const_cast<wchar_t *>(UNISP_NAME), // pszPackage
- isClient ? SECPKG_CRED_OUTBOUND : SECPKG_CRED_INBOUND, // fCredentialUse
- nullptr, // pvLogonID (unused)
- &cred, // pAuthData
- nullptr, // pGetKeyFn (unused)
- nullptr, // pvGetKeyArgument (unused)
- &credentialHandle, // phCredential
- &expiration // ptsExpir
- );
-
- if (status != SEC_E_OK) {
- setErrorAndEmit(QAbstractSocket::SslInternalError, schannelErrorToString(status));
- return false;
- }
- return true;
-}
-
-void QSslSocketBackendPrivate::deallocateContext()
-{
- if (SecIsValidHandle(&contextHandle)) {
- DeleteSecurityContext(&contextHandle);
- SecInvalidateHandle(&contextHandle);
- }
-}
-
-void QSslSocketBackendPrivate::freeCredentialsHandle()
-{
- if (SecIsValidHandle(&credentialHandle)) {
- FreeCredentialsHandle(&credentialHandle);
- SecInvalidateHandle(&credentialHandle);
- }
-}
-
-void QSslSocketBackendPrivate::closeCertificateStores()
-{
- localCertificateStore.reset();
- peerCertificateStore.reset();
- caCertificateStore.reset();
-}
-
-bool QSslSocketBackendPrivate::createContext()
-{
- Q_ASSERT(SecIsValidHandle(&credentialHandle));
- Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
- Q_ASSERT(mode == QSslSocket::SslClientMode);
- ULONG contextReq = getContextRequirements();
-
- SecBuffer outBuffers[3];
- outBuffers[0] = createSecBuffer(nullptr, 0, SECBUFFER_TOKEN);
- outBuffers[1] = createSecBuffer(nullptr, 0, SECBUFFER_ALERT);
- outBuffers[2] = createSecBuffer(nullptr, 0, SECBUFFER_EMPTY);
- auto freeBuffers = qScopeGuard([&outBuffers]() {
- for (auto i = 0ull; i < ARRAYSIZE(outBuffers); i++) {
- if (outBuffers[i].pvBuffer)
- FreeContextBuffer(outBuffers[i].pvBuffer);
- }
- });
- SecBufferDesc outputBufferDesc{
- SECBUFFER_VERSION,
- ARRAYSIZE(outBuffers),
- outBuffers
- };
-
- TimeStamp expiry;
-
- SecBufferDesc alpnBufferDesc;
- bool useAlpn = false;
-#ifdef SUPPORTS_ALPN
- configuration.nextProtocolNegotiationStatus = QSslConfiguration::NextProtocolNegotiationNone;
- QByteArray alpnString = createAlpnString(configuration.nextAllowedProtocols);
- useAlpn = !alpnString.isEmpty();
- SecBuffer alpnBuffers[1];
- alpnBuffers[0] = createSecBuffer(alpnString, SECBUFFER_APPLICATION_PROTOCOLS);
- alpnBufferDesc = {
- SECBUFFER_VERSION,
- ARRAYSIZE(alpnBuffers),
- alpnBuffers
- };
-#endif
-
- auto status = InitializeSecurityContext(&credentialHandle, // phCredential
- nullptr, // phContext
- const_reinterpret_cast<SEC_WCHAR *>(targetName().utf16()), // pszTargetName
- contextReq, // fContextReq
- 0, // Reserved1
- 0, // TargetDataRep (unused)
- useAlpn ? &alpnBufferDesc : nullptr, // pInput
- 0, // Reserved2
- &contextHandle, // phNewContext
- &outputBufferDesc, // pOutput
- &contextAttributes, // pfContextAttr
- &expiry // ptsExpiry
- );
-
- // This is the first call to InitializeSecurityContext, so theoretically "CONTINUE_NEEDED"
- // should be the only non-error return-code here.
- if (status != SEC_I_CONTINUE_NEEDED) {
- setErrorAndEmit(QAbstractSocket::SslInternalError,
- QSslSocket::tr("Error creating SSL context (%1)").arg(schannelErrorToString(status)));
- return false;
- }
-
- if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
- return false;
- schannelState = SchannelState::PerformHandshake;
- return true;
-}
-
-bool QSslSocketBackendPrivate::acceptContext()
-{
- Q_ASSERT(SecIsValidHandle(&credentialHandle));
- Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
- Q_ASSERT(mode == QSslSocket::SslServerMode);
- ULONG contextReq = getContextRequirements();
-
- if (missingData > plainSocket->bytesAvailable())
- return true;
-
- missingData = 0;
- readToBuffer(intermediateBuffer, plainSocket);
- if (intermediateBuffer.isEmpty())
- return true; // definitely need more data..
-
- SecBuffer inBuffers[2];
- inBuffers[0] = createSecBuffer(intermediateBuffer, SECBUFFER_TOKEN);
-
-#ifdef SUPPORTS_ALPN
- configuration.nextProtocolNegotiationStatus = QSslConfiguration::NextProtocolNegotiationNone;
- // The string must be alive when we call AcceptSecurityContext
- QByteArray alpnString = createAlpnString(configuration.nextAllowedProtocols);
- if (!alpnString.isEmpty()) {
- inBuffers[1] = createSecBuffer(alpnString, SECBUFFER_APPLICATION_PROTOCOLS);
- } else
-#endif
- {
- inBuffers[1] = createSecBuffer(nullptr, 0, SECBUFFER_EMPTY);
- }
-
- SecBufferDesc inputBufferDesc{
- SECBUFFER_VERSION,
- ARRAYSIZE(inBuffers),
- inBuffers
- };
-
- SecBuffer outBuffers[3];
- outBuffers[0] = createSecBuffer(nullptr, 0, SECBUFFER_TOKEN);
- outBuffers[1] = createSecBuffer(nullptr, 0, SECBUFFER_ALERT);
- outBuffers[2] = createSecBuffer(nullptr, 0, SECBUFFER_EMPTY);
- auto freeBuffers = qScopeGuard([&outBuffers]() {
- for (auto i = 0ull; i < ARRAYSIZE(outBuffers); i++) {
- if (outBuffers[i].pvBuffer)
- FreeContextBuffer(outBuffers[i].pvBuffer);
- }
- });
- SecBufferDesc outputBufferDesc{
- SECBUFFER_VERSION,
- ARRAYSIZE(outBuffers),
- outBuffers
- };
-
- TimeStamp expiry;
- auto status = AcceptSecurityContext(
- &credentialHandle, // phCredential
- nullptr, // phContext
- &inputBufferDesc, // pInput
- contextReq, // fContextReq
- 0, // TargetDataRep (unused)
- &contextHandle, // phNewContext
- &outputBufferDesc, // pOutput
- &contextAttributes, // pfContextAttr
- &expiry // ptsTimeStamp
- );
-
- if (status == SEC_E_INCOMPLETE_MESSAGE) {
- // Need more data
- missingData = checkIncompleteData(outBuffers[0]);
- return true;
- }
-
- if (inBuffers[1].BufferType == SECBUFFER_EXTRA) {
- // https://docs.microsoft.com/en-us/windows/desktop/secauthn/extra-buffers-returned-by-schannel
- // inBuffers[1].cbBuffer indicates the amount of bytes _NOT_ processed, the rest need to
- // be stored.
- retainExtraData(intermediateBuffer, inBuffers[1]);
- } else { /* No 'extra' data, message not incomplete */
- intermediateBuffer.resize(0);
- }
-
- if (status != SEC_I_CONTINUE_NEEDED) {
- setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
- QSslSocket::tr("Error creating SSL context (%1)").arg(schannelErrorToString(status)));
- return false;
- }
- if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
- return false;
- schannelState = SchannelState::PerformHandshake;
- return true;
-}
-
-bool QSslSocketBackendPrivate::performHandshake()
-{
- if (plainSocket->state() == QAbstractSocket::UnconnectedState) {
- setErrorAndEmit(QAbstractSocket::RemoteHostClosedError,
- QSslSocket::tr("The TLS/SSL connection has been closed"));
- return false;
- }
- Q_ASSERT(SecIsValidHandle(&credentialHandle));
- Q_ASSERT(SecIsValidHandle(&contextHandle));
- Q_ASSERT(schannelState == SchannelState::PerformHandshake);
-
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl, "Bytes available from socket: %lld", plainSocket->bytesAvailable());
- qCDebug(lcSsl, "intermediateBuffer size: %d", intermediateBuffer.size());
-#endif
-
- if (missingData > plainSocket->bytesAvailable())
- return true;
-
- missingData = 0;
- readToBuffer(intermediateBuffer, plainSocket);
- if (intermediateBuffer.isEmpty())
- return true; // no data, will fail
-
- SecBuffer outBuffers[3] = {};
- const auto freeOutBuffers = [&outBuffers]() {
- for (auto i = 0ull; i < ARRAYSIZE(outBuffers); i++) {
- if (outBuffers[i].pvBuffer)
- FreeContextBuffer(outBuffers[i].pvBuffer);
- }
- };
- const auto outBuffersGuard = qScopeGuard(freeOutBuffers);
- // For this call to InitializeSecurityContext we may need to call it twice.
- // In some cases us not having a certificate isn't actually an error, but just a request.
- // With Schannel, to ignore this warning, we need to call InitializeSecurityContext again
- // when we get SEC_I_INCOMPLETE_CREDENTIALS! As far as I can tell it's not documented anywhere.
- // https://stackoverflow.com/a/47479968/2493610
- SECURITY_STATUS status;
- short attempts = 2;
- do {
- SecBuffer inputBuffers[2];
- inputBuffers[0] = createSecBuffer(intermediateBuffer, SECBUFFER_TOKEN);
- inputBuffers[1] = createSecBuffer(nullptr, 0, SECBUFFER_EMPTY);
- SecBufferDesc inputBufferDesc{
- SECBUFFER_VERSION,
- ARRAYSIZE(inputBuffers),
- inputBuffers
- };
-
- freeOutBuffers(); // free buffers from any previous attempt
- outBuffers[0] = createSecBuffer(nullptr, 0, SECBUFFER_TOKEN);
- outBuffers[1] = createSecBuffer(nullptr, 0, SECBUFFER_ALERT);
- outBuffers[2] = createSecBuffer(nullptr, 0, SECBUFFER_EMPTY);
- SecBufferDesc outputBufferDesc{
- SECBUFFER_VERSION,
- ARRAYSIZE(outBuffers),
- outBuffers
- };
-
- ULONG contextReq = getContextRequirements();
- TimeStamp expiry;
- status = InitializeSecurityContext(
- &credentialHandle, // phCredential
- &contextHandle, // phContext
- const_reinterpret_cast<SEC_WCHAR *>(targetName().utf16()), // pszTargetName
- contextReq, // fContextReq
- 0, // Reserved1
- 0, // TargetDataRep (unused)
- &inputBufferDesc, // pInput
- 0, // Reserved2
- nullptr, // phNewContext (we already have one)
- &outputBufferDesc, // pOutput
- &contextAttributes, // pfContextAttr
- &expiry // ptsExpiry
- );
-
- if (inputBuffers[1].BufferType == SECBUFFER_EXTRA) {
- // https://docs.microsoft.com/en-us/windows/desktop/secauthn/extra-buffers-returned-by-schannel
- // inputBuffers[1].cbBuffer indicates the amount of bytes _NOT_ processed, the rest need
- // to be stored.
- retainExtraData(intermediateBuffer, inputBuffers[1]);
- } else if (status != SEC_E_INCOMPLETE_MESSAGE) {
- // Clear the buffer if we weren't asked for more data
- intermediateBuffer.resize(0);
- }
-
- --attempts;
- } while (status == SEC_I_INCOMPLETE_CREDENTIALS && attempts > 0);
-
- switch (status) {
- case SEC_E_OK:
- // Need to transmit a final token in the handshake if 'cbBuffer' is non-zero.
- if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
- return false;
- schannelState = SchannelState::VerifyHandshake;
- return true;
- case SEC_I_CONTINUE_NEEDED:
- if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
- return false;
- // Must call InitializeSecurityContext again later (done through continueHandshake)
- return true;
- case SEC_I_INCOMPLETE_CREDENTIALS:
- // Schannel takes care of picking certificate to send (other than the one we can specify),
- // so if we get here then that means we don't have a certificate the server accepts.
- setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
- QSslSocket::tr("Server did not accept any certificate we could present."));
- return false;
- case SEC_I_CONTEXT_EXPIRED:
- // "The message sender has finished using the connection and has initiated a shutdown."
- if (outBuffers[0].BufferType == SECBUFFER_TOKEN) {
- if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
- return false;
- }
- if (!shutdown) { // we did not initiate this
- setErrorAndEmit(QAbstractSocket::RemoteHostClosedError,
- QSslSocket::tr("The TLS/SSL connection has been closed"));
- }
- return true;
- case SEC_E_INCOMPLETE_MESSAGE:
- // Simply incomplete, wait for more data
- missingData = checkIncompleteData(outBuffers[0]);
- return true;
- case SEC_E_ALGORITHM_MISMATCH:
- setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
- QSslSocket::tr("Algorithm mismatch"));
- shutdown = true; // skip sending the "Shutdown" alert
- return false;
- }
-
- // Note: We can get here if the connection is using TLS 1.2 and the server certificate uses
- // MD5, which is not allowed in Schannel. This causes an "invalid token" error during handshake.
- // (If you came here investigating an error: md5 is insecure, update your certificate)
- setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
- QSslSocket::tr("Handshake failed: %1").arg(schannelErrorToString(status)));
- return false;
-}
-
-bool QSslSocketBackendPrivate::verifyHandshake()
-{
- Q_Q(QSslSocket);
- sslErrors.clear();
-
- const bool isClient = mode == QSslSocket::SslClientMode;
-#define CHECK_STATUS(status) \
- if (status != SEC_E_OK) { \
- setErrorAndEmit(QAbstractSocket::SslInternalError, \
- QSslSocket::tr("Failed to query the TLS context: %1") \
- .arg(schannelErrorToString(status))); \
- return false; \
- }
-
- // Everything is set up, now make sure there's nothing wrong and query some attributes...
- if (!matchesContextRequirements(contextAttributes, getContextRequirements(),
- configuration.peerVerifyMode, isClient)) {
- setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
- QSslSocket::tr("Did not get the required attributes for the connection."));
- return false;
- }
-
- // Get stream sizes (to know the max size of a message and the size of the header and trailer)
- auto status = QueryContextAttributes(&contextHandle,
- SECPKG_ATTR_STREAM_SIZES,
- &streamSizes);
- CHECK_STATUS(status);
-
- // Get session cipher info
- status = QueryContextAttributes(&contextHandle,
- SECPKG_ATTR_CONNECTION_INFO,
- &connectionInfo);
- CHECK_STATUS(status);
-
-#ifdef SUPPORTS_ALPN
- if (!configuration.nextAllowedProtocols.isEmpty() && supportsAlpn()) {
- SecPkgContext_ApplicationProtocol alpn;
- status = QueryContextAttributes(&contextHandle,
- SECPKG_ATTR_APPLICATION_PROTOCOL,
- &alpn);
- CHECK_STATUS(status);
- if (alpn.ProtoNegoStatus == SecApplicationProtocolNegotiationStatus_Success) {
- QByteArray negotiatedProto = QByteArray((const char *)alpn.ProtocolId,
- alpn.ProtocolIdSize);
- if (!configuration.nextAllowedProtocols.contains(negotiatedProto)) {
- setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
- QSslSocket::tr("Unwanted protocol was negotiated"));
- return false;
- }
- configuration.nextNegotiatedProtocol = negotiatedProto;
- configuration.nextProtocolNegotiationStatus = QSslConfiguration::NextProtocolNegotiationNegotiated;
- } else {
- configuration.nextNegotiatedProtocol = "";
- configuration.nextProtocolNegotiationStatus = QSslConfiguration::NextProtocolNegotiationUnsupported;
- }
- }
-#endif // supports ALPN
-
-#undef CHECK_STATUS
-
- // Verify certificate
- CERT_CONTEXT *certificateContext = nullptr;
- auto freeCertificate = qScopeGuard([&certificateContext]() {
- if (certificateContext)
- CertFreeCertificateContext(certificateContext);
- });
- status = QueryContextAttributes(&contextHandle,
- SECPKG_ATTR_REMOTE_CERT_CONTEXT,
- &certificateContext);
-
- // QueryPeer can (currently) not work in Schannel since Schannel itself doesn't have a way to
- // ask for a certificate and then still be OK if it's not received.
- // To work around this we don't request a certificate at all for QueryPeer.
- // For servers AutoVerifyPeer is supposed to be treated the same as QueryPeer.
- // This means that servers using Schannel will only request client certificate for "VerifyPeer".
- if ((!isClient && configuration.peerVerifyMode == QSslSocket::PeerVerifyMode::VerifyPeer)
- || (isClient && configuration.peerVerifyMode != QSslSocket::PeerVerifyMode::VerifyNone
- && configuration.peerVerifyMode != QSslSocket::PeerVerifyMode::QueryPeer)) {
- if (status != SEC_E_OK) {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << "Couldn't retrieve peer certificate, status:"
- << schannelErrorToString(status);
-#endif
- const QSslError error{ QSslError::NoPeerCertificate };
- sslErrors += error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
- }
-
- // verifyCertContext returns false if the user disconnected while it was checking errors.
- if (certificateContext && !verifyCertContext(certificateContext))
- return false;
-
- if (!checkSslErrors() || state != QAbstractSocket::ConnectedState) {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << __func__ << "was unsuccessful. Paused:" << paused;
-#endif
- // If we're paused then checkSslErrors returned false, but it's not an error
- return paused && state == QAbstractSocket::ConnectedState;
- }
-
- schannelState = SchannelState::Done;
- return true;
-}
-
-bool QSslSocketBackendPrivate::renegotiate()
-{
- SecBuffer outBuffers[3];
- outBuffers[0] = createSecBuffer(nullptr, 0, SECBUFFER_TOKEN);
- outBuffers[1] = createSecBuffer(nullptr, 0, SECBUFFER_ALERT);
- outBuffers[2] = createSecBuffer(nullptr, 0, SECBUFFER_EMPTY);
- auto freeBuffers = qScopeGuard([&outBuffers]() {
- for (auto i = 0ull; i < ARRAYSIZE(outBuffers); i++) {
- if (outBuffers[i].pvBuffer)
- FreeContextBuffer(outBuffers[i].pvBuffer);
- }
- });
- SecBufferDesc outputBufferDesc{
- SECBUFFER_VERSION,
- ARRAYSIZE(outBuffers),
- outBuffers
- };
-
- ULONG contextReq = getContextRequirements();
- TimeStamp expiry;
- SECURITY_STATUS status;
- if (mode == QSslSocket::SslClientMode) {
- status = InitializeSecurityContext(&credentialHandle, // phCredential
- &contextHandle, // phContext
- const_reinterpret_cast<SEC_WCHAR *>(targetName().utf16()), // pszTargetName
- contextReq, // fContextReq
- 0, // Reserved1
- 0, // TargetDataRep (unused)
- nullptr, // pInput (nullptr for renegotiate)
- 0, // Reserved2
- nullptr, // phNewContext (we already have one)
- &outputBufferDesc, // pOutput
- &contextAttributes, // pfContextAttr
- &expiry // ptsExpiry
- );
- } else {
- status = AcceptSecurityContext(
- &credentialHandle, // phCredential
- &contextHandle, // phContext
- nullptr, // pInput
- contextReq, // fContextReq
- 0, // TargetDataRep (unused)
- nullptr, // phNewContext
- &outputBufferDesc, // pOutput
- &contextAttributes, // pfContextAttr,
- &expiry // ptsTimeStamp
- );
- }
- if (status == SEC_I_CONTINUE_NEEDED) {
- schannelState = SchannelState::PerformHandshake;
- return sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer);
- }
- setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
- QSslSocket::tr("Renegotiation was unsuccessful: %1").arg(schannelErrorToString(status)));
- return false;
-}
-
-/*!
- \internal
- reset the state in preparation for reuse of socket
-*/
-void QSslSocketBackendPrivate::reset()
-{
- closeCertificateStores(); // certificate stores could've changed
- deallocateContext();
- freeCredentialsHandle(); // in case we already had one (@future: session resumption requires re-use)
-
- connectionInfo = {};
- streamSizes = {};
-
- CertFreeCertificateContext(localCertContext);
- localCertContext = nullptr;
-
- contextAttributes = 0;
- intermediateBuffer.clear();
- schannelState = SchannelState::InitializeHandshake;
-
- connectionEncrypted = false;
- shutdown = false;
- renegotiating = false;
-
- missingData = 0;
-}
-
-void QSslSocketBackendPrivate::startClientEncryption()
-{
- if (connectionEncrypted)
- return; // let's not mess up the connection...
- reset();
- continueHandshake();
-}
-
-void QSslSocketBackendPrivate::startServerEncryption()
-{
- if (connectionEncrypted)
- return; // let's not mess up the connection...
- reset();
- continueHandshake();
-}
-
-void QSslSocketBackendPrivate::transmit()
-{
- Q_Q(QSslSocket);
-
- // Can happen if called through QSslSocket::abort->QSslSocket::close->QSslSocket::flush->here
- if (plainSocket->state() == QAbstractSocket::SocketState::UnconnectedState)
- return;
-
- if (schannelState != SchannelState::Done) {
- continueHandshake();
- return;
- }
-
- if (connectionEncrypted) { // encrypt data in writeBuffer and write it to plainSocket
- qint64 totalBytesWritten = 0;
- qint64 writeBufferSize;
- while ((writeBufferSize = writeBuffer.size()) > 0) {
- const int headerSize = int(streamSizes.cbHeader);
- const int trailerSize = int(streamSizes.cbTrailer);
- // Try to read 'cbMaximumMessage' bytes from buffer before encrypting.
- const int size = int(std::min(writeBufferSize, qint64(streamSizes.cbMaximumMessage)));
- QByteArray fullMessage(headerSize + trailerSize + size, Qt::Uninitialized);
- {
- // Use peek() here instead of read() so we don't lose data if encryption fails.
- qint64 copied = writeBuffer.peek(fullMessage.data() + headerSize, size);
- Q_ASSERT(copied == size);
- }
-
- SecBuffer inputBuffers[4]{
- createSecBuffer(fullMessage.data(), headerSize, SECBUFFER_STREAM_HEADER),
- createSecBuffer(fullMessage.data() + headerSize, size, SECBUFFER_DATA),
- createSecBuffer(fullMessage.data() + headerSize + size, trailerSize, SECBUFFER_STREAM_TRAILER),
- createSecBuffer(nullptr, 0, SECBUFFER_EMPTY)
- };
- SecBufferDesc message{
- SECBUFFER_VERSION,
- ARRAYSIZE(inputBuffers),
- inputBuffers
- };
- auto status = EncryptMessage(&contextHandle, 0, &message, 0);
- if (status != SEC_E_OK) {
- setErrorAndEmit(QAbstractSocket::SslInternalError,
- QSslSocket::tr("Schannel failed to encrypt data: %1")
- .arg(schannelErrorToString(status)));
- return;
- }
- // Data was encrypted successfully, so we free() what we peek()ed earlier
- writeBuffer.free(size);
-
- // The trailer's size is not final, so resize fullMessage to not send trailing junk
- fullMessage.resize(inputBuffers[0].cbBuffer + inputBuffers[1].cbBuffer + inputBuffers[2].cbBuffer);
- const qint64 bytesWritten = plainSocket->write(fullMessage);
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl, "Wrote %lld of total %d bytes", bytesWritten, fullMessage.length());
-#endif
- if (bytesWritten >= 0) {
- totalBytesWritten += bytesWritten;
- } else {
- setErrorAndEmit(plainSocket->error(), plainSocket->errorString());
- return;
- }
- }
-
- if (totalBytesWritten > 0) {
- // Don't emit bytesWritten() recursively.
- if (!emittedBytesWritten) {
- emittedBytesWritten = true;
- emit q->bytesWritten(totalBytesWritten);
- emittedBytesWritten = false;
- }
- emit q->channelBytesWritten(0, totalBytesWritten);
- }
- }
-
- if (connectionEncrypted) { // Decrypt data from remote
- int totalRead = 0;
- bool hadIncompleteData = false;
- while (!readBufferMaxSize || buffer.size() < readBufferMaxSize) {
- if (missingData > plainSocket->bytesAvailable()
- && (!readBufferMaxSize || readBufferMaxSize >= missingData)) {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl, "We're still missing %lld bytes, will check later.", missingData);
-#endif
- break;
- }
-
- missingData = 0;
- const qint64 bytesRead = readToBuffer(intermediateBuffer, plainSocket);
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl, "Read %lld encrypted bytes from the socket", bytesRead);
-#endif
- if (intermediateBuffer.length() == 0 || (hadIncompleteData && bytesRead == 0)) {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl, (hadIncompleteData ? "No new data received, leaving loop!"
- : "Nothing to decrypt, leaving loop!"));
-#endif
- break;
- }
- hadIncompleteData = false;
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl, "Total amount of bytes to decrypt: %d", intermediateBuffer.length());
-#endif
-
- SecBuffer dataBuffer[4]{
- createSecBuffer(intermediateBuffer, SECBUFFER_DATA),
- createSecBuffer(nullptr, 0, SECBUFFER_EMPTY),
- createSecBuffer(nullptr, 0, SECBUFFER_EMPTY),
- createSecBuffer(nullptr, 0, SECBUFFER_EMPTY)
- };
- SecBufferDesc message{
- SECBUFFER_VERSION,
- ARRAYSIZE(dataBuffer),
- dataBuffer
- };
- auto status = DecryptMessage(&contextHandle, &message, 0, nullptr);
- if (status == SEC_E_OK || status == SEC_I_RENEGOTIATE || status == SEC_I_CONTEXT_EXPIRED) {
- // There can still be 0 output even if it succeeds, this is fine
- if (dataBuffer[1].cbBuffer > 0) {
- // It is always decrypted in-place.
- // But [0] is the STREAM_HEADER, [1] is the DATA and [2] is the STREAM_TRAILER.
- // The pointers in all of those still point into 'intermediateBuffer'.
- buffer.append(static_cast<char *>(dataBuffer[1].pvBuffer),
- dataBuffer[1].cbBuffer);
- totalRead += dataBuffer[1].cbBuffer;
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl, "Decrypted %lu bytes. New read buffer size: %d",
- dataBuffer[1].cbBuffer, buffer.size());
-#endif
- }
- if (dataBuffer[3].BufferType == SECBUFFER_EXTRA) {
- // https://docs.microsoft.com/en-us/windows/desktop/secauthn/extra-buffers-returned-by-schannel
- // dataBuffer[3].cbBuffer indicates the amount of bytes _NOT_ processed,
- // the rest need to be stored.
- retainExtraData(intermediateBuffer, dataBuffer[3]);
- } else {
- intermediateBuffer.resize(0);
- }
- }
-
- if (status == SEC_E_INCOMPLETE_MESSAGE) {
- missingData = checkIncompleteData(dataBuffer[0]);
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl, "We didn't have enough data to decrypt anything, will try again!");
-#endif
- // We try again, but if we don't get any more data then we leave
- hadIncompleteData = true;
- } else if (status == SEC_E_INVALID_HANDLE) {
- // I don't think this should happen, if it does we're done...
- qCWarning(lcSsl, "The internal SSPI handle is invalid!");
- Q_UNREACHABLE();
- } else if (status == SEC_E_INVALID_TOKEN) {
- qCWarning(lcSsl, "Got SEC_E_INVALID_TOKEN!");
- Q_UNREACHABLE(); // Happened once due to a bug, but shouldn't generally happen(?)
- } else if (status == SEC_E_MESSAGE_ALTERED) {
- // The message has been altered, disconnect now.
- shutdown = true; // skips sending the shutdown alert
- disconnectFromHost();
- setErrorAndEmit(QAbstractSocket::SslInternalError,
- schannelErrorToString(status));
- break;
- } else if (status == SEC_E_OUT_OF_SEQUENCE) {
- // @todo: I don't know if this one is actually "fatal"..
- // This path might never be hit as it seems this is for connection-oriented connections,
- // while SEC_E_MESSAGE_ALTERED is for stream-oriented ones (what we use).
- shutdown = true; // skips sending the shutdown alert
- disconnectFromHost();
- setErrorAndEmit(QAbstractSocket::SslInternalError,
- schannelErrorToString(status));
- break;
- } else if (status == SEC_I_CONTEXT_EXPIRED) {
- // 'remote' has initiated a shutdown
- disconnectFromHost();
- setErrorAndEmit(QAbstractSocket::RemoteHostClosedError,
- schannelErrorToString(status));
- break;
- } else if (status == SEC_I_RENEGOTIATE) {
- // 'remote' wants to renegotiate
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl, "The peer wants to renegotiate.");
-#endif
- schannelState = SchannelState::Renegotiate;
- renegotiating = true;
-
- // We need to call 'continueHandshake' or else there's no guarantee it ever gets called
- continueHandshake();
- break;
- }
- }
-
- if (totalRead) {
- if (readyReadEmittedPointer)
- *readyReadEmittedPointer = true;
- emit q->readyRead();
- emit q->channelReadyRead(0);
- }
- }
-}
-
-void QSslSocketBackendPrivate::sendShutdown()
-{
- const bool isClient = mode == QSslSocket::SslClientMode;
- DWORD shutdownToken = SCHANNEL_SHUTDOWN;
- SecBuffer buffer = createSecBuffer(&shutdownToken, sizeof(SCHANNEL_SHUTDOWN), SECBUFFER_TOKEN);
- SecBufferDesc token{
- SECBUFFER_VERSION,
- 1,
- &buffer
- };
- auto status = ApplyControlToken(&contextHandle, &token);
-
- if (status != SEC_E_OK) {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << "Failed to apply shutdown control token:" << schannelErrorToString(status);
-#endif
- return;
- }
-
- SecBuffer outBuffers[3];
- outBuffers[0] = createSecBuffer(nullptr, 0, SECBUFFER_TOKEN);
- outBuffers[1] = createSecBuffer(nullptr, 0, SECBUFFER_ALERT);
- outBuffers[2] = createSecBuffer(nullptr, 0, SECBUFFER_EMPTY);
- auto freeBuffers = qScopeGuard([&outBuffers]() {
- for (auto i = 0ull; i < ARRAYSIZE(outBuffers); i++) {
- if (outBuffers[i].pvBuffer)
- FreeContextBuffer(outBuffers[i].pvBuffer);
- }
- });
- SecBufferDesc outputBufferDesc{
- SECBUFFER_VERSION,
- ARRAYSIZE(outBuffers),
- outBuffers
- };
-
- ULONG contextReq = getContextRequirements();
- TimeStamp expiry;
- if (isClient) {
- status = InitializeSecurityContext(&credentialHandle, // phCredential
- &contextHandle, // phContext
- const_reinterpret_cast<SEC_WCHAR *>(targetName().utf16()), // pszTargetName
- contextReq, // fContextReq
- 0, // Reserved1
- 0, // TargetDataRep (unused)
- nullptr, // pInput
- 0, // Reserved2
- nullptr, // phNewContext (we already have one)
- &outputBufferDesc, // pOutput
- &contextAttributes, // pfContextAttr
- &expiry // ptsExpiry
- );
- } else {
- status = AcceptSecurityContext(
- &credentialHandle, // phCredential
- &contextHandle, // phContext
- nullptr, // pInput
- contextReq, // fContextReq
- 0, // TargetDataRep (unused)
- nullptr, // phNewContext
- &outputBufferDesc, // pOutput
- &contextAttributes, // pfContextAttr,
- &expiry // ptsTimeStamp
- );
- }
- if (status == SEC_E_OK || status == SEC_I_CONTEXT_EXPIRED) {
- if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, false)) {
- // We failed to send the shutdown message, but it's not that important since we're
- // shutting down anyway.
- return;
- }
- } else {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << "Failed to initialize shutdown:" << schannelErrorToString(status);
-#endif
- }
-}
-
-void QSslSocketBackendPrivate::disconnectFromHost()
-{
- if (SecIsValidHandle(&contextHandle)) {
- if (!shutdown) {
- shutdown = true;
- if (plainSocket->state() != QAbstractSocket::UnconnectedState) {
- if (connectionEncrypted) {
- // Read as much as possible because this is likely our last chance
- qint64 tempMax = readBufferMaxSize;
- readBufferMaxSize = 0;
- transmit();
- readBufferMaxSize = tempMax;
- sendShutdown();
- }
- }
- }
- }
- if (plainSocket->state() != QAbstractSocket::UnconnectedState)
- plainSocket->disconnectFromHost();
-}
-
-void QSslSocketBackendPrivate::disconnected()
-{
- shutdown = true;
- connectionEncrypted = false;
- deallocateContext();
- freeCredentialsHandle();
-}
-
-QSslCipher QSslSocketBackendPrivate::sessionCipher() const
-{
- if (!connectionEncrypted)
- return QSslCipher();
- return QSslCipher(QStringLiteral("Schannel"), sessionProtocol());
-}
-
-QSsl::SslProtocol QSslSocketBackendPrivate::sessionProtocol() const
-{
- if (!connectionEncrypted)
- return QSsl::SslProtocol::UnknownProtocol;
- return toQtSslProtocol(connectionInfo.dwProtocol);
-}
-
-void QSslSocketBackendPrivate::continueHandshake()
-{
- Q_Q(QSslSocket);
- const bool isServer = mode == QSslSocket::SslServerMode;
- switch (schannelState) {
- case SchannelState::InitializeHandshake:
- if (!SecIsValidHandle(&credentialHandle) && !acquireCredentialsHandle()) {
- disconnectFromHost();
- return;
- }
- if (!SecIsValidHandle(&credentialHandle)) // Needed to support tst_QSslSocket::setEmptyKey
- return;
- if (!SecIsValidHandle(&contextHandle) && !(isServer ? acceptContext() : createContext())) {
- disconnectFromHost();
- return;
- }
- if (schannelState != SchannelState::PerformHandshake)
- break;
- Q_FALLTHROUGH();
- case SchannelState::PerformHandshake:
- if (!performHandshake()) {
- disconnectFromHost();
- return;
- }
- if (schannelState != SchannelState::VerifyHandshake)
- break;
- Q_FALLTHROUGH();
- case SchannelState::VerifyHandshake:
- // if we're in shutdown or renegotiating then we might not need to verify
- // (since we already did)
- if (!verifyHandshake()) {
- shutdown = true; // Skip sending shutdown alert
- q->abort(); // We don't want to send buffered data
- disconnectFromHost();
- return;
- }
- if (schannelState != SchannelState::Done)
- break;
- Q_FALLTHROUGH();
- case SchannelState::Done:
- // connectionEncrypted is already true if we come here from a renegotiation
- if (!connectionEncrypted) {
- connectionEncrypted = true; // all is done
- emit q->encrypted();
- }
- renegotiating = false;
- if (pendingClose) {
- pendingClose = false;
- disconnectFromHost();
- } else {
- transmit();
- }
- break;
- case SchannelState::Renegotiate:
- if (!renegotiate()) {
- disconnectFromHost();
- return;
- }
- break;
- }
-}
-
-QList<QSslCipher> QSslSocketBackendPrivate::defaultCiphers()
-{
- QList<QSslCipher> ciphers;
- // @temp (I hope), stolen from qsslsocket_winrt.cpp
- const QString protocolStrings[] = { QStringLiteral("TLSv1"), QStringLiteral("TLSv1.1"),
- QStringLiteral("TLSv1.2"), QStringLiteral("TLSv1.3") };
- const QSsl::SslProtocol protocols[] = { QSsl::TlsV1_0, QSsl::TlsV1_1,
- QSsl::TlsV1_2, QSsl::TlsV1_3 };
- const int size = ARRAYSIZE(protocols);
- static_assert(size == ARRAYSIZE(protocolStrings));
- ciphers.reserve(size);
- for (int i = 0; i < size; ++i) {
- QSslCipher cipher;
- cipher.d->isNull = false;
- cipher.d->name = QStringLiteral("Schannel");
- cipher.d->protocol = protocols[i];
- cipher.d->protocolString = protocolStrings[i];
- ciphers.append(cipher);
- }
-
- return ciphers;
-}
-
-QList<QSslError> QSslSocketBackendPrivate::verify(const QList<QSslCertificate> &certificateChain,
- const QString &hostName)
-{
- Q_UNUSED(certificateChain);
- Q_UNUSED(hostName);
-
- Q_UNIMPLEMENTED();
- return {}; // @future implement(?)
-}
-
-bool QSslSocketBackendPrivate::importPkcs12(QIODevice *device, QSslKey *key, QSslCertificate *cert,
- QList<QSslCertificate> *caCertificates,
- const QByteArray &passPhrase)
-{
- Q_UNUSED(device);
- Q_UNUSED(key);
- Q_UNUSED(cert);
- Q_UNUSED(caCertificates);
- Q_UNUSED(passPhrase);
- // @future: can load into its own certificate store (encountered problems extracting key).
- Q_UNIMPLEMENTED();
- return false;
-}
-
-/*
- Copied from qsslsocket_mac.cpp, which was copied from qsslsocket_openssl.cpp
-*/
-bool QSslSocketBackendPrivate::checkSslErrors()
-{
- if (sslErrors.isEmpty())
- return true;
- Q_Q(QSslSocket);
-
- emit q->sslErrors(sslErrors);
-
- const bool doVerifyPeer = configuration.peerVerifyMode == QSslSocket::VerifyPeer
- || (configuration.peerVerifyMode == QSslSocket::AutoVerifyPeer
- && mode == QSslSocket::SslClientMode);
- const bool doEmitSslError = !verifyErrorsHaveBeenIgnored();
- // check whether we need to emit an SSL handshake error
- if (doVerifyPeer && doEmitSslError) {
- if (q->pauseMode() & QAbstractSocket::PauseOnSslErrors) {
- pauseSocketNotifiers(q);
- paused = true;
- } else {
- setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
- sslErrors.constFirst().errorString());
- plainSocket->disconnectFromHost();
- }
- return false;
- }
-
- return true;
-}
-
-void QSslSocketBackendPrivate::initializeCertificateStores()
-{
- //// helper function which turns a chain into a certificate store
- auto createStoreFromCertificateChain = [](const QList<QSslCertificate> certChain, const QSslKey &privateKey) {
- const wchar_t *passphrase = L"";
- // Need to embed the private key in the certificate
- QByteArray pkcs12 = _q_makePkcs12(certChain,
- privateKey,
- QString::fromWCharArray(passphrase, 0));
- CRYPT_DATA_BLOB pfxBlob;
- pfxBlob.cbData = DWORD(pkcs12.length());
- pfxBlob.pbData = reinterpret_cast<unsigned char *>(pkcs12.data());
- return QHCertStorePointer(PFXImportCertStore(&pfxBlob, passphrase, 0));
- };
-
- if (!configuration.localCertificateChain.isEmpty()) {
- if (configuration.privateKey.isNull()) {
- setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError,
- QSslSocket::tr("Cannot provide a certificate with no key"));
- return;
- }
- if (localCertificateStore == nullptr) {
- localCertificateStore = createStoreFromCertificateChain(configuration.localCertificateChain,
- configuration.privateKey);
- if (localCertificateStore == nullptr)
- qCWarning(lcSsl, "Failed to load certificate chain!");
- }
- }
-
- if (!configuration.caCertificates.isEmpty() && !caCertificateStore) {
- caCertificateStore = createStoreFromCertificateChain(configuration.caCertificates,
- {}); // No private key for the CA certs
- }
-}
-
-bool QSslSocketBackendPrivate::verifyCertContext(CERT_CONTEXT *certContext)
-{
- Q_ASSERT(certContext);
- Q_Q(QSslSocket);
-
- const bool isClient = mode == QSslSocket::SslClientMode;
-
- // Create a collection of stores so we can pass in multiple stores as additional locations to
- // search for the certificate chain
- auto tempCertCollection = QHCertStorePointer(CertOpenStore(CERT_STORE_PROV_COLLECTION,
- X509_ASN_ENCODING,
- 0,
- CERT_STORE_CREATE_NEW_FLAG,
- nullptr));
- if (!tempCertCollection) {
-#ifdef QSSLSOCKET_DEBUG
- qCWarning(lcSsl, "Failed to create certificate store collection!");
-#endif
- return false;
- }
-
- if (rootCertOnDemandLoadingAllowed()) {
- // @future(maybe): following the OpenSSL backend these certificates should be added into
- // the Ca list, not just included during verification.
- // That being said, it's not trivial to add the root certificates (if and only if they
- // came from the system root store). And I don't see this mentioned in our documentation.
- auto rootStore = QHCertStorePointer(CertOpenSystemStore(0, L"ROOT"));
- if (!rootStore) {
-#ifdef QSSLSOCKET_DEBUG
- qCWarning(lcSsl, "Failed to open the system root CA certificate store!");
-#endif
- return false;
- } else if (!CertAddStoreToCollection(tempCertCollection.get(), rootStore.get(), 0, 1)) {
-#ifdef QSSLSOCKET_DEBUG
- qCWarning(lcSsl, "Failed to add the system root CA certificate store to the certificate store collection!");
-#endif
- return false;
- }
- }
- if (caCertificateStore) {
- if (!CertAddStoreToCollection(tempCertCollection.get(), caCertificateStore.get(), 0, 1)) {
-#ifdef QSSLSOCKET_DEBUG
- qCWarning(lcSsl, "Failed to add the user's CA certificate store to the certificate store collection!");
-#endif
- return false;
- }
- }
-
- if (!CertAddStoreToCollection(tempCertCollection.get(), certContext->hCertStore, 0, 0)) {
-#ifdef QSSLSOCKET_DEBUG
- qCWarning(lcSsl, "Failed to add certificate's origin store to the certificate store collection!");
-#endif
- return false;
- }
-
- CERT_CHAIN_PARA parameters;
- ZeroMemory(&parameters, sizeof(parameters));
- parameters.cbSize = sizeof(CERT_CHAIN_PARA);
- parameters.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
- parameters.RequestedUsage.Usage.cUsageIdentifier = 1;
- LPSTR oid = LPSTR(isClient ? szOID_PKIX_KP_SERVER_AUTH
- : szOID_PKIX_KP_CLIENT_AUTH);
- parameters.RequestedUsage.Usage.rgpszUsageIdentifier = &oid;
-
- configuration.peerCertificate.clear();
- configuration.peerCertificateChain.clear();
- const CERT_CHAIN_CONTEXT *chainContext = nullptr;
- auto freeCertChain = qScopeGuard([&chainContext]() {
- if (chainContext)
- CertFreeCertificateChain(chainContext);
- });
- BOOL status = CertGetCertificateChain(nullptr, // hChainEngine, default
- certContext, // pCertContext
- nullptr, // pTime, 'now'
- tempCertCollection.get(), // hAdditionalStore, additional cert store
- &parameters, // pChainPara
- CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT, // dwFlags
- nullptr, // reserved
- &chainContext // ppChainContext
- );
- if (status == FALSE || !chainContext || chainContext->cChain == 0) {
- QSslError error(QSslError::UnableToVerifyFirstCertificate);
- sslErrors += error;
- emit q->peerVerifyError(error);
- return q->state() == QAbstractSocket::ConnectedState;
- }
-
- // Helper-function to get a QSslCertificate given a CERT_CHAIN_ELEMENT
- static auto getCertificateFromChainElement = [](CERT_CHAIN_ELEMENT *element) {
- if (!element)
- return QSslCertificate();
-
- const CERT_CONTEXT *certContext = element->pCertContext;
- return QSslCertificatePrivate::QSslCertificate_from_CERT_CONTEXT(certContext);
- };
-
- // Pick a chain to use as the certificate chain, if multiple are available:
- // According to https://docs.microsoft.com/en-gb/windows/desktop/api/wincrypt/ns-wincrypt-_cert_chain_context
- // this seems to be the best way to get a trusted chain.
- CERT_SIMPLE_CHAIN *chain = chainContext->rgpChain[chainContext->cChain - 1];
-
- if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_PARTIAL_CHAIN) {
- auto error = QSslError(QSslError::SslError::UnableToGetIssuerCertificate,
- getCertificateFromChainElement(chain->rgpElement[chain->cElement - 1]));
- sslErrors += error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
- if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_INVALID_BASIC_CONSTRAINTS) {
- // @Note: This is actually one of two errors:
- // "either the certificate cannot be used to issue other certificates, or the chain path length has been exceeded."
- // But here we are checking the chain's status, so we assume the "issuing" error cannot occur here.
- auto error = QSslError(QSslError::PathLengthExceeded);
- sslErrors += error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
- static const DWORD leftoverCertChainErrorMask = CERT_TRUST_IS_CYCLIC | CERT_TRUST_INVALID_EXTENSION
- | CERT_TRUST_INVALID_POLICY_CONSTRAINTS | CERT_TRUST_INVALID_NAME_CONSTRAINTS
- | CERT_TRUST_CTL_IS_NOT_TIME_VALID | CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID
- | CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE;
- if (chain->TrustStatus.dwErrorStatus & leftoverCertChainErrorMask) {
- auto error = QSslError(QSslError::SslError::UnspecifiedError);
- sslErrors += error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
-
- DWORD verifyDepth = chain->cElement;
- if (configuration.peerVerifyDepth > 0 && DWORD(configuration.peerVerifyDepth) < verifyDepth)
- verifyDepth = DWORD(configuration.peerVerifyDepth);
-
- for (DWORD i = 0; i < verifyDepth; i++) {
- CERT_CHAIN_ELEMENT *element = chain->rgpElement[i];
- QSslCertificate certificate = getCertificateFromChainElement(element);
- const QList<QSslCertificateExtension> extensions = certificate.extensions();
-
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << "issuer:" << certificate.issuerDisplayName()
- << "\nsubject:" << certificate.subjectDisplayName()
- << "\nQSslCertificate info:" << certificate
- << "\nextended error info:" << element->pwszExtendedErrorInfo
- << "\nerror status:" << element->TrustStatus.dwErrorStatus;
-#endif
-
- configuration.peerCertificateChain.append(certificate);
-
- if (certificate.isBlacklisted()) {
- const auto error = QSslError(QSslError::CertificateBlacklisted, certificate);
- sslErrors += error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
-
- LONG result = CertVerifyTimeValidity(nullptr /*== now */, element->pCertContext->pCertInfo);
- if (result != 0) {
- auto error = QSslError(result == -1 ? QSslError::CertificateNotYetValid
- : QSslError::CertificateExpired,
- certificate);
- sslErrors += error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
-
- //// Errors
- if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_TIME_VALID) {
- // handled right above
- Q_ASSERT(!sslErrors.isEmpty());
- }
- if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_REVOKED) {
- auto error = QSslError(QSslError::CertificateRevoked, certificate);
- sslErrors += error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
- if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_SIGNATURE_VALID) {
- auto error = QSslError(QSslError::CertificateSignatureFailed, certificate);
- sslErrors += error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
-
- // While netscape shouldn't be relevant now it defined an extension which is
- // still in use. Schannel does not check this automatically, so we do it here.
- // It is used to differentiate between client and server certificates.
- if (netscapeWrongCertType(extensions, isClient))
- element->TrustStatus.dwErrorStatus |= CERT_TRUST_IS_NOT_VALID_FOR_USAGE;
-
- if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_VALID_FOR_USAGE) {
- auto error = QSslError(QSslError::InvalidPurpose, certificate);
- sslErrors += error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
- if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_UNTRUSTED_ROOT) {
- // Override this error if we have the certificate inside our trusted CAs list.
- const bool isTrustedRoot = configuration.caCertificates.contains(certificate);
- if (!isTrustedRoot) {
- auto error = QSslError(QSslError::CertificateUntrusted, certificate);
- sslErrors += error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
- }
- static const DWORD certRevocationCheckUnavailableError = CERT_TRUST_IS_OFFLINE_REVOCATION
- | CERT_TRUST_REVOCATION_STATUS_UNKNOWN;
- if (element->TrustStatus.dwErrorStatus & certRevocationCheckUnavailableError) {
- // @future(maybe): Do something with this
- }
-
- // Dumping ground of errors that don't fit our specific errors
- static const DWORD leftoverCertErrorMask = CERT_TRUST_IS_CYCLIC
- | CERT_TRUST_INVALID_EXTENSION | CERT_TRUST_INVALID_NAME_CONSTRAINTS
- | CERT_TRUST_INVALID_POLICY_CONSTRAINTS
- | CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT
- | CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT
- | CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT
- | CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT
- | CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT;
- if (element->TrustStatus.dwErrorStatus & leftoverCertErrorMask) {
- auto error = QSslError(QSslError::UnspecifiedError, certificate);
- sslErrors += error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
- if (element->TrustStatus.dwErrorStatus & CERT_TRUST_INVALID_BASIC_CONSTRAINTS) {
- auto it = std::find_if(extensions.cbegin(), extensions.cend(),
- [](const QSslCertificateExtension &extension) {
- return extension.name() == QLatin1String("basicConstraints");
- });
- if (it != extensions.cend()) {
- // @Note: This is actually one of two errors:
- // "either the certificate cannot be used to issue other certificates,
- // or the chain path length has been exceeded."
- QVariantMap basicConstraints = it->value().toMap();
- QSslError error;
- if (i > 0 && !basicConstraints.value(QLatin1String("ca"), false).toBool())
- error = QSslError(QSslError::InvalidPurpose, certificate);
- else
- error = QSslError(QSslError::PathLengthExceeded, certificate);
- sslErrors += error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
- }
- if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_EXPLICIT_DISTRUST) {
- auto error = QSslError(QSslError::CertificateBlacklisted, certificate);
- sslErrors += error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
-
- if (element->TrustStatus.dwInfoStatus & CERT_TRUST_IS_SELF_SIGNED) {
- // If it's self-signed *and* a CA then we can assume it's a root CA certificate
- // and we can ignore the "self-signed" note:
- // We check the basicConstraints certificate extension when possible, but this didn't
- // exist for version 1, so we can only guess in that case
- const bool isRootCertificateAuthority = isCertificateAuthority(extensions)
- || certificate.version() == "1";
-
- // Root certificate tends to be signed by themselves, so ignore self-signed status.
- if (!isRootCertificateAuthority) {
- auto error = QSslError(QSslError::SelfSignedCertificate, certificate);
- sslErrors += error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
- }
- }
-
- if (!configuration.peerCertificateChain.isEmpty())
- configuration.peerCertificate = configuration.peerCertificateChain.first();
-
- // @Note: Somewhat copied from qsslsocket_mac.cpp
- const bool doVerifyPeer = configuration.peerVerifyMode == QSslSocket::VerifyPeer
- || (configuration.peerVerifyMode == QSslSocket::AutoVerifyPeer
- && mode == QSslSocket::SslClientMode);
- // Check the peer certificate itself. First try the subject's common name
- // (CN) as a wildcard, then try all alternate subject name DNS entries the
- // same way.
- if (!configuration.peerCertificate.isNull()) {
- // but only if we're a client connecting to a server
- // if we're the server, don't check CN
- if (mode == QSslSocket::SslClientMode) {
- const QString peerName(verificationPeerName.isEmpty() ? q->peerName() : verificationPeerName);
- if (!isMatchingHostname(configuration.peerCertificate, peerName)) {
- // No matches in common names or alternate names.
- const QSslError error(QSslError::HostNameMismatch, configuration.peerCertificate);
- sslErrors += error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
- }
- } else if (doVerifyPeer) {
- // No peer certificate presented. Report as error if the socket
- // expected one.
- const QSslError error(QSslError::NoPeerCertificate);
- sslErrors += error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
-
- return true;
-}
-
-bool QSslSocketBackendPrivate::rootCertOnDemandLoadingAllowed()
-{
- return allowRootCertOnDemandLoading && s_loadRootCertsOnDemand;
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslsocket_schannel_p.h b/src/network/ssl/qsslsocket_schannel_p.h
deleted file mode 100644
index fe29dadec0..0000000000
--- a/src/network/ssl/qsslsocket_schannel_p.h
+++ /dev/null
@@ -1,145 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QSSLSOCKET_SCHANNEL_P_H
-#define QSSLSOCKET_SCHANNEL_P_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.
-//
-
-QT_REQUIRE_CONFIG(schannel);
-
-#include <QtNetwork/private/qtnetworkglobal_p.h>
-
-#include "qsslsocket_p.h"
-
-#define SECURITY_WIN32
-#include <security.h>
-#include <schnlsp.h>
-#undef SECURITY_WIN32
-
-QT_BEGIN_NAMESPACE
-
-class QSslSocketBackendPrivate final : public QSslSocketPrivate
-{
- Q_DISABLE_COPY_MOVE(QSslSocketBackendPrivate)
- Q_DECLARE_PUBLIC(QSslSocket)
-public:
- QSslSocketBackendPrivate();
- ~QSslSocketBackendPrivate();
-
- // Platform specific functions
- void startClientEncryption() override;
- void startServerEncryption() override;
- void transmit() override;
- void disconnectFromHost() override;
- void disconnected() override;
- QSslCipher sessionCipher() const override;
- QSsl::SslProtocol sessionProtocol() const override;
- void continueHandshake() override;
-
- static QList<QSslCipher> defaultCiphers();
- static QList<QSslError> verify(const QList<QSslCertificate> &certificateChain,
- const QString &hostName);
- static bool importPkcs12(QIODevice *device, QSslKey *key, QSslCertificate *cert,
- QList<QSslCertificate> *caCertificates, const QByteArray &passPhrase);
-
-private:
- enum class SchannelState {
- InitializeHandshake, // create and transmit context (client)/accept context (server)
- PerformHandshake, // get token back, process it
- VerifyHandshake, // Verify that things are OK
- Done, // Connection encrypted!
- Renegotiate // Renegotiating!
- } schannelState = SchannelState::InitializeHandshake;
-
- void reset();
- bool acquireCredentialsHandle();
- ULONG getContextRequirements();
- bool createContext(); // for clients
- bool acceptContext(); // for server
- bool performHandshake();
- bool verifyHandshake();
- bool renegotiate();
-
- bool sendToken(void *token, unsigned long tokenLength, bool emitError = true);
- QString targetName() const;
-
- bool checkSslErrors();
- void deallocateContext();
- void freeCredentialsHandle();
- void closeCertificateStores();
- void sendShutdown();
-
- void initializeCertificateStores();
- bool verifyCertContext(CERT_CONTEXT *certContext);
-
- bool rootCertOnDemandLoadingAllowed();
-
- SecPkgContext_ConnectionInfo connectionInfo = {};
- SecPkgContext_StreamSizes streamSizes = {};
-
- CredHandle credentialHandle; // Initialized in ctor
- CtxtHandle contextHandle; // Initialized in ctor
-
- QByteArray intermediateBuffer; // data which is left-over or incomplete
-
- QHCertStorePointer localCertificateStore = nullptr;
- QHCertStorePointer peerCertificateStore = nullptr;
- QHCertStorePointer caCertificateStore = nullptr;
-
- const CERT_CONTEXT *localCertContext = nullptr;
-
- ULONG contextAttributes = 0;
- qint64 missingData = 0;
-
- bool renegotiating = false;
-};
-
-QT_END_NAMESPACE
-
-#endif // QSSLSOCKET_SCHANNEL_P_H
diff --git a/src/network/ssl/qtls_utils_p.h b/src/network/ssl/qtls_utils_p.h
deleted file mode 100644
index ceca3030d6..0000000000
--- a/src/network/ssl/qtls_utils_p.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QTLS_UTILS_P_H
-#define QTLS_UTILS_P_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.
-//
-
-#include <QtNetwork/private/qtnetworkglobal_p.h>
-
-#if QT_CONFIG(openssl)
-#include <QtNetwork/private/qsslsocket_openssl_p.h>
-#endif
-
-#include <QtNetwork/private/qssl_p.h>
-
-#include <QtCore/qglobal.h>
-#include <QtCore/qdebug.h>
-
-#include <memory>
-
-QT_BEGIN_NAMESPACE
-
-namespace QTlslUtils
-{
-
-template <class NativeTlsType, void (*Deleter)(NativeTlsType *)>
-void safe_delete(NativeTlsType *object)
-{
- static_assert (Deleter, "safe_delete: invalid (nullptr) function pointer provided");
-
- if (object)
- Deleter(object);
-}
-
-template<class NativeTlsType, int ok, int (*Deleter)(NativeTlsType *)>
-void safe_delete(NativeTlsType *object)
-{
- static_assert (Deleter, "safe_delete: invalid (nullptr) function pointer provided");
-
- if (object) {
- if (Deleter(object) != ok) {
- qCWarning(lcSsl, "Failed to free a resource.");
-#if QT_CONFIG(openssl) // || wolfssl later
- QSslSocketBackendPrivate::logAndClearErrorQueue();
-#endif // QT_CONFIG(openssl)
- }
- }
-}
-
-template<class NativeTlsType>
-using Deleter = std::unique_ptr<NativeTlsType, void (*)(NativeTlsType *)>;
-
-} // namespace QTlsUtils
-
-QT_END_NAMESPACE
-
-#endif // QTLS_UTILS_P_H
diff --git a/src/network/ssl/qtlsbackend.cpp b/src/network/ssl/qtlsbackend.cpp
new file mode 100644
index 0000000000..761ab33fbe
--- /dev/null
+++ b/src/network/ssl/qtlsbackend.cpp
@@ -0,0 +1,2357 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qtlsbackend_p.h"
+
+#if QT_CONFIG(ssl)
+#include "qsslpresharedkeyauthenticator_p.h"
+#include "qsslpresharedkeyauthenticator.h"
+#include "qsslsocket_p.h"
+#include "qsslcipher_p.h"
+#include "qsslkey_p.h"
+#include "qsslkey.h"
+#endif
+
+#include "qssl_p.h"
+
+#include <QtCore/private/qfactoryloader_p.h>
+
+#include "QtCore/qapplicationstatic.h"
+#include <QtCore/qbytearray.h>
+#include <QtCore/qmutex.h>
+
+#include <algorithm>
+#include <vector>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+Q_APPLICATION_STATIC(QFactoryLoader, qtlsbLoader, QTlsBackend_iid,
+ QStringLiteral("/tls"))
+
+namespace {
+
+class BackendCollection
+{
+public:
+ void addBackend(QTlsBackend *backend)
+ {
+ Q_ASSERT(backend);
+ Q_ASSERT(std::find(backends.begin(), backends.end(), backend) == backends.end());
+ const QMutexLocker locker(&collectionMutex);
+ backends.push_back(backend);
+ }
+
+ void removeBackend(QTlsBackend *backend)
+ {
+ Q_ASSERT(backend);
+ const QMutexLocker locker(&collectionMutex);
+ const auto it = std::find(backends.begin(), backends.end(), backend);
+ Q_ASSERT(it != backends.end());
+ backends.erase(it);
+ }
+
+ bool tryPopulateCollection()
+ {
+ if (!qtlsbLoader())
+ return false;
+
+ Q_CONSTINIT static QBasicMutex mutex;
+ const QMutexLocker locker(&mutex);
+ if (backends.size())
+ return true;
+
+#if QT_CONFIG(library)
+ qtlsbLoader->update();
+#endif
+ int index = 0;
+ while (qtlsbLoader->instance(index))
+ ++index;
+
+ return true;
+ }
+
+ QList<QString> backendNames()
+ {
+ QList<QString> names;
+ if (!tryPopulateCollection())
+ return names;
+
+ const QMutexLocker locker(&collectionMutex);
+ if (!backends.size())
+ return names;
+
+ names.reserve(backends.size());
+ for (const auto *backend : backends) {
+ if (backend->isValid())
+ names.append(backend->backendName());
+ }
+
+ return names;
+ }
+
+ QTlsBackend *backend(const QString &name)
+ {
+ if (!tryPopulateCollection())
+ return nullptr;
+
+ const QMutexLocker locker(&collectionMutex);
+ const auto it = std::find_if(backends.begin(), backends.end(),
+ [&name](const auto *fct) {return fct->backendName() == name;});
+
+ return it == backends.end() ? nullptr : *it;
+ }
+
+private:
+ std::vector<QTlsBackend *> backends;
+ QMutex collectionMutex;
+};
+
+} // Unnamed namespace
+
+Q_GLOBAL_STATIC(BackendCollection, backends);
+
+/*!
+ \class QTlsBackend
+ \internal (Network-private)
+ \brief QTlsBackend is a factory class, providing implementations
+ for the QSsl classes.
+
+ The purpose of QTlsBackend is to enable and simplify the addition
+ of new TLS backends to be used by QSslSocket and related classes.
+ Starting from Qt 6.1, these backends have plugin-based design (and
+ thus can co-exist simultaneously, unlike pre 6.1 times), although
+ any given run of a program can only use one of them.
+
+ Inheriting from QTlsBackend and creating an object of such
+ a class adds a new backend into the list of available TLS backends.
+
+ A new backend must provide a list of classes, features and protocols
+ it supports, and override the corresponding virtual functions that
+ create backend-specific implementations for these QSsl-classes.
+
+ The base abstract class - QTlsBackend - provides, where possible,
+ default implementations of its virtual member functions. These
+ default implementations can be overridden by a derived backend
+ class, if needed.
+
+ QTlsBackend also provides some auxiliary functions that a derived
+ backend class can use to interact with the internals of network-private classes.
+
+ \sa QSslSocket::availableBackends(), supportedFeatures(), supportedProtocols(), implementedClasses()
+*/
+
+/*!
+ \fn QString QTlsBackend::backendName() const
+ \internal
+ Returns the name of this backend. The name will be reported by QSslSocket::availableBackends().
+ Example of backend names: "openssl", "schannel", "securetransport".
+
+ \sa QSslSocket::availableBackends(), isValid()
+*/
+
+const QString QTlsBackend::builtinBackendNames[] = {
+ QStringLiteral("schannel"),
+ QStringLiteral("securetransport"),
+ QStringLiteral("openssl"),
+ QStringLiteral("cert-only")
+};
+
+/*!
+ \internal
+ The default constructor, adds a new backend to the list of available backends.
+
+ \sa ~QTlsBackend(), availableBackendNames(), QSslSocket::availableBackends()
+*/
+QTlsBackend::QTlsBackend()
+{
+ if (backends())
+ backends->addBackend(this);
+
+ if (QCoreApplication::instance()) {
+ connect(QCoreApplication::instance(), &QCoreApplication::destroyed, this, [this] {
+ delete this;
+ });
+ }
+}
+
+/*!
+ \internal
+ Removes this backend from the list of available backends.
+
+ \sa QTlsBackend(), availableBackendNames(), QSslSocket::availableBackends()
+*/
+QTlsBackend::~QTlsBackend()
+{
+ if (backends())
+ backends->removeBackend(this);
+}
+
+/*!
+ \internal
+ Returns \c true if this backend was initialised successfully. The default implementation
+ always returns \c true.
+
+ \note This function must be overridden if a particular backend has a non-trivial initialization
+ that can fail. If reimplemented, returning \c false will exclude this backend from the list of
+ backends, reported as available by QSslSocket.
+
+ \sa QSslSocket::availableBackends()
+*/
+
+bool QTlsBackend::isValid() const
+{
+ return true;
+}
+
+/*!
+ \internal
+ Returns an implementations-specific integer value, representing the TLS library's
+ version, that is currently used by this backend (i.e. runtime library version).
+ The default implementation returns 0.
+
+ \sa tlsLibraryBuildVersionNumber()
+*/
+long QTlsBackend::tlsLibraryVersionNumber() const
+{
+ return 0;
+}
+
+/*!
+ \internal
+ Returns an implementation-specific string, representing the TLS library's version,
+ that is currently used by this backend (i.e. runtime library version). The default
+ implementation returns an empty string.
+
+ \sa tlsLibraryBuildVersionString()
+*/
+
+QString QTlsBackend::tlsLibraryVersionString() const
+{
+ return {};
+}
+
+/*!
+ \internal
+ Returns an implementation-specific integer value, representing the TLS library's
+ version that this backend was built against (i.e. compile-time library version).
+ The default implementation returns 0.
+
+ \sa tlsLibraryVersionNumber()
+*/
+
+long QTlsBackend::tlsLibraryBuildVersionNumber() const
+{
+ return 0;
+}
+
+/*!
+ \internal
+ Returns an implementation-specific string, representing the TLS library's version
+ that this backend was built against (i.e. compile-time version). The default
+ implementation returns an empty string.
+
+ \sa tlsLibraryVersionString()
+*/
+QString QTlsBackend::tlsLibraryBuildVersionString() const
+{
+ return {};
+}
+
+/*!
+ \internal
+ QSslSocket and related classes call this function to ensure that backend's internal
+ resources - e.g. CA certificates, or ciphersuites - were properly initialized.
+*/
+void QTlsBackend::ensureInitialized() const
+{
+}
+
+#define REPORT_MISSING_SUPPORT(message) \
+ qCWarning(lcSsl) << "The backend" << backendName() << message
+
+/*!
+ \internal
+ If QSsl::ImplementedClass::Key is present in this backend's implementedClasses(),
+ the backend must reimplement this method to return a dynamically-allocated instance
+ of an implementation-specific type, inheriting from the class QTlsPrivate::TlsKey.
+ The default implementation of this function returns \nullptr.
+
+ \sa QSslKey, implementedClasses(), QTlsPrivate::TlsKey
+*/
+QTlsPrivate::TlsKey *QTlsBackend::createKey() const
+{
+ REPORT_MISSING_SUPPORT("does not support QSslKey");
+ return nullptr;
+}
+
+/*!
+ \internal
+ If QSsl::ImplementedClass::Certificate is present in this backend's implementedClasses(),
+ the backend must reimplement this method to return a dynamically-allocated instance of an
+ implementation-specific type, inheriting from the class QTlsPrivate::X509Certificate.
+ The default implementation of this function returns \nullptr.
+
+ \sa QSslCertificate, QTlsPrivate::X509Certificate, implementedClasses()
+*/
+QTlsPrivate::X509Certificate *QTlsBackend::createCertificate() const
+{
+ REPORT_MISSING_SUPPORT("does not support QSslCertificate");
+ return nullptr;
+}
+
+/*!
+ \internal
+ This function returns a list of system CA certificates - e.g. certificates, loaded
+ from a system store, if available. This function allows implementation of the class
+ QSslConfiguration. The default implementation of this function returns an empty list.
+
+ \sa QSslCertificate, QSslConfiguration
+*/
+QList<QSslCertificate> QTlsBackend::systemCaCertificates() const
+{
+ REPORT_MISSING_SUPPORT("does not provide system CA certificates");
+ return {};
+}
+
+/*!
+ \internal
+ If QSsl::ImplementedClass::Socket is present in this backend's implementedClasses(),
+ the backend must reimplement this method to return a dynamically-allocated instance of an
+ implementation-specific type, inheriting from the class QTlsPrivate::TlsCryptograph.
+ The default implementation of this function returns \nullptr.
+
+ \sa QSslSocket, QTlsPrivate::TlsCryptograph, implementedClasses()
+*/
+QTlsPrivate::TlsCryptograph *QTlsBackend::createTlsCryptograph() const
+{
+ REPORT_MISSING_SUPPORT("does not support QSslSocket");
+ return nullptr;
+}
+
+/*!
+ \internal
+ If QSsl::ImplementedClass::Dtls is present in this backend's implementedClasses(),
+ the backend must reimplement this method to return a dynamically-allocated instance of an
+ implementation-specific type, inheriting from the class QTlsPrivate::DtlsCryptograph.
+ The default implementation of this function returns \nullptr.
+
+ \sa QDtls, QTlsPrivate::DtlsCryptograph, implementedClasses()
+*/
+QTlsPrivate::DtlsCryptograph *QTlsBackend::createDtlsCryptograph(QDtls *qObject, int mode) const
+{
+ Q_UNUSED(qObject);
+ Q_UNUSED(mode);
+ REPORT_MISSING_SUPPORT("does not support QDtls");
+ return nullptr;
+}
+
+/*!
+ \internal
+ If QSsl::ImplementedClass::DtlsCookie is present in this backend's implementedClasses(),
+ the backend must reimplement this method to return a dynamically-allocated instance of an
+ implementation-specific type, inheriting from the class QTlsPrivate::DtlsCookieVerifier. The
+ default implementation returns \nullptr.
+
+ \sa QDtlsClientVerifier, QTlsPrivate::DtlsCookieVerifier, implementedClasses()
+*/
+QTlsPrivate::DtlsCookieVerifier *QTlsBackend::createDtlsCookieVerifier() const
+{
+ REPORT_MISSING_SUPPORT("does not support DTLS cookies");
+ return nullptr;
+}
+
+/*!
+ \internal
+ If QSsl::SupportedFeature::CertificateVerification is present in this backend's
+ supportedFeatures(), the backend must reimplement this method to return a pointer
+ to a function, that checks a certificate (or a chain of certificates) against available
+ CA certificates. The default implementation returns \nullptr.
+
+ \sa supportedFeatures(), QSslCertificate
+*/
+
+QTlsPrivate::X509ChainVerifyPtr QTlsBackend::X509Verifier() const
+{
+ REPORT_MISSING_SUPPORT("does not support (manual) certificate verification");
+ return nullptr;
+}
+
+/*!
+ \internal
+ Returns a pointer to function, that reads certificates in PEM format. The
+ default implementation returns \nullptr.
+
+ \sa QSslCertificate
+*/
+QTlsPrivate::X509PemReaderPtr QTlsBackend::X509PemReader() const
+{
+ REPORT_MISSING_SUPPORT("cannot read PEM format");
+ return nullptr;
+}
+
+/*!
+ \internal
+ Returns a pointer to function, that can read certificates in DER format.
+ The default implementation returns \nullptr.
+
+ \sa QSslCertificate
+*/
+QTlsPrivate::X509DerReaderPtr QTlsBackend::X509DerReader() const
+{
+ REPORT_MISSING_SUPPORT("cannot read DER format");
+ return nullptr;
+}
+
+/*!
+ \internal
+ Returns a pointer to function, that can read certificates in PKCS 12 format.
+ The default implementation returns \nullptr.
+
+ \sa QSslCertificate
+*/
+QTlsPrivate::X509Pkcs12ReaderPtr QTlsBackend::X509Pkcs12Reader() const
+{
+ REPORT_MISSING_SUPPORT("cannot read PKCS12 format");
+ return nullptr;
+}
+
+/*!
+ \internal
+ If QSsl::ImplementedClass::EllipticCurve is present in this backend's implementedClasses(),
+ and the backend provides information about supported curves, it must reimplement this
+ method to return a list of unique identifiers of the supported elliptic curves. The default
+ implementation returns an empty list.
+
+ \note The meaning of a curve identifier is implementation-specific.
+
+ \sa implemenedClasses(), QSslEllipticCurve
+*/
+QList<int> QTlsBackend::ellipticCurvesIds() const
+{
+ REPORT_MISSING_SUPPORT("does not support QSslEllipticCurve");
+ return {};
+}
+
+/*!
+ \internal
+ If this backend provides information about available elliptic curves, this
+ function should return a unique integer identifier for a curve named \a name,
+ which is a conventional short name for the curve. The default implementation
+ returns 0.
+
+ \note The meaning of a curve identifier is implementation-specific.
+
+ \sa QSslEllipticCurve::shortName()
+*/
+int QTlsBackend::curveIdFromShortName(const QString &name) const
+{
+ Q_UNUSED(name);
+ REPORT_MISSING_SUPPORT("does not support QSslEllipticCurve");
+ return 0;
+}
+
+/*!
+ \internal
+ If this backend provides information about available elliptic curves, this
+ function should return a unique integer identifier for a curve named \a name,
+ which is a conventional long name for the curve. The default implementation
+ returns 0.
+
+ \note The meaning of a curve identifier is implementation-specific.
+
+ \sa QSslElliptiCurve::longName()
+*/
+int QTlsBackend::curveIdFromLongName(const QString &name) const
+{
+ Q_UNUSED(name);
+ REPORT_MISSING_SUPPORT("does not support QSslEllipticCurve");
+ return 0;
+}
+
+/*!
+ \internal
+ If this backend provides information about available elliptic curves,
+ this function should return a conventional short name for a curve identified
+ by \a cid. The default implementation returns an empty string.
+
+ \note The meaning of a curve identifier is implementation-specific.
+
+ \sa ellipticCurvesIds(), QSslEllipticCurve::shortName()
+*/
+QString QTlsBackend::shortNameForId(int cid) const
+{
+ Q_UNUSED(cid);
+ REPORT_MISSING_SUPPORT("does not support QSslEllipticCurve");
+ return {};
+}
+
+/*!
+ \internal
+ If this backend provides information about available elliptic curves,
+ this function should return a conventional long name for a curve identified
+ by \a cid. The default implementation returns an empty string.
+
+ \note The meaning of a curve identifier is implementation-specific.
+
+ \sa ellipticCurvesIds(), QSslEllipticCurve::shortName()
+*/
+QString QTlsBackend::longNameForId(int cid) const
+{
+ Q_UNUSED(cid);
+ REPORT_MISSING_SUPPORT("does not support QSslEllipticCurve");
+ return {};
+}
+
+/*!
+ \internal
+ Returns true if the elliptic curve identified by \a cid is one of the named
+ curves, that can be used in the key exchange when using an elliptic curve
+ cipher with TLS; false otherwise. The default implementation returns false.
+
+ \note The meaning of curve identifier is implementation-specific.
+*/
+bool QTlsBackend::isTlsNamedCurve(int cid) const
+{
+ Q_UNUSED(cid);
+ REPORT_MISSING_SUPPORT("does not support QSslEllipticCurve");
+ return false;
+}
+
+/*!
+ \internal
+ If this backend supports the class QSslDiffieHellmanParameters, this function is
+ needed for construction of a QSslDiffieHellmanParameters from DER encoded data.
+ This function is expected to return a value that matches an enumerator in
+ QSslDiffieHellmanParameters::Error enumeration. The default implementation of this
+ function returns 0 (equals to QSslDiffieHellmanParameters::NoError).
+
+ \sa QSslDiffieHellmanParameters, implementedClasses()
+*/
+int QTlsBackend::dhParametersFromDer(const QByteArray &derData, QByteArray *data) const
+{
+ Q_UNUSED(derData);
+ Q_UNUSED(data);
+ REPORT_MISSING_SUPPORT("does not support QSslDiffieHellmanParameters in DER format");
+ return {};
+}
+
+/*!
+ \internal
+ If this backend supports the class QSslDiffieHellmanParameters, this function is
+ is needed for construction of a QSslDiffieHellmanParameters from PEM encoded data.
+ This function is expected to return a value that matches an enumerator in
+ QSslDiffieHellmanParameters::Error enumeration. The default implementation of this
+ function returns 0 (equals to QSslDiffieHellmanParameters::NoError).
+
+ \sa QSslDiffieHellmanParameters, implementedClasses()
+*/
+int QTlsBackend::dhParametersFromPem(const QByteArray &pemData, QByteArray *data) const
+{
+ Q_UNUSED(pemData);
+ Q_UNUSED(data);
+ REPORT_MISSING_SUPPORT("does not support QSslDiffieHellmanParameters in PEM format");
+ return {};
+}
+
+/*!
+ \internal
+ Returns a list of names of available backends.
+
+ \note This list contains only properly initialized backends.
+
+ \sa QTlsBackend(), isValid()
+*/
+QList<QString> QTlsBackend::availableBackendNames()
+{
+ if (!backends())
+ return {};
+
+ return backends->backendNames();
+}
+
+/*!
+ \internal
+ Returns the name of the backend that QSslSocket() would use by default. If no
+ backend was found, the function returns an empty string.
+*/
+QString QTlsBackend::defaultBackendName()
+{
+ // We prefer OpenSSL as default:
+ const auto names = availableBackendNames();
+ auto name = builtinBackendNames[nameIndexOpenSSL];
+ if (names.contains(name))
+ return name;
+ name = builtinBackendNames[nameIndexSchannel];
+ if (names.contains(name))
+ return name;
+ name = builtinBackendNames[nameIndexSecureTransport];
+ if (names.contains(name))
+ return name;
+
+ const auto pos = std::find_if(names.begin(), names.end(), [](const auto &name) {
+ return name != builtinBackendNames[nameIndexCertOnly];
+ });
+
+ if (pos != names.end())
+ return *pos;
+
+ if (names.size())
+ return names[0];
+
+ return {};
+}
+
+/*!
+ \internal
+ Returns a backend named \a backendName, if it exists.
+ Otherwise, it returns \nullptr.
+
+ \sa backendName(), QSslSocket::availableBackends()
+*/
+QTlsBackend *QTlsBackend::findBackend(const QString &backendName)
+{
+ if (!backends())
+ return {};
+
+ if (auto *fct = backends->backend(backendName))
+ return fct;
+
+ qCWarning(lcSsl) << "Cannot create unknown backend named" << backendName;
+ return nullptr;
+}
+
+/*!
+ \internal
+ Returns the backend that QSslSocket is using. If Qt was built without TLS support,
+ this function returns a minimal backend that only supports QSslCertificate.
+
+ \sa defaultBackend()
+*/
+QTlsBackend *QTlsBackend::activeOrAnyBackend()
+{
+#if QT_CONFIG(ssl)
+ return QSslSocketPrivate::tlsBackendInUse();
+#else
+ return findBackend(defaultBackendName());
+#endif // QT_CONFIG(ssl)
+}
+
+/*!
+ \internal
+ Returns a list of TLS and DTLS protocol versions, that a backend named
+ \a backendName supports.
+
+ \note This list is supposed to also include range-based versions, which
+ allows negotiation of protocols during the handshake, so that these versions
+ can be used when configuring QSslSocket (e.g. QSsl::TlsV1_2OrLater).
+
+ \sa QSsl::SslProtocol
+*/
+QList<QSsl::SslProtocol> QTlsBackend::supportedProtocols(const QString &backendName)
+{
+ if (!backends())
+ return {};
+
+ if (const auto *fct = backends->backend(backendName))
+ return fct->supportedProtocols();
+
+ return {};
+}
+
+/*!
+ \internal
+ Returns a list of features that a backend named \a backendName supports. E.g.
+ a backend may support PSK (pre-shared keys, defined as QSsl::SupportedFeature::Psk)
+ or ALPN (application layer protocol negotiation, identified by
+ QSsl::SupportedFeature::ClientSideAlpn or QSsl::SupportedFeature::ServerSideAlpn).
+
+ \sa QSsl::SupportedFeature
+*/
+QList<QSsl::SupportedFeature> QTlsBackend::supportedFeatures(const QString &backendName)
+{
+ if (!backends())
+ return {};
+
+ if (const auto *fct = backends->backend(backendName))
+ return fct->supportedFeatures();
+
+ return {};
+}
+
+/*!
+ \internal
+ Returns a list of classes that a backend named \a backendName supports. E.g. a backend
+ may implement QSslSocket (QSsl::ImplementedClass::Socket), and QDtls
+ (QSsl::ImplementedClass::Dtls).
+
+ \sa QSsl::ImplementedClass
+*/
+QList<QSsl::ImplementedClass> QTlsBackend::implementedClasses(const QString &backendName)
+{
+ if (!backends())
+ return {};
+
+ if (const auto *fct = backends->backend(backendName))
+ return fct->implementedClasses();
+
+ return {};
+}
+
+/*!
+ \internal
+ Auxiliary function. Initializes \a key to use \a keyBackend.
+*/
+void QTlsBackend::resetBackend(QSslKey &key, QTlsPrivate::TlsKey *keyBackend)
+{
+#if QT_CONFIG(ssl)
+ key.d->backend.reset(keyBackend);
+#else
+ Q_UNUSED(key);
+ Q_UNUSED(keyBackend);
+#endif // QT_CONFIG(ssl)
+}
+
+/*!
+ \internal
+ Auxiliary function. Initializes client-side \a auth using the \a hint, \a hintLength,
+ \a maxIdentityLength and \a maxPskLen.
+*/
+void QTlsBackend::setupClientPskAuth(QSslPreSharedKeyAuthenticator *auth, const char *hint,
+ int hintLength, unsigned maxIdentityLen, unsigned maxPskLen)
+{
+ Q_ASSERT(auth);
+#if QT_CONFIG(ssl)
+ if (hint)
+ auth->d->identityHint = QByteArray::fromRawData(hint, hintLength); // it's NUL terminated, but do not include the NUL
+
+ auth->d->maximumIdentityLength = int(maxIdentityLen) - 1; // needs to be NUL terminated
+ auth->d->maximumPreSharedKeyLength = int(maxPskLen);
+#else
+ Q_UNUSED(auth);
+ Q_UNUSED(hint);
+ Q_UNUSED(hintLength);
+ Q_UNUSED(maxIdentityLen);
+ Q_UNUSED(maxPskLen);
+#endif
+}
+
+/*!
+ \internal
+ Auxiliary function. Initializes server-side \a auth using the \a identity, \a identityHint and
+ \a maxPskLen.
+*/
+void QTlsBackend::setupServerPskAuth(QSslPreSharedKeyAuthenticator *auth, const char *identity,
+ const QByteArray &identityHint, unsigned int maxPskLen)
+{
+#if QT_CONFIG(ssl)
+ Q_ASSERT(auth);
+ auth->d->identityHint = identityHint;
+ auth->d->identity = identity;
+ auth->d->maximumIdentityLength = 0; // user cannot set an identity
+ auth->d->maximumPreSharedKeyLength = int(maxPskLen);
+#else
+ Q_UNUSED(auth);
+ Q_UNUSED(identity);
+ Q_UNUSED(identityHint);
+ Q_UNUSED(maxPskLen);
+#endif
+}
+
+#if QT_CONFIG(ssl)
+/*!
+ \internal
+ Auxiliary function. Creates a new QSslCipher from \a descriptionOneLine, \a bits
+ and \a supportedBits. \a descriptionOneLine consists of several fields, separated by
+ whitespace. These include: cipher name, protocol version, key exchange method,
+ authentication method, encryption method, message digest (Mac). Example:
+ "ECDHE-RSA-AES256-GCM-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD"
+*/
+QSslCipher QTlsBackend::createCiphersuite(const QString &descriptionOneLine, int bits, int supportedBits)
+{
+ QSslCipher ciph;
+
+ const auto descriptionList = QStringView{descriptionOneLine}.split(u' ', Qt::SkipEmptyParts);
+ if (descriptionList.size() > 5) {
+ ciph.d->isNull = false;
+ ciph.d->name = descriptionList.at(0).toString();
+
+ QStringView protoString = descriptionList.at(1);
+ ciph.d->protocolString = protoString.toString();
+ ciph.d->protocol = QSsl::UnknownProtocol;
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
+ if (protoString.startsWith(u"TLSv1")) {
+ QStringView tail = protoString.sliced(5);
+ if (tail.startsWith(u'.')) {
+ tail = tail.sliced(1);
+ if (tail == u"3")
+ ciph.d->protocol = QSsl::TlsV1_3;
+ else if (tail == u"2")
+ ciph.d->protocol = QSsl::TlsV1_2;
+ else if (tail == u"1")
+ ciph.d->protocol = QSsl::TlsV1_1;
+ } else if (tail.isEmpty()) {
+ ciph.d->protocol = QSsl::TlsV1_0;
+ }
+ }
+QT_WARNING_POP
+
+ if (descriptionList.at(2).startsWith("Kx="_L1))
+ ciph.d->keyExchangeMethod = descriptionList.at(2).mid(3).toString();
+ if (descriptionList.at(3).startsWith("Au="_L1))
+ ciph.d->authenticationMethod = descriptionList.at(3).mid(3).toString();
+ if (descriptionList.at(4).startsWith("Enc="_L1))
+ ciph.d->encryptionMethod = descriptionList.at(4).mid(4).toString();
+ ciph.d->exportable = (descriptionList.size() > 6 && descriptionList.at(6) == "export"_L1);
+
+ ciph.d->bits = bits;
+ ciph.d->supportedBits = supportedBits;
+ }
+
+ return ciph;
+}
+
+/*!
+ \internal
+ Auxiliary function. Creates a new QSslCipher from \a suiteName, \a protocol version and
+ \a protocolString. For example:
+ \code
+ createCiphersuite("ECDHE-RSA-AES256-GCM-SHA256"_L1, QSsl::TlsV1_2, "TLSv1.2"_L1);
+ \endcode
+*/
+QSslCipher QTlsBackend::createCiphersuite(const QString &suiteName, QSsl::SslProtocol protocol,
+ const QString &protocolString)
+{
+ QSslCipher ciph;
+
+ if (!suiteName.size())
+ return ciph;
+
+ ciph.d->isNull = false;
+ ciph.d->name = suiteName;
+ ciph.d->protocol = protocol;
+ ciph.d->protocolString = protocolString;
+
+ const auto bits = QStringView{ciph.d->name}.split(u'-');
+ if (bits.size() >= 2) {
+ if (bits.size() == 2 || bits.size() == 3)
+ ciph.d->keyExchangeMethod = "RSA"_L1;
+ else if (bits.front() == "DH"_L1 || bits.front() == "DHE"_L1)
+ ciph.d->keyExchangeMethod = "DH"_L1;
+ else if (bits.front() == "ECDH"_L1 || bits.front() == "ECDHE"_L1)
+ ciph.d->keyExchangeMethod = "ECDH"_L1;
+ else
+ qCWarning(lcSsl) << "Unknown Kx" << ciph.d->name;
+
+ if (bits.size() == 2 || bits.size() == 3)
+ ciph.d->authenticationMethod = "RSA"_L1;
+ else if (ciph.d->name.contains("-ECDSA-"_L1))
+ ciph.d->authenticationMethod = "ECDSA"_L1;
+ else if (ciph.d->name.contains("-RSA-"_L1))
+ ciph.d->authenticationMethod = "RSA"_L1;
+ else
+ qCWarning(lcSsl) << "Unknown Au" << ciph.d->name;
+
+ if (ciph.d->name.contains("RC4-"_L1)) {
+ ciph.d->encryptionMethod = "RC4(128)"_L1;
+ ciph.d->bits = 128;
+ ciph.d->supportedBits = 128;
+ } else if (ciph.d->name.contains("DES-CBC3-"_L1)) {
+ ciph.d->encryptionMethod = "3DES(168)"_L1;
+ ciph.d->bits = 168;
+ ciph.d->supportedBits = 168;
+ } else if (ciph.d->name.contains("AES128-"_L1)) {
+ ciph.d->encryptionMethod = "AES(128)"_L1;
+ ciph.d->bits = 128;
+ ciph.d->supportedBits = 128;
+ } else if (ciph.d->name.contains("AES256-GCM"_L1)) {
+ ciph.d->encryptionMethod = "AESGCM(256)"_L1;
+ ciph.d->bits = 256;
+ ciph.d->supportedBits = 256;
+ } else if (ciph.d->name.contains("AES256-"_L1)) {
+ ciph.d->encryptionMethod = "AES(256)"_L1;
+ ciph.d->bits = 256;
+ ciph.d->supportedBits = 256;
+ } else if (ciph.d->name.contains("CHACHA20-"_L1)) {
+ ciph.d->encryptionMethod = "CHACHA20"_L1;
+ ciph.d->bits = 256;
+ ciph.d->supportedBits = 256;
+ } else if (ciph.d->name.contains("NULL-"_L1)) {
+ ciph.d->encryptionMethod = "NULL"_L1;
+ } else {
+ qCWarning(lcSsl) << "Unknown Enc" << ciph.d->name;
+ }
+ }
+ return ciph;
+}
+
+/*!
+ \internal
+ Auxiliary function. Creates a new QSslCipher from \a name, \a keyExchangeMethod, \a encryptionMethod,
+ \a authenticationMethod, \a bits, \a protocol version and \a protocolString.
+ For example:
+ \code
+ createCiphersuite("ECDHE-RSA-AES256-GCM-SHA256"_L1, "ECDH"_L1, "AES"_L1, "RSA"_L1, 256,
+ QSsl::TlsV1_2, "TLSv1.2"_L1);
+ \endcode
+*/
+QSslCipher QTlsBackend::createCiphersuite(const QString &name, const QString &keyExchangeMethod,
+ const QString &encryptionMethod,
+ const QString &authenticationMethod,
+ int bits, QSsl::SslProtocol protocol,
+ const QString &protocolString)
+{
+ QSslCipher cipher;
+ cipher.d->isNull = false;
+ cipher.d->name = name;
+ cipher.d->bits = bits;
+ cipher.d->supportedBits = bits;
+ cipher.d->keyExchangeMethod = keyExchangeMethod;
+ cipher.d->encryptionMethod = encryptionMethod;
+ cipher.d->authenticationMethod = authenticationMethod;
+ cipher.d->protocol = protocol;
+ cipher.d->protocolString = protocolString;
+ return cipher;
+}
+
+/*!
+ \internal
+ Returns an implementation-specific list of ciphersuites that can be used by QSslSocket.
+
+ \sa QSslConfiguration::defaultCiphers()
+*/
+QList<QSslCipher> QTlsBackend::defaultCiphers()
+{
+ return QSslSocketPrivate::defaultCiphers();
+}
+
+/*!
+ \internal
+ Returns an implementation-specific list of ciphersuites that can be used by QDtls.
+*/
+QList<QSslCipher> QTlsBackend::defaultDtlsCiphers()
+{
+ return QSslSocketPrivate::defaultDtlsCiphers();
+}
+
+/*!
+ \internal
+ Sets \a ciphers as defaults ciphers that QSslSocket can use.
+
+ \sa defaultCiphers()
+*/
+void QTlsBackend::setDefaultCiphers(const QList<QSslCipher> &ciphers)
+{
+ QSslSocketPrivate::setDefaultCiphers(ciphers);
+}
+
+/*!
+ \internal
+ Sets \a ciphers as defaults ciphers that QDtls can use.
+
+ \sa defaultDtlsCiphers()
+*/
+void QTlsBackend::setDefaultDtlsCiphers(const QList<QSslCipher> &ciphers)
+{
+ QSslSocketPrivate::setDefaultDtlsCiphers(ciphers);
+}
+
+/*!
+ \internal
+ Sets \a ciphers as a list of supported ciphers.
+
+ \sa QSslConfiguration::supportedCiphers()
+*/
+void QTlsBackend::setDefaultSupportedCiphers(const QList<QSslCipher> &ciphers)
+{
+ QSslSocketPrivate::setDefaultSupportedCiphers(ciphers);
+}
+
+/*!
+ \internal
+ Sets the list of QSslEllipticCurve objects, that QSslConfiguration::supportedEllipticCurves()
+ returns, to ones that are supported by this backend.
+*/
+void QTlsBackend::resetDefaultEllipticCurves()
+{
+ QSslSocketPrivate::resetDefaultEllipticCurves();
+}
+
+/*!
+ Sets \a certs as a list of certificates, that QSslConfiguration::caCertificates()
+ reports.
+
+ \sa QSslConfiguration::defaultConfiguration(), QSslConfiguration::caCertificates()
+*/
+void QTlsBackend::setDefaultCaCertificates(const QList<QSslCertificate> &certs)
+{
+ QSslSocketPrivate::setDefaultCaCertificates(certs);
+}
+
+/*!
+ \internal
+ Returns true if \a configuration allows loading root certificates on demand.
+*/
+bool QTlsBackend::rootLoadingOnDemandAllowed(const QSslConfiguration &configuration)
+{
+ return configuration.d->allowRootCertOnDemandLoading;
+}
+
+/*!
+ \internal
+ Stores \a peerCert in the \a configuration.
+*/
+void QTlsBackend::storePeerCertificate(QSslConfiguration &configuration,
+ const QSslCertificate &peerCert)
+{
+ configuration.d->peerCertificate = peerCert;
+}
+
+/*!
+ \internal
+ Stores \a peerChain in the \a configuration.
+*/
+void QTlsBackend::storePeerCertificateChain(QSslConfiguration &configuration,
+ const QList<QSslCertificate> &peerChain)
+{
+ configuration.d->peerCertificateChain = peerChain;
+}
+
+/*!
+ \internal
+ Clears the peer certificate chain in \a configuration.
+*/
+void QTlsBackend::clearPeerCertificates(QSslConfiguration &configuration)
+{
+ configuration.d->peerCertificate.clear();
+ configuration.d->peerCertificateChain.clear();
+}
+
+/*!
+ \internal
+ Clears the peer certificate chain in \a d.
+*/
+void QTlsBackend::clearPeerCertificates(QSslSocketPrivate *d)
+{
+ Q_ASSERT(d);
+ d->configuration.peerCertificate.clear();
+ d->configuration.peerCertificateChain.clear();
+}
+
+/*!
+ \internal
+ Updates the configuration in \a d with \a shared value.
+*/
+void QTlsBackend::setPeerSessionShared(QSslSocketPrivate *d, bool shared)
+{
+ Q_ASSERT(d);
+ d->configuration.peerSessionShared = shared;
+}
+
+/*!
+ \internal
+ Sets TLS session in \a d to \a asn1.
+*/
+void QTlsBackend::setSessionAsn1(QSslSocketPrivate *d, const QByteArray &asn1)
+{
+ Q_ASSERT(d);
+ d->configuration.sslSession = asn1;
+}
+
+/*!
+ \internal
+ Sets TLS session lifetime hint in \a d to \a hint.
+*/
+void QTlsBackend::setSessionLifetimeHint(QSslSocketPrivate *d, int hint)
+{
+ Q_ASSERT(d);
+ d->configuration.sslSessionTicketLifeTimeHint = hint;
+}
+
+/*!
+ \internal
+ Sets application layer protocol negotiation status in \a d to \a st.
+*/
+void QTlsBackend::setAlpnStatus(QSslSocketPrivate *d, AlpnNegotiationStatus st)
+{
+ Q_ASSERT(d);
+ d->configuration.nextProtocolNegotiationStatus = st;
+}
+
+/*!
+ \internal
+ Sets \a protocol in \a d as a negotiated application layer protocol.
+*/
+void QTlsBackend::setNegotiatedProtocol(QSslSocketPrivate *d, const QByteArray &protocol)
+{
+ Q_ASSERT(d);
+ d->configuration.nextNegotiatedProtocol = protocol;
+}
+
+/*!
+ \internal
+ Stores \a peerCert in the TLS configuration of \a d.
+*/
+void QTlsBackend::storePeerCertificate(QSslSocketPrivate *d, const QSslCertificate &peerCert)
+{
+ Q_ASSERT(d);
+ d->configuration.peerCertificate = peerCert;
+}
+
+/*!
+ \internal
+
+ Stores \a peerChain in the TLS configuration of \a d.
+
+ \note This is a helper function that TlsCryptograph and DtlsCryptograph
+ call during a handshake.
+*/
+void QTlsBackend::storePeerCertificateChain(QSslSocketPrivate *d,
+ const QList<QSslCertificate> &peerChain)
+{
+ Q_ASSERT(d);
+ d->configuration.peerCertificateChain = peerChain;
+}
+
+/*!
+ \internal
+
+ Adds \a rootCert to the list of trusted root certificates in \a d.
+
+ \note In Qt 6.1 it's only used on Windows, during so called 'CA fetch'.
+*/
+void QTlsBackend::addTustedRoot(QSslSocketPrivate *d, const QSslCertificate &rootCert)
+{
+ Q_ASSERT(d);
+ if (!d->configuration.caCertificates.contains(rootCert))
+ d->configuration.caCertificates += rootCert;
+}
+
+/*!
+ \internal
+
+ Saves ephemeral \a key in \a d.
+
+ \sa QSslConfiguration::ephemeralKey()
+*/
+void QTlsBackend::setEphemeralKey(QSslSocketPrivate *d, const QSslKey &key)
+{
+ Q_ASSERT(d);
+ d->configuration.ephemeralServerKey = key;
+}
+
+/*!
+ \internal
+
+ Implementation-specific. Sets the security level suitable for Qt's
+ auto-tests.
+*/
+void QTlsBackend::forceAutotestSecurityLevel()
+{
+}
+
+#endif // QT_CONFIG(ssl)
+
+namespace QTlsPrivate {
+
+/*!
+ \internal (Network-private)
+ \namespace QTlsPrivate
+ \brief Namespace containing onternal types that TLS backends implement.
+
+ This namespace is private to Qt and the backends that implement its TLS support.
+*/
+
+/*!
+ \class TlsKey
+ \internal (Network-private)
+ \brief TlsKey is an abstract class, that allows a TLS plugin to provide
+ an underlying implementation for the class QSslKey.
+
+ Most functions in the class TlsKey are pure virtual and thus have to be
+ reimplemented by a TLS backend that supports QSslKey. In many cases an
+ empty implementation as an overrider is sufficient, albeit with some
+ of QSslKey's functionality missing.
+
+ \sa QTlsBackend::createKey(), QTlsBackend::implementedClasses(), QSslKey
+*/
+
+/*!
+ \fn void TlsKey::decodeDer(KeyType type, KeyAlgorithm algorithm, const QByteArray &der, const QByteArray &passPhrase, bool deepClear)
+ \internal
+
+ If a support of public and private keys in DER format is required, this function
+ must be overridden and should initialize this key using the \a type, \a algorithm, \a der
+ and \a passPhrase. If this key was initialized previously, \a deepClear
+ has an implementation-specific meaning (e.g., if an implementation is using
+ reference-counting and can share internally some data structures, a value \c true may
+ trigger decrementing a reference counter on some implementation-specific object).
+
+ \note An empty overrider is sufficient, but then reading keys in QSsl::Der format
+ will not be supported.
+
+ \sa isNull(), QSsl::KeyType, QSsl::EncodingFormat, QSsl::KeyAlgorithm
+*/
+
+/*!
+ \fn void TlsKey::decodePem(KeyType type, KeyAlgorithm algorithm, const QByteArray &pem, const QByteArray &passPhrase, bool deepClear)
+ \internal
+
+ If a support of public and private keys in PEM format is required, this function must
+ be overridden and should initialize this key using the \a type, \a algorithm, \a pem and
+ \a passPhrase. If this key was initialized previously, \a deepClear has an
+ implementation-specific meaning (e.g., in an implementation using reference-counting,
+ a value \c true may trigger decrementing a reference counter on some implementation-specific
+ object).
+
+ \note An empty overrider is sufficient, but then reading keys in QSsl::Pem format
+ will not be supported.
+
+ \sa isNull(), QSsl::KeyType, QSsl::EncodingFormat, QSsl::KeyAlgorithm
+*/
+
+/*!
+ \fn QByteArray TlsKey::toPem(const QByteArray &passPhrase) const
+ \internal
+
+ This function must be overridden, if converting a key to PEM format, potentially with
+ encryption, is needed (e.g. to save a QSslKey into a file). If this key is
+ private and \a passPhrase is not empty, the key's data is expected to be encrypted using
+ some conventional encryption algorithm (e.g. DES or AES - the one that different tools
+ or even the class QSslKey can understand later).
+
+ \note If this particular functionality is not needed, an overrider returning an
+ empty QByteArray is sufficient.
+
+ \sa QSslKey::toPem()
+*/
+
+/*!
+ \fn QByteArray TlsKey::derFromPem(const QByteArray &pem, QMap<QByteArray, QByteArray> *headers) const
+ \internal
+
+ Converts \a pem to DER format, using this key's type and algorithm. The parameter \a headers
+ must be a valid, non-null pointer. When parsing \a pem, the headers found there will be saved
+ into \a headers.
+
+ \note An overrider returning an empty QByteArray is sufficient, if QSslKey::toDer() is not
+ needed.
+
+ \note This function is very implementation-specific. A backend, that already has this key's
+ non-empty DER data, may simply return this data.
+
+ \sa QSslKey::toDer()
+*/
+
+/*!
+ \fn QByteArray TlsKey::pemFromDer(const QByteArray &der, const QMap<QByteArray, QByteArray> &headers) const
+ \internal
+
+ If overridden, this function is expected to convert \a der, using \a headers, to PEM format.
+
+ \note This function is very implementation-specific. As of now (Qt 6.1), it is only required by
+ Qt's own non-OpenSSL backends, that internally use DER and implement QSslKey::toPem()
+ via pemFromDer().
+*/
+
+/*!
+ \fn void TlsKey::fromHandle(Qt::HANDLE handle, KeyType type)
+ \internal
+
+ Initializes this key using the \a handle and \a type, taking the ownership
+ of the \a handle.
+
+ \note The meaning of the \a handle is implementation-specific.
+
+ \note If a TLS backend does not support such keys, it must provide an
+ empty implementation.
+
+ \sa handle(), QSslKey::QSslKey(), QSslKet::handle()
+*/
+
+/*!
+ \fn TlsKey::handle() const
+ \internal
+
+ If a TLS backend supports opaque keys, returns a native handle that
+ this key was initialized with.
+
+ \sa fromHandle(), QSslKey::handle()
+*/
+
+/*!
+ \fn bool TlsKey::isNull() const
+ \internal
+
+ Returns \c true if this is a null key, \c false otherwise.
+
+ \note A null key corresponds to the default-constructed
+ QSslKey or the one, that was cleared via QSslKey::clear().
+
+ \sa QSslKey::isNull()
+*/
+
+/*!
+ \fn QSsl::KeyType TlsKey::type() const
+ \internal
+
+ Returns the type of this key (public or private).
+*/
+
+/*!
+ \fn QSsl::KeyAlgorithm TlsKey::algorithm() const
+ \internal
+
+ Return this key's algorithm.
+*/
+
+/*!
+ \fn int TlsKey::length() const
+ \internal
+
+ Returns the length of the key in bits, or -1 if the key is null.
+*/
+
+/*!
+ \fn void TlsKey::clear(bool deep)
+ \internal
+
+ Clears the contents of this key, making it a null key. The meaning
+ of \a deep is implementation-specific (e.g. if some internal objects
+ representing a key can be shared using reference counting, \a deep equal
+ to \c true would imply decrementing a reference count).
+
+ \sa isNull()
+*/
+
+/*!
+ \fn bool TlsKey::isPkcs8() const
+ \internal
+
+ This function is internally used only by Qt's own TLS plugins and affects
+ the way PEM file is generated by TlsKey. It's sufficient to override it
+ and return \c false in case a new TLS backend is not using Qt's plugin
+ as a base.
+*/
+
+/*!
+ \fn QByteArray TlsKey::decrypt(Cipher cipher, const QByteArray &data, const QByteArray &passPhrase, const QByteArray &iv) const
+ \internal
+
+ This function allows to decrypt \a data (for example, a private key read from a file), using
+ \a passPhrase, initialization vector \a iv. \a cipher is describing a block cipher and its
+ mode (for example, AES256 + CBC). decrypt() is needed to implement QSslKey's constructor.
+
+ \note A TLS backend may provide an empty implementation, but as a result QSslKey will not be able
+ to work with private encrypted keys.
+
+ \sa QSslKey
+*/
+
+/*!
+ \fn QByteArray TlsKey::encrypt(Cipher cipher, const QByteArray &data, const QByteArray &passPhrase, const QByteArray &iv) const
+ \internal
+
+ This function is needed to implement QSslKey::toPem() with encryption (for a private
+ key). \a cipher names a block cipher to use to encrypt \a data, using
+ \a passPhrase and initialization vector \a iv.
+
+ \note An empty implementation is sufficient, but QSslKey::toPem() will fail for
+ a private key and non-empty passphrase.
+
+ \sa QSslKey
+*/
+
+/*!
+ \internal
+
+ Destroys this key.
+*/
+TlsKey::~TlsKey() = default;
+
+/*!
+ \internal
+
+ A convenience function that returns a string, corresponding to the
+ key type or algorithm, which can be used as a header in a PEM file.
+*/
+QByteArray TlsKey::pemHeader() const
+{
+ if (type() == QSsl::PublicKey)
+ return QByteArrayLiteral("-----BEGIN PUBLIC KEY-----");
+ else if (algorithm() == QSsl::Rsa)
+ return QByteArrayLiteral("-----BEGIN RSA PRIVATE KEY-----");
+ else if (algorithm() == QSsl::Dsa)
+ return QByteArrayLiteral("-----BEGIN DSA PRIVATE KEY-----");
+ else if (algorithm() == QSsl::Ec)
+ return QByteArrayLiteral("-----BEGIN EC PRIVATE KEY-----");
+ else if (algorithm() == QSsl::Dh)
+ return QByteArrayLiteral("-----BEGIN PRIVATE KEY-----");
+
+ Q_UNREACHABLE_RETURN({});
+}
+
+/*!
+ \internal
+ A convenience function that returns a string, corresponding to the
+ key type or algorithm, which can be used as a footer in a PEM file.
+*/
+QByteArray TlsKey::pemFooter() const
+{
+ if (type() == QSsl::PublicKey)
+ return QByteArrayLiteral("-----END PUBLIC KEY-----");
+ else if (algorithm() == QSsl::Rsa)
+ return QByteArrayLiteral("-----END RSA PRIVATE KEY-----");
+ else if (algorithm() == QSsl::Dsa)
+ return QByteArrayLiteral("-----END DSA PRIVATE KEY-----");
+ else if (algorithm() == QSsl::Ec)
+ return QByteArrayLiteral("-----END EC PRIVATE KEY-----");
+ else if (algorithm() == QSsl::Dh)
+ return QByteArrayLiteral("-----END PRIVATE KEY-----");
+
+ Q_UNREACHABLE_RETURN({});
+}
+
+/*!
+ \class X509Certificate
+ \internal (Network-private)
+ \brief X509Certificate is an abstract class that allows a TLS backend to
+ provide an implementation of the QSslCertificate class.
+
+ This class provides an interface that must be reimplemented by a TLS plugin,
+ that supports QSslCertificate. Most functions are pure virtual, and thus
+ have to be overridden. For some of them, an empty overrider is acceptable,
+ though a part of functionality in QSslCertificate will be missing.
+
+ \sa QTlsBackend::createCertificate(), QTlsBackend::X509PemReader(), QTlsBackend::X509DerReader()
+*/
+
+/*!
+ \fn bool X509Certificate::isEqual(const X509Certificate &other) const
+ \internal
+
+ This function is expected to return \c true if this certificate is the same as
+ the \a other, \c false otherwise. Used by QSslCertificate's comparison operators.
+*/
+
+/*!
+ \fn bool X509Certificate::isNull() const
+ \internal
+
+ Returns true if this certificate was default-constructed and not initialized yet.
+ This function is called by QSslCertificate::isNull().
+
+ \sa QSslCertificate::isNull()
+*/
+
+/*!
+ \fn bool X509Certificate::isSelfSigned() const
+ \internal
+
+ This function is needed to implement QSslCertificate::isSelfSigned()
+
+ \sa QSslCertificate::isSelfSigned()
+*/
+
+/*!
+ \fn QByteArray X509Certificate::version() const
+ \internal
+
+ Implements QSslCertificate::version().
+
+ \sa QSslCertificate::version()
+*/
+
+/*!
+ \fn QByteArray X509Certificate::serialNumber() const
+ \internal
+
+ This function is expected to return the certificate's serial number string in
+ hexadecimal format.
+
+ \sa QSslCertificate::serialNumber()
+*/
+
+/*!
+ \fn QStringList X509Certificate::issuerInfo(QSslCertificate::SubjectInfo subject) const
+ \internal
+
+ This function is expected to return the issuer information for the \a subject
+ from the certificate, or an empty list if there is no information for subject
+ in the certificate. There can be more than one entry of each type.
+
+ \sa QSslCertificate::issuerInfo().
+*/
+
+/*!
+ \fn QStringList X509Certificate::issuerInfo(const QByteArray &attribute) const
+ \internal
+
+ This function is expected to return the issuer information for attribute from
+ the certificate, or an empty list if there is no information for \a attribute
+ in the certificate. There can be more than one entry for an attribute.
+
+ \sa QSslCertificate::issuerInfo().
+*/
+
+/*!
+ \fn QStringList X509Certificate::subjectInfo(QSslCertificate::SubjectInfo subject) const
+ \internal
+
+ This function is expected to return the information for the \a subject, or an empty list
+ if there is no information for subject in the certificate. There can be more than one
+ entry of each type.
+
+ \sa QSslCertificate::subjectInfo().
+*/
+
+/*!
+ \fn QStringList X509Certificate::subjectInfo(const QByteArray &attribute) const
+ \internal
+
+ This function is expected to return the subject information for \a attribute, or
+ an empty list if there is no information for attribute in the certificate.
+ There can be more than one entry for an attribute.
+
+ \sa QSslCertificate::subjectInfo().
+*/
+
+/*!
+ \fn QList<QByteArray> X509Certificate::subjectInfoAttributes() const
+ \internal
+
+ This function is expected to return a list of the attributes that have values
+ in the subject information of this certificate. The information associated
+ with a given attribute can be accessed using the subjectInfo() method. Note
+ that this list may include the OIDs for any elements that are not known by
+ the TLS backend.
+
+ \note This function is needed for QSslCertificate:::subjectInfoAttributes().
+
+ \sa subjectInfo()
+*/
+
+/*!
+ \fn QList<QByteArray> X509Certificate::issuerInfoAttributes() const
+ \internal
+
+ This function is expected to return a list of the attributes that have
+ values in the issuer information of this certificate. The information
+ associated with a given attribute can be accessed using the issuerInfo()
+ method. Note that this list may include the OIDs for any
+ elements that are not known by the TLS backend.
+
+ \note This function implements QSslCertificate::issuerInfoAttributes().
+
+ \sa issuerInfo()
+*/
+
+/*!
+ \fn QMultiMap<QSsl::AlternativeNameEntryType, QString> X509Certificate::subjectAlternativeNames() const
+ \internal
+
+ This function is expected to return the list of alternative subject names for
+ this certificate. The alternative names typically contain host names, optionally
+ with wildcards, that are valid for this certificate.
+
+ \sa subjectInfo()
+*/
+
+/*!
+ \fn QDateTime X509Certificate::effectiveDate() const
+ \internal
+
+ This function is expected to return the date-time that the certificate
+ becomes valid, or an empty QDateTime if this is a null certificate.
+
+ \sa expiryDate()
+*/
+
+/*!
+ \fn QDateTime X509Certificate::expiryDate() const
+ \internal
+
+ This function is expected to return the date-time that the certificate expires,
+ or an empty QDateTime if this is a null certificate.
+
+ \sa effectiveDate()
+*/
+
+/*!
+ \fn qsizetype X509Certificate::numberOfExtensions() const
+ \internal
+
+ This function is expected to return the number of X509 extensions of
+ this certificate.
+*/
+
+/*!
+ \fn QString X509Certificate::oidForExtension(qsizetype i) const
+ \internal
+
+ This function is expected to return the ASN.1 OID for the extension
+ with index \a i.
+
+ \sa numberOfExtensions()
+*/
+
+/*!
+ \fn QString X509Certificate::nameForExtension(qsizetype i) const
+ \internal
+
+ This function is expected to return the name for the extension
+ with index \a i. If no name is known for the extension then the
+ OID will be returned.
+
+ \sa numberOfExtensions(), oidForExtension()
+*/
+
+/*!
+ \fn QVariant X509Certificate::valueForExtension(qsizetype i) const
+ \internal
+
+ This function is expected to return the value of the extension
+ with index \a i. The structure of the value returned depends on
+ the extension type
+
+ \sa numberOfExtensions()
+*/
+
+/*!
+ \fn bool X509Certificate::isExtensionCritical(qsizetype i) const
+ \internal
+
+ This function is expected to return the criticality of the extension
+ with index \a i.
+
+ \sa numberOfExtensions()
+*/
+
+/*!
+ \fn bool X509Certificate::isExtensionSupported(qsizetype i) const
+ \internal
+
+ This function is expected to return \c true if this extension is supported.
+ In this case, supported simply means that the structure of the QVariant returned
+ by the valueForExtension() accessor will remain unchanged between versions.
+
+ \sa numberOfExtensions()
+*/
+
+/*!
+ \fn QByteArray X509Certificate::toPem() const
+ \internal
+
+ This function is expected to return this certificate converted to a PEM (Base64)
+ encoded representation.
+*/
+
+/*!
+ \fn QByteArray X509Certificate::toDer() const
+ \internal
+
+ This function is expected to return this certificate converted to a DER (binary)
+ encoded representation.
+*/
+
+/*!
+ \fn QString X509Certificate::toText() const
+ \internal
+
+ This function is expected to return this certificate converted to a human-readable
+ text representation.
+*/
+
+/*!
+ \fn Qt::HANDLE X509Certificate::handle() const
+ \internal
+
+ This function is expected to return a pointer to the native certificate handle,
+ if there is one, else nullptr.
+*/
+
+/*!
+ \fn size_t X509Certificate::hash(size_t seed) const
+ \internal
+
+ This function is expected to return the hash value for this certificate,
+ using \a seed to seed the calculation.
+*/
+
+/*!
+ \internal
+
+ Destroys this certificate.
+*/
+X509Certificate::~X509Certificate() = default;
+
+/*!
+ \internal
+
+ Returns the certificate subject's public key.
+*/
+TlsKey *X509Certificate::publicKey() const
+{
+ return nullptr;
+}
+
+#if QT_CONFIG(ssl)
+
+/*!
+ \class TlsCryptograph
+ \internal (Network-private)
+ \brief TlsCryptograph is an abstract class, that allows a TLS plugin to implement QSslSocket.
+
+ This abstract base class provides an interface that must be reimplemented by a TLS plugin,
+ that supports QSslSocket. A class, implementing TlsCryptograph's interface, is responsible
+ for TLS handshake, reading and writing encryped application data; it is expected
+ to work with QSslSocket and it's private implementation - QSslSocketPrivate.
+ QSslSocketPrivate provides access to its read/write buffers, QTcpSocket it
+ internally uses for connecting, reading and writing. QSslSocketPrivate
+ can also be used for reporting errors and storing the certificates received
+ during the handshake phase.
+
+ \note Most of the functions in this class are pure virtual and have no actual implementation
+ in the QtNetwork module. This documentation is mostly conceptual and only describes what those
+ functions are expected to do, but not how they must be implemented.
+
+ \sa QTlsBackend::createTlsCryptograph()
+*/
+
+/*!
+ \fn void TlsCryptograph::init(QSslSocket *q, QSslSocketPrivate *d)
+ \internal
+
+ When initializing this TlsCryptograph, QSslSocket will pass a pointer to self and
+ its d-object using this function.
+*/
+
+/*!
+ \fn QList<QSslError> TlsCryptograph::tlsErrors() const
+ \internal
+
+ Returns a list of QSslError, describing errors encountered during
+ the TLS handshake.
+
+ \sa QSslSocket::sslHandshakeErrors()
+*/
+
+/*!
+ \fn void TlsCryptograph::startClientEncryption()
+ \internal
+
+ A client-side QSslSocket calls this function after its internal TCP socket
+ establishes a connection with a remote host, or from QSslSocket::startClientEncryption().
+ This TlsCryptograph is expected to initialize some implementation-specific TLS context,
+ if needed, and then start the client side of the TLS handshake (for example, by calling
+ transmit()), using TCP socket from QSslSocketPrivate.
+
+ \sa init(), transmit(), QSslSocket::startClientEncryption(), QSslSocket::connectToHostEncrypted()
+*/
+
+/*!
+ \fn void TlsCryptograph::startServerEncryption()
+ \internal
+
+ This function is called by QSslSocket::startServerEncryption(). The TlsCryptograph
+ is expected to initialize some implementation-specific TLS context, if needed,
+ and then try to read the ClientHello message and continue the TLS handshake
+ (for example, by calling transmit()).
+
+ \sa transmit(), QSslSocket::startServerEncryption()
+*/
+
+/*!
+ \fn void TlsCryptograph::continueHandshake()
+ \internal
+
+ QSslSocket::resume() calls this function if its pause mode is QAbstractSocket::PauseOnSslErrors,
+ and errors, found during the handshake, were ignored. If implemented, this function is expected
+ to emit QSslSocket::encrypted().
+
+ \sa QAbstractSocket::pauseMode(), QSslSocket::sslHandshakeErrors(), QSslSocket::ignoreSslErrors(), QSslSocket::resume()
+*/
+
+/*!
+ \fn void TlsCryptograph::disconnectFromHost()
+ \internal
+
+ This function is expected to call disconnectFromHost() on the TCP socket
+ that can be obtained from QSslSocketPrivate. Any additional actions
+ are implementation-specific (e.g., sending shutdown alert message).
+
+*/
+
+/*!
+ \fn void TlsCryptograph::disconnected()
+ \internal
+
+ This function is called when the remote has disconnected. If there
+ is data left to be read you may ignore the maxReadBufferSize restriction
+ and read it all now.
+*/
+
+/*!
+ \fn QSslCipher TlsCryptograph::sessionCipher() const
+ \internal
+
+ This function returns a QSslCipher object describing the ciphersuite negotiated
+ during the handshake.
+*/
+
+/*!
+ \fn QSsl::SslProtocol TlsCryptograph::sessionProtocol() const
+ \internal
+
+ This function returns the version of TLS (or DTLS) protocol negotiated during the handshake.
+*/
+
+/*!
+ \fn void TlsCryptograph::transmit()
+ \internal
+
+ This function is responsible for reading and writing data. The meaning of these I/O
+ operations depends on an implementation-specific TLS state machine. These read and write
+ operations can be reading and writing parts of a TLS handshake (e.g. by calling handshake-specific
+ functions), or reading and writing application data (if encrypted connection was already
+ established). transmit() is expected to use the QSslSocket's TCP socket (accessible via
+ QSslSocketPrivate) to read the incoming data and write the outgoing data. When in encrypted
+ state, transmit() is also using QSslSocket's internal read and write buffers: the read buffer
+ to fill with decrypted incoming data; the write buffer - for the data to encrypt and send.
+ This TlsCryptograph can also use QSslSocketPrivate to check which TLS errors were ignored during
+ the handshake.
+
+ \note This function is responsible for emitting QSslSocket's signals, that occur during the
+ handshake (e.g. QSslSocket::sslErrors() or QSslSocket::encrypted()), and also read/write signals,
+ e.g. QSslSocket::bytesWritten() and QSslSocket::readyRead().
+
+ \sa init()
+*/
+
+/*!
+ \internal
+
+ Destroys this object.
+*/
+TlsCryptograph::~TlsCryptograph() = default;
+
+/*!
+ \internal
+
+ This function allows to share QSslContext between several QSslSocket objects.
+ The default implementation does nothing.
+
+ \note The definition of the class QSslContext is implementation-specific.
+
+ \sa sslContext()
+*/
+void TlsCryptograph::checkSettingSslContext(std::shared_ptr<QSslContext> tlsContext)
+{
+ Q_UNUSED(tlsContext);
+}
+
+/*!
+ \internal
+
+ Returns the context previously set by checkSettingSslContext() or \nullptr,
+ if no context was set. The default implementation returns \nullptr.
+
+ \sa checkSettingSslContext()
+*/
+std::shared_ptr<QSslContext> TlsCryptograph::sslContext() const
+{
+ return {};
+}
+
+/*!
+ \internal
+
+ If this TLS backend supports reporting errors before handshake is finished,
+ e.g. from a verification callback function, enableHandshakeContinuation()
+ allows this object to continue handshake. The default implementation does
+ nothing.
+
+ \sa QSslSocket::handshakeInterruptedOnError(), QSslConfiguration::setHandshakeMustInterruptOnError()
+*/
+void TlsCryptograph::enableHandshakeContinuation()
+{
+}
+
+/*!
+ \internal
+
+ Windows and OpenSSL-specific, only used internally by Qt's OpenSSL TLS backend.
+
+ \note The default empty implementation is sufficient.
+*/
+void TlsCryptograph::cancelCAFetch()
+{
+}
+
+/*!
+ \internal
+
+ Windows and Schannel-specific, only used by Qt's Schannel TLS backend, in
+ general, if a backend has its own buffer where it stores undecrypted data
+ then it must report true if it contains any data through this function.
+
+ \note The default empty implementation, returning \c false is sufficient.
+*/
+bool TlsCryptograph::hasUndecryptedData() const
+{
+ return false;
+}
+
+/*!
+ \internal
+
+ Returns the list of OCSP (Online Certificate Status Protocol) responses,
+ received during the handshake. The default implementation returns an empty
+ list.
+*/
+QList<QOcspResponse> TlsCryptograph::ocsps() const
+{
+ return {};
+}
+
+/*!
+ \internal
+
+ A helper function that can be used during a handshake. Returns \c true if the \a peerName
+ matches one of subject alternative names or common names found in the \a certificate.
+*/
+bool TlsCryptograph::isMatchingHostname(const QSslCertificate &certificate, const QString &peerName)
+{
+ return QSslSocketPrivate::isMatchingHostname(certificate, peerName);
+}
+
+/*!
+ \internal
+ Calls QAbstractSocketPrivate::setErrorAndEmit() for \a d, passing \a errorCode and
+ \a errorDescription as parameters.
+*/
+void TlsCryptograph::setErrorAndEmit(QSslSocketPrivate *d, QAbstractSocket::SocketError errorCode,
+ const QString &errorDescription) const
+{
+ Q_ASSERT(d);
+ d->setErrorAndEmit(errorCode, errorDescription);
+}
+
+#if QT_CONFIG(dtls)
+/*!
+ \class DtlsBase
+ \internal (Network-private)
+ \brief DtlsBase is a base class for the classes DtlsCryptograph and DtlsCookieVerifier.
+
+ DtlsBase is the base class for the classes DtlsCryptograph and DtlsCookieVerifier. It's
+ an abstract class, an interface that these before-mentioned classes share. It allows to
+ set, get and clear the last error that occurred, set and get cookie generation parameters,
+ set and get QSslConfiguration.
+
+ \note This class is not supposed to be inherited directly, it's only needed by DtlsCryptograph
+ and DtlsCookieVerifier.
+
+ \sa QDtls, QDtlsClientVerifier, DtlsCryptograph, DtlsCookieVerifier
+*/
+
+/*!
+ \fn void DtlsBase::setDtlsError(QDtlsError code, const QString &description)
+ \internal
+
+ Sets the last error to \a code and its textual description to \a description.
+
+ \sa QDtlsError, error(), errorString()
+*/
+
+/*!
+ \fn QDtlsError DtlsBase::error() const
+ \internal
+
+ This function, when overridden, is expected to return the code for the last error that occurred.
+ If no error occurred it should return QDtlsError::NoError.
+
+ \sa QDtlsError, errorString(), setDtlsError()
+*/
+
+/*!
+ \fn QDtlsError DtlsBase::errorString() const
+ \internal
+
+ This function, when overridden, is expected to return the textual description for the last error
+ that occurred or an empty string if no error occurred.
+
+ \sa QDtlsError, error(), setDtlsError()
+*/
+
+/*!
+ \fn void DtlsBase::clearDtlsError()
+ \internal
+
+ This function is expected to set the error code for the last error to QDtlsError::NoError and
+ its textual description to an empty string.
+
+ \sa QDtlsError, setDtlsError(), error(), errorString()
+*/
+
+/*!
+ \fn void DtlsBase::setConfiguration(const QSslConfiguration &configuration)
+ \internal
+
+ Sets a TLS configuration that an object of a class inheriting from DtlsCookieVerifier or
+ DtlsCryptograph will use, to \a configuration.
+
+ \sa configuration()
+*/
+
+/*!
+ \fn QSslConfiguration DtlsBase::configuration() const
+ \internal
+
+ Returns TLS configuration this object is using (either set by setConfiguration()
+ previously, or the default DTLS configuration).
+
+ \sa setConfiguration(), QSslConfiguration::defaultDtlsConfiguration()
+*/
+
+/*!
+ \fn bool DtlsBase::setCookieGeneratorParameters(const QDtlsClientVerifier::GeneratorParameters &params)
+ \internal
+
+ Sets the DTLS cookie generation parameters that DtlsCookieVerifier or DtlsCryptograph will use to
+ \a params.
+
+ \note This function returns \c false if parameters were invalid - if the secret was empty. Otherwise,
+ this function must return true.
+
+ \sa QDtlsClientVerifier::GeneratorParameters, cookieGeneratorParameters()
+*/
+
+/*!
+ \fn QDtlsClientVerifier::GeneratorParameters DtlsBase::cookieGeneratorParameters() const
+ \internal
+
+ Returns DTLS cookie generation parameters that were either previously set by setCookieGeneratorParameters(),
+ or default parameters.
+
+ \sa setCookieGeneratorParameters()
+*/
+
+/*!
+ \internal
+
+ Destroys this object.
+*/
+DtlsBase::~DtlsBase() = default;
+
+/*!
+ \class DtlsCookieVerifier
+ \internal (Network-private)
+ \brief DtlsCookieVerifier is an interface that allows a TLS plugin to support the class QDtlsClientVerifier.
+
+ DtlsCookieVerifier is an interface, an abstract class, that has to be implemented by
+ a TLS plugin that supports DTLS cookie verification.
+
+ \sa QDtlsClientVerifier
+*/
+
+/*!
+ \fn bool DtlsCookieVerifier::verifyClient(QUdpSocket *socket, const QByteArray &dgram, const QHostAddress &address, quint16 port)
+ \internal
+
+ This function is expected to verify a ClientHello message, found in \a dgram, using \a address,
+ \a port, and cookie generator parameters. The function returns \c true if such cookie was found
+ and \c false otherwise. If no valid cookie was found in the \a dgram, this verifier should use
+ \a socket to send a HelloVerifyRequest message, using \a address and \a port as the destination
+ and a source material for cookie generation, see also
+ \l {RFC 6347, section 4.2.1}
+
+ \sa QDtlsClientVerifier
+*/
+
+/*!
+ \fn QByteArray DtlsCookieVerifier::verifiedHello() const
+ \internal
+
+ Returns the last ClientHello message containing the DTLS cookie that this verifier was
+ able to verify as correct, or an empty byte array.
+
+ \sa verifyClient()
+*/
+
+/*!
+ \class DtlsCryptograph
+ \internal (Network-private)
+ \brief DtlsCryptograph is an interface that allows a TLS plugin to implement the class QDtls.
+
+ DtlsCryptograph is an abstract class; a TLS plugin can provide a class, inheriting from
+ DtlsCryptograph and implementing its pure virtual functions, thus implementing the class
+ QDtls and enabling DTLS over UDP.
+
+ To write DTLS datagrams, a class, inheriting DtlsCryptograph, is expected to use
+ QUdpSocket. In general, all reading is done externally, so DtlsCryptograph is
+ expected to only write into QUdpSocket, check possible socket errors, change socket
+ options if needed.
+
+ \note All functions in this class are pure virtual and have no actual implementation
+ in the QtNetwork module. This documentation is mostly conceptual and only describes
+ what those functions are expected to do, but not how they must be implemented.
+
+ \sa QDtls, QUdpSocket
+*/
+
+/*!
+ \fn QSslSocket::SslMode DtlsCryptograph::cryptographMode() const
+ \internal
+
+ Returns the mode (client or server) this object operates in.
+
+ \note This mode is set once when a new DtlsCryptograph is created
+ by QTlsBackend and cannot change.
+
+ \sa QTlsBackend::createDtlsCryptograph()
+*/
+
+/*!
+ \fn void DtlsCryptograph::setPeer(const QHostAddress &addr, quint16 port, const QString &name)
+ \internal
+
+ Sets the remote peer's address to \a addr and remote port to \a port. \a name,
+ if not empty, is to be used when validating the peer's certificate.
+
+ \sa peerAddress(), peerPort(), peerVerificationName()
+*/
+
+/*!
+ \fn QHostAddress DtlsCryptograph::peerAddress() const
+ \internal
+
+ Returns the remote peer's address previously set by setPeer() or,
+ if no address was set, an empty address.
+
+ \sa setPeer()
+*/
+
+/*!
+ \fn quint16 DtlsCryptograph::peerPort() const
+ \internal
+
+ Returns the remote peer's port previously set by setPeer() or
+ 0 if no port was set.
+
+ \sa setPeer(), peerAddress()
+*/
+
+/*!
+ \fn void DtlsCryptograph::setPeerVerificationName(const QString &name)
+ \internal
+
+ Sets the host name to use during certificate validation to \a name.
+
+ \sa peerVerificationName(), setPeer()
+*/
+
+/*!
+ \fn QString DtlsCryptograph::peerVerificationName() const
+ \internal
+
+ Returns the name that this object is using during the certificate validation,
+ previously set by setPeer() or setPeerVerificationName(). Returns an empty string
+ if no peer verification name was set.
+
+ \sa setPeer(), setPeerVerificationName()
+*/
+
+/*!
+ \fn void DtlsCryptograph::setDtlsMtuHint(quint16 mtu)
+ \internal
+
+ Sets the maximum transmission unit (MTU), if it is supported by a TLS implementation, to \a mtu.
+
+ \sa dtlsMtuHint()
+*/
+
+/*!
+ \fn quint16 DtlsCryptograph::dtlsMtuHint() const
+ \internal
+
+ Returns the value of the maximum transmission unit either previously set by setDtlsMtuHint(),
+ or some implementation-specific value (guessed or somehow known to this DtlsCryptograph).
+
+ \sa setDtlsMtuHint()
+*/
+
+/*!
+ \fn QDtls::HandshakeState DtlsCryptograph::state() const
+ \internal
+
+ Returns the current handshake state for this DtlsCryptograph (not started, in progress,
+ peer verification error found, complete).
+
+ \sa isConnectionEncrypted(), startHandshake()
+*/
+
+/*!
+ \fn bool DtlsCryptograph::isConnectionEncrypted() const
+ \internal
+
+ Returns \c true if this DtlsCryptograph has completed a handshake without validation
+ errors (or these errors were ignored). Returns \c false otherwise.
+*/
+
+/*!
+ \fn bool DtlsCryptograph::startHandshake(QUdpSocket *socket, const QByteArray &dgram)
+ \internal
+
+ This function is expected to initialize some implementation-specific context and to start a DTLS
+ handshake, using \a socket to write datagrams (but not to read them). If this object is operating
+ as a server, \a dgram is non-empty and contains the ClientHello message. This function returns
+ \c true if no error occurred (and this DtlsCryptograph's state switching to
+ QDtls::HandshakeState::HandshakeInProgress), \c false otherwise.
+
+ \sa continueHandshake(), handleTimeout(), resumeHandshake(), abortHandshake(), state()
+*/
+
+/*!
+ \fn bool DtlsCryptograph::handleTimeout(QUdpSocket *socket)
+ \internal
+
+ In case a timeout occurred during the handshake, allows to re-transmit the last message,
+ using \a socket to write the datagram. Returns \c true if no error occurred, \c false otherwise.
+
+ \sa QDtls::handshakeTimeout(), QDtls::handleTimeout()
+*/
+
+/*!
+ \fn bool DtlsCryptograph::continueHandshake(QUdpSocket *socket, const QByteArray &dgram)
+ \internal
+
+ Continues the handshake, using \a socket to write datagrams (a handshake-specific message).
+ \a dgram contains the peer's handshake-specific message. Returns \c false in case some error
+ was encountered (this can include socket-related errors and errors found during the certificate
+ validation). Returns \c true if the handshake was complete successfully, or is still in progress.
+
+ This function, depending on the implementation-specific state machine, may leave the handshake
+ state in QDtls::HandshakeState::HandshakeInProgress, or switch to QDtls::HandshakeState::HandshakeComplete
+ or QDtls::HandshakeState::PeerVerificationFailed.
+
+ This function may store the peer's certificate (or chain of certificates), extract and store
+ the information about the negotiated session protocol and ciphersuite.
+
+ \sa startHandshake()
+*/
+
+/*!
+ \fn bool DtlsCryptograph::resumeHandshake(QUdpSocket *socket)
+ \internal
+
+ If peer validation errors were found duing the handshake, this function tries to
+ continue and complete the handshake. If errors were ignored, the function switches
+ this object's state to QDtls::HandshakeState::HandshakeComplete and returns \c true.
+
+ \sa abortHandshake()
+*/
+
+/*!
+ \fn void DtlsCryptograph::abortHandshake(QUdpSocket *socket)
+ \internal
+
+ Aborts the handshake if it's in progress or in the state QDtls::HandshakeState::PeerVerificationFailed.
+ The use of \a socket is implementation-specific (for example, this DtlsCryptograph may send
+ ShutdownAlert message).
+
+ \sa resumeHandshake()
+*/
+
+/*!
+ \fn void DtlsCryptograph::sendShutdownAlert(QUdpSocket *socket)
+ \internal
+
+ If the underlying TLS library provides the required functionality, this function
+ may sent ShutdownAlert message using \a socket.
+*/
+
+/*!
+ \fn QList<QSslError> DtlsCryptograph::peerVerificationErrors() const
+ \internal
+
+ Returns the list of errors that this object encountered during DTLS handshake
+ and certificate validation.
+
+ \sa ignoreVerificationErrors()
+*/
+
+/*!
+ \fn void DtlsCryptograph::ignoreVerificationErrors(const QList<QSslError> &errorsToIgnore)
+ \internal
+
+ Tells this object to ignore errors from \a errorsToIgnore when they are found during
+ DTLS handshake.
+
+ \sa peerVerificationErrors()
+*/
+
+/*!
+ \fn QSslCipher DtlsCryptograph::dtlsSessionCipher() const
+ \internal
+
+ If such information is available, returns the ciphersuite, negotiated during
+ the handshake.
+
+ \sa continueHandshake(), dtlsSessionProtocol()
+*/
+
+/*!
+ \fn QSsl::SslProtocol DtlsCryptograph::dtlsSessionProtocol() const
+ \internal
+
+ Returns the version of the session protocol that was negotiated during the handshake or
+ QSsl::UnknownProtocol if the handshake is incomplete or no information about the session
+ protocol is available.
+
+ \sa continueHandshake(), dtlsSessionCipher()
+*/
+
+/*!
+ \fn qint64 DtlsCryptograph::writeDatagramEncrypted(QUdpSocket *socket, const QByteArray &dgram)
+ \internal
+
+ If this DtlsCryptograph is in the QDtls::HandshakeState::HandshakeComplete state, this function
+ encrypts \a dgram and writes this encrypted data into \a socket.
+
+ Returns the number of bytes (of \a dgram) written, or -1 in case of error. This function should
+ set the error code and description if some error was encountered.
+
+ \sa decryptDatagram()
+*/
+
+/*!
+ \fn QByteArray DtlsCryptograph::decryptDatagram(QUdpSocket *socket, const QByteArray &dgram)
+ \internal
+
+ If this DtlsCryptograph is in the QDtls::HandshakeState::HandshakeComplete state, decrypts \a dgram.
+ The use of \a socket is implementation-specific. This function should return an empty byte array
+ and set the error code and description if some error was encountered.
+*/
+
+#endif // QT_CONFIG(dtls)
+#endif // QT_CONFIG(ssl)
+
+} // namespace QTlsPrivate
+
+#if QT_CONFIG(ssl)
+/*!
+ \internal
+*/
+Q_NETWORK_EXPORT void qt_ForceTlsSecurityLevel()
+{
+ if (auto *backend = QSslSocketPrivate::tlsBackendInUse())
+ backend->forceAutotestSecurityLevel();
+}
+
+#endif // QT_CONFIG(ssl)
+
+QT_END_NAMESPACE
+
+#include "moc_qtlsbackend_p.cpp"
diff --git a/src/network/ssl/qtlsbackend_p.h b/src/network/ssl/qtlsbackend_p.h
new file mode 100644
index 0000000000..090531014b
--- /dev/null
+++ b/src/network/ssl/qtlsbackend_p.h
@@ -0,0 +1,402 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QTLSBACKEND_P_H
+#define QTLSBACKEND_P_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.
+//
+
+#include <QtNetwork/private/qtnetworkglobal_p.h>
+
+#include "qsslconfiguration.h"
+#include "qsslerror.h"
+#include "qssl_p.h"
+
+#if QT_CONFIG(dtls)
+#include "qdtls.h"
+#endif
+
+#include <QtNetwork/qsslcertificate.h>
+#include <QtNetwork/qsslcipher.h>
+#include <QtNetwork/qsslkey.h>
+#include <QtNetwork/qssl.h>
+
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qnamespace.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qglobal.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qmap.h>
+
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+
+class QSslPreSharedKeyAuthenticator;
+class QSslSocketPrivate;
+class QHostAddress;
+class QSslContext;
+
+class QSslSocket;
+class QByteArray;
+class QSslCipher;
+class QUdpSocket;
+class QIODevice;
+class QSslError;
+class QSslKey;
+
+namespace QTlsPrivate {
+
+class Q_NETWORK_EXPORT TlsKey {
+public:
+ virtual ~TlsKey();
+
+ using KeyType = QSsl::KeyType;
+ using KeyAlgorithm = QSsl::KeyAlgorithm;
+
+ virtual void decodeDer(KeyType type, KeyAlgorithm algorithm, const QByteArray &der,
+ const QByteArray &passPhrase, bool deepClear) = 0;
+ virtual void decodePem(KeyType type, KeyAlgorithm algorithm, const QByteArray &pem,
+ const QByteArray &passPhrase, bool deepClear) = 0;
+
+ virtual QByteArray toPem(const QByteArray &passPhrase) const = 0;
+ virtual QByteArray derFromPem(const QByteArray &pem, QMap<QByteArray, QByteArray> *headers) const = 0;
+ virtual QByteArray pemFromDer(const QByteArray &der, const QMap<QByteArray, QByteArray> &headers) const = 0;
+
+ virtual void fromHandle(Qt::HANDLE handle, KeyType type) = 0;
+ virtual Qt::HANDLE handle() const = 0;
+
+ virtual bool isNull() const = 0;
+ virtual KeyType type() const = 0;
+ virtual KeyAlgorithm algorithm() const = 0;
+ virtual int length() const = 0;
+
+ virtual void clear(bool deepClear) = 0;
+
+ virtual bool isPkcs8() const = 0;
+
+ virtual QByteArray decrypt(Cipher cipher, const QByteArray &data,
+ const QByteArray &passPhrase, const QByteArray &iv) const = 0;
+ virtual QByteArray encrypt(Cipher cipher, const QByteArray &data,
+ const QByteArray &key, const QByteArray &iv) const = 0;
+
+ QByteArray pemHeader() const;
+ QByteArray pemFooter() const;
+};
+
+class Q_NETWORK_EXPORT X509Certificate
+{
+public:
+ virtual ~X509Certificate();
+
+ virtual bool isEqual(const X509Certificate &other) const = 0;
+ virtual bool isNull() const = 0;
+ virtual bool isSelfSigned() const = 0;
+ virtual QByteArray version() const = 0;
+ virtual QByteArray serialNumber() const = 0;
+ virtual QStringList issuerInfo(QSslCertificate::SubjectInfo subject) const = 0;
+ virtual QStringList issuerInfo(const QByteArray &attribute) const = 0;
+ virtual QStringList subjectInfo(QSslCertificate::SubjectInfo subject) const = 0;
+ virtual QStringList subjectInfo(const QByteArray &attribute) const = 0;
+
+ virtual QList<QByteArray> subjectInfoAttributes() const = 0;
+ virtual QList<QByteArray> issuerInfoAttributes() const = 0;
+ virtual QMultiMap<QSsl::AlternativeNameEntryType, QString> subjectAlternativeNames() const = 0;
+ virtual QDateTime effectiveDate() const = 0;
+ virtual QDateTime expiryDate() const = 0;
+
+ virtual TlsKey *publicKey() const;
+
+ // Extensions. Plugins do not expose internal representation
+ // and cannot rely on QSslCertificate's internals. Thus,
+ // we provide this information 'in pieces':
+ virtual qsizetype numberOfExtensions() const = 0;
+ virtual QString oidForExtension(qsizetype i) const = 0;
+ virtual QString nameForExtension(qsizetype i) const = 0;
+ virtual QVariant valueForExtension(qsizetype i) const = 0;
+ virtual bool isExtensionCritical(qsizetype i) const = 0;
+ virtual bool isExtensionSupported(qsizetype i) const = 0;
+
+ virtual QByteArray toPem() const = 0;
+ virtual QByteArray toDer() const = 0;
+ virtual QString toText() const = 0;
+
+ virtual Qt::HANDLE handle() const = 0;
+
+ virtual size_t hash(size_t seed) const noexcept = 0;
+};
+
+// TLSTODO: consider making those into virtuals in QTlsBackend. After all, we ask the backend
+// to return those pointers if the functionality is supported, but it's a bit odd to have
+// this level of indirection. They are not parts of the classes above because ...
+// you'd then have to ask backend to create a certificate to ... call those
+// functions on a certificate.
+using X509ChainVerifyPtr = QList<QSslError> (*)(const QList<QSslCertificate> &chain,
+ const QString &hostName);
+using X509PemReaderPtr = QList<QSslCertificate> (*)(const QByteArray &pem, int count);
+using X509DerReaderPtr = X509PemReaderPtr;
+using X509Pkcs12ReaderPtr = bool (*)(QIODevice *device, QSslKey *key, QSslCertificate *cert,
+ QList<QSslCertificate> *caCertificates,
+ const QByteArray &passPhrase);
+
+#if QT_CONFIG(ssl)
+// TLS over TCP. Handshake, encryption/decryption.
+class Q_NETWORK_EXPORT TlsCryptograph : public QObject
+{
+public:
+ virtual ~TlsCryptograph();
+
+ virtual void init(QSslSocket *q, QSslSocketPrivate *d) = 0;
+ virtual void checkSettingSslContext(std::shared_ptr<QSslContext> tlsContext);
+ virtual std::shared_ptr<QSslContext> sslContext() const;
+
+ virtual QList<QSslError> tlsErrors() const = 0;
+
+ virtual void startClientEncryption() = 0;
+ virtual void startServerEncryption() = 0;
+ virtual void continueHandshake() = 0;
+ virtual void enableHandshakeContinuation();
+ virtual void disconnectFromHost() = 0;
+ virtual void disconnected() = 0;
+ virtual void cancelCAFetch();
+ virtual QSslCipher sessionCipher() const = 0;
+ virtual QSsl::SslProtocol sessionProtocol() const = 0;
+
+ virtual void transmit() = 0;
+ virtual bool hasUndecryptedData() const;
+ virtual QList<QOcspResponse> ocsps() const;
+
+ static bool isMatchingHostname(const QSslCertificate &cert, const QString &peerName);
+
+ void setErrorAndEmit(QSslSocketPrivate *d, QAbstractSocket::SocketError errorCode,
+ const QString &errorDescription) const;
+};
+#else
+class TlsCryptograph;
+#endif // QT_CONFIG(ssl)
+
+#if QT_CONFIG(dtls)
+
+class Q_NETWORK_EXPORT DtlsBase
+{
+public:
+ virtual ~DtlsBase();
+
+ virtual void setDtlsError(QDtlsError code, const QString &description) = 0;
+
+ virtual QDtlsError error() const = 0;
+ virtual QString errorString() const = 0;
+
+ virtual void clearDtlsError() = 0;
+
+ virtual void setConfiguration(const QSslConfiguration &configuration) = 0;
+ virtual QSslConfiguration configuration() const = 0;
+
+ using GenParams = QDtlsClientVerifier::GeneratorParameters;
+ virtual bool setCookieGeneratorParameters(const GenParams &params) = 0;
+ virtual GenParams cookieGeneratorParameters() const = 0;
+};
+
+// DTLS cookie: generation and verification.
+class Q_NETWORK_EXPORT DtlsCookieVerifier : virtual public DtlsBase
+{
+public:
+ virtual bool verifyClient(QUdpSocket *socket, const QByteArray &dgram,
+ const QHostAddress &address, quint16 port) = 0;
+ virtual QByteArray verifiedHello() const = 0;
+};
+
+// TLS over UDP. Handshake, encryption/decryption.
+class Q_NETWORK_EXPORT DtlsCryptograph : virtual public DtlsBase
+{
+public:
+
+ virtual QSslSocket::SslMode cryptographMode() const = 0;
+ virtual void setPeer(const QHostAddress &addr, quint16 port, const QString &name) = 0;
+ virtual QHostAddress peerAddress() const = 0;
+ virtual quint16 peerPort() const = 0;
+ virtual void setPeerVerificationName(const QString &name) = 0;
+ virtual QString peerVerificationName() const = 0;
+
+ virtual void setDtlsMtuHint(quint16 mtu) = 0;
+ virtual quint16 dtlsMtuHint() const = 0;
+
+ virtual QDtls::HandshakeState state() const = 0;
+ virtual bool isConnectionEncrypted() const = 0;
+
+ virtual bool startHandshake(QUdpSocket *socket, const QByteArray &dgram) = 0;
+ virtual bool handleTimeout(QUdpSocket *socket) = 0;
+ virtual bool continueHandshake(QUdpSocket *socket, const QByteArray &dgram) = 0;
+ virtual bool resumeHandshake(QUdpSocket *socket) = 0;
+ virtual void abortHandshake(QUdpSocket *socket) = 0;
+ virtual void sendShutdownAlert(QUdpSocket *socket) = 0;
+
+ virtual QList<QSslError> peerVerificationErrors() const = 0;
+ virtual void ignoreVerificationErrors(const QList<QSslError> &errorsToIgnore) = 0;
+
+ virtual QSslCipher dtlsSessionCipher() const = 0;
+ virtual QSsl::SslProtocol dtlsSessionProtocol() const = 0;
+
+ virtual qint64 writeDatagramEncrypted(QUdpSocket *socket, const QByteArray &dgram) = 0;
+ virtual QByteArray decryptDatagram(QUdpSocket *socket, const QByteArray &dgram) = 0;
+};
+
+#else
+
+class DtlsCookieVerifier;
+class DtlsCryptograph;
+
+#endif // QT_CONFIG(dtls)
+
+} // namespace QTlsPrivate
+
+// Factory, creating back-end specific implementations of
+// different entities QSslSocket is using.
+class Q_NETWORK_EXPORT QTlsBackend : public QObject
+{
+ Q_OBJECT
+public:
+ QTlsBackend();
+ ~QTlsBackend() override;
+
+ virtual bool isValid() const;
+ virtual long tlsLibraryVersionNumber() const;
+ virtual QString tlsLibraryVersionString() const;
+ virtual long tlsLibraryBuildVersionNumber() const;
+ virtual QString tlsLibraryBuildVersionString() const;
+ virtual void ensureInitialized() const;
+
+ virtual QString backendName() const = 0;
+ virtual QList<QSsl::SslProtocol> supportedProtocols() const = 0;
+ virtual QList<QSsl::SupportedFeature> supportedFeatures() const = 0;
+ virtual QList<QSsl::ImplementedClass> implementedClasses() const = 0;
+
+ // X509 and keys:
+ virtual QTlsPrivate::TlsKey *createKey() const;
+ virtual QTlsPrivate::X509Certificate *createCertificate() const;
+
+ virtual QList<QSslCertificate> systemCaCertificates() const;
+
+ // TLS and DTLS:
+ virtual QTlsPrivate::TlsCryptograph *createTlsCryptograph() const;
+ virtual QTlsPrivate::DtlsCryptograph *createDtlsCryptograph(class QDtls *qObject, int mode) const;
+ virtual QTlsPrivate::DtlsCookieVerifier *createDtlsCookieVerifier() const;
+
+ // TLSTODO - get rid of these function pointers, make them virtuals in
+ // the backend itself. X509 machinery:
+ virtual QTlsPrivate::X509ChainVerifyPtr X509Verifier() const;
+ virtual QTlsPrivate::X509PemReaderPtr X509PemReader() const;
+ virtual QTlsPrivate::X509DerReaderPtr X509DerReader() const;
+ virtual QTlsPrivate::X509Pkcs12ReaderPtr X509Pkcs12Reader() const;
+
+ // Elliptic curves:
+ virtual QList<int> ellipticCurvesIds() const;
+ virtual int curveIdFromShortName(const QString &name) const;
+ virtual int curveIdFromLongName(const QString &name) const;
+ virtual QString shortNameForId(int cid) const;
+ virtual QString longNameForId(int cid) const;
+ virtual bool isTlsNamedCurve(int cid) const;
+
+ // Note: int and not QSslDiffieHellmanParameter::Error - because this class and
+ // its enum are QT_CONFIG(ssl)-conditioned. But not QTlsBackend and
+ // its virtual functions. DH decoding:
+ virtual int dhParametersFromDer(const QByteArray &derData, QByteArray *data) const;
+ virtual int dhParametersFromPem(const QByteArray &pemData, QByteArray *data) const;
+
+ static QList<QString> availableBackendNames();
+ static QString defaultBackendName();
+ static QTlsBackend *findBackend(const QString &backendName);
+ static QTlsBackend *activeOrAnyBackend();
+
+ static QList<QSsl::SslProtocol> supportedProtocols(const QString &backendName);
+ static QList<QSsl::SupportedFeature> supportedFeatures(const QString &backendName);
+ static QList<QSsl::ImplementedClass> implementedClasses(const QString &backendName);
+
+ // Built-in, this is what Qt provides out of the box (depending on OS):
+ static constexpr const int nameIndexSchannel = 0;
+ static constexpr const int nameIndexSecureTransport = 1;
+ static constexpr const int nameIndexOpenSSL = 2;
+ static constexpr const int nameIndexCertOnly = 3;
+
+ static const QString builtinBackendNames[];
+
+ template<class DynamicType, class TLSObject>
+ static DynamicType *backend(const TLSObject &o)
+ {
+ return static_cast<DynamicType *>(o.d->backend.get());
+ }
+
+ static void resetBackend(QSslKey &key, QTlsPrivate::TlsKey *keyBackend);
+
+ static void setupClientPskAuth(QSslPreSharedKeyAuthenticator *auth, const char *hint,
+ int hintLength, unsigned maxIdentityLen, unsigned maxPskLen);
+ static void setupServerPskAuth(QSslPreSharedKeyAuthenticator *auth, const char *identity,
+ const QByteArray &identityHint, unsigned maxPskLen);
+#if QT_CONFIG(ssl)
+ static QSslCipher createCiphersuite(const QString &description, int bits, int supportedBits);
+ static QSslCipher createCiphersuite(const QString &suiteName, QSsl::SslProtocol protocol,
+ const QString &protocolString);
+ static QSslCipher createCiphersuite(const QString &name, const QString &keyExchangeMethod,
+ const QString &encryptionMethod,
+ const QString &authenticationMethod,
+ int bits, QSsl::SslProtocol protocol,
+ const QString &protocolString);
+
+ // Those statics are implemented using QSslSocketPrivate (which is not exported,
+ // unlike QTlsBackend).
+ static QList<QSslCipher> defaultCiphers();
+ static QList<QSslCipher> defaultDtlsCiphers();
+
+ static void setDefaultCiphers(const QList<QSslCipher> &ciphers);
+ static void setDefaultDtlsCiphers(const QList<QSslCipher> &ciphers);
+ static void setDefaultSupportedCiphers(const QList<QSslCipher> &ciphers);
+
+ static void resetDefaultEllipticCurves();
+
+ static void setDefaultCaCertificates(const QList<QSslCertificate> &certs);
+
+ // Many thanks to people who designed QSslConfiguration with hidden
+ // data-members, that sneakily set by some 'friend' classes, having
+ // some twisted logic.
+ static bool rootLoadingOnDemandAllowed(const QSslConfiguration &configuration);
+ static void storePeerCertificate(QSslConfiguration &configuration, const QSslCertificate &peerCert);
+ static void storePeerCertificateChain(QSslConfiguration &configuration,
+ const QList<QSslCertificate> &peerCertificateChain);
+ static void clearPeerCertificates(QSslConfiguration &configuration);
+ // And those are even worse, this is where we don't have the original configuration,
+ // and can have only a copy. So instead we go to d->privateConfiguration.someMember:
+ static void clearPeerCertificates(QSslSocketPrivate *d);
+ static void setPeerSessionShared(QSslSocketPrivate *d, bool shared);
+ static void setSessionAsn1(QSslSocketPrivate *d, const QByteArray &asn1);
+ static void setSessionLifetimeHint(QSslSocketPrivate *d, int hint);
+ using AlpnNegotiationStatus = QSslConfiguration::NextProtocolNegotiationStatus;
+ static void setAlpnStatus(QSslSocketPrivate *d, AlpnNegotiationStatus st);
+ static void setNegotiatedProtocol(QSslSocketPrivate *d, const QByteArray &protocol);
+ static void storePeerCertificate(QSslSocketPrivate *d, const QSslCertificate &peerCert);
+ static void storePeerCertificateChain(QSslSocketPrivate *d, const QList<QSslCertificate> &peerChain);
+ static void addTustedRoot(QSslSocketPrivate *d, const QSslCertificate &rootCert);// TODO: "addTrusted..."
+ // The next one - is a "very important" feature! Kidding ...
+ static void setEphemeralKey(QSslSocketPrivate *d, const QSslKey &key);
+
+ virtual void forceAutotestSecurityLevel();
+#endif // QT_CONFIG(ssl)
+
+ Q_DISABLE_COPY_MOVE(QTlsBackend)
+};
+
+#define QTlsBackend_iid "org.qt-project.Qt.QTlsBackend"
+Q_DECLARE_INTERFACE(QTlsBackend, QTlsBackend_iid);
+
+QT_END_NAMESPACE
+
+#endif // QTLSBACKEND_P_H
diff --git a/src/network/ssl/qwindowscarootfetcher.cpp b/src/network/ssl/qwindowscarootfetcher.cpp
deleted file mode 100644
index c414ca580b..0000000000
--- a/src/network/ssl/qwindowscarootfetcher.cpp
+++ /dev/null
@@ -1,289 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qwindowscarootfetcher_p.h"
-
-#include <QtCore/QThread>
-#include <QtGlobal>
-
-#include <QtCore/qscopeguard.h>
-
-#ifdef QSSLSOCKET_DEBUG
-#include "qssl_p.h" // for debug categories
-#include <QtCore/QElapsedTimer>
-#endif
-
-#include "qsslsocket_p.h" // Transitively includes Wincrypt.h
-
-#if QT_CONFIG(openssl)
-#include "qsslsocket_openssl_p.h"
-#endif
-
-QT_BEGIN_NAMESPACE
-
-class QWindowsCaRootFetcherThread : public QThread
-{
-public:
- QWindowsCaRootFetcherThread()
- {
- qRegisterMetaType<QSslCertificate>();
- setObjectName(QStringLiteral("QWindowsCaRootFetcher"));
- start();
- }
- ~QWindowsCaRootFetcherThread()
- {
- quit();
- wait(15500); // worst case, a running request can block for 15 seconds
- }
-};
-
-Q_GLOBAL_STATIC(QWindowsCaRootFetcherThread, windowsCaRootFetcherThread);
-
-#if QT_CONFIG(openssl)
-namespace {
-
-const QList<QSslCertificate> buildVerifiedChain(const QList<QSslCertificate> &caCertificates,
- PCCERT_CHAIN_CONTEXT chainContext,
- const QString &peerVerifyName)
-{
- // We ended up here because OpenSSL verification failed to
- // build a chain, with intermediate certificate missing
- // but "Authority Information Access" extension present.
- // Also, apparently the normal CA fetching path was disabled
- // by setting custom CA certificates. We convert wincrypt's
- // structures in QSslCertificate and give OpenSSL the second
- // chance to verify the now (apparently) complete chain.
- // In addition, wincrypt gives us a benifit of some checks
- // we don't have in OpenSSL back-end.
- Q_ASSERT(chainContext);
-
- if (!chainContext->cChain)
- return {};
-
- QList<QSslCertificate> verifiedChain;
-
- CERT_SIMPLE_CHAIN *chain = chainContext->rgpChain[chainContext->cChain - 1];
- if (!chain)
- return {};
-
- if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_PARTIAL_CHAIN)
- return {}; // No need to mess with OpenSSL (the chain is still incomplete).
-
- for (DWORD i = 0; i < chain->cElement; ++i) {
- CERT_CHAIN_ELEMENT *element = chain->rgpElement[i];
- QSslCertificate cert(QByteArray(reinterpret_cast<const char*>(element->pCertContext->pbCertEncoded),
- int(element->pCertContext->cbCertEncoded)), QSsl::Der);
-
- if (cert.isBlacklisted())
- return {};
-
- if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_REVOKED) // Good to know!
- return {};
-
- if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_SIGNATURE_VALID)
- return {};
-
- verifiedChain.append(cert);
- }
-
- // We rely on OpenSSL's ability to find other problems.
- const auto tlsErrors = QSslSocketBackendPrivate::verify(caCertificates, verifiedChain, peerVerifyName);
- if (tlsErrors.size())
- verifiedChain.clear();
-
- return verifiedChain;
-}
-
-} // unnamed namespace
-#endif // QT_CONFIG(openssl)
-
-QWindowsCaRootFetcher::QWindowsCaRootFetcher(const QSslCertificate &certificate, QSslSocket::SslMode sslMode,
- const QList<QSslCertificate> &caCertificates, const QString &hostName)
- : cert(certificate), mode(sslMode), explicitlyTrustedCAs(caCertificates), peerVerifyName(hostName)
-{
- moveToThread(windowsCaRootFetcherThread());
-}
-
-QWindowsCaRootFetcher::~QWindowsCaRootFetcher()
-{
-}
-
-void QWindowsCaRootFetcher::start()
-{
- QByteArray der = cert.toDer();
- PCCERT_CONTEXT wincert = CertCreateCertificateContext(X509_ASN_ENCODING, (const BYTE *)der.constData(), der.length());
- if (!wincert) {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl, "QWindowsCaRootFetcher failed to convert certificate to windows form");
-#endif
- emit finished(cert, QSslCertificate());
- deleteLater();
- return;
- }
-
- CERT_CHAIN_PARA parameters;
- memset(&parameters, 0, sizeof(parameters));
- parameters.cbSize = sizeof(parameters);
- // set key usage constraint
- parameters.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
- parameters.RequestedUsage.Usage.cUsageIdentifier = 1;
- LPSTR oid = (LPSTR)(mode == QSslSocket::SslClientMode ? szOID_PKIX_KP_SERVER_AUTH : szOID_PKIX_KP_CLIENT_AUTH);
- parameters.RequestedUsage.Usage.rgpszUsageIdentifier = &oid;
-
-#ifdef QSSLSOCKET_DEBUG
- QElapsedTimer stopwatch;
- stopwatch.start();
-#endif
- PCCERT_CHAIN_CONTEXT chain;
- auto additionalStore = createAdditionalStore();
- BOOL result = CertGetCertificateChain(
- nullptr, //default engine
- wincert,
- nullptr, //current date/time
- additionalStore.get(), //default store (nullptr) or CAs an application trusts
- &parameters,
- 0, //default dwFlags
- nullptr, //reserved
- &chain);
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << "QWindowsCaRootFetcher" << stopwatch.elapsed() << "ms to get chain";
-#endif
-
- QSslCertificate trustedRoot;
- if (result) {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << "QWindowsCaRootFetcher - examining windows chains";
- if (chain->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR)
- qCDebug(lcSsl) << " - TRUSTED";
- else
- qCDebug(lcSsl) << " - NOT TRUSTED" << chain->TrustStatus.dwErrorStatus;
- if (chain->TrustStatus.dwInfoStatus & CERT_TRUST_IS_SELF_SIGNED)
- qCDebug(lcSsl) << " - SELF SIGNED";
- qCDebug(lcSsl) << "QSslSocketBackendPrivate::fetchCaRootForCert - dumping simple chains";
- for (unsigned int i = 0; i < chain->cChain; i++) {
- if (chain->rgpChain[i]->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR)
- qCDebug(lcSsl) << " - TRUSTED SIMPLE CHAIN" << i;
- else
- qCDebug(lcSsl) << " - UNTRUSTED SIMPLE CHAIN" << i << "reason:" << chain->rgpChain[i]->TrustStatus.dwErrorStatus;
- for (unsigned int j = 0; j < chain->rgpChain[i]->cElement; j++) {
- QSslCertificate foundCert(QByteArray((const char *)chain->rgpChain[i]->rgpElement[j]->pCertContext->pbCertEncoded
- , chain->rgpChain[i]->rgpElement[j]->pCertContext->cbCertEncoded), QSsl::Der);
- qCDebug(lcSsl) << " - " << foundCert;
- }
- }
- qCDebug(lcSsl) << " - and" << chain->cLowerQualityChainContext << "low quality chains"; //expect 0, we haven't asked for them
-#endif
-
- //based on http://msdn.microsoft.com/en-us/library/windows/desktop/aa377182%28v=vs.85%29.aspx
- //about the final chain rgpChain[cChain-1] which must begin with a trusted root to be valid
- if (chain->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR
- && chain->cChain > 0) {
- const PCERT_SIMPLE_CHAIN finalChain = chain->rgpChain[chain->cChain - 1];
- // http://msdn.microsoft.com/en-us/library/windows/desktop/aa377544%28v=vs.85%29.aspx
- // rgpElement[0] is the end certificate chain element. rgpElement[cElement-1] is the self-signed "root" certificate element.
- if (finalChain->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR
- && finalChain->cElement > 0) {
- trustedRoot = QSslCertificate(QByteArray((const char *)finalChain->rgpElement[finalChain->cElement - 1]->pCertContext->pbCertEncoded
- , finalChain->rgpElement[finalChain->cElement - 1]->pCertContext->cbCertEncoded), QSsl::Der);
- }
- } else if (explicitlyTrustedCAs.size()) {
- // Setting custom CA in configuration, and those CAs are not trusted by MS.
-#if QT_CONFIG(openssl)
- const auto verifiedChain = buildVerifiedChain(explicitlyTrustedCAs, chain, peerVerifyName);
- if (verifiedChain.size())
- trustedRoot = verifiedChain.last();
-#else
- //It's only OpenSSL code-path that can trigger such a fetch.
- Q_UNREACHABLE();
-#endif
- }
- CertFreeCertificateChain(chain);
- }
- CertFreeCertificateContext(wincert);
-
- emit finished(cert, trustedRoot);
- deleteLater();
-}
-
-QHCertStorePointer QWindowsCaRootFetcher::createAdditionalStore() const
-{
- QHCertStorePointer customStore;
- if (explicitlyTrustedCAs.isEmpty())
- return customStore;
-
- if (HCERTSTORE rawPtr = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, 0, nullptr)) {
- customStore.reset(rawPtr);
-
- unsigned rootsAdded = 0;
- for (const QSslCertificate &caCert : explicitlyTrustedCAs) {
- const auto der = caCert.toDer();
- PCCERT_CONTEXT winCert = CertCreateCertificateContext(X509_ASN_ENCODING,
- reinterpret_cast<const BYTE *>(der.data()),
- DWORD(der.length()));
- if (!winCert) {
-#if defined(QSSLSOCKET_DEBUG)
- qCWarning(lcSsl) << "CA fetcher, failed to convert QSslCertificate"
- << "to the native representation";
-#endif // QSSLSOCKET_DEBUG
- continue;
- }
- const auto deleter = qScopeGuard([winCert](){
- CertFreeCertificateContext(winCert);
- });
- if (CertAddCertificateContextToStore(customStore.get(), winCert, CERT_STORE_ADD_ALWAYS, nullptr))
- ++rootsAdded;
-#if defined(QSSLSOCKET_DEBUG)
- else //Why assert? With flags we're using and winCert check - should not happen!
- Q_ASSERT("CertAddCertificateContextToStore() failed");
-#endif // QSSLSOCKET_DEBUG
- }
- if (!rootsAdded) //Useless store, no cert was added.
- customStore.reset();
-#if defined(QSSLSOCKET_DEBUG)
- } else {
-
- qCWarning(lcSsl) << "CA fetcher, failed to create a custom"
- << "store for explicitly trusted CA certificate";
-#endif // QSSLSOCKET_DEBUG
- }
-
- return customStore;
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qwindowscarootfetcher_p.h b/src/network/ssl/qwindowscarootfetcher_p.h
deleted file mode 100644
index e98e59f0cf..0000000000
--- a/src/network/ssl/qwindowscarootfetcher_p.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QWINDOWSCAROOTFETCHER_P_H
-#define QWINDOWSCAROOTFETCHER_P_H
-
-#include <QtCore/QtGlobal>
-#include <QtCore/QObject>
-
-#include "qsslsocket_p.h"
-
-#include "qsslsocket.h"
-#include "qsslcertificate.h"
-
-#include <memory>
-
-//
-// 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.
-//
-
-QT_BEGIN_NAMESPACE
-
-class QWindowsCaRootFetcher : public QObject
-{
- Q_OBJECT
-public:
- QWindowsCaRootFetcher(const QSslCertificate &certificate, QSslSocket::SslMode sslMode,
- const QList<QSslCertificate> &caCertificates = {},
- const QString &hostName = {});
- ~QWindowsCaRootFetcher();
-public slots:
- void start();
-signals:
- void finished(QSslCertificate brokenChain, QSslCertificate caroot);
-private:
- QHCertStorePointer createAdditionalStore() const;
-
- QSslCertificate cert;
- QSslSocket::SslMode mode;
- // In case the application set CA certificates in the configuration,
- // in the past we did not load missing certs. But this disables
- // recoverable case when a certificate has Authority Information Access
- // extension. So we try to fetch in this scenario also, but in case
- // explicitly trusted root was not in a system store, we'll do
- // additional checks, thus we need 'peerVerifyName':
- QList<QSslCertificate> explicitlyTrustedCAs;
- QString peerVerifyName;
-};
-
-QT_END_NAMESPACE
-
-#endif // QWINDOWSCAROOTFETCHER_P_H
diff --git a/src/network/ssl/ssl.pri b/src/network/ssl/ssl.pri
deleted file mode 100644
index c1eb3d169e..0000000000
--- a/src/network/ssl/ssl.pri
+++ /dev/null
@@ -1,122 +0,0 @@
-HEADERS += ssl/qasn1element_p.h \
- ssl/qssl.h \
- ssl/qssl_p.h \
- ssl/qsslcertificate.h \
- ssl/qsslcertificate_p.h \
- ssl/qsslcertificateextension.h \
- ssl/qsslcertificateextension_p.h \
- ssl/qtls_utils_p.h
-
-SOURCES += ssl/qasn1element.cpp \
- ssl/qssl.cpp \
- ssl/qsslcertificate.cpp \
- ssl/qsslcertificateextension.cpp
-
-!qtConfig(openssl): SOURCES += ssl/qsslcertificate_qt.cpp
-
-qtConfig(ssl) {
- HEADERS += ssl/qsslconfiguration.h \
- ssl/qsslconfiguration_p.h \
- ssl/qsslcipher.h \
- ssl/qsslcipher_p.h \
- ssl/qssldiffiehellmanparameters.h \
- ssl/qssldiffiehellmanparameters_p.h \
- ssl/qsslellipticcurve.h \
- ssl/qsslerror.h \
- ssl/qsslkey.h \
- ssl/qsslkey_p.h \
- ssl/qsslsocket.h \
- ssl/qsslsocket_p.h \
- ssl/qsslpresharedkeyauthenticator.h \
- ssl/qsslpresharedkeyauthenticator_p.h \
- ssl/qocspresponse.h \
- ssl/qocspresponse_p.h
- SOURCES += ssl/qsslconfiguration.cpp \
- ssl/qsslcipher.cpp \
- ssl/qssldiffiehellmanparameters.cpp \
- ssl/qsslellipticcurve.cpp \
- ssl/qsslkey_p.cpp \
- ssl/qsslerror.cpp \
- ssl/qsslsocket.cpp \
- ssl/qsslpresharedkeyauthenticator.cpp \
- ssl/qocspresponse.cpp
-
- qtConfig(schannel) {
- HEADERS += ssl/qsslsocket_schannel_p.h
- SOURCES += ssl/qsslsocket_schannel.cpp \
- ssl/qsslcertificate_schannel.cpp \
- ssl/qsslkey_schannel.cpp \
- ssl/qsslkey_qt.cpp \
- ssl/qssldiffiehellmanparameters_dummy.cpp \
- ssl/qsslellipticcurve_dummy.cpp \
- ssl/qsslsocket_qt.cpp
-
- LIBS_PRIVATE += "-lSecur32" "-lCrypt32" "-lbcrypt" "-lncrypt"
- }
-
- qtConfig(securetransport) {
- HEADERS += ssl/qsslsocket_mac_p.h
- SOURCES += ssl/qssldiffiehellmanparameters_dummy.cpp \
- ssl/qsslkey_qt.cpp \
- ssl/qsslkey_mac.cpp \
- ssl/qsslsocket_mac_shared.cpp \
- ssl/qsslsocket_mac.cpp \
- ssl/qsslsocket_qt.cpp \
- ssl/qsslellipticcurve_dummy.cpp
- }
-
- qtConfig(dtls) {
- HEADERS += ssl/qdtls.h \
- ssl/qdtls_p.h
-
- SOURCES += ssl/qdtls.cpp
- }
-
- qtConfig(openssl) {
- HEADERS += ssl/qsslcontext_openssl_p.h \
- ssl/qsslsocket_openssl_p.h \
- ssl/qsslsocket_openssl_symbols_p.h
- SOURCES += ssl/qsslsocket_openssl_symbols.cpp \
- ssl/qssldiffiehellmanparameters_openssl.cpp \
- ssl/qsslcertificate_openssl.cpp \
- ssl/qsslellipticcurve_openssl.cpp \
- ssl/qsslkey_openssl.cpp \
- ssl/qsslsocket_openssl.cpp \
- ssl/qsslcontext_openssl.cpp \
-
- qtConfig(dtls) {
- HEADERS += ssl/qdtls_openssl_p.h
- SOURCES += ssl/qdtls_openssl.cpp
- }
-
- qtConfig(ocsp): HEADERS += ssl/qocsp_p.h
-
- QMAKE_CXXFLAGS += -DOPENSSL_API_COMPAT=0x10100000L
-
- darwin:SOURCES += ssl/qsslsocket_mac_shared.cpp
-
- android:!android-embedded: SOURCES += ssl/qsslsocket_openssl_android.cpp
-
- # Add optional SSL libs
- # Static linking of OpenSSL with msvc:
- # - Binaries http://slproweb.com/products/Win32OpenSSL.html
- # - also needs -lUser32 -lAdvapi32 -lGdi32 -lCrypt32
- # - libs in <OPENSSL_DIR>\lib\VC\static
- # - configure: -openssl -openssl-linked -I <OPENSSL_DIR>\include -L <OPENSSL_DIR>\lib\VC\static OPENSSL_LIBS="-lUser32 -lAdvapi32 -lGdi32" OPENSSL_LIBS_DEBUG="-lssleay32MDd -llibeay32MDd" OPENSSL_LIBS_RELEASE="-lssleay32MD -llibeay32MD"
-
- qtConfig(openssl-linked): {
- android {
- build_pass|single_android_abi: LIBS_PRIVATE += -lssl_$${QT_ARCH} -lcrypto_$${QT_ARCH}
- } else: QMAKE_USE_FOR_PRIVATE += openssl
- } else: \
- QMAKE_USE_FOR_PRIVATE += openssl/nolink
- win32 {
- LIBS_PRIVATE += -lcrypt32
- HEADERS += ssl/qwindowscarootfetcher_p.h
- SOURCES += ssl/qwindowscarootfetcher.cpp
- }
- }
-}
-
-HEADERS += ssl/qpassworddigestor.h
-SOURCES += ssl/qpassworddigestor.cpp