diff options
Diffstat (limited to 'src/network/access')
-rw-r--r-- | src/network/access/qnetworkaccessmanager.cpp | 42 | ||||
-rw-r--r-- | src/network/access/qnetworkaccessmanager.h | 3 | ||||
-rw-r--r-- | src/network/access/qnetworkaccessmanager_p.h | 2 | ||||
-rw-r--r-- | src/network/access/qnetworkreplyhttpimpl.cpp | 44 | ||||
-rw-r--r-- | src/network/access/qnetworkreplyhttpimpl_p.h | 7 | ||||
-rw-r--r-- | src/network/access/qnetworkrequest.cpp | 65 | ||||
-rw-r--r-- | src/network/access/qnetworkrequest.h | 18 |
7 files changed, 166 insertions, 15 deletions
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index 76b95b5823..3e1e6d8be8 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -1240,7 +1240,7 @@ void QNetworkAccessManager::connectToHostEncrypted(const QString &hostName, quin // There is no way to enable SPDY/HTTP2 via a request, so we need to check // the ssl configuration whether SPDY/HTTP2 is allowed here. if (sslConfiguration.allowedNextProtocols().contains(QSslConfiguration::ALPNProtocolHTTP2)) - request.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, true); + request.setAttribute(QNetworkRequest::Http2AllowedAttribute, true); else if (sslConfiguration.allowedNextProtocols().contains(QSslConfiguration::NextProtocolSpdy3_0)) request.setAttribute(QNetworkRequest::SpdyAllowedAttribute, true); @@ -1404,6 +1404,11 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera req.setAttribute(QNetworkRequest::RedirectPolicyAttribute, redirectPolicy()); } +#if QT_CONFIG(http) + if (!req.transferTimeout()) + req.setTransferTimeout(transferTimeout()); +#endif + if (autoDeleteReplies() && req.attribute(QNetworkRequest::AutoDeleteReplyOnFinishAttribute).isNull()) { req.setAttribute(QNetworkRequest::AutoDeleteReplyOnFinishAttribute, true); @@ -1713,6 +1718,41 @@ void QNetworkAccessManager::setAutoDeleteReplies(bool shouldAutoDelete) d_func()->autoDeleteReplies = shouldAutoDelete; } +/*! + \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. +*/ +int QNetworkAccessManager::transferTimeout() +{ + return d_func()->transferTimeout; +} + +/*! + \since 5.15 + + Sets \a timeout as the transfer timeout in milliseconds. + + 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::TransferTimeoutPreset. 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) +{ + d_func()->transferTimeout = timeout; +} + void QNetworkAccessManagerPrivate::_q_replyFinished() { Q_Q(QNetworkAccessManager); diff --git a/src/network/access/qnetworkaccessmanager.h b/src/network/access/qnetworkaccessmanager.h index 98498d07d2..6db4094a8e 100644 --- a/src/network/access/qnetworkaccessmanager.h +++ b/src/network/access/qnetworkaccessmanager.h @@ -170,6 +170,9 @@ public: bool autoDeleteReplies() const; void setAutoDeleteReplies(bool autoDelete); + int transferTimeout(); + void setTransferTimeout(int timeout = QNetworkRequest::TransferTimeoutPreset); + Q_SIGNALS: #ifndef QT_NO_NETWORKPROXY void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator); diff --git a/src/network/access/qnetworkaccessmanager_p.h b/src/network/access/qnetworkaccessmanager_p.h index 67ea2094b3..d558f61eed 100644 --- a/src/network/access/qnetworkaccessmanager_p.h +++ b/src/network/access/qnetworkaccessmanager_p.h @@ -229,6 +229,8 @@ public: bool autoDeleteReplies = false; + int transferTimeout = 0; + #ifndef QT_NO_BEARERMANAGEMENT Q_AUTOTEST_EXPORT static const QWeakPointer<const QNetworkSession> getNetworkSession(const QNetworkAccessManager *manager); #endif diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index 8ac81d1780..a13c2b144c 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -461,6 +461,7 @@ QNetworkReplyHttpImplPrivate::QNetworkReplyHttpImplPrivate() , preMigrationDownloaded(-1) , bytesDownloaded(0) , bytesBuffered(0) + , transferTimeout(nullptr) , downloadBufferReadPosition(0) , downloadBufferCurrentSize(0) , downloadZerocopyBuffer(nullptr) @@ -777,7 +778,7 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq if (request.attribute(QNetworkRequest::SpdyAllowedAttribute).toBool()) httpRequest.setSPDYAllowed(true); - if (request.attribute(QNetworkRequest::HTTP2AllowedAttribute).toBool()) + if (request.attribute(QNetworkRequest::Http2AllowedAttribute).toBool()) httpRequest.setHTTP2Allowed(true); if (request.attribute(QNetworkRequest::Http2DirectAttribute).toBool()) { @@ -1067,6 +1068,7 @@ void QNetworkReplyHttpImplPrivate::replyDownloadData(QByteArray d) if (!isHttpRedirectResponse()) { buffer.append(d); bytesDownloaded += d.size(); + setupTransferTimeout(); } bytesBuffered += d.size(); @@ -1280,15 +1282,15 @@ void QNetworkReplyHttpImplPrivate::replyDownloadMetaData(const QList<QPair<QByte } q->setAttribute(QNetworkRequest::HttpPipeliningWasUsedAttribute, pu); - const QVariant http2Allowed = request.attribute(QNetworkRequest::HTTP2AllowedAttribute); + const QVariant http2Allowed = request.attribute(QNetworkRequest::Http2AllowedAttribute); const QVariant http2Direct = request.attribute(QNetworkRequest::Http2DirectAttribute); if ((http2Allowed.isValid() && http2Allowed.toBool()) || (http2Direct.isValid() && http2Direct.toBool())) { - q->setAttribute(QNetworkRequest::HTTP2WasUsedAttribute, spdyWasUsed); + q->setAttribute(QNetworkRequest::Http2WasUsedAttribute, spdyWasUsed); q->setAttribute(QNetworkRequest::SpdyWasUsedAttribute, false); } else { q->setAttribute(QNetworkRequest::SpdyWasUsedAttribute, spdyWasUsed); - q->setAttribute(QNetworkRequest::HTTP2WasUsedAttribute, false); + q->setAttribute(QNetworkRequest::Http2WasUsedAttribute, false); } // reconstruct the HTTP header @@ -1401,6 +1403,7 @@ void QNetworkReplyHttpImplPrivate::replyDownloadProgressSlot(qint64 bytesReceive return; bytesDownloaded = bytesReceived; + setupTransferTimeout(); downloadBufferCurrentSize = bytesReceived; @@ -1857,7 +1860,6 @@ bool QNetworkReplyHttpImplPrivate::startWaitForSession(QSharedPointer<QNetworkSe void QNetworkReplyHttpImplPrivate::_q_startOperation() { Q_Q(QNetworkReplyHttpImpl); - if (state == Working) // ensure this function is only being called once return; @@ -1897,6 +1899,7 @@ void QNetworkReplyHttpImplPrivate::_q_startOperation() } #endif // QT_NO_BEARERMANAGEMENT + setupTransferTimeout(); if (synchronous) { state = Finished; q_func()->setFinished(true); @@ -2033,6 +2036,31 @@ void QNetworkReplyHttpImplPrivate::_q_bufferOutgoingData() } } +void QNetworkReplyHttpImplPrivate::_q_transferTimedOut() +{ + Q_Q(QNetworkReplyHttpImpl); + q->abort(); +} + +void QNetworkReplyHttpImplPrivate::setupTransferTimeout() +{ + Q_Q(QNetworkReplyHttpImpl); + if (!transferTimeout) { + transferTimeout = new QTimer(q); + QObject::connect(transferTimeout, SIGNAL(timeout()), + q, SLOT(_q_transferTimedOut()), + Qt::QueuedConnection); + } + transferTimeout->stop(); + if (request.transferTimeout()) { + transferTimeout->setSingleShot(true); + transferTimeout->setInterval(request.transferTimeout()); + QMetaObject::invokeMethod(transferTimeout, "start", + Qt::QueuedConnection); + + } +} + #ifndef QT_NO_BEARERMANAGEMENT void QNetworkReplyHttpImplPrivate::_q_networkSessionConnected() { @@ -2115,6 +2143,8 @@ void QNetworkReplyHttpImplPrivate::emitReplyUploadProgress(qint64 bytesSent, qin if (isFinished) return; + setupTransferTimeout(); + if (!emitAllUploadProgressSignals) { //choke signal emissions, except the first and last signals which are unconditional if (uploadProgressSignalChoke.isValid()) { @@ -2126,7 +2156,6 @@ void QNetworkReplyHttpImplPrivate::emitReplyUploadProgress(qint64 bytesSent, qin uploadProgressSignalChoke.start(); } } - emit q->uploadProgress(bytesSent, bytesTotal); } @@ -2159,7 +2188,8 @@ void QNetworkReplyHttpImplPrivate::_q_finished() void QNetworkReplyHttpImplPrivate::finished() { Q_Q(QNetworkReplyHttpImpl); - + if (transferTimeout) + transferTimeout->stop(); if (state == Finished || state == Aborted || state == WaitingForSession) return; diff --git a/src/network/access/qnetworkreplyhttpimpl_p.h b/src/network/access/qnetworkreplyhttpimpl_p.h index ef69ce0653..dec0c4c589 100644 --- a/src/network/access/qnetworkreplyhttpimpl_p.h +++ b/src/network/access/qnetworkreplyhttpimpl_p.h @@ -59,6 +59,7 @@ #include "QtCore/qdatetime.h" #include "QtCore/qsharedpointer.h" #include "QtCore/qscopedpointer.h" +#include "QtCore/qtimer.h" #include "qatomic.h" #include <QtNetwork/QNetworkCacheMetaData> @@ -100,6 +101,7 @@ public: Q_PRIVATE_SLOT(d_func(), void _q_cacheLoadReadyRead()) Q_PRIVATE_SLOT(d_func(), void _q_bufferOutgoingData()) Q_PRIVATE_SLOT(d_func(), void _q_bufferOutgoingDataFinished()) + Q_PRIVATE_SLOT(d_func(), void _q_transferTimedOut()) #ifndef QT_NO_BEARERMANAGEMENT Q_PRIVATE_SLOT(d_func(), void _q_networkSessionConnected()) Q_PRIVATE_SLOT(d_func(), void _q_networkSessionFailed()) @@ -181,6 +183,9 @@ public: void _q_cacheSaveDeviceAboutToClose(); + void _q_transferTimedOut(); + void setupTransferTimeout(); + #ifndef QT_NO_BEARERMANAGEMENT void _q_networkSessionConnected(); void _q_networkSessionFailed(); @@ -250,6 +255,8 @@ public: qint64 bytesDownloaded; qint64 bytesBuffered; + QTimer *transferTimeout; + // Only used when the "zero copy" style is used. // Please note that the whole "zero copy" download buffer API is private right now. Do not use it. qint64 downloadBufferReadPosition; diff --git a/src/network/access/qnetworkrequest.cpp b/src/network/access/qnetworkrequest.cpp index 118fb6b1fb..e03d844af9 100644 --- a/src/network/access/qnetworkrequest.cpp +++ b/src/network/access/qnetworkrequest.cpp @@ -277,23 +277,30 @@ QT_BEGIN_NAMESPACE Indicates whether the QNetworkAccessManager code is allowed to use SPDY with this request. This applies only to SSL requests, and depends on the server supporting SPDY. + Obsolete, use Http2 instead of Spdy. \value SpdyWasUsedAttribute Replies only, type: QMetaType::Bool Indicates whether SPDY was used for receiving - this reply. + this reply. Obsolete, use Http2 instead of Spdy. - \value HTTP2AllowedAttribute + \value Http2AllowedAttribute Requests only, type: QMetaType::Bool (default: false) Indicates whether the QNetworkAccessManager code is allowed to use HTTP/2 with this request. This applies to SSL requests or 'cleartext' HTTP/2. - \value HTTP2WasUsedAttribute + \value Http2WasUsedAttribute Replies only, type: QMetaType::Bool (default: false) Indicates whether HTTP/2 was used for receiving this reply. (This value was introduced in 5.9.) + \value HTTP2AllowedAttribute + Obsolete alias for Http2AllowedAttribute. + + \value HTTP2WasUsedAttribute + Obsolete alias for Http2WasUsedAttribute. + \value EmitAllUploadProgressSignalsAttribute Requests only, type: QMetaType::Bool (default: false) Indicates whether all upload signals should be emitted. @@ -329,7 +336,7 @@ QT_BEGIN_NAMESPACE server supports HTTP/2. The attribute works with SSL or 'cleartext' HTTP/2. If a server turns out to not support HTTP/2, when HTTP/2 direct was specified, QNetworkAccessManager gives up, without attempting to - fall back to HTTP/1.1. If both HTTP2AllowedAttribute and + fall back to HTTP/1.1. If both Http2AllowedAttribute and Http2DirectAttribute are set, Http2DirectAttribute takes priority. (This value was introduced in 5.11.) @@ -418,6 +425,18 @@ QT_BEGIN_NAMESPACE based on some app-specific configuration. */ +/*! + \enum QNetworkRequest::TransferTimeoutConstant + \since 5.15 + + A constant that can be used for enabling transfer + timeouts with a preset value. + + \value TransferTimeoutPreset The transfer timeout in milliseconds. + Used if setTimeout() is called + without an argument. + */ + class QNetworkRequestPrivate: public QSharedData, public QNetworkHeadersPrivate { public: @@ -428,6 +447,7 @@ public: , sslConfiguration(0) #endif , maxRedirectsAllowed(maxRedirectCount) + , transferTimeout(0) { qRegisterMetaType<QNetworkRequest>(); } ~QNetworkRequestPrivate() { @@ -452,6 +472,7 @@ public: #if QT_CONFIG(http) h2Configuration = other.h2Configuration; #endif + transferTimeout = other.transferTimeout; } inline bool operator==(const QNetworkRequestPrivate &other) const @@ -465,6 +486,7 @@ public: #if QT_CONFIG(http) && h2Configuration == other.h2Configuration #endif + && transferTimeout == other.transferTimeout ; // don't compare cookedHeaders } @@ -479,6 +501,7 @@ public: #if QT_CONFIG(http) QHttp2Configuration h2Configuration; #endif + int transferTimeout; }; /*! @@ -902,6 +925,40 @@ void QNetworkRequest::setHttp2Configuration(const QHttp2Configuration &configura { d->h2Configuration = configuration; } + +/*! + \since 5.15 + + Returns the timeout used for transfers, in milliseconds. + + This timeout is zero if setTransferTimeout hasn't been + called, which means that the timeout is not used. + + \sa setTransferTimeout +*/ +int QNetworkRequest::transferTimeout() +{ + return d->transferTimeout; +} + +/*! + \since 5.15 + + Sets \a timeout as the transfer timeout in milliseconds. + + 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::TransferTimeoutPreset. If this function + is not called, the timeout is disabled and has the + value zero. + + \sa transferTimeout +*/ +void QNetworkRequest::setTransferTimeout(int timeout) +{ + d->transferTimeout = timeout; +} #endif // QT_CONFIG(http) || defined(Q_CLANG_QDOC) static QByteArray headerName(QNetworkRequest::KnownHeaders header) diff --git a/src/network/access/qnetworkrequest.h b/src/network/access/qnetworkrequest.h index e09ff8aaae..5d9969bd9b 100644 --- a/src/network/access/qnetworkrequest.h +++ b/src/network/access/qnetworkrequest.h @@ -89,12 +89,18 @@ public: DownloadBufferAttribute, // internal SynchronousRequestAttribute, // internal BackgroundRequestAttribute, +#if QT_DEPRECATED_SINCE(5, 15) SpdyAllowedAttribute, SpdyWasUsedAttribute, - EmitAllUploadProgressSignalsAttribute, +#endif // QT_DEPRECATED_SINCE(5, 15) + EmitAllUploadProgressSignalsAttribute = BackgroundRequestAttribute + 3, FollowRedirectsAttribute, - HTTP2AllowedAttribute, - HTTP2WasUsedAttribute, + Http2AllowedAttribute, + Http2WasUsedAttribute, +#if QT_DEPRECATED_SINCE(5, 15) + HTTP2AllowedAttribute Q_DECL_ENUMERATOR_DEPRECATED_X("Use Http2AllowedAttribute") = Http2AllowedAttribute, + HTTP2WasUsedAttribute Q_DECL_ENUMERATOR_DEPRECATED_X("Use Http2WasUsedAttribute"), +#endif // QT_DEPRECATED_SINCE(5, 15) OriginalContentLengthAttribute, RedirectPolicyAttribute, Http2DirectAttribute, @@ -128,6 +134,9 @@ public: UserVerifiedRedirectPolicy }; + enum TransferTimeoutConstant { + TransferTimeoutPreset = 30000 + }; QNetworkRequest(); explicit QNetworkRequest(const QUrl &url); @@ -179,6 +188,9 @@ public: #if QT_CONFIG(http) || defined(Q_CLANG_QDOC) QHttp2Configuration http2Configuration() const; void setHttp2Configuration(const QHttp2Configuration &configuration); + + int transferTimeout(); + void setTransferTimeout(int timeout = TransferTimeoutPreset); #endif // QT_CONFIG(http) || defined(Q_CLANG_QDOC) private: QSharedDataPointer<QNetworkRequestPrivate> d; |