summaryrefslogtreecommitdiffstats
path: root/src/network/access/qnetworkaccessmanager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/network/access/qnetworkaccessmanager.cpp')
-rw-r--r--src/network/access/qnetworkaccessmanager.cpp448
1 files changed, 279 insertions, 169 deletions
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp
index debdaaa5d4..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>
@@ -54,23 +18,23 @@
#include "qhstsstore_p.h"
#endif // QT_CONFIG(settings)
-#if QT_CONFIG(ftp)
-#include "qnetworkaccessftpbackend_p.h"
-#endif
#include "qnetworkaccessfilebackend_p.h"
#include "qnetworkaccessdebugpipebackend_p.h"
#include "qnetworkaccesscachebackend_p.h"
#include "qnetworkreplydataimpl_p.h"
#include "qnetworkreplyfileimpl_p.h"
+#include "qnetworkaccessbackend_p.h"
+#include "qnetworkreplyimpl_p.h"
+
#include "QtCore/qbuffer.h"
#include "QtCore/qlist.h"
#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,90 +44,117 @@
#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"
+#include "qhttpmultipart.h"
+#include "qhttpmultipart_p.h"
#endif
#include "qnetconmonitor_p.h"
+#include <mutex>
+
QT_BEGIN_NAMESPACE
-Q_GLOBAL_STATIC(QNetworkAccessFileBackendFactory, fileBackend)
-#if QT_CONFIG(ftp)
-Q_GLOBAL_STATIC(QNetworkAccessFtpBackendFactory, ftpBackend)
-#endif // QT_CONFIG(ftp)
+using namespace Qt::StringLiterals;
+using namespace std::chrono_literals;
+
+Q_LOGGING_CATEGORY(lcQnam, "qt.network.access.manager")
-#ifdef QT_BUILD_INTERNAL
+Q_APPLICATION_STATIC(QNetworkAccessFileBackendFactory, fileBackend)
+
+#if QT_CONFIG(private_tests)
Q_GLOBAL_STATIC(QNetworkAccessDebugPipeBackendFactory, debugpipeBackend)
#endif
-#if defined(Q_OS_MACX)
+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;
}
- return retValue;
+
+ 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;
+ }
+ 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()
{
-#if QT_CONFIG(ftp)
- (void) ftpBackend();
-#endif
-
-#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
@@ -406,6 +397,7 @@ QNetworkAccessManager::QNetworkAccessManager(QObject *parent)
: QObject(*new QNetworkAccessManagerPrivate, parent)
{
ensureInitialized();
+ d_func()->ensureBackendPluginsLoaded();
qRegisterMetaType<QNetworkReply::NetworkError>();
#ifndef QT_NO_NETWORKPROXY
@@ -682,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(),
@@ -789,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
@@ -824,7 +856,25 @@ QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, const
return reply;
}
-#if QT_CONFIG(http)
+/*!
+ \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
@@ -908,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.
@@ -930,9 +997,9 @@ QNetworkReply *QNetworkAccessManager::deleteResource(const QNetworkRequest &requ
\a sslConfiguration. This function is useful to complete the TCP and SSL handshake
to a host before the HTTPS request is made, resulting in a lower network latency.
- \note Preconnecting a SPDY connection can be done by calling setAllowedNextProtocols()
- on \a sslConfiguration with QSslConfiguration::NextProtocolSpdy3_0 contained in
- the list of allowed protocols. When using SPDY, one single connection per host is
+ \note Preconnecting a HTTP/2 connection can be done by calling setAllowedNextProtocols()
+ on \a sslConfiguration with QSslConfiguration::ALPNProtocolHTTP2 contained in
+ the list of allowed protocols. When using HTTP/2, one single connection per host is
enough, i.e. calling this method multiple times per host will not result in faster
network transactions.
@@ -956,9 +1023,9 @@ void QNetworkAccessManager::connectToHostEncrypted(const QString &hostName, quin
validation. This function is useful to complete the TCP and SSL handshake
to a host before the HTTPS request is made, resulting in a lower network latency.
- \note Preconnecting a SPDY connection can be done by calling setAllowedNextProtocols()
- on \a sslConfiguration with QSslConfiguration::NextProtocolSpdy3_0 contained in
- the list of allowed protocols. When using SPDY, one single connection per host is
+ \note Preconnecting a HTTP/2 connection can be done by calling setAllowedNextProtocols()
+ on \a sslConfiguration with QSslConfiguration::ALPNProtocolHTTP2 contained in
+ the list of allowed protocols. When using HTTP/2, one single connection per host is
enough, i.e. calling this method multiple times per host will not result in faster
network transactions.
@@ -974,15 +1041,15 @@ 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);
- // There is no way to enable HTTP2 via a request, so we need to check
- // the ssl configuration whether HTTP2 is allowed here.
- if (sslConfiguration.allowedNextProtocols().contains(QSslConfiguration::ALPNProtocolHTTP2))
- request.setAttribute(QNetworkRequest::Http2AllowedAttribute, true);
+ // There is no way to enable HTTP2 via a request after having established the connection,
+ // so we need to check the ssl configuration whether HTTP2 is allowed here.
+ if (!sslConfiguration.allowedNextProtocols().contains(QSslConfiguration::ALPNProtocolHTTP2))
+ request.setAttribute(QNetworkRequest::Http2AllowedAttribute, false);
request.setPeerVerifyName(peerName);
get(request);
@@ -1005,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);
}
@@ -1019,16 +1086,13 @@ void QNetworkAccessManager::connectToHost(const QString &hostName, quint16 port)
Use this function to enable or disable HTTP redirects on the manager's level.
\note When creating a request QNetworkRequest::RedirectAttributePolicy has
- the highest priority, next by priority is QNetworkRequest::FollowRedirectsAttribute.
- Finally, the manager's policy has the lowest priority.
+ the highest priority, next by priority the manager's policy.
- For backwards compatibility the default value is QNetworkRequest::ManualRedirectPolicy.
- This may change in the future and some type of auto-redirect policy will become
- the default; clients relying on manual redirect handling are encouraged to set
+ The default value is QNetworkRequest::NoLessSafeRedirectPolicy.
+ Clients relying on manual redirect handling are encouraged to set
this policy explicitly in their code.
- \sa redirectPolicy(), QNetworkRequest::RedirectPolicy,
- QNetworkRequest::FollowRedirectsAttribute
+ \sa redirectPolicy(), QNetworkRequest::RedirectPolicy
*/
void QNetworkAccessManager::setRedirectPolicy(QNetworkRequest::RedirectPolicy policy)
{
@@ -1094,7 +1158,7 @@ QNetworkReply *QNetworkAccessManager::sendCustomRequest(const QNetworkRequest &r
return reply;
}
-#if QT_CONFIG(http)
+#if QT_CONFIG(http) || defined(Q_OS_WASM)
/*!
\since 5.8
@@ -1138,15 +1202,14 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
Q_D(QNetworkAccessManager);
QNetworkRequest req(originalReq);
- if (redirectPolicy() != QNetworkRequest::ManualRedirectPolicy
- && req.attribute(QNetworkRequest::RedirectPolicyAttribute).isNull()
- && req.attribute(QNetworkRequest::FollowRedirectsAttribute).isNull()) {
+ if (redirectPolicy() != QNetworkRequest::NoLessSafeRedirectPolicy
+ && req.attribute(QNetworkRequest::RedirectPolicyAttribute).isNull()) {
req.setAttribute(QNetworkRequest::RedirectPolicyAttribute, redirectPolicy());
}
-#if QT_CONFIG(http)
- if (!req.transferTimeout())
- req.setTransferTimeout(transferTimeout());
+#if QT_CONFIG(http) || defined (Q_OS_WASM)
+ if (req.transferTimeoutAsDuration() == 0ms)
+ req.setTransferTimeout(transferTimeoutAsDuration());
#endif
if (autoDeleteReplies()
@@ -1157,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
@@ -1165,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
@@ -1185,22 +1247,22 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
QNetworkReplyImplPrivate *priv = reply->d_func();
priv->manager = this;
priv->backend = new QNetworkAccessCacheBackend();
- priv->backend->manager = this->d_func();
+ priv->backend->setManagerPrivate(this->d_func());
priv->backend->setParent(reply);
- priv->backend->reply = priv;
+ priv->backend->setReplyPrivate(priv);
priv->setup(op, req, outgoingData);
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() &&
outgoingData && !outgoingData->isSequential()) {
// request has no Content-Length
// but the data that is outgoing is random-access
request.setHeader(QNetworkRequest::ContentLengthHeader, outgoingData->size());
}
-
+#endif
if (static_cast<QNetworkRequest::LoadControl>
(request.attribute(QNetworkRequest::CookieLoadControlAttribute,
QNetworkRequest::Automatic).toInt()) == QNetworkRequest::Automatic) {
@@ -1211,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;
@@ -1222,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());
@@ -1242,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
@@ -1265,7 +1332,7 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
if (priv->backend) {
priv->backend->setParent(reply);
- priv->backend->reply = priv;
+ priv->backend->setReplyPrivate(priv);
}
#ifndef QT_NO_SSL
@@ -1283,7 +1350,9 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
Lists all the URL schemes supported by the access manager.
- \sa supportedSchemesImplementation()
+ Reimplement this method to provide your own supported schemes
+ in a QNetworkAccessManager subclass. It is for instance necessary
+ when your subclass provides support for new protocols.
*/
QStringList QNetworkAccessManager::supportedSchemes() const
{
@@ -1297,19 +1366,16 @@ QStringList QNetworkAccessManager::supportedSchemes() const
/*!
\since 5.2
+ \deprecated
Lists all the URL schemes supported by the access manager.
You should not call this function directly; use
QNetworkAccessManager::supportedSchemes() instead.
- Reimplement this slot to provide your own supported schemes
- in a QNetworkAccessManager subclass. It is for instance necessary
- when your subclass provides support for new protocols.
-
Because of binary compatibility constraints, the supportedSchemes()
- method (introduced in Qt 5.2) is not virtual. Instead, supportedSchemes()
- will dynamically detect and call this slot.
+ method (introduced in Qt 5.2) was not virtual in Qt 5, but now it
+ is. Override the supportedSchemes method rather than this one.
\sa supportedSchemes()
*/
@@ -1394,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()
+*/
+
+/*!
+ \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()
*/
-int QNetworkAccessManager::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 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)
@@ -1511,9 +1598,10 @@ void QNetworkAccessManagerPrivate::authenticationRequired(QAuthenticator *authen
// also called when last URL is empty, e.g. on first call
if (allowAuthenticationReuse && (urlForLastAuthentication->isEmpty()
|| url != *urlForLastAuthentication)) {
- // if credentials are included in the url, then use them
- if (!url.userName().isEmpty()
- && !url.password().isEmpty()) {
+ // if credentials are included in the url, then use them, unless they were already used
+ if (!url.userName().isEmpty() && !url.password().isEmpty()
+ && (url.userName() != authenticator->user()
+ || url.password() != authenticator->password())) {
authenticator->setUser(url.userName(QUrl::FullyDecoded));
authenticator->setPassword(url.password(QUrl::FullyDecoded));
*urlForLastAuthentication = url;
@@ -1522,7 +1610,8 @@ void QNetworkAccessManagerPrivate::authenticationRequired(QAuthenticator *authen
}
QNetworkAuthenticationCredential cred = authenticationManager->fetchCachedCredentials(url, authenticator);
- if (!cred.isNull()) {
+ if (!cred.isNull()
+ && (cred.user != authenticator->user() || cred.password != authenticator->password())) {
authenticator->setUser(cred.user);
authenticator->setPassword(cred.password);
*urlForLastAuthentication = url;
@@ -1650,7 +1739,9 @@ void QNetworkAccessManagerPrivate::destroyThread()
}
}
-#if QT_CONFIG(http)
+
+#if QT_CONFIG(http) || defined(Q_OS_WASM)
+
QNetworkRequest QNetworkAccessManagerPrivate::prepareMultipart(const QNetworkRequest &request, QHttpMultiPart *multiPart)
{
// copy the request, we probably need to add some headers
@@ -1659,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:
@@ -1682,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()) {
@@ -1700,6 +1791,25 @@ QNetworkRequest QNetworkAccessManagerPrivate::prepareMultipart(const QNetworkReq
}
#endif // QT_CONFIG(http)
+/*!
+ \internal
+ Go through the instances so the factories will be created and
+ register themselves to QNetworkAccessBackendFactoryData
+*/
+void QNetworkAccessManagerPrivate::ensureBackendPluginsLoaded()
+{
+ Q_CONSTINIT static QBasicMutex mutex;
+ std::unique_lock locker(mutex);
+ if (!qnabfLoader())
+ return;
+#if QT_CONFIG(library)
+ qnabfLoader->update();
+#endif
+ int index = 0;
+ while (qnabfLoader->instance(index))
+ ++index;
+}
+
QT_END_NAMESPACE
#include "moc_qnetworkaccessmanager.cpp"