From c640e500ed34e9267c654e52fcc1f7a15b9b30e9 Mon Sep 17 00:00:00 2001
From: Markus Goetz <Markus.Goetz@nokia.com>
Date: Tue, 16 Mar 2010 12:24:30 +0100
Subject: QNAM HTTP: Fix no-headers and HTTP-100 handling

Reviewed-by: Thiago
---
 .../access/qhttpnetworkconnectionchannel.cpp       |  1 +
 src/network/access/qhttpnetworkreply.cpp           | 19 +++++--
 src/network/access/qhttpnetworkreply_p.h           |  1 +
 tests/auto/qnetworkreply/tst_qnetworkreply.cpp     | 58 ++++++++++++++++++++++
 4 files changed, 75 insertions(+), 4 deletions(-)

diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
index 806452c..1d8224c 100644
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
@@ -353,6 +353,7 @@ void QHttpNetworkConnectionChannel::_q_receiveReply()
                     replyPrivate->autoDecompress = false;
                 }
                 if (replyPrivate->statusCode == 100) {
+                    replyPrivate->clearHttpLayerInformation();
                     replyPrivate->state = QHttpNetworkReplyPrivate::ReadingStatusState;
                     break; // ignore
                 }
diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp
index 984f557..338236e 100644
--- a/src/network/access/qhttpnetworkreply.cpp
+++ b/src/network/access/qhttpnetworkreply.cpp
@@ -219,7 +219,7 @@ QHttpNetworkReplyPrivate::~QHttpNetworkReplyPrivate()
 {
 }
 
-void QHttpNetworkReplyPrivate::clear()
+void QHttpNetworkReplyPrivate::clearHttpLayerInformation()
 {
     state = NothingDoneState;
     statusCode = 100;
@@ -229,18 +229,24 @@ void QHttpNetworkReplyPrivate::clear()
     currentChunkSize = 0;
     currentChunkRead = 0;
     connectionCloseEnabled = true;
-    connection = 0;
-    connectionChannel = 0;
 #ifndef QT_NO_COMPRESS
     if (initInflate)
         inflateEnd(&inflateStrm);
 #endif
     initInflate = false;
     streamEnd = false;
-    autoDecompress = false;
     fields.clear();
 }
 
+// TODO: Isn't everything HTTP layer related? We don't need to set connection and connectionChannel to 0 at all
+void QHttpNetworkReplyPrivate::clear()
+{
+    connection = 0;
+    connectionChannel = 0;
+    autoDecompress = false;
+    clearHttpLayerInformation();
+}
+
 // QHttpNetworkReplyPrivate
 qint64 QHttpNetworkReplyPrivate::bytesAvailable() const
 {
@@ -539,6 +545,11 @@ qint64 QHttpNetworkReplyPrivate::readHeader(QAbstractSocket *socket)
                     || fragment.endsWith("\r\n\n")
                     || fragment.endsWith("\n\n"))
                     allHeaders = true;
+
+                // there is another case: We have no headers. Then the fragment equals just the line ending
+                if ((fragment.length() == 2 && fragment.endsWith("\r\n"))
+                    || (fragment.length() == 1 && fragment.endsWith("\n")))
+                    allHeaders = true;
             }
         }
     } while (!allHeaders && haveRead > 0);
diff --git a/src/network/access/qhttpnetworkreply_p.h b/src/network/access/qhttpnetworkreply_p.h
index fa240ec..4011c78 100644
--- a/src/network/access/qhttpnetworkreply_p.h
+++ b/src/network/access/qhttpnetworkreply_p.h
@@ -172,6 +172,7 @@ public:
     bool findChallenge(bool forProxy, QByteArray &challenge) const;
     QAuthenticatorPrivate::Method authenticationMethod(bool isProxy) const;
     void clear();
+    void clearHttpLayerInformation();
 
     qint64 readReplyBodyRaw(QIODevice *in, QByteDataBuffer *out, qint64 size);
     qint64 readReplyBodyChunked(QIODevice *in, QByteDataBuffer *out);
diff --git a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp
index 78b4d98..261e613 100644
--- a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp
+++ b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp
@@ -199,6 +199,10 @@ private Q_SLOTS:
 #endif
     void ioGetFromHttpBrokenServer_data();
     void ioGetFromHttpBrokenServer();
+    void ioGetFromHttpStatus100_data();
+    void ioGetFromHttpStatus100();
+    void ioGetFromHttpNoHeaders_data();
+    void ioGetFromHttpNoHeaders();
     void ioGetFromHttpWithCache_data();
     void ioGetFromHttpWithCache();
 
@@ -2074,6 +2078,60 @@ void tst_QNetworkReply::ioGetFromHttpBrokenServer()
     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>();
-- 
cgit v0.12