summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarkus Goetz <Markus.Goetz@nokia.com>2009-09-23 10:40:05 (GMT)
committerMarkus Goetz <Markus.Goetz@nokia.com>2009-09-23 11:39:00 (GMT)
commitaf71faf8cb2c9cbf34c408b81ce7ae1ef6c6403e (patch)
treed3332709352660b5256d8656c48b360d31eaf67d
parentd74b951c7380f8a210c701152ddafe6481c1a43b (diff)
downloadQt-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.cpp38
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel.cpp3
-rw-r--r--src/network/access/qhttpnetworkreply.cpp3
-rw-r--r--src/network/access/qhttpnetworkreply_p.h1
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;