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:
Mårten Nordheim 2024-03-04 17:32:00 +01:00
parent c9a1e8d306
commit 956795bda8
3 changed files with 131 additions and 64 deletions

View File

@ -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--;
} }

View File

@ -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;

View File

@ -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