307 QString errorMsg = call; \ |
317 QString errorMsg = call; \ |
308 if (!errorMsg.isEmpty()) \ |
318 if (!errorMsg.isEmpty()) \ |
309 QFAIL(qPrintable(errorMsg)); \ |
319 QFAIL(qPrintable(errorMsg)); \ |
310 } while (0); |
320 } while (0); |
311 |
321 |
|
322 |
|
323 // Does not work for POST/PUT! |
312 class MiniHttpServer: public QTcpServer |
324 class MiniHttpServer: public QTcpServer |
313 { |
325 { |
314 Q_OBJECT |
326 Q_OBJECT |
315 QTcpSocket *client; |
|
316 |
|
317 public: |
327 public: |
|
328 QTcpSocket *client; // always the last one that was received |
318 QByteArray dataToTransmit; |
329 QByteArray dataToTransmit; |
319 QByteArray receivedData; |
330 QByteArray receivedData; |
320 bool doClose; |
331 bool doClose; |
321 |
332 bool multiple; |
322 MiniHttpServer(const QByteArray &data) : client(0), dataToTransmit(data), doClose(true) |
333 int totalConnections; |
|
334 |
|
335 MiniHttpServer(const QByteArray &data) : client(0), dataToTransmit(data), doClose(true), multiple(false), totalConnections(0) |
323 { |
336 { |
324 listen(); |
337 listen(); |
325 connect(this, SIGNAL(newConnection()), this, SLOT(doAccept())); |
338 connect(this, SIGNAL(newConnection()), this, SLOT(doAccept())); |
326 } |
339 } |
327 |
340 |
328 public slots: |
341 public slots: |
329 void doAccept() |
342 void doAccept() |
330 { |
343 { |
331 client = nextPendingConnection(); |
344 client = nextPendingConnection(); |
332 connect(client, SIGNAL(readyRead()), this, SLOT(sendData())); |
345 client->setParent(this); |
333 } |
346 ++totalConnections; |
334 |
347 connect(client, SIGNAL(readyRead()), this, SLOT(readyReadSlot())); |
335 void sendData() |
348 } |
|
349 |
|
350 void readyReadSlot() |
336 { |
351 { |
337 receivedData += client->readAll(); |
352 receivedData += client->readAll(); |
338 if (receivedData.contains("\r\n\r\n") || |
353 int doubleEndlPos = receivedData.indexOf("\r\n\r\n"); |
339 receivedData.contains("\n\n")) { |
354 |
|
355 if (doubleEndlPos != -1) { |
|
356 // multiple requests incoming. remove the bytes of the current one |
|
357 if (multiple) |
|
358 receivedData.remove(0, doubleEndlPos+4); |
|
359 |
340 client->write(dataToTransmit); |
360 client->write(dataToTransmit); |
341 if (doClose) { |
361 if (doClose) { |
342 client->disconnectFromHost(); |
362 client->disconnectFromHost(); |
343 disconnect(client, 0, this, 0); |
363 disconnect(client, 0, this, 0); |
344 client = 0; |
364 client = 0; |
775 |
851 |
776 QVERIFY(reply.data()); |
852 QVERIFY(reply.data()); |
777 QVERIFY(reply->isOpen()); |
853 QVERIFY(reply->isOpen()); |
778 QVERIFY(reply->isReadable()); |
854 QVERIFY(reply->isReadable()); |
779 QVERIFY(!reply->isWritable()); |
855 QVERIFY(!reply->isWritable()); |
780 QCOMPARE(reply->errorString(), QString("Unknown error")); |
856 |
|
857 // both behaviours are OK since we might change underlying behaviour again |
|
858 if (!reply->isFinished()) |
|
859 QCOMPARE(reply->errorString(), QString("Unknown error")); |
|
860 else |
|
861 QVERIFY(!reply->errorString().isEmpty()); |
|
862 |
781 |
863 |
782 QCOMPARE(reply->manager(), &manager); |
864 QCOMPARE(reply->manager(), &manager); |
783 QCOMPARE(reply->request(), req); |
865 QCOMPARE(reply->request(), req); |
784 QCOMPARE(int(reply->operation()), int(QNetworkAccessManager::GetOperation)); |
866 QCOMPARE(int(reply->operation()), int(QNetworkAccessManager::GetOperation)); |
785 QCOMPARE(reply->error(), QNetworkReply::NoError); |
867 // error and not error are OK since we might change underlying behaviour again |
786 QCOMPARE(reply->isFinished(), false); |
868 if (!reply->isFinished()) |
|
869 QCOMPARE(reply->error(), QNetworkReply::NoError); |
787 QCOMPARE(reply->url(), url); |
870 QCOMPARE(reply->url(), url); |
788 |
871 |
789 reply->abort(); |
872 reply->abort(); |
790 } |
873 } |
791 |
874 |
1980 QTestEventLoop::instance().enterLoop(10); |
2070 QTestEventLoop::instance().enterLoop(10); |
1981 QVERIFY(!QTestEventLoop::instance().timeout()); |
2071 QVERIFY(!QTestEventLoop::instance().timeout()); |
1982 |
2072 |
1983 QCOMPARE(reply->url(), request.url()); |
2073 QCOMPARE(reply->url(), request.url()); |
1984 QVERIFY(reply->error() != QNetworkReply::NoError); |
2074 QVERIFY(reply->error() != QNetworkReply::NoError); |
|
2075 } |
|
2076 |
|
2077 void tst_QNetworkReply::ioGetFromHttpWithCache_data() |
|
2078 { |
|
2079 qRegisterMetaType<MyMemoryCache::CachedContent>(); |
|
2080 QTest::addColumn<QByteArray>("dataToSend"); |
|
2081 QTest::addColumn<QString>("body"); |
|
2082 QTest::addColumn<MyMemoryCache::CachedContent>("cachedReply"); |
|
2083 QTest::addColumn<int>("cacheMode"); |
|
2084 QTest::addColumn<bool>("loadedFromCache"); |
|
2085 QTest::addColumn<bool>("networkUsed"); |
|
2086 |
|
2087 QByteArray reply200 = |
|
2088 "HTTP/1.0 200\r\n" |
|
2089 "Connection: keep-alive\r\n" |
|
2090 "Content-Type: text/plain\r\n" |
|
2091 "Cache-control: no-cache\r\n" |
|
2092 "Content-length: 8\r\n" |
|
2093 "\r\n" |
|
2094 "Reloaded"; |
|
2095 QByteArray reply304 = |
|
2096 "HTTP/1.0 304 Use Cache\r\n" |
|
2097 "Connection: keep-alive\r\n" |
|
2098 "\r\n"; |
|
2099 |
|
2100 QTest::newRow("not-cached,always-network") |
|
2101 << reply200 << "Reloaded" << MyMemoryCache::CachedContent() << int(QNetworkRequest::AlwaysNetwork) << false << true; |
|
2102 QTest::newRow("not-cached,prefer-network") |
|
2103 << reply200 << "Reloaded" << MyMemoryCache::CachedContent() << int(QNetworkRequest::PreferNetwork) << false << true; |
|
2104 QTest::newRow("not-cached,prefer-cache") |
|
2105 << reply200 << "Reloaded" << MyMemoryCache::CachedContent() << int(QNetworkRequest::PreferCache) << false << true; |
|
2106 |
|
2107 QDateTime present = QDateTime::currentDateTime().toUTC(); |
|
2108 QDateTime past = present.addSecs(-3600); |
|
2109 QDateTime future = present.addSecs(3600); |
|
2110 static const char dateFormat[] = "ddd, dd MMM yyyy hh:mm:ss 'GMT'"; |
|
2111 |
|
2112 QNetworkCacheMetaData::RawHeaderList rawHeaders; |
|
2113 MyMemoryCache::CachedContent content; |
|
2114 content.second = "Not-reloaded"; |
|
2115 content.first.setLastModified(past); |
|
2116 |
|
2117 // |
|
2118 // Set to expired |
|
2119 // |
|
2120 rawHeaders.clear(); |
|
2121 rawHeaders << QNetworkCacheMetaData::RawHeader("Date", QLocale::c().toString(past, dateFormat).toLatin1()) |
|
2122 << QNetworkCacheMetaData::RawHeader("Cache-control", "max-age=0"); // isn't used in cache loading |
|
2123 content.first.setRawHeaders(rawHeaders); |
|
2124 content.first.setLastModified(past); |
|
2125 |
|
2126 QTest::newRow("expired,200,prefer-network") |
|
2127 << reply200 << "Reloaded" << content << int(QNetworkRequest::PreferNetwork) << false << true; |
|
2128 QTest::newRow("expired,200,prefer-cache") |
|
2129 << reply200 << "Reloaded" << content << int(QNetworkRequest::PreferCache) << false << true; |
|
2130 |
|
2131 QTest::newRow("expired,304,prefer-network") |
|
2132 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferNetwork) << true << true; |
|
2133 QTest::newRow("expired,304,prefer-cache") |
|
2134 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << true << true; |
|
2135 |
|
2136 // |
|
2137 // Set to not-expired |
|
2138 // |
|
2139 rawHeaders.clear(); |
|
2140 rawHeaders << QNetworkCacheMetaData::RawHeader("Date", QLocale::c().toString(past, dateFormat).toLatin1()) |
|
2141 << QNetworkCacheMetaData::RawHeader("Cache-control", "max-age=7200"); // isn't used in cache loading |
|
2142 content.first.setRawHeaders(rawHeaders); |
|
2143 content.first.setExpirationDate(future); |
|
2144 |
|
2145 QTest::newRow("not-expired,200,always-network") |
|
2146 << reply200 << "Reloaded" << content << int(QNetworkRequest::AlwaysNetwork) << false << true; |
|
2147 QTest::newRow("not-expired,200,prefer-network") |
|
2148 << reply200 << "Not-reloaded" << content << int(QNetworkRequest::PreferNetwork) << true << false; |
|
2149 QTest::newRow("not-expired,200,prefer-cache") |
|
2150 << reply200 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << true << false; |
|
2151 QTest::newRow("not-expired,200,always-cache") |
|
2152 << reply200 << "Not-reloaded" << content << int(QNetworkRequest::AlwaysCache) << true << false; |
|
2153 |
|
2154 QTest::newRow("not-expired,304,prefer-network") |
|
2155 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferNetwork) << true << false; |
|
2156 QTest::newRow("not-expired,304,prefer-cache") |
|
2157 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << true << false; |
|
2158 QTest::newRow("not-expired,304,always-cache") |
|
2159 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::AlwaysCache) << true << false; |
|
2160 |
|
2161 // |
|
2162 // Set must-revalidate now |
|
2163 // |
|
2164 rawHeaders.clear(); |
|
2165 rawHeaders << QNetworkCacheMetaData::RawHeader("Date", QLocale::c().toString(past, dateFormat).toLatin1()) |
|
2166 << QNetworkCacheMetaData::RawHeader("Cache-control", "max-age=7200, must-revalidate"); // must-revalidate is used |
|
2167 content.first.setRawHeaders(rawHeaders); |
|
2168 |
|
2169 QTest::newRow("must-revalidate,200,always-network") |
|
2170 << reply200 << "Reloaded" << content << int(QNetworkRequest::AlwaysNetwork) << false << true; |
|
2171 QTest::newRow("must-revalidate,200,prefer-network") |
|
2172 << reply200 << "Reloaded" << content << int(QNetworkRequest::PreferNetwork) << false << true; |
|
2173 QTest::newRow("must-revalidate,200,prefer-cache") |
|
2174 << reply200 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << true << false; |
|
2175 QTest::newRow("must-revalidate,200,always-cache") |
|
2176 << reply200 << "Not-reloaded" << content << int(QNetworkRequest::AlwaysCache) << true << false; |
|
2177 |
|
2178 QTest::newRow("must-revalidate,304,prefer-network") |
|
2179 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferNetwork) << true << true; |
|
2180 QTest::newRow("must-revalidate,304,prefer-cache") |
|
2181 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << true << false; |
|
2182 QTest::newRow("must-revalidate,304,always-cache") |
|
2183 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::AlwaysCache) << true << false; |
|
2184 } |
|
2185 |
|
2186 void tst_QNetworkReply::ioGetFromHttpWithCache() |
|
2187 { |
|
2188 QFETCH(QByteArray, dataToSend); |
|
2189 MiniHttpServer server(dataToSend); |
|
2190 server.doClose = false; |
|
2191 |
|
2192 MyMemoryCache *memoryCache = new MyMemoryCache(&manager); |
|
2193 manager.setCache(memoryCache); |
|
2194 |
|
2195 QFETCH(MyMemoryCache::CachedContent, cachedReply); |
|
2196 QUrl url = "http://localhost:" + QString::number(server.serverPort()); |
|
2197 cachedReply.first.setUrl(url); |
|
2198 if (!cachedReply.second.isNull()) |
|
2199 memoryCache->cache.insert(url.toEncoded(), cachedReply); |
|
2200 |
|
2201 QFETCH(int, cacheMode); |
|
2202 QNetworkRequest request(url); |
|
2203 request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, cacheMode); |
|
2204 request.setAttribute(QNetworkRequest::CacheSaveControlAttribute, false); |
|
2205 QNetworkReplyPtr reply = manager.get(request); |
|
2206 |
|
2207 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); |
|
2208 QTestEventLoop::instance().enterLoop(10); |
|
2209 QVERIFY(!QTestEventLoop::instance().timeout()); |
|
2210 |
|
2211 QTEST(reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool(), "loadedFromCache"); |
|
2212 QTEST(server.totalConnections > 0, "networkUsed"); |
|
2213 QFETCH(QString, body); |
|
2214 QCOMPARE(reply->readAll().constData(), qPrintable(body)); |
1985 } |
2215 } |
1986 |
2216 |
1987 void tst_QNetworkReply::ioGetWithManyProxies_data() |
2217 void tst_QNetworkReply::ioGetWithManyProxies_data() |
1988 { |
2218 { |
1989 QTest::addColumn<QList<QNetworkProxy> >("proxyList"); |
2219 QTest::addColumn<QList<QNetworkProxy> >("proxyList"); |
3571 #else |
3801 #else |
3572 QCOMPARE(pendingConnectionCount, 6); |
3802 QCOMPARE(pendingConnectionCount, 6); |
3573 #endif |
3803 #endif |
3574 } |
3804 } |
3575 |
3805 |
|
3806 void tst_QNetworkReply::httpReUsingConnectionSequential_data() |
|
3807 { |
|
3808 QTest::addColumn<bool>("doDeleteLater"); |
|
3809 QTest::newRow("deleteLater") << true; |
|
3810 QTest::newRow("noDeleteLater") << false; |
|
3811 } |
|
3812 |
|
3813 void tst_QNetworkReply::httpReUsingConnectionSequential() |
|
3814 { |
|
3815 QFETCH(bool, doDeleteLater); |
|
3816 |
|
3817 QByteArray response("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); |
|
3818 MiniHttpServer server(response); |
|
3819 server.multiple = true; |
|
3820 server.doClose = false; |
|
3821 |
|
3822 QUrl url; |
|
3823 url.setScheme("http"); |
|
3824 url.setPort(server.serverPort()); |
|
3825 url.setHost("127.0.0.1"); |
|
3826 // first request |
|
3827 QNetworkReply* reply1 = manager.get(QNetworkRequest(url)); |
|
3828 connect(reply1, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); |
|
3829 QTestEventLoop::instance().enterLoop(2); |
|
3830 QVERIFY(!QTestEventLoop::instance().timeout()); |
|
3831 QVERIFY(!reply1->error()); |
|
3832 int reply1port = server.client->peerPort(); |
|
3833 |
|
3834 if (doDeleteLater) |
|
3835 reply1->deleteLater(); |
|
3836 |
|
3837 // finished received, send the next one |
|
3838 QNetworkReply*reply2 = manager.get(QNetworkRequest(url)); |
|
3839 connect(reply2, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); |
|
3840 QTestEventLoop::instance().enterLoop(2); |
|
3841 QVERIFY(!QTestEventLoop::instance().timeout()); |
|
3842 QVERIFY(!reply2->error()); |
|
3843 int reply2port = server.client->peerPort(); // should still be the same object |
|
3844 |
|
3845 QVERIFY(reply1port > 0); |
|
3846 QCOMPARE(server.totalConnections, 1); |
|
3847 QCOMPARE(reply2port, reply1port); |
|
3848 |
|
3849 if (!doDeleteLater) |
|
3850 reply1->deleteLater(); // only do it if it was not done earlier |
|
3851 reply2->deleteLater(); |
|
3852 } |
|
3853 |
|
3854 class HttpReUsingConnectionFromFinishedSlot : public QObject { |
|
3855 Q_OBJECT; |
|
3856 public: |
|
3857 QNetworkReply* reply1; |
|
3858 QNetworkReply* reply2; |
|
3859 QUrl url; |
|
3860 QNetworkAccessManager manager; |
|
3861 public slots: |
|
3862 void finishedSlot() { |
|
3863 QVERIFY(!reply1->error()); |
|
3864 |
|
3865 QFETCH(bool, doDeleteLater); |
|
3866 if (doDeleteLater) { |
|
3867 reply1->deleteLater(); |
|
3868 reply1 = 0; |
|
3869 } |
|
3870 |
|
3871 // kick off 2nd request and exit the loop when it is done |
|
3872 reply2 = manager.get(QNetworkRequest(url)); |
|
3873 reply2->setParent(this); |
|
3874 connect(reply2, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); |
|
3875 } |
|
3876 }; |
|
3877 |
|
3878 void tst_QNetworkReply::httpReUsingConnectionFromFinishedSlot_data() |
|
3879 { |
|
3880 httpReUsingConnectionSequential_data(); |
|
3881 } |
|
3882 |
|
3883 void tst_QNetworkReply::httpReUsingConnectionFromFinishedSlot() |
|
3884 { |
|
3885 QByteArray response("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); |
|
3886 MiniHttpServer server(response); |
|
3887 server.multiple = true; |
|
3888 server.doClose = false; |
|
3889 |
|
3890 HttpReUsingConnectionFromFinishedSlot helper; |
|
3891 helper.reply1 = 0; |
|
3892 helper.reply2 = 0; |
|
3893 helper.url.setScheme("http"); |
|
3894 helper.url.setPort(server.serverPort()); |
|
3895 helper.url.setHost("127.0.0.1"); |
|
3896 |
|
3897 // first request |
|
3898 helper.reply1 = helper.manager.get(QNetworkRequest(helper.url)); |
|
3899 helper.reply1->setParent(&helper); |
|
3900 connect(helper.reply1, SIGNAL(finished()), &helper, SLOT(finishedSlot())); |
|
3901 QTestEventLoop::instance().enterLoop(4); |
|
3902 QVERIFY(!QTestEventLoop::instance().timeout()); |
|
3903 |
|
3904 QVERIFY(helper.reply2); |
|
3905 QVERIFY(!helper.reply2->error()); |
|
3906 |
|
3907 QCOMPARE(server.totalConnections, 1); |
|
3908 } |
|
3909 |
|
3910 class HttpRecursiveCreationHelper : public QObject { |
|
3911 Q_OBJECT |
|
3912 public: |
|
3913 |
|
3914 HttpRecursiveCreationHelper(): |
|
3915 QObject(0), |
|
3916 requestsStartedCount_finished(0), |
|
3917 requestsStartedCount_readyRead(0), |
|
3918 requestsFinishedCount(0) |
|
3919 { |
|
3920 } |
|
3921 QNetworkAccessManager manager; |
|
3922 int requestsStartedCount_finished; |
|
3923 int requestsStartedCount_readyRead; |
|
3924 int requestsFinishedCount; |
|
3925 public slots: |
|
3926 void finishedSlot() { |
|
3927 requestsFinishedCount++; |
|
3928 |
|
3929 QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender()); |
|
3930 QVERIFY(!reply->error()); |
|
3931 QVERIFY(reply->bytesAvailable() == 27906); |
|
3932 |
|
3933 if (requestsFinishedCount == 60) { |
|
3934 QTestEventLoop::instance().exitLoop(); |
|
3935 return; |
|
3936 } |
|
3937 |
|
3938 if (requestsStartedCount_finished < 30) { |
|
3939 startOne(); |
|
3940 requestsStartedCount_finished++; |
|
3941 } |
|
3942 |
|
3943 reply->deleteLater(); |
|
3944 } |
|
3945 void readyReadSlot() { |
|
3946 QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender()); |
|
3947 QVERIFY(!reply->error()); |
|
3948 |
|
3949 if (requestsStartedCount_readyRead < 30 && reply->bytesAvailable() > 27906/2) { |
|
3950 startOne(); |
|
3951 requestsStartedCount_readyRead++; |
|
3952 } |
|
3953 } |
|
3954 void startOne() { |
|
3955 QUrl url = "http://" + QtNetworkSettings::serverName() + "/gif/fluke.gif"; |
|
3956 QNetworkRequest request(url); |
|
3957 QNetworkReply *reply = manager.get(request); |
|
3958 reply->setParent(this); |
|
3959 connect(reply, SIGNAL(finished()), this, SLOT(finishedSlot())); |
|
3960 connect(reply, SIGNAL(readyRead()), this, SLOT(readyReadSlot())); |
|
3961 } |
|
3962 }; |
|
3963 |
|
3964 void tst_QNetworkReply::httpRecursiveCreation() |
|
3965 { |
|
3966 // this test checks if creation of new requests to the same host properly works |
|
3967 // from readyRead() and finished() signals |
|
3968 HttpRecursiveCreationHelper helper; |
|
3969 helper.startOne(); |
|
3970 QTestEventLoop::instance().enterLoop(30); |
|
3971 QVERIFY(!QTestEventLoop::instance().timeout()); |
|
3972 } |
|
3973 |
3576 #ifndef QT_NO_OPENSSL |
3974 #ifndef QT_NO_OPENSSL |
3577 void tst_QNetworkReply::ignoreSslErrorsList_data() |
3975 void tst_QNetworkReply::ignoreSslErrorsList_data() |
3578 { |
3976 { |
3579 QTest::addColumn<QString>("url"); |
3977 QTest::addColumn<QString>("url"); |
3580 QTest::addColumn<QList<QSslError> >("expectedSslErrors"); |
3978 QTest::addColumn<QList<QSslError> >("expectedSslErrors"); |