From 9c2ecf89eb773b4929d39a0a4929ce2b647aaaef Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Wed, 26 Mar 2014 09:40:52 -0400 Subject: 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 --- .../access/qhttpnetworkconnectionchannel.cpp | 27 +++++++++------ .../access/qnetworkreply/tst_qnetworkreply.cpp | 40 ++++++++++++++++++++++ 2 files changed, 56 insertions(+), 11 deletions(-) diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index fb40958178..169124e9f4 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -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 spdyPairs = spdyRequestsToSend.values(); for (int a = 0; a < spdyPairs.count(); ++a) { // emit error for all replies diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp index 11ea8aebc8..fbac7dc77c 100644 --- a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp @@ -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 &); @@ -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("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 urls = QList() << QUrl("http://localhost:100/request1") + << QUrl("http://localhost:100/request2") + << QUrl("http://localhost:100/request3"); + QList replies; + QList errorSpies; + QList 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() { -- cgit v1.2.3