Skip to content

Commit

Permalink
Prefer previously used channels in QHttpNetworkConnection
Browse files Browse the repository at this point in the history
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
Pick-to: 5.15 6.1
Change-Id: Ic9dc6a24ef793a29c2652ad37bc11120e2e6ceef
Reviewed-by: Mårten Nordheim <[email protected]>
  • Loading branch information
SmallLars committed May 11, 2021
1 parent 1a63217 commit a120d11
Showing 1 changed file with 38 additions and 19 deletions.
57 changes: 38 additions & 19 deletions src/network/access/qhttpnetworkconnection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1117,31 +1117,50 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
int normalRequests = queuedRequests - preConnectRequests;
neededOpenChannels = qMax(normalRequests, preConnectRequests);
}

if (neededOpenChannels <= 0)
return;

QQueue<int> channelsToConnect;

// use previously used channels first
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 (!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();
}
}


Expand Down

0 comments on commit a120d11

Please sign in to comment.