Add setAutoDeleteReplies to QNetworkAccessManager

Following the introduction of AutoDeleteReplyOnFinishAttribute to
QNetworkRequest it seems natural to make it easy to enable for all
replies created with the current QNetworkAccessManager.

[ChangeLog][QtNetwork][QNetworkAccessManager] Added setAutoDeleteReplies
to QNetworkAccessManager to enable the AutoDeleteReplyOnFinishAttribute
attribute for all QNetworkRequests that are passed to
QNetworkAccessManager.

Change-Id: I7f96dd1fc9a899328e89732be17780b4e710c2a2
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Reviewed-by: Markus Goetz (Woboq GmbH) <markus@woboq.com>
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
Mårten Nordheim 2019-04-26 12:56:23 +02:00
parent 927eba344c
commit cd816d4b6a
4 changed files with 135 additions and 0 deletions

View File

@ -1402,6 +1402,11 @@ 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();
@ -1672,6 +1677,40 @@ 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);

View File

@ -167,6 +167,9 @@ public:
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);

View File

@ -227,6 +227,8 @@ public:
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);
#endif

View File

@ -505,6 +505,8 @@ private Q_SLOTS:
void autoDeleteRepliesAttribute_data();
void autoDeleteRepliesAttribute();
void autoDeleteReplies_data();
void autoDeleteReplies();
// NOTE: This test must be last!
void parentingRepliesToTheApp();
@ -9241,6 +9243,95 @@ void tst_QNetworkReply::autoDeleteRepliesAttribute()
}
}
void tst_QNetworkReply::autoDeleteReplies_data()
{
autoDeleteRepliesAttribute_data();
}
void tst_QNetworkReply::autoDeleteReplies()
{
QFETCH(QUrl, destination);
manager.setAutoDeleteReplies(true);
auto cleanup = qScopeGuard([this] { manager.setAutoDeleteReplies(false); });
{
// Get
QNetworkRequest request(destination);
QNetworkReply *reply = manager.get(request);
QSignalSpy finishedSpy(reply, &QNetworkReply::finished);
QSignalSpy destroyedSpy(reply, &QObject::destroyed);
QVERIFY(finishedSpy.wait());
QCOMPARE(destroyedSpy.count(), 0);
QVERIFY(destroyedSpy.wait());
}
{
// Post
QNetworkRequest request(destination);
QNetworkReply *reply = manager.post(request, QByteArrayLiteral("datastring"));
QSignalSpy finishedSpy(reply, &QNetworkReply::finished);
QSignalSpy destroyedSpy(reply, &QObject::destroyed);
QVERIFY(finishedSpy.wait());
QCOMPARE(destroyedSpy.count(), 0);
QVERIFY(destroyedSpy.wait());
}
// Here we repeat the test, but override the auto-deletion in the QNetworkRequest
// We need two calls to processEvents to test that the QNetworkReply doesn't get deleted.
// The first call executes a metacall event which adds the deleteLater meta event which
// would be executed in the second call. But that shouldn't happen in this case.
{
// Get
QNetworkRequest request(destination);
request.setAttribute(QNetworkRequest::AutoDeleteReplyOnFinishAttribute, false);
QScopedPointer<QNetworkReply> reply(manager.get(request));
QSignalSpy finishedSpy(reply.data(), &QNetworkReply::finished);
QSignalSpy destroyedSpy(reply.data(), &QObject::destroyed);
QVERIFY(finishedSpy.wait());
QCOMPARE(destroyedSpy.count(), 0);
QCoreApplication::processEvents();
QCoreApplication::processEvents();
QCOMPARE(destroyedSpy.count(), 0);
}
{
// Post
QNetworkRequest request(destination);
request.setAttribute(QNetworkRequest::AutoDeleteReplyOnFinishAttribute, false);
QScopedPointer<QNetworkReply> reply(manager.post(request, QByteArrayLiteral("datastring")));
QSignalSpy finishedSpy(reply.data(), &QNetworkReply::finished);
QSignalSpy destroyedSpy(reply.data(), &QObject::destroyed);
QVERIFY(finishedSpy.wait());
QCOMPARE(destroyedSpy.count(), 0);
QCoreApplication::processEvents();
QCoreApplication::processEvents();
QCOMPARE(destroyedSpy.count(), 0);
}
// Now we repeat the test with autoDeleteReplies set to false
cleanup.dismiss();
manager.setAutoDeleteReplies(false);
{
// Get
QNetworkRequest request(destination);
QScopedPointer<QNetworkReply> reply(manager.get(request));
QSignalSpy finishedSpy(reply.data(), &QNetworkReply::finished);
QSignalSpy destroyedSpy(reply.data(), &QObject::destroyed);
QVERIFY(finishedSpy.wait());
QCOMPARE(destroyedSpy.count(), 0);
QCoreApplication::processEvents();
QCoreApplication::processEvents();
QCOMPARE(destroyedSpy.count(), 0);
}
{
// Post
QNetworkRequest request(destination);
QScopedPointer<QNetworkReply> reply(manager.post(request, QByteArrayLiteral("datastring")));
QSignalSpy finishedSpy(reply.data(), &QNetworkReply::finished);
QSignalSpy destroyedSpy(reply.data(), &QObject::destroyed);
QVERIFY(finishedSpy.wait());
QCOMPARE(destroyedSpy.count(), 0);
QCoreApplication::processEvents();
QCoreApplication::processEvents();
QCOMPARE(destroyedSpy.count(), 0);
}
}
// NOTE: This test must be last testcase in tst_qnetworkreply!
void tst_QNetworkReply::parentingRepliesToTheApp()
{