Http connection( channel)?: support local socket
Task-number: QTBUG-102855 Change-Id: Idcf571498b7a18792cf7843a826d78672e264a73 Reviewed-by: Mate Barany <mate.barany@qt.io> Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
This commit is contained in:
parent
c9a1e8d306
commit
956795bda8
@ -102,13 +102,18 @@ void QHttpNetworkConnectionPrivate::pauseConnection()
|
|||||||
|
|
||||||
// Disable all socket notifiers
|
// Disable all socket notifiers
|
||||||
for (int i = 0; i < activeChannelCount; i++) {
|
for (int i = 0; i < activeChannelCount; i++) {
|
||||||
if (channels[i].socket) {
|
if (auto *absSocket = qobject_cast<QAbstractSocket *>(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*>(absSocket));
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
QAbstractSocketPrivate::pauseSocketNotifiers(channels[i].socket);
|
QAbstractSocketPrivate::pauseSocketNotifiers(absSocket);
|
||||||
|
} else if (qobject_cast<QLocalSocket *>(channels[i].socket)) {
|
||||||
|
// @todo how would we do this?
|
||||||
|
#if 0 // @todo Enable this when there is a debug category for this
|
||||||
|
qDebug() << "Should pause socket but there is no way to do it for local sockets";
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -118,17 +123,21 @@ void QHttpNetworkConnectionPrivate::resumeConnection()
|
|||||||
state = RunningState;
|
state = RunningState;
|
||||||
// Enable all socket notifiers
|
// Enable all socket notifiers
|
||||||
for (int i = 0; i < activeChannelCount; i++) {
|
for (int i = 0; i < activeChannelCount; i++) {
|
||||||
if (channels[i].socket) {
|
if (auto *absSocket = qobject_cast<QAbstractSocket *>(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*>(absSocket));
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
QAbstractSocketPrivate::resumeSocketNotifiers(channels[i].socket);
|
QAbstractSocketPrivate::resumeSocketNotifiers(absSocket);
|
||||||
|
|
||||||
// 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);
|
||||||
|
} else if (qobject_cast<QLocalSocket *>(channels[i].socket)) {
|
||||||
|
#if 0 // @todo Enable this when there is a debug category for this
|
||||||
|
qDebug() << "Should resume socket but there is no way to do it for local sockets";
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1024,7 +1033,7 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
|
|||||||
for (int i = 0; i < activeChannelCount; ++i) {
|
for (int i = 0; i < activeChannelCount; ++i) {
|
||||||
if (channels[i].resendCurrent && (channels[i].state != QHttpNetworkConnectionChannel::ClosingState)) {
|
if (channels[i].resendCurrent && (channels[i].state != QHttpNetworkConnectionChannel::ClosingState)) {
|
||||||
if (!channels[i].socket
|
if (!channels[i].socket
|
||||||
|| channels[i].socket->state() == QAbstractSocket::UnconnectedState) {
|
|| QSocketAbstraction::socketState(channels[i].socket) == QAbstractSocket::UnconnectedState) {
|
||||||
if (!channels[i].ensureConnection())
|
if (!channels[i].ensureConnection())
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -1048,7 +1057,9 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
|
|||||||
// try to get a free AND connected socket
|
// try to get a free AND connected socket
|
||||||
for (int i = 0; i < activeChannelCount; ++i) {
|
for (int i = 0; i < activeChannelCount; ++i) {
|
||||||
if (channels[i].socket) {
|
if (channels[i].socket) {
|
||||||
if (!channels[i].reply && !channels[i].isSocketBusy() && channels[i].socket->state() == QAbstractSocket::ConnectedState) {
|
if (!channels[i].reply && !channels[i].isSocketBusy()
|
||||||
|
&& QSocketAbstraction::socketState(channels[i].socket)
|
||||||
|
== QAbstractSocket::ConnectedState) {
|
||||||
if (dequeueRequest(channels[i].socket))
|
if (dequeueRequest(channels[i].socket))
|
||||||
channels[i].sendRequest();
|
channels[i].sendRequest();
|
||||||
}
|
}
|
||||||
@ -1068,7 +1079,8 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
|
|||||||
else if (networkLayerState == IPv6)
|
else if (networkLayerState == IPv6)
|
||||||
channels[0].networkLayerPreference = QAbstractSocket::IPv6Protocol;
|
channels[0].networkLayerPreference = QAbstractSocket::IPv6Protocol;
|
||||||
channels[0].ensureConnection();
|
channels[0].ensureConnection();
|
||||||
if (channels[0].socket && channels[0].socket->state() == QAbstractSocket::ConnectedState
|
if (auto *s = channels[0].socket; s
|
||||||
|
&& QSocketAbstraction::socketState(s) == QAbstractSocket::ConnectedState
|
||||||
&& !channels[0].pendingEncrypt) {
|
&& !channels[0].pendingEncrypt) {
|
||||||
if (channels[0].h2RequestsToSend.size()) {
|
if (channels[0].h2RequestsToSend.size()) {
|
||||||
channels[0].sendRequest();
|
channels[0].sendRequest();
|
||||||
@ -1095,9 +1107,13 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
|
|||||||
// return fast if there is nothing to pipeline
|
// return fast if there is nothing to pipeline
|
||||||
if (highPriorityQueue.isEmpty() && lowPriorityQueue.isEmpty())
|
if (highPriorityQueue.isEmpty() && lowPriorityQueue.isEmpty())
|
||||||
return;
|
return;
|
||||||
for (int i = 0; i < activeChannelCount; i++)
|
for (int i = 0; i < activeChannelCount; i++) {
|
||||||
if (channels[i].socket && channels[i].socket->state() == QAbstractSocket::ConnectedState)
|
if (channels[i].socket
|
||||||
|
&& QSocketAbstraction::socketState(channels[i].socket)
|
||||||
|
== 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.
|
||||||
// We do not pair the channel with the request until we know if it is
|
// We do not pair the channel with the request until we know if it is
|
||||||
@ -1122,15 +1138,16 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
|
|||||||
if (!channels[i].socket)
|
if (!channels[i].socket)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if ((channels[i].socket->state() == QAbstractSocket::ConnectingState)
|
using State = QAbstractSocket::SocketState;
|
||||||
|| (channels[i].socket->state() == QAbstractSocket::HostLookupState)
|
if ((QSocketAbstraction::socketState(channels[i].socket) == State::ConnectingState)
|
||||||
|
|| (QSocketAbstraction::socketState(channels[i].socket) == State::HostLookupState)
|
||||||
|| channels[i].pendingEncrypt) { // pendingEncrypt == "EncryptingState"
|
|| channels[i].pendingEncrypt) { // pendingEncrypt == "EncryptingState"
|
||||||
neededOpenChannels--;
|
neededOpenChannels--;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!channels[i].reply && !channels[i].isSocketBusy()
|
if (!channels[i].reply && !channels[i].isSocketBusy()
|
||||||
&& (channels[i].socket->state() == QAbstractSocket::UnconnectedState)) {
|
&& (QSocketAbstraction::socketState(channels[i].socket) == State::UnconnectedState)) {
|
||||||
channelsToConnect.push_back(i);
|
channelsToConnect.push_back(i);
|
||||||
neededOpenChannels--;
|
neededOpenChannels--;
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include <private/qhttp2protocolhandler_p.h>
|
#include <private/qhttp2protocolhandler_p.h>
|
||||||
#include <private/qhttpprotocolhandler_p.h>
|
#include <private/qhttpprotocolhandler_p.h>
|
||||||
#include <private/http2protocol_p.h>
|
#include <private/http2protocol_p.h>
|
||||||
|
#include <private/qsocketabstraction_p.h>
|
||||||
|
|
||||||
#ifndef QT_NO_SSL
|
#ifndef QT_NO_SSL
|
||||||
# include <private/qsslsocket_p.h>
|
# include <private/qsslsocket_p.h>
|
||||||
@ -85,7 +86,8 @@ void QHttpNetworkConnectionChannel::init()
|
|||||||
#endif
|
#endif
|
||||||
#ifndef QT_NO_NETWORKPROXY
|
#ifndef QT_NO_NETWORKPROXY
|
||||||
// Set by QNAM anyway, but let's be safe here
|
// Set by QNAM anyway, but let's be safe here
|
||||||
socket->setProxy(QNetworkProxy::NoProxy);
|
if (auto s = qobject_cast<QAbstractSocket *>(socket))
|
||||||
|
s->setProxy(QNetworkProxy::NoProxy);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// After some back and forth in all the last years, this is now a DirectConnection because otherwise
|
// After some back and forth in all the last years, this is now a DirectConnection because otherwise
|
||||||
@ -94,32 +96,48 @@ void QHttpNetworkConnectionChannel::init()
|
|||||||
QObject::connect(socket, &QIODevice::bytesWritten,
|
QObject::connect(socket, &QIODevice::bytesWritten,
|
||||||
this, &QHttpNetworkConnectionChannel::_q_bytesWritten,
|
this, &QHttpNetworkConnectionChannel::_q_bytesWritten,
|
||||||
Qt::DirectConnection);
|
Qt::DirectConnection);
|
||||||
QObject::connect(socket, &QAbstractSocket::connected,
|
|
||||||
this, &QHttpNetworkConnectionChannel::_q_connected,
|
|
||||||
Qt::DirectConnection);
|
|
||||||
QObject::connect(socket, &QIODevice::readyRead,
|
QObject::connect(socket, &QIODevice::readyRead,
|
||||||
this, &QHttpNetworkConnectionChannel::_q_readyRead,
|
this, &QHttpNetworkConnectionChannel::_q_readyRead,
|
||||||
Qt::DirectConnection);
|
Qt::DirectConnection);
|
||||||
|
|
||||||
// The disconnected() and error() signals may already come
|
|
||||||
// while calling connectToHost().
|
QSocketAbstraction::visit([this](auto *socket){
|
||||||
// In case of a cached hostname or an IP this
|
using SocketType = std::remove_pointer_t<decltype(socket)>;
|
||||||
// will then emit a signal to the user of QNetworkReply
|
QObject::connect(socket, &SocketType::connected,
|
||||||
// but cannot be caught because the user did not have a chance yet
|
this, &QHttpNetworkConnectionChannel::_q_connected,
|
||||||
// to connect to QNetworkReply's signals.
|
Qt::DirectConnection);
|
||||||
qRegisterMetaType<QAbstractSocket::SocketError>();
|
|
||||||
QObject::connect(socket, &QAbstractSocket::disconnected,
|
// The disconnected() and error() signals may already come
|
||||||
this, &QHttpNetworkConnectionChannel::_q_disconnected,
|
// while calling connectToHost().
|
||||||
Qt::DirectConnection);
|
// In case of a cached hostname or an IP this
|
||||||
QObject::connect(socket, &QAbstractSocket::errorOccurred,
|
// will then emit a signal to the user of QNetworkReply
|
||||||
this, &QHttpNetworkConnectionChannel::_q_error,
|
// but cannot be caught because the user did not have a chance yet
|
||||||
Qt::DirectConnection);
|
// to connect to QNetworkReply's signals.
|
||||||
|
QObject::connect(socket, &SocketType::disconnected,
|
||||||
|
this, &QHttpNetworkConnectionChannel::_q_disconnected,
|
||||||
|
Qt::DirectConnection);
|
||||||
|
if constexpr (std::is_same_v<SocketType, QAbstractSocket>) {
|
||||||
|
QObject::connect(socket, &QAbstractSocket::errorOccurred,
|
||||||
|
this, &QHttpNetworkConnectionChannel::_q_error,
|
||||||
|
Qt::DirectConnection);
|
||||||
|
} else if constexpr (std::is_same_v<SocketType, QLocalSocket>) {
|
||||||
|
auto convertAndForward = [this](QLocalSocket::LocalSocketError error) {
|
||||||
|
_q_error(static_cast<QAbstractSocket::SocketError>(error));
|
||||||
|
};
|
||||||
|
QObject::connect(socket, &SocketType::errorOccurred,
|
||||||
|
this, std::move(convertAndForward),
|
||||||
|
Qt::DirectConnection);
|
||||||
|
}
|
||||||
|
}, socket);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef QT_NO_NETWORKPROXY
|
#ifndef QT_NO_NETWORKPROXY
|
||||||
QObject::connect(socket, &QAbstractSocket::proxyAuthenticationRequired,
|
if (auto *s = qobject_cast<QAbstractSocket *>(socket)) {
|
||||||
this, &QHttpNetworkConnectionChannel::_q_proxyAuthenticationRequired,
|
QObject::connect(s, &QAbstractSocket::proxyAuthenticationRequired,
|
||||||
Qt::DirectConnection);
|
this, &QHttpNetworkConnectionChannel::_q_proxyAuthenticationRequired,
|
||||||
|
Qt::DirectConnection);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef QT_NO_SSL
|
#ifndef QT_NO_SSL
|
||||||
@ -156,8 +174,10 @@ void QHttpNetworkConnectionChannel::init()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef QT_NO_NETWORKPROXY
|
#ifndef QT_NO_NETWORKPROXY
|
||||||
if (proxy.type() != QNetworkProxy::NoProxy)
|
if (auto *s = qobject_cast<QAbstractSocket *>(socket);
|
||||||
socket->setProxy(proxy);
|
s && proxy.type() != QNetworkProxy::NoProxy) {
|
||||||
|
s->setProxy(proxy);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
isInitialized = true;
|
isInitialized = true;
|
||||||
}
|
}
|
||||||
@ -170,7 +190,7 @@ void QHttpNetworkConnectionChannel::close()
|
|||||||
|
|
||||||
if (!socket)
|
if (!socket)
|
||||||
state = QHttpNetworkConnectionChannel::IdleState;
|
state = QHttpNetworkConnectionChannel::IdleState;
|
||||||
else if (socket->state() == QAbstractSocket::UnconnectedState)
|
else if (QSocketAbstraction::socketState(socket) == QAbstractSocket::UnconnectedState)
|
||||||
state = QHttpNetworkConnectionChannel::IdleState;
|
state = QHttpNetworkConnectionChannel::IdleState;
|
||||||
else
|
else
|
||||||
state = QHttpNetworkConnectionChannel::ClosingState;
|
state = QHttpNetworkConnectionChannel::ClosingState;
|
||||||
@ -190,7 +210,7 @@ void QHttpNetworkConnectionChannel::abort()
|
|||||||
{
|
{
|
||||||
if (!socket)
|
if (!socket)
|
||||||
state = QHttpNetworkConnectionChannel::IdleState;
|
state = QHttpNetworkConnectionChannel::IdleState;
|
||||||
else if (socket->state() == QAbstractSocket::UnconnectedState)
|
else if (QSocketAbstraction::socketState(socket) == QAbstractSocket::UnconnectedState)
|
||||||
state = QHttpNetworkConnectionChannel::IdleState;
|
state = QHttpNetworkConnectionChannel::IdleState;
|
||||||
else
|
else
|
||||||
state = QHttpNetworkConnectionChannel::ClosingState;
|
state = QHttpNetworkConnectionChannel::ClosingState;
|
||||||
@ -201,7 +221,10 @@ void QHttpNetworkConnectionChannel::abort()
|
|||||||
if (socket) {
|
if (socket) {
|
||||||
// socket can be 0 since the host lookup is done from qhttpnetworkconnection.cpp while
|
// socket can be 0 since the host lookup is done from qhttpnetworkconnection.cpp while
|
||||||
// there is no socket yet.
|
// there is no socket yet.
|
||||||
socket->abort();
|
auto callAbort = [](auto *s) {
|
||||||
|
s->abort();
|
||||||
|
};
|
||||||
|
QSocketAbstraction::visit(callAbort, socket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,7 +291,7 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
|
|||||||
if (!isInitialized)
|
if (!isInitialized)
|
||||||
init();
|
init();
|
||||||
|
|
||||||
QAbstractSocket::SocketState socketState = socket->state();
|
QAbstractSocket::SocketState socketState = QSocketAbstraction::socketState(socket);
|
||||||
|
|
||||||
// resend this request after we receive the disconnected signal
|
// resend this request after we receive the disconnected signal
|
||||||
// If !socket->isOpen() then we have already called close() on the socket, but there was still a
|
// If !socket->isOpen() then we have already called close() on the socket, but there was still a
|
||||||
@ -335,7 +358,8 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
|
|||||||
connectHost = connection->d_func()->networkProxy.hostName();
|
connectHost = connection->d_func()->networkProxy.hostName();
|
||||||
connectPort = connection->d_func()->networkProxy.port();
|
connectPort = connection->d_func()->networkProxy.port();
|
||||||
}
|
}
|
||||||
if (socket->proxy().type() == QNetworkProxy::HttpProxy) {
|
if (auto *abSocket = qobject_cast<QAbstractSocket *>(socket);
|
||||||
|
abSocket && abSocket->proxy().type() == QNetworkProxy::HttpProxy) {
|
||||||
// Make user-agent field available to HTTP proxy socket engine (QTBUG-17223)
|
// Make user-agent field available to HTTP proxy socket engine (QTBUG-17223)
|
||||||
QByteArray value;
|
QByteArray value;
|
||||||
// ensureConnection is called before any request has been assigned, but can also be
|
// ensureConnection is called before any request has been assigned, but can also be
|
||||||
@ -353,11 +377,11 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
|
|||||||
value = request.headerField("user-agent");
|
value = request.headerField("user-agent");
|
||||||
}
|
}
|
||||||
if (!value.isEmpty()) {
|
if (!value.isEmpty()) {
|
||||||
QNetworkProxy proxy(socket->proxy());
|
QNetworkProxy proxy(abSocket->proxy());
|
||||||
auto h = proxy.headers();
|
auto h = proxy.headers();
|
||||||
h.replaceOrAppend(QHttpHeaders::WellKnownHeader::UserAgent, value);
|
h.replaceOrAppend(QHttpHeaders::WellKnownHeader::UserAgent, value);
|
||||||
proxy.setHeaders(std::move(h));
|
proxy.setHeaders(std::move(h));
|
||||||
socket->setProxy(proxy);
|
abSocket->setProxy(proxy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -380,7 +404,7 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
|
|||||||
// limit the socket read buffer size. we will read everything into
|
// limit the socket read buffer size. we will read everything into
|
||||||
// the QHttpNetworkReply anyway, so let's grow only that and not
|
// the QHttpNetworkReply anyway, so let's grow only that and not
|
||||||
// here and there.
|
// here and there.
|
||||||
socket->setReadBufferSize(64*1024);
|
sslSocket->setReadBufferSize(64*1024);
|
||||||
#else
|
#else
|
||||||
// Need to dequeue the request so that we can emit the error.
|
// Need to dequeue the request so that we can emit the error.
|
||||||
if (!reply)
|
if (!reply)
|
||||||
@ -394,17 +418,24 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
|
|||||||
&& connection->cacheProxy().type() == QNetworkProxy::NoProxy
|
&& connection->cacheProxy().type() == QNetworkProxy::NoProxy
|
||||||
&& connection->transparentProxy().type() == QNetworkProxy::NoProxy) {
|
&& connection->transparentProxy().type() == QNetworkProxy::NoProxy) {
|
||||||
#endif
|
#endif
|
||||||
socket->connectToHost(connectHost, connectPort, QIODevice::ReadWrite | QIODevice::Unbuffered, networkLayerPreference);
|
if (auto *s = qobject_cast<QAbstractSocket *>(socket)) {
|
||||||
// For an Unbuffered QTcpSocket, the read buffer size has a special meaning.
|
s->connectToHost(connectHost, connectPort,
|
||||||
socket->setReadBufferSize(1*1024);
|
QIODevice::ReadWrite | QIODevice::Unbuffered,
|
||||||
|
networkLayerPreference);
|
||||||
|
// For an Unbuffered QTcpSocket, the read buffer size has a special meaning.
|
||||||
|
s->setReadBufferSize(1 * 1024);
|
||||||
|
} else if (auto *s = qobject_cast<QLocalSocket *>(socket)) {
|
||||||
|
s->connectToServer(connectHost);
|
||||||
|
}
|
||||||
#ifndef QT_NO_NETWORKPROXY
|
#ifndef QT_NO_NETWORKPROXY
|
||||||
} else {
|
} else {
|
||||||
socket->connectToHost(connectHost, connectPort, QIODevice::ReadWrite, networkLayerPreference);
|
auto *s = qobject_cast<QAbstractSocket *>(socket);
|
||||||
|
Q_ASSERT(s);
|
||||||
// limit the socket read buffer size. we will read everything into
|
// limit the socket read buffer size. we will read everything into
|
||||||
// the QHttpNetworkReply anyway, so let's grow only that and not
|
// the QHttpNetworkReply anyway, so let's grow only that and not
|
||||||
// here and there.
|
// here and there.
|
||||||
socket->setReadBufferSize(64*1024);
|
s->connectToHost(connectHost, connectPort, QIODevice::ReadWrite, networkLayerPreference);
|
||||||
|
s->setReadBufferSize(64 * 1024);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -507,7 +538,7 @@ void QHttpNetworkConnectionChannel::allDone()
|
|||||||
|
|
||||||
// move next from pipeline to current request
|
// move next from pipeline to current request
|
||||||
if (!alreadyPipelinedRequests.isEmpty()) {
|
if (!alreadyPipelinedRequests.isEmpty()) {
|
||||||
if (resendCurrent || connectionCloseEnabled || socket->state() != QAbstractSocket::ConnectedState) {
|
if (resendCurrent || connectionCloseEnabled || QSocketAbstraction::socketState(socket) != QAbstractSocket::ConnectedState) {
|
||||||
// move the pipelined ones back to the main queue
|
// move the pipelined ones back to the main queue
|
||||||
requeueCurrentlyPipelinedRequests();
|
requeueCurrentlyPipelinedRequests();
|
||||||
close();
|
close();
|
||||||
@ -538,7 +569,7 @@ void QHttpNetworkConnectionChannel::allDone()
|
|||||||
QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
|
||||||
} else if (alreadyPipelinedRequests.isEmpty()) {
|
} else if (alreadyPipelinedRequests.isEmpty()) {
|
||||||
if (connectionCloseEnabled)
|
if (connectionCloseEnabled)
|
||||||
if (socket->state() != QAbstractSocket::UnconnectedState)
|
if (QSocketAbstraction::socketState(socket) != QAbstractSocket::UnconnectedState)
|
||||||
close();
|
close();
|
||||||
if (qobject_cast<QHttpNetworkConnection*>(connection))
|
if (qobject_cast<QHttpNetworkConnection*>(connection))
|
||||||
QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
|
||||||
@ -556,7 +587,7 @@ void QHttpNetworkConnectionChannel::detectPipeliningSupport()
|
|||||||
// check for not having connection close
|
// check for not having connection close
|
||||||
&& (!reply->d_func()->isConnectionCloseEnabled())
|
&& (!reply->d_func()->isConnectionCloseEnabled())
|
||||||
// check if it is still connected
|
// check if it is still connected
|
||||||
&& (socket->state() == QAbstractSocket::ConnectedState)
|
&& (QSocketAbstraction::socketState(socket) == QAbstractSocket::ConnectedState)
|
||||||
// check for broken servers in server reply header
|
// check for broken servers in server reply header
|
||||||
// this is adapted from http://mxr.mozilla.org/firefox/ident?i=SupportsPipelining
|
// this is adapted from http://mxr.mozilla.org/firefox/ident?i=SupportsPipelining
|
||||||
&& (serverHeaderField = reply->headerField("Server"), !serverHeaderField.contains("Microsoft-IIS/4."))
|
&& (serverHeaderField = reply->headerField("Server"), !serverHeaderField.contains("Microsoft-IIS/4."))
|
||||||
@ -679,8 +710,8 @@ bool QHttpNetworkConnectionChannel::resetUploadData()
|
|||||||
|
|
||||||
void QHttpNetworkConnectionChannel::setProxy(const QNetworkProxy &networkProxy)
|
void QHttpNetworkConnectionChannel::setProxy(const QNetworkProxy &networkProxy)
|
||||||
{
|
{
|
||||||
if (socket)
|
if (auto *s = qobject_cast<QAbstractSocket *>(socket))
|
||||||
socket->setProxy(networkProxy);
|
s->setProxy(networkProxy);
|
||||||
|
|
||||||
proxy = networkProxy;
|
proxy = networkProxy;
|
||||||
}
|
}
|
||||||
@ -841,7 +872,7 @@ void QHttpNetworkConnectionChannel::_q_disconnected()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void QHttpNetworkConnectionChannel::_q_connected()
|
void QHttpNetworkConnectionChannel::_q_connected_abstract_socket(QAbstractSocket *absSocket)
|
||||||
{
|
{
|
||||||
// For the Happy Eyeballs we need to check if this is the first channel to connect.
|
// For the Happy Eyeballs we need to check if this is the first channel to connect.
|
||||||
if (connection->d_func()->networkLayerState == QHttpNetworkConnectionPrivate::HostLookupPending || connection->d_func()->networkLayerState == QHttpNetworkConnectionPrivate::IPv4or6) {
|
if (connection->d_func()->networkLayerState == QHttpNetworkConnectionPrivate::HostLookupPending || connection->d_func()->networkLayerState == QHttpNetworkConnectionPrivate::IPv4or6) {
|
||||||
@ -852,7 +883,7 @@ void QHttpNetworkConnectionChannel::_q_connected()
|
|||||||
else if (networkLayerPreference == QAbstractSocket::IPv6Protocol)
|
else if (networkLayerPreference == QAbstractSocket::IPv6Protocol)
|
||||||
connection->d_func()->networkLayerState = QHttpNetworkConnectionPrivate::IPv6;
|
connection->d_func()->networkLayerState = QHttpNetworkConnectionPrivate::IPv6;
|
||||||
else {
|
else {
|
||||||
if (socket->peerAddress().protocol() == QAbstractSocket::IPv4Protocol)
|
if (absSocket->peerAddress().protocol() == QAbstractSocket::IPv4Protocol)
|
||||||
connection->d_func()->networkLayerState = QHttpNetworkConnectionPrivate::IPv4;
|
connection->d_func()->networkLayerState = QHttpNetworkConnectionPrivate::IPv4;
|
||||||
else
|
else
|
||||||
connection->d_func()->networkLayerState = QHttpNetworkConnectionPrivate::IPv6;
|
connection->d_func()->networkLayerState = QHttpNetworkConnectionPrivate::IPv6;
|
||||||
@ -875,7 +906,7 @@ void QHttpNetworkConnectionChannel::_q_connected()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// improve performance since we get the request sent by the kernel ASAP
|
// improve performance since we get the request sent by the kernel ASAP
|
||||||
//socket->setSocketOption(QAbstractSocket::LowDelayOption, 1);
|
//absSocket->setSocketOption(QAbstractSocket::LowDelayOption, 1);
|
||||||
// We have this commented out now. It did not have the effect we wanted. If we want to
|
// We have this commented out now. It did not have the effect we wanted. If we want to
|
||||||
// do this properly, Qt has to combine multiple HTTP requests into one buffer
|
// do this properly, Qt has to combine multiple HTTP requests into one buffer
|
||||||
// and send this to the kernel in one syscall and then the kernel immediately sends
|
// and send this to the kernel in one syscall and then the kernel immediately sends
|
||||||
@ -884,7 +915,7 @@ void QHttpNetworkConnectionChannel::_q_connected()
|
|||||||
// the requests into one TCP packet.
|
// the requests into one TCP packet.
|
||||||
|
|
||||||
// not sure yet if it helps, but it makes sense
|
// not sure yet if it helps, but it makes sense
|
||||||
socket->setSocketOption(QAbstractSocket::KeepAliveOption, 1);
|
absSocket->setSocketOption(QAbstractSocket::KeepAliveOption, 1);
|
||||||
|
|
||||||
pipeliningSupported = QHttpNetworkConnectionChannel::PipeliningSupportUnknown;
|
pipeliningSupported = QHttpNetworkConnectionChannel::PipeliningSupportUnknown;
|
||||||
|
|
||||||
@ -893,7 +924,7 @@ void QHttpNetworkConnectionChannel::_q_connected()
|
|||||||
if (!connectionPrivate->connectionMonitor.isMonitoring()) {
|
if (!connectionPrivate->connectionMonitor.isMonitoring()) {
|
||||||
// Now that we have a pair of addresses, we can start monitoring the
|
// Now that we have a pair of addresses, we can start monitoring the
|
||||||
// connection status to handle its loss properly.
|
// connection status to handle its loss properly.
|
||||||
if (connectionPrivate->connectionMonitor.setTargets(socket->localAddress(), socket->peerAddress()))
|
if (connectionPrivate->connectionMonitor.setTargets(absSocket->localAddress(), absSocket->peerAddress()))
|
||||||
connectionPrivate->connectionMonitor.startMonitoring();
|
connectionPrivate->connectionMonitor.startMonitoring();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -905,7 +936,7 @@ void QHttpNetworkConnectionChannel::_q_connected()
|
|||||||
if (!connection->sslContext()) {
|
if (!connection->sslContext()) {
|
||||||
// this socket is making the 1st handshake for this connection,
|
// this socket is making the 1st handshake for this connection,
|
||||||
// we need to set the SSL context so new sockets can reuse it
|
// we need to set the SSL context so new sockets can reuse it
|
||||||
if (auto socketSslContext = QSslSocketPrivate::sslContext(static_cast<QSslSocket*>(socket)))
|
if (auto socketSslContext = QSslSocketPrivate::sslContext(static_cast<QSslSocket*>(absSocket)))
|
||||||
connection->setSslContext(std::move(socketSslContext));
|
connection->setSslContext(std::move(socketSslContext));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -927,7 +958,7 @@ void QHttpNetworkConnectionChannel::_q_connected()
|
|||||||
switchedToHttp2 = false;
|
switchedToHttp2 = false;
|
||||||
|
|
||||||
if (!reply)
|
if (!reply)
|
||||||
connection->d_func()->dequeueRequest(socket);
|
connection->d_func()->dequeueRequest(absSocket);
|
||||||
|
|
||||||
if (reply) {
|
if (reply) {
|
||||||
if (tryProtocolUpgrade) {
|
if (tryProtocolUpgrade) {
|
||||||
@ -940,6 +971,22 @@ void QHttpNetworkConnectionChannel::_q_connected()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QHttpNetworkConnectionChannel::_q_connected_local_socket(QLocalSocket *localSocket)
|
||||||
|
{
|
||||||
|
state = QHttpNetworkConnectionChannel::IdleState;
|
||||||
|
if (!reply) // No reply object, try to dequeue a request (which is paired with a reply):
|
||||||
|
connection->d_func()->dequeueRequest(localSocket);
|
||||||
|
if (reply)
|
||||||
|
sendRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QHttpNetworkConnectionChannel::_q_connected()
|
||||||
|
{
|
||||||
|
if (auto *s = qobject_cast<QAbstractSocket *>(socket))
|
||||||
|
_q_connected_abstract_socket(s);
|
||||||
|
else if (auto *s = qobject_cast<QLocalSocket *>(socket))
|
||||||
|
_q_connected_local_socket(s);
|
||||||
|
}
|
||||||
|
|
||||||
void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socketError)
|
void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socketError)
|
||||||
{
|
{
|
||||||
@ -1116,7 +1163,7 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
|
|||||||
//signal emission triggered event loop
|
//signal emission triggered event loop
|
||||||
if (!socket)
|
if (!socket)
|
||||||
state = QHttpNetworkConnectionChannel::IdleState;
|
state = QHttpNetworkConnectionChannel::IdleState;
|
||||||
else if (socket->state() == QAbstractSocket::UnconnectedState)
|
else if (QSocketAbstraction::socketState(socket) == QAbstractSocket::UnconnectedState)
|
||||||
state = QHttpNetworkConnectionChannel::IdleState;
|
state = QHttpNetworkConnectionChannel::IdleState;
|
||||||
else
|
else
|
||||||
state = QHttpNetworkConnectionChannel::ClosingState;
|
state = QHttpNetworkConnectionChannel::ClosingState;
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include <QtNetwork/qnetworkrequest.h>
|
#include <QtNetwork/qnetworkrequest.h>
|
||||||
#include <QtNetwork/qnetworkreply.h>
|
#include <QtNetwork/qnetworkreply.h>
|
||||||
#include <QtNetwork/qabstractsocket.h>
|
#include <QtNetwork/qabstractsocket.h>
|
||||||
|
#include <QtNetwork/qlocalsocket.h>
|
||||||
|
|
||||||
#include <private/qobject_p.h>
|
#include <private/qobject_p.h>
|
||||||
#include <qauthenticator.h>
|
#include <qauthenticator.h>
|
||||||
@ -71,7 +72,7 @@ public:
|
|||||||
ClosingState = 16,
|
ClosingState = 16,
|
||||||
BusyState = (ConnectingState|WritingState|WaitingState|ReadingState|ClosingState)
|
BusyState = (ConnectingState|WritingState|WaitingState|ReadingState|ClosingState)
|
||||||
};
|
};
|
||||||
QAbstractSocket *socket;
|
QIODevice *socket;
|
||||||
bool ssl;
|
bool ssl;
|
||||||
bool isInitialized;
|
bool isInitialized;
|
||||||
ChannelState state;
|
ChannelState state;
|
||||||
@ -156,6 +157,8 @@ public:
|
|||||||
void _q_bytesWritten(qint64 bytes); // proceed sending
|
void _q_bytesWritten(qint64 bytes); // proceed sending
|
||||||
void _q_readyRead(); // pending data to read
|
void _q_readyRead(); // pending data to read
|
||||||
void _q_disconnected(); // disconnected from host
|
void _q_disconnected(); // disconnected from host
|
||||||
|
void _q_connected_abstract_socket(QAbstractSocket *socket);
|
||||||
|
void _q_connected_local_socket(QLocalSocket *socket);
|
||||||
void _q_connected(); // start sending request
|
void _q_connected(); // start sending request
|
||||||
void _q_error(QAbstractSocket::SocketError); // error from socket
|
void _q_error(QAbstractSocket::SocketError); // error from socket
|
||||||
#ifndef QT_NO_NETWORKPROXY
|
#ifndef QT_NO_NETWORKPROXY
|
||||||
|
Loading…
x
Reference in New Issue
Block a user