Add an encrypted() signal to QNetworkAccessManager and QNetworkReply.
Add an encrypted signal to QNAM and QNetworkReply to allow applications to perform additional checks on the certificate chain beyond those done as part of the standard SSL validation. This allows things like certificate change notification to be implemented for QNAM as they can be for QSSLSocket currently. Change-Id: I693e3e6fec8b7040379b7e7f1f819550e6b2617f Reviewed-by: Peter Hartmann <phartmann@rim.com>bb10
parent
7898080ca7
commit
5ebc8d3663
|
|
@ -1224,6 +1224,8 @@ void QHttpNetworkConnectionChannel::_q_encrypted()
|
|||
pendingEncrypt = false;
|
||||
if (!reply)
|
||||
connection->d_func()->dequeueRequest(socket);
|
||||
if (reply)
|
||||
emit reply->encrypted();
|
||||
if (reply)
|
||||
sendRequest();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -142,6 +142,7 @@ public:
|
|||
void ignoreSslErrors(const QList<QSslError> &errors);
|
||||
|
||||
Q_SIGNALS:
|
||||
void encrypted();
|
||||
void sslErrors(const QList<QSslError> &errors);
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -315,6 +315,7 @@ void QHttpThreadDelegate::startRequest()
|
|||
connect(httpReply,SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
|
||||
connect(httpReply,SIGNAL(dataReadProgress(qint64,qint64)), this, SLOT(dataReadProgressSlot(qint64,qint64)));
|
||||
#ifndef QT_NO_SSL
|
||||
connect(httpReply,SIGNAL(encrypted()), this, SLOT(encryptedSlot()));
|
||||
connect(httpReply,SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(sslErrorsSlot(QList<QSslError>)));
|
||||
#endif
|
||||
|
||||
|
|
@ -589,6 +590,14 @@ void QHttpThreadDelegate::cacheCredentialsSlot(const QHttpNetworkRequest &reques
|
|||
|
||||
|
||||
#ifndef QT_NO_SSL
|
||||
void QHttpThreadDelegate::encryptedSlot()
|
||||
{
|
||||
if (!httpReply)
|
||||
return;
|
||||
|
||||
emit encrypted();
|
||||
}
|
||||
|
||||
void QHttpThreadDelegate::sslErrorsSlot(const QList<QSslError> &errors)
|
||||
{
|
||||
if (!httpReply)
|
||||
|
|
|
|||
|
|
@ -135,6 +135,7 @@ signals:
|
|||
void proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *);
|
||||
#endif
|
||||
#ifndef QT_NO_SSL
|
||||
void encrypted();
|
||||
void sslErrors(const QList<QSslError> &, bool *, QList<QSslError> *);
|
||||
void sslConfigurationChanged(const QSslConfiguration);
|
||||
#endif
|
||||
|
|
@ -164,6 +165,7 @@ protected slots:
|
|||
void dataReadProgressSlot(qint64 done, qint64 total);
|
||||
void cacheCredentialsSlot(const QHttpNetworkRequest &request, QAuthenticator *authenticator);
|
||||
#ifndef QT_NO_SSL
|
||||
void encryptedSlot();
|
||||
void sslErrorsSlot(const QList<QSslError> &errors);
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -340,6 +340,13 @@ void QNetworkAccessBackend::redirectionRequested(const QUrl &target)
|
|||
reply->redirectionRequested(target);
|
||||
}
|
||||
|
||||
void QNetworkAccessBackend::encrypted()
|
||||
{
|
||||
#ifndef QT_NO_SSL
|
||||
reply->encrypted();
|
||||
#endif
|
||||
}
|
||||
|
||||
void QNetworkAccessBackend::sslErrors(const QList<QSslError> &errors)
|
||||
{
|
||||
#ifndef QT_NO_SSL
|
||||
|
|
|
|||
|
|
@ -196,6 +196,7 @@ protected slots:
|
|||
void authenticationRequired(QAuthenticator *auth);
|
||||
void metaDataChanged();
|
||||
void redirectionRequested(const QUrl &destination);
|
||||
void encrypted();
|
||||
void sslErrors(const QList<QSslError> &errors);
|
||||
void emitReplyUploadProgress(qint64 bytesSent, qint64 bytesTotal);
|
||||
|
||||
|
|
|
|||
|
|
@ -373,6 +373,32 @@ static void ensureInitialized()
|
|||
\sa QNetworkReply::finished(), QNetworkReply::error()
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn void QNetworkAccessManager::encrypted(QNetworkReply *reply)
|
||||
\since 5.1
|
||||
|
||||
This signal is emitted when an SSL/TLS session has successfully
|
||||
completed the initial handshake. At this point, no user data
|
||||
has been transmitted. The signal can be used to perform
|
||||
additional checks on the certificate chain, for example to
|
||||
notify users when the certificate for a website has changed. The
|
||||
\a reply parameter specifies which network reply is responsible.
|
||||
If the reply does not match the expected criteria then it should
|
||||
be aborted by calling QNetworkReply::abort() by a slot connected
|
||||
to this signal. The SSL configuration in use can be inspected
|
||||
using the QNetworkReply::sslConfiguration() method.
|
||||
|
||||
Internally, QNetworkAccessManager may open multiple connections
|
||||
to a server, in order to allow it process requests in parallel.
|
||||
These connections may be reused, which means that the encrypted()
|
||||
signal would not be emitted. This means that you are only
|
||||
guaranteed to receive this signal for the first connection to a
|
||||
site in the lifespan of the QNetworkAccessManager.
|
||||
|
||||
\sa QSslSocket::encrypted()
|
||||
\sa QNetworkReply::encrypted()
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn void QNetworkAccessManager::sslErrors(QNetworkReply *reply, const QList<QSslError> &errors)
|
||||
|
||||
|
|
@ -1132,6 +1158,16 @@ void QNetworkAccessManagerPrivate::_q_replyFinished()
|
|||
#endif
|
||||
}
|
||||
|
||||
void QNetworkAccessManagerPrivate::_q_replyEncrypted()
|
||||
{
|
||||
#ifndef QT_NO_SSL
|
||||
Q_Q(QNetworkAccessManager);
|
||||
QNetworkReply *reply = qobject_cast<QNetworkReply *>(q->sender());
|
||||
if (reply)
|
||||
emit q->encrypted(reply);
|
||||
#endif
|
||||
}
|
||||
|
||||
void QNetworkAccessManagerPrivate::_q_replySslErrors(const QList<QSslError> &errors)
|
||||
{
|
||||
#ifndef QT_NO_SSL
|
||||
|
|
@ -1152,6 +1188,7 @@ QNetworkReply *QNetworkAccessManagerPrivate::postProcess(QNetworkReply *reply)
|
|||
#ifndef QT_NO_SSL
|
||||
/* In case we're compiled without SSL support, we don't have this signal and we need to
|
||||
* avoid getting a connection error. */
|
||||
q->connect(reply, SIGNAL(encrypted()), SLOT(_q_replyEncrypted()));
|
||||
q->connect(reply, SIGNAL(sslErrors(QList<QSslError>)), SLOT(_q_replySslErrors(QList<QSslError>)));
|
||||
#endif
|
||||
#ifndef QT_NO_BEARERMANAGEMENT
|
||||
|
|
|
|||
|
|
@ -139,6 +139,7 @@ Q_SIGNALS:
|
|||
void authenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator);
|
||||
void finished(QNetworkReply *reply);
|
||||
#ifndef QT_NO_SSL
|
||||
void encrypted(QNetworkReply *reply);
|
||||
void sslErrors(QNetworkReply *reply, const QList<QSslError> &errors);
|
||||
#endif
|
||||
|
||||
|
|
@ -159,6 +160,7 @@ private:
|
|||
|
||||
Q_DECLARE_PRIVATE(QNetworkAccessManager)
|
||||
Q_PRIVATE_SLOT(d_func(), void _q_replyFinished())
|
||||
Q_PRIVATE_SLOT(d_func(), void _q_replyEncrypted())
|
||||
Q_PRIVATE_SLOT(d_func(), void _q_replySslErrors(QList<QSslError>))
|
||||
#ifndef QT_NO_BEARERMANAGEMENT
|
||||
Q_PRIVATE_SLOT(d_func(), void _q_networkSessionClosed())
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ public:
|
|||
~QNetworkAccessManagerPrivate();
|
||||
|
||||
void _q_replyFinished();
|
||||
void _q_replyEncrypted();
|
||||
void _q_replySslErrors(const QList<QSslError> &errors);
|
||||
QNetworkReply *postProcess(QNetworkReply *reply);
|
||||
void createCookieJar() const;
|
||||
|
|
|
|||
|
|
@ -194,6 +194,31 @@ QNetworkReplyPrivate::QNetworkReplyPrivate()
|
|||
\sa error()
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn void QNetworkReply::encrypted()
|
||||
\since 5.1
|
||||
|
||||
This signal is emitted when an SSL/TLS session has successfully
|
||||
completed the initial handshake. At this point, no user data
|
||||
has been transmitted. The signal can be used to perform
|
||||
additional checks on the certificate chain, for example to
|
||||
notify users when the certificate for a website has changed.
|
||||
If the reply does not match the expected criteria then it should
|
||||
be aborted by calling QNetworkReply::abort() by a slot connected
|
||||
to this signal. The SSL configuration in use can be inspected
|
||||
using the QNetworkReply::sslConfiguration() method.
|
||||
|
||||
Internally, QNetworkAccessManager may open multiple connections
|
||||
to a server, in order to allow it process requests in parallel.
|
||||
These connections may be reused, which means that the encrypted()
|
||||
signal would not be emitted. This means that you are only
|
||||
guaranteed to receive this signal for the first connection to a
|
||||
site in the lifespan of the QNetworkAccessManager.
|
||||
|
||||
\sa QSslSocket::encrypted()
|
||||
\sa QNetworkAccessManager::encrypted()
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn void QNetworkReply::sslErrors(const QList<QSslError> &errors)
|
||||
|
||||
|
|
|
|||
|
|
@ -148,6 +148,7 @@ Q_SIGNALS:
|
|||
void finished();
|
||||
void error(QNetworkReply::NetworkError);
|
||||
#ifndef QT_NO_SSL
|
||||
void encrypted();
|
||||
void sslErrors(const QList<QSslError> &errors);
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -830,6 +830,8 @@ void QNetworkReplyHttpImplPrivate::postRequest()
|
|||
Qt::BlockingQueuedConnection);
|
||||
#endif
|
||||
#ifndef QT_NO_SSL
|
||||
QObject::connect(delegate, SIGNAL(encrypted()), q, SLOT(replyEncrypted()),
|
||||
Qt::BlockingQueuedConnection);
|
||||
QObject::connect(delegate, SIGNAL(sslErrors(QList<QSslError>,bool*,QList<QSslError>*)),
|
||||
q, SLOT(replySslErrors(QList<QSslError>,bool*,QList<QSslError>*)),
|
||||
Qt::BlockingQueuedConnection);
|
||||
|
|
@ -1220,6 +1222,12 @@ void QNetworkReplyHttpImplPrivate::httpError(QNetworkReply::NetworkError errorCo
|
|||
}
|
||||
|
||||
#ifndef QT_NO_SSL
|
||||
void QNetworkReplyHttpImplPrivate::replyEncrypted()
|
||||
{
|
||||
Q_Q(QNetworkReplyHttpImpl);
|
||||
emit q->encrypted();
|
||||
}
|
||||
|
||||
void QNetworkReplyHttpImplPrivate::replySslErrors(
|
||||
const QList<QSslError> &list, bool *ignoreAll, QList<QSslError> *toBeIgnored)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -116,6 +116,7 @@ public:
|
|||
Q_PRIVATE_SLOT(d_func(), void httpAuthenticationRequired(const QHttpNetworkRequest &, QAuthenticator *))
|
||||
Q_PRIVATE_SLOT(d_func(), void httpError(QNetworkReply::NetworkError, const QString &))
|
||||
#ifndef QT_NO_SSL
|
||||
Q_PRIVATE_SLOT(d_func(), void replyEncrypted())
|
||||
Q_PRIVATE_SLOT(d_func(), void replySslErrors(const QList<QSslError> &, bool *, QList<QSslError> *))
|
||||
Q_PRIVATE_SLOT(d_func(), void replySslConfigurationChanged(const QSslConfiguration&))
|
||||
#endif
|
||||
|
|
@ -280,6 +281,7 @@ public:
|
|||
void httpAuthenticationRequired(const QHttpNetworkRequest &request, QAuthenticator *auth);
|
||||
void httpError(QNetworkReply::NetworkError error, const QString &errorString);
|
||||
#ifndef QT_NO_SSL
|
||||
void replyEncrypted();
|
||||
void replySslErrors(const QList<QSslError> &, bool *, QList<QSslError> *);
|
||||
void replySslConfigurationChanged(const QSslConfiguration&);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -879,6 +879,14 @@ void QNetworkReplyImplPrivate::redirectionRequested(const QUrl &target)
|
|||
attributes.insert(QNetworkRequest::RedirectionTargetAttribute, target);
|
||||
}
|
||||
|
||||
void QNetworkReplyImplPrivate::encrypted()
|
||||
{
|
||||
#ifndef QT_NO_SSL
|
||||
Q_Q(QNetworkReplyImpl);
|
||||
emit q->encrypted();
|
||||
#endif
|
||||
}
|
||||
|
||||
void QNetworkReplyImplPrivate::sslErrors(const QList<QSslError> &errors)
|
||||
{
|
||||
#ifndef QT_NO_SSL
|
||||
|
|
|
|||
|
|
@ -176,6 +176,7 @@ public:
|
|||
void error(QNetworkReply::NetworkError code, const QString &errorString);
|
||||
void metaDataChanged();
|
||||
void redirectionRequested(const QUrl &target);
|
||||
void encrypted();
|
||||
void sslErrors(const QList<QSslError> &errors);
|
||||
|
||||
QNetworkAccessBackend *backend;
|
||||
|
|
|
|||
|
|
@ -361,6 +361,7 @@ private Q_SLOTS:
|
|||
void ignoreSslErrorsList();
|
||||
void ignoreSslErrorsListWithSlot_data();
|
||||
void ignoreSslErrorsListWithSlot();
|
||||
void encrypted();
|
||||
void sslConfiguration_data();
|
||||
void sslConfiguration();
|
||||
#ifdef QT_BUILD_INTERNAL
|
||||
|
|
@ -5867,6 +5868,24 @@ void tst_QNetworkReply::sslConfiguration_data()
|
|||
QTest::newRow("secure") << conf << true;
|
||||
}
|
||||
|
||||
void tst_QNetworkReply::encrypted()
|
||||
{
|
||||
qDebug() << QtNetworkSettings::serverName();
|
||||
QUrl url("https://" + QtNetworkSettings::serverName());
|
||||
QNetworkRequest request(url);
|
||||
QNetworkReply *reply = manager.get(request);
|
||||
reply->ignoreSslErrors();
|
||||
|
||||
QSignalSpy spy(reply, SIGNAL(encrypted()));
|
||||
connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
|
||||
QTestEventLoop::instance().enterLoop(20);
|
||||
QVERIFY(!QTestEventLoop::instance().timeout());
|
||||
|
||||
QCOMPARE(spy.count(), 1);
|
||||
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
void tst_QNetworkReply::sslConfiguration()
|
||||
{
|
||||
QNetworkRequest request(QUrl("https://" + QtNetworkSettings::serverName() + "/index.html"));
|
||||
|
|
|
|||
Loading…
Reference in New Issue