Add support for setting the peer verify name via the QNetwork* classes

This adds functions to QNetworkRequest to be able to set the
peerVerifyName. An overload of connectToHostEncrypted is also added to
have an extra argument to allow setting it directly in this manner too.

Fixes: QTBUG-73125
Change-Id: I371e90035b53a74c9eb3cef64f367e307dce073e
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
This commit is contained in:
Andy Shaw 2019-01-30 12:05:31 +01:00 committed by Liang Qi
parent 8a7c373f8e
commit 5133e22ae2
11 changed files with 105 additions and 9 deletions

View File

@ -1518,6 +1518,18 @@ void QHttpNetworkConnection::preConnectFinished()
d_func()->preConnectRequests--;
}
QString QHttpNetworkConnection::peerVerifyName() const
{
Q_D(const QHttpNetworkConnection);
return d->peerVerifyName;
}
void QHttpNetworkConnection::setPeerVerifyName(const QString &peerName)
{
Q_D(QHttpNetworkConnection);
d->peerVerifyName = peerName;
}
#ifndef QT_NO_NETWORKPROXY
// only called from QHttpNetworkConnectionChannel::_q_proxyAuthenticationRequired, not
// from QHttpNetworkConnectionChannel::handleAuthenticationChallenge

View File

@ -154,6 +154,8 @@ public:
void preConnectFinished();
QString peerVerifyName() const;
void setPeerVerifyName(const QString &peerName);
private:
Q_DECLARE_PRIVATE(QHttpNetworkConnection)
Q_DISABLE_COPY_MOVE(QHttpNetworkConnection)
@ -289,6 +291,8 @@ public:
Http2::ProtocolParameters http2Parameters;
QString peerVerifyName;
friend class QHttpNetworkConnectionChannel;
};

View File

@ -392,6 +392,7 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
if (!connection->sslContext().isNull())
QSslSocketPrivate::checkSettingSslContext(sslSocket, connection->sslContext());
sslSocket->setPeerVerifyName(connection->d_func()->peerVerifyName);
sslSocket->connectToHostEncrypted(connectHost, connectPort, QIODevice::ReadWrite, networkLayerPreference);
if (ignoreAllSslErrors)
sslSocket->ignoreSslErrors();

View File

@ -66,7 +66,8 @@ QHttpNetworkRequestPrivate::QHttpNetworkRequestPrivate(const QHttpNetworkRequest
ssl(other.ssl),
preConnect(other.preConnect),
redirectCount(other.redirectCount),
redirectPolicy(other.redirectPolicy)
redirectPolicy(other.redirectPolicy),
peerVerifyName(other.peerVerifyName)
{
}
@ -90,7 +91,8 @@ bool QHttpNetworkRequestPrivate::operator==(const QHttpNetworkRequestPrivate &ot
&& (withCredentials == other.withCredentials)
&& (ssl == other.ssl)
&& (preConnect == other.preConnect)
&& (redirectPolicy == other.redirectPolicy);
&& (redirectPolicy == other.redirectPolicy)
&& (peerVerifyName == other.peerVerifyName);
}
QByteArray QHttpNetworkRequest::methodName() const
@ -397,6 +399,15 @@ int QHttpNetworkRequest::minorVersion() const
return 1;
}
QString QHttpNetworkRequest::peerVerifyName() const
{
return d->peerVerifyName;
}
void QHttpNetworkRequest::setPeerVerifyName(const QString &peerName)
{
d->peerVerifyName = peerName;
}
QT_END_NAMESPACE

View File

@ -147,6 +147,8 @@ public:
QByteArray methodName() const;
QByteArray uri(bool throughProxy) const;
QString peerVerifyName() const;
void setPeerVerifyName(const QString &peerName);
private:
QSharedDataPointer<QHttpNetworkRequestPrivate> d;
friend class QHttpNetworkRequestPrivate;
@ -182,6 +184,7 @@ public:
bool preConnect;
int redirectCount;
QNetworkRequest::RedirectPolicy redirectPolicy;
QString peerVerifyName;
};

View File

@ -123,7 +123,7 @@ static QNetworkReply::NetworkError statusCodeFromHttp(int httpStatusCode, const
}
static QByteArray makeCacheKey(QUrl &url, QNetworkProxy *proxy)
static QByteArray makeCacheKey(QUrl &url, QNetworkProxy *proxy, const QString &peerVerifyName)
{
QString result;
QUrl copy = url;
@ -170,7 +170,8 @@ static QByteArray makeCacheKey(QUrl &url, QNetworkProxy *proxy)
#else
Q_UNUSED(proxy)
#endif
if (!peerVerifyName.isEmpty())
result += QLatin1Char(':') + peerVerifyName;
return "http-connection:" + std::move(result).toLatin1();
}
@ -317,12 +318,12 @@ void QHttpThreadDelegate::startRequest()
#ifndef QT_NO_NETWORKPROXY
if (transparentProxy.type() != QNetworkProxy::NoProxy)
cacheKey = makeCacheKey(urlCopy, &transparentProxy);
cacheKey = makeCacheKey(urlCopy, &transparentProxy, httpRequest.peerVerifyName());
else if (cacheProxy.type() != QNetworkProxy::NoProxy)
cacheKey = makeCacheKey(urlCopy, &cacheProxy);
cacheKey = makeCacheKey(urlCopy, &cacheProxy, httpRequest.peerVerifyName());
else
#endif
cacheKey = makeCacheKey(urlCopy, 0);
cacheKey = makeCacheKey(urlCopy, 0, httpRequest.peerVerifyName());
// the http object is actually a QHttpNetworkConnection
@ -352,7 +353,7 @@ void QHttpThreadDelegate::startRequest()
httpConnection->setTransparentProxy(transparentProxy);
httpConnection->setCacheProxy(cacheProxy);
#endif
httpConnection->setPeerVerifyName(httpRequest.peerVerifyName());
// cache the QHttpNetworkConnection corresponding to this cache key
connections.localData()->addEntry(cacheKey, httpConnection);
} else {

View File

@ -1181,8 +1181,36 @@ QSharedPointer<QNetworkSession> QNetworkAccessManagerPrivate::getNetworkSession(
\sa connectToHost(), get(), post(), put(), deleteResource()
*/
void QNetworkAccessManager::connectToHostEncrypted(const QString &hostName, quint16 port,
const QSslConfiguration &sslConfiguration)
{
connectToHostEncrypted(hostName, port, sslConfiguration, QString());
}
/*!
\since 5.13
\overload
Initiates a connection to the host given by \a hostName at port \a port, using
\a sslConfiguration with \a peerName set to be the hostName used for certificate
validation. This function is useful to complete the TCP and SSL handshake
to a host before the HTTPS request is made, resulting in a lower network latency.
\note Preconnecting a SPDY connection can be done by calling setAllowedNextProtocols()
on \a sslConfiguration with QSslConfiguration::NextProtocolSpdy3_0 contained in
the list of allowed protocols. When using SPDY, one single connection per host is
enough, i.e. calling this method multiple times per host will not result in faster
network transactions.
\note This function has no possibility to report errors.
\sa connectToHost(), get(), post(), put(), deleteResource()
*/
void QNetworkAccessManager::connectToHostEncrypted(const QString &hostName, quint16 port,
const QSslConfiguration &sslConfiguration,
const QString &peerName)
{
QUrl url;
url.setHost(hostName);
@ -1198,6 +1226,7 @@ void QNetworkAccessManager::connectToHostEncrypted(const QString &hostName, quin
QSslConfiguration::NextProtocolSpdy3_0))
request.setAttribute(QNetworkRequest::SpdyAllowedAttribute, true);
request.setPeerVerifyName(peerName);
get(request);
}
#endif

View File

@ -158,6 +158,9 @@ public:
#ifndef QT_NO_SSL
void connectToHostEncrypted(const QString &hostName, quint16 port = 443,
const QSslConfiguration &sslConfiguration = QSslConfiguration::defaultConfiguration());
void connectToHostEncrypted(const QString &hostName, quint16 port,
const QSslConfiguration &sslConfiguration,
const QString &peerName);
#endif
void connectToHost(const QString &hostName, quint16 port = 80);

View File

@ -785,6 +785,7 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq
if (request.attribute(QNetworkRequest::EmitAllUploadProgressSignalsAttribute).toBool())
emitAllUploadProgressSignals = true;
httpRequest.setPeerVerifyName(newHttpRequest.peerVerifyName());
// Create the HTTP thread delegate
QHttpThreadDelegate *delegate = new QHttpThreadDelegate;

View File

@ -438,6 +438,7 @@ public:
if (other.sslConfiguration)
sslConfiguration = new QSslConfiguration(*other.sslConfiguration);
#endif
peerVerifyName = other.peerVerifyName;
}
inline bool operator==(const QNetworkRequestPrivate &other) const
@ -446,7 +447,8 @@ public:
priority == other.priority &&
rawHeaders == other.rawHeaders &&
attributes == other.attributes &&
maxRedirectsAllowed == other.maxRedirectsAllowed;
maxRedirectsAllowed == other.maxRedirectsAllowed &&
peerVerifyName == other.peerVerifyName;
// don't compare cookedHeaders
}
@ -456,6 +458,7 @@ public:
mutable QSslConfiguration *sslConfiguration;
#endif
int maxRedirectsAllowed;
QString peerVerifyName;
};
/*!
@ -789,6 +792,32 @@ void QNetworkRequest::setMaximumRedirectsAllowed(int maxRedirectsAllowed)
d->maxRedirectsAllowed = maxRedirectsAllowed;
}
/*!
\since 5.13
Returns the host name set for the certificate validation, as set by
setPeerVerifyName. By default this returns a null string.
\sa setPeerVerifyName
*/
QString QNetworkRequest::peerVerifyName() const
{
return d->peerVerifyName;
}
/*!
\since 5.13
Sets \a peerName as host name for the certificate validation, instead of the one used for the
TCP connection.
\sa peerVerifyName
*/
void QNetworkRequest::setPeerVerifyName(const QString &peerName)
{
d->peerVerifyName = peerName;
}
static QByteArray headerName(QNetworkRequest::KnownHeaders header)
{
switch (header) {

View File

@ -173,6 +173,8 @@ public:
int maximumRedirectsAllowed() const;
void setMaximumRedirectsAllowed(int maximumRedirectsAllowed);
QString peerVerifyName() const;
void setPeerVerifyName(const QString &peerName);
private:
QSharedDataPointer<QNetworkRequestPrivate> d;
friend class QNetworkRequestPrivate;