network: finish all pending replies upon error

... and not only one. This was a problem e.g. when there were several
requests to the same host and the host was not reachable; only one
reply would get an error signal in case we suppressed other errors in
"happy eyeballs" host lookup style.

Task-number: QTBUG-36890

Change-Id: I1b5757498bd644b0d773cf6c43e4950620949c5c
Reviewed-by: Richard J. Moore <rich@kde.org>
This commit is contained in:
Peter Hartmann 2014-03-26 09:40:52 -04:00 committed by The Qt Project
parent 362c75f7c1
commit 9c2ecf89eb
2 changed files with 56 additions and 11 deletions

View File

@ -873,18 +873,23 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
if (!connection->d_func()->shouldEmitChannelError(socket))
return;
// Need to dequeu the request so that we can emit the error.
if (!reply)
connection->d_func()->dequeueRequest(socket);
if (reply) {
reply->d_func()->errorString = errorString;
emit reply->finishedWithError(errorCode, errorString);
reply = 0;
if (protocolHandler)
protocolHandler->setReply(0);
}
// emit error for all waiting replies
do {
// Need to dequeu the request so that we can emit the error.
if (!reply)
connection->d_func()->dequeueRequest(socket);
if (reply) {
reply->d_func()->errorString = errorString;
emit reply->finishedWithError(errorCode, errorString);
reply = 0;
if (protocolHandler)
protocolHandler->setReply(0);
}
} while (!connection->d_func()->highPriorityQueue.isEmpty()
|| !connection->d_func()->lowPriorityQueue.isEmpty());
#ifndef QT_NO_SSL
else if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeSPDY) {
if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeSPDY) {
QList<HttpMessagePair> spdyPairs = spdyRequestsToSend.values();
for (int a = 0; a < spdyPairs.count(); ++a) {
// emit error for all replies

View File

@ -177,6 +177,7 @@ public Q_SLOTS:
void authenticationRequired(QNetworkReply*,QAuthenticator*);
void proxyAuthenticationRequired(const QNetworkProxy &,QAuthenticator*);
void pipeliningHelperSlot();
void emitErrorForAllRepliesSlot();
#ifndef QT_NO_SSL
void sslErrors(QNetworkReply*,const QList<QSslError> &);
@ -449,6 +450,8 @@ private Q_SLOTS:
void ftpAuthentication_data();
void ftpAuthentication();
void emitErrorForAllReplies(); // QTBUG-36890
#ifdef QT_BUILD_INTERNAL
void backgroundRequest_data();
void backgroundRequest();
@ -7465,6 +7468,12 @@ void tst_QNetworkReply::pipeliningHelperSlot() {
}
}
void tst_QNetworkReply::emitErrorForAllRepliesSlot() {
static int a = 0;
if (++a == 3)
QTestEventLoop::instance().exitLoop();
}
void tst_QNetworkReply::closeDuringDownload_data()
{
QTest::addColumn<QUrl>("url");
@ -7513,6 +7522,37 @@ void tst_QNetworkReply::ftpAuthentication()
QCOMPARE(reply->error(), QNetworkReply::NetworkError(error));
}
void tst_QNetworkReply::emitErrorForAllReplies() // QTBUG-36890
{
// port 100 is not well-known and should be closed
QList<QUrl> urls = QList<QUrl>() << QUrl("http://localhost:100/request1")
<< QUrl("http://localhost:100/request2")
<< QUrl("http://localhost:100/request3");
QList<QNetworkReply *> replies;
QList<QSignalSpy *> errorSpies;
QList<QSignalSpy *> finishedSpies;
for (int a = 0; a < urls.count(); ++a) {
QNetworkRequest request(urls.at(a));
QNetworkReply *reply = manager.get(request);
replies.append(reply);
QSignalSpy *errorSpy = new QSignalSpy(reply, SIGNAL(error(QNetworkReply::NetworkError)));
errorSpies.append(errorSpy);
QSignalSpy *finishedSpy = new QSignalSpy(reply, SIGNAL(finished()));
finishedSpies.append(finishedSpy);
QObject::connect(reply, SIGNAL(finished()), SLOT(emitErrorForAllRepliesSlot()));
}
QTestEventLoop::instance().enterLoop(10);
QVERIFY(!QTestEventLoop::instance().timeout());
for (int a = 0; a < urls.count(); ++a) {
QVERIFY(replies.at(a)->isFinished());
QCOMPARE(errorSpies.at(a)->count(), 1);
errorSpies.at(a)->deleteLater();
QCOMPARE(finishedSpies.at(a)->count(), 1);
finishedSpies.at(a)->deleteLater();
replies.at(a)->deleteLater();
}
}
#ifdef QT_BUILD_INTERNAL
void tst_QNetworkReply::backgroundRequest_data()
{