tests/auto/qnetworkreply/tst_qnetworkreply.cpp
branchRCL_3
changeset 8 3f74d0d4af4c
parent 4 3b1da2848fc7
child 14 c0432d11811c
--- a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp	Mon Mar 15 12:43:09 2010 +0200
+++ b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp	Thu Apr 08 14:19:33 2010 +0300
@@ -199,6 +199,10 @@
 #endif
     void ioGetFromHttpBrokenServer_data();
     void ioGetFromHttpBrokenServer();
+    void ioGetFromHttpStatus100_data();
+    void ioGetFromHttpStatus100();
+    void ioGetFromHttpNoHeaders_data();
+    void ioGetFromHttpNoHeaders();
     void ioGetFromHttpWithCache_data();
     void ioGetFromHttpWithCache();
 
@@ -257,6 +261,13 @@
 
     void httpConnectionCount();
 
+    void httpReUsingConnectionSequential_data();
+    void httpReUsingConnectionSequential();
+    void httpReUsingConnectionFromFinishedSlot_data();
+    void httpReUsingConnectionFromFinishedSlot();
+
+    void httpRecursiveCreation();
+
 #ifndef QT_NO_OPENSSL
     void ioPostToHttpsUploadProgress();
     void ignoreSslErrorsList_data();
@@ -264,6 +275,9 @@
     void ignoreSslErrorsListWithSlot_data();
     void ignoreSslErrorsListWithSlot();
 #endif
+
+    // NOTE: This test must be last!
+    void parentingRepliesToTheApp();
 };
 
 QT_BEGIN_NAMESPACE
@@ -312,18 +326,20 @@
             QFAIL(qPrintable(errorMsg));        \
     } while (0);
 
+
+// Does not work for POST/PUT!
 class MiniHttpServer: public QTcpServer
 {
     Q_OBJECT
-    QTcpSocket *client;
-
 public:
+    QTcpSocket *client; // always the last one that was received
     QByteArray dataToTransmit;
     QByteArray receivedData;
     bool doClose;
+    bool multiple;
     int totalConnections;
 
-    MiniHttpServer(const QByteArray &data) : client(0), dataToTransmit(data), doClose(true), totalConnections(0)
+    MiniHttpServer(const QByteArray &data) : client(0), dataToTransmit(data), doClose(true), multiple(false), totalConnections(0)
     {
         listen();
         connect(this, SIGNAL(newConnection()), this, SLOT(doAccept()));
@@ -333,15 +349,21 @@
     void doAccept()
     {
         client = nextPendingConnection();
+        client->setParent(this);
         ++totalConnections;
-        connect(client, SIGNAL(readyRead()), this, SLOT(sendData()));
+        connect(client, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
     }
 
-    void sendData()
+    void readyReadSlot()
     {
         receivedData += client->readAll();
-        if (receivedData.contains("\r\n\r\n") ||
-            receivedData.contains("\n\n")) {
+        int doubleEndlPos = receivedData.indexOf("\r\n\r\n");
+
+        if (doubleEndlPos != -1) {
+            // multiple requests incoming. remove the bytes of the current one
+            if (multiple)
+                receivedData.remove(0, doubleEndlPos+4);
+
             client->write(dataToTransmit);
             if (doClose) {
                 client->disconnectFromHost();
@@ -2034,6 +2056,11 @@
     QTest::newRow("invalid-version+disconnect") << QByteArray("HTTP/123 200 ") << true;
     QTest::newRow("invalid-version2+disconnect") << QByteArray("HTTP/a.\033 200 ") << true;
     QTest::newRow("invalid-reply-code+disconnect") << QByteArray("HTTP/1.0 fuu ") << true;
+
+    QTest::newRow("immediate disconnect") << QByteArray("") << true;
+    QTest::newRow("justHalfStatus+disconnect") << QByteArray("HTTP/1.1") << true;
+    QTest::newRow("justStatus+disconnect") << QByteArray("HTTP/1.1 200 OK\r\n") << true;
+    QTest::newRow("justStatusAndHalfHeaders+disconnect") << QByteArray("HTTP/1.1 200 OK\r\nContent-L") << true;
 }
 
 void tst_QNetworkReply::ioGetFromHttpBrokenServer()
@@ -2054,6 +2081,60 @@
     QVERIFY(reply->error() != QNetworkReply::NoError);
 }
 
+void tst_QNetworkReply::ioGetFromHttpStatus100_data()
+{
+    QTest::addColumn<QByteArray>("dataToSend");
+    QTest::newRow("normal") << QByteArray("HTTP/1.1 100 Continue\r\n\r\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
+    QTest::newRow("minimal") << QByteArray("HTTP/1.1 100 Continue\n\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
+    QTest::newRow("minimal2") << QByteArray("HTTP/1.1 100 Continue\n\nHTTP/1.0 200 OK\r\n\r\n");
+    QTest::newRow("minimal3") << QByteArray("HTTP/1.1 100 Continue\n\nHTTP/1.0 200 OK\n\n");
+    QTest::newRow("with_headers") << QByteArray("HTTP/1.1 100 Continue\r\nBla: x\r\n\r\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
+    QTest::newRow("with_headers2") << QByteArray("HTTP/1.1 100 Continue\nBla: x\n\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
+}
+
+void tst_QNetworkReply::ioGetFromHttpStatus100()
+{
+    QFETCH(QByteArray, dataToSend);
+    MiniHttpServer server(dataToSend);
+    server.doClose = true;
+
+    QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
+    QNetworkReplyPtr reply = manager.get(request);
+
+    connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
+    QTestEventLoop::instance().enterLoop(10);
+    QVERIFY(!QTestEventLoop::instance().timeout());
+
+    QCOMPARE(reply->url(), request.url());
+    QCOMPARE(reply->error(), QNetworkReply::NoError);
+    QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
+    QVERIFY(reply->rawHeader("bla").isNull());
+}
+
+void tst_QNetworkReply::ioGetFromHttpNoHeaders_data()
+{
+    QTest::addColumn<QByteArray>("dataToSend");
+    QTest::newRow("justStatus+noheaders+disconnect") << QByteArray("HTTP/1.0 200 OK\r\n\r\n");
+}
+
+void tst_QNetworkReply::ioGetFromHttpNoHeaders()
+{
+    QFETCH(QByteArray, dataToSend);
+    MiniHttpServer server(dataToSend);
+    server.doClose = true;
+
+    QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
+    QNetworkReplyPtr reply = manager.get(request);
+
+    connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
+    QTestEventLoop::instance().enterLoop(10);
+    QVERIFY(!QTestEventLoop::instance().timeout());
+
+    QCOMPARE(reply->url(), request.url());
+    QCOMPARE(reply->error(), QNetworkReply::NoError);
+    QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
+}
+
 void tst_QNetworkReply::ioGetFromHttpWithCache_data()
 {
     qRegisterMetaType<MyMemoryCache::CachedContent>();
@@ -3753,7 +3834,7 @@
     for (int i = 0; i < 10; i++) {
         QNetworkRequest request (QUrl("http://127.0.0.1:" + QString::number(server.serverPort()) + "/" +  QString::number(i)));
         QNetworkReply* reply = manager.get(request);
-        reply->setParent(this);
+        reply->setParent(&server);
     }
 
     int pendingConnectionCount = 0;
@@ -3783,6 +3864,174 @@
 #endif
 }
 
+void tst_QNetworkReply::httpReUsingConnectionSequential_data()
+{
+    QTest::addColumn<bool>("doDeleteLater");
+    QTest::newRow("deleteLater") << true;
+    QTest::newRow("noDeleteLater") << false;
+}
+
+void tst_QNetworkReply::httpReUsingConnectionSequential()
+{
+    QFETCH(bool, doDeleteLater);
+
+    QByteArray response("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
+    MiniHttpServer server(response);
+    server.multiple = true;
+    server.doClose = false;
+
+    QUrl url;
+    url.setScheme("http");
+    url.setPort(server.serverPort());
+    url.setHost("127.0.0.1");
+    // first request
+    QNetworkReply* reply1 = manager.get(QNetworkRequest(url));
+    connect(reply1, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
+    QTestEventLoop::instance().enterLoop(2);
+    QVERIFY(!QTestEventLoop::instance().timeout());
+    QVERIFY(!reply1->error());
+    int reply1port = server.client->peerPort();
+
+    if (doDeleteLater)
+        reply1->deleteLater();
+
+    // finished received, send the next one
+    QNetworkReply*reply2 = manager.get(QNetworkRequest(url));
+    connect(reply2, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
+    QTestEventLoop::instance().enterLoop(2);
+    QVERIFY(!QTestEventLoop::instance().timeout());
+    QVERIFY(!reply2->error());
+    int reply2port = server.client->peerPort(); // should still be the same object
+
+    QVERIFY(reply1port > 0);
+    QCOMPARE(server.totalConnections, 1);
+    QCOMPARE(reply2port, reply1port);
+
+    if (!doDeleteLater)
+        reply1->deleteLater(); // only do it if it was not done earlier
+    reply2->deleteLater();
+}
+
+class HttpReUsingConnectionFromFinishedSlot : public QObject {
+    Q_OBJECT;
+public:
+    QNetworkReply* reply1;
+    QNetworkReply* reply2;
+    QUrl url;
+    QNetworkAccessManager manager;
+public slots:
+    void finishedSlot() {
+        QVERIFY(!reply1->error());
+
+        QFETCH(bool, doDeleteLater);
+        if (doDeleteLater) {
+            reply1->deleteLater();
+            reply1 = 0;
+        }
+
+        // kick off 2nd request and exit the loop when it is done
+        reply2 = manager.get(QNetworkRequest(url));
+        reply2->setParent(this);
+        connect(reply2, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
+    }
+};
+
+void tst_QNetworkReply::httpReUsingConnectionFromFinishedSlot_data()
+{
+    httpReUsingConnectionSequential_data();
+}
+
+void tst_QNetworkReply::httpReUsingConnectionFromFinishedSlot()
+{
+    QByteArray response("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
+    MiniHttpServer server(response);
+    server.multiple = true;
+    server.doClose = false;
+
+    HttpReUsingConnectionFromFinishedSlot helper;
+    helper.reply1 = 0;
+    helper.reply2 = 0;
+    helper.url.setScheme("http");
+    helper.url.setPort(server.serverPort());
+    helper.url.setHost("127.0.0.1");
+
+    // first request
+    helper.reply1 = helper.manager.get(QNetworkRequest(helper.url));
+    helper.reply1->setParent(&helper);
+    connect(helper.reply1, SIGNAL(finished()), &helper, SLOT(finishedSlot()));
+    QTestEventLoop::instance().enterLoop(4);
+    QVERIFY(!QTestEventLoop::instance().timeout());
+
+    QVERIFY(helper.reply2);
+    QVERIFY(!helper.reply2->error());
+
+    QCOMPARE(server.totalConnections, 1);
+}
+
+class HttpRecursiveCreationHelper : public QObject {
+    Q_OBJECT
+public:
+
+    HttpRecursiveCreationHelper():
+            QObject(0),
+            requestsStartedCount_finished(0),
+            requestsStartedCount_readyRead(0),
+            requestsFinishedCount(0)
+    {
+    }
+    QNetworkAccessManager manager;
+    int requestsStartedCount_finished;
+    int requestsStartedCount_readyRead;
+    int requestsFinishedCount;
+public slots:
+    void finishedSlot() {
+        requestsFinishedCount++;
+
+        QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
+        QVERIFY(!reply->error());
+        QVERIFY(reply->bytesAvailable() == 27906);
+
+        if (requestsFinishedCount == 60) {
+            QTestEventLoop::instance().exitLoop();
+            return;
+        }
+
+        if (requestsStartedCount_finished < 30) {
+            startOne();
+            requestsStartedCount_finished++;
+        }
+
+        reply->deleteLater();
+    }
+    void readyReadSlot() {
+        QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
+        QVERIFY(!reply->error());
+
+        if (requestsStartedCount_readyRead < 30 && reply->bytesAvailable() > 27906/2) {
+            startOne();
+            requestsStartedCount_readyRead++;
+        }
+    }
+    void startOne() {
+        QUrl url = "http://" + QtNetworkSettings::serverName() + "/gif/fluke.gif";
+        QNetworkRequest request(url);
+        QNetworkReply *reply = manager.get(request);
+        reply->setParent(this);
+        connect(reply, SIGNAL(finished()), this, SLOT(finishedSlot()));
+        connect(reply, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
+    }
+};
+
+void tst_QNetworkReply::httpRecursiveCreation()
+{
+    // this test checks if creation of new requests to the same host properly works
+    // from readyRead() and finished() signals
+    HttpRecursiveCreationHelper helper;
+    helper.startOne();
+    QTestEventLoop::instance().enterLoop(30);
+    QVERIFY(!QTestEventLoop::instance().timeout());
+}
+
 #ifndef QT_NO_OPENSSL
 void tst_QNetworkReply::ignoreSslErrorsList_data()
 {
@@ -3859,5 +4108,13 @@
 
 #endif // QT_NO_OPENSSL
 
+// NOTE: This test must be last testcase in tst_qnetworkreply!
+void tst_QNetworkReply::parentingRepliesToTheApp()
+{
+    QNetworkRequest request (QUrl("http://" + QtNetworkSettings::serverName()));
+    manager.get(request)->setParent(this); // parent to this object
+    manager.get(request)->setParent(qApp); // parent to the app
+}
+
 QTEST_MAIN(tst_QNetworkReply)
 #include "tst_qnetworkreply.moc"