summaryrefslogtreecommitdiffstats
path: root/src/network
diff options
context:
space:
mode:
Diffstat (limited to 'src/network')
-rw-r--r--src/network/CMakeLists.txt7
-rw-r--r--src/network/access/http2/http2protocol_p.h2
-rw-r--r--src/network/access/qformdatabuilder.cpp363
-rw-r--r--src/network/access/qformdatabuilder.h120
-rw-r--r--src/network/access/qhttp2connection.cpp2
-rw-r--r--src/network/access/qhttp2protocolhandler.cpp8
-rw-r--r--src/network/access/qhttpheaders.cpp52
-rw-r--r--src/network/access/qhttpmultipart.cpp8
-rw-r--r--src/network/access/qhttpmultipart_p.h15
-rw-r--r--src/network/access/qhttpnetworkconnection.cpp67
-rw-r--r--src/network/access/qhttpnetworkconnection_p.h7
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel.cpp147
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel_p.h5
-rw-r--r--src/network/access/qhttpnetworkrequest.cpp10
-rw-r--r--src/network/access/qhttpnetworkrequest_p.h4
-rw-r--r--src/network/access/qhttpthreaddelegate.cpp36
-rw-r--r--src/network/access/qnetworkaccessmanager.cpp40
-rw-r--r--src/network/access/qnetworkaccessmanager.h12
-rw-r--r--src/network/access/qnetworkreplyhttpimpl.cpp19
-rw-r--r--src/network/access/qnetworkreplywasmimpl.cpp1
-rw-r--r--src/network/access/qnetworkrequest.cpp13
-rw-r--r--src/network/access/qnetworkrequest.h1
-rw-r--r--src/network/access/qnetworkrequestfactory.cpp4
-rw-r--r--src/network/access/qnetworkrequestfactory.h2
-rw-r--r--src/network/access/qrestaccessmanager.cpp2
-rw-r--r--src/network/access/qrestaccessmanager.h2
-rw-r--r--src/network/access/qrestaccessmanager_p.h3
-rw-r--r--src/network/access/qrestreply.cpp4
-rw-r--r--src/network/access/qrestreply.h2
-rw-r--r--src/network/android/jar/build.gradle4
-rw-r--r--src/network/android/jar/src/org/qtproject/qt/android/network/QtNetwork.java10
-rw-r--r--src/network/kernel/qdnslookup.cpp10
-rw-r--r--src/network/kernel/qdnslookup.h15
-rw-r--r--src/network/kernel/qnetworkinformation.cpp2
-rw-r--r--src/network/kernel/qnetworkinformation.h4
-rw-r--r--src/network/kernel/qnetworkinformation_p.h4
-rw-r--r--src/network/kernel/qnetworkinterface_unix.cpp26
-rw-r--r--src/network/kernel/qnetworkproxy_android.cpp33
-rw-r--r--src/network/kernel/qtldurl.cpp4
-rw-r--r--src/network/socket/qlocalserver.cpp4
40 files changed, 839 insertions, 235 deletions
diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt
index e977400245..7029548b18 100644
--- a/src/network/CMakeLists.txt
+++ b/src/network/CMakeLists.txt
@@ -76,7 +76,6 @@ qt_internal_add_module(Network
compat/removed_api.cpp
PRECOMPILED_HEADER
"../corelib/global/qt_pch.h"
- GENERATE_CPP_EXPORTS
)
## Scopes:
@@ -110,6 +109,7 @@ qt_internal_extend_target(Network CONDITION APPLE
qt_internal_extend_target(Network CONDITION WASM
SOURCES
+ access/qformdatabuilder.cpp access/qformdatabuilder.h
access/qhttpmultipart.cpp access/qhttpmultipart.h access/qhttpmultipart_p.h
access/qhttpnetworkheader.cpp access/qhttpnetworkheader_p.h
access/qnetworkreplywasmimpl.cpp access/qnetworkreplywasmimpl_p.h
@@ -126,6 +126,7 @@ 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/qformdatabuilder.cpp access/qformdatabuilder.h
access/qhttp1configuration.cpp access/qhttp1configuration.h
access/qhttp2configuration.cpp access/qhttp2configuration.h
access/qhttp2connection.cpp access/qhttp2connection_p.h
@@ -165,6 +166,8 @@ qt_internal_extend_target(Network CONDITION QT_FEATURE_system_zlib
qt_internal_extend_target(Network CONDITION NOT QT_FEATURE_system_zlib
INCLUDE_DIRECTORIES
../3rdparty/zlib/src
+ ATTRIBUTION_FILE_DIR_PATHS
+ ../3rdparty/zlib
)
qt_internal_extend_target(Network CONDITION NOT QT_FEATURE_system_zlib AND NOT no_core_dep
@@ -178,6 +181,8 @@ qt_internal_extend_target(Network CONDITION QT_FEATURE_topleveldomain
../3rdparty/libpsl/src/lookup_string_in_fixed_set.c
INCLUDE_DIRECTORIES
../3rdparty/libpsl
+ ATTRIBUTION_FILE_DIR_PATHS
+ ../3rdparty/libpsl
)
qt_internal_extend_target(Network CONDITION QT_FEATURE_dnslookup
diff --git a/src/network/access/http2/http2protocol_p.h b/src/network/access/http2/http2protocol_p.h
index fb5ff199c5..f0f18d1dd5 100644
--- a/src/network/access/http2/http2protocol_p.h
+++ b/src/network/access/http2/http2protocol_p.h
@@ -117,7 +117,7 @@ const qint32 maxSessionReceiveWindowSize((quint32(1) << 31) - 1);
// 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);
+struct Frame Q_AUTOTEST_EXPORT 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);
diff --git a/src/network/access/qformdatabuilder.cpp b/src/network/access/qformdatabuilder.cpp
new file mode 100644
index 0000000000..d4065c7fd2
--- /dev/null
+++ b/src/network/access/qformdatabuilder.cpp
@@ -0,0 +1,363 @@
+// 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
+
+#include "qformdatabuilder.h"
+
+#include <QtCore/private/qstringconverter_p.h>
+#if QT_CONFIG(mimetype)
+#include "QtCore/qmimedatabase.h"
+#endif
+
+#include <vector>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QFormDataPartBuilder
+ \brief The QFormDataPartBuilder class is a convenience class to simplify
+ the construction of QHttpPart objects.
+ \since 6.8
+
+ \ingroup network
+ \ingroup shared
+ \inmodule QtNetwork
+
+ The QFormDataPartBuilder class can be used to build a QHttpPart object with
+ the content disposition header set to be form-data by default. Then the
+ generated object can be used as part of a multipart message (which is
+ represented by the QHttpMultiPart class).
+
+ \sa QHttpPart, QHttpMultiPart, QFormDataBuilder
+*/
+
+static QByteArray nameToByteArray(QStringView view)
+{
+ return view.toUtf8();
+}
+
+static QByteArray nameToByteArray(QLatin1StringView view)
+{
+ if (!QtPrivate::isAscii(view))
+ return view.toString().toUtf8(); // ### optimize
+
+ return QByteArray::fromRawData(view.data(), view.size());
+}
+
+static QByteArray nameToByteArray(QUtf8StringView view)
+{
+ return QByteArray::fromRawData(view.data(), view.size());
+}
+
+static void escapeNameAndAppend(QByteArray &dst, QByteArrayView src)
+{
+ for (auto c : src) {
+ if (c == '"' || c == '\\')
+ dst += '\\';
+ dst += c;
+ }
+}
+
+/*!
+ Constructs a QFormDataPartBuilder object and sets \a name as the name
+ parameter of the form-data.
+*/
+QFormDataPartBuilder::QFormDataPartBuilder(QAnyStringView name, PrivateConstructor /*unused*/)
+{
+ static_assert(std::is_nothrow_move_constructible_v<decltype(m_body)>);
+ static_assert(std::is_nothrow_move_assignable_v<decltype(m_body)>);
+
+ const auto enc = name.visit([](auto name) { return nameToByteArray(name); });
+
+ m_headerValue += "form-data; name=\"";
+ escapeNameAndAppend(m_headerValue, enc);
+ m_headerValue += "\"";
+}
+
+/*!
+ \fn QFormDataPartBuilder::QFormDataPartBuilder(QFormDataPartBuilder &&other) noexcept
+
+ Move-constructs a QFormDataPartBuilder instance, making it point at the same
+ object that \a other was pointing to.
+*/
+
+/*!
+ \fn QFormDataPartBuilder &QFormDataPartBuilder::operator=(QFormDataPartBuilder &&other)
+
+ Move-assigns \a other to this QFormDataPartBuilder instance.
+*/
+
+/*!
+ Destroys the QFormDataPartBuilder object.
+*/
+
+QFormDataPartBuilder::~QFormDataPartBuilder()
+ = default;
+
+static void convertInto_impl(QByteArray &dst, QUtf8StringView in)
+{
+ dst.clear();
+ dst += QByteArrayView{in}; // it's ASCII, anyway
+}
+
+static void convertInto_impl(QByteArray &dst, QLatin1StringView in)
+{
+ dst.clear();
+ dst += QByteArrayView{in}; // it's ASCII, anyway
+}
+
+static void convertInto_impl(QByteArray &dst, QStringView in)
+{
+ dst.resize(in.size());
+ (void)QLatin1::convertFromUnicode(dst.data(), in);
+}
+
+static void convertInto(QByteArray &dst, QAnyStringView in)
+{
+ in.visit([&dst](auto in) { convertInto_impl(dst, in); });
+}
+
+QFormDataPartBuilder &QFormDataPartBuilder::setBodyHelper(const QByteArray &data,
+ QAnyStringView name,
+ QAnyStringView mimeType)
+{
+ m_originalBodyName = name.toString();
+ convertInto(m_mimeType, mimeType);
+ m_body = data;
+ return *this;
+}
+
+/*!
+ Sets \a data as the body of this MIME part and, if given, \a fileName as the
+ file name parameter in the content disposition header.
+
+ If \a mimeType is not given (is empty), then QFormDataPartBuilder tries to
+ auto-detect the mime-type of \a data using QMimeDatabase.
+
+ A subsequent call to setBodyDevice() discards the body and the device will
+ be used instead.
+
+ For a large amount of data (e.g. an image), setBodyDevice() is preferred,
+ which will not copy the data internally.
+
+ \sa setBodyDevice()
+*/
+
+QFormDataPartBuilder &QFormDataPartBuilder::setBody(QByteArrayView data,
+ QAnyStringView fileName,
+ QAnyStringView mimeType)
+{
+ return setBody(data.toByteArray(), fileName, mimeType);
+}
+
+/*!
+ Sets \a body as the body device of this part and \a fileName as the file
+ name parameter in the content disposition header.
+
+ If \a mimeType is not given (is empty), then QFormDataPartBuilder tries to
+ auto-detect the mime-type of \a body using QMimeDatabase.
+
+ A subsequent call to setBody() discards the body device and the data set by
+ setBody() will be used instead.
+
+ For large amounts of data this method should be preferred over setBody(),
+ because the content is not copied when using this method, but read
+ directly from the device.
+
+ \a body must be open and readable. QFormDataPartBuilder does not take
+ ownership of \a body, i.e. the device must be closed and destroyed if
+ necessary.
+
+ \sa setBody(), QHttpPart::setBodyDevice()
+ */
+
+QFormDataPartBuilder &QFormDataPartBuilder::setBodyDevice(QIODevice *body, QAnyStringView fileName,
+ QAnyStringView mimeType)
+{
+ m_originalBodyName = fileName.toString();
+ convertInto(m_mimeType, mimeType);
+ m_body = body;
+ return *this;
+}
+
+/*!
+ Sets the headers specified in \a headers.
+
+ \note The "content-type" and "content-disposition" headers, if any are
+ specified in \a headers, will be overwritten by the class.
+*/
+
+QFormDataPartBuilder &QFormDataPartBuilder::setHeaders(const QHttpHeaders &headers)
+{
+ m_httpHeaders = headers;
+ return *this;
+}
+
+/*!
+ \internal
+
+ Generates a QHttpPart and sets the content disposition header as form-data.
+
+ When this function called, it uses the MIME database to deduce the type the
+ body based on its name and then sets the deduced type as the content type
+ header.
+*/
+
+QHttpPart QFormDataPartBuilder::build()
+{
+ QHttpPart httpPart;
+
+ if (!m_originalBodyName.isNull()) {
+ const bool utf8 = !QtPrivate::isAscii(m_originalBodyName);
+ const auto enc = utf8 ? m_originalBodyName.toUtf8() : m_originalBodyName.toLatin1();
+ m_headerValue += "; filename=\"";
+ escapeNameAndAppend(m_headerValue, enc);
+ m_headerValue += "\"";
+ if (utf8) {
+ // For 'filename*' production see
+ // https://datatracker.ietf.org/doc/html/rfc5987#section-3.2.1
+ // For providing both filename and filename* parameters see
+ // https://datatracker.ietf.org/doc/html/rfc6266#section-4.3 and
+ // https://datatracker.ietf.org/doc/html/rfc8187#section-4.2
+ m_headerValue += "; filename*=UTF-8''" + enc.toPercentEncoding();
+ }
+ }
+
+#if QT_CONFIG(mimetype)
+ if (m_mimeType.isEmpty()) {
+ // auto-detect
+ QMimeDatabase db;
+ convertInto(m_mimeType, std::visit([&](auto &arg) {
+ return db.mimeTypeForFileNameAndData(m_originalBodyName, arg);
+ }, m_body).name());
+ }
+#endif
+
+ for (qsizetype i = 0; i < m_httpHeaders.size(); i++) {
+ httpPart.setRawHeader(QByteArrayView(m_httpHeaders.nameAt(i)).toByteArray(),
+ m_httpHeaders.valueAt(i).toByteArray());
+ }
+
+ if (!m_mimeType.isEmpty())
+ httpPart.setHeader(QNetworkRequest::ContentTypeHeader, m_mimeType);
+
+ httpPart.setHeader(QNetworkRequest::ContentDispositionHeader, m_headerValue);
+
+ if (auto d = std::get_if<QIODevice*>(&m_body))
+ httpPart.setBodyDevice(*d);
+ else if (auto b = std::get_if<QByteArray>(&m_body))
+ httpPart.setBody(*b);
+ else
+ Q_UNREACHABLE();
+
+ return httpPart;
+}
+
+/*!
+ \class QFormDataBuilder
+ \brief The QFormDataBuilder class is a convenience class to simplify
+ the construction of QHttpMultiPart objects.
+ \since 6.8
+
+ \ingroup network
+ \ingroup shared
+ \inmodule QtNetwork
+
+ The QFormDataBuilder class can be used to build a QHttpMultiPart object
+ with the content type set to be FormDataType by default.
+
+ The snippet below demonstrates how to build a multipart message with
+ QFormDataBuilder:
+
+ \code
+ QFormDataBuilder builder;
+ QFile image(u"../../pic.png"_s); image.open(QFile::ReadOnly);
+ QFile mask(u"../../mask.png"_s); mask.open(QFile::ReadOnly);
+
+ builder.part("image"_L1).setBodyDevice(&image, "the actual image");
+ builder.part("mask"_L1).setBodyDevice(&mask, "the mask image");
+ builder.part("prompt"_L1).setBody("Lobster wearing a beret");
+ builder.part("n"_L1).setBody("2");
+ builder.part("size"_L1).setBody("512x512");
+
+ std::unique_ptr<QHttpMultiPart> = builder.buildMultiPart();
+ \endcode
+
+ \sa QHttpPart, QHttpMultiPart, QFormDataPartBuilder
+*/
+
+class QFormDataBuilderPrivate
+{
+public:
+ std::vector<QFormDataPartBuilder> parts;
+};
+
+/*!
+ Constructs an empty QFormDataBuilder object.
+*/
+
+QFormDataBuilder::QFormDataBuilder()
+ : d_ptr(new QFormDataBuilderPrivate())
+{
+
+}
+
+/*!
+ Destroys the QFormDataBuilder object.
+*/
+
+QFormDataBuilder::~QFormDataBuilder()
+{
+ delete d_ptr;
+}
+
+/*!
+ \fn QFormDataBuilder::QFormDataBuilder(QFormDataBuilder &&other) noexcept
+
+ Move-constructs a QFormDataBuilder instance, making it point at the same
+ object that \a other was pointing to.
+*/
+
+/*!
+ \fn QFormDataBuilder &QFormDataBuilder::operator=(QFormDataBuilder &&other) noexcept
+
+ Move-assigns \a other to this QFormDataBuilder instance.
+*/
+
+/*!
+ Constructs and returns a reference to a QFormDataPartBuilder object and sets
+ \a name as the name parameter of the form-data. The returned reference is
+ valid until the next call to this function.
+
+ Limiting \a name characters to US-ASCII is
+ \l {https://datatracker.ietf.org/doc/html/rfc7578#section-5.1.1}{strongly recommended}
+ for interoperability reasons.
+
+ \sa QFormDataPartBuilder, QHttpPart
+*/
+
+QFormDataPartBuilder &QFormDataBuilder::part(QAnyStringView name)
+{
+ Q_D(QFormDataBuilder);
+
+ return d->parts.emplace_back(name, QFormDataPartBuilder::PrivateConstructor());
+}
+
+/*!
+ Constructs and returns a pointer to a QHttpMultipart object.
+
+ \sa QHttpMultiPart
+*/
+
+std::unique_ptr<QHttpMultiPart> QFormDataBuilder::buildMultiPart()
+{
+ Q_D(QFormDataBuilder);
+
+ auto multiPart = std::make_unique<QHttpMultiPart>(QHttpMultiPart::FormDataType);
+
+ for (auto &part : d->parts)
+ multiPart->append(part.build());
+
+ return multiPart;
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/access/qformdatabuilder.h b/src/network/access/qformdatabuilder.h
new file mode 100644
index 0000000000..16274734be
--- /dev/null
+++ b/src/network/access/qformdatabuilder.h
@@ -0,0 +1,120 @@
+// 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 QFORMDATABUILDER_H
+#define QFORMDATABUILDER_H
+
+#include <QtNetwork/qtnetworkglobal.h>
+#include <QtNetwork/qhttpheaders.h>
+#include <QtNetwork/qhttpmultipart.h>
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qiodevice.h>
+#include <QtCore/qstring.h>
+
+#include <memory>
+#include <variant>
+
+#ifndef Q_OS_WASM
+QT_REQUIRE_CONFIG(http);
+#endif
+
+class tst_QFormDataBuilder;
+
+QT_BEGIN_NAMESPACE
+
+class QHttpPartPrivate;
+class QHttpMultiPart;
+class QDebug;
+
+class QFormDataBuilderPrivate;
+
+class QFormDataPartBuilder
+{
+ struct PrivateConstructor { explicit PrivateConstructor() = default; };
+public:
+ Q_NETWORK_EXPORT explicit QFormDataPartBuilder(QAnyStringView name, PrivateConstructor);
+
+ QFormDataPartBuilder(QFormDataPartBuilder &&other) noexcept
+ : m_headerValue(std::move(other.m_headerValue)),
+ m_originalBodyName(std::move(other.m_originalBodyName)),
+ m_httpHeaders(std::move(other.m_httpHeaders)),
+ m_body(std::move(other.m_body)),
+ m_reserved(std::exchange(other.m_reserved, nullptr))
+ {
+
+ }
+
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QFormDataPartBuilder)
+ void swap(QFormDataPartBuilder &other) noexcept
+ {
+ m_headerValue.swap(other.m_headerValue);
+ m_originalBodyName.swap(other.m_originalBodyName);
+ m_httpHeaders.swap(other.m_httpHeaders);
+ m_body.swap(other.m_body);
+ qt_ptr_swap(m_reserved, other.m_reserved);
+ }
+
+ Q_NETWORK_EXPORT ~QFormDataPartBuilder();
+
+ Q_WEAK_OVERLOAD QFormDataPartBuilder &setBody(const QByteArray &data,
+ QAnyStringView fileName = {},
+ QAnyStringView mimeType = {})
+ { return setBodyHelper(data, fileName, mimeType); }
+
+ Q_NETWORK_EXPORT QFormDataPartBuilder &setBody(QByteArrayView data,
+ QAnyStringView fileName = {},
+ QAnyStringView mimeType = {});
+ Q_NETWORK_EXPORT QFormDataPartBuilder &setBodyDevice(QIODevice *body,
+ QAnyStringView fileName = {},
+ QAnyStringView mimeType = {});
+ Q_NETWORK_EXPORT QFormDataPartBuilder &setHeaders(const QHttpHeaders &headers);
+private:
+ Q_DISABLE_COPY(QFormDataPartBuilder)
+
+ Q_NETWORK_EXPORT QFormDataPartBuilder &setBodyHelper(const QByteArray &data,
+ QAnyStringView fileName,
+ QAnyStringView mimeType);
+ Q_NETWORK_EXPORT QHttpPart build();
+
+ QByteArray m_headerValue;
+ QByteArray m_mimeType;
+ QString m_originalBodyName;
+ QHttpHeaders m_httpHeaders;
+ std::variant<QIODevice*, QByteArray> m_body;
+ void *m_reserved = nullptr;
+
+ friend class QFormDataBuilder;
+ friend class ::tst_QFormDataBuilder;
+ friend void swap(QFormDataPartBuilder &lhs, QFormDataPartBuilder &rhs) noexcept
+ { lhs.swap(rhs); }
+};
+
+class QFormDataBuilder
+{
+public:
+ Q_NETWORK_EXPORT explicit QFormDataBuilder();
+
+ QFormDataBuilder(QFormDataBuilder &&other) noexcept : d_ptr(std::exchange(other.d_ptr, nullptr)) {}
+
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QFormDataBuilder)
+ void swap(QFormDataBuilder &other) noexcept
+ {
+ qt_ptr_swap(d_ptr, other.d_ptr);
+ }
+
+ Q_NETWORK_EXPORT ~QFormDataBuilder();
+ Q_NETWORK_EXPORT QFormDataPartBuilder &part(QAnyStringView name);
+ Q_NETWORK_EXPORT std::unique_ptr<QHttpMultiPart> buildMultiPart();
+private:
+ QFormDataBuilderPrivate *d_ptr;
+
+ Q_DECLARE_PRIVATE(QFormDataBuilder)
+ Q_DISABLE_COPY(QFormDataBuilder)
+};
+
+Q_DECLARE_SHARED(QFormDataBuilder)
+
+QT_END_NAMESPACE
+
+#endif // QFORMDATABUILDER_H
diff --git a/src/network/access/qhttp2connection.cpp b/src/network/access/qhttp2connection.cpp
index 8560e0da38..2d92684863 100644
--- a/src/network/access/qhttp2connection.cpp
+++ b/src/network/access/qhttp2connection.cpp
@@ -17,7 +17,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(qHttp2ConnectionLog, "qt.network.http2.connection", QtCriticalMsg)
+Q_STATIC_LOGGING_CATEGORY(qHttp2ConnectionLog, "qt.network.http2.connection", QtCriticalMsg)
using namespace Qt::StringLiterals;
using namespace Http2;
diff --git a/src/network/access/qhttp2protocolhandler.cpp b/src/network/access/qhttp2protocolhandler.cpp
index d9341dc643..3d55cee1eb 100644
--- a/src/network/access/qhttp2protocolhandler.cpp
+++ b/src/network/access/qhttp2protocolhandler.cpp
@@ -1341,8 +1341,8 @@ quint32 QHttp2ProtocolHandler::createNewStream(const HttpMessagePair &message, b
replyPrivate->connectionChannel = m_channel;
reply->setHttp2WasUsed(true);
streamIDs.insert(reply, newStreamID);
- connect(reply, SIGNAL(destroyed(QObject*)),
- this, SLOT(_q_replyDestroyed(QObject*)));
+ connect(reply, &QHttpNetworkReply::destroyed,
+ this, &QHttp2ProtocolHandler::_q_replyDestroyed);
const Stream newStream(message, newStreamID,
streamInitialSendWindowSize,
@@ -1350,8 +1350,8 @@ quint32 QHttp2ProtocolHandler::createNewStream(const HttpMessagePair &message, b
if (!uploadDone) {
if (auto src = newStream.data()) {
- connect(src, SIGNAL(readyRead()), this,
- SLOT(_q_uploadDataReadyRead()), Qt::QueuedConnection);
+ connect(src, &QNonContiguousByteDevice::readyRead, this,
+ &QHttp2ProtocolHandler::_q_uploadDataReadyRead, Qt::QueuedConnection);
connect(src, &QHttp2ProtocolHandler::destroyed,
this, &QHttp2ProtocolHandler::_q_uploadDataDestroyed);
streamIDs.insert(src, newStreamID);
diff --git a/src/network/access/qhttpheaders.cpp b/src/network/access/qhttpheaders.cpp
index c63da899a8..a4ec7b422d 100644
--- a/src/network/access/qhttpheaders.cpp
+++ b/src/network/access/qhttpheaders.cpp
@@ -18,7 +18,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcQHttpHeaders, "qt.network.http.headers");
+Q_STATIC_LOGGING_CATEGORY(lcQHttpHeaders, "qt.network.http.headers");
/*!
\class QHttpHeaders
@@ -988,50 +988,6 @@ QDebug operator<<(QDebug debug, const QHttpHeaders &headers)
}
#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"
@@ -1106,8 +1062,10 @@ static bool headerValueValidImpl(QLatin1StringView value) noexcept
static bool headerValueValidImpl(QUtf8StringView value) noexcept
{
- if (!isUtf8Latin1Representable(value)) // TODO FIXME see the function
- return false;
+ // UTF-8 byte sequences are also used as values directly
+ // => allow them as such. UTF-8 byte sequences for characters
+ // outside of ASCII should all fit into obs-text (>= 0x80)
+ // (see isValidHttpHeaderValueChar)
return std::all_of(value.begin(), value.end(), isValidHttpHeaderValueChar);
}
diff --git a/src/network/access/qhttpmultipart.cpp b/src/network/access/qhttpmultipart.cpp
index a695969f00..711d89544c 100644
--- a/src/network/access/qhttpmultipart.cpp
+++ b/src/network/access/qhttpmultipart.cpp
@@ -409,6 +409,14 @@ QHttpMultiPartPrivate::QHttpMultiPartPrivate() : contentType(QHttpMultiPart::Mix
Q_ASSERT(boundary.size() <= 70);
}
+QHttpMultiPartPrivate::~QHttpMultiPartPrivate()
+{
+ delete device;
+}
+
+QHttpMultiPartIODevice::~QHttpMultiPartIODevice()
+ = default;
+
qint64 QHttpMultiPartIODevice::size() const
{
// if not done yet, we calculate the size and the offsets of each part,
diff --git a/src/network/access/qhttpmultipart_p.h b/src/network/access/qhttpmultipart_p.h
index 7a12ce8424..39c147d2bc 100644
--- a/src/network/access/qhttpmultipart_p.h
+++ b/src/network/access/qhttpmultipart_p.h
@@ -16,10 +16,14 @@
//
#include <QtNetwork/private/qtnetworkglobal_p.h>
+#include <QtNetwork/qhttpmultipart.h>
+
#include "QtCore/qshareddata.h"
#include "qnetworkrequest_p.h" // for deriving QHttpPartPrivate from QNetworkHeadersPrivate
#include "qhttpheadershelper_p.h"
+
#include "private/qobject_p.h"
+#include <QtCore/qiodevice.h>
#ifndef Q_OS_WASM
QT_REQUIRE_CONFIG(http);
@@ -92,8 +96,7 @@ public:
QIODevice(), multiPart(parentMultiPart), readPointer(0), deviceSize(-1) {
}
- ~QHttpMultiPartIODevice() {
- }
+ ~QHttpMultiPartIODevice() override;
virtual bool atEnd() const override {
return readPointer == size();
@@ -128,15 +131,17 @@ public:
-class QHttpMultiPartPrivate: public QObjectPrivate
+class Q_AUTOTEST_EXPORT QHttpMultiPartPrivate: public QObjectPrivate
{
public:
QHttpMultiPartPrivate();
+ ~QHttpMultiPartPrivate() override;
- ~QHttpMultiPartPrivate()
+ static QHttpMultiPartPrivate *get(QHttpMultiPart *message) { return message->d_func(); }
+ static const QHttpMultiPartPrivate *get(const QHttpMultiPart *message)
{
- delete device;
+ return message->d_func();
}
QList<QHttpPart> parts;
diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp
index 419491a711..3ef07c6993 100644
--- a/src/network/access/qhttpnetworkconnection.cpp
+++ b/src/network/access/qhttpnetworkconnection.cpp
@@ -52,10 +52,11 @@ static int getPreferredActiveChannelCount(QHttpNetworkConnection::ConnectionType
QHttpNetworkConnectionPrivate::QHttpNetworkConnectionPrivate(
quint16 connectionCount, const QString &hostName, quint16 port, bool encrypt,
- QHttpNetworkConnection::ConnectionType type)
+ bool isLocalSocket, QHttpNetworkConnection::ConnectionType type)
: hostName(hostName),
port(port),
encrypt(encrypt),
+ isLocalSocket(isLocalSocket),
activeChannelCount(getPreferredActiveChannelCount(type, connectionCount)),
channelCount(connectionCount),
channels(new QHttpNetworkConnectionChannel[channelCount]),
@@ -64,6 +65,8 @@ QHttpNetworkConnectionPrivate::QHttpNetworkConnectionPrivate(
#endif
connectionType(type)
{
+ if (isLocalSocket) // Don't try to do host lookup for local sockets
+ networkLayerState = IPv4;
// 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.
@@ -102,13 +105,18 @@ void QHttpNetworkConnectionPrivate::pauseConnection()
// Disable all socket notifiers
for (int i = 0; i < activeChannelCount; i++) {
- if (channels[i].socket) {
+ if (auto *absSocket = qobject_cast<QAbstractSocket *>(channels[i].socket)) {
#ifndef QT_NO_SSL
if (encrypt)
- QSslSocketPrivate::pauseSocketNotifiers(static_cast<QSslSocket*>(channels[i].socket));
+ QSslSocketPrivate::pauseSocketNotifiers(static_cast<QSslSocket*>(absSocket));
else
#endif
- QAbstractSocketPrivate::pauseSocketNotifiers(channels[i].socket);
+ QAbstractSocketPrivate::pauseSocketNotifiers(absSocket);
+ } else if (qobject_cast<QLocalSocket *>(channels[i].socket)) {
+ // @todo how would we do this?
+#if 0 // @todo Enable this when there is a debug category for this
+ qDebug() << "Should pause socket but there is no way to do it for local sockets";
+#endif
}
}
}
@@ -118,17 +126,21 @@ void QHttpNetworkConnectionPrivate::resumeConnection()
state = RunningState;
// Enable all socket notifiers
for (int i = 0; i < activeChannelCount; i++) {
- if (channels[i].socket) {
+ if (auto *absSocket = qobject_cast<QAbstractSocket *>(channels[i].socket)) {
#ifndef QT_NO_SSL
if (encrypt)
- QSslSocketPrivate::resumeSocketNotifiers(static_cast<QSslSocket*>(channels[i].socket));
+ QSslSocketPrivate::resumeSocketNotifiers(static_cast<QSslSocket*>(absSocket));
else
#endif
- QAbstractSocketPrivate::resumeSocketNotifiers(channels[i].socket);
+ QAbstractSocketPrivate::resumeSocketNotifiers(absSocket);
// Resume pending upload if needed
if (channels[i].state == QHttpNetworkConnectionChannel::WritingState)
QMetaObject::invokeMethod(&channels[i], "_q_uploadDataReadyRead", Qt::QueuedConnection);
+ } else if (qobject_cast<QLocalSocket *>(channels[i].socket)) {
+#if 0 // @todo Enable this when there is a debug category for this
+ qDebug() << "Should resume socket but there is no way to do it for local sockets";
+#endif
}
}
@@ -292,7 +304,12 @@ void QHttpNetworkConnectionPrivate::prepareRequest(HttpMessagePair &messagePair)
request.setHeaderField("User-Agent", "Mozilla/5.0");
// set the host
value = request.headerField("host");
- if (value.isEmpty()) {
+ if (isLocalSocket && value.isEmpty()) {
+ // The local socket connections might have a full file path, and that
+ // may not be suitable for the Host header. But we can use whatever the
+ // user has set in the URL.
+ request.prependHeaderField("Host", request.url().host().toLocal8Bit());
+ } else if (value.isEmpty()) {
QHostAddress add;
QByteArray host;
if (add.setAddress(hostName)) {
@@ -524,7 +541,9 @@ QHttpNetworkConnectionPrivate::parseRedirectResponse(QHttpNetworkReply *reply)
// Check redirect url protocol
const QUrl priorUrl(reply->request().url());
- if (redirectUrl.scheme() == "http"_L1 || redirectUrl.scheme() == "https"_L1) {
+ const QString targetUrlScheme = redirectUrl.scheme();
+ if (targetUrlScheme == "http"_L1 || targetUrlScheme == "https"_L1
+ || targetUrlScheme.startsWith("unix"_L1)) {
switch (reply->request().redirectPolicy()) {
case QNetworkRequest::NoLessSafeRedirectPolicy:
// Here we could handle https->http redirects as InsecureProtocolError.
@@ -535,7 +554,7 @@ QHttpNetworkConnectionPrivate::parseRedirectResponse(QHttpNetworkReply *reply)
break;
case QNetworkRequest::SameOriginRedirectPolicy:
if (priorUrl.host() != redirectUrl.host()
- || priorUrl.scheme() != redirectUrl.scheme()
+ || priorUrl.scheme() != targetUrlScheme
|| priorUrl.port() != redirectUrl.port()) {
return {{}, QNetworkReply::InsecureRedirectError};
}
@@ -1024,7 +1043,7 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
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) {
+ || QSocketAbstraction::socketState(channels[i].socket) == QAbstractSocket::UnconnectedState) {
if (!channels[i].ensureConnection())
continue;
}
@@ -1048,7 +1067,9 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
// try to get a free AND connected socket
for (int i = 0; i < activeChannelCount; ++i) {
if (channels[i].socket) {
- if (!channels[i].reply && !channels[i].isSocketBusy() && channels[i].socket->state() == QAbstractSocket::ConnectedState) {
+ if (!channels[i].reply && !channels[i].isSocketBusy()
+ && QSocketAbstraction::socketState(channels[i].socket)
+ == QAbstractSocket::ConnectedState) {
if (dequeueRequest(channels[i].socket))
channels[i].sendRequest();
}
@@ -1068,7 +1089,8 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
else if (networkLayerState == IPv6)
channels[0].networkLayerPreference = QAbstractSocket::IPv6Protocol;
channels[0].ensureConnection();
- if (channels[0].socket && channels[0].socket->state() == QAbstractSocket::ConnectedState
+ if (auto *s = channels[0].socket; s
+ && QSocketAbstraction::socketState(s) == QAbstractSocket::ConnectedState
&& !channels[0].pendingEncrypt) {
if (channels[0].h2RequestsToSend.size()) {
channels[0].sendRequest();
@@ -1095,9 +1117,13 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
// return fast if there is nothing to pipeline
if (highPriorityQueue.isEmpty() && lowPriorityQueue.isEmpty())
return;
- for (int i = 0; i < activeChannelCount; i++)
- if (channels[i].socket && channels[i].socket->state() == QAbstractSocket::ConnectedState)
+ for (int i = 0; i < activeChannelCount; i++) {
+ if (channels[i].socket
+ && QSocketAbstraction::socketState(channels[i].socket)
+ == QAbstractSocket::ConnectedState) {
fillPipeline(channels[i].socket);
+ }
+ }
// 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
@@ -1122,15 +1148,16 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
if (!channels[i].socket)
continue;
- if ((channels[i].socket->state() == QAbstractSocket::ConnectingState)
- || (channels[i].socket->state() == QAbstractSocket::HostLookupState)
+ using State = QAbstractSocket::SocketState;
+ if ((QSocketAbstraction::socketState(channels[i].socket) == State::ConnectingState)
+ || (QSocketAbstraction::socketState(channels[i].socket) == State::HostLookupState)
|| channels[i].pendingEncrypt) { // pendingEncrypt == "EncryptingState"
neededOpenChannels--;
continue;
}
if (!channels[i].reply && !channels[i].isSocketBusy()
- && (channels[i].socket->state() == QAbstractSocket::UnconnectedState)) {
+ && (QSocketAbstraction::socketState(channels[i].socket) == State::UnconnectedState)) {
channelsToConnect.push_back(i);
neededOpenChannels--;
}
@@ -1329,9 +1356,9 @@ void QHttpNetworkConnectionPrivate::_q_connectDelayedChannel()
}
QHttpNetworkConnection::QHttpNetworkConnection(quint16 connectionCount, const QString &hostName,
- quint16 port, bool encrypt, QObject *parent,
+ quint16 port, bool encrypt, bool isLocalSocket, QObject *parent,
QHttpNetworkConnection::ConnectionType connectionType)
- : QObject(*(new QHttpNetworkConnectionPrivate(connectionCount, hostName, port, encrypt,
+ : QObject(*(new QHttpNetworkConnectionPrivate(connectionCount, hostName, port, encrypt, isLocalSocket,
connectionType)), parent)
{
Q_D(QHttpNetworkConnection);
diff --git a/src/network/access/qhttpnetworkconnection_p.h b/src/network/access/qhttpnetworkconnection_p.h
index c2d062fb16..5e4bce5eb0 100644
--- a/src/network/access/qhttpnetworkconnection_p.h
+++ b/src/network/access/qhttpnetworkconnection_p.h
@@ -64,7 +64,8 @@ public:
};
QHttpNetworkConnection(quint16 channelCount, const QString &hostName, quint16 port = 80,
- bool encrypt = false, QObject *parent = nullptr,
+ bool encrypt = false, bool isLocalSocket = false,
+ QObject *parent = nullptr,
ConnectionType connectionType = ConnectionTypeHTTP);
~QHttpNetworkConnection();
@@ -155,7 +156,8 @@ public:
};
QHttpNetworkConnectionPrivate(quint16 connectionCount, const QString &hostName, quint16 port,
- bool encrypt, QHttpNetworkConnection::ConnectionType type);
+ bool encrypt, bool isLocalSocket,
+ QHttpNetworkConnection::ConnectionType type);
~QHttpNetworkConnectionPrivate();
void init();
@@ -205,6 +207,7 @@ public:
QString hostName;
quint16 port;
bool encrypt;
+ bool isLocalSocket;
bool delayIpv4 = true;
// Number of channels we are trying to use at the moment:
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
index e178d65356..8688e4b8d7 100644
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
@@ -12,6 +12,7 @@
#include <private/qhttp2protocolhandler_p.h>
#include <private/qhttpprotocolhandler_p.h>
#include <private/http2protocol_p.h>
+#include <private/qsocketabstraction_p.h>
#ifndef QT_NO_SSL
# include <private/qsslsocket_p.h>
@@ -78,6 +79,8 @@ void QHttpNetworkConnectionChannel::init()
#ifndef QT_NO_SSL
if (connection->d_func()->encrypt)
socket = new QSslSocket;
+ else if (connection->d_func()->isLocalSocket)
+ socket = new QLocalSocket;
else
socket = new QTcpSocket;
#else
@@ -85,7 +88,8 @@ void QHttpNetworkConnectionChannel::init()
#endif
#ifndef QT_NO_NETWORKPROXY
// Set by QNAM anyway, but let's be safe here
- socket->setProxy(QNetworkProxy::NoProxy);
+ if (auto s = qobject_cast<QAbstractSocket *>(socket))
+ s->setProxy(QNetworkProxy::NoProxy);
#endif
// After some back and forth in all the last years, this is now a DirectConnection because otherwise
@@ -94,32 +98,48 @@ void QHttpNetworkConnectionChannel::init()
QObject::connect(socket, &QIODevice::bytesWritten,
this, &QHttpNetworkConnectionChannel::_q_bytesWritten,
Qt::DirectConnection);
- QObject::connect(socket, &QAbstractSocket::connected,
- this, &QHttpNetworkConnectionChannel::_q_connected,
- Qt::DirectConnection);
QObject::connect(socket, &QIODevice::readyRead,
this, &QHttpNetworkConnectionChannel::_q_readyRead,
Qt::DirectConnection);
- // The disconnected() and error() signals may already come
- // while calling connectToHost().
- // In case of a cached hostname or an IP this
- // will then emit a signal to the user of QNetworkReply
- // but cannot be caught because the user did not have a chance yet
- // to connect to QNetworkReply's signals.
- qRegisterMetaType<QAbstractSocket::SocketError>();
- QObject::connect(socket, &QAbstractSocket::disconnected,
- this, &QHttpNetworkConnectionChannel::_q_disconnected,
- Qt::DirectConnection);
- QObject::connect(socket, &QAbstractSocket::errorOccurred,
- this, &QHttpNetworkConnectionChannel::_q_error,
- Qt::DirectConnection);
+
+ QSocketAbstraction::visit([this](auto *socket){
+ using SocketType = std::remove_pointer_t<decltype(socket)>;
+ QObject::connect(socket, &SocketType::connected,
+ this, &QHttpNetworkConnectionChannel::_q_connected,
+ Qt::DirectConnection);
+
+ // The disconnected() and error() signals may already come
+ // while calling connectToHost().
+ // In case of a cached hostname or an IP this
+ // will then emit a signal to the user of QNetworkReply
+ // but cannot be caught because the user did not have a chance yet
+ // to connect to QNetworkReply's signals.
+ QObject::connect(socket, &SocketType::disconnected,
+ this, &QHttpNetworkConnectionChannel::_q_disconnected,
+ Qt::DirectConnection);
+ if constexpr (std::is_same_v<SocketType, QAbstractSocket>) {
+ QObject::connect(socket, &QAbstractSocket::errorOccurred,
+ this, &QHttpNetworkConnectionChannel::_q_error,
+ Qt::DirectConnection);
+ } else if constexpr (std::is_same_v<SocketType, QLocalSocket>) {
+ auto convertAndForward = [this](QLocalSocket::LocalSocketError error) {
+ _q_error(static_cast<QAbstractSocket::SocketError>(error));
+ };
+ QObject::connect(socket, &SocketType::errorOccurred,
+ this, std::move(convertAndForward),
+ Qt::DirectConnection);
+ }
+ }, socket);
+
#ifndef QT_NO_NETWORKPROXY
- QObject::connect(socket, &QAbstractSocket::proxyAuthenticationRequired,
- this, &QHttpNetworkConnectionChannel::_q_proxyAuthenticationRequired,
- Qt::DirectConnection);
+ if (auto *s = qobject_cast<QAbstractSocket *>(socket)) {
+ QObject::connect(s, &QAbstractSocket::proxyAuthenticationRequired,
+ this, &QHttpNetworkConnectionChannel::_q_proxyAuthenticationRequired,
+ Qt::DirectConnection);
+ }
#endif
#ifndef QT_NO_SSL
@@ -156,8 +176,10 @@ void QHttpNetworkConnectionChannel::init()
#endif
#ifndef QT_NO_NETWORKPROXY
- if (proxy.type() != QNetworkProxy::NoProxy)
- socket->setProxy(proxy);
+ if (auto *s = qobject_cast<QAbstractSocket *>(socket);
+ s && proxy.type() != QNetworkProxy::NoProxy) {
+ s->setProxy(proxy);
+ }
#endif
isInitialized = true;
}
@@ -170,7 +192,7 @@ void QHttpNetworkConnectionChannel::close()
if (!socket)
state = QHttpNetworkConnectionChannel::IdleState;
- else if (socket->state() == QAbstractSocket::UnconnectedState)
+ else if (QSocketAbstraction::socketState(socket) == QAbstractSocket::UnconnectedState)
state = QHttpNetworkConnectionChannel::IdleState;
else
state = QHttpNetworkConnectionChannel::ClosingState;
@@ -190,7 +212,7 @@ void QHttpNetworkConnectionChannel::abort()
{
if (!socket)
state = QHttpNetworkConnectionChannel::IdleState;
- else if (socket->state() == QAbstractSocket::UnconnectedState)
+ else if (QSocketAbstraction::socketState(socket) == QAbstractSocket::UnconnectedState)
state = QHttpNetworkConnectionChannel::IdleState;
else
state = QHttpNetworkConnectionChannel::ClosingState;
@@ -201,7 +223,10 @@ void QHttpNetworkConnectionChannel::abort()
if (socket) {
// socket can be 0 since the host lookup is done from qhttpnetworkconnection.cpp while
// there is no socket yet.
- socket->abort();
+ auto callAbort = [](auto *s) {
+ s->abort();
+ };
+ QSocketAbstraction::visit(callAbort, socket);
}
}
@@ -268,7 +293,7 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
if (!isInitialized)
init();
- QAbstractSocket::SocketState socketState = socket->state();
+ QAbstractSocket::SocketState socketState = QSocketAbstraction::socketState(socket);
// resend this request after we receive the disconnected signal
// If !socket->isOpen() then we have already called close() on the socket, but there was still a
@@ -335,7 +360,8 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
connectHost = connection->d_func()->networkProxy.hostName();
connectPort = connection->d_func()->networkProxy.port();
}
- if (socket->proxy().type() == QNetworkProxy::HttpProxy) {
+ if (auto *abSocket = qobject_cast<QAbstractSocket *>(socket);
+ abSocket && abSocket->proxy().type() == QNetworkProxy::HttpProxy) {
// Make user-agent field available to HTTP proxy socket engine (QTBUG-17223)
QByteArray value;
// ensureConnection is called before any request has been assigned, but can also be
@@ -353,11 +379,11 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
value = request.headerField("user-agent");
}
if (!value.isEmpty()) {
- QNetworkProxy proxy(socket->proxy());
+ QNetworkProxy proxy(abSocket->proxy());
auto h = proxy.headers();
h.replaceOrAppend(QHttpHeaders::WellKnownHeader::UserAgent, value);
proxy.setHeaders(std::move(h));
- socket->setProxy(proxy);
+ abSocket->setProxy(proxy);
}
}
#endif
@@ -380,7 +406,7 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
// limit the socket read buffer size. we will read everything into
// the QHttpNetworkReply anyway, so let's grow only that and not
// here and there.
- socket->setReadBufferSize(64*1024);
+ sslSocket->setReadBufferSize(64*1024);
#else
// Need to dequeue the request so that we can emit the error.
if (!reply)
@@ -394,17 +420,24 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
&& connection->cacheProxy().type() == QNetworkProxy::NoProxy
&& connection->transparentProxy().type() == QNetworkProxy::NoProxy) {
#endif
- socket->connectToHost(connectHost, connectPort, QIODevice::ReadWrite | QIODevice::Unbuffered, networkLayerPreference);
- // For an Unbuffered QTcpSocket, the read buffer size has a special meaning.
- socket->setReadBufferSize(1*1024);
+ if (auto *s = qobject_cast<QAbstractSocket *>(socket)) {
+ s->connectToHost(connectHost, connectPort,
+ QIODevice::ReadWrite | QIODevice::Unbuffered,
+ networkLayerPreference);
+ // For an Unbuffered QTcpSocket, the read buffer size has a special meaning.
+ s->setReadBufferSize(1 * 1024);
+ } else if (auto *s = qobject_cast<QLocalSocket *>(socket)) {
+ s->connectToServer(connectHost);
+ }
#ifndef QT_NO_NETWORKPROXY
} else {
- socket->connectToHost(connectHost, connectPort, QIODevice::ReadWrite, networkLayerPreference);
-
+ auto *s = qobject_cast<QAbstractSocket *>(socket);
+ Q_ASSERT(s);
// limit the socket read buffer size. we will read everything into
// the QHttpNetworkReply anyway, so let's grow only that and not
// here and there.
- socket->setReadBufferSize(64*1024);
+ s->connectToHost(connectHost, connectPort, QIODevice::ReadWrite, networkLayerPreference);
+ s->setReadBufferSize(64 * 1024);
}
#endif
}
@@ -507,7 +540,7 @@ void QHttpNetworkConnectionChannel::allDone()
// move next from pipeline to current request
if (!alreadyPipelinedRequests.isEmpty()) {
- if (resendCurrent || connectionCloseEnabled || socket->state() != QAbstractSocket::ConnectedState) {
+ if (resendCurrent || connectionCloseEnabled || QSocketAbstraction::socketState(socket) != QAbstractSocket::ConnectedState) {
// move the pipelined ones back to the main queue
requeueCurrentlyPipelinedRequests();
close();
@@ -538,7 +571,7 @@ void QHttpNetworkConnectionChannel::allDone()
QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
} else if (alreadyPipelinedRequests.isEmpty()) {
if (connectionCloseEnabled)
- if (socket->state() != QAbstractSocket::UnconnectedState)
+ if (QSocketAbstraction::socketState(socket) != QAbstractSocket::UnconnectedState)
close();
if (qobject_cast<QHttpNetworkConnection*>(connection))
QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
@@ -556,7 +589,7 @@ void QHttpNetworkConnectionChannel::detectPipeliningSupport()
// check for not having connection close
&& (!reply->d_func()->isConnectionCloseEnabled())
// check if it is still connected
- && (socket->state() == QAbstractSocket::ConnectedState)
+ && (QSocketAbstraction::socketState(socket) == QAbstractSocket::ConnectedState)
// check for broken servers in server reply header
// this is adapted from http://mxr.mozilla.org/firefox/ident?i=SupportsPipelining
&& (serverHeaderField = reply->headerField("Server"), !serverHeaderField.contains("Microsoft-IIS/4."))
@@ -679,8 +712,8 @@ bool QHttpNetworkConnectionChannel::resetUploadData()
void QHttpNetworkConnectionChannel::setProxy(const QNetworkProxy &networkProxy)
{
- if (socket)
- socket->setProxy(networkProxy);
+ if (auto *s = qobject_cast<QAbstractSocket *>(socket))
+ s->setProxy(networkProxy);
proxy = networkProxy;
}
@@ -841,7 +874,7 @@ void QHttpNetworkConnectionChannel::_q_disconnected()
}
-void QHttpNetworkConnectionChannel::_q_connected()
+void QHttpNetworkConnectionChannel::_q_connected_abstract_socket(QAbstractSocket *absSocket)
{
// For the Happy Eyeballs we need to check if this is the first channel to connect.
if (connection->d_func()->networkLayerState == QHttpNetworkConnectionPrivate::HostLookupPending || connection->d_func()->networkLayerState == QHttpNetworkConnectionPrivate::IPv4or6) {
@@ -852,7 +885,7 @@ void QHttpNetworkConnectionChannel::_q_connected()
else if (networkLayerPreference == QAbstractSocket::IPv6Protocol)
connection->d_func()->networkLayerState = QHttpNetworkConnectionPrivate::IPv6;
else {
- if (socket->peerAddress().protocol() == QAbstractSocket::IPv4Protocol)
+ if (absSocket->peerAddress().protocol() == QAbstractSocket::IPv4Protocol)
connection->d_func()->networkLayerState = QHttpNetworkConnectionPrivate::IPv4;
else
connection->d_func()->networkLayerState = QHttpNetworkConnectionPrivate::IPv6;
@@ -875,7 +908,7 @@ void QHttpNetworkConnectionChannel::_q_connected()
}
// improve performance since we get the request sent by the kernel ASAP
- //socket->setSocketOption(QAbstractSocket::LowDelayOption, 1);
+ //absSocket->setSocketOption(QAbstractSocket::LowDelayOption, 1);
// We have this commented out now. It did not have the effect we wanted. If we want to
// do this properly, Qt has to combine multiple HTTP requests into one buffer
// and send this to the kernel in one syscall and then the kernel immediately sends
@@ -884,7 +917,7 @@ void QHttpNetworkConnectionChannel::_q_connected()
// the requests into one TCP packet.
// not sure yet if it helps, but it makes sense
- socket->setSocketOption(QAbstractSocket::KeepAliveOption, 1);
+ absSocket->setSocketOption(QAbstractSocket::KeepAliveOption, 1);
pipeliningSupported = QHttpNetworkConnectionChannel::PipeliningSupportUnknown;
@@ -893,7 +926,7 @@ void QHttpNetworkConnectionChannel::_q_connected()
if (!connectionPrivate->connectionMonitor.isMonitoring()) {
// Now that we have a pair of addresses, we can start monitoring the
// connection status to handle its loss properly.
- if (connectionPrivate->connectionMonitor.setTargets(socket->localAddress(), socket->peerAddress()))
+ if (connectionPrivate->connectionMonitor.setTargets(absSocket->localAddress(), absSocket->peerAddress()))
connectionPrivate->connectionMonitor.startMonitoring();
}
}
@@ -905,7 +938,7 @@ void QHttpNetworkConnectionChannel::_q_connected()
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
- if (auto socketSslContext = QSslSocketPrivate::sslContext(static_cast<QSslSocket*>(socket)))
+ if (auto socketSslContext = QSslSocketPrivate::sslContext(static_cast<QSslSocket*>(absSocket)))
connection->setSslContext(std::move(socketSslContext));
}
#endif
@@ -927,7 +960,7 @@ void QHttpNetworkConnectionChannel::_q_connected()
switchedToHttp2 = false;
if (!reply)
- connection->d_func()->dequeueRequest(socket);
+ connection->d_func()->dequeueRequest(absSocket);
if (reply) {
if (tryProtocolUpgrade) {
@@ -940,6 +973,22 @@ void QHttpNetworkConnectionChannel::_q_connected()
}
}
+void QHttpNetworkConnectionChannel::_q_connected_local_socket(QLocalSocket *localSocket)
+{
+ state = QHttpNetworkConnectionChannel::IdleState;
+ if (!reply) // No reply object, try to dequeue a request (which is paired with a reply):
+ connection->d_func()->dequeueRequest(localSocket);
+ if (reply)
+ sendRequest();
+}
+
+void QHttpNetworkConnectionChannel::_q_connected()
+{
+ if (auto *s = qobject_cast<QAbstractSocket *>(socket))
+ _q_connected_abstract_socket(s);
+ else if (auto *s = qobject_cast<QLocalSocket *>(socket))
+ _q_connected_local_socket(s);
+}
void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socketError)
{
@@ -1116,7 +1165,7 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
//signal emission triggered event loop
if (!socket)
state = QHttpNetworkConnectionChannel::IdleState;
- else if (socket->state() == QAbstractSocket::UnconnectedState)
+ else if (QSocketAbstraction::socketState(socket) == QAbstractSocket::UnconnectedState)
state = QHttpNetworkConnectionChannel::IdleState;
else
state = QHttpNetworkConnectionChannel::ClosingState;
diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h
index c42290feca..853b647ecc 100644
--- a/src/network/access/qhttpnetworkconnectionchannel_p.h
+++ b/src/network/access/qhttpnetworkconnectionchannel_p.h
@@ -19,6 +19,7 @@
#include <QtNetwork/qnetworkrequest.h>
#include <QtNetwork/qnetworkreply.h>
#include <QtNetwork/qabstractsocket.h>
+#include <QtNetwork/qlocalsocket.h>
#include <private/qobject_p.h>
#include <qauthenticator.h>
@@ -71,7 +72,7 @@ public:
ClosingState = 16,
BusyState = (ConnectingState|WritingState|WaitingState|ReadingState|ClosingState)
};
- QAbstractSocket *socket;
+ QIODevice *socket;
bool ssl;
bool isInitialized;
ChannelState state;
@@ -156,6 +157,8 @@ public:
void _q_bytesWritten(qint64 bytes); // proceed sending
void _q_readyRead(); // pending data to read
void _q_disconnected(); // disconnected from host
+ void _q_connected_abstract_socket(QAbstractSocket *socket);
+ void _q_connected_local_socket(QLocalSocket *socket);
void _q_connected(); // start sending request
void _q_error(QAbstractSocket::SocketError); // error from socket
#ifndef QT_NO_NETWORKPROXY
diff --git a/src/network/access/qhttpnetworkrequest.cpp b/src/network/access/qhttpnetworkrequest.cpp
index 7a4ffb1684..06cc0b4464 100644
--- a/src/network/access/qhttpnetworkrequest.cpp
+++ b/src/network/access/qhttpnetworkrequest.cpp
@@ -381,5 +381,15 @@ void QHttpNetworkRequest::setPeerVerifyName(const QString &peerName)
d->peerVerifyName = peerName;
}
+QString QHttpNetworkRequest::fullLocalServerName() const
+{
+ return d->fullLocalServerName;
+}
+
+void QHttpNetworkRequest::setFullLocalServerName(const QString &fullServerName)
+{
+ d->fullLocalServerName = fullServerName;
+}
+
QT_END_NAMESPACE
diff --git a/src/network/access/qhttpnetworkrequest_p.h b/src/network/access/qhttpnetworkrequest_p.h
index 131885f6d2..4444020402 100644
--- a/src/network/access/qhttpnetworkrequest_p.h
+++ b/src/network/access/qhttpnetworkrequest_p.h
@@ -117,6 +117,9 @@ public:
QString peerVerifyName() const;
void setPeerVerifyName(const QString &peerName);
+ QString fullLocalServerName() const;
+ void setFullLocalServerName(const QString &fullServerName);
+
private:
QSharedDataPointer<QHttpNetworkRequestPrivate> d;
friend class QHttpNetworkRequestPrivate;
@@ -140,6 +143,7 @@ public:
QHttpNetworkRequest::Operation operation;
QByteArray customVerb;
+ QString fullLocalServerName; // for local sockets
QHttpNetworkRequest::Priority priority;
mutable QNonContiguousByteDevice* uploadByteDevice;
bool autoDecompress;
diff --git a/src/network/access/qhttpthreaddelegate.cpp b/src/network/access/qhttpthreaddelegate.cpp
index b0ae0dcf44..4e5cf05aef 100644
--- a/src/network/access/qhttpthreaddelegate.cpp
+++ b/src/network/access/qhttpthreaddelegate.cpp
@@ -95,7 +95,9 @@ static QByteArray makeCacheKey(QUrl &url, QNetworkProxy *proxy, const QString &p
QUrl copy = url;
QString scheme = copy.scheme();
bool isEncrypted = scheme == "https"_L1 || scheme == "preconnect-https"_L1;
- copy.setPort(copy.port(isEncrypted ? 443 : 80));
+ const bool isLocalSocket = scheme.startsWith("unix"_L1);
+ if (!isLocalSocket)
+ copy.setPort(copy.port(isEncrypted ? 443 : 80));
if (scheme == "preconnect-http"_L1)
copy.setScheme("http"_L1);
else if (scheme == "preconnect-https"_L1)
@@ -145,9 +147,9 @@ class QNetworkAccessCachedHttpConnection: public QHttpNetworkConnection,
{
// Q_OBJECT
public:
- QNetworkAccessCachedHttpConnection(quint16 connectionCount, const QString &hostName, quint16 port, bool encrypt,
+ QNetworkAccessCachedHttpConnection(quint16 connectionCount, const QString &hostName, quint16 port, bool encrypt, bool isLocalSocket,
QHttpNetworkConnection::ConnectionType connectionType)
- : QHttpNetworkConnection(connectionCount, hostName, port, encrypt, /*parent=*/nullptr, connectionType)
+ : QHttpNetworkConnection(connectionCount, hostName, port, encrypt, isLocalSocket, /*parent=*/nullptr, connectionType)
{
setExpires(true);
setShareable(true);
@@ -244,7 +246,9 @@ void QHttpThreadDelegate::startRequest()
// check if we have an open connection to this host
QUrl urlCopy = httpRequest.url();
- urlCopy.setPort(urlCopy.port(ssl ? 443 : 80));
+ const bool isLocalSocket = urlCopy.scheme().startsWith("unix"_L1);
+ if (!isLocalSocket)
+ urlCopy.setPort(urlCopy.port(ssl ? 443 : 80));
QHttpNetworkConnection::ConnectionType connectionType
= httpRequest.isHTTP2Allowed() ? QHttpNetworkConnection::ConnectionTypeHTTP2
@@ -279,10 +283,19 @@ void QHttpThreadDelegate::startRequest()
} else
#endif // QT_CONFIG(ssl)
{
- urlCopy.setScheme(QStringLiteral("h2"));
+ if (isLocalSocket)
+ urlCopy.setScheme(QStringLiteral("unix+h2"));
+ else
+ urlCopy.setScheme(QStringLiteral("h2"));
}
}
+ QString extraData = httpRequest.peerVerifyName();
+ if (isLocalSocket) {
+ if (QString path = httpRequest.fullLocalServerName(); !path.isEmpty())
+ extraData = path;
+ }
+
#ifndef QT_NO_NETWORKPROXY
if (transparentProxy.type() != QNetworkProxy::NoProxy)
cacheKey = makeCacheKey(urlCopy, &transparentProxy, httpRequest.peerVerifyName());
@@ -295,10 +308,19 @@ void QHttpThreadDelegate::startRequest()
// the http object is actually a QHttpNetworkConnection
httpConnection = static_cast<QNetworkAccessCachedHttpConnection *>(connections.localData()->requestEntryNow(cacheKey));
if (!httpConnection) {
+
+ QString host = urlCopy.host();
+ // Update the host if a unix socket path or named pipe is used:
+ if (isLocalSocket) {
+ if (QString path = httpRequest.fullLocalServerName(); !path.isEmpty())
+ host = path;
+ }
+
// no entry in cache; create an object
// the http object is actually a QHttpNetworkConnection
- httpConnection = new QNetworkAccessCachedHttpConnection(http1Parameters.numberOfConnectionsPerHost(), urlCopy.host(), urlCopy.port(), ssl,
- connectionType);
+ httpConnection = new QNetworkAccessCachedHttpConnection(
+ http1Parameters.numberOfConnectionsPerHost(), host, urlCopy.port(), ssl,
+ isLocalSocket, connectionType);
if (connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2
|| connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) {
httpConnection->setHttp2Parameters(http2Parameters);
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp
index 7ef062a54d..b371730c3c 100644
--- a/src/network/access/qnetworkaccessmanager.cpp
+++ b/src/network/access/qnetworkaccessmanager.cpp
@@ -857,22 +857,15 @@ QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, const
}
/*!
- \overload
+ \fn QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, std::nullptr_t nptr)
\since 6.8
+ \overload
+
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)
/*!
@@ -958,22 +951,16 @@ QNetworkReply *QNetworkAccessManager::put(const QNetworkRequest &request, const
}
/*!
+ \since 6.8
+
\overload
- \since 6.8
+ \fn QNetworkReply *QNetworkAccessManager::put(const QNetworkRequest &request, std::nullptr_t nptr)
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
@@ -1220,6 +1207,13 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
bool isLocalFile = req.url().isLocalFile();
QString scheme = req.url().scheme();
+ // Remap local+http to unix+http to make further processing easier
+ if (scheme == "local+http"_L1) {
+ scheme = u"unix+http"_s;
+ QUrl url = req.url();
+ url.setScheme(scheme);
+ req.setUrl(url);
+ }
// fast path for GET on file:// URLs
// The QNetworkAccessFileBackend will right now only be used for PUT
@@ -1296,11 +1290,15 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
u"https",
u"preconnect-https",
#endif
+ u"unix+http",
};
// 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())) {
+ const bool isLocalSocket = scheme.startsWith("unix"_L1);
+ if (!isLocalSocket && isStrictTransportSecurityEnabled()
+ && d->stsCache.isKnownHost(request.url())) {
QUrl stsUrl(request.url());
// RFC6797, 8.3:
// The UA MUST replace the URI scheme with "https" [RFC2818],
@@ -1391,6 +1389,8 @@ QStringList QNetworkAccessManager::supportedSchemesImplementation() const
// Those ones don't exist in backends
#if QT_CONFIG(http)
schemes << QStringLiteral("http");
+ schemes << QStringLiteral("unix+http");
+ schemes << QStringLiteral("local+http");
#ifndef QT_NO_SSL
if (QSslSocket::supportsSsl())
schemes << QStringLiteral("https");
diff --git a/src/network/access/qnetworkaccessmanager.h b/src/network/access/qnetworkaccessmanager.h
index 0d069b2a9b..4bae05772f 100644
--- a/src/network/access/qnetworkaccessmanager.h
+++ b/src/network/access/qnetworkaccessmanager.h
@@ -84,10 +84,18 @@ public:
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 *post(const QNetworkRequest &request, std::nullptr_t)
+ {
+ return post(request, static_cast<QIODevice*>(nullptr));
+ }
+
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 *put(const QNetworkRequest &request, std::nullptr_t)
+ {
+ return put(request, static_cast<QIODevice*>(nullptr));
+ }
+
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);
diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp
index 3e1fe761ee..89458825e9 100644
--- a/src/network/access/qnetworkreplyhttpimpl.cpp
+++ b/src/network/access/qnetworkreplyhttpimpl.cpp
@@ -809,6 +809,13 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq
httpRequest.setPeerVerifyName(newHttpRequest.peerVerifyName());
+ if (scheme.startsWith(("unix"_L1))) {
+ if (QVariant path = newHttpRequest.attribute(QNetworkRequest::FullLocalServerNameAttribute);
+ path.isValid() && path.canConvert<QString>()) {
+ httpRequest.setFullLocalServerName(path.toString());
+ }
+ }
+
// Create the HTTP thread delegate
QHttpThreadDelegate *delegate = new QHttpThreadDelegate;
// Propagate Http/2 settings:
@@ -1228,7 +1235,8 @@ void QNetworkReplyHttpImplPrivate::onRedirected(const QUrl &redirectUrl, int htt
if (httpRequest.isFollowRedirects()) // update the reply's url as it could've changed
url = redirectUrl;
- if (managerPrivate->stsEnabled && managerPrivate->stsCache.isKnownHost(url)) {
+ const bool wasLocalSocket = schemeBefore.startsWith("unix"_L1);
+ if (!wasLocalSocket && managerPrivate->stsEnabled && managerPrivate->stsCache.isKnownHost(url)) {
// RFC6797, 8.3:
// The UA MUST replace the URI scheme with "https" [RFC2818],
// and if the URI contains an explicit port component of "80",
@@ -1242,9 +1250,12 @@ void QNetworkReplyHttpImplPrivate::onRedirected(const QUrl &redirectUrl, int htt
url.setPort(443);
}
- const bool isLessSafe = schemeBefore == "https"_L1 && url.scheme() == "http"_L1;
- if (httpRequest.redirectPolicy() == QNetworkRequest::NoLessSafeRedirectPolicy
- && isLessSafe) {
+ // Just to be on the safe side for local sockets, any changes to the scheme
+ // are considered less safe
+ const bool changingLocalScheme = wasLocalSocket && url.scheme() != schemeBefore;
+ const bool isLessSafe = changingLocalScheme
+ || (schemeBefore == "https"_L1 && url.scheme() == "http"_L1);
+ if (httpRequest.redirectPolicy() == QNetworkRequest::NoLessSafeRedirectPolicy && isLessSafe) {
error(QNetworkReply::InsecureRedirectError,
QCoreApplication::translate("QHttp", "Insecure redirect"));
return;
diff --git a/src/network/access/qnetworkreplywasmimpl.cpp b/src/network/access/qnetworkreplywasmimpl.cpp
index 7d2b6a701e..ccf1542958 100644
--- a/src/network/access/qnetworkreplywasmimpl.cpp
+++ b/src/network/access/qnetworkreplywasmimpl.cpp
@@ -4,7 +4,6 @@
#include "qnetworkreplywasmimpl_p.h"
#include "qnetworkrequest.h"
-#include <QtCore/qtimer.h>
#include <QtCore/qdatetime.h>
#include <QtCore/qcoreapplication.h>
#include <QtCore/qfileinfo.h>
diff --git a/src/network/access/qnetworkrequest.cpp b/src/network/access/qnetworkrequest.cpp
index 7a1b5426d2..2fb467d3a8 100644
--- a/src/network/access/qnetworkrequest.cpp
+++ b/src/network/access/qnetworkrequest.cpp
@@ -144,7 +144,8 @@ QT_IMPL_METATYPE_EXTERN_TAGGED(QNetworkRequest::RedirectPolicy, QNetworkRequest_
server (like "Ok", "Found", "Not Found", "Access Denied",
etc.) This is the human-readable representation of the status
code (see above). If the connection was not HTTP-based, this
- attribute will not be present.
+ attribute will not be present. \e{Note:} The reason phrase is
+ not used when using HTTP/2.
\value RedirectionTargetAttribute
Replies only, type: QMetaType::QUrl (no default)
@@ -324,6 +325,16 @@ QT_IMPL_METATYPE_EXTERN_TAGGED(QNetworkRequest::RedirectPolicy, QNetworkRequest_
same-origin requests. This only affects the WebAssembly platform.
(This value was introduced in 6.5.)
+ \value FullLocalServerNameAttribute
+ Requests only, type: QMetaType::String
+ Holds the full local server name to be used for the underlying
+ QLocalSocket. This attribute is used by the QNetworkAccessManager
+ to connect to a specific local server, when QLocalSocket's behavior for
+ a simple name isn't enough. The URL in the QNetworkRequest must still
+ use unix+http: or local+http: scheme. And the hostname in the URL will
+ be used for the Host header in the HTTP request.
+ (This value was introduced in 6.8.)
+
\value User
Special type. Additional information can be passed in
QVariants with types ranging from User to UserMax. The default
diff --git a/src/network/access/qnetworkrequest.h b/src/network/access/qnetworkrequest.h
index e281c74834..368eb99d95 100644
--- a/src/network/access/qnetworkrequest.h
+++ b/src/network/access/qnetworkrequest.h
@@ -70,6 +70,7 @@ public:
ConnectionCacheExpiryTimeoutSecondsAttribute,
Http2CleartextAllowedAttribute,
UseCredentialsAttribute,
+ FullLocalServerNameAttribute,
User = 1000,
UserMax = 32767
diff --git a/src/network/access/qnetworkrequestfactory.cpp b/src/network/access/qnetworkrequestfactory.cpp
index d9c536cef2..4666891b2e 100644
--- a/src/network/access/qnetworkrequestfactory.cpp
+++ b/src/network/access/qnetworkrequestfactory.cpp
@@ -17,7 +17,7 @@ QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QNetworkRequestFactoryPrivate)
using namespace Qt::StringLiterals;
-Q_LOGGING_CATEGORY(lcQrequestfactory, "qt.network.access.request.factory")
+Q_STATIC_LOGGING_CATEGORY(lcQrequestfactory, "qt.network.access.request.factory")
/*!
\class QNetworkRequestFactory
@@ -28,8 +28,6 @@ Q_LOGGING_CATEGORY(lcQrequestfactory, "qt.network.access.request.factory")
\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
diff --git a/src/network/access/qnetworkrequestfactory.h b/src/network/access/qnetworkrequestfactory.h
index 9d955a51e7..c170b75c8e 100644
--- a/src/network/access/qnetworkrequestfactory.h
+++ b/src/network/access/qnetworkrequestfactory.h
@@ -25,7 +25,7 @@ class QSslConfiguration;
class QNetworkRequestFactoryPrivate;
QT_DECLARE_QESDP_SPECIALIZATION_DTOR_WITH_EXPORT(QNetworkRequestFactoryPrivate, Q_NETWORK_EXPORT)
-class QT_TECH_PREVIEW_API QNetworkRequestFactory
+class QNetworkRequestFactory
{
public:
Q_NETWORK_EXPORT QNetworkRequestFactory();
diff --git a/src/network/access/qrestaccessmanager.cpp b/src/network/access/qrestaccessmanager.cpp
index 7ef682e955..9e0182c7cb 100644
--- a/src/network/access/qrestaccessmanager.cpp
+++ b/src/network/access/qrestaccessmanager.cpp
@@ -31,8 +31,6 @@ Q_LOGGING_CATEGORY(lcQrest, "qt.network.access.rest")
\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.
diff --git a/src/network/access/qrestaccessmanager.h b/src/network/access/qrestaccessmanager.h
index 3245b41785..d72c075bf8 100644
--- a/src/network/access/qrestaccessmanager.h
+++ b/src/network/access/qrestaccessmanager.h
@@ -74,7 +74,7 @@ QNetworkReply *customWithDataImpl(const QNetworkRequest& request, const QByteArr
/* end */
class QRestAccessManagerPrivate;
-class QT_TECH_PREVIEW_API Q_NETWORK_EXPORT QRestAccessManager : public QObject
+class Q_NETWORK_EXPORT QRestAccessManager : public QObject
{
Q_OBJECT
using CallbackPrototype = void(*)(QRestReply&);
diff --git a/src/network/access/qrestaccessmanager_p.h b/src/network/access/qrestaccessmanager_p.h
index 2e6c1afb90..5fa2cc9e5a 100644
--- a/src/network/access/qrestaccessmanager_p.h
+++ b/src/network/access/qrestaccessmanager_p.h
@@ -20,6 +20,7 @@
#include <QtNetwork/qnetworkaccessmanager.h>
+#include <QtCore/qloggingcategory.h>
#include <QtCore/qjsonarray.h>
#include <QtCore/qhash.h>
#include <QtCore/qjsondocument.h>
@@ -28,6 +29,8 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcQrest)
+
class QRestReply;
class QRestAccessManagerPrivate : public QObjectPrivate
{
diff --git a/src/network/access/qrestreply.cpp b/src/network/access/qrestreply.cpp
index 2d8d101084..204ecf6553 100644
--- a/src/network/access/qrestreply.cpp
+++ b/src/network/access/qrestreply.cpp
@@ -5,6 +5,7 @@
#include "qrestreply_p.h"
#include <QtNetwork/private/qnetworkreply_p.h>
+#include <QtNetwork/private/qrestaccessmanager_p.h>
#include <QtCore/qbytearrayview.h>
#include <QtCore/qjsondocument.h>
@@ -18,7 +19,6 @@
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
-Q_DECLARE_LOGGING_CATEGORY(lcQrest)
/*!
\class QRestReply
@@ -29,8 +29,6 @@ Q_DECLARE_LOGGING_CATEGORY(lcQrest)
\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.
diff --git a/src/network/access/qrestreply.h b/src/network/access/qrestreply.h
index c32fff1d4e..61aa7a6788 100644
--- a/src/network/access/qrestreply.h
+++ b/src/network/access/qrestreply.h
@@ -20,7 +20,7 @@ class QJsonDocument;
class QString;
class QRestReplyPrivate;
-class QT_TECH_PREVIEW_API QRestReply
+class QRestReply
{
public:
Q_NETWORK_EXPORT explicit QRestReply(QNetworkReply *reply);
diff --git a/src/network/android/jar/build.gradle b/src/network/android/jar/build.gradle
index 68a9381ad2..ea6d06c257 100644
--- a/src/network/android/jar/build.gradle
+++ b/src/network/android/jar/build.gradle
@@ -7,7 +7,7 @@ buildscript {
}
dependencies {
- classpath 'com.android.tools.build:gradle:8.0.2'
+ classpath 'com.android.tools.build:gradle:8.4.0'
}
}
@@ -26,7 +26,7 @@ android {
compileSdk 34
defaultConfig {
- minSdkVersion 23
+ minSdkVersion 28
}
sourceSets {
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
index eb6a16d5b7..5272a2caf0 100644
--- 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
@@ -11,7 +11,7 @@ import android.net.ConnectivityManager;
import android.net.Proxy;
import android.net.ProxyInfo;
-public class QtNetwork
+class QtNetwork
{
private static final String LOG_TAG = "QtNetwork";
private static ProxyReceiver m_proxyReceiver = null;
@@ -29,7 +29,7 @@ public class QtNetwork
private QtNetwork() {}
- public static void registerReceiver(final Context context)
+ static void registerReceiver(final Context context)
{
synchronized (m_lock) {
if (m_proxyReceiver == null) {
@@ -40,7 +40,7 @@ public class QtNetwork
}
}
- public static void unregisterReceiver(final Context context)
+ static void unregisterReceiver(final Context context)
{
synchronized (m_lock) {
if (m_proxyReceiver == null)
@@ -50,12 +50,12 @@ public class QtNetwork
}
}
- public static ConnectivityManager getConnectivityManager(final Context context)
+ static ConnectivityManager getConnectivityManager(final Context context)
{
return (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
}
- public static ProxyInfo getProxyInfo(final Context context)
+ static ProxyInfo getProxyInfo(final Context context)
{
if (m_proxyInfo == null)
m_proxyInfo = (ProxyInfo)getConnectivityManager(context).getDefaultProxy();
diff --git a/src/network/kernel/qdnslookup.cpp b/src/network/kernel/qdnslookup.cpp
index 1b4db7130b..e25662b33c 100644
--- a/src/network/kernel/qdnslookup.cpp
+++ b/src/network/kernel/qdnslookup.cpp
@@ -24,7 +24,7 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
-static Q_LOGGING_CATEGORY(lcDnsLookup, "qt.network.dnslookup", QtCriticalMsg)
+Q_STATIC_LOGGING_CATEGORY(lcDnsLookup, "qt.network.dnslookup", QtCriticalMsg)
namespace {
struct QDnsLookupThreadPool : QThreadPool
@@ -336,7 +336,7 @@ quint16 QDnsLookup::defaultPortForProtocol(Protocol protocol) noexcept
*/
/*!
- \fn void QDnsLookup::typeChanged(Type type)
+ \fn void QDnsLookup::typeChanged(QDnsLookup::Type type)
This signal is emitted when the lookup \l type changes.
\a type is the new lookup type.
@@ -1295,7 +1295,7 @@ QDnsTextRecord &QDnsTextRecord::operator=(const QDnsTextRecord &other)
\sa QDnsLookup
*/
-QT_DEFINE_QSDP_SPECIALIZATION_DTOR(QDnsTlsAssociationRecordPrivate)
+QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QDnsTlsAssociationRecordPrivate)
/*!
\enum QDnsTlsAssociationRecord::CertificateUsage
@@ -1347,7 +1347,7 @@ QT_DEFINE_QSDP_SPECIALIZATION_DTOR(QDnsTlsAssociationRecordPrivate)
standards. This enumeration can be used for those values even if no
enumerator is provided.
- \sa certificateUsage()
+ \sa usage()
*/
/*!
@@ -1415,7 +1415,7 @@ QT_DEFINE_QSDP_SPECIALIZATION_DTOR(QDnsTlsAssociationRecordPrivate)
standards. This enumeration can be used for those values even if no
enumerator is provided.
- \sa matchingType()
+ \sa matchType()
*/
/*!
diff --git a/src/network/kernel/qdnslookup.h b/src/network/kernel/qdnslookup.h
index 8d21e99c84..0cf601698f 100644
--- a/src/network/kernel/qdnslookup.h
+++ b/src/network/kernel/qdnslookup.h
@@ -25,7 +25,7 @@ class QDnsTextRecordPrivate;
class QDnsTlsAssociationRecordPrivate;
class QSslConfiguration;
-QT_DECLARE_QSDP_SPECIALIZATION_DTOR(QDnsTlsAssociationRecordPrivate)
+QT_DECLARE_QESDP_SPECIALIZATION_DTOR(QDnsTlsAssociationRecordPrivate)
class Q_NETWORK_EXPORT QDnsDomainNameRecord
{
@@ -144,6 +144,7 @@ Q_DECLARE_SHARED(QDnsTextRecord)
class Q_NETWORK_EXPORT QDnsTlsAssociationRecord
{
Q_GADGET
+ Q_CLASSINFO("RegisterEnumClassesUnscoped", "false")
public:
enum class CertificateUsage : quint8 {
// https://www.iana.org/assignments/dane-parameters/dane-parameters.xhtml#certificate-usages
@@ -190,10 +191,8 @@ public:
QDnsTlsAssociationRecord();
QDnsTlsAssociationRecord(const QDnsTlsAssociationRecord &other);
- QDnsTlsAssociationRecord(QDnsTlsAssociationRecord &&other)
- : d(std::move(other.d))
- {}
- QDnsTlsAssociationRecord &operator=(QDnsTlsAssociationRecord &&other) noexcept { swap(other); return *this; }
+ QDnsTlsAssociationRecord(QDnsTlsAssociationRecord &&other) noexcept = default;
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QDnsTlsAssociationRecord)
QDnsTlsAssociationRecord &operator=(const QDnsTlsAssociationRecord &other);
~QDnsTlsAssociationRecord();
@@ -207,7 +206,7 @@ public:
QByteArray value() const;
private:
- QSharedDataPointer<QDnsTlsAssociationRecordPrivate> d;
+ QExplicitlySharedDataPointer<QDnsTlsAssociationRecordPrivate> d;
friend class QDnsLookupRunnable;
};
@@ -323,10 +322,10 @@ public Q_SLOTS:
Q_SIGNALS:
void finished();
void nameChanged(const QString &name);
- void typeChanged(Type type);
+ void typeChanged(QDnsLookup::Type type);
void nameserverChanged(const QHostAddress &nameserver);
void nameserverPortChanged(quint16 port);
- void nameserverProtocolChanged(Protocol protocol);
+ void nameserverProtocolChanged(QDnsLookup::Protocol protocol);
private:
Q_DECLARE_PRIVATE(QDnsLookup)
diff --git a/src/network/kernel/qnetworkinformation.cpp b/src/network/kernel/qnetworkinformation.cpp
index 10d6b89e2c..5115372b20 100644
--- a/src/network/kernel/qnetworkinformation.cpp
+++ b/src/network/kernel/qnetworkinformation.cpp
@@ -328,7 +328,7 @@ QNetworkInformationBackend::~QNetworkInformationBackend() = default;
*/
/*!
- \fn void QNetworkInformationBackend::reachabilityChanged()
+ \fn void QNetworkInformationBackend::reachabilityChanged(NetworkInformation::Reachability reachability)
You should not emit this signal manually, call setReachability()
instead which will emit this signal when the value changes.
diff --git a/src/network/kernel/qnetworkinformation.h b/src/network/kernel/qnetworkinformation.h
index 57a49f23c8..72e2b59550 100644
--- a/src/network/kernel/qnetworkinformation.h
+++ b/src/network/kernel/qnetworkinformation.h
@@ -76,9 +76,9 @@ public:
static QNetworkInformation *instance();
Q_SIGNALS:
- void reachabilityChanged(Reachability newReachability);
+ void reachabilityChanged(QNetworkInformation::Reachability newReachability);
void isBehindCaptivePortalChanged(bool state);
- void transportMediumChanged(TransportMedium current);
+ void transportMediumChanged(QNetworkInformation::TransportMedium current);
void isMeteredChanged(bool isMetered);
private:
diff --git a/src/network/kernel/qnetworkinformation_p.h b/src/network/kernel/qnetworkinformation_p.h
index 504955a6e1..76b2937ced 100644
--- a/src/network/kernel/qnetworkinformation_p.h
+++ b/src/network/kernel/qnetworkinformation_p.h
@@ -74,9 +74,9 @@ public:
}
Q_SIGNALS:
- void reachabilityChanged(Reachability reachability);
+ void reachabilityChanged(QNetworkInformation::Reachability reachability);
void behindCaptivePortalChanged(bool behindPortal);
- void transportMediumChanged(TransportMedium medium);
+ void transportMediumChanged(QNetworkInformation::TransportMedium medium);
void isMeteredChanged(bool isMetered);
protected:
diff --git a/src/network/kernel/qnetworkinterface_unix.cpp b/src/network/kernel/qnetworkinterface_unix.cpp
index c0a7d9e00d..39ff8dbb92 100644
--- a/src/network/kernel/qnetworkinterface_unix.cpp
+++ b/src/network/kernel/qnetworkinterface_unix.cpp
@@ -310,12 +310,20 @@ QT_BEGIN_INCLUDE_NAMESPACE
QT_END_INCLUDE_NAMESPACE
# endif
+static int openSocket(int &socket)
+{
+ if (socket == -1)
+ socket = qt_safe_socket(AF_INET, SOCK_DGRAM, 0);
+ return socket;
+}
+
# if defined(Q_OS_LINUX) && __GLIBC__ - 0 >= 2 && __GLIBC_MINOR__ - 0 >= 1 && !defined(QT_LINUXBASE)
# include <netpacket/packet.h>
static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList)
{
Q_UNUSED(getMtu);
+ Q_UNUSED(openSocket);
QList<QNetworkInterfacePrivate *> interfaces;
QDuplicateTracker<QString> seenInterfaces;
QDuplicateTracker<int> seenIndexes;
@@ -387,13 +395,6 @@ QT_BEGIN_INCLUDE_NAMESPACE
#endif // QT_PLATFORM_UIKIT
QT_END_INCLUDE_NAMESPACE
-static int openSocket(int &socket)
-{
- if (socket == -1)
- socket = qt_safe_socket(AF_INET, SOCK_DGRAM, 0);
- return socket;
-}
-
static QNetworkInterface::InterfaceType probeIfType(int socket, int iftype, struct ifmediareq *req)
{
// Determine the interface type.
@@ -537,8 +538,8 @@ static void getAddressExtraInfo(QNetworkAddressEntry *entry, struct sockaddr *sa
static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList)
{
- Q_UNUSED(getMtu);
QList<QNetworkInterfacePrivate *> interfaces;
+ int socket = -1;
// make sure there's one entry for each interface
for (ifaddrs *ptr = rawList; ptr; ptr = ptr->ifa_next) {
@@ -559,9 +560,18 @@ static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList)
iface->index = ifindex;
iface->name = QString::fromLatin1(ptr->ifa_name);
iface->flags = convertFlags(ptr->ifa_flags);
+
+ if ((socket = openSocket(socket)) >= 0) {
+ struct ifreq ifr;
+ qstrncpy(ifr.ifr_name, ptr->ifa_name, sizeof(ifr.ifr_name));
+ iface->mtu = getMtu(socket, &ifr);
+ }
}
}
+ if (socket != -1)
+ qt_safe_close(socket);
+
return interfaces;
}
diff --git a/src/network/kernel/qnetworkproxy_android.cpp b/src/network/kernel/qnetworkproxy_android.cpp
index 3d37266b70..d5b56bba86 100644
--- a/src/network/kernel/qnetworkproxy_android.cpp
+++ b/src/network/kernel/qnetworkproxy_android.cpp
@@ -19,26 +19,21 @@ public:
};
using namespace QNativeInterface;
+using namespace QtJniTypes;
Q_GLOBAL_STATIC(ProxyInfoObject, proxyInfoInstance)
-static const char networkClass[] = "org/qtproject/qt/android/network/QtNetwork";
-
+Q_DECLARE_JNI_CLASS(QtNetwork, "org/qtproject/qt/android/network/QtNetwork")
Q_DECLARE_JNI_CLASS(ProxyInfo, "android/net/ProxyInfo")
-Q_DECLARE_JNI_TYPE(JStringArray, "[Ljava/lang/String;")
ProxyInfoObject::ProxyInfoObject()
{
- QJniObject::callStaticMethod<void>(networkClass,
- "registerReceiver",
- QAndroidApplication::context());
+ QtNetwork::callStaticMethod<void>("registerReceiver", QAndroidApplication::context());
}
ProxyInfoObject::~ProxyInfoObject()
{
- QJniObject::callStaticMethod<void>(networkClass,
- "unregisterReceiver",
- QAndroidApplication::context());
+ QtNetwork::callStaticMethod<void>("unregisterReceiver", QAndroidApplication::context());
}
QList<QNetworkProxy> QNetworkProxyFactory::systemProxyForQuery(const QNetworkProxyQuery &query)
@@ -47,20 +42,14 @@ QList<QNetworkProxy> QNetworkProxyFactory::systemProxyForQuery(const QNetworkPro
if (!proxyInfoInstance)
return proxyList;
- QJniObject proxyInfo = QJniObject::callStaticObjectMethod<QtJniTypes::ProxyInfo>(
- networkClass, "getProxyInfo", QAndroidApplication::context());
+ QJniObject proxyInfo = QtNetwork::callStaticMethod<ProxyInfo>("getProxyInfo",
+ QAndroidApplication::context());
if (proxyInfo.isValid()) {
- QJniObject exclusionList =
- proxyInfo.callObjectMethod<QtJniTypes::JStringArray>("getExclusionList");
+ const QJniArray exclusionList = proxyInfo.callMethod<String[]>("getExclusionList");
bool exclude = false;
if (exclusionList.isValid()) {
- 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) {
- entry = env->GetObjectArrayElement(listObject, i);
+ const QUrl host = QUrl(query.url().host());
+ for (const auto &entry : exclusionList) {
if (host.matches(QUrl(entry.toString()), QUrl::RemoveScheme)) {
exclude = true;
break;
@@ -68,9 +57,9 @@ QList<QNetworkProxy> QNetworkProxyFactory::systemProxyForQuery(const QNetworkPro
}
}
if (!exclude) {
- QJniObject hostName = proxyInfo.callObjectMethod<jstring>("getHost");
+ const QString hostName = proxyInfo.callMethod<QString>("getHost");
const int port = proxyInfo.callMethod<jint>("getPort");
- QNetworkProxy proxy(QNetworkProxy::HttpProxy, hostName.toString(), port);
+ QNetworkProxy proxy(QNetworkProxy::HttpProxy, hostName, port);
proxyList << proxy;
}
}
diff --git a/src/network/kernel/qtldurl.cpp b/src/network/kernel/qtldurl.cpp
index a7aceddb18..4ad11d8c36 100644
--- a/src/network/kernel/qtldurl.cpp
+++ b/src/network/kernel/qtldurl.cpp
@@ -28,7 +28,9 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
-Q_LOGGING_CATEGORY(lcTld, "qt.network.tld")
+#if QT_CONFIG(publicsuffix_system)
+Q_STATIC_LOGGING_CATEGORY(lcTld, "qt.network.tld")
+#endif
static constexpr int PSL_NOT_FOUND = -1;
static constexpr int PSL_FLAG_EXCEPTION = 1 << 0;
diff --git a/src/network/socket/qlocalserver.cpp b/src/network/socket/qlocalserver.cpp
index 5ef2db6b94..72b6d5ec90 100644
--- a/src/network/socket/qlocalserver.cpp
+++ b/src/network/socket/qlocalserver.cpp
@@ -277,10 +277,10 @@ void QLocalServer::incomingConnection(quintptr socketDescriptor)
\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
+ newConnection() signal after the socket has been
added.
- \sa incomingConnection(), pendingConnectionAvailable()
+ \sa incomingConnection(), newConnection()
\since 6.8
*/
void QLocalServer::addPendingConnection(QLocalSocket *socket)