src/network/access/qhttpnetworkconnection.cpp
changeset 7 f7bc934e204c
parent 3 41300fa6a67c
--- 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);