diff options
author | Markus Goetz <Markus.Goetz@nokia.com> | 2009-09-23 10:40:05 (GMT) |
---|---|---|
committer | Markus Goetz <Markus.Goetz@nokia.com> | 2009-09-23 11:39:00 (GMT) |
commit | af71faf8cb2c9cbf34c408b81ce7ae1ef6c6403e (patch) | |
tree | d3332709352660b5256d8656c48b360d31eaf67d | |
parent | d74b951c7380f8a210c701152ddafe6481c1a43b (diff) | |
download | Qt-af71faf8cb2c9cbf34c408b81ce7ae1ef6c6403e.zip Qt-af71faf8cb2c9cbf34c408b81ce7ae1ef6c6403e.tar.gz Qt-af71faf8cb2c9cbf34c408b81ce7ae1ef6c6403e.tar.bz2 |
QNAM HTTP Code: Properly remove aborted requests from processing
This fixes a crash that occured because aborted requests were
not properly removed from the channel.alreadyPipelinedRequests.
Task-number: QTBUG-4507
Reviewed-by: Peter Hartmann
-rw-r--r-- | src/network/access/qhttpnetworkconnection.cpp | 38 | ||||
-rw-r--r-- | src/network/access/qhttpnetworkconnectionchannel.cpp | 3 | ||||
-rw-r--r-- | src/network/access/qhttpnetworkreply.cpp | 3 | ||||
-rw-r--r-- | src/network/access/qhttpnetworkreply_p.h | 1 |
4 files changed, 41 insertions, 4 deletions
diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp index 2aa84d0..27c0ed4 100644 --- a/src/network/access/qhttpnetworkconnection.cpp +++ b/src/network/access/qhttpnetworkconnection.cpp @@ -588,19 +588,53 @@ QString QHttpNetworkConnectionPrivate::errorDetail(QNetworkReply::NetworkError e return errorString; } +// this is called from the destructor of QHttpNetworkReply. It is called when +// the reply was finished correctly or when it was aborted. void QHttpNetworkConnectionPrivate::removeReply(QHttpNetworkReply *reply) { Q_Q(QHttpNetworkConnection); - // remove the from active list. + // check if the reply is currently being processed or it is pipelined in for (int i = 0; i < channelCount; ++i) { + // is the reply associated the currently processing of this channel? if (channels[i].reply == reply) { channels[i].reply = 0; - if (reply->d_func()->isConnectionCloseEnabled()) + + if (!reply->isFinished() && !channels[i].alreadyPipelinedRequests.isEmpty()) { + // the reply had to be prematurely removed, e.g. it was not finished + // therefore we have to requeue the already pipelined requests. + channels[i].requeueCurrentlyPipelinedRequests(); + } + + // if HTTP mandates we should close + // or the reply is not finished yet, e.g. it was aborted + // we have to close that connection + if (reply->d_func()->isConnectionCloseEnabled() || !reply->isFinished()) channels[i].close(); + QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection); return; } + + // is the reply inside the pipeline of this channel already? + for (int j = 0; j < channels[i].alreadyPipelinedRequests.length(); j++) { + if (channels[i].alreadyPipelinedRequests.at(j).second == reply) { + // Remove that HttpMessagePair + channels[i].alreadyPipelinedRequests.removeAt(j); + + channels[i].requeueCurrentlyPipelinedRequests(); + + // Since some requests had already been pipelined, but we removed + // one and re-queued the others + // we must force a connection close after the request that is + // currently in processing has been finished. + if (channels[i].reply) + channels[i].reply->d_func()->forceConnectionCloseEnabled = true; + + QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection); + return; + } + } } // remove from the high priority queue if (!highPriorityQueue.isEmpty()) { diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index 641b35b..beab9af 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -542,6 +542,7 @@ void QHttpNetworkConnectionChannel::allDone() if (resendCurrent || reply->d_func()->isConnectionCloseEnabled() || socket->state() != QAbstractSocket::ConnectedState) { // move the pipelined ones back to the main queue requeueCurrentlyPipelinedRequests(); + close(); } else { // there were requests pipelined in and we can continue HttpMessagePair messagePair = alreadyPipelinedRequests.takeFirst(); @@ -601,7 +602,6 @@ void QHttpNetworkConnectionChannel::requeueCurrentlyPipelinedRequests() connection->d_func()->requeueRequest(alreadyPipelinedRequests.at(i)); alreadyPipelinedRequests.clear(); - close(); QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection); } @@ -758,6 +758,7 @@ void QHttpNetworkConnectionChannel::_q_disconnected() state = QHttpNetworkConnectionChannel::IdleState; requeueCurrentlyPipelinedRequests(); + close(); } diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp index c953ebf..e990704 100644 --- a/src/network/access/qhttpnetworkreply.cpp +++ b/src/network/access/qhttpnetworkreply.cpp @@ -198,6 +198,7 @@ QHttpNetworkReplyPrivate::QHttpNetworkReplyPrivate(const QUrl &newUrl) majorVersion(0), minorVersion(0), bodyLength(0), contentRead(0), totalProgress(0), chunkedTransferEncoding(false), connectionCloseEnabled(true), + forceConnectionCloseEnabled(false), currentChunkSize(0), currentChunkRead(0), connection(0), initInflate(false), autoDecompress(false), responseData(), requestIsPrepared(false) ,pipeliningUsed(false) @@ -564,7 +565,7 @@ bool QHttpNetworkReplyPrivate::isChunked() bool QHttpNetworkReplyPrivate::isConnectionCloseEnabled() { - return connectionCloseEnabled; + return connectionCloseEnabled || forceConnectionCloseEnabled; } // note this function can only be used for non-chunked, non-compressed with diff --git a/src/network/access/qhttpnetworkreply_p.h b/src/network/access/qhttpnetworkreply_p.h index ded1d44..1073560 100644 --- a/src/network/access/qhttpnetworkreply_p.h +++ b/src/network/access/qhttpnetworkreply_p.h @@ -213,6 +213,7 @@ public: QByteArray fragment; // used for header, status, chunk header etc, not for reply data bool chunkedTransferEncoding; bool connectionCloseEnabled; + bool forceConnectionCloseEnabled; qint64 currentChunkSize; qint64 currentChunkRead; QPointer<QHttpNetworkConnection> connection; |