From ecd5366c0552d758a38cae4949b76a816d18a0ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20Andr=C3=A9=20Vadla=20Ravn=C3=A5s?= Date: Wed, 29 Jun 2011 03:29:35 +0200 Subject: [PATCH 1/2] network: add autotest for QNetworkDiskCache crash Reproduces crash when creating a cache-invalidating request on QNetworkAccessManager while another request with the same URL is already in progress. http://bugreports.qt.nokia.com/browse/QTBUG-20162 --- .../qnetworkdiskcache/tst_qnetworkdiskcache.cpp | 83 ++++++++++++++++++-- 1 files changed, 75 insertions(+), 8 deletions(-) diff --git a/tests/auto/qnetworkdiskcache/tst_qnetworkdiskcache.cpp b/tests/auto/qnetworkdiskcache/tst_qnetworkdiskcache.cpp index 63d6d0e..6dffb9d 100644 --- a/tests/auto/qnetworkdiskcache/tst_qnetworkdiskcache.cpp +++ b/tests/auto/qnetworkdiskcache/tst_qnetworkdiskcache.cpp @@ -80,6 +80,7 @@ private slots: void sync(); void crashWhenParentingCache(); + void crashWithOverlappingRequestsForSameUrl(); }; // FIXME same as in tst_qnetworkreply.cpp .. could be unified @@ -88,23 +89,33 @@ class MiniHttpServer: public QTcpServer { Q_OBJECT public: - QTcpSocket *client; // always the last one that was received + QList lingeringClients; QByteArray dataToTransmit; QByteArray receivedData; bool doClose; bool multiple; int totalConnections; - MiniHttpServer(const QByteArray &data) : client(0), dataToTransmit(data), doClose(true), multiple(false), totalConnections(0) + MiniHttpServer(const QByteArray &data) : dataToTransmit(data), doClose(true), multiple(false), totalConnections(0) { listen(); connect(this, SIGNAL(newConnection()), this, SLOT(doAccept())); } + void finishLingeringClients(const QByteArray &goodByeData) + { + Q_FOREACH(QTcpSocket *client, lingeringClients) { + if (goodByeData.size() > 0) + client->write(goodByeData); + disconnectClient(client); + } + lingeringClients.clear(); + } + public slots: void doAccept() { - client = nextPendingConnection(); + QTcpSocket *client = nextPendingConnection(); client->setParent(this); ++totalConnections; connect(client, SIGNAL(readyRead()), this, SLOT(readyReadSlot())); @@ -112,6 +123,8 @@ public slots: void readyReadSlot() { + QTcpSocket *client = static_cast(sender()); + receivedData += client->readAll(); int doubleEndlPos = receivedData.indexOf("\r\n\r\n"); @@ -121,13 +134,19 @@ public slots: receivedData.remove(0, doubleEndlPos+4); client->write(dataToTransmit); - if (doClose) { - client->disconnectFromHost(); - disconnect(client, 0, this, 0); - client = 0; - } + if (doClose) + disconnectClient(client); + else + lingeringClients.append(client); } } + +private: + void disconnectClient(QTcpSocket *client) + { + client->disconnectFromHost(); + disconnect(client, 0, this, 0); + } }; // Subclass that exposes the protected functions. @@ -658,6 +677,54 @@ void tst_QNetworkDiskCache::crashWhenParentingCache() delete manager; // crashed before.. } +void tst_QNetworkDiskCache::crashWithOverlappingRequestsForSameUrl() +{ + QByteArray data("HTTP/1.0 200 OK\r\nContent-Type: application/octet-stream\r\nContent-Length: 5\r\n\r\nHel"); + MiniHttpServer server(data); + + server.doClose = false; + + QNetworkAccessManager *manager = new QNetworkAccessManager(); + QNetworkDiskCache *diskCache = new QNetworkDiskCache(manager); + diskCache->setCacheDirectory(QString("%1/cacheDir_%2").arg(QDir::tempPath()).arg(QCoreApplication::applicationPid())); + manager->setCache(diskCache); + + QUrl url("http://127.0.0.1:" + QString::number(server.serverPort()) + "/resource"); + + QNetworkRequest firstRequest(url); + QNetworkReply *firstReply = manager->get(firstRequest); + connect(firstReply, SIGNAL(readyRead()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(5); + QVERIFY(!QTestEventLoop::instance().timeout()); + + server.finishLingeringClients(QString("lo").toUtf8()); + + QNetworkRequest secondRequest(url); + QNetworkReply *secondReply = manager->post(secondRequest, QByteArray()); + connect(secondReply, SIGNAL(readyRead()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(5); + QVERIFY(!QTestEventLoop::instance().timeout()); + + if (!firstReply->isFinished()) { + connect(firstReply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(5); + QVERIFY(!QTestEventLoop::instance().timeout()); + } + + if (!secondReply->isFinished()) { + server.finishLingeringClients(QString("lo").toUtf8()); + + connect(secondReply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(5); + QVERIFY(!QTestEventLoop::instance().timeout()); + } + + QCOMPARE(firstReply->error(), QNetworkReply::NoError); + QCOMPARE(secondReply->error(), QNetworkReply::NoError); + + delete manager; +} + void tst_QNetworkDiskCache::sync() { // This tests would be a nice to have, but is currently not supported. -- 1.7.3.4