--- a/src/network/access/qhttpnetworkconnection.cpp Tue Feb 02 00:43:10 2010 +0200
+++ b/src/network/access/qhttpnetworkconnection.cpp Wed Mar 31 11:06:36 2010 +0300
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
@@ -404,6 +404,7 @@
QHttpNetworkReply *reply = new QHttpNetworkReply(request.url());
reply->setRequest(request);
reply->d_func()->connection = q;
+ reply->d_func()->connectionChannel = &channels[0]; // will have the correct one set later
HttpMessagePair pair = qMakePair(request, reply);
switch (request.priority()) {
@@ -415,7 +416,18 @@
lowPriorityQueue.prepend(pair);
break;
}
- QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection);
+
+ // this used to be called via invokeMethod and a QueuedConnection
+ // It is the only place _q_startNextRequest is called directly without going
+ // through the event loop using a QueuedConnection.
+ // This is dangerous because of recursion that might occur when emitting
+ // signals as DirectConnection from this code path. Therefore all signal
+ // emissions that can come out from this code path need to
+ // be QueuedConnection.
+ // We are currently trying to fine-tune this.
+ _q_startNextRequest();
+
+
return reply;
}
@@ -433,6 +445,7 @@
lowPriorityQueue.prepend(pair);
break;
}
+
QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection);
}
@@ -564,7 +577,8 @@
}
-QString QHttpNetworkConnectionPrivate::errorDetail(QNetworkReply::NetworkError errorCode, QAbstractSocket* socket)
+QString QHttpNetworkConnectionPrivate::errorDetail(QNetworkReply::NetworkError errorCode, QAbstractSocket* socket,
+ const QString &extraDetail)
{
Q_ASSERT(socket);
@@ -581,7 +595,7 @@
errorString = QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Connection closed"));
break;
case QNetworkReply::TimeoutError:
- errorString = QLatin1String(QT_TRANSLATE_NOOP("QHttp", "HTTP request failed"));
+ errorString = QLatin1String(QT_TRANSLATE_NOOP("QAbstractSocket", "Socket operation timed out"));
break;
case QNetworkReply::ProxyAuthenticationRequiredError:
errorString = QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Proxy requires authentication"));
@@ -600,7 +614,7 @@
break;
default:
// all other errors are treated as QNetworkReply::UnknownNetworkError
- errorString = QLatin1String(QT_TRANSLATE_NOOP("QHttp", "HTTP request failed"));
+ errorString = extraDetail;
break;
}
return errorString;
@@ -680,6 +694,8 @@
+// This function must be called from the event loop. The only
+// exception is documented in QHttpNetworkConnectionPrivate::queueRequest
void QHttpNetworkConnectionPrivate::_q_startNextRequest()
{
//resend the necessary ones.
@@ -687,23 +703,39 @@
if (channels[i].resendCurrent) {
channels[i].resendCurrent = false;
channels[i].state = QHttpNetworkConnectionChannel::IdleState;
- if (channels[i].reply)
- channels[i].sendRequest();
+
+ // if this is not possible, error will be emitted and connection terminated
+ if (!channels[i].resetUploadData())
+ continue;
+
+ channels[i].sendRequest();
}
}
+
+ // dequeue new ones
+
QAbstractSocket *socket = 0;
for (int i = 0; i < channelCount; ++i) {
QAbstractSocket *chSocket = channels[i].socket;
- // send the request using the idle socket
- if (!channels[i].isSocketBusy()) {
+ // try to get a free AND connected socket
+ if (!channels[i].isSocketBusy() && channels[i].socket->state() == QAbstractSocket::ConnectedState) {
socket = chSocket;
+ dequeueAndSendRequest(socket);
break;
}
}
- // this socket is free,
- if (socket)
- dequeueAndSendRequest(socket);
+ if (!socket) {
+ for (int i = 0; i < channelCount; ++i) {
+ QAbstractSocket *chSocket = channels[i].socket;
+ // try to get a free unconnected socket
+ if (!channels[i].isSocketBusy()) {
+ socket = chSocket;
+ dequeueAndSendRequest(socket);
+ break;
+ }
+ }
+ }
// try to push more into all sockets
// ### FIXME we should move this to the beginning of the function
@@ -731,6 +763,16 @@
}
}
+void QHttpNetworkConnectionPrivate::readMoreLater(QHttpNetworkReply *reply)
+{
+ for (int i = 0 ; i < channelCount; ++i) {
+ if (channels[i].reply == reply) {
+ // emulate a readyRead() from the socket
+ QMetaObject::invokeMethod(&channels[i], "_q_readyRead", Qt::QueuedConnection);
+ return;
+ }
+ }
+}
QHttpNetworkConnection::QHttpNetworkConnection(const QString &hostName, quint16 port, bool encrypt, QObject *parent)
: QObject(*(new QHttpNetworkConnectionPrivate(hostName, port, encrypt)), parent)
@@ -832,17 +874,6 @@
// SSL support below
#ifndef QT_NO_OPENSSL
-QSslConfiguration QHttpNetworkConnectionPrivate::sslConfiguration(const QHttpNetworkReply &reply) const
-{
- if (!encrypt)
- return QSslConfiguration();
-
- for (int i = 0; i < channelCount; ++i)
- if (channels[i].reply == &reply)
- return static_cast<QSslSocket *>(channels[0].socket)->sslConfiguration();
- return QSslConfiguration(); // pending or done request
-}
-
void QHttpNetworkConnection::setSslConfiguration(const QSslConfiguration &config)
{
Q_D(QHttpNetworkConnection);