Make sure SSL configuration is correct in QNetworkReply::encrypted.

In some cases, when QNetworkReply::encrypted is emitted,
QNetworkReply::sslConfiguration is not yet initialized, in particular
certificate chain is empty, which breaks the documented usage of
'encrypted' to perform additional checks on certificate chain.

It looks to be caused by the fact that QHttpNetworkReply is originally
associated with 0th QHttpNetworkConnectionChannel, and this association
is not updated if HTTP pipelining is not used. Therefore, a reply on
channel >0 might arrive before reply on channel 0, and then using ssl
configuration from channel 0, which not made it through handshake, is
not usable.

Task-number: QTBUG-49554
Change-Id: Ie5d4b5a0c503d5bdc44761ce8581f6ffe4e3bac2
Reviewed-by: Markus Goetz (Woboq GmbH) <markus@woboq.com>
bb10
Vladimir Prus 2015-11-20 11:20:02 +03:00 committed by André Klitzing
parent dc737fa0d7
commit 840e2dd2f0
3 changed files with 13 additions and 6 deletions

View File

@ -666,8 +666,7 @@ bool QHttpNetworkConnectionPrivate::dequeueRequest(QAbstractSocket *socket)
HttpMessagePair messagePair = highPriorityQueue.takeLast();
if (!messagePair.second->d_func()->requestIsPrepared)
prepareRequest(messagePair);
channels[i].request = messagePair.first;
channels[i].reply = messagePair.second;
updateChannel(i, messagePair);
return true;
}
@ -676,13 +675,21 @@ bool QHttpNetworkConnectionPrivate::dequeueRequest(QAbstractSocket *socket)
HttpMessagePair messagePair = lowPriorityQueue.takeLast();
if (!messagePair.second->d_func()->requestIsPrepared)
prepareRequest(messagePair);
channels[i].request = messagePair.first;
channels[i].reply = messagePair.second;
updateChannel(i, messagePair);
return true;
}
return false;
}
void QHttpNetworkConnectionPrivate::updateChannel(int i, const HttpMessagePair &messagePair)
{
channels[i].request = messagePair.first;
channels[i].reply = messagePair.second;
// Now that reply is assigned a channel, correct reply to channel association
// previously set in queueRequest.
channels[i].reply->d_func()->connectionChannel = &channels[i];
}
QHttpNetworkRequest QHttpNetworkConnectionPrivate::predictNextRequest()
{
if (!highPriorityQueue.isEmpty())

View File

@ -207,6 +207,7 @@ public:
void requeueRequest(const HttpMessagePair &pair); // e.g. after pipeline broke
bool dequeueRequest(QAbstractSocket *socket);
void prepareRequest(HttpMessagePair &request);
void updateChannel(int i, const HttpMessagePair &messagePair);
QHttpNetworkRequest predictNextRequest();
void fillPipeline(QAbstractSocket *socket);

View File

@ -1070,6 +1070,7 @@ void QHttpNetworkConnectionChannel::_q_encrypted()
connection->d_func()->dequeueRequest(socket);
if (reply) {
reply->setSpdyWasUsed(false);
Q_ASSERT(reply->d_func()->connectionChannel == this);
emit reply->encrypted();
}
if (reply)
@ -1109,8 +1110,6 @@ void QHttpNetworkConnectionChannel::_q_sslErrors(const QList<QSslError> &errors)
connection->d_func()->pauseConnection();
if (pendingEncrypt && !reply)
connection->d_func()->dequeueRequest(socket);
if (reply) // a reply was actually dequeued.
reply->d_func()->connectionChannel = this; // set correct channel like in sendRequest() and queueRequest();
if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP) {
if (reply)
emit reply->sslErrors(errors);