summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTimur Pocheptsov <timur.pocheptsov@theqtcompany.com>2016-09-06 12:36:55 +0200
committerTimur Pocheptsov <timur.pocheptsov@theqtcompany.com>2016-09-27 10:27:58 +0000
commit158781ff2555fabcb9af6b47c887519ade5aba50 (patch)
treefab3a65b3dfd111b853ee70e3f6c222e395b81c6
parentb827b8ccf7311d8bc3551501a5faa6d456da052b (diff)
QSslSocket: respect read buffer's max size (SecureTransport)
1. QSslSocketBackendPrivate::transmit was ignoring 'readBufferMaxSize'; as a result, we can have a user trying to set read buffer's size to a small value (and more important - reading slowly in a small chunks from this socket), but SSL itself socket reading 'too fast', potentially growing its internal buffer to a huge size. This also results in auto-tests failing - whenever we're trying to limit read rate in some test. 2. Update qsslsocket auto-test. Task-number: QTBUG-43388 Task-number: QTBUG-55170 Change-Id: Iedece26df0ac5b3b7cad62cc8c98aedc28e7ca5b Reviewed-by: Richard J. Moore <rich@kde.org>
-rw-r--r--src/network/ssl/qsslsocket_mac.cpp2
-rw-r--r--tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp63
2 files changed, 64 insertions, 1 deletions
diff --git a/src/network/ssl/qsslsocket_mac.cpp b/src/network/ssl/qsslsocket_mac.cpp
index 8aa9269f4b..233f7b5d15 100644
--- a/src/network/ssl/qsslsocket_mac.cpp
+++ b/src/network/ssl/qsslsocket_mac.cpp
@@ -668,7 +668,7 @@ void QSslSocketBackendPrivate::transmit()
if (connectionEncrypted) {
QVarLengthArray<char, 4096> data;
- while (context) {
+ while (context && (!readBufferMaxSize || buffer.size() < readBufferMaxSize)) {
size_t readBytes = 0;
data.resize(4096);
const OSStatus err = SSLRead(context, data.data(), data.size(), &readBytes);
diff --git a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp
index 2d35081dff..9b544e0db8 100644
--- a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp
+++ b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp
@@ -229,6 +229,7 @@ private slots:
void ecdhServer();
void verifyClientCertificate_data();
void verifyClientCertificate();
+ void readBufferMaxSize();
void setEmptyDefaultConfiguration(); // this test should be last
#ifndef QT_NO_OPENSSL
@@ -3043,6 +3044,68 @@ void tst_QSslSocket::verifyClientCertificate()
QCOMPARE(client->isEncrypted(), works);
}
+void tst_QSslSocket::readBufferMaxSize()
+{
+#ifdef QT_SECURETRANSPORT
+ // QTBUG-55170:
+ // SecureTransport back-end was ignoring read-buffer
+ // size limit, resulting (potentially) in a constantly
+ // growing internal buffer.
+ // The test's logic is: we set a small read buffer size on a client
+ // socket (to some ridiculously small value), server sends us
+ // a bunch of bytes , we ignore readReady signal so
+ // that socket's internal buffer size stays
+ // >= readBufferMaxSize, we wait for a quite long time
+ // (which previously would be enough to read completely)
+ // and we check socket's bytesAvaiable to be less than sent.
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy)
+ return;
+
+ SslServer server;
+ QVERIFY(server.listen());
+
+ QEventLoop loop;
+
+ QSslSocketPtr client(new QSslSocket);
+ socket = client.data();
+ connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), &loop, SLOT(quit()));
+ connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot()));
+ connect(socket, SIGNAL(encrypted()), &loop, SLOT(quit()));
+
+ client->connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(),
+ server.serverPort());
+
+ // Wait for 'encrypted' first:
+ QTimer::singleShot(5000, &loop, SLOT(quit()));
+ loop.exec();
+
+ QCOMPARE(client->state(), QAbstractSocket::ConnectedState);
+ QCOMPARE(client->mode(), QSslSocket::SslClientMode);
+
+ client->setReadBufferSize(10);
+ const QByteArray message(int(0xffff), 'a');
+ server.socket->write(message);
+
+ QTimer::singleShot(5000, &loop, SLOT(quit()));
+ loop.exec();
+
+ int readSoFar = client->bytesAvailable();
+ QVERIFY(readSoFar > 0 && readSoFar < message.size());
+ // Now, let's check that we still can read the rest of it:
+ QCOMPARE(client->readAll().size(), readSoFar);
+
+ client->setReadBufferSize(0);
+
+ QTimer::singleShot(1500, &loop, SLOT(quit()));
+ loop.exec();
+
+ QCOMPARE(client->bytesAvailable() + readSoFar, message.size());
+#else
+ // Not needed, QSslSocket works correctly with other back-ends.
+#endif
+}
+
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