Fix Q_ASSERT(!channels[0].isSocketBusy());
Since commit f30641a7
is has been possible to issue more than one host
lookup request per HttpNetworkConnection. If the result was both an
IPv4 and IPv6 address, and we get a second similar DNS reply, we
end up triggering the assert in startNetworkLayerStateLookup().
This patch splits the InProgress state to HostLookupPending and the state
of trying both IPv4 and IPv6. This makes it possible to ignore any new DNS
replies received after the first succesfull one.
Change-Id: I0b8d6b1582fdaed69dde5926019b60bb0cbd580d
Reviewed-by: Peter Hartmann <phartmann@blackberry.com>
This commit is contained in:
parent
13035f7fd6
commit
690cf426f3
@ -181,7 +181,7 @@ int QHttpNetworkConnectionPrivate::indexOf(QAbstractSocket *socket) const
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If the connection is in the InProgress state channel errors should not always be
|
||||
// If the connection is in the HostLookupPendening state channel errors should not always be
|
||||
// emitted. This function will check the status of the connection channels if we
|
||||
// have not decided the networkLayerState and will return true if the channel error
|
||||
// should be emitted by the channel.
|
||||
@ -200,12 +200,12 @@ bool QHttpNetworkConnectionPrivate::shouldEmitChannelError(QAbstractSocket *sock
|
||||
}
|
||||
|
||||
if (channelCount == 1) {
|
||||
if (networkLayerState == QHttpNetworkConnectionPrivate::InProgress)
|
||||
if (networkLayerState == HostLookupPending || networkLayerState == IPv4or6)
|
||||
networkLayerState = QHttpNetworkConnectionPrivate::Unknown;
|
||||
channels[0].close();
|
||||
emitError = true;
|
||||
} else {
|
||||
if (networkLayerState == QHttpNetworkConnectionPrivate::InProgress) {
|
||||
if (networkLayerState == HostLookupPending || networkLayerState == IPv4or6) {
|
||||
if (channels[otherSocket].isSocketBusy() && (channels[otherSocket].state != QHttpNetworkConnectionChannel::ClosingState)) {
|
||||
// this was the first socket to fail.
|
||||
channels[i].close();
|
||||
@ -560,7 +560,7 @@ QHttpNetworkReply* QHttpNetworkConnectionPrivate::queueRequest(const QHttpNetwor
|
||||
// untill we have started the first connection attempt. So no
|
||||
// request will be started untill we know if IPv4 or IPv6
|
||||
// should be used.
|
||||
if (networkLayerState == Unknown || networkLayerState == InProgress) {
|
||||
if (networkLayerState == Unknown || networkLayerState == HostLookupPending) {
|
||||
startHostInfoLookup();
|
||||
} else if ( networkLayerState == IPv4 || networkLayerState == IPv6 ) {
|
||||
// this used to be called via invokeMethod and a QueuedConnection
|
||||
@ -878,7 +878,7 @@ void QHttpNetworkConnectionPrivate::removeReply(QHttpNetworkReply *reply)
|
||||
void QHttpNetworkConnectionPrivate::_q_startNextRequest()
|
||||
{
|
||||
// If there is no network layer state decided we should not start any new requests.
|
||||
if (networkLayerState == Unknown || networkLayerState == InProgress)
|
||||
if (networkLayerState == Unknown || networkLayerState == HostLookupPending || networkLayerState == IPv4or6)
|
||||
return;
|
||||
|
||||
// If the QHttpNetworkConnection is currently paused then bail out immediately
|
||||
@ -986,7 +986,7 @@ void QHttpNetworkConnectionPrivate::readMoreLater(QHttpNetworkReply *reply)
|
||||
// lookup as then the hostinfo will already be in the cache.
|
||||
void QHttpNetworkConnectionPrivate::startHostInfoLookup()
|
||||
{
|
||||
networkLayerState = InProgress;
|
||||
networkLayerState = HostLookupPending;
|
||||
|
||||
// check if we already now can decide if this is IPv4 or IPv6
|
||||
QString lookupHost = hostName;
|
||||
@ -1028,6 +1028,8 @@ void QHttpNetworkConnectionPrivate::_q_hostLookupFinished(QHostInfo info)
|
||||
bool bIpv4 = false;
|
||||
bool bIpv6 = false;
|
||||
bool foundAddress = false;
|
||||
if (networkLayerState == IPv4 || networkLayerState == IPv6 || networkLayerState == IPv4or6)
|
||||
return;
|
||||
|
||||
foreach (const QHostAddress &address, info.addresses()) {
|
||||
if (address.protocol() == QAbstractSocket::IPv4Protocol) {
|
||||
@ -1077,7 +1079,7 @@ void QHttpNetworkConnectionPrivate::startNetworkLayerStateLookup()
|
||||
Q_ASSERT(!channels[0].isSocketBusy());
|
||||
Q_ASSERT(!channels[1].isSocketBusy());
|
||||
|
||||
networkLayerState = InProgress;
|
||||
networkLayerState = IPv4or6;
|
||||
|
||||
channels[0].networkLayerPreference = QAbstractSocket::IPv4Protocol;
|
||||
channels[1].networkLayerPreference = QAbstractSocket::IPv6Protocol;
|
||||
@ -1101,7 +1103,7 @@ void QHttpNetworkConnectionPrivate::startNetworkLayerStateLookup()
|
||||
else
|
||||
channels[0].ensureConnection();
|
||||
} else {
|
||||
networkLayerState = InProgress;
|
||||
networkLayerState = IPv4or6;
|
||||
channels[0].networkLayerPreference = QAbstractSocket::AnyIPProtocol;
|
||||
channels[0].ensureConnection();
|
||||
}
|
||||
|
@ -165,9 +165,10 @@ public:
|
||||
|
||||
enum NetworkLayerPreferenceState {
|
||||
Unknown,
|
||||
InProgress,
|
||||
HostLookupPending,
|
||||
IPv4,
|
||||
IPv6
|
||||
IPv6,
|
||||
IPv4or6
|
||||
};
|
||||
|
||||
QHttpNetworkConnectionPrivate(const QString &hostName, quint16 port, bool encrypt);
|
||||
|
@ -1045,7 +1045,7 @@ void QHttpNetworkConnectionChannel::_q_disconnected()
|
||||
void QHttpNetworkConnectionChannel::_q_connected()
|
||||
{
|
||||
// For the Happy Eyeballs we need to check if this is the first channel to connect.
|
||||
if (connection->d_func()->networkLayerState == QHttpNetworkConnectionPrivate::InProgress) {
|
||||
if (connection->d_func()->networkLayerState == QHttpNetworkConnectionPrivate::HostLookupPending || connection->d_func()->networkLayerState == QHttpNetworkConnectionPrivate::IPv4or6) {
|
||||
if (connection->d_func()->delayedConnectionTimer.isActive())
|
||||
connection->d_func()->delayedConnectionTimer.stop();
|
||||
if (networkLayerPreference == QAbstractSocket::IPv4Protocol)
|
||||
@ -1212,7 +1212,7 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
|
||||
QPointer<QHttpNetworkConnection> that = connection;
|
||||
QString errorString = connection->d_func()->errorDetail(errorCode, socket, socket->errorString());
|
||||
|
||||
// In the InProgress state the channel should not emit the error.
|
||||
// In the HostLookupPending state the channel should not emit the error.
|
||||
// This will instead be handled by the connection.
|
||||
if (!connection->d_func()->shouldEmitChannelError(socket))
|
||||
return;
|
||||
|
Loading…
Reference in New Issue
Block a user