From 516d8d22ff45da01ae9de367a39c129dd408246a Mon Sep 17 00:00:00 2001 From: Lars Schmertmann Date: Thu, 14 Sep 2017 12:47:11 +0200 Subject: [PATCH] Prefer previously used channels in QHttpNetworkConnection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When IPv4 and IPv6 are supported by a server, QHttpNetworkConnection will start up two connections and pick the network layer of the one that finish first. In this case the channel with index 1 is used for IPv6. When IPv6 wins, there is no channel at index 0. This situation needs to be respected and we should try to use existing channels first when there is a next request. This is especially important when TLS session resumption is used. Creating a new channel will cause to lose the ephemeralServerKey used in the first connection. Fixes: QTBUG-93295 Change-Id: Ic9dc6a24ef793a29c2652ad37bc11120e2e6ceef Reviewed-by: MÃ¥rten Nordheim (cherry picked from commit a120d11cb5506ef0a5535e790f23d49595fb8857) Reviewed-by: Qt Cherry-pick Bot --- src/network/access/qhttpnetworkconnection.cpp | 57 ++++++++++++------- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp index 13c86c6a9b0..18b9e38b9a3 100644 --- a/src/network/access/qhttpnetworkconnection.cpp +++ b/src/network/access/qhttpnetworkconnection.cpp @@ -1117,31 +1117,50 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest() int normalRequests = queuedRequests - preConnectRequests; neededOpenChannels = qMax(normalRequests, preConnectRequests); } - for (int i = 0; i < activeChannelCount && neededOpenChannels > 0; ++i) { - bool connectChannel = false; - if (channels[i].socket) { - if ((channels[i].socket->state() == QAbstractSocket::ConnectingState) - || (channels[i].socket->state() == QAbstractSocket::HostLookupState) - || channels[i].pendingEncrypt) // pendingEncrypt == "EncryptingState" - neededOpenChannels--; - if (neededOpenChannels <= 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 (neededOpenChannels <= 0) + return; + + QQueue channelsToConnect; + + // use previously used channels first + for (int i = 0; i < activeChannelCount && neededOpenChannels > 0; ++i) { + if (!channels[i].socket) + continue; + + if ((channels[i].socket->state() == QAbstractSocket::ConnectingState) + || (channels[i].socket->state() == QAbstractSocket::HostLookupState) + || channels[i].pendingEncrypt) { // pendingEncrypt == "EncryptingState" + neededOpenChannels--; + continue; } - if (connectChannel) { - if (networkLayerState == IPv4) - channels[i].networkLayerPreference = QAbstractSocket::IPv4Protocol; - else if (networkLayerState == IPv6) - channels[i].networkLayerPreference = QAbstractSocket::IPv6Protocol; - channels[i].ensureConnection(); + if (!channels[i].reply && !channels[i].isSocketBusy() + && (channels[i].socket->state() == QAbstractSocket::UnconnectedState)) { + channelsToConnect.enqueue(i); neededOpenChannels--; } } + + // use other channels + for (int i = 0; i < activeChannelCount && neededOpenChannels > 0; ++i) { + if (channels[i].socket) + continue; + + channelsToConnect.enqueue(i); + neededOpenChannels--; + } + + while (!channelsToConnect.isEmpty()) { + const int channel = channelsToConnect.dequeue(); + + if (networkLayerState == IPv4) + channels[channel].networkLayerPreference = QAbstractSocket::IPv4Protocol; + else if (networkLayerState == IPv6) + channels[channel].networkLayerPreference = QAbstractSocket::IPv6Protocol; + + channels[channel].ensureConnection(); + } }