refactor disconnectFromFtp to remove cached entries when necessary

In cases where a cached ftp connection fails to connect, or a file
transfer has failed, we should removed the cached connection. Since qnam
has an idea of a single internal QFtp per full operation, when file
transfers failed previously the cached connection would be reused for
subsequent connections and thus fail.

[ChangeLog][QtNetwork][QNetworkAccessManager] QNetworkAccessManager now
properly handles FTP transfer failures by removing failed cached ftp
connections.

Task-number: QTBUG-40797
Change-Id: Ie090a39ceddd7e58a0d8baf7d01f2a08c70162e5
Reviewed-by: Richard J. Moore <rich@kde.org>
bb10
Matt Broadstone 2014-08-15 09:26:04 -04:00 committed by Matt Broadstone
parent f630eb1120
commit 45cbbe56bc
3 changed files with 36 additions and 12 deletions

View File

@ -211,7 +211,7 @@ void QNetworkAccessFtpBackend::ftpConnectionReady(QNetworkAccessCache::Cacheable
// no, defer the actual operation until after we've logged in
}
void QNetworkAccessFtpBackend::disconnectFromFtp()
void QNetworkAccessFtpBackend::disconnectFromFtp(CacheCleanupMode mode)
{
state = Disconnecting;
@ -219,7 +219,12 @@ void QNetworkAccessFtpBackend::disconnectFromFtp()
disconnect(ftp, 0, this, 0);
QByteArray key = makeCacheKey(url());
QNetworkAccessManagerPrivate::getObjectCache(this)->releaseEntry(key);
if (mode == RemoveCachedConnection) {
QNetworkAccessManagerPrivate::getObjectCache(this)->removeEntry(key);
ftp->dispose();
} else {
QNetworkAccessManagerPrivate::getObjectCache(this)->releaseEntry(key);
}
ftp = 0;
}
@ -274,14 +279,7 @@ void QNetworkAccessFtpBackend::ftpDone()
}
// we're not connected, so remove the cache entry:
QByteArray key = makeCacheKey(url());
QNetworkAccessManagerPrivate::getObjectCache(this)->removeEntry(key);
disconnect(ftp, 0, this, 0);
ftp->dispose();
ftp = 0;
state = Disconnecting;
disconnectFromFtp(RemoveCachedConnection);
finished();
return;
}
@ -301,7 +299,7 @@ void QNetworkAccessFtpBackend::ftpDone()
else
error(QNetworkReply::ContentAccessDenied, msg);
disconnectFromFtp();
disconnectFromFtp(RemoveCachedConnection);
finished();
}

View File

@ -90,7 +90,12 @@ public:
virtual void downstreamReadyWrite();
void disconnectFromFtp();
enum CacheCleanupMode {
ReleaseCachedConnection,
RemoveCachedConnection
};
void disconnectFromFtp(CacheCleanupMode mode = ReleaseCachedConnection);
public slots:
void ftpConnectionReady(QNetworkAccessCache::CacheableObject *object);

View File

@ -206,6 +206,7 @@ private Q_SLOTS:
void getFromFileSpecial();
void getFromFtp_data();
void getFromFtp();
void getFromFtpAfterError(); // QTBUG-40797
void getFromHttp_data();
void getFromHttp();
void getErrors_data();
@ -1753,6 +1754,26 @@ void tst_QNetworkReply::getFromFtp()
QCOMPARE(reply->readAll(), reference.readAll());
}
void tst_QNetworkReply::getFromFtpAfterError()
{
QNetworkRequest invalidRequest(QUrl("ftp://" + QtNetworkSettings::serverName() + "/qtest/invalid.txt"));
QNetworkReplyPtr invalidReply;
invalidReply.reset(manager.get(invalidRequest));
QSignalSpy spy(invalidReply.data(), SIGNAL(error(QNetworkReply::NetworkError)));
QVERIFY(spy.wait());
QCOMPARE(invalidReply->error(), QNetworkReply::ContentNotFoundError);
QFile reference(testDataDir + "/rfc3252.txt");
QVERIFY(reference.open(QIODevice::ReadOnly));
QNetworkRequest validRequest(QUrl("ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
QNetworkReplyPtr validReply;
RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, validRequest, validReply));
QCOMPARE(validReply->url(), validRequest.url());
QCOMPARE(validReply->error(), QNetworkReply::NoError);
QCOMPARE(validReply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
QCOMPARE(validReply->readAll(), reference.readAll());
}
void tst_QNetworkReply::getFromHttp_data()
{
QTest::addColumn<QString>("referenceName");