diff options
author | Kalle Viironen <kalle.viironen@digia.com> | 2012-01-26 12:33:47 +0200 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2012-03-19 15:16:36 +0100 |
commit | 68b1d5c17aa38d5921bdade2b0e0cb67c6c90513 (patch) | |
tree | b759f8421f23876b85c97536bf5277c75593e868 | |
parent | c0b782e8c516245bd534542f3682e7e25a33c414 (diff) |
Fix bug in qsslsocket peek()
Calling peek() for qsslsocket caused socket data to be copied into
qiodevices buffer and therefore make it unaccessible in qsslsocket.
Task-number: QTBUG-18498
Change-Id: Ie27a90a468be8158bd8afcd259dbb34483623c36
Reviewed-by: Shane Kearns <shane.kearns@accenture.com>
-rw-r--r-- | src/network/ssl/qsslsocket.cpp | 35 | ||||
-rw-r--r-- | src/network/ssl/qsslsocket_p.h | 3 | ||||
-rw-r--r-- | tests/auto/qsslsocket/tst_qsslsocket.cpp | 127 |
3 files changed, 165 insertions, 0 deletions
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp index f89b9b3545..7fc36c8523 100644 --- a/src/network/ssl/qsslsocket.cpp +++ b/src/network/ssl/qsslsocket.cpp @@ -2246,6 +2246,41 @@ void QSslSocketPrivate::_q_flushReadBuffer() /*! \internal */ +qint64 QSslSocketPrivate::peek(char *data, qint64 maxSize) +{ + if (mode == QSslSocket::UnencryptedMode && !autoStartHandshake) { + if (plainSocket) + return plainSocket->peek(data, maxSize); + else + return -1; + } else { + QByteArray tmp; + tmp = readBuffer.peek(maxSize); + memcpy(data, tmp.data(), tmp.length()); + return tmp.length(); + } +} + +/*! + \internal +*/ +QByteArray QSslSocketPrivate::peek(qint64 maxSize) +{ + if (mode == QSslSocket::UnencryptedMode && !autoStartHandshake) { + if (plainSocket) + return plainSocket->peek(maxSize); + else + return QByteArray(); + } else { + QByteArray tmp; + tmp = readBuffer.peek(maxSize); + return tmp; + } +} + +/*! + \internal +*/ QList<QByteArray> QSslSocketPrivate::unixRootCertDirectories() { return QList<QByteArray>() << "/etc/ssl/certs/" // (K)ubuntu, OpenSUSE, Mandriva, MeeGo ... diff --git a/src/network/ssl/qsslsocket_p.h b/src/network/ssl/qsslsocket_p.h index 606352b0ba..58515c9f04 100644 --- a/src/network/ssl/qsslsocket_p.h +++ b/src/network/ssl/qsslsocket_p.h @@ -159,6 +159,9 @@ public: void _q_flushWriteBuffer(); void _q_flushReadBuffer(); + virtual qint64 peek(char *data, qint64 maxSize); + virtual QByteArray peek(qint64 maxSize); + // Platform specific functions virtual void startClientEncryption() = 0; virtual void startServerEncryption() = 0; diff --git a/tests/auto/qsslsocket/tst_qsslsocket.cpp b/tests/auto/qsslsocket/tst_qsslsocket.cpp index 961e4da306..cf4d04e07c 100644 --- a/tests/auto/qsslsocket/tst_qsslsocket.cpp +++ b/tests/auto/qsslsocket/tst_qsslsocket.cpp @@ -190,6 +190,7 @@ private slots: void readFromClosedSocket(); void writeBigChunk(); void blacklistedCertificates(); + void qtbug18498_peek(); void setEmptyDefaultConfiguration(); static void exitLoop() @@ -2032,6 +2033,132 @@ void tst_QSslSocket::blacklistedCertificates() QCOMPARE(sslErrors.at(0).error(), QSslError::CertificateBlacklisted); } +class WebSocket : public QSslSocket +{ + Q_OBJECT +public: + explicit WebSocket(int socketDescriptor, + const QString &keyFile = SRCDIR "certs/fluke.key", + const QString &certFile = SRCDIR "certs/fluke.cert"); + +protected slots: + void onReadyReadFirstBytes(void); + +private: + void _startServerEncryption(void); + + QString m_keyFile; + QString m_certFile; + +private: + Q_DISABLE_COPY(WebSocket) +}; + +WebSocket::WebSocket (int socketDescriptor, const QString &keyFile, const QString &certFile) + : m_keyFile(keyFile), + m_certFile(certFile) +{ + QVERIFY(setSocketDescriptor(socketDescriptor, QAbstractSocket::ConnectedState, QIODevice::ReadWrite | QIODevice::Unbuffered)); + connect (this, SIGNAL(readyRead()), this, SLOT(onReadyReadFirstBytes())); +} + +void WebSocket::_startServerEncryption (void) +{ + QFile file(m_keyFile); + QVERIFY(file.open(QIODevice::ReadOnly)); + QSslKey key(file.readAll(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey); + QVERIFY(!key.isNull()); + setPrivateKey(key); + + QList<QSslCertificate> localCert = QSslCertificate::fromPath(m_certFile); + QVERIFY(!localCert.isEmpty()); + QVERIFY(localCert.first().handle()); + setLocalCertificate(localCert.first()); + + QVERIFY(!peerAddress().isNull()); + QVERIFY(peerPort() != 0); + QVERIFY(!localAddress().isNull()); + QVERIFY(localPort() != 0); + + setProtocol(QSsl::AnyProtocol); + setPeerVerifyMode(QSslSocket::VerifyNone); + ignoreSslErrors(); + startServerEncryption(); +} + +void WebSocket::onReadyReadFirstBytes (void) +{ + peek(1); + disconnect(this,SIGNAL(readyRead()), this, SLOT(onReadyReadFirstBytes())); + _startServerEncryption(); +} + +class SslServer4 : public QTcpServer +{ + Q_OBJECT +public: + SslServer4() : socket(0) {} + WebSocket *socket; + +protected: + void incomingConnection(int socketDescriptor) + { + socket = new WebSocket(socketDescriptor); + } +}; + +void tst_QSslSocket::qtbug18498_peek() +{ + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) + return; + + SslServer4 server; + QSslSocket *client = new QSslSocket(this); + + QVERIFY(server.listen(QHostAddress::LocalHost)); + client->connectToHost("127.0.0.1", server.serverPort()); + QVERIFY(client->waitForConnected(5000)); + QVERIFY(server.waitForNewConnection(0)); + client->setObjectName("client"); + client->ignoreSslErrors(); + + connect(client, SIGNAL(encrypted()), this, SLOT(exitLoop())); + connect(client, SIGNAL(disconnected()), this, SLOT(exitLoop())); + + client->startClientEncryption(); + WebSocket *serversocket = server.socket; + QVERIFY(serversocket); + serversocket->setObjectName("server"); + + enterLoop(1); + QVERIFY(!timeout()); + QVERIFY(serversocket->isEncrypted()); + QVERIFY(client->isEncrypted()); + + QByteArray data("abc123"); + client->write(data.data()); + + connect(serversocket, SIGNAL(readyRead()), this, SLOT(exitLoop())); + enterLoop(1); + QVERIFY(!timeout()); + + QByteArray peek1_data; + peek1_data.reserve(data.size()); + QByteArray peek2_data; + QByteArray read_data; + + int lngth = serversocket->peek(peek1_data.data(), 10); + peek1_data.resize(lngth); + + peek2_data = serversocket->peek(10); + read_data = serversocket->readAll(); + + QCOMPARE(peek1_data, data); + QCOMPARE(peek2_data, data); + QCOMPARE(read_data, data); +} + void tst_QSslSocket::setEmptyDefaultConfiguration() { // used to produce a crash in QSslConfigurationPrivate::deepCopyDefaultConfiguration, QTBUG-13265 |