diff options
Diffstat (limited to 'src/network/access')
38 files changed, 535 insertions, 230 deletions
diff --git a/src/network/access/http2/bitstreams_p.h b/src/network/access/http2/bitstreams_p.h index 9eba319dc2..ca272062a6 100644 --- a/src/network/access/http2/bitstreams_p.h +++ b/src/network/access/http2/bitstreams_p.h @@ -89,7 +89,7 @@ public: void clear(); private: - Q_DISABLE_COPY(BitOStream); + Q_DISABLE_COPY_MOVE(BitOStream); std::vector<uchar> &buffer; quint64 bitsSet; diff --git a/src/network/access/http2/hpacktable_p.h b/src/network/access/http2/hpacktable_p.h index 960e6a3d70..587d86f09c 100644 --- a/src/network/access/http2/hpacktable_p.h +++ b/src/network/access/http2/hpacktable_p.h @@ -236,7 +236,7 @@ private: mutable QByteArray dummyDst; - Q_DISABLE_COPY(FieldLookupTable) + Q_DISABLE_COPY_MOVE(FieldLookupTable) }; } diff --git a/src/network/access/qabstractnetworkcache.cpp b/src/network/access/qabstractnetworkcache.cpp index 9afb99f23f..4e217294c4 100644 --- a/src/network/access/qabstractnetworkcache.cpp +++ b/src/network/access/qabstractnetworkcache.cpp @@ -331,11 +331,11 @@ QDataStream &operator<<(QDataStream &out, const QNetworkCacheMetaData &metaData) static inline QDataStream &operator<<(QDataStream &out, const QNetworkCacheMetaData::AttributesMap &hash) { out << quint32(hash.size()); - QNetworkCacheMetaData::AttributesMap::ConstIterator it = hash.end(); - QNetworkCacheMetaData::AttributesMap::ConstIterator begin = hash.begin(); - while (it != begin) { - --it; + QNetworkCacheMetaData::AttributesMap::ConstIterator it = hash.begin(); + QNetworkCacheMetaData::AttributesMap::ConstIterator end = hash.end(); + while (it != end) { out << int(it.key()) << it.value(); + ++it; } return out; } @@ -383,7 +383,7 @@ static inline QDataStream &operator>>(QDataStream &in, QNetworkCacheMetaData::At int k; QVariant t; in >> k >> t; - hash.insertMulti(QNetworkRequest::Attribute(k), t); + hash.insert(QNetworkRequest::Attribute(k), t); } if (in.status() != QDataStream::Ok) @@ -475,7 +475,7 @@ QAbstractNetworkCache::~QAbstractNetworkCache() the QIODevice when done with it. If there is no cache for \a url, the url is invalid, or if there - is an internal cache error 0 is returned. + is an internal cache error \nullptr is returned. In the base class this is a pure virtual function. @@ -496,7 +496,7 @@ QAbstractNetworkCache::~QAbstractNetworkCache() Returns the device that should be populated with the data for the cache item \a metaData. When all of the data has been written insert() should be called. If metaData is invalid or the url in - the metadata is invalid 0 is returned. + the metadata is invalid \nullptr is returned. The cache owns the device and will take care of deleting it when it is inserted or removed. diff --git a/src/network/access/qabstractnetworkcache.h b/src/network/access/qabstractnetworkcache.h index 678bae2d6e..e357dfe58f 100644 --- a/src/network/access/qabstractnetworkcache.h +++ b/src/network/access/qabstractnetworkcache.h @@ -67,12 +67,10 @@ public: QNetworkCacheMetaData(const QNetworkCacheMetaData &other); ~QNetworkCacheMetaData(); -#ifdef Q_COMPILER_RVALUE_REFS - QNetworkCacheMetaData &operator=(QNetworkCacheMetaData &&other) Q_DECL_NOTHROW { swap(other); return *this; } -#endif + QNetworkCacheMetaData &operator=(QNetworkCacheMetaData &&other) noexcept { swap(other); return *this; } QNetworkCacheMetaData &operator=(const QNetworkCacheMetaData &other); - void swap(QNetworkCacheMetaData &other) Q_DECL_NOTHROW + void swap(QNetworkCacheMetaData &other) noexcept { qSwap(d, other.d); } bool operator==(const QNetworkCacheMetaData &other) const; diff --git a/src/network/access/qftp.cpp b/src/network/access/qftp.cpp index d33355c470..cc230a5411 100644 --- a/src/network/access/qftp.cpp +++ b/src/network/access/qftp.cpp @@ -955,11 +955,9 @@ void QFtpPI::readyRead() } } } - QString endOfMultiLine; - endOfMultiLine[0] = '0' + replyCode[0]; - endOfMultiLine[1] = '0' + replyCode[1]; - endOfMultiLine[2] = '0' + replyCode[2]; - endOfMultiLine[3] = QLatin1Char(' '); + const char count[4] = { char('0' + replyCode[0]), char('0' + replyCode[1]), + char('0' + replyCode[2]), char(' ') }; + QString endOfMultiLine(QLatin1String(count, 4)); QString lineCont(endOfMultiLine); lineCont[3] = QLatin1Char('-'); QStringRef lineLeft4 = line.leftRef(4); @@ -1826,8 +1824,8 @@ int QFtp::cd(const QString &dir) is data available to read. You can then read the data with the read() or readAll() functions. - If \a dev is not 0, the data is written directly to the device \a - dev. Make sure that the \a dev pointer is valid for the duration + If \a dev is not \nullptr, the data is written directly to the device + \a dev. Make sure that the \a dev pointer is valid for the duration of the operation (it is safe to delete it when the commandFinished() signal is emitted). In this case the readyRead() signal is \e not emitted and you cannot read data with the @@ -2124,6 +2122,17 @@ void QFtp::abort() /*! \internal + Clears the last error. + + \sa currentCommand() +*/ +void QFtp::clearError() +{ + d_func()->error = NoError; +} + +/*! + \internal Returns the identifier of the FTP command that is being executed or 0 if there is no command being executed. diff --git a/src/network/access/qftp_p.h b/src/network/access/qftp_p.h index bba1f9b09d..a55429933b 100644 --- a/src/network/access/qftp_p.h +++ b/src/network/access/qftp_p.h @@ -67,7 +67,7 @@ class Q_AUTOTEST_EXPORT QFtp : public QObject Q_OBJECT public: - explicit QFtp(QObject *parent = 0); + explicit QFtp(QObject *parent = nullptr); virtual ~QFtp(); enum State { @@ -118,7 +118,7 @@ public: int setTransferMode(TransferMode mode); int list(const QString &dir = QString()); int cd(const QString &dir); - int get(const QString &file, QIODevice *dev=0, TransferType type = Binary); + int get(const QString &file, QIODevice *dev=nullptr, TransferType type = Binary); int put(const QByteArray &data, const QString &file, TransferType type = Binary); int put(QIODevice *dev, const QString &file, TransferType type = Binary); int remove(const QString &file); @@ -157,8 +157,11 @@ Q_SIGNALS: void commandFinished(int, bool); void done(bool); +protected: + void clearError(); + private: - Q_DISABLE_COPY(QFtp) + Q_DISABLE_COPY_MOVE(QFtp) Q_DECLARE_PRIVATE(QFtp) Q_PRIVATE_SLOT(d_func(), void _q_startNextCommand()) diff --git a/src/network/access/qhsts.cpp b/src/network/access/qhsts.cpp index ce70b6af90..0cef0ad3dc 100644 --- a/src/network/access/qhsts.cpp +++ b/src/network/access/qhsts.cpp @@ -145,7 +145,7 @@ void QHstsCache::updateKnownHost(const QString &host, const QDateTime &expires, return; } - knownHosts.insert(pos, {hostName, newPolicy}); + knownHosts.insert({hostName, newPolicy}); #if QT_CONFIG(settings) if (hstsStore) hstsStore->addToObserved(newPolicy); @@ -156,7 +156,7 @@ void QHstsCache::updateKnownHost(const QString &host, const QDateTime &expires, if (newPolicy.isExpired()) knownHosts.erase(pos); else if (pos->second != newPolicy) - pos->second = std::move(newPolicy); + pos->second = newPolicy; else return; diff --git a/src/network/access/qhstspolicy.h b/src/network/access/qhstspolicy.h index 176a8fa635..f1b2ee99e5 100644 --- a/src/network/access/qhstspolicy.h +++ b/src/network/access/qhstspolicy.h @@ -65,10 +65,10 @@ public: QUrl::ParsingMode mode = QUrl::DecodedMode); QHstsPolicy(const QHstsPolicy &rhs); QHstsPolicy &operator=(const QHstsPolicy &rhs); - QHstsPolicy &operator=(QHstsPolicy &&other) Q_DECL_NOTHROW { swap(other); return *this; } + QHstsPolicy &operator=(QHstsPolicy &&other) noexcept { swap(other); return *this; } ~QHstsPolicy(); - void swap(QHstsPolicy &other) Q_DECL_NOTHROW { qSwap(d, other.d); } + void swap(QHstsPolicy &other) noexcept { qSwap(d, other.d); } void setHost(const QString &host, QUrl::ParsingMode mode = QUrl::DecodedMode); QString host(QUrl::ComponentFormattingOptions options = QUrl::FullyDecoded) const; diff --git a/src/network/access/qhstsstore_p.h b/src/network/access/qhstsstore_p.h index e82596b250..5338d15592 100644 --- a/src/network/access/qhstsstore_p.h +++ b/src/network/access/qhstsstore_p.h @@ -87,7 +87,7 @@ private: QVector<QHstsPolicy> observedPolicies; QSettings store; - Q_DISABLE_COPY(QHstsStore) + Q_DISABLE_COPY_MOVE(QHstsStore) }; QT_END_NAMESPACE diff --git a/src/network/access/qhttpmultipart.h b/src/network/access/qhttpmultipart.h index 78585a704d..56db83779a 100644 --- a/src/network/access/qhttpmultipart.h +++ b/src/network/access/qhttpmultipart.h @@ -60,12 +60,10 @@ public: QHttpPart(); QHttpPart(const QHttpPart &other); ~QHttpPart(); -#ifdef Q_COMPILER_RVALUE_REFS - QHttpPart &operator=(QHttpPart &&other) Q_DECL_NOTHROW { swap(other); return *this; } -#endif + QHttpPart &operator=(QHttpPart &&other) noexcept { swap(other); return *this; } QHttpPart &operator=(const QHttpPart &other); - void swap(QHttpPart &other) Q_DECL_NOTHROW { qSwap(d, other.d); } + void swap(QHttpPart &other) noexcept { qSwap(d, other.d); } bool operator==(const QHttpPart &other) const; inline bool operator!=(const QHttpPart &other) const diff --git a/src/network/access/qhttpmultipart_p.h b/src/network/access/qhttpmultipart_p.h index 363e0b346c..ead1eadf3b 100644 --- a/src/network/access/qhttpmultipart_p.h +++ b/src/network/access/qhttpmultipart_p.h @@ -64,7 +64,7 @@ QT_BEGIN_NAMESPACE class QHttpPartPrivate: public QSharedData, public QNetworkHeadersPrivate { public: - inline QHttpPartPrivate() : bodyDevice(0), headerCreated(false), readPointer(0) + inline QHttpPartPrivate() : bodyDevice(nullptr), headerCreated(false), readPointer(0) { } ~QHttpPartPrivate() diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp index c58fd24a44..2e38ac2dcf 100644 --- a/src/network/access/qhttpnetworkconnection.cpp +++ b/src/network/access/qhttpnetworkconnection.cpp @@ -398,11 +398,12 @@ void QHttpNetworkConnectionPrivate::copyCredentials(int fromChannel, QAuthentica { Q_ASSERT(auth); - // NTLM is a multi phase authentication. Copying credentials between authenticators would mess things up. + // NTLM and Negotiate do multi-phase authentication. + // Copying credentialsbetween authenticators would mess things up. if (fromChannel >= 0) { - if (!isProxy && channels[fromChannel].authMethod == QAuthenticatorPrivate::Ntlm) - return; - if (isProxy && channels[fromChannel].proxyAuthMethod == QAuthenticatorPrivate::Ntlm) + const QHttpNetworkConnectionChannel &channel = channels[fromChannel]; + const QAuthenticatorPrivate::Method method = isProxy ? channel.proxyAuthMethod : channel.authMethod; + if (method == QAuthenticatorPrivate::Ntlm || method == QAuthenticatorPrivate::Negotiate) return; } @@ -592,24 +593,26 @@ void QHttpNetworkConnectionPrivate::createAuthorization(QAbstractSocket *socket, if ((channels[i].authMethod != QAuthenticatorPrivate::Ntlm && request.headerField("Authorization").isEmpty()) || channels[i].lastStatus == 401) { QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(channels[i].authenticator); if (priv && priv->method != QAuthenticatorPrivate::None) { - QByteArray response = priv->calculateResponse(request.methodName(), request.uri(false)); + QByteArray response = priv->calculateResponse(request.methodName(), request.uri(false), request.url().host()); request.setHeaderField("Authorization", response); channels[i].authenticationCredentialsSent = true; } } } +#if QT_CONFIG(networkproxy) // Send "Proxy-Authorization" header, but not if it's NTLM and the socket is already authenticated. if (channels[i].proxyAuthMethod != QAuthenticatorPrivate::None) { if (!(channels[i].proxyAuthMethod == QAuthenticatorPrivate::Ntlm && channels[i].lastStatus != 407)) { QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(channels[i].proxyAuthenticator); if (priv && priv->method != QAuthenticatorPrivate::None) { - QByteArray response = priv->calculateResponse(request.methodName(), request.uri(false)); + QByteArray response = priv->calculateResponse(request.methodName(), request.uri(false), networkProxy.hostName()); request.setHeaderField("Proxy-Authorization", response); channels[i].proxyCredentialsSent = true; } } } +#endif // QT_CONFIG(networkproxy) } QHttpNetworkReply* QHttpNetworkConnectionPrivate::queueRequest(const QHttpNetworkRequest &request) @@ -641,7 +644,7 @@ QHttpNetworkReply* QHttpNetworkConnectionPrivate::queueRequest(const QHttpNetwor else { // SPDY, HTTP/2 ('h2' mode) if (!pair.second->d_func()->requestIsPrepared) prepareRequest(pair); - channels[0].spdyRequestsToSend.insertMulti(request.priority(), pair); + channels[0].spdyRequestsToSend.insert(request.priority(), pair); } #ifndef Q_OS_WINRT @@ -677,7 +680,7 @@ void QHttpNetworkConnectionPrivate::fillHttp2Queue() for (auto &pair : highPriorityQueue) { if (!pair.second->d_func()->requestIsPrepared) prepareRequest(pair); - channels[0].spdyRequestsToSend.insertMulti(QHttpNetworkRequest::HighPriority, pair); + channels[0].spdyRequestsToSend.insert(QHttpNetworkRequest::HighPriority, pair); } highPriorityQueue.clear(); @@ -685,7 +688,7 @@ void QHttpNetworkConnectionPrivate::fillHttp2Queue() for (auto &pair : lowPriorityQueue) { if (!pair.second->d_func()->requestIsPrepared) prepareRequest(pair); - channels[0].spdyRequestsToSend.insertMulti(pair.first.priority(), pair); + channels[0].spdyRequestsToSend.insert(pair.first.priority(), pair); } lowPriorityQueue.clear(); @@ -1317,8 +1320,12 @@ QHttpNetworkConnection::QHttpNetworkConnection(const QString &hostName, quint16 : QObject(*(new QHttpNetworkConnectionPrivate(hostName, port, encrypt, connectionType)), parent) { Q_D(QHttpNetworkConnection); - d->networkSession = qMove(networkSession); + d->networkSession = std::move(networkSession); d->init(); + if (QNetworkStatusMonitor::isEnabled()) { + connect(&d->connectionMonitor, &QNetworkConnectionMonitor::reachabilityChanged, + this, &QHttpNetworkConnection::onlineStateChanged, Qt::QueuedConnection); + } } QHttpNetworkConnection::QHttpNetworkConnection(quint16 connectionCount, const QString &hostName, @@ -1329,8 +1336,12 @@ QHttpNetworkConnection::QHttpNetworkConnection(quint16 connectionCount, const QS connectionType)), parent) { Q_D(QHttpNetworkConnection); - d->networkSession = qMove(networkSession); + d->networkSession = std::move(networkSession); d->init(); + if (QNetworkStatusMonitor::isEnabled()) { + connect(&d->connectionMonitor, &QNetworkConnectionMonitor::reachabilityChanged, + this, &QHttpNetworkConnection::onlineStateChanged, Qt::QueuedConnection); + } } #else QHttpNetworkConnection::QHttpNetworkConnection(const QString &hostName, quint16 port, bool encrypt, @@ -1339,6 +1350,10 @@ QHttpNetworkConnection::QHttpNetworkConnection(const QString &hostName, quint16 { Q_D(QHttpNetworkConnection); d->init(); + if (QNetworkStatusMonitor::isEnabled()) { + connect(&d->connectionMonitor, &QNetworkConnectionMonitor::reachabilityChanged, + this, &QHttpNetworkConnection::onlineStateChanged, Qt::QueuedConnection); + } } QHttpNetworkConnection::QHttpNetworkConnection(quint16 connectionCount, const QString &hostName, @@ -1349,8 +1364,12 @@ QHttpNetworkConnection::QHttpNetworkConnection(quint16 connectionCount, const QS { Q_D(QHttpNetworkConnection); d->init(); + if (QNetworkStatusMonitor::isEnabled()) { + connect(&d->connectionMonitor, &QNetworkConnectionMonitor::reachabilityChanged, + this, &QHttpNetworkConnection::onlineStateChanged, Qt::QueuedConnection); + } } -#endif +#endif // QT_NO_BEARERMANAGEMENT QHttpNetworkConnection::~QHttpNetworkConnection() { @@ -1476,7 +1495,7 @@ QSharedPointer<QSslContext> QHttpNetworkConnection::sslContext() void QHttpNetworkConnection::setSslContext(QSharedPointer<QSslContext> context) { Q_D(QHttpNetworkConnection); - d->sslContext = qMove(context); + d->sslContext = std::move(context); } void QHttpNetworkConnection::ignoreSslErrors(int channel) @@ -1518,6 +1537,38 @@ void QHttpNetworkConnection::preConnectFinished() d_func()->preConnectRequests--; } +QString QHttpNetworkConnection::peerVerifyName() const +{ + Q_D(const QHttpNetworkConnection); + return d->peerVerifyName; +} + +void QHttpNetworkConnection::setPeerVerifyName(const QString &peerName) +{ + Q_D(QHttpNetworkConnection); + d->peerVerifyName = peerName; +} + +void QHttpNetworkConnection::onlineStateChanged(bool isOnline) +{ + Q_D(QHttpNetworkConnection); + + if (isOnline) { + // If we did not have any 'isOffline' previously - well, good + // to know, we are 'online' apparently. + return; + } + + for (int i = 0; i < d->activeChannelCount; i++) { + auto &channel = d->channels[i]; + channel.emitFinishedWithError(QNetworkReply::TemporaryNetworkFailureError, "Temporary network failure."); + channel.close(); + } + + // We don't care, this connection is broken from our POV. + d->connectionMonitor.stopMonitoring(); +} + #ifndef QT_NO_NETWORKPROXY // only called from QHttpNetworkConnectionChannel::_q_proxyAuthenticationRequired, not // from QHttpNetworkConnectionChannel::handleAuthenticationChallenge diff --git a/src/network/access/qhttpnetworkconnection_p.h b/src/network/access/qhttpnetworkconnection_p.h index 91827a6eb1..85d89f20c2 100644 --- a/src/network/access/qhttpnetworkconnection_p.h +++ b/src/network/access/qhttpnetworkconnection_p.h @@ -67,6 +67,7 @@ #include <private/qhttpnetworkheader_p.h> #include <private/qhttpnetworkrequest_p.h> #include <private/qhttpnetworkreply_p.h> +#include <private/qnetconmonitor_p.h> #include <private/http2protocol_p.h> #include <private/qhttpnetworkconnectionchannel_p.h> @@ -101,10 +102,10 @@ public: #ifndef QT_NO_BEARERMANAGEMENT explicit QHttpNetworkConnection(const QString &hostName, quint16 port = 80, bool encrypt = false, ConnectionType connectionType = ConnectionTypeHTTP, - QObject *parent = 0, QSharedPointer<QNetworkSession> networkSession + QObject *parent = nullptr, QSharedPointer<QNetworkSession> networkSession = QSharedPointer<QNetworkSession>()); QHttpNetworkConnection(quint16 channelCount, const QString &hostName, quint16 port = 80, - bool encrypt = false, QObject *parent = 0, + bool encrypt = false, QObject *parent = nullptr, QSharedPointer<QNetworkSession> networkSession = QSharedPointer<QNetworkSession>(), ConnectionType connectionType = ConnectionTypeHTTP); #else @@ -154,9 +155,15 @@ public: void preConnectFinished(); + QString peerVerifyName() const; + void setPeerVerifyName(const QString &peerName); + +public slots: + void onlineStateChanged(bool isOnline); + private: Q_DECLARE_PRIVATE(QHttpNetworkConnection) - Q_DISABLE_COPY(QHttpNetworkConnection) + Q_DISABLE_COPY_MOVE(QHttpNetworkConnection) friend class QHttpThreadDelegate; friend class QHttpNetworkReply; friend class QHttpNetworkReplyPrivate; @@ -289,6 +296,16 @@ public: Http2::ProtocolParameters http2Parameters; + QString peerVerifyName; + // If network status monitoring is enabled, we activate connectionMonitor + // as soons as one of channels managed to connect to host (and we + // have a pair of addresses (us,peer). + // NETMONTODO: consider activating a monitor on a change from + // HostLookUp state to ConnectingState (means we have both + // local/remote addresses known and can start monitoring this + // early). + QNetworkConnectionMonitor connectionMonitor; + friend class QHttpNetworkConnectionChannel; }; diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index d5f63af745..9309d718e4 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -59,6 +59,8 @@ #include "private/qnetworksession_p.h" #endif +#include "private/qnetconmonitor_p.h" + QT_BEGIN_NAMESPACE namespace @@ -392,6 +394,7 @@ bool QHttpNetworkConnectionChannel::ensureConnection() if (!connection->sslContext().isNull()) QSslSocketPrivate::checkSettingSslContext(sslSocket, connection->sslContext()); + sslSocket->setPeerVerifyName(connection->d_func()->peerVerifyName); sslSocket->connectToHostEncrypted(connectHost, connectPort, QIODevice::ReadWrite, networkLayerPreference); if (ignoreAllSslErrors) sslSocket->ignoreSslErrors(); @@ -895,6 +898,16 @@ void QHttpNetworkConnectionChannel::_q_connected() pipeliningSupported = QHttpNetworkConnectionChannel::PipeliningSupportUnknown; + if (QNetworkStatusMonitor::isEnabled()) { + auto connectionPrivate = connection->d_func(); + 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())) + connectionPrivate->connectionMonitor.startMonitoring(); + } + } + // ### FIXME: if the server closes the connection unexpectedly, we shouldn't send the same broken request again! //channels[i].reconnectAttempts = 2; if (ssl || pendingEncrypt) { // FIXME: Didn't work properly with pendingEncrypt only, we should refactor this into an EncrypingState diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp index c9c3172304..a8b635c45a 100644 --- a/src/network/access/qhttpnetworkreply.cpp +++ b/src/network/access/qhttpnetworkreply.cpp @@ -444,6 +444,9 @@ QAuthenticatorPrivate::Method QHttpNetworkReplyPrivate::authenticationMethod(boo } else if (method < QAuthenticatorPrivate::DigestMd5 && line.startsWith("digest")) { method = QAuthenticatorPrivate::DigestMd5; + } else if (method < QAuthenticatorPrivate::Negotiate + && line.startsWith("negotiate")) { + method = QAuthenticatorPrivate::Negotiate; } } return method; diff --git a/src/network/access/qhttpnetworkreply_p.h b/src/network/access/qhttpnetworkreply_p.h index 863e21ea3e..12cfe359aa 100644 --- a/src/network/access/qhttpnetworkreply_p.h +++ b/src/network/access/qhttpnetworkreply_p.h @@ -89,7 +89,7 @@ class Q_AUTOTEST_EXPORT QHttpNetworkReply : public QObject, public QHttpNetworkH Q_OBJECT public: - explicit QHttpNetworkReply(const QUrl &url = QUrl(), QObject *parent = 0); + explicit QHttpNetworkReply(const QUrl &url = QUrl(), QObject *parent = nullptr); virtual ~QHttpNetworkReply(); QUrl url() const override; diff --git a/src/network/access/qhttpnetworkrequest.cpp b/src/network/access/qhttpnetworkrequest.cpp index 8de9760710..a3f71b8d2f 100644 --- a/src/network/access/qhttpnetworkrequest.cpp +++ b/src/network/access/qhttpnetworkrequest.cpp @@ -66,7 +66,8 @@ QHttpNetworkRequestPrivate::QHttpNetworkRequestPrivate(const QHttpNetworkRequest ssl(other.ssl), preConnect(other.preConnect), redirectCount(other.redirectCount), - redirectPolicy(other.redirectPolicy) + redirectPolicy(other.redirectPolicy), + peerVerifyName(other.peerVerifyName) { } @@ -90,7 +91,8 @@ bool QHttpNetworkRequestPrivate::operator==(const QHttpNetworkRequestPrivate &ot && (withCredentials == other.withCredentials) && (ssl == other.ssl) && (preConnect == other.preConnect) - && (redirectPolicy == other.redirectPolicy); + && (redirectPolicy == other.redirectPolicy) + && (peerVerifyName == other.peerVerifyName); } QByteArray QHttpNetworkRequest::methodName() const @@ -397,6 +399,15 @@ int QHttpNetworkRequest::minorVersion() const return 1; } +QString QHttpNetworkRequest::peerVerifyName() const +{ + return d->peerVerifyName; +} + +void QHttpNetworkRequest::setPeerVerifyName(const QString &peerName) +{ + d->peerVerifyName = peerName; +} QT_END_NAMESPACE diff --git a/src/network/access/qhttpnetworkrequest_p.h b/src/network/access/qhttpnetworkrequest_p.h index bc797537ae..fb4896195b 100644 --- a/src/network/access/qhttpnetworkrequest_p.h +++ b/src/network/access/qhttpnetworkrequest_p.h @@ -147,6 +147,8 @@ public: QByteArray methodName() const; QByteArray uri(bool throughProxy) const; + QString peerVerifyName() const; + void setPeerVerifyName(const QString &peerName); private: QSharedDataPointer<QHttpNetworkRequestPrivate> d; friend class QHttpNetworkRequestPrivate; @@ -182,6 +184,7 @@ public: bool preConnect; int redirectCount; QNetworkRequest::RedirectPolicy redirectPolicy; + QString peerVerifyName; }; diff --git a/src/network/access/qhttpthreaddelegate.cpp b/src/network/access/qhttpthreaddelegate.cpp index 0e97acdd9d..6fb4710d77 100644 --- a/src/network/access/qhttpthreaddelegate.cpp +++ b/src/network/access/qhttpthreaddelegate.cpp @@ -123,7 +123,7 @@ static QNetworkReply::NetworkError statusCodeFromHttp(int httpStatusCode, const } -static QByteArray makeCacheKey(QUrl &url, QNetworkProxy *proxy) +static QByteArray makeCacheKey(QUrl &url, QNetworkProxy *proxy, const QString &peerVerifyName) { QString result; QUrl copy = url; @@ -170,7 +170,8 @@ static QByteArray makeCacheKey(QUrl &url, QNetworkProxy *proxy) #else Q_UNUSED(proxy) #endif - + if (!peerVerifyName.isEmpty()) + result += QLatin1Char(':') + peerVerifyName; return "http-connection:" + std::move(result).toLatin1(); } @@ -188,7 +189,7 @@ public: QHttpNetworkConnection::ConnectionType connectionType, QSharedPointer<QNetworkSession> networkSession) : QHttpNetworkConnection(hostName, port, encrypt, connectionType, /*parent=*/0, - qMove(networkSession)) + std::move(networkSession)) #endif { setExpires(true); @@ -317,12 +318,12 @@ void QHttpThreadDelegate::startRequest() #ifndef QT_NO_NETWORKPROXY if (transparentProxy.type() != QNetworkProxy::NoProxy) - cacheKey = makeCacheKey(urlCopy, &transparentProxy); + cacheKey = makeCacheKey(urlCopy, &transparentProxy, httpRequest.peerVerifyName()); else if (cacheProxy.type() != QNetworkProxy::NoProxy) - cacheKey = makeCacheKey(urlCopy, &cacheProxy); + cacheKey = makeCacheKey(urlCopy, &cacheProxy, httpRequest.peerVerifyName()); else #endif - cacheKey = makeCacheKey(urlCopy, 0); + cacheKey = makeCacheKey(urlCopy, 0, httpRequest.peerVerifyName()); // the http object is actually a QHttpNetworkConnection @@ -352,7 +353,7 @@ void QHttpThreadDelegate::startRequest() httpConnection->setTransparentProxy(transparentProxy); httpConnection->setCacheProxy(cacheProxy); #endif - + httpConnection->setPeerVerifyName(httpRequest.peerVerifyName()); // cache the QHttpNetworkConnection corresponding to this cache key connections.localData()->addEntry(cacheKey, httpConnection); } else { diff --git a/src/network/access/qhttpthreaddelegate_p.h b/src/network/access/qhttpthreaddelegate_p.h index 019a8b8b74..6184b39b30 100644 --- a/src/network/access/qhttpthreaddelegate_p.h +++ b/src/network/access/qhttpthreaddelegate_p.h @@ -82,7 +82,7 @@ class QHttpThreadDelegate : public QObject { Q_OBJECT public: - explicit QHttpThreadDelegate(QObject *parent = 0); + explicit QHttpThreadDelegate(QObject *parent = nullptr); ~QHttpThreadDelegate(); @@ -207,7 +207,7 @@ public: : QNonContiguousByteDevice(), wantDataPending(false), m_amount(0), - m_data(0), + m_data(nullptr), m_atEnd(aE), m_size(s), m_pos(0) @@ -240,12 +240,12 @@ public: // Do nothing, we already sent a wantData signal and wait for results len = 0; } - return 0; + return nullptr; } bool advanceReadPointer(qint64 a) override { - if (m_data == 0) + if (m_data == nullptr) return false; m_amount -= a; @@ -269,7 +269,7 @@ public: bool reset() override { m_amount = 0; - m_data = 0; + m_data = nullptr; m_dataArray.clear(); if (wantDataPending) { diff --git a/src/network/access/qnetworkaccessauthenticationmanager_p.h b/src/network/access/qnetworkaccessauthenticationmanager_p.h index 548675728f..31111ca2a5 100644 --- a/src/network/access/qnetworkaccessauthenticationmanager_p.h +++ b/src/network/access/qnetworkaccessauthenticationmanager_p.h @@ -90,12 +90,12 @@ public: void cacheCredentials(const QUrl &url, const QAuthenticator *auth); QNetworkAuthenticationCredential fetchCachedCredentials(const QUrl &url, - const QAuthenticator *auth = 0); + const QAuthenticator *auth = nullptr); #ifndef QT_NO_NETWORKPROXY void cacheProxyCredentials(const QNetworkProxy &proxy, const QAuthenticator *auth); QNetworkAuthenticationCredential fetchCachedProxyCredentials(const QNetworkProxy &proxy, - const QAuthenticator *auth = 0); + const QAuthenticator *auth = nullptr); #endif void clearCache(); diff --git a/src/network/access/qnetworkaccessbackend.cpp b/src/network/access/qnetworkaccessbackend.cpp index 272dd22097..848fc84de7 100644 --- a/src/network/access/qnetworkaccessbackend.cpp +++ b/src/network/access/qnetworkaccessbackend.cpp @@ -83,7 +83,7 @@ QNetworkAccessBackendFactory::QNetworkAccessBackendFactory() QNetworkAccessBackendFactory::~QNetworkAccessBackendFactory() { - if (QNetworkAccessBackendFactoryData::valid.load()) { + if (QNetworkAccessBackendFactoryData::valid.loadRelaxed()) { QMutexLocker locker(&factoryData()->mutex); factoryData()->removeAll(this); } @@ -92,7 +92,7 @@ QNetworkAccessBackendFactory::~QNetworkAccessBackendFactory() QNetworkAccessBackend *QNetworkAccessManagerPrivate::findBackend(QNetworkAccessManager::Operation op, const QNetworkRequest &request) { - if (QNetworkAccessBackendFactoryData::valid.load()) { + if (QNetworkAccessBackendFactoryData::valid.loadRelaxed()) { QMutexLocker locker(&factoryData()->mutex); QNetworkAccessBackendFactoryData::ConstIterator it = factoryData()->constBegin(), end = factoryData()->constEnd(); @@ -110,7 +110,7 @@ QNetworkAccessBackend *QNetworkAccessManagerPrivate::findBackend(QNetworkAccessM QStringList QNetworkAccessManagerPrivate::backendSupportedSchemes() const { - if (QNetworkAccessBackendFactoryData::valid.load()) { + if (QNetworkAccessBackendFactoryData::valid.loadRelaxed()) { QMutexLocker locker(&factoryData()->mutex); QNetworkAccessBackendFactoryData::ConstIterator it = factoryData()->constBegin(); QNetworkAccessBackendFactoryData::ConstIterator end = factoryData()->constEnd(); diff --git a/src/network/access/qnetworkaccesscache.cpp b/src/network/access/qnetworkaccesscache.cpp index 00bb18cb82..b694a2c999 100644 --- a/src/network/access/qnetworkaccesscache.cpp +++ b/src/network/access/qnetworkaccesscache.cpp @@ -40,11 +40,12 @@ #include "qnetworkaccesscache_p.h" #include "QtCore/qpointer.h" #include "QtCore/qdatetime.h" -#include "QtCore/qqueue.h" #include "qnetworkaccessmanager_p.h" #include "qnetworkreply_p.h" #include "qnetworkrequest.h" +#include <vector> + QT_BEGIN_NAMESPACE enum ExpiryTimeEnum { @@ -63,7 +64,7 @@ namespace { struct QNetworkAccessCache::Node { QDateTime timestamp; - QQueue<Receiver> receiverQueue; + std::vector<Receiver> receiverQueue; QByteArray key; Node *older, *newer; @@ -277,10 +278,7 @@ bool QNetworkAccessCache::requestEntry(const QByteArray &key, QObject *target, c // object is not shareable and is in use // queue for later use Q_ASSERT(node->older == 0 && node->newer == 0); - Receiver receiver; - receiver.object = target; - receiver.member = member; - node->receiverQueue.enqueue(receiver); + node->receiverQueue.push_back({target, member}); // request queued return true; @@ -331,17 +329,19 @@ void QNetworkAccessCache::releaseEntry(const QByteArray &key) Q_ASSERT(node->useCount > 0); // are there other objects waiting? - if (!node->receiverQueue.isEmpty()) { + const auto objectStillExists = [](const Receiver &r) { return !r.object.isNull(); }; + + auto &queue = node->receiverQueue; + auto qit = std::find_if(queue.begin(), queue.end(), objectStillExists); + + const Receiver receiver = qit == queue.end() ? Receiver{} : std::move(*qit++) ; + + queue.erase(queue.begin(), qit); + + if (receiver.object) { // queue another activation - Receiver receiver; - do { - receiver = node->receiverQueue.dequeue(); - } while (receiver.object.isNull() && !node->receiverQueue.isEmpty()); - - if (!receiver.object.isNull()) { - emitEntryReady(node, receiver.object, receiver.member); - return; - } + emitEntryReady(node, receiver.object, receiver.member); + return; } if (!--node->useCount) { diff --git a/src/network/access/qnetworkaccessftpbackend.cpp b/src/network/access/qnetworkaccessftpbackend.cpp index fd6589b396..51ed2f5a55 100644 --- a/src/network/access/qnetworkaccessftpbackend.cpp +++ b/src/network/access/qnetworkaccessftpbackend.cpp @@ -99,6 +99,8 @@ public: connect(this, SIGNAL(done(bool)), this, SLOT(deleteLater())); close(); } + + using QFtp::clearError; }; QNetworkAccessFtpBackend::QNetworkAccessFtpBackend() @@ -282,7 +284,10 @@ void QNetworkAccessFtpBackend::ftpDone() } // check for errors: - if (ftp->error() != QFtp::NoError) { + if (state == CheckingFeatures && ftp->error() == QFtp::UnknownError) { + qWarning("QNetworkAccessFtpBackend: HELP command failed, ignoring it"); + ftp->clearError(); + } else if (ftp->error() != QFtp::NoError) { QString msg; if (operation() == QNetworkAccessManager::GetOperation) msg = tr("Error while downloading %1: %2"); @@ -351,7 +356,7 @@ void QNetworkAccessFtpBackend::ftpDone() } } else if (state == Statting) { // statted successfully, send the actual request - emit metaDataChanged(); + metaDataChanged(); state = Transferring; QFtp::TransferType type = QFtp::Binary; diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index 85e2c492e4..a2996e3533 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -90,6 +90,8 @@ #include "qnetworkreplywasmimpl_p.h" #endif +#include "qnetconmonitor_p.h" + QT_BEGIN_NAMESPACE Q_GLOBAL_STATIC(QNetworkAccessFileBackendFactory, fileBackend) @@ -486,18 +488,25 @@ QNetworkAccessManager::QNetworkAccessManager(QObject *parent) qRegisterMetaType<QNetworkReply::NetworkError>(); qRegisterMetaType<QSharedPointer<char> >(); -#ifndef QT_NO_BEARERMANAGEMENT Q_D(QNetworkAccessManager); - // if a session is required, we track online state through - // the QNetworkSession's signals if a request is already made. - // we need to track current accessibility state by default - // - connect(&d->networkConfigurationManager, SIGNAL(onlineStateChanged(bool)), - SLOT(_q_onlineStateChanged(bool))); - connect(&d->networkConfigurationManager, SIGNAL(configurationChanged(QNetworkConfiguration)), - SLOT(_q_configurationChanged(QNetworkConfiguration))); - -#endif + if (QNetworkStatusMonitor::isEnabled()) { + connect(&d->statusMonitor, SIGNAL(onlineStateChanged(bool)), + SLOT(_q_onlineStateChanged(bool))); +#ifdef QT_NO_BEARERMANAGEMENT + d->networkAccessible = d->statusMonitor.isNetworkAccesible(); +#else + d->networkAccessible = d->statusMonitor.isNetworkAccesible() ? Accessible : NotAccessible; + } else { + // if a session is required, we track online state through + // the QNetworkSession's signals if a request is already made. + // we need to track current accessibility state by default + // + connect(&d->networkConfigurationManager, SIGNAL(onlineStateChanged(bool)), + SLOT(_q_onlineStateChanged(bool))); + connect(&d->networkConfigurationManager, SIGNAL(configurationChanged(QNetworkConfiguration)), + SLOT(_q_configurationChanged(QNetworkConfiguration))); +#endif // QT_NO_BEARERMANAGEMENT + } } /*! @@ -1030,6 +1039,7 @@ QNetworkReply *QNetworkAccessManager::deleteResource(const QNetworkRequest &requ void QNetworkAccessManager::setConfiguration(const QNetworkConfiguration &config) { Q_D(QNetworkAccessManager); + d->networkConfiguration = config; d->customNetworkConfiguration = true; d->createSession(config); @@ -1048,7 +1058,7 @@ QNetworkConfiguration QNetworkAccessManager::configuration() const Q_D(const QNetworkAccessManager); QSharedPointer<QNetworkSession> session(d->getNetworkSession()); - if (session) { + if (session && !d->statusMonitor.isEnabled()) { return session->configuration(); } else { return d->networkConfigurationManager.defaultConfiguration(); @@ -1075,7 +1085,7 @@ QNetworkConfiguration QNetworkAccessManager::activeConfiguration() const Q_D(const QNetworkAccessManager); QSharedPointer<QNetworkSession> networkSession(d->getNetworkSession()); - if (networkSession) { + if (networkSession && !d->statusMonitor.isEnabled()) { return d->networkConfigurationManager.configurationFromIdentifier( networkSession->sessionProperty(QLatin1String("ActiveConfiguration")).toString()); } else { @@ -1114,6 +1124,12 @@ QNetworkAccessManager::NetworkAccessibility QNetworkAccessManager::networkAccess { Q_D(const QNetworkAccessManager); + if (d->statusMonitor.isEnabled()) { + if (!d->statusMonitor.isMonitoring()) + d->statusMonitor.start(); + return d->networkAccessible; + } + if (d->customNetworkConfiguration && d->networkConfiguration.state().testFlag(QNetworkConfiguration::Undefined)) return UnknownAccessibility; @@ -1181,9 +1197,37 @@ QSharedPointer<QNetworkSession> QNetworkAccessManagerPrivate::getNetworkSession( \sa connectToHost(), get(), post(), put(), deleteResource() */ + void QNetworkAccessManager::connectToHostEncrypted(const QString &hostName, quint16 port, const QSslConfiguration &sslConfiguration) { + connectToHostEncrypted(hostName, port, sslConfiguration, QString()); +} + +/*! + \since 5.13 + \overload + + Initiates a connection to the host given by \a hostName at port \a port, using + \a sslConfiguration with \a peerName set to be the hostName used for certificate + 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 + enough, i.e. calling this method multiple times per host will not result in faster + network transactions. + + \note This function has no possibility to report errors. + + \sa connectToHost(), get(), post(), put(), deleteResource() +*/ + +void QNetworkAccessManager::connectToHostEncrypted(const QString &hostName, quint16 port, + const QSslConfiguration &sslConfiguration, + const QString &peerName) +{ QUrl url; url.setHost(hostName); url.setPort(port); @@ -1198,6 +1242,7 @@ void QNetworkAccessManager::connectToHostEncrypted(const QString &hostName, quin QSslConfiguration::NextProtocolSpdy3_0)) request.setAttribute(QNetworkRequest::SpdyAllowedAttribute, true); + request.setPeerVerifyName(peerName); get(request); } #endif @@ -1357,11 +1402,17 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera req.setAttribute(QNetworkRequest::RedirectPolicyAttribute, redirectPolicy()); } + if (autoDeleteReplies() + && req.attribute(QNetworkRequest::AutoDeleteReplyOnFinishAttribute).isNull()) { + req.setAttribute(QNetworkRequest::AutoDeleteReplyOnFinishAttribute, true); + } + bool isLocalFile = req.url().isLocalFile(); QString scheme = req.url().scheme(); #ifdef Q_OS_WASM - if (scheme == QLatin1String("http") || scheme == QLatin1String("https")) { + // Support http, https, and relateive urls + if (scheme == QLatin1String("http") || scheme == QLatin1String("https") || scheme.isEmpty()) { QNetworkReplyWasmImpl *reply = new QNetworkReplyWasmImpl(this); QNetworkReplyWasmImplPrivate *priv = reply->d_func(); priv->manager = this; @@ -1404,35 +1455,57 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera } } -#ifndef QT_NO_BEARERMANAGEMENT + if (d->statusMonitor.isEnabled()) { + // See the code in ctor - QNetworkStatusMonitor allows us to + // immediately set 'networkAccessible' even before we start + // the monitor. +#ifdef QT_NO_BEARERMANAGEMENT + if (d->networkAccessible +#else + if (d->networkAccessible == NotAccessible +#endif // QT_NO_BEARERMANAGEMENT + && !isLocalFile) { + QHostAddress dest; + QString host = req.url().host().toLower(); + if (!(dest.setAddress(host) && dest.isLoopback()) + && host != QLatin1String("localhost") + && host != QHostInfo::localHostName().toLower()) { + return new QDisabledNetworkReply(this, req, op); + } + } - // Return a disabled network reply if network access is disabled. - // Except if the scheme is empty or file:// or if the host resolves to a loopback address. - if (d->networkAccessible == NotAccessible && !isLocalFile) { - QHostAddress dest; - QString host = req.url().host().toLower(); - if (!(dest.setAddress(host) && dest.isLoopback()) && host != QLatin1String("localhost") + if (!d->statusMonitor.isMonitoring() && !d->statusMonitor.start()) + qWarning(lcNetMon, "failed to start network status monitoring"); + } else { +#ifndef QT_NO_BEARERMANAGEMENT + // Return a disabled network reply if network access is disabled. + // Except if the scheme is empty or file:// or if the host resolves to a loopback address. + if (d->networkAccessible == NotAccessible && !isLocalFile) { + QHostAddress dest; + QString host = req.url().host().toLower(); + if (!(dest.setAddress(host) && dest.isLoopback()) && host != QLatin1String("localhost") && host != QHostInfo::localHostName().toLower()) { - return new QDisabledNetworkReply(this, req, op); + return new QDisabledNetworkReply(this, req, op); + } } - } - if (!d->networkSessionStrongRef && (d->initializeSession || !d->networkConfiguration.identifier().isEmpty())) { - if (!d->networkConfiguration.identifier().isEmpty()) { - if ((d->networkConfiguration.state() & QNetworkConfiguration::Defined) - && d->networkConfiguration != d->networkConfigurationManager.defaultConfiguration()) - d->createSession(d->networkConfigurationManager.defaultConfiguration()); - else - d->createSession(d->networkConfiguration); + if (!d->networkSessionStrongRef && (d->initializeSession || !d->networkConfiguration.identifier().isEmpty())) { + if (!d->networkConfiguration.identifier().isEmpty()) { + if ((d->networkConfiguration.state() & QNetworkConfiguration::Defined) + && d->networkConfiguration != d->networkConfigurationManager.defaultConfiguration()) + d->createSession(d->networkConfigurationManager.defaultConfiguration()); + else + d->createSession(d->networkConfiguration); - } else { - if (d->networkSessionRequired) - d->createSession(d->networkConfigurationManager.defaultConfiguration()); - else - d->initializeSession = false; + } else { + if (d->networkSessionRequired) + d->createSession(d->networkConfigurationManager.defaultConfiguration()); + else + d->initializeSession = false; + } } - } #endif + } QNetworkRequest request = req; if (!request.header(QNetworkRequest::ContentLengthHeader).isValid() && @@ -1479,8 +1552,10 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera #endif QNetworkReplyHttpImpl *reply = new QNetworkReplyHttpImpl(this, request, op, outgoingData); #ifndef QT_NO_BEARERMANAGEMENT - connect(this, SIGNAL(networkSessionConnected()), - reply, SLOT(_q_networkSessionConnected())); + if (!d->statusMonitor.isEnabled()) { + connect(this, SIGNAL(networkSessionConnected()), + reply, SLOT(_q_networkSessionConnected())); + } #endif return reply; } @@ -1489,7 +1564,9 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera // first step: create the reply QNetworkReplyImpl *reply = new QNetworkReplyImpl(this); #ifndef QT_NO_BEARERMANAGEMENT - if (!isLocalFile) { + // NETMONTODO: network reply impl must be augmented to use the same monitoring + // capabilities as http network reply impl does. + if (!isLocalFile && !d->statusMonitor.isEnabled()) { connect(this, SIGNAL(networkSessionConnected()), reply, SLOT(_q_networkSessionConnected())); } @@ -1600,13 +1677,50 @@ void QNetworkAccessManager::clearConnectionCache() QNetworkAccessManagerPrivate::clearConnectionCache(this); } + +/*! + \since 5.14 + + Returns the true if QNetworkAccessManager is currently configured + to automatically delete QNetworkReplies, false otherwise. + + \sa setAutoDeleteReplies, + QNetworkRequest::AutoDeleteReplyOnFinishAttribute +*/ +bool QNetworkAccessManager::autoDeleteReplies() +{ + return d_func()->autoDeleteReplies; +} + +/*! + \since 5.14 + + Enables or disables automatic deletion of \l {QNetworkReply} {QNetworkReplies}. + + Setting \a shouldAutoDelete to true is the same as setting the + QNetworkRequest::AutoDeleteReplyOnFinishAttribute attribute to + true on all \e{future} \l {QNetworkRequest} {QNetworkRequests} + passed to this instance of QNetworkAccessManager unless the + attribute was already explicitly set on the QNetworkRequest. + + \sa autoDeleteReplies, + QNetworkRequest::AutoDeleteReplyOnFinishAttribute +*/ +void QNetworkAccessManager::setAutoDeleteReplies(bool shouldAutoDelete) +{ + d_func()->autoDeleteReplies = shouldAutoDelete; +} + void QNetworkAccessManagerPrivate::_q_replyFinished() { Q_Q(QNetworkAccessManager); QNetworkReply *reply = qobject_cast<QNetworkReply *>(q->sender()); - if (reply) + if (reply) { emit q->finished(reply); + if (reply->request().attribute(QNetworkRequest::AutoDeleteReplyOnFinishAttribute, false).toBool()) + QMetaObject::invokeMethod(reply, [reply] { reply->deleteLater(); }, Qt::QueuedConnection); + } #ifndef QT_NO_BEARERMANAGEMENT // If there are no active requests, release our reference to the network session. @@ -1958,7 +2072,13 @@ void QNetworkAccessManagerPrivate::_q_networkSessionStateChanged(QNetworkSession void QNetworkAccessManagerPrivate::_q_onlineStateChanged(bool isOnline) { - Q_Q(QNetworkAccessManager); + Q_Q(QNetworkAccessManager); + + if (statusMonitor.isEnabled()) { + networkAccessible = isOnline ? QNetworkAccessManager::Accessible : QNetworkAccessManager::NotAccessible; + return; + } + // if the user set a config, we only care whether this one is active. // Otherwise, this QNAM is online if there is an online config. @@ -1988,6 +2108,9 @@ void QNetworkAccessManagerPrivate::_q_onlineStateChanged(bool isOnline) void QNetworkAccessManagerPrivate::_q_configurationChanged(const QNetworkConfiguration &configuration) { + if (statusMonitor.isEnabled()) + return; + const QString id = configuration.identifier(); if (configuration.state().testFlag(QNetworkConfiguration::Active)) { if (!onlineConfigurations.contains(id)) { @@ -2020,6 +2143,9 @@ void QNetworkAccessManagerPrivate::_q_configurationChanged(const QNetworkConfigu void QNetworkAccessManagerPrivate::_q_networkSessionFailed(QNetworkSession::SessionError) { + if (statusMonitor.isEnabled()) + return; + const auto cfgs = networkConfigurationManager.allConfigurations(); for (const QNetworkConfiguration &cfg : cfgs) { if (cfg.state().testFlag(QNetworkConfiguration::Active)) { @@ -2031,6 +2157,13 @@ void QNetworkAccessManagerPrivate::_q_networkSessionFailed(QNetworkSession::Sess } } +#else + +void QNetworkAccessManagerPrivate::_q_onlineStateChanged(bool isOnline) +{ + networkAccessible = isOnline; +} + #endif // QT_NO_BEARERMANAGEMENT #if QT_CONFIG(http) diff --git a/src/network/access/qnetworkaccessmanager.h b/src/network/access/qnetworkaccessmanager.h index 67b3a8b71b..601d0420ff 100644 --- a/src/network/access/qnetworkaccessmanager.h +++ b/src/network/access/qnetworkaccessmanager.h @@ -158,12 +158,18 @@ public: #ifndef QT_NO_SSL void connectToHostEncrypted(const QString &hostName, quint16 port = 443, const QSslConfiguration &sslConfiguration = QSslConfiguration::defaultConfiguration()); + void connectToHostEncrypted(const QString &hostName, quint16 port, + const QSslConfiguration &sslConfiguration, + const QString &peerName); #endif void connectToHost(const QString &hostName, quint16 port = 80); void setRedirectPolicy(QNetworkRequest::RedirectPolicy policy); QNetworkRequest::RedirectPolicy redirectPolicy() const; + bool autoDeleteReplies(); + void setAutoDeleteReplies(bool autoDelete); + Q_SIGNALS: #ifndef QT_NO_NETWORKPROXY void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator); @@ -206,10 +212,10 @@ private: #ifndef QT_NO_BEARERMANAGEMENT Q_PRIVATE_SLOT(d_func(), void _q_networkSessionClosed()) Q_PRIVATE_SLOT(d_func(), void _q_networkSessionStateChanged(QNetworkSession::State)) - Q_PRIVATE_SLOT(d_func(), void _q_onlineStateChanged(bool)) Q_PRIVATE_SLOT(d_func(), void _q_configurationChanged(const QNetworkConfiguration &)) Q_PRIVATE_SLOT(d_func(), void _q_networkSessionFailed(QNetworkSession::SessionError)) #endif + Q_PRIVATE_SLOT(d_func(), void _q_onlineStateChanged(bool)) }; QT_END_NAMESPACE diff --git a/src/network/access/qnetworkaccessmanager_p.h b/src/network/access/qnetworkaccessmanager_p.h index 5cab4928e4..67ea2094b3 100644 --- a/src/network/access/qnetworkaccessmanager_p.h +++ b/src/network/access/qnetworkaccessmanager_p.h @@ -55,6 +55,7 @@ #include "qnetworkaccessmanager.h" #include "qnetworkaccesscache_p.h" #include "qnetworkaccessbackend_p.h" +#include "private/qnetconmonitor_p.h" #include "qnetworkrequest.h" #include "qhsts_p.h" #include "private/qobject_p.h" @@ -151,6 +152,7 @@ public: QNetworkAccessBackend *findBackend(QNetworkAccessManager::Operation op, const QNetworkRequest &request); QStringList backendSupportedSchemes() const; + void _q_onlineStateChanged(bool isOnline); #ifndef QT_NO_BEARERMANAGEMENT void createSession(const QNetworkConfiguration &config); QSharedPointer<QNetworkSession> getNetworkSession() const; @@ -160,12 +162,11 @@ public: void _q_networkSessionPreferredConfigurationChanged(const QNetworkConfiguration &config, bool isSeamless); void _q_networkSessionStateChanged(QNetworkSession::State state); - void _q_onlineStateChanged(bool isOnline); + void _q_configurationChanged(const QNetworkConfiguration &configuration); void _q_networkSessionFailed(QNetworkSession::SessionError error); QSet<QString> onlineConfigurations; - #endif #if QT_CONFIG(http) @@ -199,6 +200,8 @@ public: int activeReplyCount; bool online; bool initializeSession; +#else + bool networkAccessible = true; #endif bool cookieJarCreated; @@ -222,6 +225,9 @@ public: QScopedPointer<QHstsStore> stsStore; #endif // QT_CONFIG(settings) bool stsEnabled = false; + mutable QNetworkStatusMonitor statusMonitor; + + bool autoDeleteReplies = false; #ifndef QT_NO_BEARERMANAGEMENT Q_AUTOTEST_EXPORT static const QWeakPointer<const QNetworkSession> getNetworkSession(const QNetworkAccessManager *manager); diff --git a/src/network/access/qnetworkcookie.cpp b/src/network/access/qnetworkcookie.cpp index b7cf989477..903de322ff 100644 --- a/src/network/access/qnetworkcookie.cpp +++ b/src/network/access/qnetworkcookie.cpp @@ -46,6 +46,7 @@ #include "QtCore/qdebug.h" #include "QtCore/qlist.h" #include "QtCore/qlocale.h" +#include <QtCore/qregexp.h> #include "QtCore/qstring.h" #include "QtCore/qstringlist.h" #include "QtCore/qurl.h" diff --git a/src/network/access/qnetworkcookie.h b/src/network/access/qnetworkcookie.h index e462b98555..b712b63849 100644 --- a/src/network/access/qnetworkcookie.h +++ b/src/network/access/qnetworkcookie.h @@ -66,12 +66,10 @@ public: explicit QNetworkCookie(const QByteArray &name = QByteArray(), const QByteArray &value = QByteArray()); QNetworkCookie(const QNetworkCookie &other); ~QNetworkCookie(); -#ifdef Q_COMPILER_RVALUE_REFS - QNetworkCookie &operator=(QNetworkCookie &&other) Q_DECL_NOTHROW { swap(other); return *this; } -#endif + QNetworkCookie &operator=(QNetworkCookie &&other) noexcept { swap(other); return *this; } QNetworkCookie &operator=(const QNetworkCookie &other); - void swap(QNetworkCookie &other) Q_DECL_NOTHROW { qSwap(d, other.d); } + void swap(QNetworkCookie &other) noexcept { qSwap(d, other.d); } bool operator==(const QNetworkCookie &other) const; inline bool operator!=(const QNetworkCookie &other) const diff --git a/src/network/access/qnetworkcookiejar.cpp b/src/network/access/qnetworkcookiejar.cpp index 072a7f249d..af5b126953 100644 --- a/src/network/access/qnetworkcookiejar.cpp +++ b/src/network/access/qnetworkcookiejar.cpp @@ -45,6 +45,14 @@ #include "QtCore/qdatetime.h" #if QT_CONFIG(topleveldomain) #include "private/qtldurl_p.h" +#else +QT_BEGIN_NAMESPACE +static bool qIsEffectiveTLD(QString domain) +{ + // provide minimal checking by not accepting cookies on real TLDs + return !domain.contains(QLatin1Char('.')); +} +QT_END_NAMESPACE #endif QT_BEGIN_NAMESPACE @@ -356,19 +364,12 @@ bool QNetworkCookieJar::validateCookie(const QNetworkCookie &cookie, const QUrl // https://tools.ietf.org/html/rfc6265#section-5.3 step 5 if (host == domain) return true; -#if QT_CONFIG(topleveldomain) // the check for effective TLDs makes the "embedded dot" rule from RFC 2109 section 4.3.2 // redundant; the "leading dot" rule has been relaxed anyway, see QNetworkCookie::normalize() // we remove the leading dot for this check if it's present - if (qIsEffectiveTLD(domain)) - return false; // not accepted -#else - // provide minimal checking by not accepting cookies on real TLDs - if (!domain.contains(QLatin1Char('.'))) - return false; -#endif - - return true; + // Normally defined in qtldurl_p.h, but uses fall-back in this file when topleveldomain isn't + // configured: + return !qIsEffectiveTLD(domain); } QT_END_NAMESPACE diff --git a/src/network/access/qnetworkdiskcache_p.h b/src/network/access/qnetworkdiskcache_p.h index f7988e7dda..c797e63830 100644 --- a/src/network/access/qnetworkdiskcache_p.h +++ b/src/network/access/qnetworkdiskcache_p.h @@ -67,7 +67,7 @@ class QFile; class QCacheItem { public: - QCacheItem() : file(0) + QCacheItem() : file(nullptr) { } ~QCacheItem() @@ -85,7 +85,7 @@ public: metaData = QNetworkCacheMetaData(); data.close(); delete file; - file = 0; + file = nullptr; } void writeHeader(QFile *device) const; void writeCompressedData(QFile *device) const; diff --git a/src/network/access/qnetworkfile.cpp b/src/network/access/qnetworkfile.cpp index 374dd26e2e..b7c91f28d8 100644 --- a/src/network/access/qnetworkfile.cpp +++ b/src/network/access/qnetworkfile.cpp @@ -65,21 +65,21 @@ void QNetworkFile::open() if (fi.isDir()) { QString msg = QCoreApplication::translate("QNetworkAccessFileBackend", "Cannot open %1: Path is a directory").arg(fileName()); - error(QNetworkReply::ContentOperationNotPermittedError, msg); + emit error(QNetworkReply::ContentOperationNotPermittedError, msg); } else { - headerRead(QNetworkRequest::LastModifiedHeader, QVariant::fromValue(fi.lastModified())); - headerRead(QNetworkRequest::ContentLengthHeader, QVariant::fromValue(fi.size())); + emit headerRead(QNetworkRequest::LastModifiedHeader, QVariant::fromValue(fi.lastModified())); + emit headerRead(QNetworkRequest::ContentLengthHeader, QVariant::fromValue(fi.size())); opened = QFile::open(QIODevice::ReadOnly | QIODevice::Unbuffered); if (!opened) { QString msg = QCoreApplication::translate("QNetworkAccessFileBackend", "Error opening %1: %2").arg(fileName(), errorString()); if (exists()) - error(QNetworkReply::ContentAccessDenied, msg); + emit error(QNetworkReply::ContentAccessDenied, msg); else - error(QNetworkReply::ContentNotFoundError, msg); + emit error(QNetworkReply::ContentNotFoundError, msg); } } - finished(opened); + emit finished(opened); } void QNetworkFile::close() diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index 2d7649fa61..b9651b35d2 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -59,6 +59,7 @@ #include <QtCore/private/qthread_p.h> #include "qnetworkcookiejar.h" +#include "qnetconmonitor_p.h" #include <string.h> // for strchr @@ -166,6 +167,11 @@ static QHash<QByteArray, QByteArray> parseHttpOptionHeader(const QByteArray &hea #if QT_CONFIG(bearermanagement) static bool isSessionNeeded(const QUrl &url) { + if (QNetworkStatusMonitor::isEnabled()) { + // In case QNetworkStatus/QNetConManager are in business, + // no session, no bearer manager are involved. + return false; + } // Connections to the local machine does not require a session QString host = url.host().toLower(); return !QHostAddress(host).isLoopback() && host != QLatin1String("localhost") @@ -787,6 +793,7 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq if (request.attribute(QNetworkRequest::EmitAllUploadProgressSignalsAttribute).toBool()) emitAllUploadProgressSignals = true; + httpRequest.setPeerVerifyName(newHttpRequest.peerVerifyName()); // Create the HTTP thread delegate QHttpThreadDelegate *delegate = new QHttpThreadDelegate; @@ -795,7 +802,8 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq if (blob.isValid() && blob.canConvert<Http2::ProtocolParameters>()) delegate->http2Parameters = blob.value<Http2::ProtocolParameters>(); #ifndef QT_NO_BEARERMANAGEMENT - delegate->networkSession = managerPrivate->getNetworkSession(); + if (!QNetworkStatusMonitor::isEnabled()) + delegate->networkSession = managerPrivate->getNetworkSession(); #endif // For the synchronous HTTP, this is the normal way the delegate gets deleted @@ -1563,7 +1571,7 @@ bool QNetworkReplyHttpImplPrivate::sendCacheContents(const QNetworkCacheMetaData QIODevice *contents = nc->data(url); if (!contents) { #if defined(QNETWORKACCESSHTTPBACKEND_DEBUG) - qDebug() << "Can not send cache, the contents are 0" << url; + qDebug() << "Cannot send cache, the contents are 0" << url; #endif return false; } @@ -1806,7 +1814,7 @@ bool QNetworkReplyHttpImplPrivate::start(const QNetworkRequest &newHttpRequest) { #ifndef QT_NO_BEARERMANAGEMENT QSharedPointer<QNetworkSession> networkSession(managerPrivate->getNetworkSession()); - if (!networkSession) { + if (!networkSession || QNetworkStatusMonitor::isEnabled()) { #endif postRequest(newHttpRequest); return true; @@ -1894,7 +1902,7 @@ void QNetworkReplyHttpImplPrivate::_q_startOperation() // state changes. if (!startWaitForSession(session)) return; - } else if (session) { + } else if (session && !QNetworkStatusMonitor::isEnabled()) { QObject::connect(session.data(), SIGNAL(stateChanged(QNetworkSession::State)), q, SLOT(_q_networkSessionStateChanged(QNetworkSession::State)), Qt::QueuedConnection); @@ -2183,7 +2191,7 @@ void QNetworkReplyHttpImplPrivate::finished() #ifndef QT_NO_BEARERMANAGEMENT Q_ASSERT(managerPrivate); QSharedPointer<QNetworkSession> session = managerPrivate->getNetworkSession(); - if (session && session->state() == QNetworkSession::Roaming && + if (!QNetworkStatusMonitor::isEnabled() && session && session->state() == QNetworkSession::Roaming && state == Working && errorCode != QNetworkReply::OperationCanceledError) { // only content with a known size will fail with a temporary network failure error if (!totalSize.isNull()) { diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp index a794b492e7..6eab500e8c 100644 --- a/src/network/access/qnetworkreplyimpl.cpp +++ b/src/network/access/qnetworkreplyimpl.cpp @@ -158,7 +158,7 @@ void QNetworkReplyImplPrivate::_q_startOperation() } else { if (state != Finished) { if (operation == QNetworkAccessManager::GetOperation) - pendingNotifications.append(NotifyDownstreamReadyWrite); + pendingNotifications.push_back(NotifyDownstreamReadyWrite); handleNotifications(); } @@ -368,6 +368,7 @@ void QNetworkReplyImplPrivate::setup(QNetworkAccessManager::Operation op, const outgoingData = data; request = req; + originalRequest = req; url = request.url(); operation = op; @@ -432,8 +433,9 @@ void QNetworkReplyImplPrivate::setup(QNetworkAccessManager::Operation op, const void QNetworkReplyImplPrivate::backendNotify(InternalNotifications notification) { Q_Q(QNetworkReplyImpl); - if (!pendingNotifications.contains(notification)) - pendingNotifications.enqueue(notification); + const auto it = std::find(pendingNotifications.cbegin(), pendingNotifications.cend(), notification); + if (it == pendingNotifications.cend()) + pendingNotifications.push_back(notification); if (pendingNotifications.size() == 1) QCoreApplication::postEvent(q, new QEvent(QEvent::NetworkReplyUpdated)); @@ -444,14 +446,9 @@ void QNetworkReplyImplPrivate::handleNotifications() if (notificationHandlingPaused) return; - NotificationQueue current = pendingNotifications; - pendingNotifications.clear(); - - if (state != Working) - return; - - while (state == Working && !current.isEmpty()) { - InternalNotifications notification = current.dequeue(); + for (InternalNotifications notification : qExchange(pendingNotifications, {})) { + if (state != Working) + return; switch (notification) { case NotifyDownstreamReadyWrite: if (copyDevice) @@ -465,8 +462,7 @@ void QNetworkReplyImplPrivate::handleNotifications() break; case NotifyCopyFinished: { - QIODevice *dev = copyDevice; - copyDevice = 0; + QIODevice *dev = qExchange(copyDevice, nullptr); backend->copyFinished(dev); break; } @@ -1116,7 +1112,6 @@ bool QNetworkReplyImplPrivate::migrateBackend() return true; } -#ifndef QT_NO_BEARERMANAGEMENT QDisabledNetworkReply::QDisabledNetworkReply(QObject *parent, const QNetworkRequest &req, QNetworkAccessManager::Operation op) @@ -1141,7 +1136,6 @@ QDisabledNetworkReply::QDisabledNetworkReply(QObject *parent, QDisabledNetworkReply::~QDisabledNetworkReply() { } -#endif QT_END_NAMESPACE diff --git a/src/network/access/qnetworkreplyimpl_p.h b/src/network/access/qnetworkreplyimpl_p.h index f4e8284ab6..8cec79541a 100644 --- a/src/network/access/qnetworkreplyimpl_p.h +++ b/src/network/access/qnetworkreplyimpl_p.h @@ -74,7 +74,7 @@ class QNetworkReplyImpl: public QNetworkReply { Q_OBJECT public: - QNetworkReplyImpl(QObject *parent = 0); + QNetworkReplyImpl(QObject *parent = nullptr); ~QNetworkReplyImpl(); virtual void abort() override; @@ -117,8 +117,6 @@ public: NotifyCopyFinished }; - typedef QQueue<InternalNotifications> NotificationQueue; - QNetworkReplyImplPrivate(); void _q_startOperation(); @@ -178,7 +176,7 @@ public: bool cacheEnabled; QIODevice *cacheSaveDevice; - NotificationQueue pendingNotifications; + std::vector<InternalNotifications> pendingNotifications; bool notificationHandlingPaused; QUrl urlForLastAuthentication; @@ -209,7 +207,6 @@ public: }; Q_DECLARE_TYPEINFO(QNetworkReplyImplPrivate::InternalNotifications, Q_PRIMITIVE_TYPE); -#ifndef QT_NO_BEARERMANAGEMENT class QDisabledNetworkReply : public QNetworkReply { Q_OBJECT @@ -223,7 +220,6 @@ public: protected: qint64 readData(char *, qint64) override { return -1; } }; -#endif QT_END_NAMESPACE diff --git a/src/network/access/qnetworkreplywasmimpl.cpp b/src/network/access/qnetworkreplywasmimpl.cpp index b1e9853a50..9f6422a107 100644 --- a/src/network/access/qnetworkreplywasmimpl.cpp +++ b/src/network/access/qnetworkreplywasmimpl.cpp @@ -59,6 +59,9 @@ using namespace emscripten; static void q_requestErrorCallback(val event) { + if (event.isNull() || event.isUndefined()) + return; + val xhr = event["target"]; quintptr func = xhr["data-handler"].as<quintptr>(); @@ -77,19 +80,24 @@ static void q_requestErrorCallback(val event) static void q_progressCallback(val event) { + if (event.isNull() || event.isUndefined()) + return; + val xhr = event["target"]; QNetworkReplyWasmImplPrivate *reply = reinterpret_cast<QNetworkReplyWasmImplPrivate*>(xhr["data-handler"].as<quintptr>()); Q_ASSERT(reply); - if (xhr["lengthComputable"].as<bool>() && xhr["status"].as<int>() < 400) - reply->emitDataReadProgress(xhr["loaded"].as<qint64>(), xhr["total"].as<qint64>()); - + if (xhr["status"].as<int>() < 400) + reply->emitDataReadProgress(event["loaded"].as<int>(), event["total"].as<int>()); } static void q_loadCallback(val event) { + if (event.isNull() || event.isUndefined()) + return; + val xhr = event["target"]; QNetworkReplyWasmImplPrivate *reply = @@ -117,10 +125,11 @@ static void q_loadCallback(val event) val blob = xhr["response"]; val reader = val::global("FileReader").new_(); - reader.set("onload", val::module_property("QNetworkReplyWasmImplPrivate_readBinary")); + reader.set("onload", val::module_property("qt_QNetworkReplyWasmImplPrivate_readBinary")); reader.set("data-handler", xhr["data-handler"]); reader.call<void>("readAsArrayBuffer", blob); + val::global("Module").delete_(reader); } @@ -136,6 +145,9 @@ static void q_loadCallback(val event) static void q_responseHeadersCallback(val event) { + if (event.isNull() || event.isUndefined()) + return; + val xhr = event["target"]; if (xhr["readyState"].as<int>() == 2) { // HEADERS_RECEIVED @@ -152,12 +164,18 @@ static void q_responseHeadersCallback(val event) static void q_readBinary(val event) { + if (event.isNull() || event.isUndefined()) + return; + val fileReader = event["target"]; QNetworkReplyWasmImplPrivate *reply = reinterpret_cast<QNetworkReplyWasmImplPrivate*>(fileReader["data-handler"].as<quintptr>()); Q_ASSERT(reply); + if (reply->state == QNetworkReplyPrivate::Finished || reply->state == QNetworkReplyPrivate::Aborted) + return; + // Set up source typed array val result = fileReader["result"]; // ArrayBuffer val Uint8Array = val::global("Uint8Array"); @@ -171,15 +189,19 @@ static void q_readBinary(val event) reinterpret_cast<quintptr>(buffer.data()), size); destinationTypedArray.call<void>("set", sourceTypedArray); reply->dataReceived(buffer, buffer.size()); + + event.delete_(fileReader); + Uint8Array.delete_(sourceTypedArray); + QCoreApplication::processEvents(); } -EMSCRIPTEN_BINDINGS(network_module) { - function("QNetworkReplyWasmImplPrivate_requestErrorCallback", q_requestErrorCallback); - function("QNetworkReplyWasmImplPrivate_progressCallback", q_progressCallback); - function("QNetworkReplyWasmImplPrivate_loadCallback", q_loadCallback); - function("QNetworkReplyWasmImplPrivate_responseHeadersCallback", q_responseHeadersCallback); - function("QNetworkReplyWasmImplPrivate_readBinary", q_readBinary); +EMSCRIPTEN_BINDINGS(qtNetworkModule) { + function("qt_QNetworkReplyWasmImplPrivate_requestErrorCallback", q_requestErrorCallback); + function("qt_QNetworkReplyWasmImplPrivate_progressCallback", q_progressCallback); + function("qt_QNetworkReplyWasmImplPrivate_loadCallback", q_loadCallback); + function("qt_QNetworkReplyWasmImplPrivate_responseHeadersCallback", q_responseHeadersCallback); + function("qt_QNetworkReplyWasmImplPrivate_readBinary", q_readBinary); } QNetworkReplyWasmImplPrivate::QNetworkReplyWasmImplPrivate() @@ -194,14 +216,21 @@ QNetworkReplyWasmImplPrivate::QNetworkReplyWasmImplPrivate() QNetworkReplyWasmImplPrivate::~QNetworkReplyWasmImplPrivate() { + m_xhr.set("onerror", val::null()); + m_xhr.set("onload", val::null()); + m_xhr.set("onprogress", val::null()); + m_xhr.set("onreadystatechange", val::null()); + m_xhr.set("data-handler", val::null()); } -QNetworkReplyWasmImpl::~QNetworkReplyWasmImpl() +QNetworkReplyWasmImpl::QNetworkReplyWasmImpl(QObject *parent) + : QNetworkReply(*new QNetworkReplyWasmImplPrivate(), parent) { + Q_D( QNetworkReplyWasmImpl); + d->state = QNetworkReplyPrivate::Idle; } -QNetworkReplyWasmImpl::QNetworkReplyWasmImpl(QObject *parent) - : QNetworkReply(*new QNetworkReplyWasmImplPrivate(), parent) +QNetworkReplyWasmImpl::~QNetworkReplyWasmImpl() { } @@ -226,18 +255,23 @@ QByteArray QNetworkReplyWasmImpl::methodName() const void QNetworkReplyWasmImpl::close() { + QNetworkReply::close(); setFinished(true); emit finished(); - - QNetworkReply::close(); } void QNetworkReplyWasmImpl::abort() { - Q_D(const QNetworkReplyWasmImpl); + Q_D( QNetworkReplyWasmImpl); + if (d->state == QNetworkReplyPrivate::Finished || d->state == QNetworkReplyPrivate::Aborted) + return; + + setError(QNetworkReply::OperationCanceledError, QStringLiteral("Operation canceled")); + d->doAbort(); close(); + d->state = QNetworkReplyPrivate::Aborted; } qint64 QNetworkReplyWasmImpl::bytesAvailable() const @@ -327,14 +361,12 @@ void QNetworkReplyWasmImplPrivate::doSendRequest() m_xhr = val::global("XMLHttpRequest").new_(); std::string verb = q->methodName().toStdString(); - QString extraDataString; - m_xhr.call<void>("open", verb, request.url().toString().toStdString()); - m_xhr.set("onerror", val::module_property("QNetworkReplyWasmImplPrivate_requestErrorCallback")); - m_xhr.set("onload", val::module_property("QNetworkReplyWasmImplPrivate_loadCallback")); - m_xhr.set("onprogress", val::module_property("QNetworkReplyWasmImplPrivate_progressCallback")); - m_xhr.set("onreadystatechange", val::module_property("QNetworkReplyWasmImplPrivate_responseHeadersCallback")); + m_xhr.set("onerror", val::module_property("qt_QNetworkReplyWasmImplPrivate_requestErrorCallback")); + m_xhr.set("onload", val::module_property("qt_QNetworkReplyWasmImplPrivate_loadCallback")); + m_xhr.set("onprogress", val::module_property("qt_QNetworkReplyWasmImplPrivate_progressCallback")); + m_xhr.set("onreadystatechange", val::module_property("qt_QNetworkReplyWasmImplPrivate_responseHeadersCallback")); m_xhr.set("data-handler", val(quintptr(reinterpret_cast<void *>(this)))); @@ -347,30 +379,12 @@ void QNetworkReplyWasmImplPrivate::doSendRequest() if (outgoingData) // data from post request extraData = outgoingData->readAll(); - if (contentType.contains("text") || - contentType.contains("json") || - contentType.contains("form")) { - if (extraData.size() > 0) - extraDataString.fromUtf8(extraData); - } - if (contentType.contains("json")) { - if (!extraDataString.isEmpty()) { - m_xhr.set("responseType", val("json")); - dataToSend = val(extraDataString.toStdString()); - } - } else if (contentType.contains("form")) { //construct form data - if (!extraDataString.isEmpty()) { - val formData = val::global("FormData").new_(); - QStringList formList = extraDataString.split('&'); - - for (auto formEntry : formList) { - formData.call<void>("append", formEntry.split('=')[0].toStdString(), formEntry.split('=')[1].toStdString()); - } - dataToSend = formData; - } - } else { - m_xhr.set("responseType", val("blob")); + if (!extraData.isEmpty()) { + dataToSend = val(typed_memory_view(extraData.size(), + reinterpret_cast<const unsigned char *> + (extraData.constData()))); } + m_xhr.set("responseType", val("blob")); // set request headers for (auto header : request.rawHeaderList()) { m_xhr.call<void>("setRequestHeader", header.toStdString(), request.rawHeader(header).toStdString()); diff --git a/src/network/access/qnetworkrequest.cpp b/src/network/access/qnetworkrequest.cpp index e4c46c3183..ba36c75419 100644 --- a/src/network/access/qnetworkrequest.cpp +++ b/src/network/access/qnetworkrequest.cpp @@ -331,6 +331,12 @@ QT_BEGIN_NAMESPACE \omitvalue ResourceTypeAttribute + \value AutoDeleteReplyOnFinishAttribute + Requests only, type: QMetaType::Bool (default: false) + If set, this attribute will make QNetworkAccessManager delete + the QNetworkReply after having emitted "finished". + (This value was introduced in 5.14.) + \value User Special type. Additional information can be passed in QVariants with types ranging from User to UserMax. The default @@ -438,6 +444,7 @@ public: if (other.sslConfiguration) sslConfiguration = new QSslConfiguration(*other.sslConfiguration); #endif + peerVerifyName = other.peerVerifyName; } inline bool operator==(const QNetworkRequestPrivate &other) const @@ -446,7 +453,8 @@ public: priority == other.priority && rawHeaders == other.rawHeaders && attributes == other.attributes && - maxRedirectsAllowed == other.maxRedirectsAllowed; + maxRedirectsAllowed == other.maxRedirectsAllowed && + peerVerifyName == other.peerVerifyName; // don't compare cookedHeaders } @@ -456,6 +464,7 @@ public: mutable QSslConfiguration *sslConfiguration; #endif int maxRedirectsAllowed; + QString peerVerifyName; }; /*! @@ -789,6 +798,32 @@ void QNetworkRequest::setMaximumRedirectsAllowed(int maxRedirectsAllowed) d->maxRedirectsAllowed = maxRedirectsAllowed; } +/*! + \since 5.13 + + Returns the host name set for the certificate validation, as set by + setPeerVerifyName. By default this returns a null string. + + \sa setPeerVerifyName +*/ +QString QNetworkRequest::peerVerifyName() const +{ + return d->peerVerifyName; +} + +/*! + \since 5.13 + + Sets \a peerName as host name for the certificate validation, instead of the one used for the + TCP connection. + + \sa peerVerifyName +*/ +void QNetworkRequest::setPeerVerifyName(const QString &peerName) +{ + d->peerVerifyName = peerName; +} + static QByteArray headerName(QNetworkRequest::KnownHeaders header) { switch (header) { @@ -1309,7 +1344,7 @@ QDateTime QNetworkHeadersPrivate::fromHttpDate(const QByteArray &value) QByteArray QNetworkHeadersPrivate::toHttpDate(const QDateTime &dt) { - return QLocale::c().toString(dt, QLatin1String("ddd, dd MMM yyyy hh:mm:ss 'GMT'")) + return QLocale::c().toString(dt, QStringViewLiteral("ddd, dd MMM yyyy hh:mm:ss 'GMT'")) .toLatin1(); } diff --git a/src/network/access/qnetworkrequest.h b/src/network/access/qnetworkrequest.h index 8462eae8c8..846ead1592 100644 --- a/src/network/access/qnetworkrequest.h +++ b/src/network/access/qnetworkrequest.h @@ -98,6 +98,7 @@ public: RedirectPolicyAttribute, Http2DirectAttribute, ResourceTypeAttribute, // internal + AutoDeleteReplyOnFinishAttribute, User = 1000, UserMax = 32767 @@ -130,12 +131,10 @@ public: explicit QNetworkRequest(const QUrl &url = QUrl()); QNetworkRequest(const QNetworkRequest &other); ~QNetworkRequest(); -#ifdef Q_COMPILER_RVALUE_REFS - QNetworkRequest &operator=(QNetworkRequest &&other) Q_DECL_NOTHROW { swap(other); return *this; } -#endif + QNetworkRequest &operator=(QNetworkRequest &&other) noexcept { swap(other); return *this; } QNetworkRequest &operator=(const QNetworkRequest &other); - void swap(QNetworkRequest &other) Q_DECL_NOTHROW { qSwap(d, other.d); } + void swap(QNetworkRequest &other) noexcept { qSwap(d, other.d); } bool operator==(const QNetworkRequest &other) const; inline bool operator!=(const QNetworkRequest &other) const @@ -173,6 +172,8 @@ public: int maximumRedirectsAllowed() const; void setMaximumRedirectsAllowed(int maximumRedirectsAllowed); + QString peerVerifyName() const; + void setPeerVerifyName(const QString &peerName); private: QSharedDataPointer<QNetworkRequestPrivate> d; friend class QNetworkRequestPrivate; |