QNam: only init channels when needed.

Each channel will create a socket that will allocate memory for the
read and write buffers. This change will instead initialize
channels only when they are needed.

Change-Id: I112b4c7b944a7dd345414f06260c92803394eaed
Reviewed-by: Shane Kearns <shane.kearns@accenture.com>
This commit is contained in:
Martin Petersson 2012-03-01 10:36:38 +01:00 committed by Qt by Nokia
parent 8be558e99d
commit c68737add3
3 changed files with 139 additions and 47 deletions

View File

@ -123,8 +123,8 @@ void QHttpNetworkConnectionPrivate::init()
//push session down to channels //push session down to channels
channels[i].networkSession = networkSession; channels[i].networkSession = networkSession;
#endif #endif
channels[i].init();
} }
delayedConnectionTimer.setSingleShot(true); delayedConnectionTimer.setSingleShot(true);
QObject::connect(&delayedConnectionTimer, SIGNAL(timeout()), q, SLOT(_q_connectDelayedChannel())); QObject::connect(&delayedConnectionTimer, SIGNAL(timeout()), q, SLOT(_q_connectDelayedChannel()));
} }
@ -135,12 +135,14 @@ void QHttpNetworkConnectionPrivate::pauseConnection()
// Disable all socket notifiers // Disable all socket notifiers
for (int i = 0; i < channelCount; i++) { for (int i = 0; i < channelCount; i++) {
if (channels[i].socket) {
#ifndef QT_NO_SSL #ifndef QT_NO_SSL
if (encrypt) if (encrypt)
QSslSocketPrivate::pauseSocketNotifiers(static_cast<QSslSocket*>(channels[i].socket)); QSslSocketPrivate::pauseSocketNotifiers(static_cast<QSslSocket*>(channels[i].socket));
else else
#endif #endif
QAbstractSocketPrivate::pauseSocketNotifiers(channels[i].socket); QAbstractSocketPrivate::pauseSocketNotifiers(channels[i].socket);
}
} }
} }
@ -149,16 +151,18 @@ void QHttpNetworkConnectionPrivate::resumeConnection()
state = RunningState; state = RunningState;
// Enable all socket notifiers // Enable all socket notifiers
for (int i = 0; i < channelCount; i++) { for (int i = 0; i < channelCount; i++) {
if (channels[i].socket) {
#ifndef QT_NO_SSL #ifndef QT_NO_SSL
if (encrypt) if (encrypt)
QSslSocketPrivate::resumeSocketNotifiers(static_cast<QSslSocket*>(channels[i].socket)); QSslSocketPrivate::resumeSocketNotifiers(static_cast<QSslSocket*>(channels[i].socket));
else else
#endif #endif
QAbstractSocketPrivate::resumeSocketNotifiers(channels[i].socket); QAbstractSocketPrivate::resumeSocketNotifiers(channels[i].socket);
// Resume pending upload if needed // Resume pending upload if needed
if (channels[i].state == QHttpNetworkConnectionChannel::WritingState) if (channels[i].state == QHttpNetworkConnectionChannel::WritingState)
QMetaObject::invokeMethod(&channels[i], "_q_uploadDataReadyRead", Qt::QueuedConnection); QMetaObject::invokeMethod(&channels[i], "_q_uploadDataReadyRead", Qt::QueuedConnection);
}
} }
// queue _q_startNextRequest // queue _q_startNextRequest
@ -346,11 +350,15 @@ void QHttpNetworkConnectionPrivate::emitReplyError(QAbstractSocket *socket,
QNetworkReply::NetworkError errorCode) QNetworkReply::NetworkError errorCode)
{ {
Q_Q(QHttpNetworkConnection); Q_Q(QHttpNetworkConnection);
if (socket && reply) {
int i = 0;
if (socket)
i = indexOf(socket);
if (reply) {
// this error matters only to this reply // this error matters only to this reply
reply->d_func()->errorString = errorDetail(errorCode, socket); reply->d_func()->errorString = errorDetail(errorCode, socket);
emit reply->finishedWithError(errorCode, reply->d_func()->errorString); emit reply->finishedWithError(errorCode, reply->d_func()->errorString);
int i = indexOf(socket);
// remove the corrupt data if any // remove the corrupt data if any
reply->d_func()->eraseData(); reply->d_func()->eraseData();
@ -358,7 +366,8 @@ void QHttpNetworkConnectionPrivate::emitReplyError(QAbstractSocket *socket,
channels[i].close(); channels[i].close();
channels[i].reply = 0; channels[i].reply = 0;
channels[i].request = QHttpNetworkRequest(); channels[i].request = QHttpNetworkRequest();
channels[i].requeueCurrentlyPipelinedRequests(); if (socket)
channels[i].requeueCurrentlyPipelinedRequests();
// send the next request // send the next request
QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection); QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection);
@ -582,9 +591,9 @@ void QHttpNetworkConnectionPrivate::requeueRequest(const HttpMessagePair &pair)
bool QHttpNetworkConnectionPrivate::dequeueRequest(QAbstractSocket *socket) bool QHttpNetworkConnectionPrivate::dequeueRequest(QAbstractSocket *socket)
{ {
Q_ASSERT(socket); int i = 0;
if (socket)
int i = indexOf(socket); i = indexOf(socket);
if (!highPriorityQueue.isEmpty()) { if (!highPriorityQueue.isEmpty()) {
// remove from queue before sendRequest! else we might pipeline the same request again // remove from queue before sendRequest! else we might pipeline the same request again
@ -740,15 +749,15 @@ bool QHttpNetworkConnectionPrivate::fillPipeline(QList<HttpMessagePair> &queue,
} }
QString QHttpNetworkConnectionPrivate::errorDetail(QNetworkReply::NetworkError errorCode, QAbstractSocket* socket, QString QHttpNetworkConnectionPrivate::errorDetail(QNetworkReply::NetworkError errorCode, QAbstractSocket *socket, const QString &extraDetail)
const QString &extraDetail)
{ {
Q_ASSERT(socket);
QString errorString; QString errorString;
switch (errorCode) { switch (errorCode) {
case QNetworkReply::HostNotFoundError: case QNetworkReply::HostNotFoundError:
errorString = QCoreApplication::translate("QHttp", "Host %1 not found").arg(socket->peerName()); if (socket)
errorString = QCoreApplication::translate("QHttp", "Host %1 not found").arg(socket->peerName());
else
errorString = QCoreApplication::translate("QHttp", "Host %1 not found").arg(hostName);
break; break;
case QNetworkReply::ConnectionRefusedError: case QNetworkReply::ConnectionRefusedError:
errorString = QCoreApplication::translate("QHttp", "Connection refused"); errorString = QCoreApplication::translate("QHttp", "Connection refused");
@ -891,9 +900,11 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
return; return;
// try to get a free AND connected socket // try to get a free AND connected socket
for (int i = 0; i < channelCount; ++i) { for (int i = 0; i < channelCount; ++i) {
if (!channels[i].reply && !channels[i].isSocketBusy() && channels[i].socket->state() == QAbstractSocket::ConnectedState) { if (channels[i].socket) {
if (dequeueRequest(channels[i].socket)) if (!channels[i].reply && !channels[i].isSocketBusy() && channels[i].socket->state() == QAbstractSocket::ConnectedState) {
channels[i].sendRequest(); if (dequeueRequest(channels[i].socket))
channels[i].sendRequest();
}
} }
} }
@ -908,7 +919,7 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
if (highPriorityQueue.isEmpty() && lowPriorityQueue.isEmpty()) if (highPriorityQueue.isEmpty() && lowPriorityQueue.isEmpty())
return; return;
for (int i = 0; i < channelCount; i++) for (int i = 0; i < channelCount; i++)
if (channels[i].socket->state() == QAbstractSocket::ConnectedState) if (channels[i].socket && channels[i].socket->state() == QAbstractSocket::ConnectedState)
fillPipeline(channels[i].socket); fillPipeline(channels[i].socket);
// If there is not already any connected channels we need to connect a new one. // If there is not already any connected channels we need to connect a new one.
@ -916,11 +927,19 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
// connected or not. This is to reuse connected channels before we connect new once. // connected or not. This is to reuse connected channels before we connect new once.
int queuedRequest = highPriorityQueue.count() + lowPriorityQueue.count(); int queuedRequest = highPriorityQueue.count() + lowPriorityQueue.count();
for (int i = 0; i < channelCount; ++i) { for (int i = 0; i < channelCount; ++i) {
if ((channels[i].socket->state() == QAbstractSocket::ConnectingState) || (channels[i].socket->state() == QAbstractSocket::HostLookupState)) bool connectChannel = false;
queuedRequest--; if (channels[i].socket) {
if ( queuedRequest <=0 ) if ((channels[i].socket->state() == QAbstractSocket::ConnectingState) || (channels[i].socket->state() == QAbstractSocket::HostLookupState))
break; queuedRequest--;
if (!channels[i].reply && !channels[i].isSocketBusy() && (channels[i].socket->state() == QAbstractSocket::UnconnectedState)) { if ( queuedRequest <=0 )
break;
if (!channels[i].reply && !channels[i].isSocketBusy() && (channels[i].socket->state() == QAbstractSocket::UnconnectedState))
connectChannel = true;
} else { // not previously used channel
connectChannel = true;
}
if (connectChannel) {
if (networkLayerState == IPv4) if (networkLayerState == IPv4)
channels[i].networkLayerPreference = QAbstractSocket::IPv4Protocol; channels[i].networkLayerPreference = QAbstractSocket::IPv4Protocol;
else if (networkLayerState == IPv6) else if (networkLayerState == IPv6)
@ -928,6 +947,9 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
channels[i].ensureConnection(); channels[i].ensureConnection();
queuedRequest--; queuedRequest--;
} }
if ( queuedRequest <=0 )
break;
} }
} }
@ -958,8 +980,8 @@ void QHttpNetworkConnectionPrivate::startHostInfoLookup()
#ifndef QT_NO_NETWORKPROXY #ifndef QT_NO_NETWORKPROXY
if (networkProxy.capabilities() & QNetworkProxy::HostNameLookupCapability) { if (networkProxy.capabilities() & QNetworkProxy::HostNameLookupCapability) {
lookupHost = networkProxy.hostName(); lookupHost = networkProxy.hostName();
} else if (channels[0].socket->proxy().capabilities() & QNetworkProxy::HostNameLookupCapability) { } else if (channels[0].proxy.capabilities() & QNetworkProxy::HostNameLookupCapability) {
lookupHost = channels[0].socket->proxy().hostName(); lookupHost = channels[0].proxy.hostName();
} }
#endif #endif
QHostAddress temp; QHostAddress temp;
@ -1169,13 +1191,13 @@ void QHttpNetworkConnection::setTransparentProxy(const QNetworkProxy &networkPro
{ {
Q_D(QHttpNetworkConnection); Q_D(QHttpNetworkConnection);
for (int i = 0; i < d->channelCount; ++i) for (int i = 0; i < d->channelCount; ++i)
d->channels[i].socket->setProxy(networkProxy); d->channels[i].setProxy(networkProxy);
} }
QNetworkProxy QHttpNetworkConnection::transparentProxy() const QNetworkProxy QHttpNetworkConnection::transparentProxy() const
{ {
Q_D(const QHttpNetworkConnection); Q_D(const QHttpNetworkConnection);
return d->channels[0].socket->proxy(); return d->channels[0].proxy;
} }
#endif #endif
@ -1190,7 +1212,7 @@ void QHttpNetworkConnection::setSslConfiguration(const QSslConfiguration &config
// set the config on all channels // set the config on all channels
for (int i = 0; i < d->channelCount; ++i) for (int i = 0; i < d->channelCount; ++i)
static_cast<QSslSocket *>(d->channels[i].socket)->setSslConfiguration(config); d->channels[i].setSslConfiguration(config);
} }
void QHttpNetworkConnection::ignoreSslErrors(int channel) void QHttpNetworkConnection::ignoreSslErrors(int channel)
@ -1201,13 +1223,11 @@ void QHttpNetworkConnection::ignoreSslErrors(int channel)
if (channel == -1) { // ignore for all channels if (channel == -1) { // ignore for all channels
for (int i = 0; i < d->channelCount; ++i) { for (int i = 0; i < d->channelCount; ++i) {
static_cast<QSslSocket *>(d->channels[i].socket)->ignoreSslErrors(); d->channels[i].ignoreSslErrors();
d->channels[i].ignoreAllSslErrors = true;
} }
} else { } else {
static_cast<QSslSocket *>(d->channels[channel].socket)->ignoreSslErrors(); d->channels[channel].ignoreSslErrors();
d->channels[channel].ignoreAllSslErrors = true;
} }
} }
@ -1219,13 +1239,11 @@ void QHttpNetworkConnection::ignoreSslErrors(const QList<QSslError> &errors, int
if (channel == -1) { // ignore for all channels if (channel == -1) { // ignore for all channels
for (int i = 0; i < d->channelCount; ++i) { for (int i = 0; i < d->channelCount; ++i) {
static_cast<QSslSocket *>(d->channels[i].socket)->ignoreSslErrors(errors); d->channels[i].ignoreSslErrors(errors);
d->channels[i].ignoreSslErrorsList = errors;
} }
} else { } else {
static_cast<QSslSocket *>(d->channels[channel].socket)->ignoreSslErrors(errors); d->channels[channel].ignoreSslErrors(errors);
d->channels[channel].ignoreSslErrorsList = errors;
} }
} }

View File

@ -65,6 +65,7 @@ QT_BEGIN_NAMESPACE
QHttpNetworkConnectionChannel::QHttpNetworkConnectionChannel() QHttpNetworkConnectionChannel::QHttpNetworkConnectionChannel()
: socket(0) : socket(0)
, ssl(false) , ssl(false)
, isInitialized(false)
, state(IdleState) , state(IdleState)
, reply(0) , reply(0)
, written(0) , written(0)
@ -152,19 +153,38 @@ void QHttpNetworkConnectionChannel::init()
QObject::connect(sslSocket, SIGNAL(encryptedBytesWritten(qint64)), QObject::connect(sslSocket, SIGNAL(encryptedBytesWritten(qint64)),
this, SLOT(_q_encryptedBytesWritten(qint64)), this, SLOT(_q_encryptedBytesWritten(qint64)),
Qt::DirectConnection); Qt::DirectConnection);
if (ignoreAllSslErrors)
sslSocket->ignoreSslErrors();
if (!ignoreSslErrorsList.isEmpty())
sslSocket->ignoreSslErrors(ignoreSslErrorsList);
if (!sslConfiguration.isNull())
sslSocket->setSslConfiguration(sslConfiguration);
} }
#endif #endif
#ifndef QT_NO_NETWORKPROXY
if (proxy.type() != QNetworkProxy::NoProxy)
socket->setProxy(proxy);
#endif
isInitialized = true;
} }
void QHttpNetworkConnectionChannel::close() void QHttpNetworkConnectionChannel::close()
{ {
if (socket->state() == QAbstractSocket::UnconnectedState) if (!socket)
state = QHttpNetworkConnectionChannel::IdleState;
else if (socket->state() == QAbstractSocket::UnconnectedState)
state = QHttpNetworkConnectionChannel::IdleState; state = QHttpNetworkConnectionChannel::IdleState;
else else
state = QHttpNetworkConnectionChannel::ClosingState; state = QHttpNetworkConnectionChannel::ClosingState;
socket->close(); if (socket)
socket->close();
} }
@ -527,6 +547,9 @@ void QHttpNetworkConnectionChannel::handleUnexpectedEOF()
bool QHttpNetworkConnectionChannel::ensureConnection() bool QHttpNetworkConnectionChannel::ensureConnection()
{ {
if (!isInitialized)
init();
QAbstractSocket::SocketState socketState = socket->state(); QAbstractSocket::SocketState socketState = socket->state();
// resend this request after we receive the disconnected signal // resend this request after we receive the disconnected signal
@ -835,6 +858,46 @@ bool QHttpNetworkConnectionChannel::resetUploadData()
} }
} }
#ifndef QT_NO_NETWORKPROXY
void QHttpNetworkConnectionChannel::setProxy(const QNetworkProxy &networkProxy)
{
if (socket)
socket->setProxy(networkProxy);
proxy = networkProxy;
}
#endif
#ifndef QT_NO_SSL
void QHttpNetworkConnectionChannel::ignoreSslErrors()
{
if (socket)
static_cast<QSslSocket *>(socket)->ignoreSslErrors();
ignoreAllSslErrors = true;
}
void QHttpNetworkConnectionChannel::ignoreSslErrors(const QList<QSslError> &errors)
{
if (socket)
static_cast<QSslSocket *>(socket)->ignoreSslErrors(errors);
ignoreSslErrorsList = errors;
}
void QHttpNetworkConnectionChannel::setSslConfiguration(const QSslConfiguration &config)
{
if (socket)
static_cast<QSslSocket *>(socket)->setSslConfiguration(config);
sslConfiguration = config;
}
#endif
void QHttpNetworkConnectionChannel::pipelineInto(HttpMessagePair &pair) void QHttpNetworkConnectionChannel::pipelineInto(HttpMessagePair &pair)
{ {

View File

@ -72,6 +72,7 @@
#ifndef QT_NO_SSL #ifndef QT_NO_SSL
# include <QtNetwork/qsslsocket.h> # include <QtNetwork/qsslsocket.h>
# include <QtNetwork/qsslerror.h> # include <QtNetwork/qsslerror.h>
# include <QtNetwork/qsslconfiguration.h>
#else #else
# include <QtNetwork/qtcpsocket.h> # include <QtNetwork/qtcpsocket.h>
#endif #endif
@ -100,6 +101,7 @@ public:
}; };
QAbstractSocket *socket; QAbstractSocket *socket;
bool ssl; bool ssl;
bool isInitialized;
ChannelState state; ChannelState state;
QHttpNetworkRequest request; // current request QHttpNetworkRequest request; // current request
QHttpNetworkReply *reply; // current reply for this request QHttpNetworkReply *reply; // current reply for this request
@ -118,6 +120,10 @@ public:
#ifndef QT_NO_SSL #ifndef QT_NO_SSL
bool ignoreAllSslErrors; bool ignoreAllSslErrors;
QList<QSslError> ignoreSslErrorsList; QList<QSslError> ignoreSslErrorsList;
QSslConfiguration sslConfiguration;
void ignoreSslErrors();
void ignoreSslErrors(const QList<QSslError> &errors);
void setSslConfiguration(const QSslConfiguration &config);
#endif #endif
#ifndef QT_NO_BEARERMANAGEMENT #ifndef QT_NO_BEARERMANAGEMENT
QSharedPointer<QNetworkSession> networkSession; QSharedPointer<QNetworkSession> networkSession;
@ -144,6 +150,11 @@ public:
void setConnection(QHttpNetworkConnection *c); void setConnection(QHttpNetworkConnection *c);
QPointer<QHttpNetworkConnection> connection; QPointer<QHttpNetworkConnection> connection;
#ifndef QT_NO_NETWORKPROXY
QNetworkProxy proxy;
void setProxy(const QNetworkProxy &networkProxy);
#endif
void init(); void init();
void close(); void close();