QAbstractSocket / QSslSocket: add API to pause and resume
pause and resume is currently only supported upon emitting the QSslSocket::sslErrors() signal. The API was added in QAbstractSocket to also support QAbstractSocket::proxyAuthenticationRequired() in the future. This is the first patch to support that feature on the socket level, another patch will follow to support sslErrors() and authenticationRequired() in QNetworkAccessManager / QNetworkReply. Task-number: QTBUG-19032 Change-Id: Ide2918268590ab9a01454ab26cb7fdca3dc840ab Reviewed-by: Shane Kearns <ext-shane.2.kearns@nokia.com>
This commit is contained in:
parent
0da4451b78
commit
07662f93ac
@ -425,6 +425,19 @@
|
|||||||
+ ReuseAddressHint), and on Windows, its equivalent to ShareAddress.
|
+ ReuseAddressHint), and on Windows, its equivalent to ShareAddress.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*! \enum QAbstractSocket::PauseMode
|
||||||
|
\since 5.0
|
||||||
|
|
||||||
|
This enum describes the behavior of when the socket should hold
|
||||||
|
back with continuing data transfer.
|
||||||
|
|
||||||
|
\value PauseNever Do not pause data transfer on the socket. This is the
|
||||||
|
default and matches the behaviour of Qt 4.
|
||||||
|
\value PauseOnNotify Pause data transfer on the socket upon receiving a
|
||||||
|
notification. The only notification currently supported is
|
||||||
|
QSslSocket::sslErrors().
|
||||||
|
*/
|
||||||
|
|
||||||
#include "qabstractsocket.h"
|
#include "qabstractsocket.h"
|
||||||
#include "qabstractsocket_p.h"
|
#include "qabstractsocket_p.h"
|
||||||
|
|
||||||
@ -529,6 +542,7 @@ QAbstractSocketPrivate::QAbstractSocketPrivate()
|
|||||||
abortCalled(false),
|
abortCalled(false),
|
||||||
closeCalled(false),
|
closeCalled(false),
|
||||||
pendingClose(false),
|
pendingClose(false),
|
||||||
|
pauseMode(QAbstractSocket::PauseNever),
|
||||||
port(0),
|
port(0),
|
||||||
localPort(0),
|
localPort(0),
|
||||||
peerPort(0),
|
peerPort(0),
|
||||||
@ -1351,6 +1365,55 @@ QAbstractSocket::~QAbstractSocket()
|
|||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\since 5.0
|
||||||
|
|
||||||
|
Continues data transfer on the socket. This method should only be used
|
||||||
|
after the socket has been set to pause upon notifications and a
|
||||||
|
notification has been received.
|
||||||
|
The only notification currently supported is QSslSocket::sslErrors().
|
||||||
|
Calling this method if the socket is not paused results in undefined
|
||||||
|
behavior.
|
||||||
|
|
||||||
|
\sa pauseMode(), setPauseMode()
|
||||||
|
*/
|
||||||
|
void QAbstractSocket::resume()
|
||||||
|
{
|
||||||
|
Q_D(QAbstractSocket);
|
||||||
|
d->resumeSocketNotifiers(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\since 5.0
|
||||||
|
|
||||||
|
Returns the pause mode of this socket.
|
||||||
|
|
||||||
|
\sa setPauseMode(), resume()
|
||||||
|
*/
|
||||||
|
QAbstractSocket::PauseMode QAbstractSocket::pauseMode() const
|
||||||
|
{
|
||||||
|
return d_func()->pauseMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\since 5.0
|
||||||
|
|
||||||
|
Controls whether to pause upon receiving a notification. The only notification
|
||||||
|
currently supported is QSslSocket::sslErrors(). If set to PauseOnNotify,
|
||||||
|
data transfer on the socket will be paused and needs to be enabled explicitly
|
||||||
|
again by calling resume().
|
||||||
|
By default this option is set to PauseNever.
|
||||||
|
This option must be called before connecting to the server, otherwise it will
|
||||||
|
result in undefined behavior.
|
||||||
|
|
||||||
|
\sa pauseMode(), resume()
|
||||||
|
*/
|
||||||
|
void QAbstractSocket::setPauseMode(PauseMode pauseMode)
|
||||||
|
{
|
||||||
|
d_func()->pauseMode = pauseMode;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\since 5.0
|
\since 5.0
|
||||||
|
|
||||||
|
@ -123,10 +123,18 @@ public:
|
|||||||
ReuseAddressHint = 0x4
|
ReuseAddressHint = 0x4
|
||||||
};
|
};
|
||||||
Q_DECLARE_FLAGS(BindMode, BindFlag)
|
Q_DECLARE_FLAGS(BindMode, BindFlag)
|
||||||
|
enum PauseMode {
|
||||||
|
PauseNever,
|
||||||
|
PauseOnNotify
|
||||||
|
};
|
||||||
|
|
||||||
QAbstractSocket(SocketType socketType, QObject *parent);
|
QAbstractSocket(SocketType socketType, QObject *parent);
|
||||||
virtual ~QAbstractSocket();
|
virtual ~QAbstractSocket();
|
||||||
|
|
||||||
|
virtual void resume(); // to continue after proxy authentication required, SSL errors etc.
|
||||||
|
PauseMode pauseMode() const;
|
||||||
|
void setPauseMode(PauseMode pauseMode);
|
||||||
|
|
||||||
bool bind(const QHostAddress &address, quint16 port = 0, BindMode mode = DefaultForPlatform);
|
bool bind(const QHostAddress &address, quint16 port = 0, BindMode mode = DefaultForPlatform);
|
||||||
bool bind(quint16 port = 0, BindMode mode = DefaultForPlatform);
|
bool bind(quint16 port = 0, BindMode mode = DefaultForPlatform);
|
||||||
|
|
||||||
|
@ -106,6 +106,8 @@ public:
|
|||||||
bool closeCalled;
|
bool closeCalled;
|
||||||
bool pendingClose;
|
bool pendingClose;
|
||||||
|
|
||||||
|
QAbstractSocket::PauseMode pauseMode;
|
||||||
|
|
||||||
QString hostName;
|
QString hostName;
|
||||||
quint16 port;
|
quint16 port;
|
||||||
QHostAddress host;
|
QHostAddress host;
|
||||||
|
@ -355,6 +355,24 @@ QSslSocket::~QSslSocket()
|
|||||||
d->plainSocket = 0;
|
d->plainSocket = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\reimp
|
||||||
|
|
||||||
|
\since 5.0
|
||||||
|
|
||||||
|
Continues data transfer on the socket after it has been paused. If
|
||||||
|
"setPauseMode(QAbstractSocket::PauseOnNotify);" has been called on
|
||||||
|
this socket and a sslErrors() signal is received, calling this method
|
||||||
|
is necessary for the socket to continue.
|
||||||
|
|
||||||
|
\sa QAbstractSocket::pauseMode(), QAbstractSocket::setPauseMode()
|
||||||
|
*/
|
||||||
|
void QSslSocket::resume()
|
||||||
|
{
|
||||||
|
// continuing might emit signals, rather do this through the event loop
|
||||||
|
QMetaObject::invokeMethod(this, "_q_resumeImplementation", Qt::QueuedConnection);
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Starts an encrypted connection to the device \a hostName on \a
|
Starts an encrypted connection to the device \a hostName on \a
|
||||||
port, using \a mode as the \l OpenMode. This is equivalent to
|
port, using \a mode as the \l OpenMode. This is equivalent to
|
||||||
@ -1860,6 +1878,7 @@ QSslSocketPrivate::QSslSocketPrivate()
|
|||||||
, readyReadEmittedPointer(0)
|
, readyReadEmittedPointer(0)
|
||||||
, allowRootCertOnDemandLoading(true)
|
, allowRootCertOnDemandLoading(true)
|
||||||
, plainSocket(0)
|
, plainSocket(0)
|
||||||
|
, paused(false)
|
||||||
{
|
{
|
||||||
QSslConfigurationPrivate::deepCopyDefaultConfiguration(&configuration);
|
QSslConfigurationPrivate::deepCopyDefaultConfiguration(&configuration);
|
||||||
}
|
}
|
||||||
@ -2114,6 +2133,11 @@ void QSslSocketPrivate::resumeSocketNotifiers(QSslSocket *socket)
|
|||||||
QAbstractSocketPrivate::resumeSocketNotifiers(socket->d_func()->plainSocket);
|
QAbstractSocketPrivate::resumeSocketNotifiers(socket->d_func()->plainSocket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool QSslSocketPrivate::isPaused() const
|
||||||
|
{
|
||||||
|
return paused;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\internal
|
\internal
|
||||||
*/
|
*/
|
||||||
@ -2257,6 +2281,55 @@ void QSslSocketPrivate::_q_flushReadBuffer()
|
|||||||
transmit();
|
transmit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\internal
|
||||||
|
*/
|
||||||
|
void QSslSocketPrivate::_q_resumeImplementation()
|
||||||
|
{
|
||||||
|
Q_Q(QSslSocket);
|
||||||
|
if (plainSocket)
|
||||||
|
plainSocket->resume();
|
||||||
|
paused = false;
|
||||||
|
if (!connectionEncrypted) {
|
||||||
|
if (verifyErrorsHaveBeenIgnored()) {
|
||||||
|
continueHandshake();
|
||||||
|
} else {
|
||||||
|
q->setErrorString(sslErrors.first().errorString());
|
||||||
|
q->setSocketError(QAbstractSocket::SslHandshakeFailedError);
|
||||||
|
emit q->error(QAbstractSocket::SslHandshakeFailedError);
|
||||||
|
plainSocket->disconnectFromHost();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
transmit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\internal
|
||||||
|
*/
|
||||||
|
bool QSslSocketPrivate::verifyErrorsHaveBeenIgnored()
|
||||||
|
{
|
||||||
|
bool doEmitSslError;
|
||||||
|
if (!ignoreErrorsList.empty()) {
|
||||||
|
// check whether the errors we got are all in the list of expected errors
|
||||||
|
// (applies only if the method QSslSocket::ignoreSslErrors(const QList<QSslError> &errors)
|
||||||
|
// was called)
|
||||||
|
doEmitSslError = false;
|
||||||
|
for (int a = 0; a < sslErrors.count(); a++) {
|
||||||
|
if (!ignoreErrorsList.contains(sslErrors.at(a))) {
|
||||||
|
doEmitSslError = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// if QSslSocket::ignoreSslErrors(const QList<QSslError> &errors) was not called and
|
||||||
|
// we get an SSL error, emit a signal unless we ignored all errors (by calling
|
||||||
|
// QSslSocket::ignoreSslErrors() )
|
||||||
|
doEmitSslError = !ignoreAllSslErrors;
|
||||||
|
}
|
||||||
|
return !doEmitSslError;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\internal
|
\internal
|
||||||
*/
|
*/
|
||||||
|
@ -82,6 +82,7 @@ public:
|
|||||||
|
|
||||||
QSslSocket(QObject *parent = 0);
|
QSslSocket(QObject *parent = 0);
|
||||||
~QSslSocket();
|
~QSslSocket();
|
||||||
|
void resume(); // to continue after proxy authentication required, SSL errors etc.
|
||||||
|
|
||||||
// Autostarting the SSL client handshake.
|
// Autostarting the SSL client handshake.
|
||||||
void connectToHostEncrypted(const QString &hostName, quint16 port, OpenMode mode = ReadWrite, NetworkLayerProtocol protocol = AnyIPProtocol);
|
void connectToHostEncrypted(const QString &hostName, quint16 port, OpenMode mode = ReadWrite, NetworkLayerProtocol protocol = AnyIPProtocol);
|
||||||
@ -211,6 +212,7 @@ private:
|
|||||||
Q_PRIVATE_SLOT(d_func(), void _q_bytesWrittenSlot(qint64))
|
Q_PRIVATE_SLOT(d_func(), void _q_bytesWrittenSlot(qint64))
|
||||||
Q_PRIVATE_SLOT(d_func(), void _q_flushWriteBuffer())
|
Q_PRIVATE_SLOT(d_func(), void _q_flushWriteBuffer())
|
||||||
Q_PRIVATE_SLOT(d_func(), void _q_flushReadBuffer())
|
Q_PRIVATE_SLOT(d_func(), void _q_flushReadBuffer())
|
||||||
|
Q_PRIVATE_SLOT(d_func(), void _q_resumeImplementation())
|
||||||
friend class QSslSocketBackendPrivate;
|
friend class QSslSocketBackendPrivate;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -295,6 +295,7 @@ bool QSslSocketBackendPrivate::initSslContext()
|
|||||||
bool client = (mode == QSslSocket::SslClientMode);
|
bool client = (mode == QSslSocket::SslClientMode);
|
||||||
|
|
||||||
bool reinitialized = false;
|
bool reinitialized = false;
|
||||||
|
|
||||||
init_context:
|
init_context:
|
||||||
switch (configuration.protocol) {
|
switch (configuration.protocol) {
|
||||||
case QSsl::SslV2:
|
case QSsl::SslV2:
|
||||||
@ -950,6 +951,9 @@ void QSslSocketBackendPrivate::transmit()
|
|||||||
qDebug() << "QSslSocketBackendPrivate::transmit: connection lost";
|
qDebug() << "QSslSocketBackendPrivate::transmit: connection lost";
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
} else if (paused) {
|
||||||
|
// just wait until the user continues
|
||||||
|
return;
|
||||||
} else {
|
} else {
|
||||||
#ifdef QSSLSOCKET_DEBUG
|
#ifdef QSSLSOCKET_DEBUG
|
||||||
qDebug() << "QSslSocketBackendPrivate::transmit: encryption not done yet";
|
qDebug() << "QSslSocketBackendPrivate::transmit: encryption not done yet";
|
||||||
@ -1188,46 +1192,25 @@ bool QSslSocketBackendPrivate::startHandshake()
|
|||||||
sslErrors = errors;
|
sslErrors = errors;
|
||||||
emit q->sslErrors(errors);
|
emit q->sslErrors(errors);
|
||||||
|
|
||||||
bool doEmitSslError;
|
bool doEmitSslError = !verifyErrorsHaveBeenIgnored();
|
||||||
if (!ignoreErrorsList.empty()) {
|
|
||||||
// check whether the errors we got are all in the list of expected errors
|
|
||||||
// (applies only if the method QSslSocket::ignoreSslErrors(const QList<QSslError> &errors)
|
|
||||||
// was called)
|
|
||||||
doEmitSslError = false;
|
|
||||||
for (int a = 0; a < errors.count(); a++) {
|
|
||||||
if (!ignoreErrorsList.contains(errors.at(a))) {
|
|
||||||
doEmitSslError = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// if QSslSocket::ignoreSslErrors(const QList<QSslError> &errors) was not called and
|
|
||||||
// we get an SSL error, emit a signal unless we ignored all errors (by calling
|
|
||||||
// QSslSocket::ignoreSslErrors() )
|
|
||||||
doEmitSslError = !ignoreAllSslErrors;
|
|
||||||
}
|
|
||||||
// check whether we need to emit an SSL handshake error
|
// check whether we need to emit an SSL handshake error
|
||||||
if (doVerifyPeer && doEmitSslError) {
|
if (doVerifyPeer && doEmitSslError) {
|
||||||
q->setErrorString(sslErrors.first().errorString());
|
if (q->pauseMode() == QAbstractSocket::PauseOnNotify) {
|
||||||
q->setSocketError(QAbstractSocket::SslHandshakeFailedError);
|
pauseSocketNotifiers(q);
|
||||||
emit q->error(QAbstractSocket::SslHandshakeFailedError);
|
paused = true;
|
||||||
plainSocket->disconnectFromHost();
|
} else {
|
||||||
|
q->setErrorString(sslErrors.first().errorString());
|
||||||
|
q->setSocketError(QAbstractSocket::SslHandshakeFailedError);
|
||||||
|
emit q->error(QAbstractSocket::SslHandshakeFailedError);
|
||||||
|
plainSocket->disconnectFromHost();
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sslErrors.clear();
|
sslErrors.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we have a max read buffer size, reset the plain socket's to 1k
|
continueHandshake();
|
||||||
if (readBufferMaxSize)
|
|
||||||
plainSocket->setReadBufferSize(1024);
|
|
||||||
|
|
||||||
connectionEncrypted = true;
|
|
||||||
emit q->encrypted();
|
|
||||||
if (autoStartHandshake && pendingClose) {
|
|
||||||
pendingClose = false;
|
|
||||||
q->disconnectFromHost();
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1271,6 +1254,21 @@ QSslCipher QSslSocketBackendPrivate::sessionCipher() const
|
|||||||
return sessionCipher ? QSslCipher_from_SSL_CIPHER(sessionCipher) : QSslCipher();
|
return sessionCipher ? QSslCipher_from_SSL_CIPHER(sessionCipher) : QSslCipher();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QSslSocketBackendPrivate::continueHandshake()
|
||||||
|
{
|
||||||
|
Q_Q(QSslSocket);
|
||||||
|
// if we have a max read buffer size, reset the plain socket's to match
|
||||||
|
if (readBufferMaxSize)
|
||||||
|
plainSocket->setReadBufferSize(readBufferMaxSize);
|
||||||
|
|
||||||
|
connectionEncrypted = true;
|
||||||
|
emit q->encrypted();
|
||||||
|
if (autoStartHandshake && pendingClose) {
|
||||||
|
pendingClose = false;
|
||||||
|
q->disconnectFromHost();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QList<QSslCertificate> QSslSocketBackendPrivate::STACKOFX509_to_QSslCertificates(STACK_OF(X509) *x509)
|
QList<QSslCertificate> QSslSocketBackendPrivate::STACKOFX509_to_QSslCertificates(STACK_OF(X509) *x509)
|
||||||
{
|
{
|
||||||
ensureInitialized();
|
ensureInitialized();
|
||||||
|
@ -115,6 +115,7 @@ public:
|
|||||||
void disconnectFromHost();
|
void disconnectFromHost();
|
||||||
void disconnected();
|
void disconnected();
|
||||||
QSslCipher sessionCipher() const;
|
QSslCipher sessionCipher() const;
|
||||||
|
void continueHandshake();
|
||||||
|
|
||||||
Q_AUTOTEST_EXPORT static long setupOpenSslOptions(QSsl::SslProtocol protocol, QSsl::SslOptions sslOptions);
|
Q_AUTOTEST_EXPORT static long setupOpenSslOptions(QSsl::SslProtocol protocol, QSsl::SslOptions sslOptions);
|
||||||
static QSslCipher QSslCipher_from_SSL_CIPHER(SSL_CIPHER *cipher);
|
static QSslCipher QSslCipher_from_SSL_CIPHER(SSL_CIPHER *cipher);
|
||||||
|
@ -149,6 +149,7 @@ public:
|
|||||||
void createPlainSocket(QIODevice::OpenMode openMode);
|
void createPlainSocket(QIODevice::OpenMode openMode);
|
||||||
static void pauseSocketNotifiers(QSslSocket*);
|
static void pauseSocketNotifiers(QSslSocket*);
|
||||||
static void resumeSocketNotifiers(QSslSocket*);
|
static void resumeSocketNotifiers(QSslSocket*);
|
||||||
|
bool isPaused() const;
|
||||||
void _q_connectedSlot();
|
void _q_connectedSlot();
|
||||||
void _q_hostFoundSlot();
|
void _q_hostFoundSlot();
|
||||||
void _q_disconnectedSlot();
|
void _q_disconnectedSlot();
|
||||||
@ -158,6 +159,7 @@ public:
|
|||||||
void _q_bytesWrittenSlot(qint64);
|
void _q_bytesWrittenSlot(qint64);
|
||||||
void _q_flushWriteBuffer();
|
void _q_flushWriteBuffer();
|
||||||
void _q_flushReadBuffer();
|
void _q_flushReadBuffer();
|
||||||
|
void _q_resumeImplementation();
|
||||||
|
|
||||||
// Platform specific functions
|
// Platform specific functions
|
||||||
virtual void startClientEncryption() = 0;
|
virtual void startClientEncryption() = 0;
|
||||||
@ -166,6 +168,7 @@ public:
|
|||||||
virtual void disconnectFromHost() = 0;
|
virtual void disconnectFromHost() = 0;
|
||||||
virtual void disconnected() = 0;
|
virtual void disconnected() = 0;
|
||||||
virtual QSslCipher sessionCipher() const = 0;
|
virtual QSslCipher sessionCipher() const = 0;
|
||||||
|
virtual void continueHandshake() = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static bool ensureLibraryLoaded();
|
static bool ensureLibraryLoaded();
|
||||||
@ -174,8 +177,10 @@ private:
|
|||||||
static bool s_libraryLoaded;
|
static bool s_libraryLoaded;
|
||||||
static bool s_loadedCiphersAndCerts;
|
static bool s_loadedCiphersAndCerts;
|
||||||
protected:
|
protected:
|
||||||
|
bool verifyErrorsHaveBeenIgnored();
|
||||||
static bool s_loadRootCertsOnDemand;
|
static bool s_loadRootCertsOnDemand;
|
||||||
static QList<QByteArray> unixRootCertDirectories();
|
static QList<QByteArray> unixRootCertDirectories();
|
||||||
|
bool paused;
|
||||||
};
|
};
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
@ -192,10 +192,12 @@ private slots:
|
|||||||
void readFromClosedSocket();
|
void readFromClosedSocket();
|
||||||
void writeBigChunk();
|
void writeBigChunk();
|
||||||
void blacklistedCertificates();
|
void blacklistedCertificates();
|
||||||
void setEmptyDefaultConfiguration();
|
|
||||||
void versionAccessors();
|
void versionAccessors();
|
||||||
void sslOptions();
|
void sslOptions();
|
||||||
void encryptWithoutConnecting();
|
void encryptWithoutConnecting();
|
||||||
|
void resume_data();
|
||||||
|
void resume();
|
||||||
|
void setEmptyDefaultConfiguration(); // this test should be last
|
||||||
|
|
||||||
static void exitLoop()
|
static void exitLoop()
|
||||||
{
|
{
|
||||||
@ -2058,22 +2060,6 @@ void tst_QSslSocket::blacklistedCertificates()
|
|||||||
QCOMPARE(sslErrors.at(0).error(), QSslError::CertificateBlacklisted);
|
QCOMPARE(sslErrors.at(0).error(), QSslError::CertificateBlacklisted);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_QSslSocket::setEmptyDefaultConfiguration()
|
|
||||||
{
|
|
||||||
// used to produce a crash in QSslConfigurationPrivate::deepCopyDefaultConfiguration, QTBUG-13265
|
|
||||||
|
|
||||||
if (!QSslSocket::supportsSsl())
|
|
||||||
return;
|
|
||||||
|
|
||||||
QSslConfiguration emptyConf;
|
|
||||||
QSslConfiguration::setDefaultConfiguration(emptyConf);
|
|
||||||
|
|
||||||
QSslSocketPtr socket = newSocket();
|
|
||||||
connect(socket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(ignoreErrorSlot()));
|
|
||||||
socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443);
|
|
||||||
QVERIFY2(!socket->waitForEncrypted(4000), qPrintable(socket->errorString()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void tst_QSslSocket::versionAccessors()
|
void tst_QSslSocket::versionAccessors()
|
||||||
{
|
{
|
||||||
if (!QSslSocket::supportsSsl())
|
if (!QSslSocket::supportsSsl())
|
||||||
@ -2141,7 +2127,97 @@ void tst_QSslSocket::encryptWithoutConnecting()
|
|||||||
sock.startClientEncryption();
|
sock.startClientEncryption();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QSslSocket::resume_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn<bool>("ignoreErrorsAfterPause");
|
||||||
|
QTest::addColumn<QList<QSslError> >("errorsToIgnore");
|
||||||
|
QTest::addColumn<bool>("expectSuccess");
|
||||||
|
|
||||||
|
QList<QSslError> errorsList;
|
||||||
|
QTest::newRow("DoNotIgnoreErrors") << false << QList<QSslError>() << false;
|
||||||
|
QTest::newRow("ignoreAllErrors") << true << QList<QSslError>() << true;
|
||||||
|
|
||||||
|
QList<QSslCertificate> certs = QSslCertificate::fromPath(QLatin1String(SRCDIR "certs/qt-test-server-cacert.pem"));
|
||||||
|
QSslError rightError(QSslError::SelfSignedCertificate, certs.at(0));
|
||||||
|
QSslError wrongError(QSslError::SelfSignedCertificate);
|
||||||
|
errorsList.append(wrongError);
|
||||||
|
QTest::newRow("ignoreSpecificErrors-Wrong") << true << errorsList << false;
|
||||||
|
errorsList.clear();
|
||||||
|
errorsList.append(rightError);
|
||||||
|
QTest::newRow("ignoreSpecificErrors-Right") << true << errorsList << true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_QSslSocket::resume()
|
||||||
|
{
|
||||||
|
// make sure the server certificate is not in the list of accepted certificates,
|
||||||
|
// we want to trigger the sslErrors signal
|
||||||
|
QSslSocket::setDefaultCaCertificates(QSslSocket::systemCaCertificates());
|
||||||
|
|
||||||
|
QFETCH(bool, ignoreErrorsAfterPause);
|
||||||
|
QFETCH(QList<QSslError>, errorsToIgnore);
|
||||||
|
QFETCH(bool, expectSuccess);
|
||||||
|
|
||||||
|
QSslSocket socket;
|
||||||
|
socket.setPauseMode(QAbstractSocket::PauseOnNotify);
|
||||||
|
|
||||||
|
QSignalSpy sslErrorSpy(&socket, SIGNAL(sslErrors(QList<QSslError>)));
|
||||||
|
QSignalSpy encryptedSpy(&socket, SIGNAL(encrypted()));
|
||||||
|
QSignalSpy errorSpy(&socket, SIGNAL(error(QAbstractSocket::SocketError)));
|
||||||
|
|
||||||
|
connect(&socket, SIGNAL(sslErrors(QList<QSslError>)), &QTestEventLoop::instance(), SLOT(exitLoop()));
|
||||||
|
connect(&socket, SIGNAL(encrypted()), &QTestEventLoop::instance(), SLOT(exitLoop()));
|
||||||
|
connect(&socket, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
|
||||||
|
this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
|
||||||
|
connect(&socket, SIGNAL(error(QAbstractSocket::SocketError)), &QTestEventLoop::instance(), SLOT(exitLoop()));
|
||||||
|
|
||||||
|
socket.connectToHostEncrypted(QtNetworkSettings::serverName(), 993);
|
||||||
|
QTestEventLoop::instance().enterLoop(10);
|
||||||
|
QVERIFY(!QTestEventLoop::instance().timeout());
|
||||||
|
QCOMPARE(sslErrorSpy.count(), 1);
|
||||||
|
QCOMPARE(errorSpy.count(), 0);
|
||||||
|
QCOMPARE(encryptedSpy.count(), 0);
|
||||||
|
QVERIFY(!socket.isEncrypted());
|
||||||
|
if (ignoreErrorsAfterPause) {
|
||||||
|
if (errorsToIgnore.empty())
|
||||||
|
socket.ignoreSslErrors();
|
||||||
|
else
|
||||||
|
socket.ignoreSslErrors(errorsToIgnore);
|
||||||
|
}
|
||||||
|
socket.resume();
|
||||||
|
QTestEventLoop::instance().enterLoop(10);
|
||||||
|
QVERIFY(!QTestEventLoop::instance().timeout()); // quit by encrypted() or error() signal
|
||||||
|
if (expectSuccess) {
|
||||||
|
QCOMPARE(encryptedSpy.count(), 1);
|
||||||
|
QVERIFY(socket.isEncrypted());
|
||||||
|
QCOMPARE(errorSpy.count(), 0);
|
||||||
|
socket.disconnectFromHost();
|
||||||
|
QVERIFY(socket.waitForDisconnected(10000));
|
||||||
|
} else {
|
||||||
|
QCOMPARE(encryptedSpy.count(), 0);
|
||||||
|
QVERIFY(!socket.isEncrypted());
|
||||||
|
QCOMPARE(errorSpy.count(), 1);
|
||||||
|
QCOMPARE(socket.error(), QAbstractSocket::SslHandshakeFailedError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_QSslSocket::setEmptyDefaultConfiguration() // this test should be last, as it has some side effects
|
||||||
|
{
|
||||||
|
// used to produce a crash in QSslConfigurationPrivate::deepCopyDefaultConfiguration, QTBUG-13265
|
||||||
|
|
||||||
|
if (!QSslSocket::supportsSsl())
|
||||||
|
return;
|
||||||
|
|
||||||
|
QSslConfiguration emptyConf;
|
||||||
|
QSslConfiguration::setDefaultConfiguration(emptyConf);
|
||||||
|
|
||||||
|
QSslSocketPtr socket = newSocket();
|
||||||
|
connect(socket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(ignoreErrorSlot()));
|
||||||
|
socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443);
|
||||||
|
QVERIFY2(!socket->waitForEncrypted(4000), qPrintable(socket->errorString()));
|
||||||
|
}
|
||||||
|
|
||||||
#endif // QT_NO_OPENSSL
|
#endif // QT_NO_OPENSSL
|
||||||
|
|
||||||
QTEST_MAIN(tst_QSslSocket)
|
QTEST_MAIN(tst_QSslSocket)
|
||||||
|
|
||||||
#include "tst_qsslsocket.moc"
|
#include "tst_qsslsocket.moc"
|
||||||
|
Loading…
Reference in New Issue
Block a user