diff options
author | Peter Hartmann <peter.hartmann@nokia.com> | 2009-12-15 09:52:52 (GMT) |
---|---|---|
committer | Peter Hartmann <peter.hartmann@nokia.com> | 2010-01-11 09:48:05 (GMT) |
commit | 145fecc833926c307819752912e6833169799a53 (patch) | |
tree | e527d59a10244b7b6c71b8e63c5019a7dd34c2e4 | |
parent | ef5a985cf47c32bac0ddd3bae1edb7e922e7ec69 (diff) | |
download | Qt-145fecc833926c307819752912e6833169799a53.zip Qt-145fecc833926c307819752912e6833169799a53.tar.gz Qt-145fecc833926c307819752912e6833169799a53.tar.bz2 |
network internals: start HTTP GET requests right away when called
on the code path from QNetworkAccessManager::get() to
QTcpSocket::write() there were two calls involved that were invoked
via a QueuedConnection, which would in some occasions delay writing the
data to the socket. This patch makes sure the data is written to the
socket immediately, without returning to the event loop (only the HTTP
backend was changed for that event, the other backends were not
changed)
Reviewed-by: Thiago Macieira
Reviewed-by: Markus Goetz
-rw-r--r-- | src/network/access/qhttpnetworkconnection.cpp | 8 | ||||
-rw-r--r-- | src/network/access/qhttpnetworkconnectionchannel.cpp | 12 | ||||
-rw-r--r-- | src/network/access/qhttpnetworkconnectionchannel_p.h | 2 | ||||
-rw-r--r-- | src/network/access/qnetworkaccesshttpbackend.cpp | 7 | ||||
-rw-r--r-- | src/network/access/qnetworkaccesshttpbackend_p.h | 2 | ||||
-rw-r--r-- | src/network/access/qnetworkaccessmanager.cpp | 4 | ||||
-rw-r--r-- | src/network/access/qnetworkreplyimpl.cpp | 13 |
7 files changed, 30 insertions, 18 deletions
diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp index 44a0a79..2c56524 100644 --- a/src/network/access/qhttpnetworkconnection.cpp +++ b/src/network/access/qhttpnetworkconnection.cpp @@ -415,14 +415,13 @@ QHttpNetworkReply* QHttpNetworkConnectionPrivate::queueRequest(const QHttpNetwor lowPriorityQueue.prepend(pair); break; } - QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection); + // this used to be called via invokeMethod and a QueuedConnection + _q_startNextRequest(); return reply; } void QHttpNetworkConnectionPrivate::requeueRequest(const HttpMessagePair &pair) { - Q_Q(QHttpNetworkConnection); - QHttpNetworkRequest request = pair.first; switch (request.priority()) { case QHttpNetworkRequest::HighPriority: @@ -433,7 +432,8 @@ void QHttpNetworkConnectionPrivate::requeueRequest(const HttpMessagePair &pair) lowPriorityQueue.prepend(pair); break; } - QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection); + // this used to be called via invokeMethod and a QueuedConnection + _q_startNextRequest(); } void QHttpNetworkConnectionPrivate::dequeueAndSendRequest(QAbstractSocket *socket) diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index 1a68e97..7cf632f 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -166,6 +166,8 @@ bool QHttpNetworkConnectionChannel::sendRequest() QByteArray header = QHttpNetworkRequestPrivate::header(request, false); #endif socket->write(header); + // flushing is dangerous (QSslSocket calls transmit which might read or error) +// socket->flush(); QNonContiguousByteDevice* uploadByteDevice = request.uploadByteDevice(); if (uploadByteDevice) { // connect the signals so this function gets called again @@ -258,7 +260,7 @@ bool QHttpNetworkConnectionChannel::sendRequest() // ensure we try to receive a reply in all cases, even if _q_readyRead_ hat not been called // this is needed if the sends an reply before we have finished sending the request. In that // case receiveReply had been called before but ignored the server reply - receiveReply(); + QMetaObject::invokeMethod(connection, "_q_receiveReply", Qt::QueuedConnection); break; } case QHttpNetworkConnectionChannel::ReadingState: @@ -272,7 +274,7 @@ bool QHttpNetworkConnectionChannel::sendRequest() } -void QHttpNetworkConnectionChannel::receiveReply() +void QHttpNetworkConnectionChannel::_q_receiveReply() { Q_ASSERT(socket); @@ -567,7 +569,7 @@ void QHttpNetworkConnectionChannel::allDone() connection->d_func()->fillPipeline(socket); // continue reading - receiveReply(); + _q_receiveReply(); } } else if (alreadyPipelinedRequests.isEmpty() && socket->bytesAvailable() > 0) { eatWhitespace(); @@ -739,7 +741,7 @@ void QHttpNetworkConnectionChannel::_q_readyRead() if (isSocketWaiting() || isSocketReading()) { state = QHttpNetworkConnectionChannel::ReadingState; if (reply) - receiveReply(); + _q_receiveReply(); } } @@ -758,7 +760,7 @@ void QHttpNetworkConnectionChannel::_q_disconnected() if (isSocketWaiting() || isSocketReading()) { state = QHttpNetworkConnectionChannel::ReadingState; if (reply) - receiveReply(); + _q_receiveReply(); } else if (state == QHttpNetworkConnectionChannel::IdleState && resendCurrent) { // re-sending request because the socket was in ClosingState QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection); diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h index bbe43cd..c30c236 100644 --- a/src/network/access/qhttpnetworkconnectionchannel_p.h +++ b/src/network/access/qhttpnetworkconnectionchannel_p.h @@ -144,7 +144,6 @@ public: void close(); bool sendRequest(); - void receiveReply(); bool ensureConnection(); @@ -166,6 +165,7 @@ public: bool isSocketReading() const; protected slots: + void _q_receiveReply(); void _q_bytesWritten(qint64 bytes); // proceed sending void _q_readyRead(); // pending data to read void _q_disconnected(); // disconnected from host diff --git a/src/network/access/qnetworkaccesshttpbackend.cpp b/src/network/access/qnetworkaccesshttpbackend.cpp index 5a2cce4..ada00df 100644 --- a/src/network/access/qnetworkaccesshttpbackend.cpp +++ b/src/network/access/qnetworkaccesshttpbackend.cpp @@ -594,9 +594,10 @@ void QNetworkAccessHttpBackend::open() if (transparentProxy.type() == QNetworkProxy::DefaultProxy && cacheProxy.type() == QNetworkProxy::DefaultProxy) { // unsuitable proxies - error(QNetworkReply::ProxyNotFoundError, - tr("No suitable proxy found")); - finished(); + QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, + Q_ARG(QNetworkReply::NetworkError, QNetworkReply::ProxyNotFoundError), + Q_ARG(QString, QCoreApplication::translate("QNetworkAccessHttpBackend", "No suitable proxy found"))); + QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection); return; } #endif diff --git a/src/network/access/qnetworkaccesshttpbackend_p.h b/src/network/access/qnetworkaccesshttpbackend_p.h index bc3980d..705323d 100644 --- a/src/network/access/qnetworkaccesshttpbackend_p.h +++ b/src/network/access/qnetworkaccesshttpbackend_p.h @@ -104,6 +104,7 @@ private slots: void httpAuthenticationRequired(const QHttpNetworkRequest &request, QAuthenticator *auth); void httpError(QNetworkReply::NetworkError error, const QString &errorString); bool sendCacheContents(const QNetworkCacheMetaData &metaData); + void finished(); // override private: QHttpNetworkReply *httpReply; @@ -118,7 +119,6 @@ private: #endif void disconnectFromHttp(); - void finished(); // override void setupConnection(); void validateCache(QHttpNetworkRequest &httpRequest, bool &loadedFromCache); void invalidateCache(); diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index 2f57fee..d27fbe7 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -723,8 +723,6 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera // third step: find a backend priv->backend = d->findBackend(op, request); - // fourth step: setup the reply - priv->setup(op, request, outgoingData); #ifndef QT_NO_NETWORKPROXY QList<QNetworkProxy> proxyList = d->queryProxy(QNetworkProxyQuery(request.url())); priv->proxyList = proxyList; @@ -733,6 +731,8 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera priv->backend->setParent(reply); priv->backend->reply = priv; } + // fourth step: setup the reply + priv->setup(op, request, outgoingData); #ifndef QT_NO_OPENSSL reply->setSslConfiguration(request.sslConfiguration()); diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp index 42e802f..285864d 100644 --- a/src/network/access/qnetworkreplyimpl.cpp +++ b/src/network/access/qnetworkreplyimpl.cpp @@ -72,6 +72,9 @@ void QNetworkReplyImplPrivate::_q_startOperation() } state = Working; + // note: if that method is called directly, it cannot happen that the backend is 0, + // because we just checked via a qobject_cast that we got a http backend (see + // QNetworkReplyImplPrivate::setup()) if (!backend) { error(QNetworkReplyImpl::ProtocolUnknownError, QCoreApplication::translate("QNetworkReply", "Protocol \"%1\" is unknown").arg(url.scheme())); // not really true!; @@ -203,7 +206,6 @@ void QNetworkReplyImplPrivate::_q_bufferOutgoingData() } } - void QNetworkReplyImplPrivate::setup(QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice *data) { @@ -246,7 +248,14 @@ void QNetworkReplyImplPrivate::setup(QNetworkAccessManager::Operation op, const // No outgoing data (e.g. HTTP GET request) // or no backend // if no backend, _q_startOperation will handle the error of this - QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection); + + // for HTTP, we want to send out the request as fast as possible to the network, without + // invoking methods in a QueuedConnection + if (qobject_cast<QNetworkAccessHttpBackend *>(backend)) { + _q_startOperation(); + } else { + QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection); + } } q->QIODevice::open(QIODevice::ReadOnly); |