1 /****************************************************************************
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the test suite of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
40 ****************************************************************************/
43 #include <QtTest/QtTest>
44 #include <QtCore/QCryptographicHash>
45 #include <QtCore/QDataStream>
46 #include <QtCore/QUrl>
47 #include <QtCore/QEventLoop>
48 #include <QtCore/QFile>
49 #include <QtCore/QSharedPointer>
50 #include <QtCore/QScopedPointer>
51 #include <QtCore/QTemporaryFile>
52 #include <QtNetwork/QTcpServer>
53 #include <QtNetwork/QTcpSocket>
54 #include <QtNetwork/QLocalSocket>
55 #include <QtNetwork/QLocalServer>
56 #include <QtNetwork/QHostInfo>
57 #include <QtNetwork/QNetworkAccessManager>
58 #include <QtNetwork/QNetworkRequest>
59 #include <QtNetwork/QNetworkReply>
60 #include <QtNetwork/QAbstractNetworkCache>
61 #include <QtNetwork/qauthenticator.h>
62 #include <QtNetwork/qnetworkaccessmanager.h>
63 #include <QtNetwork/qnetworkrequest.h>
64 #include <QtNetwork/qnetworkreply.h>
65 #include <QtNetwork/qnetworkcookie.h>
66 #include <QtNetwork/QNetworkCookieJar>
67 #include <QtNetwork/QHttpPart>
68 #include <QtNetwork/QHttpMultiPart>
69 #include <QtNetwork/QNetworkProxyQuery>
71 #include <QtNetwork/qsslerror.h>
72 #include <QtNetwork/qsslconfiguration.h>
74 #ifndef QT_NO_BEARERMANAGEMENT
75 #include <QtNetwork/qnetworkconfigmanager.h>
76 #include <QtNetwork/qnetworkconfiguration.h>
77 #include <QtNetwork/qnetworksession.h>
78 #include <QtNetwork/private/qnetworksession_p.h>
80 #ifdef QT_BUILD_INTERNAL
81 #include <QtNetwork/private/qnetworkreplyimpl_p.h> // implicitly included by qnetworkaccessmanager_p.h currently, but don't rely on that being true forever
82 #include <QtNetwork/private/qnetworkaccessmanager_p.h>
84 Q_DECLARE_METATYPE(QSharedPointer<char>)
88 # include <sys/types.h>
89 # include <unistd.h> // for getuid()
93 #include "../../../network-settings.h"
95 Q_DECLARE_METATYPE(QNetworkReply*)
96 Q_DECLARE_METATYPE(QAuthenticator*)
97 Q_DECLARE_METATYPE(QNetworkProxyQuery)
98 Q_DECLARE_METATYPE(QBuffer*)
99 Q_DECLARE_METATYPE(QHttpMultiPart *)
100 Q_DECLARE_METATYPE(QList<QFile*>) // for multiparts
102 typedef QSharedPointer<QNetworkReply> QNetworkReplyPtr;
105 class tst_QNetworkReply: public QObject
110 ProxyData(const QNetworkProxy &p, const QByteArray &t, bool auth)
111 : tag(t), proxy(p), requiresAuthentication(auth)
115 bool requiresAuthentication;
118 static bool seedCreated;
119 static QString createUniqueExtension() {
121 qsrand(QTime(0,0,0).msecsTo(QTime::currentTime()) + QCoreApplication::applicationPid());
122 seedCreated = true; // not thread-safe, but who cares
124 QString s = QString("%1-%2-%3").arg(QTime(0,0,0).msecsTo(QTime::currentTime())).arg(QCoreApplication::applicationPid()).arg(qrand());
129 enum RunSimpleRequestReturn { Timeout = 0, Success, Failure };
131 QString testFileName;
132 QString echoProcessDir;
133 #if !defined Q_OS_WIN
134 QString wronlyFileName;
136 QString uniqueExtension;
137 QList<ProxyData> proxies;
138 QNetworkAccessManager manager;
139 MyCookieJar *cookieJar;
141 QSslConfiguration storedSslConfiguration;
142 QList<QSslError> storedExpectedSslErrors;
144 #ifndef QT_NO_BEARERMANAGEMENT
145 QNetworkConfigurationManager *netConfMan;
146 QNetworkConfiguration networkConfiguration;
147 QScopedPointer<QNetworkSession> networkSession;
150 using QObject::connect;
151 static bool connect(const QNetworkReplyPtr &ptr, const char *signal, const QObject *receiver, const char *slot, Qt::ConnectionType ct = Qt::AutoConnection)
152 { return connect(ptr.data(), signal, receiver, slot, ct); }
153 bool connect(const QNetworkReplyPtr &ptr, const char *signal, const char *slot, Qt::ConnectionType ct = Qt::AutoConnection)
154 { return connect(ptr.data(), signal, slot, ct); }
158 ~tst_QNetworkReply();
159 QString runSimpleRequest(QNetworkAccessManager::Operation op, const QNetworkRequest &request,
160 QNetworkReplyPtr &reply, const QByteArray &data = QByteArray());
161 QString runMultipartRequest(const QNetworkRequest &request, QNetworkReplyPtr &reply,
162 QHttpMultiPart *multiPart, const QByteArray &verb);
164 QString runCustomRequest(const QNetworkRequest &request, QNetworkReplyPtr &reply,
165 const QByteArray &verb, QIODevice *data);
166 int waitForFinish(QNetworkReplyPtr &reply);
171 void authenticationRequired(QNetworkReply*,QAuthenticator*);
172 void proxyAuthenticationRequired(const QNetworkProxy &,QAuthenticator*);
173 void pipeliningHelperSlot();
176 void sslErrors(QNetworkReply*,const QList<QSslError> &);
177 void storeSslConfiguration();
178 void ignoreSslErrorListSlot(QNetworkReply *reply, const QList<QSslError> &);
182 void nestedEventLoops_slot();
188 void cleanupTestCase();
190 void stateChecking();
191 void invalidProtocol();
192 void getFromData_data();
195 void getFromFileSpecial_data();
196 void getFromFileSpecial();
197 void getFromFtp_data();
199 void getFromHttp_data();
201 void getErrors_data();
203 void headFromHttp_data();
205 void putToFile_data();
207 void putToFtp_data();
209 void putToHttp_data();
211 void putToHttpSynchronous_data();
212 void putToHttpSynchronous();
213 void putToHttpMultipart_data();
214 void putToHttpMultipart();
215 void postToHttp_data();
217 void postToHttpSynchronous_data();
218 void postToHttpSynchronous();
219 void postToHttpMultipart_data();
220 void postToHttpMultipart();
221 void deleteFromHttp_data();
222 void deleteFromHttp();
223 void putGetDeleteGetFromHttp_data();
224 void putGetDeleteGetFromHttp();
225 void sendCustomRequestToHttp_data();
226 void sendCustomRequestToHttp();
227 void connectToIPv6Address_data();
228 void connectToIPv6Address();
230 void ioGetFromData_data();
231 void ioGetFromData();
232 void ioGetFromFileSpecial_data();
233 void ioGetFromFileSpecial();
234 void ioGetFromFile_data();
235 void ioGetFromFile();
236 void ioGetFromFtp_data();
238 void ioGetFromFtpWithReuse();
239 void ioGetFromHttp();
241 void ioGetFromBuiltinHttp_data();
242 void ioGetFromBuiltinHttp();
243 void ioGetFromHttpWithReuseParallel();
244 void ioGetFromHttpWithReuseSequential();
245 void ioGetFromHttpWithAuth_data();
246 void ioGetFromHttpWithAuth();
247 void ioGetFromHttpWithAuthSynchronous();
248 void ioGetFromHttpWithProxyAuth();
249 void ioGetFromHttpWithProxyAuthSynchronous();
250 void ioGetFromHttpWithSocksProxy();
252 void ioGetFromHttpsWithSslErrors();
253 void ioGetFromHttpsWithIgnoreSslErrors();
254 void ioGetFromHttpsWithSslHandshakeError();
256 void ioGetFromHttpBrokenServer_data();
257 void ioGetFromHttpBrokenServer();
258 void ioGetFromHttpStatus100_data();
259 void ioGetFromHttpStatus100();
260 void ioGetFromHttpNoHeaders_data();
261 void ioGetFromHttpNoHeaders();
262 void ioGetFromHttpWithCache_data();
263 void ioGetFromHttpWithCache();
265 void ioGetWithManyProxies_data();
266 void ioGetWithManyProxies();
268 void ioPutToFileFromFile_data();
269 void ioPutToFileFromFile();
270 void ioPutToFileFromSocket_data();
271 void ioPutToFileFromSocket();
272 void ioPutToFileFromLocalSocket_data();
273 void ioPutToFileFromLocalSocket();
274 #ifndef QT_NO_PROCESS
275 void ioPutToFileFromProcess_data();
276 void ioPutToFileFromProcess();
278 void ioPutToFtpFromFile_data();
279 void ioPutToFtpFromFile();
280 void ioPutToHttpFromFile_data();
281 void ioPutToHttpFromFile();
282 void ioPostToHttpFromFile_data();
283 void ioPostToHttpFromFile();
284 void ioPostToHttpFromSocket_data();
285 void ioPostToHttpFromSocket();
286 void ioPostToHttpFromSocketSynchronous();
287 void ioPostToHttpFromSocketSynchronous_data();
288 void ioPostToHttpFromMiddleOfFileToEnd();
289 void ioPostToHttpFromMiddleOfFileFiveBytes();
290 void ioPostToHttpFromMiddleOfQBufferFiveBytes();
291 void ioPostToHttpNoBufferFlag();
292 void ioPostToHttpUploadProgress();
293 void ioPostToHttpEmptyUploadProgress();
295 void lastModifiedHeaderForFile();
296 void lastModifiedHeaderForHttp();
298 void httpCanReadLine();
300 #ifdef QT_BUILD_INTERNAL
301 void rateControl_data();
305 void downloadProgress_data();
306 void downloadProgress();
307 #ifdef QT_BUILD_INTERNAL
308 void uploadProgress_data();
309 void uploadProgress();
312 void chaining_data();
315 void receiveCookiesFromHttp_data();
316 void receiveCookiesFromHttp();
317 void receiveCookiesFromHttpSynchronous_data();
318 void receiveCookiesFromHttpSynchronous();
319 void sendCookies_data();
321 void sendCookiesSynchronous_data();
322 void sendCookiesSynchronous();
324 void nestedEventLoops();
326 void httpProxyCommands_data();
327 void httpProxyCommands();
328 void httpProxyCommandsSynchronous_data();
329 void httpProxyCommandsSynchronous();
331 void authorizationError_data();
332 void authorizationError();
334 void httpConnectionCount();
336 void httpReUsingConnectionSequential_data();
337 void httpReUsingConnectionSequential();
338 void httpReUsingConnectionFromFinishedSlot_data();
339 void httpReUsingConnectionFromFinishedSlot();
341 void httpRecursiveCreation();
344 void ioPostToHttpsUploadProgress();
345 void ignoreSslErrorsList_data();
346 void ignoreSslErrorsList();
347 void ignoreSslErrorsListWithSlot_data();
348 void ignoreSslErrorsListWithSlot();
349 void sslConfiguration_data();
350 void sslConfiguration();
353 void getAndThenDeleteObject_data();
354 void getAndThenDeleteObject();
356 void symbianOpenCDataUrlCrash();
358 void getFromHttpIntoBuffer_data();
359 void getFromHttpIntoBuffer();
360 void getFromHttpIntoBuffer2_data();
361 void getFromHttpIntoBuffer2();
362 void getFromHttpIntoBufferCanReadLine();
364 void ioGetFromHttpWithoutContentLength();
366 void ioGetFromHttpBrokenChunkedEncoding();
367 void qtbug12908compressedHttpReply();
368 void compressedHttpReplyBrokenGzip();
370 void getFromUnreachableIp();
372 void qtbug4121unknownAuthentication();
374 void qtbug13431replyThrottling();
376 void httpWithNoCredentialUsage();
378 void qtbug15311doubleContentLength();
380 void qtbug18232gzipContentLengthZero();
381 void qtbug22660gzipNoContentLengthEmptyContent();
383 void qtbug27161httpHeaderMayBeDamaged_data();
384 void qtbug27161httpHeaderMayBeDamaged();
386 void synchronousRequest_data();
387 void synchronousRequest();
389 void synchronousRequestSslFailure();
394 void dontInsertPartialContentIntoTheCache();
396 void httpUserAgent();
397 void authenticationCacheAfterCancel_data();
398 void authenticationCacheAfterCancel();
399 void authenticationWithDifferentRealm();
400 void synchronousAuthenticationCache();
403 void closeDuringDownload_data();
404 void closeDuringDownload();
406 void ftpAuthentication_data();
407 void ftpAuthentication();
409 #ifdef QT_BUILD_INTERNAL
410 void backgroundRequest_data();
411 void backgroundRequest();
412 void backgroundRequestInterruption_data();
413 void backgroundRequestInterruption();
414 void backgroundRequestConnectInBackground_data();
415 void backgroundRequestConnectInBackground();
418 // NOTE: This test must be last!
419 void parentingRepliesToTheApp();
424 bool tst_QNetworkReply::seedCreated = false;
430 char *toString(const QNetworkReply::NetworkError& code)
432 const QMetaObject *mo = &QNetworkReply::staticMetaObject;
433 int index = mo->indexOfEnumerator("NetworkError");
437 QMetaEnum qme = mo->enumerator(index);
438 return qstrdup(qme.valueToKey(code));
442 char *toString(const QNetworkCookie &cookie)
444 return qstrdup(cookie.toRawForm());
448 char *toString(const QList<QNetworkCookie> &list)
450 QString result = "QList(";
452 foreach (QNetworkCookie cookie, list) {
456 result += QString::fromLatin1("QNetworkCookie(%1)").arg(QLatin1String(cookie.toRawForm()));
459 return qstrdup(result.append(')').toLocal8Bit());
465 #define RUN_REQUEST(call) \
467 QString errorMsg = call; \
468 if (!errorMsg.isEmpty()) \
469 QFAIL(qPrintable(errorMsg)); \
473 static void setupSslServer(QSslSocket* serverSocket)
475 QString testDataDir = QFileInfo(QFINDTESTDATA("rfc3252.txt")).absolutePath();
476 if (testDataDir.isEmpty())
477 testDataDir = QCoreApplication::applicationDirPath();
479 serverSocket->setProtocol(QSsl::AnyProtocol);
480 serverSocket->setLocalCertificate(testDataDir + "/certs/server.pem");
481 serverSocket->setPrivateKey(testDataDir + "/certs/server.key");
485 // Does not work for POST/PUT!
486 class MiniHttpServer: public QTcpServer
490 QTcpSocket *client; // always the last one that was received
491 QByteArray dataToTransmit;
492 QByteArray receivedData;
498 int totalConnections;
500 MiniHttpServer(const QByteArray &data, bool ssl = false, QThread *thread = 0, bool useipv6 = false)
501 : client(0), dataToTransmit(data), doClose(true), doSsl(ssl), ipv6(useipv6),
502 multiple(false), totalConnections(0)
505 listen(QHostAddress::AnyIPv6);
507 listen(QHostAddress::AnyIPv4);
510 connect(thread, SIGNAL(started()), this, SLOT(threadStartedSlot()));
511 moveToThread(thread);
518 void incomingConnection(qintptr socketDescriptor)
520 //qDebug() << "incomingConnection" << socketDescriptor << "doSsl:" << doSsl << "ipv6:" << ipv6;
522 client = new QTcpSocket;
523 client->setSocketDescriptor(socketDescriptor);
524 connectSocketSignals();
527 QSslSocket *serverSocket = new QSslSocket;
528 serverSocket->setParent(this);
529 if (serverSocket->setSocketDescriptor(socketDescriptor)) {
530 connect(serverSocket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(slotSslErrors(QList<QSslError>)));
531 setupSslServer(serverSocket);
532 serverSocket->startServerEncryption();
533 client = serverSocket;
534 connectSocketSignals();
541 client->setParent(this);
545 virtual void reply() {
546 // we need to emulate the bytesWrittenSlot call if the data is empty.
547 if (dataToTransmit.size() == 0)
548 QMetaObject::invokeMethod(this, "bytesWrittenSlot", Qt::QueuedConnection);
550 client->write(dataToTransmit);
553 void connectSocketSignals()
555 //qDebug() << "connectSocketSignals" << client;
556 connect(client, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
557 connect(client, SIGNAL(bytesWritten(qint64)), this, SLOT(bytesWrittenSlot()));
558 connect(client, SIGNAL(error(QAbstractSocket::SocketError)),
559 this, SLOT(slotError(QAbstractSocket::SocketError)));
564 void slotSslErrors(const QList<QSslError>& errors)
566 qDebug() << "slotSslErrors" << client->errorString() << errors;
569 void slotError(QAbstractSocket::SocketError err)
571 qDebug() << "slotError" << err << client->errorString();
577 receivedData += client->readAll();
578 int doubleEndlPos = receivedData.indexOf("\r\n\r\n");
580 if (doubleEndlPos != -1) {
581 // multiple requests incoming. remove the bytes of the current one
583 receivedData.remove(0, doubleEndlPos+4);
589 void bytesWrittenSlot() {
590 if (doClose && client->bytesToWrite() == 0) {
591 client->disconnectFromHost();
592 disconnect(client, 0, this, 0);
596 void threadStartedSlot()
602 class MyCookieJar: public QNetworkCookieJar
605 inline QList<QNetworkCookie> allCookies() const
606 { return QNetworkCookieJar::allCookies(); }
607 inline void setAllCookies(const QList<QNetworkCookie> &cookieList)
608 { QNetworkCookieJar::setAllCookies(cookieList); }
611 class MyProxyFactory: public QNetworkProxyFactory
615 QList<QNetworkProxy> toReturn;
616 QNetworkProxyQuery lastQuery;
617 inline MyProxyFactory() { clear(); }
622 toReturn = QList<QNetworkProxy>() << QNetworkProxy::DefaultProxy;
623 lastQuery = QNetworkProxyQuery();
626 virtual QList<QNetworkProxy> queryProxy(const QNetworkProxyQuery &query)
634 class MyMemoryCache: public QAbstractNetworkCache
637 typedef QPair<QNetworkCacheMetaData, QByteArray> CachedContent;
638 typedef QHash<QByteArray, CachedContent> CacheData;
641 MyMemoryCache(QObject *parent) : QAbstractNetworkCache(parent) {}
643 QNetworkCacheMetaData metaData(const QUrl &url)
645 return cache.value(url.toEncoded()).first;
648 void updateMetaData(const QNetworkCacheMetaData &metaData)
650 cache[metaData.url().toEncoded()].first = metaData;
653 QIODevice *data(const QUrl &url)
655 CacheData::ConstIterator it = cache.find(url.toEncoded());
656 if (it == cache.constEnd())
658 QBuffer *io = new QBuffer(this);
659 io->setData(it->second);
660 io->open(QIODevice::ReadOnly);
665 bool remove(const QUrl &url)
667 cache.remove(url.toEncoded());
671 qint64 cacheSize() const
674 foreach (const CachedContent &entry, cache)
675 total += entry.second.size();
679 QIODevice *prepare(const QNetworkCacheMetaData &)
681 qFatal("%s: Should not have tried to add to the cache", Q_FUNC_INFO);
684 void insert(QIODevice *)
686 qFatal("%s: Should not have tried to add to the cache", Q_FUNC_INFO);
689 void clear() { cache.clear(); }
691 Q_DECLARE_METATYPE(MyMemoryCache::CachedContent)
692 Q_DECLARE_METATYPE(MyMemoryCache::CacheData)
694 class MySpyMemoryCache: public QAbstractNetworkCache
697 MySpyMemoryCache(QObject *parent) : QAbstractNetworkCache(parent) {}
700 qDeleteAll(m_buffers);
704 QHash<QUrl, QIODevice*> m_buffers;
705 QList<QUrl> m_insertedUrls;
707 QNetworkCacheMetaData metaData(const QUrl &)
709 return QNetworkCacheMetaData();
712 void updateMetaData(const QNetworkCacheMetaData &)
716 QIODevice *data(const QUrl &)
721 bool remove(const QUrl &url)
723 delete m_buffers.take(url);
724 return m_insertedUrls.removeAll(url) > 0;
727 qint64 cacheSize() const
732 QIODevice *prepare(const QNetworkCacheMetaData &metaData)
734 QBuffer* buffer = new QBuffer;
735 buffer->open(QIODevice::ReadWrite);
736 buffer->setProperty("url", metaData.url());
737 m_buffers.insert(metaData.url(), buffer);
741 void insert(QIODevice *buffer)
743 QUrl url = buffer->property("url").toUrl();
744 m_insertedUrls << url;
745 delete m_buffers.take(url);
748 void clear() { m_insertedUrls.clear(); }
751 class DataReader: public QObject
759 DataReader(const QNetworkReplyPtr &dev, bool acc = true) : totalBytes(0), device(dev.data()), accumulate(acc)
760 { connect(device, SIGNAL(readyRead()), SLOT(doRead()) ); }
761 DataReader(QIODevice *dev, bool acc = true) : totalBytes(0), device(dev), accumulate(acc)
763 connect(device, SIGNAL(readyRead()), SLOT(doRead()));
770 buffer.resize(device->bytesAvailable());
771 qint64 bytesRead = device->read(buffer.data(), device->bytesAvailable());
772 if (bytesRead == -1) {
773 QTestEventLoop::instance().exitLoop();
776 buffer.truncate(bytesRead);
777 totalBytes += bytesRead;
785 class SocketPair: public QObject
789 QIODevice *endPoints[2];
791 SocketPair(QObject *parent = 0)
794 endPoints[0] = endPoints[1] = 0;
802 QTcpSocket *active = new QTcpSocket(this);
803 active->connectToHost("127.0.0.1", server.serverPort());
805 // need more time as working with embedded
806 // device and testing from emualtor
807 // things tend to get slower
808 if (!active->waitForConnected(1000))
811 if (!server.waitForNewConnection(1000))
814 QTcpSocket *passive = server.nextPendingConnection();
815 passive->setParent(this);
817 endPoints[0] = active;
818 endPoints[1] = passive;
823 // A blocking tcp server (must be used in a thread) which supports SSL.
824 class BlockingTcpServer : public QTcpServer
828 BlockingTcpServer(bool ssl) : doSsl(ssl), sslSocket(0) {}
830 QTcpSocket* waitForNextConnectionSocket() {
831 waitForNewConnection(-1);
834 qFatal("%s: sslSocket should not be null after calling waitForNewConnection()",
838 //qDebug() << "returning nextPendingConnection";
839 return nextPendingConnection();
842 virtual void incomingConnection(qintptr socketDescriptor)
846 QSslSocket *serverSocket = new QSslSocket;
847 serverSocket->setParent(this);
848 serverSocket->setSocketDescriptor(socketDescriptor);
849 connect(serverSocket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(slotSslErrors(QList<QSslError>)));
850 setupSslServer(serverSocket);
851 serverSocket->startServerEncryption();
852 sslSocket = serverSocket;
856 QTcpServer::incomingConnection(socketDescriptor);
862 void slotSslErrors(const QList<QSslError>& errors)
864 qDebug() << "slotSslErrors" << sslSocket->errorString() << errors;
870 QTcpSocket* sslSocket;
873 // This server tries to send data as fast as possible (like most servers)
874 // but it measures how fast it was able to send it, which shows at which
875 // rate the reader is processing the data.
876 class FastSender: public QThread
882 enum Protocol { DebugPipe, ProvidedData };
883 const Protocol protocol;
885 const bool fillKernelBuffer;
890 QByteArray dataToTransmit;
893 // a server that sends debugpipe data
894 FastSender(qint64 size)
895 : wantedSize(size), port(-1), protocol(DebugPipe),
896 doSsl(false), fillKernelBuffer(true), transferRate(-1),
903 // a server that sends the data provided at construction time, useful for HTTP
904 FastSender(const QByteArray& data, bool https, bool fillBuffer)
905 : wantedSize(data.size()), port(-1), protocol(ProvidedData),
906 doSsl(https), fillKernelBuffer(fillBuffer), transferRate(-1),
907 dataToTransmit(data), dataIndex(0)
913 inline int serverPort() const { return port; }
915 int writeNextData(QTcpSocket* socket, qint32 size)
917 if (protocol == DebugPipe) {
919 QDataStream stream(&data, QIODevice::WriteOnly);
920 stream << QVariantMap() << QByteArray(size, 'a');
921 socket->write((char*)&size, sizeof size);
926 const QByteArray data = dataToTransmit.mid(dataIndex, size);
928 dataIndex += data.size();
929 //qDebug() << "wrote" << dataIndex << "/" << dataToTransmit.size();
933 void writeLastData(QTcpSocket* socket)
935 if (protocol == DebugPipe) {
937 QDataStream stream(&data, QIODevice::WriteOnly);
938 stream << QVariantMap() << QByteArray();
939 const qint32 size = data.size();
940 socket->write((char*)&size, sizeof size);
948 BlockingTcpServer server(doSsl);
950 port = server.serverPort();
953 QTcpSocket *client = server.waitForNextConnectionSocket();
955 // get the "request" packet
956 if (!client->waitForReadyRead(2000)) {
957 qDebug() << "FastSender:" << client->error() << "waiting for \"request\" packet";
960 client->readAll(); // we're not interested in the actual contents (e.g. HTTP request)
962 enum { BlockSize = 1024 };
964 if (fillKernelBuffer) {
966 // write a bunch of bytes to fill up the buffers
969 if (writeNextData(client, BlockSize) < BlockSize) {
970 qDebug() << "ERROR: FastSender: not enough data to write in order to fill buffers; or client is reading too fast";
973 while (client->bytesToWrite() > 0) {
974 if (!client->waitForBytesWritten(0)) {
979 //qDebug() << "Filling kernel buffer: wrote" << dataIndex << "bytes";
982 qDebug() << "FastSender: ok, kernel buffer is full after writing" << dataIndex << "bytes";
985 // Tell the client to start reading
988 // the kernel buffer is full
989 // clean up QAbstractSocket's residue:
990 while (client->bytesToWrite() > 0) {
991 qDebug() << "Still having" << client->bytesToWrite() << "bytes to write, doing that now";
992 if (!client->waitForBytesWritten(2000)) {
993 qDebug() << "ERROR: FastSender:" << client->error() << "cleaning up residue";
998 // now write in "blocking mode", this is where the rate measuring starts
1001 //const qint64 writtenBefore = dataIndex;
1002 //qint64 measuredTotalBytes = wantedSize - writtenBefore;
1003 qint64 measuredSentBytes = 0;
1004 while (dataIndex < wantedSize) {
1005 const int remainingBytes = wantedSize - measuredSentBytes;
1006 const int bytesToWrite = qMin(remainingBytes, static_cast<int>(BlockSize));
1007 if (bytesToWrite <= 0)
1008 qFatal("%s: attempt to write %d bytes", Q_FUNC_INFO, bytesToWrite);
1009 measuredSentBytes += writeNextData(client, bytesToWrite);
1011 while (client->bytesToWrite() > 0) {
1012 if (!client->waitForBytesWritten(2000)) {
1013 qDebug() << "ERROR: FastSender:" << client->error() << "during blocking write";
1017 /*qDebug() << "FastSender:" << bytesToWrite << "bytes written now;"
1018 << measuredSentBytes << "measured bytes" << measuredSentBytes + writtenBefore << "total ("
1019 << measuredSentBytes*100/measuredTotalBytes << "% complete);"
1020 << timer.elapsed() << "ms elapsed";*/
1023 transferRate = measuredSentBytes * 1000 / timer.elapsed();
1024 qDebug() << "FastSender: flushed" << measuredSentBytes << "bytes in" << timer.elapsed() << "ms: rate =" << transferRate << "B/s";
1026 // write a "close connection" packet, if the protocol needs it
1027 writeLastData(client);
1033 class RateControlledReader: public QObject
1042 qint64 totalBytesRead;
1043 RateControlledReader(QObject& senderObj, QIODevice *dev, int kbPerSec, int maxBufferSize = 0)
1044 : device(dev), readBufferSize(maxBufferSize), totalBytesRead(0)
1046 // determine how often we have to wake up
1048 if (readBufferSize == 0) {
1049 // The requirement is simply "N KB per seconds"
1050 timesPerSecond = 20;
1051 bytesToRead = kbPerSec * 1024 / timesPerSecond;
1053 // The requirement also includes "<readBufferSize> bytes at a time"
1054 bytesToRead = readBufferSize;
1055 timesPerSecond = kbPerSec * 1024 / readBufferSize;
1057 interval = 1000 / timesPerSecond; // in ms
1059 qDebug() << "RateControlledReader: going to read" << bytesToRead
1060 << "bytes every" << interval << "ms";
1061 qDebug() << "actual read rate will be"
1062 << (bytesToRead * 1000 / interval) << "bytes/sec (wanted"
1063 << kbPerSec * 1024 << "bytes/sec)";
1065 // Wait for data to be readyRead
1066 bool ok = connect(&senderObj, SIGNAL(dataReady()), this, SLOT(slotDataReady()));
1068 qFatal("%s: Cannot connect dataReady signal", Q_FUNC_INFO);
1073 QByteArray someData = device->read(device->bytesAvailable());
1075 totalBytesRead += someData.size();
1076 qDebug() << "wrapUp: found" << someData.size() << "bytes left. progress" << data.size();
1077 //qDebug() << "wrapUp: now bytesAvailable=" << device->bytesAvailable();
1081 void slotDataReady()
1083 //qDebug() << "RateControlledReader: ready to go";
1084 startTimer(interval);
1088 void timerEvent(QTimerEvent *)
1090 //qDebug() << "RateControlledReader: timerEvent bytesAvailable=" << device->bytesAvailable();
1091 if (readBufferSize > 0 && device->bytesAvailable() > readBufferSize) {
1092 // This passes all the time, except in the final flush.
1093 //qFatal("%s: Too many bytes available", Q_FUNC_INFO);
1096 qint64 bytesRead = 0;
1100 if (device->bytesAvailable() == 0) {
1101 if (stopWatch.elapsed() > 20) {
1102 qDebug() << "RateControlledReader: Not enough data available for reading, waited too much, timing out";
1105 if (!device->waitForReadyRead(5)) {
1106 qDebug() << "RateControlledReader: Not enough data available for reading, even after waiting 5ms, bailing out";
1110 QByteArray someData = device->read(bytesToRead - bytesRead);
1112 bytesRead += someData.size();
1113 //qDebug() << "RateControlledReader: successfully read" << someData.size() << "progress:" << data.size();
1114 } while (bytesRead < bytesToRead);
1115 totalBytesRead += bytesRead;
1117 if (bytesRead < bytesToRead)
1118 qWarning() << "RateControlledReader: WARNING:" << bytesToRead - bytesRead << "bytes not read";
1123 tst_QNetworkReply::tst_QNetworkReply()
1125 qRegisterMetaType<QNetworkReply *>(); // for QSignalSpy
1126 qRegisterMetaType<QAuthenticator *>();
1127 qRegisterMetaType<QNetworkProxy>();
1129 qRegisterMetaType<QList<QSslError> >();
1131 qRegisterMetaType<QNetworkReply::NetworkError>();
1133 uniqueExtension = createUniqueExtension();
1134 testFileName = QDir::currentPath() + "/testfile" + uniqueExtension;
1135 cookieJar = new MyCookieJar;
1136 manager.setCookieJar(cookieJar);
1138 QHostInfo hostInfo = QHostInfo::fromName(QtNetworkSettings::serverName());
1140 proxies << ProxyData(QNetworkProxy::NoProxy, "", false);
1142 if (hostInfo.error() == QHostInfo::NoError && !hostInfo.addresses().isEmpty()) {
1143 QString proxyserver = hostInfo.addresses().first().toString();
1144 proxies << ProxyData(QNetworkProxy(QNetworkProxy::HttpProxy, proxyserver, 3128), "+proxy", false)
1145 << ProxyData(QNetworkProxy(QNetworkProxy::HttpProxy, proxyserver, 3129), "+proxyauth", true)
1146 // currently unsupported
1147 // << ProxyData(QNetworkProxy(QNetworkProxy::HttpProxy, proxyserver, 3130), "+proxyauth-ntlm", true);
1148 << ProxyData(QNetworkProxy(QNetworkProxy::Socks5Proxy, proxyserver, 1080), "+socks", false)
1149 << ProxyData(QNetworkProxy(QNetworkProxy::Socks5Proxy, proxyserver, 1081), "+socksauth", true);
1151 printf("==================================================================\n");
1152 printf("Proxy could not be looked up. No proxy will be used while testing!\n");
1153 printf("==================================================================\n");
1157 tst_QNetworkReply::~tst_QNetworkReply()
1162 void tst_QNetworkReply::authenticationRequired(QNetworkReply*, QAuthenticator* auth)
1164 auth->setUser("httptest");
1165 auth->setPassword("httptest");
1168 void tst_QNetworkReply::proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator* auth)
1170 auth->setUser("qsockstest");
1171 auth->setPassword("password");
1175 void tst_QNetworkReply::sslErrors(QNetworkReply *reply, const QList<QSslError> &errors)
1177 reply->ignoreSslErrors();
1178 QVERIFY(!errors.isEmpty());
1179 QVERIFY(!reply->sslConfiguration().isNull());
1182 void tst_QNetworkReply::storeSslConfiguration()
1184 storedSslConfiguration = QSslConfiguration();
1185 QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
1187 storedSslConfiguration = reply->sslConfiguration();
1191 QString tst_QNetworkReply::runMultipartRequest(const QNetworkRequest &request,
1192 QNetworkReplyPtr &reply,
1193 QHttpMultiPart *multiPart,
1194 const QByteArray &verb)
1197 reply.reset(manager.post(request, multiPart));
1199 reply.reset(manager.put(request, multiPart));
1201 // the code below is copied from tst_QNetworkReply::runSimpleRequest, see below
1202 reply->setParent(this);
1203 connect(reply, SIGNAL(finished()), SLOT(finished()));
1204 connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(gotError()));
1205 multiPart->setParent(reply.data());
1207 returnCode = Timeout;
1208 loop = new QEventLoop;
1209 QTimer::singleShot(25000, loop, SLOT(quit()));
1210 int code = returnCode == Timeout ? loop->exec() : returnCode;
1216 return "Request failed: " + reply->errorString();
1218 return "Network timeout";
1223 QString tst_QNetworkReply::runSimpleRequest(QNetworkAccessManager::Operation op,
1224 const QNetworkRequest &request,
1225 QNetworkReplyPtr &reply,
1226 const QByteArray &data)
1229 case QNetworkAccessManager::HeadOperation:
1230 reply.reset(manager.head(request));
1233 case QNetworkAccessManager::GetOperation:
1234 reply.reset(manager.get(request));
1237 case QNetworkAccessManager::PutOperation:
1238 reply.reset(manager.put(request, data));
1241 case QNetworkAccessManager::PostOperation:
1242 reply.reset(manager.post(request, data));
1245 case QNetworkAccessManager::DeleteOperation:
1246 reply.reset(manager.deleteResource(request));
1250 qFatal("%s: Invalid/unknown operation requested", Q_FUNC_INFO);
1252 reply->setParent(this);
1254 returnCode = Timeout;
1257 if (request.attribute(QNetworkRequest::SynchronousRequestAttribute).toBool()) {
1258 if (reply->isFinished())
1259 code = reply->error() != QNetworkReply::NoError ? Failure : Success;
1263 connect(reply, SIGNAL(finished()), SLOT(finished()));
1264 connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(gotError()));
1267 loop = new QEventLoop;
1268 QSignalSpy spy(reply.data(), SIGNAL(downloadProgress(qint64,qint64)));
1269 while (!reply->isFinished()) {
1270 QTimer::singleShot(20000, loop, SLOT(quit()));
1271 code = loop->exec();
1272 if (count == spy.count() && !reply->isFinished()) {
1276 count = spy.count();
1284 return "Request failed: " + reply->errorString();
1286 return "Network timeout";
1291 QString tst_QNetworkReply::runCustomRequest(const QNetworkRequest &request,
1292 QNetworkReplyPtr &reply,
1293 const QByteArray &verb,
1296 reply.reset(manager.sendCustomRequest(request, verb, data));
1297 reply->setParent(this);
1298 connect(reply, SIGNAL(finished()), SLOT(finished()));
1299 connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(gotError()));
1301 returnCode = Timeout;
1302 loop = new QEventLoop;
1303 QTimer::singleShot(20000, loop, SLOT(quit()));
1304 int code = returnCode == Timeout ? loop->exec() : returnCode;
1310 return "Request failed: " + reply->errorString();
1312 return "Network timeout";
1317 int tst_QNetworkReply::waitForFinish(QNetworkReplyPtr &reply)
1321 connect(reply, SIGNAL(finished()), SLOT(finished()));
1322 connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(gotError()));
1323 returnCode = Success;
1324 loop = new QEventLoop;
1325 QSignalSpy spy(reply.data(), SIGNAL(downloadProgress(qint64,qint64)));
1326 while (!reply->isFinished()) {
1327 QTimer::singleShot(5000, loop, SLOT(quit()));
1328 if ( loop->exec() == Timeout && count == spy.count() && !reply->isFinished()) {
1329 returnCode = Timeout;
1332 count = spy.count();
1340 void tst_QNetworkReply::finished()
1342 loop->exit(returnCode = Success);
1345 void tst_QNetworkReply::gotError()
1347 loop->exit(returnCode = Failure);
1348 disconnect(QObject::sender(), SIGNAL(finished()), this, 0);
1351 void tst_QNetworkReply::initTestCase()
1353 testDataDir = QFileInfo(QFINDTESTDATA("rfc3252.txt")).absolutePath();
1354 if (testDataDir.isEmpty())
1355 testDataDir = QCoreApplication::applicationDirPath();
1357 if (!QtNetworkSettings::verifyTestNetworkSettings())
1358 QSKIP("No network test server available");
1359 #if !defined Q_OS_WIN
1360 wronlyFileName = testDataDir + "/write-only" + uniqueExtension;
1361 QFile wr(wronlyFileName);
1362 QVERIFY(wr.open(QIODevice::WriteOnly | QIODevice::Truncate));
1363 wr.setPermissions(QFile::WriteOwner | QFile::WriteUser);
1367 QDir::setSearchPaths("testdata", QStringList() << testDataDir);
1369 QSslSocket::defaultCaCertificates(); //preload certificates
1371 #ifndef QT_NO_BEARERMANAGEMENT
1372 netConfMan = new QNetworkConfigurationManager(this);
1373 networkConfiguration = netConfMan->defaultConfiguration();
1374 networkSession.reset(new QNetworkSession(networkConfiguration));
1375 if (!networkSession->isOpen()) {
1376 networkSession->open();
1377 QVERIFY(networkSession->waitForOpened(30000));
1381 echoProcessDir = QFINDTESTDATA("echo");
1382 QVERIFY2(!echoProcessDir.isEmpty(), qPrintable(
1383 QString::fromLatin1("Couldn't find echo dir starting from %1.").arg(QDir::currentPath())));
1386 void tst_QNetworkReply::cleanupTestCase()
1388 #if !defined Q_OS_WIN
1389 QFile::remove(wronlyFileName);
1391 #ifndef QT_NO_BEARERMANAGEMENT
1392 if (networkSession && networkSession->isOpen()) {
1393 networkSession->close();
1398 void tst_QNetworkReply::init()
1403 void tst_QNetworkReply::cleanup()
1405 QFile file(testFileName);
1406 QVERIFY(!file.exists() || file.remove());
1408 // clear the internal cache
1409 manager.clearAccessCache();
1410 manager.setProxy(QNetworkProxy());
1411 manager.setCache(0);
1414 cookieJar->setAllCookies(QList<QNetworkCookie>());
1416 // disconnect manager signals
1418 manager.disconnect(SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)));
1420 manager.disconnect(SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
1421 manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
1424 void tst_QNetworkReply::stateChecking()
1426 QUrl url = QUrl("file:///");
1427 QNetworkRequest req(url); // you can't open this file, I know
1428 QNetworkReplyPtr reply(manager.get(req));
1430 QVERIFY(reply.data());
1431 QVERIFY(reply->isOpen());
1432 QVERIFY(reply->isReadable());
1433 QVERIFY(!reply->isWritable());
1435 // both behaviours are OK since we might change underlying behaviour again
1436 if (!reply->isFinished())
1437 QCOMPARE(reply->errorString(), QString("Unknown error"));
1439 QVERIFY(!reply->errorString().isEmpty());
1442 QCOMPARE(reply->manager(), &manager);
1443 QCOMPARE(reply->request(), req);
1444 QCOMPARE(int(reply->operation()), int(QNetworkAccessManager::GetOperation));
1445 // error and not error are OK since we might change underlying behaviour again
1446 if (!reply->isFinished())
1447 QCOMPARE(reply->error(), QNetworkReply::NoError);
1448 QCOMPARE(reply->url(), url);
1453 void tst_QNetworkReply::invalidProtocol()
1455 QUrl url = QUrl::fromEncoded("not-a-known-protocol://foo/bar");
1456 QNetworkRequest req(url);
1457 QNetworkReplyPtr reply;
1459 QString errorMsg = "Request failed: Protocol \"not-a-known-protocol\" is unknown";
1460 QString result = runSimpleRequest(QNetworkAccessManager::GetOperation, req, reply);
1461 QCOMPARE(result, errorMsg);
1463 QCOMPARE(reply->url(), url);
1464 QCOMPARE(reply->error(), QNetworkReply::ProtocolUnknownError);
1467 void tst_QNetworkReply::getFromData_data()
1469 QTest::addColumn<QString>("request");
1470 QTest::addColumn<QByteArray>("expected");
1471 QTest::addColumn<QString>("mimeType");
1473 const QString defaultMimeType("text/plain;charset=US-ASCII");
1475 //QTest::newRow("empty") << "data:" << QByteArray() << defaultMimeType;
1476 QTest::newRow("empty2") << "data:," << QByteArray() << defaultMimeType;
1477 QTest::newRow("just-charset_1") << "data:charset=iso-8859-1,"
1478 << QByteArray() << "text/plain;charset=iso-8859-1";
1479 QTest::newRow("just-charset_2") << "data:charset = iso-8859-1 ,"
1480 << QByteArray() << "text/plain;charset = iso-8859-1";
1481 //QTest::newRow("just-media") << "data:text/xml" << QByteArray() << "text/xml";
1482 QTest::newRow("just-media2") << "data:text/xml," << QByteArray() << "text/xml";
1484 QTest::newRow("plain_1") << "data:,foo" << QByteArray("foo") << defaultMimeType;
1485 QTest::newRow("plain_2") << "data:text/html,Hello World" << QByteArray("Hello World")
1487 QTest::newRow("plain_3") << "data:text/html;charset=utf-8,Hello World"
1488 << QByteArray("Hello World") << "text/html;charset=utf-8";
1490 QTest::newRow("pct_1") << "data:,%3Cbody%20contentEditable%3Dtrue%3E%0D%0A"
1491 << QByteArray("<body contentEditable=true>\r\n") << defaultMimeType;
1492 QTest::newRow("pct_2") << "data:text/html;charset=utf-8,%3Cbody%20contentEditable%3Dtrue%3E%0D%0A"
1493 << QByteArray("<body contentEditable=true>\r\n")
1494 << "text/html;charset=utf-8";
1496 QTest::newRow("base64-empty_1") << "data:;base64," << QByteArray() << defaultMimeType;
1497 QTest::newRow("base64-empty_2") << "data:charset=utf-8;base64," << QByteArray()
1498 << "text/plain;charset=utf-8";
1499 QTest::newRow("base64-empty_3") << "data:text/html;charset=utf-8;base64,"
1500 << QByteArray() << "text/html;charset=utf-8";
1502 QTest::newRow("base64_1") << "data:;base64,UXQgaXMgZ3JlYXQh" << QByteArray("Qt is great!")
1504 QTest::newRow("base64_2") << "data:charset=utf-8;base64,UXQgaXMgZ3JlYXQh"
1505 << QByteArray("Qt is great!") << "text/plain;charset=utf-8";
1506 QTest::newRow("base64_3") << "data:text/html;charset=utf-8;base64,UXQgaXMgZ3JlYXQh"
1507 << QByteArray("Qt is great!") << "text/html;charset=utf-8";
1509 QTest::newRow("pct-nul") << "data:,a%00g" << QByteArray("a\0g", 3) << defaultMimeType;
1510 QTest::newRow("base64-nul") << "data:;base64,YQBn" << QByteArray("a\0g", 3) << defaultMimeType;
1511 QTest::newRow("pct-nonutf8") << "data:,a%E1g" << QByteArray("a\xE1g", 3) << defaultMimeType;
1513 QTest::newRow("base64")
1514 << QString::fromLatin1("data:application/xml;base64,PGUvPg==")
1515 << QByteArray("<e/>")
1516 << "application/xml";
1518 QTest::newRow("base64, no media type")
1519 << QString::fromLatin1("data:;base64,PGUvPg==")
1520 << QByteArray("<e/>")
1523 QTest::newRow("Percent encoding")
1524 << QString::fromLatin1("data:application/xml,%3Ce%2F%3E")
1525 << QByteArray("<e/>")
1526 << "application/xml";
1528 QTest::newRow("Percent encoding, no media type")
1529 << QString::fromLatin1("data:,%3Ce%2F%3E")
1530 << QByteArray("<e/>")
1533 QTest::newRow("querychars")
1534 << QString::fromLatin1("data:,foo?x=0&y=0")
1535 << QByteArray("foo?x=0&y=0")
1538 QTest::newRow("css") << "data:text/css,div%20{%20border-right:%20solid;%20}"
1539 << QByteArray("div { border-right: solid; }")
1543 void tst_QNetworkReply::getFromData()
1545 QFETCH(QString, request);
1546 QFETCH(QByteArray, expected);
1547 QFETCH(QString, mimeType);
1549 QUrl url = QUrl::fromEncoded(request.toLatin1());
1550 QNetworkRequest req(url);
1551 QNetworkReplyPtr reply;
1553 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, req, reply));
1555 QCOMPARE(reply->url(), url);
1556 QCOMPARE(reply->error(), QNetworkReply::NoError);
1558 QCOMPARE(reply->header(QNetworkRequest::ContentTypeHeader).toString(), mimeType);
1559 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), qint64(expected.size()));
1560 QCOMPARE(reply->readAll(), expected);
1563 void tst_QNetworkReply::getFromFile()
1566 QTemporaryFile file(QDir::currentPath() + "/temp-XXXXXX");
1567 file.setAutoRemove(true);
1568 QVERIFY(file.open());
1570 QNetworkRequest request(QUrl::fromLocalFile(file.fileName()));
1571 QNetworkReplyPtr reply;
1573 static const char fileData[] = "This is some data that is in the file.\r\n";
1574 QByteArray data = QByteArray::fromRawData(fileData, sizeof fileData - 1);
1575 QVERIFY(file.write(data) == data.size());
1577 QCOMPARE(file.size(), qint64(data.size()));
1579 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
1581 QCOMPARE(reply->url(), request.url());
1582 QCOMPARE(reply->error(), QNetworkReply::NoError);
1584 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), file.size());
1585 QCOMPARE(reply->readAll(), data);
1587 // make the file bigger
1589 const int multiply = (128 * 1024) / (sizeof fileData - 1);
1590 for (int i = 0; i < multiply; ++i)
1591 file.write(fileData, sizeof fileData - 1);
1597 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
1598 QCOMPARE(reply->url(), request.url());
1599 QCOMPARE(reply->error(), QNetworkReply::NoError);
1601 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), file.size());
1602 QCOMPARE(qint64(reply->readAll().size()), file.size());
1605 void tst_QNetworkReply::getFromFileSpecial_data()
1607 QTest::addColumn<QString>("fileName");
1608 QTest::addColumn<QString>("url");
1610 QTest::newRow("resource") << ":/resource" << "qrc:/resource";
1611 QTest::newRow("search-path") << "testdata:/rfc3252.txt" << "testdata:/rfc3252.txt";
1612 QTest::newRow("bigfile-path") << "testdata:/bigfile" << "testdata:/bigfile";
1614 QTest::newRow("smb-path") << "testdata:/smb-file.txt" << "file://" + QtNetworkSettings::winServerName() + "/testshare/test.pri";
1618 void tst_QNetworkReply::getFromFileSpecial()
1620 QFETCH(QString, fileName);
1621 QFETCH(QString, url);
1623 // open the resource so we can find out its size
1624 QFile resource(fileName);
1625 QVERIFY(resource.open(QIODevice::ReadOnly));
1627 QNetworkRequest request;
1628 QNetworkReplyPtr reply;
1629 request.setUrl(url);
1630 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
1632 QCOMPARE(reply->url(), request.url());
1633 QCOMPARE(reply->error(), QNetworkReply::NoError);
1635 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), resource.size());
1636 QCOMPARE(reply->readAll(), resource.readAll());
1639 void tst_QNetworkReply::getFromFtp_data()
1641 QTest::addColumn<QString>("referenceName");
1642 QTest::addColumn<QString>("url");
1644 QTest::newRow("rfc3252.txt") << (testDataDir + "/rfc3252.txt") << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt";
1645 QTest::newRow("bigfile") << (testDataDir + "/bigfile") << "ftp://" + QtNetworkSettings::serverName() + "/qtest/bigfile";
1648 void tst_QNetworkReply::getFromFtp()
1650 QFETCH(QString, referenceName);
1651 QFETCH(QString, url);
1653 QFile reference(referenceName);
1654 QVERIFY(reference.open(QIODevice::ReadOnly));
1656 QNetworkRequest request(url);
1657 QNetworkReplyPtr reply;
1658 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
1660 QCOMPARE(reply->url(), request.url());
1661 QCOMPARE(reply->error(), QNetworkReply::NoError);
1663 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
1664 QCOMPARE(reply->readAll(), reference.readAll());
1667 void tst_QNetworkReply::getFromHttp_data()
1669 QTest::addColumn<QString>("referenceName");
1670 QTest::addColumn<QString>("url");
1672 QTest::newRow("success-internal") << (testDataDir + "/rfc3252.txt") << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt";
1673 QTest::newRow("success-external") << (testDataDir + "/rfc3252.txt") << "http://www.ietf.org/rfc/rfc3252.txt";
1674 QTest::newRow("bigfile-internal") << (testDataDir + "/bigfile") << "http://" + QtNetworkSettings::serverName() + "/qtest/bigfile";
1677 void tst_QNetworkReply::getFromHttp()
1679 QFETCH(QString, referenceName);
1680 QFETCH(QString, url);
1682 QFile reference(referenceName);
1683 QVERIFY(reference.open(QIODevice::ReadOnly));
1685 QNetworkRequest request(url);
1686 QNetworkReplyPtr reply;
1687 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
1689 QCOMPARE(reply->url(), request.url());
1690 QCOMPARE(reply->error(), QNetworkReply::NoError);
1691 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
1692 QCOMPARE(reply->size(), reference.size());
1693 // only compare when the header is set.
1694 if (reply->header(QNetworkRequest::ContentLengthHeader).isValid())
1695 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
1697 // We know our internal server is apache..
1698 if (qstrcmp(QTest::currentDataTag(), "success-internal") == 0)
1699 QVERIFY(reply->header(QNetworkRequest::ServerHeader).toString().contains("Apache"));
1701 QCOMPARE(reply->readAll(), reference.readAll());
1704 void tst_QNetworkReply::headFromHttp_data()
1706 QTest::addColumn<qint64>("referenceSize");
1707 QTest::addColumn<QUrl>("url");
1708 QTest::addColumn<QString>("contentType");
1709 QTest::addColumn<QNetworkProxy>("proxy");
1711 qint64 rfcsize = QFileInfo(testDataDir + "/rfc3252.txt").size();
1712 qint64 bigfilesize = QFileInfo(testDataDir + "/bigfile").size();
1713 qint64 indexsize = QFileInfo(testDataDir + "/index.html").size();
1715 //testing proxies, mainly for the 407 response from http proxy
1716 for (int i = 0; i < proxies.count(); ++i) {
1717 QTest::newRow("rfc" + proxies.at(i).tag) << rfcsize << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt") << "text/plain" << proxies.at(i).proxy;
1718 QTest::newRow("bigfile" + proxies.at(i).tag) << bigfilesize << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/bigfile") << "text/plain" << proxies.at(i).proxy;
1719 QTest::newRow("index" + proxies.at(i).tag) << indexsize << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/") << "text/html" << proxies.at(i).proxy;
1720 QTest::newRow("with-authentication" + proxies.at(i).tag) << rfcsize << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt") << "text/plain" << proxies.at(i).proxy;
1721 QTest::newRow("cgi" + proxies.at(i).tag) << (qint64)-1 << QUrl("http://qt-test-server/qtest/cgi-bin/httpcachetest_expires500.cgi") << "text/html" << proxies.at(i).proxy;
1725 void tst_QNetworkReply::headFromHttp()
1727 QFETCH(qint64, referenceSize);
1729 QFETCH(QString, contentType);
1730 QFETCH(QNetworkProxy, proxy);
1732 QNetworkRequest request(url);
1733 QNetworkReplyPtr reply;
1738 manager.setProxy(proxy);
1739 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
1740 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
1741 connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
1742 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
1744 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::HeadOperation, request, reply));
1746 manager.disconnect(SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
1747 this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
1748 manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
1749 this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
1751 QVERIFY(time.elapsed() < 8000); //check authentication didn't wait for the server to timeout the http connection (15s on qt test server)
1753 QCOMPARE(reply->url(), request.url());
1754 QCOMPARE(reply->error(), QNetworkReply::NoError);
1755 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
1756 // only compare when the header is set.
1757 if (reply->header(QNetworkRequest::ContentLengthHeader).isValid() && referenceSize >= 0)
1758 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), referenceSize);
1759 if (reply->header(QNetworkRequest::ContentTypeHeader).isValid())
1760 QCOMPARE(reply->header(QNetworkRequest::ContentTypeHeader).toString(), contentType);
1763 void tst_QNetworkReply::getErrors_data()
1765 QTest::addColumn<QString>("url");
1766 QTest::addColumn<int>("error");
1767 QTest::addColumn<int>("httpStatusCode");
1768 QTest::addColumn<bool>("dataIsEmpty");
1771 QTest::newRow("empty-url") << QString() << int(QNetworkReply::ProtocolUnknownError) << 0 << true;
1772 QTest::newRow("empty-scheme-host") << (testDataDir + "/rfc3252.txt") << int(QNetworkReply::ProtocolUnknownError) << 0 << true;
1773 QTest::newRow("empty-scheme") << "//" + QtNetworkSettings::winServerName() + "/testshare/test.pri"
1774 << int(QNetworkReply::ProtocolUnknownError) << 0 << true;
1777 QTest::newRow("file-host") << "file://this-host-doesnt-exist.troll.no/foo.txt"
1778 #if !defined Q_OS_WIN
1779 << int(QNetworkReply::ProtocolInvalidOperationError) << 0 << true;
1781 << int(QNetworkReply::ContentNotFoundError) << 0 << true;
1783 QTest::newRow("file-no-path") << "file://localhost"
1784 << int(QNetworkReply::ContentOperationNotPermittedError) << 0 << true;
1785 QTest::newRow("file-is-dir") << QUrl::fromLocalFile(QDir::currentPath()).toString()
1786 << int(QNetworkReply::ContentOperationNotPermittedError) << 0 << true;
1787 QTest::newRow("file-exist") << QUrl::fromLocalFile(QDir::currentPath() + "/this-file-doesnt-exist.txt").toString()
1788 << int(QNetworkReply::ContentNotFoundError) << 0 << true;
1789 #if !defined Q_OS_WIN
1790 QTest::newRow("file-is-wronly") << QUrl::fromLocalFile(wronlyFileName).toString()
1791 << int(QNetworkReply::ContentAccessDenied) << 0 << true;
1793 if (QFile::exists("/etc/shadow"))
1794 QTest::newRow("file-permissions") << "file:/etc/shadow"
1795 << int(QNetworkReply::ContentAccessDenied) << 0 << true;
1798 QTest::newRow("ftp-host") << "ftp://this-host-doesnt-exist.troll.no/foo.txt"
1799 << int(QNetworkReply::HostNotFoundError) << 0 << true;
1800 QTest::newRow("ftp-no-path") << "ftp://" + QtNetworkSettings::serverName()
1801 << int(QNetworkReply::ContentOperationNotPermittedError) << 0 << true;
1802 QTest::newRow("ftp-is-dir") << "ftp://" + QtNetworkSettings::serverName() + "/qtest"
1803 << int(QNetworkReply::ContentOperationNotPermittedError) << 0 << true;
1804 QTest::newRow("ftp-dir-not-readable") << "ftp://" + QtNetworkSettings::serverName() + "/pub/dir-not-readable/foo.txt"
1805 << int(QNetworkReply::ContentAccessDenied) << 0 << true;
1806 QTest::newRow("ftp-file-not-readable") << "ftp://" + QtNetworkSettings::serverName() + "/pub/file-not-readable.txt"
1807 << int(QNetworkReply::ContentAccessDenied) << 0 << true;
1808 QTest::newRow("ftp-exist") << "ftp://" + QtNetworkSettings::serverName() + "/pub/this-file-doesnt-exist.txt"
1809 << int(QNetworkReply::ContentNotFoundError) << 0 << true;
1812 QTest::newRow("http-host") << "http://this-host-will-never-exist.troll.no/"
1813 << int(QNetworkReply::HostNotFoundError) << 0 << true;
1814 QTest::newRow("http-exist") << "http://" + QtNetworkSettings::serverName() + "/this-file-doesnt-exist.txt"
1815 << int(QNetworkReply::ContentNotFoundError) << 404 << false;
1816 QTest::newRow("http-authentication") << "http://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth"
1817 << int(QNetworkReply::AuthenticationRequiredError) << 401 << false;
1820 void tst_QNetworkReply::getErrors()
1822 QFETCH(QString, url);
1823 QNetworkRequest request(url);
1826 if ((qstrcmp(QTest::currentDataTag(), "file-is-wronly") == 0) ||
1827 (qstrcmp(QTest::currentDataTag(), "file-permissions") == 0)) {
1828 if (::getuid() == 0)
1829 QSKIP("Running this test as root doesn't make sense");
1833 QNetworkReplyPtr reply(manager.get(request));
1834 reply->setParent(this); // we have expect-fails
1836 if (!reply->isFinished())
1837 QCOMPARE(reply->error(), QNetworkReply::NoError);
1839 // now run the request:
1840 QVERIFY(waitForFinish(reply) != Timeout);
1843 QEXPECT_FAIL("ftp-is-dir", "QFtp cannot provide enough detail", Abort);
1844 // the line below is not necessary
1845 QEXPECT_FAIL("ftp-dir-not-readable", "QFtp cannot provide enough detail", Abort);
1846 QCOMPARE(reply->error(), QNetworkReply::NetworkError(error));
1848 QTEST(reply->readAll().isEmpty(), "dataIsEmpty");
1850 QVERIFY(reply->isFinished());
1851 QVERIFY(!reply->isRunning());
1853 QFETCH(int, httpStatusCode);
1854 if (httpStatusCode != 0) {
1855 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), httpStatusCode);
1859 static inline QByteArray md5sum(const QByteArray &data)
1861 return QCryptographicHash::hash(data, QCryptographicHash::Md5);
1864 void tst_QNetworkReply::putToFile_data()
1866 QTest::addColumn<QByteArray>("data");
1867 QTest::addColumn<QByteArray>("md5sum");
1871 QTest::newRow("empty") << data << md5sum(data);
1873 data = "This is a normal message.";
1874 QTest::newRow("generic") << data << md5sum(data);
1876 data = "This is a message to show that Qt rocks!\r\n\n";
1877 QTest::newRow("small") << data << md5sum(data);
1879 data = QByteArray("abcd\0\1\2\abcd",12);
1880 QTest::newRow("with-nul") << data << md5sum(data);
1882 data = QByteArray(4097, '\4');
1883 QTest::newRow("4k+1") << data << md5sum(data);
1885 data = QByteArray(128*1024+1, '\177');
1886 QTest::newRow("128k+1") << data << md5sum(data);
1888 data = QByteArray(2*1024*1024+1, '\177');
1889 QTest::newRow("2MB+1") << data << md5sum(data);
1892 void tst_QNetworkReply::putToFile()
1894 QFile file(testFileName);
1896 QUrl url = QUrl::fromLocalFile(file.fileName());
1897 QNetworkRequest request(url);
1898 QNetworkReplyPtr reply;
1900 QFETCH(QByteArray, data);
1902 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PutOperation, request, reply, data));
1904 QCOMPARE(reply->url(), url);
1905 QCOMPARE(reply->error(), QNetworkReply::NoError);
1906 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
1907 QVERIFY(reply->readAll().isEmpty());
1909 QVERIFY(file.open(QIODevice::ReadOnly));
1910 QCOMPARE(file.size(), qint64(data.size()));
1911 QByteArray contents = file.readAll();
1912 QCOMPARE(contents, data);
1915 void tst_QNetworkReply::putToFtp_data()
1920 void tst_QNetworkReply::putToFtp()
1922 QUrl url("ftp://" + QtNetworkSettings::serverName());
1923 url.setPath(QString("/qtest/upload/qnetworkaccess-putToFtp-%1-%2")
1924 .arg(QTest::currentDataTag())
1925 .arg(uniqueExtension));
1927 QNetworkRequest request(url);
1928 QNetworkReplyPtr reply;
1930 QFETCH(QByteArray, data);
1932 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PutOperation, request, reply, data));
1934 QCOMPARE(reply->url(), url);
1935 QCOMPARE(reply->error(), QNetworkReply::NoError);
1936 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
1937 QVERIFY(reply->readAll().isEmpty());
1939 // download the file again from FTP to make sure it was uploaded
1941 QNetworkAccessManager qnam;
1942 QNetworkRequest req(url);
1943 QNetworkReply *r = qnam.get(req);
1945 QObject::connect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
1947 QSignalSpy spy(r, SIGNAL(downloadProgress(qint64,qint64)));
1948 while (!r->isFinished()) {
1949 QTestEventLoop::instance().enterLoop(10);
1950 if (count == spy.count() && !r->isFinished())
1952 count = spy.count();
1954 QObject::disconnect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
1956 QByteArray uploaded = r->readAll();
1957 QCOMPARE(uploaded.size(), data.size());
1958 QCOMPARE(uploaded, data);
1961 QObject::connect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
1962 QTestEventLoop::instance().enterLoop(10);
1963 QObject::disconnect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
1966 void tst_QNetworkReply::putToHttp_data()
1971 void tst_QNetworkReply::putToHttp()
1973 QUrl url("http://" + QtNetworkSettings::serverName());
1974 url.setPath(QString("/dav/qnetworkaccess-putToHttp-%1-%2")
1975 .arg(QTest::currentDataTag())
1976 .arg(uniqueExtension));
1978 QNetworkRequest request(url);
1979 QNetworkReplyPtr reply;
1981 QFETCH(QByteArray, data);
1983 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PutOperation, request, reply, data));
1985 QCOMPARE(reply->url(), url);
1986 QCOMPARE(reply->error(), QNetworkReply::NoError);
1988 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 201); // 201 Created
1990 // download the file again from HTTP to make sure it was uploaded
1991 // correctly. HTTP/0.9 is enough
1993 socket.connectToHost(QtNetworkSettings::serverName(), 80);
1994 socket.write("GET " + url.toEncoded(QUrl::RemoveScheme | QUrl::RemoveAuthority) + "\r\n");
1995 if (!socket.waitForDisconnected(10000))
1996 QFAIL("Network timeout");
1998 QByteArray uploadedData = socket.readAll();
1999 QCOMPARE(uploadedData, data);
2002 void tst_QNetworkReply::putToHttpSynchronous_data()
2004 uniqueExtension = createUniqueExtension();
2008 void tst_QNetworkReply::putToHttpSynchronous()
2010 QUrl url("http://" + QtNetworkSettings::serverName());
2011 url.setPath(QString("/dav/qnetworkaccess-putToHttp-%1-%2")
2012 .arg(QTest::currentDataTag())
2013 .arg(uniqueExtension));
2015 QNetworkRequest request(url);
2016 QNetworkReplyPtr reply;
2018 QFETCH(QByteArray, data);
2020 request.setAttribute(
2021 QNetworkRequest::SynchronousRequestAttribute,
2024 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PutOperation, request, reply, data));
2026 QCOMPARE(reply->url(), url);
2027 QCOMPARE(reply->error(), QNetworkReply::NoError);
2029 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 201); // 201 Created
2031 // download the file again from HTTP to make sure it was uploaded
2032 // correctly. HTTP/0.9 is enough
2034 socket.connectToHost(QtNetworkSettings::serverName(), 80);
2035 socket.write("GET " + url.toEncoded(QUrl::RemoveScheme | QUrl::RemoveAuthority) + "\r\n");
2036 if (!socket.waitForDisconnected(10000))
2037 QFAIL("Network timeout");
2039 QByteArray uploadedData = socket.readAll();
2040 QCOMPARE(uploadedData, data);
2043 void tst_QNetworkReply::postToHttp_data()
2048 void tst_QNetworkReply::postToHttp()
2050 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi");
2052 QNetworkRequest request(url);
2053 request.setRawHeader("Content-Type", "application/octet-stream");
2054 QNetworkReplyPtr reply;
2056 QFETCH(QByteArray, data);
2058 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PostOperation, request, reply, data));
2060 QCOMPARE(reply->url(), url);
2061 QCOMPARE(reply->error(), QNetworkReply::NoError);
2063 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
2065 QFETCH(QByteArray, md5sum);
2066 QByteArray uploadedData = reply->readAll().trimmed();
2067 QCOMPARE(uploadedData, md5sum.toHex());
2070 void tst_QNetworkReply::postToHttpSynchronous_data()
2075 void tst_QNetworkReply::postToHttpSynchronous()
2077 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi");
2079 QNetworkRequest request(url);
2080 request.setRawHeader("Content-Type", "application/octet-stream");
2082 request.setAttribute(
2083 QNetworkRequest::SynchronousRequestAttribute,
2086 QNetworkReplyPtr reply;
2088 QFETCH(QByteArray, data);
2090 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PostOperation, request, reply, data));
2092 QCOMPARE(reply->url(), url);
2093 QCOMPARE(reply->error(), QNetworkReply::NoError);
2095 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
2097 QFETCH(QByteArray, md5sum);
2098 QByteArray uploadedData = reply->readAll().trimmed();
2099 QCOMPARE(uploadedData, md5sum.toHex());
2102 void tst_QNetworkReply::postToHttpMultipart_data()
2104 QTest::addColumn<QUrl>("url");
2105 QTest::addColumn<QHttpMultiPart *>("multiPart");
2106 QTest::addColumn<QByteArray>("expectedReplyData");
2107 QTest::addColumn<QByteArray>("contentType");
2109 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/multipart.cgi");
2110 QByteArray expectedData;
2115 QHttpMultiPart *emptyMultiPart = new QHttpMultiPart;
2116 QTest::newRow("empty") << url << emptyMultiPart << expectedData << QByteArray("mixed");
2118 QHttpMultiPart *emptyRelatedMultiPart = new QHttpMultiPart;
2119 emptyRelatedMultiPart->setContentType(QHttpMultiPart::RelatedType);
2120 QTest::newRow("empty-related") << url << emptyRelatedMultiPart << expectedData << QByteArray("related");
2122 QHttpMultiPart *emptyAlternativeMultiPart = new QHttpMultiPart;
2123 emptyAlternativeMultiPart->setContentType(QHttpMultiPart::AlternativeType);
2124 QTest::newRow("empty-alternative") << url << emptyAlternativeMultiPart << expectedData << QByteArray("alternative");
2130 textPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain"));
2131 textPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"text\""));
2132 textPart.setBody("7 bytes");
2133 QHttpMultiPart *multiPart1 = new QHttpMultiPart;
2134 multiPart1->setContentType(QHttpMultiPart::FormDataType);
2135 multiPart1->append(textPart);
2136 expectedData = "key: text, value: 7 bytes\n";
2137 QTest::newRow("text") << url << multiPart1 << expectedData << QByteArray("form-data");
2139 QHttpMultiPart *customMultiPart = new QHttpMultiPart;
2140 customMultiPart->append(textPart);
2141 expectedData = "header: Content-Type, value: 'text/plain'\n"
2142 "header: Content-Disposition, value: 'form-data; name=\"text\"'\n"
2143 "content: 7 bytes\n"
2145 QTest::newRow("text-custom") << url << customMultiPart << expectedData << QByteArray("custom");
2147 QHttpPart textPart2;
2148 textPart2.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain"));
2149 textPart2.setRawHeader("myRawHeader", "myValue");
2150 textPart2.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"text2\""));
2151 textPart2.setBody("some more bytes");
2152 textPart2.setBodyDevice((QIODevice *) 1); // test whether setting and unsetting of the device works
2153 textPart2.setBodyDevice(0);
2154 QHttpMultiPart *multiPart2 = new QHttpMultiPart;
2155 multiPart2->setContentType(QHttpMultiPart::FormDataType);
2156 multiPart2->append(textPart);
2157 multiPart2->append(textPart2);
2158 expectedData = "key: text2, value: some more bytes\n"
2159 "key: text, value: 7 bytes\n";
2160 QTest::newRow("text-text") << url << multiPart2 << expectedData << QByteArray("form-data");
2163 QHttpPart textPart3;
2164 textPart3.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain"));
2165 textPart3.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"text3\""));
2166 textPart3.setRawHeader("Content-Location", "http://my.test.location.tld");
2167 textPart3.setBody("even more bytes");
2168 QHttpMultiPart *multiPart3 = new QHttpMultiPart;
2169 multiPart3->setContentType(QHttpMultiPart::AlternativeType);
2170 multiPart3->append(textPart);
2171 multiPart3->append(textPart2);
2172 multiPart3->append(textPart3);
2173 expectedData = "header: Content-Type, value: 'text/plain'\n"
2174 "header: Content-Disposition, value: 'form-data; name=\"text\"'\n"
2175 "content: 7 bytes\n"
2177 "header: Content-Type, value: 'text/plain'\n"
2178 "header: myRawHeader, value: 'myValue'\n"
2179 "header: Content-Disposition, value: 'form-data; name=\"text2\"'\n"
2180 "content: some more bytes\n"
2182 "header: Content-Type, value: 'text/plain'\n"
2183 "header: Content-Disposition, value: 'form-data; name=\"text3\"'\n"
2184 "header: Content-Location, value: 'http://my.test.location.tld'\n"
2185 "content: even more bytes\n\n";
2186 QTest::newRow("text-text-text") << url << multiPart3 << expectedData << QByteArray("alternative");
2190 // text and image parts
2192 QHttpPart imagePart11;
2193 imagePart11.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
2194 imagePart11.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage\""));
2195 imagePart11.setRawHeader("Content-Location", "http://my.test.location.tld");
2196 imagePart11.setRawHeader("Content-ID", "my@id.tld");
2197 QFile *file11 = new QFile(testDataDir + "/image1.jpg");
2198 file11->open(QIODevice::ReadOnly);
2199 imagePart11.setBodyDevice(file11);
2200 QHttpMultiPart *imageMultiPart1 = new QHttpMultiPart(QHttpMultiPart::FormDataType);
2201 imageMultiPart1->append(imagePart11);
2202 file11->setParent(imageMultiPart1);
2203 expectedData = "key: testImage, value: 87ef3bb319b004ba9e5e9c9fa713776e\n"; // md5 sum of file
2204 QTest::newRow("image") << url << imageMultiPart1 << expectedData << QByteArray("form-data");
2206 QHttpPart imagePart21;
2207 imagePart21.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
2208 imagePart21.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage1\""));
2209 imagePart21.setRawHeader("Content-Location", "http://my.test.location.tld");
2210 imagePart21.setRawHeader("Content-ID", "my@id.tld");
2211 QFile *file21 = new QFile(testDataDir + "/image1.jpg");
2212 file21->open(QIODevice::ReadOnly);
2213 imagePart21.setBodyDevice(file21);
2214 QHttpMultiPart *imageMultiPart2 = new QHttpMultiPart();
2215 imageMultiPart2->setContentType(QHttpMultiPart::FormDataType);
2216 imageMultiPart2->append(textPart);
2217 imageMultiPart2->append(imagePart21);
2218 file21->setParent(imageMultiPart2);
2219 QHttpPart imagePart22;
2220 imagePart22.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
2221 imagePart22.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage2\""));
2222 QFile *file22 = new QFile(testDataDir + "/image2.jpg");
2223 file22->open(QIODevice::ReadOnly);
2224 imagePart22.setBodyDevice(file22);
2225 imageMultiPart2->append(imagePart22);
2226 file22->setParent(imageMultiPart2);
2227 expectedData = "key: testImage1, value: 87ef3bb319b004ba9e5e9c9fa713776e\n"
2228 "key: text, value: 7 bytes\n"
2229 "key: testImage2, value: 483761b893f7fb1bd2414344cd1f3dfb\n";
2230 QTest::newRow("text-image-image") << url << imageMultiPart2 << expectedData << QByteArray("form-data");
2233 QHttpPart imagePart31;
2234 imagePart31.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
2235 imagePart31.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage1\""));
2236 imagePart31.setRawHeader("Content-Location", "http://my.test.location.tld");
2237 imagePart31.setRawHeader("Content-ID", "my@id.tld");
2238 QFile *file31 = new QFile(testDataDir + "/image1.jpg");
2239 file31->open(QIODevice::ReadOnly);
2240 imagePart31.setBodyDevice(file31);
2241 QHttpMultiPart *imageMultiPart3 = new QHttpMultiPart(QHttpMultiPart::FormDataType);
2242 imageMultiPart3->append(imagePart31);
2243 file31->setParent(imageMultiPart3);
2244 QHttpPart imagePart32;
2245 imagePart32.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
2246 imagePart32.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage2\""));
2247 QFile *file32 = new QFile(testDataDir + "/image2.jpg");
2248 file32->open(QIODevice::ReadOnly);
2249 imagePart32.setBodyDevice(file31); // check that resetting works
2250 imagePart32.setBodyDevice(file32);
2251 imageMultiPart3->append(imagePart32);
2252 file32->setParent(imageMultiPart3);
2253 QHttpPart imagePart33;
2254 imagePart33.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
2255 imagePart33.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage3\""));
2256 QFile *file33 = new QFile(testDataDir + "/image3.jpg");
2257 file33->open(QIODevice::ReadOnly);
2258 imagePart33.setBodyDevice(file33);
2259 imageMultiPart3->append(imagePart33);
2260 file33->setParent(imageMultiPart3);
2261 expectedData = "key: testImage1, value: 87ef3bb319b004ba9e5e9c9fa713776e\n"
2262 "key: testImage2, value: 483761b893f7fb1bd2414344cd1f3dfb\n"
2263 "key: testImage3, value: ab0eb6fd4fcf8b4436254870b4513033\n";
2264 QTest::newRow("3-images") << url << imageMultiPart3 << expectedData << QByteArray("form-data");
2267 // note: nesting multiparts is not working currently; for that, the outputDevice would need to be public
2269 // QHttpPart imagePart41;
2270 // imagePart41.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
2271 // QFile *file41 = new QFile(testDataDir + "/image1.jpg");
2272 // file41->open(QIODevice::ReadOnly);
2273 // imagePart41.setBodyDevice(file41);
2275 // QHttpMultiPart *innerMultiPart = new QHttpMultiPart();
2276 // innerMultiPart->setContentType(QHttpMultiPart::FormDataType);
2277 // textPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant());
2278 // innerMultiPart->append(textPart);
2279 // innerMultiPart->append(imagePart41);
2280 // textPart2.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant());
2281 // innerMultiPart->append(textPart2);
2283 // QHttpPart nestedPart;
2284 // nestedPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"nestedMessage"));
2285 // nestedPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("multipart/alternative; boundary=\"" + innerMultiPart->boundary() + "\""));
2286 // innerMultiPart->outputDevice()->open(QIODevice::ReadOnly);
2287 // nestedPart.setBodyDevice(innerMultiPart->outputDevice());
2289 // QHttpMultiPart *outerMultiPart = new QHttpMultiPart;
2290 // outerMultiPart->setContentType(QHttpMultiPart::FormDataType);
2291 // outerMultiPart->append(textPart);
2292 // outerMultiPart->append(nestedPart);
2293 // outerMultiPart->append(textPart2);
2294 // expectedData = "nothing"; // the CGI.pm module running on the test server does not understand nested multiparts
2295 // openFiles.clear();
2296 // openFiles << file41;
2297 // QTest::newRow("nested") << url << outerMultiPart << expectedData << openFiles;
2300 // test setting large chunks of content with a byte array instead of a device (DISCOURAGED because of high memory consumption,
2301 // but we need to test that the behavior is correct)
2302 QHttpPart imagePart51;
2303 imagePart51.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
2304 imagePart51.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage\""));
2305 QFile *file51 = new QFile(testDataDir + "/image1.jpg");
2306 file51->open(QIODevice::ReadOnly);
2307 QByteArray imageData = file51->readAll();
2310 imagePart51.setBody("7 bytes"); // check that resetting works
2311 imagePart51.setBody(imageData);
2312 QHttpMultiPart *imageMultiPart5 = new QHttpMultiPart;
2313 imageMultiPart5->setContentType(QHttpMultiPart::FormDataType);
2314 imageMultiPart5->append(imagePart51);
2315 expectedData = "key: testImage, value: 87ef3bb319b004ba9e5e9c9fa713776e\n"; // md5 sum of file
2316 QTest::newRow("image-as-content") << url << imageMultiPart5 << expectedData << QByteArray("form-data");
2319 void tst_QNetworkReply::postToHttpMultipart()
2323 static QSet<QByteArray> boundaries;
2325 QNetworkRequest request(url);
2326 QNetworkReplyPtr reply;
2328 QFETCH(QHttpMultiPart *, multiPart);
2329 QFETCH(QByteArray, expectedReplyData);
2330 QFETCH(QByteArray, contentType);
2332 // hack for testing the setting of the content-type header by hand:
2333 if (contentType == "custom") {
2334 QByteArray contentType("multipart/custom; boundary=\"" + multiPart->boundary() + "\"");
2335 request.setHeader(QNetworkRequest::ContentTypeHeader, contentType);
2338 QVERIFY2(! boundaries.contains(multiPart->boundary()), "boundary '" + multiPart->boundary() + "' has been created twice");
2339 boundaries.insert(multiPart->boundary());
2341 RUN_REQUEST(runMultipartRequest(request, reply, multiPart, "POST"));
2342 multiPart->deleteLater();
2344 QCOMPARE(reply->url(), url);
2345 QCOMPARE(reply->error(), QNetworkReply::NoError);
2347 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
2349 QVERIFY(multiPart->boundary().count() > 20); // check that there is randomness after the "boundary_.oOo._" string
2350 QVERIFY(multiPart->boundary().count() < 70);
2351 QByteArray replyData = reply->readAll();
2353 expectedReplyData.prepend("content type: multipart/" + contentType + "; boundary=\"" + multiPart->boundary() + "\"\n");
2354 // QEXPECT_FAIL("nested", "the server does not understand nested multipart messages", Continue); // see above
2355 QCOMPARE(replyData, expectedReplyData);
2358 void tst_QNetworkReply::putToHttpMultipart_data()
2360 postToHttpMultipart_data();
2363 void tst_QNetworkReply::putToHttpMultipart()
2365 QSKIP("test server script cannot handle PUT data yet");
2368 static QSet<QByteArray> boundaries;
2370 QNetworkRequest request(url);
2371 QNetworkReplyPtr reply;
2373 QFETCH(QHttpMultiPart *, multiPart);
2374 QFETCH(QByteArray, expectedReplyData);
2375 QFETCH(QByteArray, contentType);
2377 // hack for testing the setting of the content-type header by hand:
2378 if (contentType == "custom") {
2379 QByteArray contentType("multipart/custom; boundary=\"" + multiPart->boundary() + "\"");
2380 request.setHeader(QNetworkRequest::ContentTypeHeader, contentType);
2383 QVERIFY2(! boundaries.contains(multiPart->boundary()), "boundary '" + multiPart->boundary() + "' has been created twice");
2384 boundaries.insert(multiPart->boundary());
2386 RUN_REQUEST(runMultipartRequest(request, reply, multiPart, "PUT"));
2387 multiPart->deleteLater();
2389 QCOMPARE(reply->url(), url);
2390 QCOMPARE(reply->error(), QNetworkReply::NoError);
2392 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
2394 QVERIFY(multiPart->boundary().count() > 20); // check that there is randomness after the "boundary_.oOo._" string
2395 QVERIFY(multiPart->boundary().count() < 70);
2396 QByteArray replyData = reply->readAll();
2398 expectedReplyData.prepend("content type: multipart/" + contentType + "; boundary=\"" + multiPart->boundary() + "\"\n");
2399 // QEXPECT_FAIL("nested", "the server does not understand nested multipart messages", Continue); // see above
2400 QCOMPARE(replyData, expectedReplyData);
2403 void tst_QNetworkReply::deleteFromHttp_data()
2405 QTest::addColumn<QUrl>("url");
2406 QTest::addColumn<int>("resultCode");
2407 QTest::addColumn<QNetworkReply::NetworkError>("error");
2409 // for status codes to expect, see http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
2411 QTest::newRow("405-method-not-allowed") << QUrl("http://" + QtNetworkSettings::serverName() + "/index.html") << 405 << QNetworkReply::ContentOperationNotPermittedError;
2412 QTest::newRow("200-ok") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/http-delete.cgi?200-ok") << 200 << QNetworkReply::NoError;
2413 QTest::newRow("202-accepted") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/http-delete.cgi?202-accepted") << 202 << QNetworkReply::NoError;
2414 QTest::newRow("204-no-content") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/http-delete.cgi?204-no-content") << 204 << QNetworkReply::NoError;
2415 QTest::newRow("404-not-found") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/http-delete.cgi?404-not-found") << 404 << QNetworkReply::ContentNotFoundError;
2418 void tst_QNetworkReply::deleteFromHttp()
2421 QFETCH(int, resultCode);
2422 QFETCH(QNetworkReply::NetworkError, error);
2423 QNetworkRequest request(url);
2424 QNetworkReplyPtr reply;
2425 runSimpleRequest(QNetworkAccessManager::DeleteOperation, request, reply, 0);
2426 QCOMPARE(reply->url(), url);
2427 QCOMPARE(reply->error(), error);
2428 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), resultCode);
2431 void tst_QNetworkReply::putGetDeleteGetFromHttp_data()
2433 QTest::addColumn<QUrl>("putUrl");
2434 QTest::addColumn<int>("putResultCode");
2435 QTest::addColumn<QNetworkReply::NetworkError>("putError");
2436 QTest::addColumn<QUrl>("deleteUrl");
2437 QTest::addColumn<int>("deleteResultCode");
2438 QTest::addColumn<QNetworkReply::NetworkError>("deleteError");
2439 QTest::addColumn<QUrl>("get2Url");
2440 QTest::addColumn<int>("get2ResultCode");
2441 QTest::addColumn<QNetworkReply::NetworkError>("get2Error");
2443 QUrl url("http://" + QtNetworkSettings::serverName());
2444 url.setPath(QString("/dav/qnetworkaccess-putToHttp-%1-%2")
2445 .arg(QTest::currentDataTag())
2446 .arg(uniqueExtension));
2448 // first use case: put, get (to check it is there), delete, get (to check it is not there anymore)
2449 QTest::newRow("success") << url << 201 << QNetworkReply::NoError << url << 204 << QNetworkReply::NoError << url << 404 << QNetworkReply::ContentNotFoundError;
2451 QUrl wrongUrl("http://" + QtNetworkSettings::serverName());
2452 wrongUrl.setPath(QString("/dav/qnetworkaccess-thisURLisNotAvailable"));
2454 // second use case: put, get (to check it is there), delete wrong URL, get (to check it is still there)
2455 QTest::newRow("delete-error") << url << 201 << QNetworkReply::NoError << wrongUrl << 404 << QNetworkReply::ContentNotFoundError << url << 200 << QNetworkReply::NoError;
2459 void tst_QNetworkReply::putGetDeleteGetFromHttp()
2461 QFETCH(QUrl, putUrl);
2462 QFETCH(int, putResultCode);
2463 QFETCH(QNetworkReply::NetworkError, putError);
2464 QFETCH(QUrl, deleteUrl);
2465 QFETCH(int, deleteResultCode);
2466 QFETCH(QNetworkReply::NetworkError, deleteError);
2467 QFETCH(QUrl, get2Url);
2468 QFETCH(int, get2ResultCode);
2469 QFETCH(QNetworkReply::NetworkError, get2Error);
2471 QNetworkRequest putRequest(putUrl);
2472 QNetworkRequest deleteRequest(deleteUrl);
2473 QNetworkRequest get2Request(get2Url);
2474 QNetworkReplyPtr reply;
2476 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PutOperation, putRequest, reply, 0));
2477 QCOMPARE(reply->error(), putError);
2478 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), putResultCode);
2480 runSimpleRequest(QNetworkAccessManager::GetOperation, putRequest, reply, 0);
2481 QCOMPARE(reply->error(), QNetworkReply::NoError);
2482 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2484 runSimpleRequest(QNetworkAccessManager::DeleteOperation, deleteRequest, reply, 0);
2485 QCOMPARE(reply->error(), deleteError);
2486 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), deleteResultCode);
2488 runSimpleRequest(QNetworkAccessManager::GetOperation, get2Request, reply, 0);
2489 QCOMPARE(reply->error(), get2Error);
2490 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), get2ResultCode);
2494 void tst_QNetworkReply::connectToIPv6Address_data()
2496 QTest::addColumn<QUrl>("url");
2497 QTest::addColumn<QNetworkReply::NetworkError>("error");
2498 QTest::addColumn<QByteArray>("dataToSend");
2499 QTest::addColumn<QByteArray>("hostfield");
2500 QTest::newRow("localhost") << QUrl(QByteArray("http://[::1]")) << QNetworkReply::NoError<< QByteArray("localhost") << QByteArray("[::1]");
2501 //QTest::newRow("ipv4localhost") << QUrl(QByteArray("http://127.0.0.1")) << QNetworkReply::NoError<< QByteArray("ipv4localhost") << QByteArray("127.0.0.1");
2502 //to add more test data here
2505 void tst_QNetworkReply::connectToIPv6Address()
2508 QFETCH(QNetworkReply::NetworkError, error);
2509 QFETCH(QByteArray, dataToSend);
2510 QFETCH(QByteArray, hostfield);
2512 if (!QtNetworkSettings::hasIPv6())
2513 QSKIP("system doesn't support ipv6!");
2515 QByteArray httpResponse = QByteArray("HTTP/1.0 200 OK\r\nContent-Length: ");
2516 httpResponse += QByteArray::number(dataToSend.size());
2517 httpResponse += "\r\n\r\n";
2518 httpResponse += dataToSend;
2520 MiniHttpServer server(httpResponse, false, NULL/*thread*/, true/*useipv6*/);
2521 server.doClose = true;
2523 url.setPort(server.serverPort());
2524 QNetworkRequest request(url);
2526 QNetworkReplyPtr reply(manager.get(request));
2527 QVERIFY(waitForFinish(reply) == Success);
2528 QByteArray content = reply->readAll();
2529 //qDebug() << server.receivedData;
2530 QByteArray hostinfo = "\r\nHost: " + hostfield + ":" + QByteArray::number(server.serverPort()) + "\r\n";
2531 QVERIFY(server.receivedData.contains(hostinfo));
2532 QVERIFY(content == dataToSend);
2533 QCOMPARE(reply->url(), request.url());
2534 QVERIFY(reply->error() == error);
2537 void tst_QNetworkReply::sendCustomRequestToHttp_data()
2539 QTest::addColumn<QUrl>("url");
2540 QTest::addColumn<QByteArray>("verb");
2541 QTest::addColumn<QBuffer *>("device");
2542 QTest::addColumn<int>("resultCode");
2543 QTest::addColumn<QNetworkReply::NetworkError>("error");
2544 QTest::addColumn<QByteArray>("expectedContent");
2546 QTest::newRow("options") << QUrl("http://" + QtNetworkSettings::serverName()) <<
2547 QByteArray("OPTIONS") << (QBuffer *) 0 << 200 << QNetworkReply::NoError << QByteArray();
2548 QTest::newRow("trace") << QUrl("http://" + QtNetworkSettings::serverName()) <<
2549 QByteArray("TRACE") << (QBuffer *) 0 << 200 << QNetworkReply::NoError << QByteArray();
2550 QTest::newRow("connect") << QUrl("http://" + QtNetworkSettings::serverName()) <<
2551 QByteArray("CONNECT") << (QBuffer *) 0 << 400 << QNetworkReply::UnknownContentError << QByteArray(); // 400 = Bad Request
2552 QTest::newRow("nonsense") << QUrl("http://" + QtNetworkSettings::serverName()) <<
2553 QByteArray("NONSENSE") << (QBuffer *) 0 << 501 << QNetworkReply::ProtocolUnknownError << QByteArray(); // 501 = Method Not Implemented
2555 QByteArray ba("test");
2556 QBuffer *buffer = new QBuffer;
2557 buffer->setData(ba);
2558 buffer->open(QIODevice::ReadOnly);
2559 QTest::newRow("post") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi") << QByteArray("POST")
2560 << buffer << 200 << QNetworkReply::NoError << QByteArray("098f6bcd4621d373cade4e832627b4f6\n");
2562 QByteArray ba2("test");
2563 QBuffer *buffer2 = new QBuffer;
2564 buffer2->setData(ba2);
2565 buffer2->open(QIODevice::ReadOnly);
2566 QTest::newRow("put") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi") << QByteArray("PUT")
2567 << buffer2 << 200 << QNetworkReply::NoError << QByteArray("098f6bcd4621d373cade4e832627b4f6\n");
2570 void tst_QNetworkReply::sendCustomRequestToHttp()
2573 QNetworkRequest request(url);
2574 QNetworkReplyPtr reply;
2575 QFETCH(QByteArray, verb);
2576 QFETCH(QBuffer *, device);
2577 runCustomRequest(request, reply, verb, device);
2578 QCOMPARE(reply->url(), url);
2579 QFETCH(QNetworkReply::NetworkError, error);
2580 QCOMPARE(reply->error(), error);
2581 QFETCH(int, resultCode);
2582 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), resultCode);
2583 QFETCH(QByteArray, expectedContent);
2584 if (! expectedContent.isEmpty())
2585 QCOMPARE(reply->readAll(), expectedContent);
2588 void tst_QNetworkReply::ioGetFromData_data()
2590 QTest::addColumn<QString>("urlStr");
2591 QTest::addColumn<QByteArray>("data");
2593 QTest::newRow("data-empty") << "data:," << QByteArray();
2594 QTest::newRow("data-literal") << "data:,foo" << QByteArray("foo");
2595 QTest::newRow("data-pct") << "data:,%3Cbody%20contentEditable%3Dtrue%3E%0D%0A"
2596 << QByteArray("<body contentEditable=true>\r\n");
2597 QTest::newRow("data-base64") << "data:;base64,UXQgaXMgZ3JlYXQh" << QByteArray("Qt is great!");
2600 void tst_QNetworkReply::ioGetFromData()
2602 QFETCH(QString, urlStr);
2604 QUrl url = QUrl::fromEncoded(urlStr.toLatin1());
2605 QNetworkRequest request(url);
2607 QNetworkReplyPtr reply(manager.get(request));
2608 DataReader reader(reply);
2610 connect(reply, SIGNAL(finished()),
2611 &QTestEventLoop::instance(), SLOT(exitLoop()));
2612 QTestEventLoop::instance().enterLoop(10);
2613 QVERIFY(!QTestEventLoop::instance().timeout());
2615 QCOMPARE(reply->url(), request.url());
2616 QCOMPARE(reply->error(), QNetworkReply::NoError);
2618 QFETCH(QByteArray, data);
2619 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toInt(), data.size());
2620 QCOMPARE(reader.data.size(), data.size());
2621 QCOMPARE(reader.data, data);
2624 void tst_QNetworkReply::ioGetFromFileSpecial_data()
2626 getFromFileSpecial_data();
2629 void tst_QNetworkReply::ioGetFromFileSpecial()
2631 QFETCH(QString, fileName);
2632 QFETCH(QString, url);
2634 QFile resource(fileName);
2635 QVERIFY(resource.open(QIODevice::ReadOnly));
2637 QNetworkRequest request;
2638 request.setUrl(url);
2639 QNetworkReplyPtr reply(manager.get(request));
2640 DataReader reader(reply);
2642 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
2643 QTestEventLoop::instance().enterLoop(10);
2644 QVERIFY(!QTestEventLoop::instance().timeout());
2646 QCOMPARE(reply->url(), request.url());
2647 QCOMPARE(reply->error(), QNetworkReply::NoError);
2649 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), resource.size());
2650 QCOMPARE(qint64(reader.data.size()), resource.size());
2651 QCOMPARE(reader.data, resource.readAll());
2654 void tst_QNetworkReply::ioGetFromFile_data()
2659 void tst_QNetworkReply::ioGetFromFile()
2661 QTemporaryFile file(QDir::currentPath() + "/temp-XXXXXX");
2662 file.setAutoRemove(true);
2663 QVERIFY(file.open());
2665 QFETCH(QByteArray, data);
2666 QVERIFY(file.write(data) == data.size());
2668 QCOMPARE(file.size(), qint64(data.size()));
2670 QNetworkRequest request(QUrl::fromLocalFile(file.fileName()));
2671 QNetworkReplyPtr reply(manager.get(request));
2672 QVERIFY(reply->isFinished()); // a file should immediately be done
2673 DataReader reader(reply);
2675 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
2676 QTestEventLoop::instance().enterLoop(10);
2677 QVERIFY(!QTestEventLoop::instance().timeout());
2679 QCOMPARE(reply->url(), request.url());
2680 QCOMPARE(reply->error(), QNetworkReply::NoError);
2682 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), file.size());
2683 QCOMPARE(qint64(reader.data.size()), file.size());
2684 QCOMPARE(reader.data, data);
2687 void tst_QNetworkReply::ioGetFromFtp_data()
2689 QTest::addColumn<QString>("fileName");
2690 QTest::addColumn<qint64>("expectedSize");
2692 QTest::newRow("bigfile") << "bigfile" << Q_INT64_C(519240);
2694 QFile file(testDataDir + "/rfc3252.txt");
2695 QTest::newRow("rfc3252.txt") << "rfc3252.txt" << file.size();
2698 void tst_QNetworkReply::ioGetFromFtp()
2700 QFETCH(QString, fileName);
2701 QFile reference(fileName);
2702 reference.open(QIODevice::ReadOnly); // will fail for bigfile
2704 QNetworkRequest request("ftp://" + QtNetworkSettings::serverName() + "/qtest/" + fileName);
2705 QNetworkReplyPtr reply(manager.get(request));
2706 DataReader reader(reply);
2708 QVERIFY(waitForFinish(reply) == Success);
2710 QCOMPARE(reply->url(), request.url());
2711 QCOMPARE(reply->error(), QNetworkReply::NoError);
2713 QFETCH(qint64, expectedSize);
2714 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), expectedSize);
2715 QCOMPARE(qint64(reader.data.size()), expectedSize);
2717 if (reference.isOpen())
2718 QCOMPARE(reader.data, reference.readAll());
2721 void tst_QNetworkReply::ioGetFromFtpWithReuse()
2723 QString fileName = testDataDir + "/rfc3252.txt";
2724 QFile reference(fileName);
2725 reference.open(QIODevice::ReadOnly);
2727 QNetworkRequest request(QUrl("ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
2729 // two concurrent (actually, consecutive) gets:
2730 QNetworkReplyPtr reply1(manager.get(request));
2731 DataReader reader1(reply1);
2732 QNetworkReplyPtr reply2(manager.get(request));
2733 DataReader reader2(reply2);
2734 QSignalSpy spy(reply1.data(), SIGNAL(finished()));
2736 QVERIFY(waitForFinish(reply1) == Success);
2737 QVERIFY(waitForFinish(reply2) == Success);
2739 QCOMPARE(reply1->url(), request.url());
2740 QCOMPARE(reply2->url(), request.url());
2741 QCOMPARE(reply1->error(), QNetworkReply::NoError);
2742 QCOMPARE(reply2->error(), QNetworkReply::NoError);
2744 QCOMPARE(qint64(reader1.data.size()), reference.size());
2745 QCOMPARE(qint64(reader2.data.size()), reference.size());
2746 QCOMPARE(reply1->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
2747 QCOMPARE(reply2->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
2749 QByteArray referenceData = reference.readAll();
2750 QCOMPARE(reader1.data, referenceData);
2751 QCOMPARE(reader2.data, referenceData);
2754 void tst_QNetworkReply::ioGetFromHttp()
2756 QFile reference(testDataDir + "/rfc3252.txt");
2757 QVERIFY(reference.open(QIODevice::ReadOnly));
2759 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
2760 QNetworkReplyPtr reply(manager.get(request));
2761 DataReader reader(reply);
2763 QVERIFY(waitForFinish(reply) == Success);
2765 QCOMPARE(reply->url(), request.url());
2766 QCOMPARE(reply->error(), QNetworkReply::NoError);
2767 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2769 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
2770 QCOMPARE(qint64(reader.data.size()), reference.size());
2772 QCOMPARE(reader.data, reference.readAll());
2775 void tst_QNetworkReply::ioGetFromHttpWithReuseParallel()
2777 QFile reference(testDataDir + "/rfc3252.txt");
2778 QVERIFY(reference.open(QIODevice::ReadOnly));
2780 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
2781 QNetworkReplyPtr reply1(manager.get(request));
2782 QNetworkReplyPtr reply2(manager.get(request));
2783 DataReader reader1(reply1);
2784 DataReader reader2(reply2);
2785 QSignalSpy spy(reply1.data(), SIGNAL(finished()));
2787 QVERIFY(waitForFinish(reply2) == Success);
2788 QVERIFY(waitForFinish(reply1) == Success);
2790 QCOMPARE(reply1->url(), request.url());
2791 QCOMPARE(reply2->url(), request.url());
2792 QCOMPARE(reply1->error(), QNetworkReply::NoError);
2793 QCOMPARE(reply2->error(), QNetworkReply::NoError);
2794 QCOMPARE(reply1->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2795 QCOMPARE(reply2->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2797 QCOMPARE(reply1->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
2798 QCOMPARE(reply2->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
2799 QCOMPARE(qint64(reader1.data.size()), reference.size());
2800 QCOMPARE(qint64(reader2.data.size()), reference.size());
2802 QByteArray referenceData = reference.readAll();
2803 QCOMPARE(reader1.data, referenceData);
2804 QCOMPARE(reader2.data, referenceData);
2807 void tst_QNetworkReply::ioGetFromHttpWithReuseSequential()
2809 QFile reference(testDataDir + "/rfc3252.txt");
2810 QVERIFY(reference.open(QIODevice::ReadOnly));
2812 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
2814 QNetworkReplyPtr reply(manager.get(request));
2815 DataReader reader(reply);
2817 QVERIFY(waitForFinish(reply) == Success);
2819 QCOMPARE(reply->url(), request.url());
2820 QCOMPARE(reply->error(), QNetworkReply::NoError);
2821 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2823 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
2824 QCOMPARE(qint64(reader.data.size()), reference.size());
2826 QCOMPARE(reader.data, reference.readAll());
2830 // rinse and repeat:
2832 QNetworkReplyPtr reply(manager.get(request));
2833 DataReader reader(reply);
2835 QVERIFY(waitForFinish(reply) == Success);
2837 QCOMPARE(reply->url(), request.url());
2838 QCOMPARE(reply->error(), QNetworkReply::NoError);
2839 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2841 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
2842 QCOMPARE(qint64(reader.data.size()), reference.size());
2844 QCOMPARE(reader.data, reference.readAll());
2848 void tst_QNetworkReply::ioGetFromHttpWithAuth_data()
2850 QTest::addColumn<QUrl>("url");
2851 QTest::addColumn<QByteArray>("expectedData");
2852 QTest::addColumn<int>("expectedAuth");
2854 QFile reference(testDataDir + "/rfc3252.txt");
2855 reference.open(QIODevice::ReadOnly);
2856 QByteArray referenceData = reference.readAll();
2857 QTest::newRow("basic") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt") << referenceData << 1;
2858 QTest::newRow("digest") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/auth-digest/") << QByteArray("digest authentication successful\n") << 1;
2859 //if url contains username & password, then it should be used
2860 QTest::newRow("basic-in-url") << QUrl("http://httptest:httptest@" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt") << referenceData << 0;
2861 QTest::newRow("digest-in-url") << QUrl("http://httptest:httptest@" + QtNetworkSettings::serverName() + "/qtest/auth-digest/") << QByteArray("digest authentication successful\n") << 0;
2862 // if url contains incorrect credentials, expect QNAM to ask for good ones (even if cached - matches behaviour of browsers)
2863 QTest::newRow("basic-bad-user-in-url") << QUrl("http://baduser:httptest@" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt") << referenceData << 3;
2864 QTest::newRow("basic-bad-password-in-url") << QUrl("http://httptest:wrong@" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt") << referenceData << 3;
2865 QTest::newRow("digest-bad-user-in-url") << QUrl("http://baduser:httptest@" + QtNetworkSettings::serverName() + "/qtest/auth-digest/") << QByteArray("digest authentication successful\n") << 3;
2866 QTest::newRow("digest-bad-password-in-url") << QUrl("http://httptest:wrong@" + QtNetworkSettings::serverName() + "/qtest/auth-digest/") << QByteArray("digest authentication successful\n") << 3;
2869 void tst_QNetworkReply::ioGetFromHttpWithAuth()
2871 // This test sends three requests
2872 // The first two in parallel
2873 // The third after the first two finished
2876 QFETCH(QByteArray, expectedData);
2877 QFETCH(int, expectedAuth);
2878 QNetworkRequest request(url);
2880 QNetworkReplyPtr reply1(manager.get(request));
2881 QNetworkReplyPtr reply2(manager.get(request));
2882 DataReader reader1(reply1);
2883 DataReader reader2(reply2);
2884 QSignalSpy finishedspy(reply1.data(), SIGNAL(finished()));
2886 QSignalSpy authspy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2887 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
2888 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2890 QVERIFY(waitForFinish(reply2) == Success);
2891 QVERIFY(waitForFinish(reply1) == Success);
2893 manager.disconnect(SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
2894 this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2896 QCOMPARE(reply1->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2897 QCOMPARE(reply2->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2898 QCOMPARE(reader1.data, expectedData);
2899 QCOMPARE(reader2.data, expectedData);
2901 QCOMPARE(authspy.count(), (expectedAuth ? 1 : 0));
2902 expectedAuth = qMax(0, expectedAuth - 1);
2905 // rinse and repeat:
2907 QNetworkReplyPtr reply(manager.get(request));
2908 DataReader reader(reply);
2910 QSignalSpy authspy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2911 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
2912 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2914 QVERIFY(waitForFinish(reply) == Success);
2916 manager.disconnect(SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
2917 this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2919 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2920 QCOMPARE(reader.data, expectedData);
2922 QCOMPARE(authspy.count(), (expectedAuth ? 1 : 0));
2923 expectedAuth = qMax(0, expectedAuth - 1);
2926 // now check with synchronous calls:
2928 request.setAttribute(
2929 QNetworkRequest::SynchronousRequestAttribute,
2932 QSignalSpy authspy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2933 QNetworkReplyPtr replySync(manager.get(request));
2934 QVERIFY(replySync->isFinished()); // synchronous
2936 // bad credentials in a synchronous request should just fail
2937 QCOMPARE(replySync->error(), QNetworkReply::AuthenticationRequiredError);
2939 QCOMPARE(authspy.count(), 0);
2941 // we cannot use a data reader here, since that connects to the readyRead signal,
2942 // just use readAll()
2944 // the only thing we check here is that the auth cache was used when using synchronous requests
2945 QCOMPARE(replySync->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2946 QCOMPARE(replySync->readAll(), expectedData);
2950 // check that credentials are used from cache if the same url is requested without credentials
2952 url.setUserInfo(QString());
2953 request.setUrl(url);
2954 request.setAttribute(
2955 QNetworkRequest::SynchronousRequestAttribute,
2958 QSignalSpy authspy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2959 QNetworkReplyPtr replySync(manager.get(request));
2960 QVERIFY(replySync->isFinished()); // synchronous
2962 // bad credentials in a synchronous request should just fail
2963 QCOMPARE(replySync->error(), QNetworkReply::AuthenticationRequiredError);
2965 QCOMPARE(authspy.count(), 0);
2967 // we cannot use a data reader here, since that connects to the readyRead signal,
2968 // just use readAll()
2970 // the only thing we check here is that the auth cache was used when using synchronous requests
2971 QCOMPARE(replySync->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2972 QCOMPARE(replySync->readAll(), expectedData);
2977 void tst_QNetworkReply::ioGetFromHttpWithAuthSynchronous()
2979 // verify that we do not enter an endless loop with synchronous calls and wrong credentials
2980 // the case when we succeed with the login is tested in ioGetFromHttpWithAuth()
2982 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt"));
2983 request.setAttribute(
2984 QNetworkRequest::SynchronousRequestAttribute,
2987 QSignalSpy authspy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2988 QNetworkReplyPtr replySync(manager.get(request));
2989 QVERIFY(replySync->isFinished()); // synchronous
2990 QCOMPARE(replySync->error(), QNetworkReply::AuthenticationRequiredError);
2991 QCOMPARE(authspy.count(), 0);
2992 QCOMPARE(replySync->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 401);
2995 void tst_QNetworkReply::ioGetFromHttpWithProxyAuth()
2997 // This test sends three requests
2998 // The first two in parallel
2999 // The third after the first two finished
3000 QFile reference(testDataDir + "/rfc3252.txt");
3001 QVERIFY(reference.open(QIODevice::ReadOnly));
3003 QNetworkProxy proxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129);
3004 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
3006 manager.setProxy(proxy);
3007 QNetworkReplyPtr reply1(manager.get(request));
3008 QNetworkReplyPtr reply2(manager.get(request));
3009 manager.setProxy(QNetworkProxy());
3011 DataReader reader1(reply1);
3012 DataReader reader2(reply2);
3013 QSignalSpy finishedspy(reply1.data(), SIGNAL(finished()));
3015 QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3016 connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3017 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3019 QVERIFY(waitForFinish(reply2) == Success);
3020 QVERIFY(waitForFinish(reply1) == Success);
3022 manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3023 this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3025 QCOMPARE(reply1->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
3026 QCOMPARE(reply2->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
3027 QByteArray referenceData = reference.readAll();
3028 QCOMPARE(reader1.data, referenceData);
3029 QCOMPARE(reader2.data, referenceData);
3031 QCOMPARE(authspy.count(), 1);
3035 // rinse and repeat:
3037 manager.setProxy(proxy);
3038 QNetworkReplyPtr reply(manager.get(request));
3039 DataReader reader(reply);
3040 manager.setProxy(QNetworkProxy());
3042 QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3043 connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3044 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3046 QVERIFY(waitForFinish(reply) == Success);
3048 manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3049 this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3051 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
3052 QCOMPARE(reader.data, reference.readAll());
3054 QCOMPARE(authspy.count(), 0);
3057 // now check with synchronous calls:
3060 request.setAttribute(
3061 QNetworkRequest::SynchronousRequestAttribute,
3064 QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3065 QNetworkReplyPtr replySync(manager.get(request));
3066 QVERIFY(replySync->isFinished()); // synchronous
3067 QCOMPARE(authspy.count(), 0);
3069 // we cannot use a data reader here, since that connects to the readyRead signal,
3070 // just use readAll()
3072 // the only thing we check here is that the proxy auth cache was used when using synchronous requests
3073 QCOMPARE(replySync->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
3074 QCOMPARE(replySync->readAll(), reference.readAll());
3078 void tst_QNetworkReply::ioGetFromHttpWithProxyAuthSynchronous()
3080 // verify that we do not enter an endless loop with synchronous calls and wrong credentials
3081 // the case when we succeed with the login is tested in ioGetFromHttpWithAuth()
3083 QNetworkProxy proxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129);
3084 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
3085 manager.setProxy(proxy);
3086 request.setAttribute(
3087 QNetworkRequest::SynchronousRequestAttribute,
3090 QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3091 QNetworkReplyPtr replySync(manager.get(request));
3092 manager.setProxy(QNetworkProxy()); // reset
3093 QVERIFY(replySync->isFinished()); // synchronous
3094 QCOMPARE(replySync->error(), QNetworkReply::ProxyAuthenticationRequiredError);
3095 QCOMPARE(authspy.count(), 0);
3096 QCOMPARE(replySync->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 407);
3099 void tst_QNetworkReply::ioGetFromHttpWithSocksProxy()
3101 // HTTP caching proxies are tested by the above function
3102 // test SOCKSv5 proxies too
3104 QFile reference(testDataDir + "/rfc3252.txt");
3105 QVERIFY(reference.open(QIODevice::ReadOnly));
3107 QNetworkProxy proxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080);
3108 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
3110 manager.setProxy(proxy);
3111 QNetworkReplyPtr reply(manager.get(request));
3112 DataReader reader(reply);
3113 manager.setProxy(QNetworkProxy());
3115 QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3116 connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3117 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3119 QVERIFY(waitForFinish(reply) == Success);
3121 manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3122 this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3124 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
3125 QCOMPARE(reader.data, reference.readAll());
3127 QCOMPARE(authspy.count(), 0);
3130 // set an invalid proxy just to make sure that we can't load
3131 proxy = QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1079);
3133 manager.setProxy(proxy);
3134 QNetworkReplyPtr reply(manager.get(request));
3135 DataReader reader(reply);
3136 manager.setProxy(QNetworkProxy());
3138 QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3139 connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3140 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3142 QVERIFY(waitForFinish(reply) == Failure);
3144 manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3145 this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3147 QVERIFY(!reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).isValid());
3148 QVERIFY(reader.data.isEmpty());
3150 QVERIFY(int(reply->error()) > 0);
3151 QEXPECT_FAIL("", "QTcpSocket doesn't return enough information yet", Continue);
3152 QCOMPARE(int(reply->error()), int(QNetworkReply::ProxyConnectionRefusedError));
3154 QCOMPARE(authspy.count(), 0);
3159 void tst_QNetworkReply::ioGetFromHttpsWithSslErrors()
3161 QFile reference(testDataDir + "/rfc3252.txt");
3162 QVERIFY(reference.open(QIODevice::ReadOnly));
3164 QNetworkRequest request(QUrl("https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
3165 QNetworkReplyPtr reply(manager.get(request));
3166 DataReader reader(reply);
3168 QSignalSpy sslspy(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)));
3169 connect(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
3170 SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
3171 connect(reply, SIGNAL(metaDataChanged()), SLOT(storeSslConfiguration()));
3173 QVERIFY(waitForFinish(reply) == Success);
3175 manager.disconnect(SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
3176 this, SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
3178 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
3179 QCOMPARE(reader.data, reference.readAll());
3181 QCOMPARE(sslspy.count(), 1);
3183 QVERIFY(!storedSslConfiguration.isNull());
3184 QVERIFY(!reply->sslConfiguration().isNull());
3187 void tst_QNetworkReply::ioGetFromHttpsWithIgnoreSslErrors()
3189 // same as above, except that we call ignoreSslErrors and don't connect
3190 // to the sslErrors() signal (which is *still* emitted)
3192 QFile reference(testDataDir + "/rfc3252.txt");
3193 QVERIFY(reference.open(QIODevice::ReadOnly));
3195 QNetworkRequest request(QUrl("https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
3197 QNetworkReplyPtr reply(manager.get(request));
3198 reply->ignoreSslErrors();
3199 DataReader reader(reply);
3201 QSignalSpy sslspy(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)));
3202 connect(reply, SIGNAL(metaDataChanged()), SLOT(storeSslConfiguration()));
3204 QVERIFY(waitForFinish(reply) == Success);
3206 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
3207 QCOMPARE(reader.data, reference.readAll());
3209 QCOMPARE(sslspy.count(), 1);
3211 QVERIFY(!storedSslConfiguration.isNull());
3212 QVERIFY(!reply->sslConfiguration().isNull());
3215 void tst_QNetworkReply::ioGetFromHttpsWithSslHandshakeError()
3217 QFile reference(testDataDir + "/rfc3252.txt");
3218 QVERIFY(reference.open(QIODevice::ReadOnly));
3220 QNetworkRequest request(QUrl("https://" + QtNetworkSettings::serverName() + ":80"));
3222 QNetworkReplyPtr reply(manager.get(request));
3223 reply->ignoreSslErrors();
3224 DataReader reader(reply);
3226 QSignalSpy sslspy(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)));
3227 connect(reply, SIGNAL(metaDataChanged()), SLOT(storeSslConfiguration()));
3229 QVERIFY(waitForFinish(reply) == Failure);
3231 QCOMPARE(reply->error(), QNetworkReply::SslHandshakeFailedError);
3232 QCOMPARE(sslspy.count(), 0);
3236 void tst_QNetworkReply::ioGetFromHttpBrokenServer_data()
3238 QTest::addColumn<QByteArray>("dataToSend");
3239 QTest::addColumn<bool>("doDisconnect");
3241 QTest::newRow("no-newline") << QByteArray("Hello World") << false;
3243 // these are OK now, we just eat the lonely newlines
3244 //QTest::newRow("just-newline") << QByteArray("\r\n") << false;
3245 //QTest::newRow("just-2newline") << QByteArray("\r\n\r\n") << false;
3247 QTest::newRow("with-newlines") << QByteArray("Long first line\r\nLong second line") << false;
3248 QTest::newRow("with-newlines2") << QByteArray("\r\nSecond line") << false;
3249 QTest::newRow("with-newlines3") << QByteArray("ICY\r\nSecond line") << false;
3250 QTest::newRow("invalid-version") << QByteArray("HTTP/123 200 \r\n") << false;
3251 QTest::newRow("invalid-version2") << QByteArray("HTTP/a.\033 200 \r\n") << false;
3252 QTest::newRow("invalid-reply-code") << QByteArray("HTTP/1.0 fuu \r\n") << false;
3254 QTest::newRow("empty+disconnect") << QByteArray() << true;
3256 QTest::newRow("no-newline+disconnect") << QByteArray("Hello World") << true;
3257 QTest::newRow("just-newline+disconnect") << QByteArray("\r\n") << true;
3258 QTest::newRow("just-2newline+disconnect") << QByteArray("\r\n\r\n") << true;
3259 QTest::newRow("with-newlines+disconnect") << QByteArray("Long first line\r\nLong second line") << true;
3260 QTest::newRow("with-newlines2+disconnect") << QByteArray("\r\nSecond line") << true;
3261 QTest::newRow("with-newlines3+disconnect") << QByteArray("ICY\r\nSecond line") << true;
3263 QTest::newRow("invalid-version+disconnect") << QByteArray("HTTP/123 200 ") << true;
3264 QTest::newRow("invalid-version2+disconnect") << QByteArray("HTTP/a.\033 200 ") << true;
3265 QTest::newRow("invalid-reply-code+disconnect") << QByteArray("HTTP/1.0 fuu ") << true;
3267 QTest::newRow("immediate disconnect") << QByteArray("") << true;
3268 QTest::newRow("justHalfStatus+disconnect") << QByteArray("HTTP/1.1") << true;
3269 QTest::newRow("justStatus+disconnect") << QByteArray("HTTP/1.1 200 OK\r\n") << true;
3270 QTest::newRow("justStatusAndHalfHeaders+disconnect") << QByteArray("HTTP/1.1 200 OK\r\nContent-L") << true;
3272 QTest::newRow("halfContent+disconnect") << QByteArray("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\nAB") << true;
3276 void tst_QNetworkReply::ioGetFromHttpBrokenServer()
3278 QFETCH(QByteArray, dataToSend);
3279 QFETCH(bool, doDisconnect);
3280 MiniHttpServer server(dataToSend);
3281 server.doClose = doDisconnect;
3283 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
3284 QNetworkReplyPtr reply(manager.get(request));
3285 QSignalSpy spy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError)));
3287 QVERIFY(waitForFinish(reply) == Failure);
3289 QCOMPARE(reply->url(), request.url());
3290 QCOMPARE(spy.count(), 1);
3291 QVERIFY(reply->error() != QNetworkReply::NoError);
3294 void tst_QNetworkReply::ioGetFromHttpStatus100_data()
3296 QTest::addColumn<QByteArray>("dataToSend");
3297 QTest::addColumn<int>("statusCode");
3298 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") << 200;
3299 QTest::newRow("minimal") << QByteArray("HTTP/1.1 100 Continue\n\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") << 200;
3300 QTest::newRow("minimal2") << QByteArray("HTTP/1.1 100 Continue\n\nHTTP/1.0 200 OK\r\n\r\n") << 200;
3301 QTest::newRow("minimal3") << QByteArray("HTTP/1.1 100 Continue\n\nHTTP/1.0 200 OK\n\n") << 200;
3302 QTest::newRow("minimal+404") << QByteArray("HTTP/1.1 100 Continue\n\nHTTP/1.0 204 No Content\r\n\r\n") << 204;
3303 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") << 200;
3304 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") << 200;
3307 void tst_QNetworkReply::ioGetFromHttpStatus100()
3309 QFETCH(QByteArray, dataToSend);
3310 QFETCH(int, statusCode);
3311 MiniHttpServer server(dataToSend);
3312 server.doClose = true;
3314 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
3315 QNetworkReplyPtr reply(manager.get(request));
3317 QVERIFY(waitForFinish(reply) == Success);
3319 QCOMPARE(reply->url(), request.url());
3320 QCOMPARE(reply->error(), QNetworkReply::NoError);
3321 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), statusCode);
3322 QVERIFY(reply->rawHeader("bla").isNull());
3325 void tst_QNetworkReply::ioGetFromHttpNoHeaders_data()
3327 QTest::addColumn<QByteArray>("dataToSend");
3328 QTest::newRow("justStatus+noheaders+disconnect") << QByteArray("HTTP/1.0 200 OK\r\n\r\n");
3331 void tst_QNetworkReply::ioGetFromHttpNoHeaders()
3333 QFETCH(QByteArray, dataToSend);
3334 MiniHttpServer server(dataToSend);
3335 server.doClose = true;
3337 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
3338 QNetworkReplyPtr reply(manager.get(request));
3340 QVERIFY(waitForFinish(reply) == Success);
3342 QCOMPARE(reply->url(), request.url());
3343 QCOMPARE(reply->error(), QNetworkReply::NoError);
3344 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
3347 void tst_QNetworkReply::ioGetFromHttpWithCache_data()
3349 qRegisterMetaType<MyMemoryCache::CachedContent>();
3350 QTest::addColumn<QByteArray>("dataToSend");
3351 QTest::addColumn<QString>("body");
3352 QTest::addColumn<MyMemoryCache::CachedContent>("cachedReply");
3353 QTest::addColumn<int>("cacheMode");
3354 QTest::addColumn<QStringList>("extraHttpHeaders");
3355 QTest::addColumn<bool>("loadedFromCache");
3356 QTest::addColumn<bool>("networkUsed");
3358 QByteArray reply200 =
3360 "Connection: keep-alive\r\n"
3361 "Content-Type: text/plain\r\n"
3362 "Cache-control: no-cache\r\n"
3363 "Content-length: 8\r\n"
3366 QByteArray reply304 =
3367 "HTTP/1.0 304 Use Cache\r\n"
3368 "Connection: keep-alive\r\n"
3371 QTest::newRow("not-cached,always-network")
3372 << reply200 << "Reloaded" << MyMemoryCache::CachedContent() << int(QNetworkRequest::AlwaysNetwork) << QStringList() << false << true;
3373 QTest::newRow("not-cached,prefer-network")
3374 << reply200 << "Reloaded" << MyMemoryCache::CachedContent() << int(QNetworkRequest::PreferNetwork) << QStringList() << false << true;
3375 QTest::newRow("not-cached,prefer-cache")
3376 << reply200 << "Reloaded" << MyMemoryCache::CachedContent() << int(QNetworkRequest::PreferCache) << QStringList() << false << true;
3378 QDateTime present = QDateTime::currentDateTime().toUTC();
3379 QDateTime past = present.addSecs(-3600);
3380 QDateTime future = present.addSecs(3600);
3381 static const char dateFormat[] = "ddd, dd MMM yyyy hh:mm:ss 'GMT'";
3383 QNetworkCacheMetaData::RawHeaderList rawHeaders;
3384 MyMemoryCache::CachedContent content;
3385 content.second = "Not-reloaded";
3386 content.first.setLastModified(past);
3392 rawHeaders << QNetworkCacheMetaData::RawHeader("Date", QLocale::c().toString(past, dateFormat).toLatin1())
3393 << QNetworkCacheMetaData::RawHeader("Cache-control", "max-age=0"); // isn't used in cache loading
3394 content.first.setRawHeaders(rawHeaders);
3395 content.first.setLastModified(past);
3396 content.first.setExpirationDate(past);
3398 QTest::newRow("expired,200,prefer-network")
3399 << reply200 << "Reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << false << true;
3400 QTest::newRow("expired,200,prefer-cache")
3401 << reply200 << "Reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << false << true;
3403 QTest::newRow("expired,304,prefer-network")
3404 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << true << true;
3405 QTest::newRow("expired,304,prefer-cache")
3406 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << true << true;
3409 // Set to not-expired
3412 rawHeaders << QNetworkCacheMetaData::RawHeader("Date", QLocale::c().toString(past, dateFormat).toLatin1())
3413 << QNetworkCacheMetaData::RawHeader("Cache-control", "max-age=7200"); // isn't used in cache loading
3414 content.first.setRawHeaders(rawHeaders);
3415 content.first.setExpirationDate(future);
3417 QTest::newRow("not-expired,200,always-network")
3418 << reply200 << "Reloaded" << content << int(QNetworkRequest::AlwaysNetwork) << QStringList() << false << true;
3419 QTest::newRow("not-expired,200,prefer-network")
3420 << reply200 << "Not-reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << true << false;
3421 QTest::newRow("not-expired,200,prefer-cache")
3422 << reply200 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << true << false;
3423 QTest::newRow("not-expired,200,always-cache")
3424 << reply200 << "Not-reloaded" << content << int(QNetworkRequest::AlwaysCache) << QStringList() << true << false;
3426 QTest::newRow("not-expired,304,prefer-network")
3427 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << true << false;
3428 QTest::newRow("not-expired,304,prefer-cache")
3429 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << true << false;
3430 QTest::newRow("not-expired,304,always-cache")
3431 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::AlwaysCache) << QStringList() << true << false;
3434 // Set must-revalidate now
3437 rawHeaders << QNetworkCacheMetaData::RawHeader("Date", QLocale::c().toString(past, dateFormat).toLatin1())
3438 << QNetworkCacheMetaData::RawHeader("Cache-control", "max-age=7200, must-revalidate"); // must-revalidate is used
3439 content.first.setRawHeaders(rawHeaders);
3441 QTest::newRow("must-revalidate,200,always-network")
3442 << reply200 << "Reloaded" << content << int(QNetworkRequest::AlwaysNetwork) << QStringList() << false << true;
3443 QTest::newRow("must-revalidate,200,prefer-network")
3444 << reply200 << "Reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << false << true;
3445 QTest::newRow("must-revalidate,200,prefer-cache")
3446 << reply200 << "Reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << false << true;
3447 QTest::newRow("must-revalidate,200,always-cache")
3448 << reply200 << "" << content << int(QNetworkRequest::AlwaysCache) << QStringList() << false << false;
3450 QTest::newRow("must-revalidate,304,prefer-network")
3451 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << true << true;
3452 QTest::newRow("must-revalidate,304,prefer-cache")
3453 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << true << true;
3454 QTest::newRow("must-revalidate,304,always-cache")
3455 << reply304 << "" << content << int(QNetworkRequest::AlwaysCache) << QStringList() << false << false;
3461 rawHeaders << QNetworkCacheMetaData::RawHeader("Date", QLocale::c().toString(past, dateFormat).toLatin1())
3462 << QNetworkCacheMetaData::RawHeader("Cache-control", "max-age=7200"); // isn't used in cache loading
3463 content.first.setRawHeaders(rawHeaders);
3464 content.first.setExpirationDate(future);
3466 QByteArray reply206 =
3468 "Connection: keep-alive\r\n"
3469 "Content-Type: text/plain\r\n"
3470 "Cache-control: no-cache\r\n"
3471 "Content-Range: bytes 2-6/8\r\n"
3472 "Content-length: 4\r\n"
3476 QTest::newRow("partial,dontuse-cache")
3477 << reply206 << "load" << content << int(QNetworkRequest::PreferCache) << (QStringList() << "Range" << "bytes=2-6") << false << true;
3480 void tst_QNetworkReply::ioGetFromHttpWithCache()
3482 QFETCH(QByteArray, dataToSend);
3483 MiniHttpServer server(dataToSend);
3484 server.doClose = false;
3486 MyMemoryCache *memoryCache = new MyMemoryCache(&manager);
3487 manager.setCache(memoryCache);
3489 QFETCH(MyMemoryCache::CachedContent, cachedReply);
3490 QUrl url = "http://localhost:" + QString::number(server.serverPort());
3491 cachedReply.first.setUrl(url);
3492 if (!cachedReply.second.isNull())
3493 memoryCache->cache.insert(url.toEncoded(), cachedReply);
3495 QFETCH(int, cacheMode);
3496 QNetworkRequest request(url);
3497 request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, cacheMode);
3498 request.setAttribute(QNetworkRequest::CacheSaveControlAttribute, false);
3500 QFETCH(QStringList, extraHttpHeaders);
3501 QStringListIterator it(extraHttpHeaders);
3502 while (it.hasNext()) {
3503 QString header = it.next();
3504 QString value = it.next();
3505 request.setRawHeader(header.toLatin1(), value.toLatin1()); // To latin1? Deal with it!
3508 QNetworkReplyPtr reply(manager.get(request));
3510 QVERIFY(waitForFinish(reply) != Timeout);
3512 QTEST(reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool(), "loadedFromCache");
3513 QTEST(server.totalConnections > 0, "networkUsed");
3514 QFETCH(QString, body);
3515 QCOMPARE(reply->readAll().constData(), qPrintable(body));
3518 void tst_QNetworkReply::ioGetWithManyProxies_data()
3520 QTest::addColumn<QList<QNetworkProxy> >("proxyList");
3521 QTest::addColumn<QNetworkProxy>("proxyUsed");
3522 QTest::addColumn<QString>("url");
3523 QTest::addColumn<QNetworkReply::NetworkError>("expectedError");
3525 QList<QNetworkProxy> proxyList;
3527 // All of the other functions test DefaultProxy
3528 // So let's test something else
3530 // Simple tests that work:
3532 // HTTP request with HTTP caching proxy
3533 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129);
3534 QTest::newRow("http-on-http")
3535 << proxyList << proxyList.at(0)
3536 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3537 << QNetworkReply::NoError;
3539 // HTTP request with HTTP transparent proxy
3541 proxyList << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3129);
3542 QTest::newRow("http-on-http2")
3543 << proxyList << proxyList.at(0)
3544 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3545 << QNetworkReply::NoError;
3547 // HTTP request with SOCKS transparent proxy
3549 proxyList << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081);
3550 QTest::newRow("http-on-socks")
3551 << proxyList << proxyList.at(0)
3552 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3553 << QNetworkReply::NoError;
3555 // FTP request with FTP caching proxy
3557 proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121);
3558 QTest::newRow("ftp-on-ftp")
3559 << proxyList << proxyList.at(0)
3560 << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3561 << QNetworkReply::NoError;
3563 // The following test doesn't work because QFtp is too limited
3564 // It can only talk to its own kind of proxies
3566 // FTP request with SOCKSv5 transparent proxy
3568 proxyList << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081);
3569 QTest::newRow("ftp-on-socks")
3570 << proxyList << proxyList.at(0)
3571 << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3572 << QNetworkReply::NoError;
3575 // HTTPS with HTTP transparent proxy
3577 proxyList << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3129);
3578 QTest::newRow("https-on-http")
3579 << proxyList << proxyList.at(0)
3580 << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3581 << QNetworkReply::NoError;
3583 // HTTPS request with SOCKS transparent proxy
3585 proxyList << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081);
3586 QTest::newRow("https-on-socks")
3587 << proxyList << proxyList.at(0)
3588 << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3589 << QNetworkReply::NoError;
3594 // HTTP request with FTP caching proxy
3596 proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121);
3597 QTest::newRow("http-on-ftp")
3598 << proxyList << QNetworkProxy()
3599 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3600 << QNetworkReply::ProxyNotFoundError;
3602 // FTP request with HTTP caching proxy
3604 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129);
3605 QTest::newRow("ftp-on-http")
3606 << proxyList << QNetworkProxy()
3607 << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3608 << QNetworkReply::ProxyNotFoundError;
3610 // FTP request with HTTP caching proxies
3612 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
3613 << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3130);
3614 QTest::newRow("ftp-on-multiple-http")
3615 << proxyList << QNetworkProxy()
3616 << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3617 << QNetworkReply::ProxyNotFoundError;
3620 // HTTPS with HTTP caching proxy
3622 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129);
3623 QTest::newRow("https-on-httptransparent")
3624 << proxyList << QNetworkProxy()
3625 << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3626 << QNetworkReply::ProxyNotFoundError;
3628 // HTTPS with FTP caching proxy
3630 proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121);
3631 QTest::newRow("https-on-ftp")
3632 << proxyList << QNetworkProxy()
3633 << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3634 << QNetworkReply::ProxyNotFoundError;
3637 // Complex requests:
3639 // HTTP request with more than one HTTP proxy
3641 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
3642 << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3130);
3643 QTest::newRow("http-on-multiple-http")
3644 << proxyList << proxyList.at(0)
3645 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3646 << QNetworkReply::NoError;
3648 // HTTP request with HTTP + SOCKS
3650 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
3651 << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081);
3652 QTest::newRow("http-on-http+socks")
3653 << proxyList << proxyList.at(0)
3654 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3655 << QNetworkReply::NoError;
3657 // HTTP request with FTP + HTTP + SOCKS
3659 proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121)
3660 << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
3661 << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081);
3662 QTest::newRow("http-on-ftp+http+socks")
3663 << proxyList << proxyList.at(1) // second proxy should be used
3664 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3665 << QNetworkReply::NoError;
3667 // HTTP request with NoProxy + HTTP
3669 proxyList << QNetworkProxy(QNetworkProxy::NoProxy)
3670 << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129);
3671 QTest::newRow("http-on-noproxy+http")
3672 << proxyList << proxyList.at(0)
3673 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3674 << QNetworkReply::NoError;
3676 // HTTP request with FTP + NoProxy
3678 proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121)
3679 << QNetworkProxy(QNetworkProxy::NoProxy);
3680 QTest::newRow("http-on-ftp+noproxy")
3681 << proxyList << proxyList.at(1) // second proxy should be used
3682 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3683 << QNetworkReply::NoError;
3685 // FTP request with HTTP Caching + FTP
3687 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
3688 << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121);
3689 QTest::newRow("ftp-on-http+ftp")
3690 << proxyList << proxyList.at(1) // second proxy should be used
3691 << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3692 << QNetworkReply::NoError;
3695 // HTTPS request with HTTP Caching + HTTP transparent
3697 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
3698 << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3129);
3699 QTest::newRow("https-on-httpcaching+http")
3700 << proxyList << proxyList.at(1) // second proxy should be used
3701 << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3702 << QNetworkReply::NoError;
3704 // HTTPS request with FTP + HTTP C + HTTP T
3706 proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121)
3707 << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
3708 << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3129);
3709 QTest::newRow("https-on-ftp+httpcaching+http")
3710 << proxyList << proxyList.at(2) // skip the first two
3711 << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3712 << QNetworkReply::NoError;
3716 void tst_QNetworkReply::ioGetWithManyProxies()
3718 // Test proxy factories
3720 QFile reference(testDataDir + "/rfc3252.txt");
3721 QVERIFY(reference.open(QIODevice::ReadOnly));
3723 // set the proxy factory:
3724 QFETCH(QList<QNetworkProxy>, proxyList);
3725 MyProxyFactory *proxyFactory = new MyProxyFactory;
3726 proxyFactory->toReturn = proxyList;
3727 manager.setProxyFactory(proxyFactory);
3729 QFETCH(QString, url);
3731 QNetworkRequest request(theUrl);
3732 QNetworkReplyPtr reply(manager.get(request));
3733 DataReader reader(reply);
3735 QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3736 connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3737 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3739 connect(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
3740 SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
3743 QVERIFY(waitForFinish(reply) != Timeout);
3745 manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3746 this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3748 manager.disconnect(SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
3749 this, SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
3752 QFETCH(QNetworkReply::NetworkError, expectedError);
3753 QEXPECT_FAIL("ftp-on-socks", "QFtp is too limited and won't accept non-FTP proxies", Abort);
3754 QCOMPARE(reply->error(), expectedError);
3756 // Verify that the factory was called properly
3757 QCOMPARE(proxyFactory->callCount, 1);
3758 QCOMPARE(proxyFactory->lastQuery, QNetworkProxyQuery(theUrl));
3760 if (expectedError == QNetworkReply::NoError) {
3761 // request succeeded
3762 QCOMPARE(reader.data, reference.readAll());
3764 // now verify that the proxies worked:
3765 QFETCH(QNetworkProxy, proxyUsed);
3766 if (proxyUsed.type() == QNetworkProxy::NoProxy) {
3767 QCOMPARE(authspy.count(), 0);
3769 if (QByteArray(QTest::currentDataTag()).startsWith("ftp-"))
3770 return; // No authentication with current FTP or with FTP proxies
3771 QCOMPARE(authspy.count(), 1);
3772 QCOMPARE(qvariant_cast<QNetworkProxy>(authspy.at(0).at(0)), proxyUsed);
3776 QCOMPARE(authspy.count(), 0);
3780 void tst_QNetworkReply::ioPutToFileFromFile_data()
3782 QTest::addColumn<QString>("fileName");
3784 QTest::newRow("empty") << (testDataDir + "/empty");
3785 QTest::newRow("real-file") << (testDataDir + "/rfc3252.txt");
3786 QTest::newRow("resource") << ":/resource";
3787 QTest::newRow("search-path") << "testdata:/rfc3252.txt";
3790 void tst_QNetworkReply::ioPutToFileFromFile()
3792 QFETCH(QString, fileName);
3793 QFile sourceFile(fileName);
3794 QFile targetFile(testFileName);
3796 QVERIFY(sourceFile.open(QIODevice::ReadOnly));
3798 QUrl url = QUrl::fromLocalFile(targetFile.fileName());
3799 QNetworkRequest request(url);
3800 QNetworkReplyPtr reply(manager.put(request, &sourceFile));
3802 QVERIFY(waitForFinish(reply) == Success);
3804 QCOMPARE(reply->url(), url);
3805 QCOMPARE(reply->error(), QNetworkReply::NoError);
3806 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
3807 QVERIFY(reply->readAll().isEmpty());
3809 QVERIFY(sourceFile.atEnd());
3810 sourceFile.seek(0); // reset it to the beginning
3812 QVERIFY(targetFile.open(QIODevice::ReadOnly));
3813 QCOMPARE(targetFile.size(), sourceFile.size());
3814 QCOMPARE(targetFile.readAll(), sourceFile.readAll());
3817 void tst_QNetworkReply::ioPutToFileFromSocket_data()
3822 void tst_QNetworkReply::ioPutToFileFromSocket()
3824 QFile file(testFileName);
3826 QUrl url = QUrl::fromLocalFile(file.fileName());
3827 QNetworkRequest request(url);
3829 QFETCH(QByteArray, data);
3830 SocketPair socketpair;
3831 QTRY_VERIFY(socketpair.create()); //QTRY_VERIFY as a workaround for QTBUG-24451
3833 socketpair.endPoints[0]->write(data);
3834 QNetworkReplyPtr reply(manager.put(QNetworkRequest(url), socketpair.endPoints[1]));
3835 socketpair.endPoints[0]->close();
3837 QVERIFY(waitForFinish(reply) == Success);
3838 QCOMPARE(reply->error(), QNetworkReply::NoError);
3840 QCOMPARE(reply->url(), url);
3841 QCOMPARE(reply->error(), QNetworkReply::NoError);
3842 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
3843 QVERIFY(reply->readAll().isEmpty());
3845 QVERIFY(file.open(QIODevice::ReadOnly));
3846 QCOMPARE(file.size(), qint64(data.size()));
3847 QByteArray contents = file.readAll();
3848 QCOMPARE(contents, data);
3851 void tst_QNetworkReply::ioPutToFileFromLocalSocket_data()
3856 void tst_QNetworkReply::ioPutToFileFromLocalSocket()
3858 QString socketname = "networkreplytest";
3859 QLocalServer server;
3860 if (!server.listen(socketname)) {
3861 QLocalServer::removeServer(socketname);
3862 QVERIFY(server.listen(socketname));
3864 QLocalSocket active;
3865 active.connectToServer(socketname);
3866 QVERIFY2(server.waitForNewConnection(10), server.errorString().toLatin1().constData());
3867 QVERIFY2(active.waitForConnected(10), active.errorString().toLatin1().constData());
3868 QVERIFY2(server.hasPendingConnections(), server.errorString().toLatin1().constData());
3869 QLocalSocket *passive = server.nextPendingConnection();
3871 QFile file(testFileName);
3872 QUrl url = QUrl::fromLocalFile(file.fileName());
3873 QNetworkRequest request(url);
3875 QFETCH(QByteArray, data);
3878 QNetworkReplyPtr reply(manager.put(QNetworkRequest(url), passive));
3879 passive->setParent(reply.data());
3882 if (!data.isEmpty())
3883 QEXPECT_FAIL("", "QTBUG-18385", Abort);
3885 QVERIFY(waitForFinish(reply) == Success);
3886 QCOMPARE(reply->error(), QNetworkReply::NoError);
3888 QCOMPARE(reply->url(), url);
3889 QCOMPARE(reply->error(), QNetworkReply::NoError);
3890 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
3891 QVERIFY(reply->readAll().isEmpty());
3893 QVERIFY(file.open(QIODevice::ReadOnly));
3894 QCOMPARE(file.size(), qint64(data.size()));
3895 QByteArray contents = file.readAll();
3896 QCOMPARE(contents, data);
3899 // Currently no stdin/out supported for Windows CE.
3900 #ifndef QT_NO_PROCESS
3901 void tst_QNetworkReply::ioPutToFileFromProcess_data()
3906 void tst_QNetworkReply::ioPutToFileFromProcess()
3908 #if defined(Q_OS_WINCE)
3909 QSKIP("Currently no stdin/out supported for Windows CE");
3912 if (qstrcmp(QTest::currentDataTag(), "small") == 0)
3913 QSKIP("When passing a CR-LF-LF sequence through Windows stdio, it gets converted, "
3914 "so this test fails. Disabled on Windows");
3917 QFile file(testFileName);
3919 QUrl url = QUrl::fromLocalFile(file.fileName());
3920 QNetworkRequest request(url);
3922 QFETCH(QByteArray, data);
3924 QString echoExe = echoProcessDir + "/echo";
3925 process.start(echoExe, QStringList("all"));
3926 QVERIFY2(process.waitForStarted(), qPrintable(
3927 QString::fromLatin1("Could not start %1: %2").arg(echoExe, process.errorString())));
3928 process.write(data);
3929 process.closeWriteChannel();
3931 QNetworkReplyPtr reply(manager.put(QNetworkRequest(url), &process));
3933 QVERIFY(waitForFinish(reply) == Success);
3935 QCOMPARE(reply->url(), url);
3936 QCOMPARE(reply->error(), QNetworkReply::NoError);
3937 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
3938 QVERIFY(reply->readAll().isEmpty());
3940 QVERIFY(file.open(QIODevice::ReadOnly));
3941 QCOMPARE(file.size(), qint64(data.size()));
3942 QByteArray contents = file.readAll();
3943 QCOMPARE(contents, data);
3948 void tst_QNetworkReply::ioPutToFtpFromFile_data()
3950 ioPutToFileFromFile_data();
3953 void tst_QNetworkReply::ioPutToFtpFromFile()
3955 QFETCH(QString, fileName);
3956 QFile sourceFile(fileName);
3957 QVERIFY(sourceFile.open(QIODevice::ReadOnly));
3959 QUrl url("ftp://" + QtNetworkSettings::serverName());
3960 url.setPath(QString("/qtest/upload/qnetworkaccess-ioPutToFtpFromFile-%1-%2")
3961 .arg(QTest::currentDataTag())
3962 .arg(uniqueExtension));
3964 QNetworkRequest request(url);
3965 QNetworkReplyPtr reply(manager.put(request, &sourceFile));
3967 QVERIFY(waitForFinish(reply) == Success);
3969 QCOMPARE(reply->url(), url);
3970 QCOMPARE(reply->error(), QNetworkReply::NoError);
3971 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
3972 QVERIFY(reply->readAll().isEmpty());
3974 QVERIFY(sourceFile.atEnd());
3975 sourceFile.seek(0); // reset it to the beginning
3977 // download the file again from FTP to make sure it was uploaded
3979 QNetworkAccessManager qnam;
3980 QNetworkRequest req(url);
3981 QNetworkReply *r = qnam.get(req);
3983 QObject::connect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
3984 QTestEventLoop::instance().enterLoop(3);
3985 QObject::disconnect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
3987 QByteArray uploaded = r->readAll();
3988 QCOMPARE(qint64(uploaded.size()), sourceFile.size());
3989 QCOMPARE(uploaded, sourceFile.readAll());
3992 QObject::connect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
3993 QTestEventLoop::instance().enterLoop(10);
3994 QObject::disconnect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
3997 void tst_QNetworkReply::ioPutToHttpFromFile_data()
3999 ioPutToFileFromFile_data();
4002 void tst_QNetworkReply::ioPutToHttpFromFile()
4004 QFETCH(QString, fileName);
4005 QFile sourceFile(fileName);
4006 QVERIFY(sourceFile.open(QIODevice::ReadOnly));
4008 QUrl url("http://" + QtNetworkSettings::serverName());
4009 url.setPath(QString("/dav/qnetworkaccess-ioPutToHttpFromFile-%1-%2")
4010 .arg(QTest::currentDataTag())
4011 .arg(uniqueExtension));
4013 QNetworkRequest request(url);
4014 QNetworkReplyPtr reply(manager.put(request, &sourceFile));
4016 QVERIFY(waitForFinish(reply) == Success);
4018 QCOMPARE(reply->url(), url);
4019 QCOMPARE(reply->error(), QNetworkReply::NoError);
4021 // verify that the HTTP status code is 201 Created
4022 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 201);
4024 QVERIFY(sourceFile.atEnd());
4025 sourceFile.seek(0); // reset it to the beginning
4027 // download the file again from HTTP to make sure it was uploaded
4029 reply.reset(manager.get(request));
4031 QVERIFY(waitForFinish(reply) == Success);
4033 QCOMPARE(reply->url(), url);
4034 QCOMPARE(reply->error(), QNetworkReply::NoError);
4035 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
4037 QCOMPARE(reply->readAll(), sourceFile.readAll());
4040 void tst_QNetworkReply::ioPostToHttpFromFile_data()
4042 ioPutToFileFromFile_data();
4045 void tst_QNetworkReply::ioPostToHttpFromFile()
4047 QFETCH(QString, fileName);
4048 QFile sourceFile(fileName);
4049 QVERIFY(sourceFile.open(QIODevice::ReadOnly));
4051 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi");
4052 QNetworkRequest request(url);
4053 request.setRawHeader("Content-Type", "application/octet-stream");
4055 QNetworkReplyPtr reply(manager.post(request, &sourceFile));
4057 QVERIFY(waitForFinish(reply) == Success);
4059 QCOMPARE(reply->url(), url);
4060 QCOMPARE(reply->error(), QNetworkReply::NoError);
4062 // verify that the HTTP status code is 200 Ok
4063 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
4065 QVERIFY(sourceFile.atEnd());
4066 sourceFile.seek(0); // reset it to the beginning
4068 QCOMPARE(reply->readAll().trimmed(), md5sum(sourceFile.readAll()).toHex());
4071 void tst_QNetworkReply::ioPostToHttpFromSocket_data()
4073 QTest::addColumn<QByteArray>("data");
4074 QTest::addColumn<QByteArray>("md5sum");
4075 QTest::addColumn<QUrl>("url");
4076 QTest::addColumn<QNetworkProxy>("proxy");
4077 QTest::addColumn<int>("authenticationRequiredCount");
4078 QTest::addColumn<int>("proxyAuthenticationRequiredCount");
4080 for (int i = 0; i < proxies.count(); ++i)
4081 for (int auth = 0; auth < 2; ++auth) {
4084 url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi";
4086 url = "http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi";
4088 QNetworkProxy proxy = proxies.at(i).proxy;
4089 QByteArray testsuffix = QByteArray(auth ? "+auth" : "") + proxies.at(i).tag;
4090 int proxyauthcount = proxies.at(i).requiresAuthentication;
4094 QTest::newRow("empty" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount;
4096 data = "This is a normal message.";
4097 QTest::newRow("generic" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount;
4099 data = "This is a message to show that Qt rocks!\r\n\n";
4100 QTest::newRow("small" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount;
4102 data = QByteArray("abcd\0\1\2\abcd",12);
4103 QTest::newRow("with-nul" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount;
4105 data = QByteArray(4097, '\4');
4106 QTest::newRow("4k+1" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount;
4108 data = QByteArray(128*1024+1, '\177');
4109 QTest::newRow("128k+1" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount;
4113 void tst_QNetworkReply::ioPostToHttpFromSocket()
4115 QFETCH(QByteArray, data);
4117 QFETCH(QNetworkProxy, proxy);
4119 SocketPair socketpair;
4120 QTRY_VERIFY(socketpair.create()); //QTRY_VERIFY as a workaround for QTBUG-24451
4122 socketpair.endPoints[0]->write(data);
4124 QNetworkRequest request(url);
4125 request.setRawHeader("Content-Type", "application/octet-stream");
4127 manager.setProxy(proxy);
4128 QNetworkReplyPtr reply(manager.post(request, socketpair.endPoints[1]));
4129 socketpair.endPoints[0]->close();
4131 connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
4132 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
4133 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4134 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4136 QSignalSpy authenticationRequiredSpy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4137 QSignalSpy proxyAuthenticationRequiredSpy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
4139 QVERIFY(waitForFinish(reply) == Success);
4141 disconnect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
4142 this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
4143 disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4144 this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4145 QCOMPARE(reply->error(), QNetworkReply::NoError);
4147 QCOMPARE(reply->url(), url);
4148 QCOMPARE(reply->error(), QNetworkReply::NoError);
4149 // verify that the HTTP status code is 200 Ok
4150 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
4152 QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex());
4154 QTEST(authenticationRequiredSpy.count(), "authenticationRequiredCount");
4155 QTEST(proxyAuthenticationRequiredSpy.count(), "proxyAuthenticationRequiredCount");
4158 void tst_QNetworkReply::ioPostToHttpFromSocketSynchronous_data()
4160 QTest::addColumn<QByteArray>("data");
4161 QTest::addColumn<QByteArray>("md5sum");
4165 QTest::newRow("empty") << data << md5sum(data);
4167 data = "This is a normal message.";
4168 QTest::newRow("generic") << data << md5sum(data);
4170 data = "This is a message to show that Qt rocks!\r\n\n";
4171 QTest::newRow("small") << data << md5sum(data);
4173 data = QByteArray("abcd\0\1\2\abcd",12);
4174 QTest::newRow("with-nul") << data << md5sum(data);
4176 data = QByteArray(4097, '\4');
4177 QTest::newRow("4k+1") << data << md5sum(data);
4179 data = QByteArray(128*1024+1, '\177');
4180 QTest::newRow("128k+1") << data << md5sum(data);
4182 data = QByteArray(2*1024*1024+1, '\177');
4183 QTest::newRow("2MB+1") << data << md5sum(data);
4186 void tst_QNetworkReply::ioPostToHttpFromSocketSynchronous()
4188 QFETCH(QByteArray, data);
4190 SocketPair socketpair;
4191 QTRY_VERIFY(socketpair.create()); //QTRY_VERIFY as a workaround for QTBUG-24451
4192 socketpair.endPoints[0]->write(data);
4193 socketpair.endPoints[0]->waitForBytesWritten(5000);
4194 // ### for 4.8: make the socket pair unbuffered, to not read everything in one go in QNetworkReplyImplPrivate::setup()
4195 QTestEventLoop::instance().enterLoop(3);
4197 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi");
4198 QNetworkRequest request(url);
4199 request.setRawHeader("Content-Type", "application/octet-stream");
4200 request.setAttribute(
4201 QNetworkRequest::SynchronousRequestAttribute,
4204 QNetworkReplyPtr reply(manager.post(request, socketpair.endPoints[1]));
4205 QVERIFY(reply->isFinished());
4206 socketpair.endPoints[0]->close();
4208 QCOMPARE(reply->error(), QNetworkReply::NoError);
4210 QCOMPARE(reply->url(), url);
4211 QCOMPARE(reply->error(), QNetworkReply::NoError);
4212 // verify that the HTTP status code is 200 Ok
4213 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
4215 QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex());
4218 // this tests checks if rewinding the POST-data to some place in the middle
4220 void tst_QNetworkReply::ioPostToHttpFromMiddleOfFileToEnd()
4222 QFile sourceFile(testDataDir + "/rfc3252.txt");
4223 QVERIFY(sourceFile.open(QIODevice::ReadOnly));
4224 // seeking to the middle
4225 sourceFile.seek(sourceFile.size() / 2);
4227 QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi";
4228 QNetworkRequest request(url);
4229 request.setRawHeader("Content-Type", "application/octet-stream");
4230 QNetworkReplyPtr reply(manager.post(request, &sourceFile));
4232 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4233 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4235 QVERIFY(waitForFinish(reply) == Success);
4237 disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4238 this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4240 // compare half data
4241 sourceFile.seek(sourceFile.size() / 2);
4242 QByteArray data = sourceFile.readAll();
4243 QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex());
4246 void tst_QNetworkReply::ioPostToHttpFromMiddleOfFileFiveBytes()
4248 QFile sourceFile(testDataDir + "/rfc3252.txt");
4249 QVERIFY(sourceFile.open(QIODevice::ReadOnly));
4250 // seeking to the middle
4251 sourceFile.seek(sourceFile.size() / 2);
4253 QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi";
4254 QNetworkRequest request(url);
4255 request.setRawHeader("Content-Type", "application/octet-stream");
4256 // only send 5 bytes
4257 request.setHeader(QNetworkRequest::ContentLengthHeader, 5);
4258 QVERIFY(request.header(QNetworkRequest::ContentLengthHeader).isValid());
4259 QNetworkReplyPtr reply(manager.post(request, &sourceFile));
4261 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4262 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4264 QVERIFY(waitForFinish(reply) == Success);
4266 disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4267 this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4269 // compare half data
4270 sourceFile.seek(sourceFile.size() / 2);
4271 QByteArray data = sourceFile.read(5);
4272 QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex());
4275 void tst_QNetworkReply::ioPostToHttpFromMiddleOfQBufferFiveBytes()
4277 // test needed since a QBuffer goes with a different codepath than the QFile
4278 // tested in ioPostToHttpFromMiddleOfFileFiveBytes
4279 QBuffer uploadBuffer;
4280 uploadBuffer.open(QIODevice::ReadWrite);
4281 uploadBuffer.write("1234567890");
4282 uploadBuffer.seek(5);
4284 QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi";
4285 QNetworkRequest request(url);
4286 request.setRawHeader("Content-Type", "application/octet-stream");
4287 QNetworkReplyPtr reply(manager.post(request, &uploadBuffer));
4289 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4290 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4292 QVERIFY(waitForFinish(reply) == Success);
4294 disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4295 this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4297 // compare half data
4298 uploadBuffer.seek(5);
4299 QByteArray data = uploadBuffer.read(5);
4300 QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex());
4304 void tst_QNetworkReply::ioPostToHttpNoBufferFlag()
4306 QByteArray data = QByteArray("daaaaaaataaaaaaa");
4307 // create a sequential QIODevice by feeding the data into a local TCP server
4308 SocketPair socketpair;
4309 QTRY_VERIFY(socketpair.create()); //QTRY_VERIFY as a workaround for QTBUG-24451
4310 socketpair.endPoints[0]->write(data);
4312 QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi";
4313 QNetworkRequest request(url);
4314 request.setRawHeader("Content-Type", "application/octet-stream");
4315 // disallow buffering
4316 request.setAttribute(QNetworkRequest::DoNotBufferUploadDataAttribute, true);
4317 request.setHeader(QNetworkRequest::ContentLengthHeader, data.size());
4318 QNetworkReplyPtr reply(manager.post(request, socketpair.endPoints[1]));
4319 socketpair.endPoints[0]->close();
4321 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4322 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4324 QVERIFY(waitForFinish(reply) == Failure);
4326 disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4327 this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4329 // verify: error code is QNetworkReply::ContentReSendError
4330 QCOMPARE(reply->error(), QNetworkReply::ContentReSendError);
4334 class SslServer : public QTcpServer {
4337 SslServer() : socket(0) {};
4338 void incomingConnection(qintptr socketDescriptor) {
4339 QSslSocket *serverSocket = new QSslSocket;
4340 serverSocket->setParent(this);
4342 if (serverSocket->setSocketDescriptor(socketDescriptor)) {
4343 QString testDataDir = QFileInfo(QFINDTESTDATA("rfc3252.txt")).absolutePath();
4344 if (testDataDir.isEmpty())
4345 testDataDir = QCoreApplication::applicationDirPath();
4347 connect(serverSocket, SIGNAL(encrypted()), this, SLOT(encryptedSlot()));
4348 connect(serverSocket, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
4349 serverSocket->setProtocol(QSsl::AnyProtocol);
4350 connect(serverSocket, SIGNAL(sslErrors(QList<QSslError>)), serverSocket, SLOT(ignoreSslErrors()));
4351 serverSocket->setLocalCertificate(testDataDir + "/certs/server.pem");
4352 serverSocket->setPrivateKey(testDataDir + "/certs/server.key");
4353 serverSocket->startServerEncryption();
4355 delete serverSocket;
4359 void newEncryptedConnection();
4361 void encryptedSlot() {
4362 socket = (QSslSocket*) sender();
4363 emit newEncryptedConnection();
4365 void readyReadSlot() {
4366 // for the incoming sockets, not the server socket
4367 //qDebug() << static_cast<QSslSocket*>(sender())->bytesAvailable() << static_cast<QSslSocket*>(sender())->encryptedBytesAvailable();
4374 // very similar to ioPostToHttpUploadProgress but for SSL
4375 void tst_QNetworkReply::ioPostToHttpsUploadProgress()
4377 //QFile sourceFile(testDataDir + "/bigfile");
4378 //QVERIFY(sourceFile.open(QIODevice::ReadOnly));
4379 qint64 wantedSize = 2*1024*1024; // 2 MB
4380 QByteArray sourceFile;
4381 // And in the case of SSL, the compression can fool us and let the
4382 // server send the data much faster than expected.
4383 // So better provide random data that cannot be compressed.
4384 for (int i = 0; i < wantedSize; ++i)
4385 sourceFile += (char)qrand();
4387 // emulate a minimal https server
4389 server.listen(QHostAddress(QHostAddress::LocalHost), 0);
4391 // create the request
4392 QUrl url = QUrl(QString("https://127.0.0.1:%1/").arg(server.serverPort()));
4393 QNetworkRequest request(url);
4395 request.setRawHeader("Content-Type", "application/octet-stream");
4396 QNetworkReplyPtr reply(manager.post(request, sourceFile));
4398 QSignalSpy spy(reply.data(), SIGNAL(uploadProgress(qint64,qint64)));
4399 connect(&server, SIGNAL(newEncryptedConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
4400 connect(reply, SIGNAL(sslErrors(QList<QSslError>)), reply.data(), SLOT(ignoreSslErrors()));
4402 // get the request started and the incoming socket connected
4403 QTestEventLoop::instance().enterLoop(10);
4404 QVERIFY(!QTestEventLoop::instance().timeout());
4405 QTcpSocket *incomingSocket = server.socket;
4406 QVERIFY(incomingSocket);
4407 disconnect(&server, SIGNAL(newEncryptedConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
4410 incomingSocket->setReadBufferSize(1*1024);
4411 // some progress should have been made
4412 QTRY_VERIFY(!spy.isEmpty());
4413 QList<QVariant> args = spy.last();
4414 QVERIFY(args.at(0).toLongLong() > 0);
4415 // but not everything!
4416 QVERIFY(args.at(0).toLongLong() != sourceFile.size());
4418 // set the read buffer to unlimited
4419 incomingSocket->setReadBufferSize(0);
4420 QTestEventLoop::instance().enterLoop(10);
4421 // progress should be finished
4422 QVERIFY(!spy.isEmpty());
4423 QList<QVariant> args3 = spy.last();
4424 QCOMPARE(args3.at(0).toLongLong(), args3.at(1).toLongLong());
4425 QCOMPARE(args3.at(0).toLongLong(), qint64(sourceFile.size()));
4427 // after sending this, the QNAM should emit finished()
4428 incomingSocket->write("HTTP/1.0 200 OK\r\n");
4429 incomingSocket->write("Content-Length: 0\r\n");
4430 incomingSocket->write("\r\n");
4432 QVERIFY(waitForFinish(reply) == Success);
4434 incomingSocket->close();
4439 void tst_QNetworkReply::ioGetFromBuiltinHttp_data()
4441 QTest::addColumn<bool>("https");
4442 QTest::addColumn<int>("bufferSize");
4443 QTest::newRow("http+unlimited") << false << 0;
4444 QTest::newRow("http+limited") << false << 4096;
4446 QTest::newRow("https+unlimited") << true << 0;
4447 QTest::newRow("https+limited") << true << 4096;
4451 void tst_QNetworkReply::ioGetFromBuiltinHttp()
4453 QFETCH(bool, https);
4454 QFETCH(int, bufferSize);
4456 QByteArray testData;
4457 // Make the data big enough so that it can fill the kernel buffer
4458 // (which seems to hold 202 KB here)
4459 const int wantedSize = 1200 * 1000;
4460 testData.reserve(wantedSize);
4461 // And in the case of SSL, the compression can fool us and let the
4462 // server send the data much faster than expected.
4463 // So better provide random data that cannot be compressed.
4464 for (int i = 0; i < wantedSize; ++i)
4465 testData += (char)qrand();
4467 QByteArray httpResponse = QByteArray("HTTP/1.0 200 OK\r\nContent-Length: ");
4468 httpResponse += QByteArray::number(testData.size());
4469 httpResponse += "\r\n\r\n";
4470 httpResponse += testData;
4472 qDebug() << "Server will send" << (httpResponse.size()-testData.size()) << "bytes of header and"
4473 << testData.size() << "bytes of data";
4475 const bool fillKernelBuffer = bufferSize > 0;
4476 FastSender server(httpResponse, https, fillKernelBuffer);
4478 QUrl url(QString("%1://127.0.0.1:%2/qtest/rfc3252.txt")
4479 .arg(https?"https":"http")
4480 .arg(server.serverPort()));
4481 QNetworkRequest request(url);
4482 QNetworkReplyPtr reply(manager.get(request));
4483 reply->setReadBufferSize(bufferSize);
4484 reply->ignoreSslErrors();
4485 const int rate = 200; // in kB per sec
4486 RateControlledReader reader(server, reply.data(), rate, bufferSize);
4491 QVERIFY(waitForFinish(reply) == Success);
4493 const int elapsedTime = loopTime.elapsed();
4497 qDebug() << "send rate:" << server.transferRate << "B/s";
4498 qDebug() << "receive rate:" << reader.totalBytesRead * 1000 / elapsedTime
4499 << "(it received" << reader.totalBytesRead << "bytes in" << elapsedTime << "ms)";
4501 QCOMPARE(reply->url(), request.url());
4502 QCOMPARE(reply->error(), QNetworkReply::NoError);
4503 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
4505 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), (qint64)testData.size());
4506 if (reader.data.size() < testData.size()) { // oops?
4507 QCOMPARE(reader.data, testData.mid(0, reader.data.size()));
4508 qDebug() << "The data is incomplete, the last" << testData.size() - reader.data.size() << "bytes are missing";
4510 QCOMPARE(reader.data.size(), testData.size());
4511 QCOMPARE(reader.data, testData);
4513 // OK we got the file alright, but did setReadBufferSize work?
4514 QVERIFY(server.transferRate != -1);
4515 if (bufferSize > 0) {
4516 const int allowedDeviation = 16; // TODO find out why the send rate is 13% faster currently
4517 const int minRate = rate * 1024 * (100-allowedDeviation) / 100;
4518 const int maxRate = rate * 1024 * (100+allowedDeviation) / 100;
4519 qDebug() << minRate << "<="<< server.transferRate << "<=" << maxRate << "?";
4520 // The test takes too long to run if sending enough data to overwhelm the
4521 // reciever's kernel buffers.
4522 //QEXPECT_FAIL("http+limited", "Limiting is broken right now, check QTBUG-15065", Continue);
4523 //QEXPECT_FAIL("https+limited", "Limiting is broken right now, check QTBUG-15065", Continue);
4524 //QVERIFY(server.transferRate >= minRate && server.transferRate <= maxRate);
4528 void tst_QNetworkReply::ioPostToHttpUploadProgress()
4530 //test file must be larger than OS socket buffers (~830kB on MacOS 10.6)
4531 QFile sourceFile(testDataDir + "/image1.jpg");
4532 QVERIFY(sourceFile.open(QIODevice::ReadOnly));
4534 // emulate a minimal http server
4536 server.listen(QHostAddress(QHostAddress::LocalHost), 0);
4538 // create the request
4539 QUrl url = QUrl(QString("http://127.0.0.1:%1/").arg(server.serverPort()));
4540 QNetworkRequest request(url);
4541 request.setRawHeader("Content-Type", "application/octet-stream");
4542 QNetworkReplyPtr reply(manager.post(request, &sourceFile));
4543 QSignalSpy spy(reply.data(), SIGNAL(uploadProgress(qint64,qint64)));
4544 connect(&server, SIGNAL(newConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
4546 // get the request started and the incoming socket connected
4547 QTestEventLoop::instance().enterLoop(10);
4548 QVERIFY(!QTestEventLoop::instance().timeout());
4549 QTcpSocket *incomingSocket = server.nextPendingConnection();
4550 QVERIFY(incomingSocket);
4551 disconnect(&server, SIGNAL(newConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
4553 incomingSocket->setReadBufferSize(1*1024);
4554 QTestEventLoop::instance().enterLoop(5);
4555 // some progress should have been made
4556 QVERIFY(!spy.isEmpty());
4557 QList<QVariant> args = spy.last();
4558 QVERIFY(!args.isEmpty());
4559 QVERIFY(args.at(0).toLongLong() > 0);
4560 // but not everything!
4561 QVERIFY(args.at(0).toLongLong() != sourceFile.size());
4563 // set the read buffer to unlimited
4564 incomingSocket->setReadBufferSize(0);
4565 QTestEventLoop::instance().enterLoop(10);
4566 // progress should be finished
4567 QVERIFY(!spy.isEmpty());
4568 QList<QVariant> args3 = spy.last();
4569 QVERIFY(!args3.isEmpty());
4570 // More progress than before
4571 QVERIFY(args3.at(0).toLongLong() > args.at(0).toLongLong());
4572 QCOMPARE(args3.at(0).toLongLong(), args3.at(1).toLongLong());
4573 // And actually finished..
4574 QCOMPARE(args3.at(0).toLongLong(), sourceFile.size());
4576 // after sending this, the QNAM should emit finished()
4577 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
4578 incomingSocket->write("HTTP/1.0 200 OK\r\n");
4579 incomingSocket->write("Content-Length: 0\r\n");
4580 incomingSocket->write("\r\n");
4581 QTestEventLoop::instance().enterLoop(10);
4582 // not timeouted -> finished() was emitted
4583 QVERIFY(!QTestEventLoop::instance().timeout());
4585 incomingSocket->close();
4589 void tst_QNetworkReply::ioPostToHttpEmptyUploadProgress()
4593 QBuffer buffer(&ba,0);
4594 QVERIFY(buffer.open(QIODevice::ReadOnly));
4596 // emulate a minimal http server
4598 server.listen(QHostAddress(QHostAddress::LocalHost), 0);
4600 // create the request
4601 QUrl url = QUrl(QString("http://127.0.0.1:%1/").arg(server.serverPort()));
4602 QNetworkRequest request(url);
4603 request.setRawHeader("Content-Type", "application/octet-stream");
4604 QNetworkReplyPtr reply(manager.post(request, &buffer));
4605 QSignalSpy spy(reply.data(), SIGNAL(uploadProgress(qint64,qint64)));
4606 connect(&server, SIGNAL(newConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
4609 // get the request started and the incoming socket connected
4610 QTestEventLoop::instance().enterLoop(10);
4611 QVERIFY(!QTestEventLoop::instance().timeout());
4612 QTcpSocket *incomingSocket = server.nextPendingConnection();
4613 QVERIFY(incomingSocket);
4615 // after sending this, the QNAM should emit finished()
4616 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
4617 incomingSocket->write("HTTP/1.0 200 OK\r\n");
4618 incomingSocket->write("Content-Length: 0\r\n");
4619 incomingSocket->write("\r\n");
4620 incomingSocket->flush();
4621 QTestEventLoop::instance().enterLoop(10);
4622 // not timeouted -> finished() was emitted
4623 QVERIFY(!QTestEventLoop::instance().timeout());
4625 // final check: only 1 uploadProgress has been emitted
4626 QVERIFY(spy.length() == 1);
4627 QList<QVariant> args = spy.last();
4628 QVERIFY(!args.isEmpty());
4629 QCOMPARE(args.at(0).toLongLong(), buffer.size());
4630 QCOMPARE(args.at(0).toLongLong(), buffer.size());
4632 incomingSocket->close();
4636 void tst_QNetworkReply::lastModifiedHeaderForFile()
4638 QFileInfo fileInfo(testDataDir + "/bigfile");
4639 QVERIFY(fileInfo.exists());
4641 QUrl url = QUrl::fromLocalFile(fileInfo.filePath());
4643 QNetworkRequest request(url);
4644 QNetworkReplyPtr reply(manager.head(request));
4646 QVERIFY(waitForFinish(reply) == Success);
4648 QDateTime header = reply->header(QNetworkRequest::LastModifiedHeader).toDateTime();
4649 QCOMPARE(header, fileInfo.lastModified());
4652 void tst_QNetworkReply::lastModifiedHeaderForHttp()
4654 // Tue, 22 May 2007 12:04:57 GMT according to webserver
4655 QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/fluke.gif";
4657 QNetworkRequest request(url);
4658 QNetworkReplyPtr reply(manager.head(request));
4660 QVERIFY(waitForFinish(reply) == Success);
4662 QDateTime header = reply->header(QNetworkRequest::LastModifiedHeader).toDateTime();
4663 QDateTime realDate = QDateTime::fromString("2007-05-22T12:04:57", Qt::ISODate);
4664 realDate.setTimeSpec(Qt::UTC);
4666 QCOMPARE(header, realDate);
4669 void tst_QNetworkReply::httpCanReadLine()
4671 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
4672 QNetworkReplyPtr reply(manager.get(request));
4674 QVERIFY(waitForFinish(reply) == Success);
4676 QCOMPARE(reply->error(), QNetworkReply::NoError);
4678 QVERIFY(reply->canReadLine());
4679 QVERIFY(!reply->readAll().isEmpty());
4680 QVERIFY(!reply->canReadLine());
4683 #ifdef QT_BUILD_INTERNAL
4684 void tst_QNetworkReply::rateControl_data()
4686 QTest::addColumn<int>("rate");
4688 QTest::newRow("15") << 15;
4689 QTest::newRow("40") << 40;
4690 QTest::newRow("73") << 73;
4691 QTest::newRow("80") << 80;
4692 QTest::newRow("125") << 125;
4693 QTest::newRow("250") << 250;
4694 QTest::newRow("1024") << 1024;
4698 #ifdef QT_BUILD_INTERNAL
4699 void tst_QNetworkReply::rateControl()
4701 QSKIP("Test disabled -- only for manual purposes");
4702 // this function tests that we aren't reading from the network
4703 // faster than the data is being consumed.
4706 // ask for 20 seconds worth of data
4707 FastSender sender(20 * rate * 1024);
4709 QNetworkRequest request("debugpipe://localhost:" + QString::number(sender.serverPort()));
4710 QNetworkReplyPtr reply(manager.get(request));
4711 reply->setReadBufferSize(32768);
4712 QSignalSpy errorSpy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError)));
4714 RateControlledReader reader(sender, reply.data(), rate, 20);
4716 // this test is designed to run for 25 seconds at most
4720 QVERIFY(waitForFinish(reply) == Success);
4722 int elapsedTime = loopTime.elapsed();
4724 if (!errorSpy.isEmpty()) {
4725 qDebug() << "ERROR!" << errorSpy[0][0] << reply->errorString();
4728 qDebug() << "tst_QNetworkReply::rateControl" << "send rate:" << sender.transferRate;
4729 qDebug() << "tst_QNetworkReply::rateControl" << "receive rate:" << reader.totalBytesRead * 1000 / elapsedTime
4730 << "(it received" << reader.totalBytesRead << "bytes in" << elapsedTime << "ms)";
4734 QCOMPARE(reply->url(), request.url());
4735 QCOMPARE(reply->error(), QNetworkReply::NoError);
4737 QVERIFY(sender.transferRate != -1);
4738 int minRate = rate * 1024 * 9 / 10;
4739 int maxRate = rate * 1024 * 11 / 10;
4740 QVERIFY(sender.transferRate >= minRate);
4741 QVERIFY(sender.transferRate <= maxRate);
4745 void tst_QNetworkReply::downloadProgress_data()
4747 QTest::addColumn<QUrl>("url");
4748 QTest::addColumn<int>("expectedSize");
4750 QTest::newRow("empty") << QUrl::fromLocalFile(QFINDTESTDATA("empty")) << 0;
4751 QTest::newRow("http:small") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt") << 25962;
4752 QTest::newRow("http:big") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/bigfile") << 519240;
4753 QTest::newRow("http:no-length") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/deflate/rfc2616.html") << -1;
4754 QTest::newRow("ftp:small") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt") << 25962;
4755 QTest::newRow("ftp:big") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/bigfile") << 519240;
4758 class SlowReader : public QObject
4762 SlowReader(QIODevice *dev)
4765 connect(device, SIGNAL(readyRead()), this, SLOT(deviceReady()));
4770 QTimer::singleShot(100, this, SLOT(doRead()));
4781 void tst_QNetworkReply::downloadProgress()
4784 QFETCH(int, expectedSize);
4786 QNetworkRequest request(url);
4787 QNetworkReplyPtr reply(manager.get(request));
4788 //artificially slow down the test, otherwise only the final signal is emitted
4789 reply->setReadBufferSize(qMax(20000, expectedSize / 4));
4790 SlowReader reader(reply.data());
4791 QSignalSpy spy(reply.data(), SIGNAL(downloadProgress(qint64,qint64)));
4792 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
4793 QTestEventLoop::instance().enterLoop(30);
4794 QVERIFY(!QTestEventLoop::instance().timeout());
4795 QVERIFY(reply->isFinished());
4797 QVERIFY(spy.count() > 0);
4799 //final progress should have equal current & total
4800 QList<QVariant> args = spy.takeLast();
4801 QCOMPARE(args.at(0).toInt(), args.at(1).toInt());
4804 //intermediate progress ascending and has expected total
4805 while (!spy.isEmpty()) {
4806 args = spy.takeFirst();
4807 QVERIFY(args.at(0).toInt() >= current);
4808 if (expectedSize >=0)
4809 QCOMPARE(args.at(1).toInt(), expectedSize);
4811 QVERIFY(args.at(1).toInt() == expectedSize || args.at(1).toInt() == args.at(0).toInt());
4812 current = args.at(0).toInt();
4816 #ifdef QT_BUILD_INTERNAL
4817 void tst_QNetworkReply::uploadProgress_data()
4823 #ifdef QT_BUILD_INTERNAL
4824 void tst_QNetworkReply::uploadProgress()
4826 QFETCH(QByteArray, data);
4828 QVERIFY(server.listen());
4830 QNetworkRequest request("debugpipe://127.0.0.1:" + QString::number(server.serverPort()) + "/?bare=1");
4831 QNetworkReplyPtr reply(manager.put(request, data));
4832 QSignalSpy spy(reply.data(), SIGNAL(uploadProgress(qint64,qint64)));
4833 QSignalSpy finished(reply.data(), SIGNAL(finished()));
4834 QVERIFY(spy.isValid());
4835 QVERIFY(finished.isValid());
4837 QCoreApplication::instance()->processEvents();
4838 if (!server.hasPendingConnections())
4839 server.waitForNewConnection(1000);
4840 QVERIFY(server.hasPendingConnections());
4842 QTcpSocket *receiver = server.nextPendingConnection();
4843 if (finished.count() == 0) {
4844 // it's not finished yet, so wait for it to be
4845 QVERIFY(waitForFinish(reply) == Success);
4849 QVERIFY(finished.count() > 0);
4850 QVERIFY(spy.count() > 0);
4852 QList<QVariant> args = spy.last();
4853 QCOMPARE(args.at(0).toInt(), data.size());
4854 QCOMPARE(args.at(1).toInt(), data.size());
4858 void tst_QNetworkReply::chaining_data()
4863 void tst_QNetworkReply::chaining()
4865 QTemporaryFile sourceFile(QDir::currentPath() + "/temp-XXXXXX");
4866 sourceFile.setAutoRemove(true);
4867 QVERIFY(sourceFile.open());
4869 QFETCH(QByteArray, data);
4870 QVERIFY(sourceFile.write(data) == data.size());
4872 QCOMPARE(sourceFile.size(), qint64(data.size()));
4874 QNetworkRequest request(QUrl::fromLocalFile(sourceFile.fileName()));
4875 QNetworkReplyPtr getReply(manager.get(request));
4877 QFile targetFile(testFileName);
4878 QUrl url = QUrl::fromLocalFile(targetFile.fileName());
4879 request.setUrl(url);
4880 QNetworkReplyPtr putReply(manager.put(request, getReply.data()));
4882 QVERIFY(waitForFinish(putReply) == Success);
4884 QCOMPARE(getReply->url(), QUrl::fromLocalFile(sourceFile.fileName()));
4885 QCOMPARE(getReply->error(), QNetworkReply::NoError);
4886 QCOMPARE(getReply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), sourceFile.size());
4888 QCOMPARE(putReply->url(), url);
4889 QCOMPARE(putReply->error(), QNetworkReply::NoError);
4890 QCOMPARE(putReply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
4891 QVERIFY(putReply->readAll().isEmpty());
4893 QVERIFY(sourceFile.atEnd());
4894 sourceFile.seek(0); // reset it to the beginning
4896 QVERIFY(targetFile.open(QIODevice::ReadOnly));
4897 QCOMPARE(targetFile.size(), sourceFile.size());
4898 QCOMPARE(targetFile.readAll(), sourceFile.readAll());
4901 void tst_QNetworkReply::receiveCookiesFromHttp_data()
4903 QTest::addColumn<QString>("cookieString");
4904 QTest::addColumn<QList<QNetworkCookie> >("expectedCookiesFromHttp");
4905 QTest::addColumn<QList<QNetworkCookie> >("expectedCookiesInJar");
4907 QTest::newRow("empty") << "" << QList<QNetworkCookie>() << QList<QNetworkCookie>();
4909 QList<QNetworkCookie> header, jar;
4910 QNetworkCookie cookie("a", "b");
4912 cookie.setDomain(QtNetworkSettings::serverName());
4913 cookie.setPath("/qtest/cgi-bin/");
4915 QTest::newRow("simple-cookie") << "a=b" << header << jar;
4917 header << QNetworkCookie("c", "d");
4918 cookie.setName("c");
4919 cookie.setValue("d");
4921 QTest::newRow("two-cookies") << "a=b\nc=d" << header << jar;
4925 header << QNetworkCookie("a", "b, c=d");
4926 cookie.setName("a");
4927 cookie.setValue("b, c=d");
4929 QTest::newRow("invalid-two-cookies") << "a=b, c=d" << header << jar;
4933 cookie = QNetworkCookie("a", "b");
4934 cookie.setPath("/not/part-of-path");
4936 cookie.setDomain(QtNetworkSettings::serverName());
4938 QTest::newRow("invalid-cookie-path") << "a=b; path=/not/part-of-path" << header << jar;
4941 cookie = QNetworkCookie("a", "b");
4942 cookie.setDomain(".example.com");
4945 QTest::newRow("invalid-cookie-domain") << "a=b; domain=.example.com" << header << jar;
4948 void tst_QNetworkReply::receiveCookiesFromHttp()
4950 QFETCH(QString, cookieString);
4952 QByteArray data = cookieString.toLatin1() + '\n';
4953 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/set-cookie.cgi");
4954 QNetworkRequest request(url);
4955 request.setRawHeader("Content-Type", "application/octet-stream");
4956 QNetworkReplyPtr reply;
4957 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PostOperation, request, reply, data));
4959 QCOMPARE(reply->url(), url);
4960 QCOMPARE(reply->error(), QNetworkReply::NoError);
4962 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
4964 QList<QNetworkCookie> setCookies =
4965 qvariant_cast<QList<QNetworkCookie> >(reply->header(QNetworkRequest::SetCookieHeader));
4966 QTEST(setCookies, "expectedCookiesFromHttp");
4967 QTEST(cookieJar->allCookies(), "expectedCookiesInJar");
4970 void tst_QNetworkReply::receiveCookiesFromHttpSynchronous_data()
4972 tst_QNetworkReply::receiveCookiesFromHttp_data();
4975 void tst_QNetworkReply::receiveCookiesFromHttpSynchronous()
4977 QFETCH(QString, cookieString);
4979 QByteArray data = cookieString.toLatin1() + '\n';
4980 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/set-cookie.cgi");
4982 QNetworkRequest request(url);
4983 request.setRawHeader("Content-Type", "application/octet-stream");
4984 request.setAttribute(
4985 QNetworkRequest::SynchronousRequestAttribute,
4988 QNetworkReplyPtr reply;
4989 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PostOperation, request, reply, data));
4991 QCOMPARE(reply->url(), url);
4992 QCOMPARE(reply->error(), QNetworkReply::NoError);
4994 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
4996 QList<QNetworkCookie> setCookies =
4997 qvariant_cast<QList<QNetworkCookie> >(reply->header(QNetworkRequest::SetCookieHeader));
4998 QTEST(setCookies, "expectedCookiesFromHttp");
4999 QTEST(cookieJar->allCookies(), "expectedCookiesInJar");
5002 void tst_QNetworkReply::sendCookies_data()
5004 QTest::addColumn<QList<QNetworkCookie> >("cookiesToSet");
5005 QTest::addColumn<QString>("expectedCookieString");
5007 QList<QNetworkCookie> list;
5008 QTest::newRow("empty") << list << "";
5010 QNetworkCookie cookie("a", "b");
5011 cookie.setPath("/");
5012 cookie.setDomain("example.com");
5014 QTest::newRow("no-match-domain") << list << "";
5016 cookie.setDomain(QtNetworkSettings::serverName());
5017 cookie.setPath("/something/else");
5019 QTest::newRow("no-match-path") << list << "";
5021 cookie.setPath("/");
5023 QTest::newRow("simple-cookie") << list << "a=b";
5025 cookie.setPath("/qtest");
5026 cookie.setValue("longer");
5028 QTest::newRow("two-cookies") << list << "a=longer; a=b";
5031 cookie = QNetworkCookie("a", "b");
5032 cookie.setPath("/");
5033 cookie.setDomain("." + QtNetworkSettings::serverDomainName());
5035 QTest::newRow("domain-match") << list << "a=b";
5037 // but it shouldn't match this:
5038 cookie.setDomain(QtNetworkSettings::serverDomainName());
5040 QTest::newRow("domain-match-2") << list << "a=b";
5043 void tst_QNetworkReply::sendCookies()
5045 QFETCH(QString, expectedCookieString);
5046 QFETCH(QList<QNetworkCookie>, cookiesToSet);
5047 cookieJar->setAllCookies(cookiesToSet);
5049 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/get-cookie.cgi");
5050 QNetworkRequest request(url);
5051 QNetworkReplyPtr reply;
5052 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
5054 QCOMPARE(reply->url(), url);
5055 QCOMPARE(reply->error(), QNetworkReply::NoError);
5057 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
5059 QCOMPARE(QString::fromLatin1(reply->readAll()).trimmed(), expectedCookieString);
5062 void tst_QNetworkReply::sendCookiesSynchronous_data()
5064 tst_QNetworkReply::sendCookies_data();
5067 void tst_QNetworkReply::sendCookiesSynchronous()
5069 QFETCH(QString, expectedCookieString);
5070 QFETCH(QList<QNetworkCookie>, cookiesToSet);
5071 cookieJar->setAllCookies(cookiesToSet);
5073 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/get-cookie.cgi");
5074 QNetworkRequest request(url);
5076 request.setAttribute(
5077 QNetworkRequest::SynchronousRequestAttribute,
5080 QNetworkReplyPtr reply;
5081 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
5083 QCOMPARE(reply->url(), url);
5084 QCOMPARE(reply->error(), QNetworkReply::NoError);
5086 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
5088 QCOMPARE(QString::fromLatin1(reply->readAll()).trimmed(), expectedCookieString);
5091 void tst_QNetworkReply::nestedEventLoops_slot()
5095 // 16 seconds: fluke times out in 15 seconds, which triggers a QTcpSocket error
5096 QTimer::singleShot(16000, &subloop, SLOT(quit()));
5099 QTestEventLoop::instance().exitLoop();
5102 void tst_QNetworkReply::nestedEventLoops()
5104 // Slightly fragile test, it may not be testing anything
5105 // This is certifying that we're not running into the same issue
5106 // that QHttp had (task 200432): the QTcpSocket connection is
5107 // closed by the remote end because of the kept-alive HTTP
5108 // connection timed out.
5110 // The exact time required for this to happen is not exactly
5111 // defined. Our server (Apache httpd) times out after 15
5112 // seconds. (see above)
5114 qDebug("Takes 16 seconds to run, please wait");
5116 QUrl url("http://" + QtNetworkSettings::serverName());
5117 QNetworkRequest request(url);
5118 QNetworkReplyPtr reply(manager.get(request));
5120 QSignalSpy finishedspy(reply.data(), SIGNAL(finished()));
5121 QSignalSpy errorspy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError)));
5123 connect(reply, SIGNAL(finished()), SLOT(nestedEventLoops_slot()));
5124 QTestEventLoop::instance().enterLoop(20);
5125 QVERIFY2(!QTestEventLoop::instance().timeout(), "Network timeout");
5127 QCOMPARE(finishedspy.count(), 1);
5128 QCOMPARE(errorspy.count(), 0);
5131 void tst_QNetworkReply::httpProxyCommands_data()
5133 QTest::addColumn<QUrl>("url");
5134 QTest::addColumn<QByteArray>("responseToSend");
5135 QTest::addColumn<QString>("expectedCommand");
5137 QTest::newRow("http")
5138 << QUrl("http://0.0.0.0:4443/http-request")
5139 << QByteArray("HTTP/1.0 200 OK\r\nProxy-Connection: close\r\nContent-Length: 1\r\n\r\n1")
5140 << "GET http://0.0.0.0:4443/http-request HTTP/1.";
5142 QTest::newRow("https")
5143 << QUrl("https://0.0.0.0:4443/https-request")
5144 << QByteArray("HTTP/1.0 200 Connection Established\r\n\r\n")
5145 << "CONNECT 0.0.0.0:4443 HTTP/1.";
5149 void tst_QNetworkReply::httpProxyCommands()
5152 QFETCH(QByteArray, responseToSend);
5153 QFETCH(QString, expectedCommand);
5155 MiniHttpServer proxyServer(responseToSend);
5156 QNetworkProxy proxy(QNetworkProxy::HttpProxy, "127.0.0.1", proxyServer.serverPort());
5158 manager.setProxy(proxy);
5159 QNetworkRequest request(url);
5160 request.setRawHeader("User-Agent", "QNetworkReplyAutoTest/1.0");
5161 QNetworkReplyPtr reply(manager.get(request));
5162 //clearing the proxy here causes the test to fail.
5163 //the proxy isn't used until after the bearer has been started
5164 //which is correct in general, because system proxy isn't known until that time.
5165 //removing this line is safe, as the proxy is also reset by the cleanup() function
5166 //manager.setProxy(QNetworkProxy());
5168 // wait for the finished signal
5169 QVERIFY(waitForFinish(reply) != Timeout);
5171 //qDebug() << reply->error() << reply->errorString();
5172 //qDebug() << proxyServer.receivedData;
5174 // we don't really care if the request succeeded
5175 // especially since it won't succeed in the HTTPS case
5176 // so just check that the command was correct
5178 QString receivedHeader = proxyServer.receivedData.left(expectedCommand.length());
5179 QCOMPARE(receivedHeader, expectedCommand);
5181 //QTBUG-17223 - make sure the user agent from the request is sent to proxy server even for CONNECT
5182 int uapos = proxyServer.receivedData.indexOf("User-Agent");
5183 int uaend = proxyServer.receivedData.indexOf("\r\n", uapos);
5184 QByteArray uaheader = proxyServer.receivedData.mid(uapos, uaend - uapos);
5185 QCOMPARE(uaheader, QByteArray("User-Agent: QNetworkReplyAutoTest/1.0"));
5188 class ProxyChangeHelper : public QObject {
5191 ProxyChangeHelper() : QObject(), signalCount(0) {};
5193 void finishedSlot() {
5195 if (signalCount == 2)
5196 QMetaObject::invokeMethod(&QTestEventLoop::instance(), "exitLoop", Qt::QueuedConnection);
5202 void tst_QNetworkReply::httpProxyCommandsSynchronous_data()
5204 httpProxyCommands_data();
5207 struct QThreadCleanup
5209 static inline void cleanup(QThread *thread)
5212 if (thread->wait(3000))
5215 qWarning("thread hung, leaking memory so test can finish");
5219 struct QDeleteLaterCleanup
5221 static inline void cleanup(QObject *o)
5227 void tst_QNetworkReply::httpProxyCommandsSynchronous()
5230 QFETCH(QByteArray, responseToSend);
5231 QFETCH(QString, expectedCommand);
5233 // when using synchronous commands, we need a different event loop for
5234 // the server thread, because the client is never returning to the
5236 QScopedPointer<QThread, QThreadCleanup> serverThread(new QThread);
5237 QScopedPointer<MiniHttpServer, QDeleteLaterCleanup> proxyServer(new MiniHttpServer(responseToSend, false, serverThread.data()));
5238 QNetworkProxy proxy(QNetworkProxy::HttpProxy, "127.0.0.1", proxyServer->serverPort());
5240 manager.setProxy(proxy);
5241 QNetworkRequest request(url);
5243 // send synchronous request
5244 request.setAttribute(
5245 QNetworkRequest::SynchronousRequestAttribute,
5248 QNetworkReplyPtr reply(manager.get(request));
5249 QVERIFY(reply->isFinished()); // synchronous
5250 manager.setProxy(QNetworkProxy());
5252 //qDebug() << reply->error() << reply->errorString();
5254 // we don't really care if the request succeeded
5255 // especially since it won't succeed in the HTTPS case
5256 // so just check that the command was correct
5258 QString receivedHeader = proxyServer->receivedData.left(expectedCommand.length());
5259 QCOMPARE(receivedHeader, expectedCommand);
5262 void tst_QNetworkReply::proxyChange()
5264 ProxyChangeHelper helper;
5265 MiniHttpServer proxyServer(
5266 "HTTP/1.0 200 OK\r\nProxy-Connection: keep-alive\r\n"
5267 "Content-Length: 1\r\n\r\n1");
5268 QNetworkProxy dummyProxy(QNetworkProxy::HttpProxy, "127.0.0.1", proxyServer.serverPort());
5269 QNetworkRequest req(QUrl("http://" + QtNetworkSettings::serverName()));
5270 proxyServer.doClose = false;
5272 manager.setProxy(dummyProxy);
5273 QNetworkReplyPtr reply1(manager.get(req));
5274 connect(reply1, SIGNAL(finished()), &helper, SLOT(finishedSlot()));
5276 manager.setProxy(QNetworkProxy());
5277 QNetworkReplyPtr reply2(manager.get(req));
5278 connect(reply2, SIGNAL(finished()), &helper, SLOT(finishedSlot()));
5280 QTestEventLoop::instance().enterLoop(20);
5281 QVERIFY(!QTestEventLoop::instance().timeout());
5283 // verify that the replies succeeded
5284 QCOMPARE(reply1->error(), QNetworkReply::NoError);
5285 QCOMPARE(reply1->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
5286 QVERIFY(reply1->size() == 1);
5288 QCOMPARE(reply2->error(), QNetworkReply::NoError);
5289 QCOMPARE(reply2->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
5290 QVERIFY(reply2->size() > 1);
5292 // now try again and get an error
5293 // this verifies that we reuse the already-open connection
5295 proxyServer.doClose = true;
5296 proxyServer.dataToTransmit =
5297 "HTTP/1.0 403 Forbidden\r\nProxy-Connection: close\r\n"
5298 "Content-Length: 1\r\n\r\n1";
5300 manager.setProxy(dummyProxy);
5301 QNetworkReplyPtr reply3(manager.get(req));
5303 QVERIFY(waitForFinish(reply3) == Failure);
5305 QVERIFY(int(reply3->error()) > 0);
5308 void tst_QNetworkReply::authorizationError_data()
5311 QTest::addColumn<QString>("url");
5312 QTest::addColumn<int>("errorSignalCount");
5313 QTest::addColumn<int>("finishedSignalCount");
5314 QTest::addColumn<int>("error");
5315 QTest::addColumn<int>("httpStatusCode");
5316 QTest::addColumn<QString>("httpBody");
5318 QTest::newRow("unknown-authorization-method") << "http://" + QtNetworkSettings::serverName() +
5319 "/qtest/cgi-bin/http-unknown-authentication-method.cgi?401-authorization-required" << 1 << 1
5320 << int(QNetworkReply::AuthenticationRequiredError) << 401 << "authorization required";
5321 QTest::newRow("unknown-proxy-authorization-method") << "http://" + QtNetworkSettings::serverName() +
5322 "/qtest/cgi-bin/http-unknown-authentication-method.cgi?407-proxy-authorization-required" << 1 << 1
5323 << int(QNetworkReply::ProxyAuthenticationRequiredError) << 407
5324 << "authorization required";
5327 void tst_QNetworkReply::authorizationError()
5329 QFETCH(QString, url);
5330 QNetworkRequest request(url);
5331 QNetworkReplyPtr reply(manager.get(request));
5333 QCOMPARE(reply->error(), QNetworkReply::NoError);
5335 QSignalSpy errorSpy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError)));
5336 QSignalSpy finishedSpy(reply.data(), SIGNAL(finished()));
5337 // now run the request:
5338 QVERIFY(waitForFinish(reply) == Failure);
5340 QFETCH(int, errorSignalCount);
5341 QCOMPARE(errorSpy.count(), errorSignalCount);
5342 QFETCH(int, finishedSignalCount);
5343 QCOMPARE(finishedSpy.count(), finishedSignalCount);
5345 QCOMPARE(reply->error(), QNetworkReply::NetworkError(error));
5347 QFETCH(int, httpStatusCode);
5348 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), httpStatusCode);
5350 QFETCH(QString, httpBody);
5351 QCOMPARE(qint64(reply->size()), qint64(httpBody.size()));
5352 QCOMPARE(QString(reply->readAll()), httpBody);
5355 void tst_QNetworkReply::httpConnectionCount()
5358 QVERIFY(server.listen());
5359 QCoreApplication::instance()->processEvents();
5361 for (int i = 0; i < 10; i++) {
5362 QNetworkRequest request (QUrl("http://127.0.0.1:" + QString::number(server.serverPort()) + "/" + QString::number(i)));
5363 QNetworkReply* reply = manager.get(request);
5364 reply->setParent(&server);
5367 int pendingConnectionCount = 0;
5371 while(pendingConnectionCount <= 20) {
5372 QTestEventLoop::instance().enterLoop(1);
5373 QTcpSocket *socket = server.nextPendingConnection();
5374 while (socket != 0) {
5375 pendingConnectionCount++;
5376 socket->setParent(&server);
5377 socket = server.nextPendingConnection();
5380 // at max. wait 10 sec
5381 if (time.elapsed() > 10000)
5385 QCOMPARE(pendingConnectionCount, 6);
5388 void tst_QNetworkReply::httpReUsingConnectionSequential_data()
5390 QTest::addColumn<bool>("doDeleteLater");
5391 QTest::newRow("deleteLater") << true;
5392 QTest::newRow("noDeleteLater") << false;
5395 void tst_QNetworkReply::httpReUsingConnectionSequential()
5397 QFETCH(bool, doDeleteLater);
5399 QByteArray response("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
5400 MiniHttpServer server(response);
5401 server.multiple = true;
5402 server.doClose = false;
5405 url.setScheme("http");
5406 url.setPort(server.serverPort());
5407 url.setHost("127.0.0.1");
5409 QNetworkReply* reply1 = manager.get(QNetworkRequest(url));
5410 connect(reply1, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
5411 QTestEventLoop::instance().enterLoop(2);
5412 QVERIFY(!QTestEventLoop::instance().timeout());
5413 QVERIFY(!reply1->error());
5414 int reply1port = server.client->peerPort();
5417 reply1->deleteLater();
5419 // finished received, send the next one
5420 QNetworkReply*reply2 = manager.get(QNetworkRequest(url));
5421 connect(reply2, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
5422 QTestEventLoop::instance().enterLoop(2);
5423 QVERIFY(!QTestEventLoop::instance().timeout());
5424 QVERIFY(!reply2->error());
5425 int reply2port = server.client->peerPort(); // should still be the same object
5427 QVERIFY(reply1port > 0);
5428 QCOMPARE(server.totalConnections, 1);
5429 QCOMPARE(reply2port, reply1port);
5432 reply1->deleteLater(); // only do it if it was not done earlier
5433 reply2->deleteLater();
5436 class HttpReUsingConnectionFromFinishedSlot : public QObject {
5439 QNetworkReply* reply1;
5440 QNetworkReply* reply2;
5442 QNetworkAccessManager manager;
5444 void finishedSlot() {
5445 QVERIFY(!reply1->error());
5447 QFETCH(bool, doDeleteLater);
5448 if (doDeleteLater) {
5449 reply1->deleteLater();
5453 // kick off 2nd request and exit the loop when it is done
5454 reply2 = manager.get(QNetworkRequest(url));
5455 reply2->setParent(this);
5456 connect(reply2, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
5460 void tst_QNetworkReply::httpReUsingConnectionFromFinishedSlot_data()
5462 httpReUsingConnectionSequential_data();
5465 void tst_QNetworkReply::httpReUsingConnectionFromFinishedSlot()
5467 QByteArray response("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
5468 MiniHttpServer server(response);
5469 server.multiple = true;
5470 server.doClose = false;
5472 HttpReUsingConnectionFromFinishedSlot helper;
5475 helper.url.setScheme("http");
5476 helper.url.setPort(server.serverPort());
5477 helper.url.setHost("127.0.0.1");
5480 helper.reply1 = helper.manager.get(QNetworkRequest(helper.url));
5481 helper.reply1->setParent(&helper);
5482 connect(helper.reply1, SIGNAL(finished()), &helper, SLOT(finishedSlot()));
5483 QTestEventLoop::instance().enterLoop(4);
5484 QVERIFY(!QTestEventLoop::instance().timeout());
5486 QVERIFY(helper.reply2);
5487 QVERIFY(!helper.reply2->error());
5489 QCOMPARE(server.totalConnections, 1);
5492 class HttpRecursiveCreationHelper : public QObject {
5496 HttpRecursiveCreationHelper():
5498 requestsStartedCount_finished(0),
5499 requestsStartedCount_readyRead(0),
5500 requestsFinishedCount(0)
5503 QNetworkAccessManager manager;
5504 int requestsStartedCount_finished;
5505 int requestsStartedCount_readyRead;
5506 int requestsFinishedCount;
5508 void finishedSlot() {
5509 requestsFinishedCount++;
5511 QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
5512 QVERIFY(!reply->error());
5513 QVERIFY(reply->bytesAvailable() == 27906);
5515 if (requestsFinishedCount == 60) {
5516 QTestEventLoop::instance().exitLoop();
5520 if (requestsStartedCount_finished < 30) {
5522 requestsStartedCount_finished++;
5525 reply->deleteLater();
5527 void readyReadSlot() {
5528 QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
5529 QVERIFY(!reply->error());
5531 if (requestsStartedCount_readyRead < 30 && reply->bytesAvailable() > 27906/2) {
5533 requestsStartedCount_readyRead++;
5537 QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/fluke.gif";
5538 QNetworkRequest request(url);
5539 QNetworkReply *reply = manager.get(request);
5540 reply->setParent(this);
5541 connect(reply, SIGNAL(finished()), this, SLOT(finishedSlot()));
5542 connect(reply, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
5546 void tst_QNetworkReply::httpRecursiveCreation()
5548 // this test checks if creation of new requests to the same host properly works
5549 // from readyRead() and finished() signals
5550 HttpRecursiveCreationHelper helper;
5552 QTestEventLoop::instance().enterLoop(30);
5553 QVERIFY(!QTestEventLoop::instance().timeout());
5557 void tst_QNetworkReply::ignoreSslErrorsList_data()
5559 QTest::addColumn<QString>("url");
5560 QTest::addColumn<QList<QSslError> >("expectedSslErrors");
5561 QTest::addColumn<QNetworkReply::NetworkError>("expectedNetworkError");
5563 QList<QSslError> expectedSslErrors;
5564 QList<QSslCertificate> certs = QSslCertificate::fromPath(testDataDir + "/certs/qt-test-server-cacert.pem");
5565 QSslError rightError(QSslError::SelfSignedCertificate, certs.at(0));
5566 QSslError wrongError(QSslError::SelfSignedCertificate);
5568 QTest::newRow("SSL-failure-empty-list") << "https://" + QtNetworkSettings::serverName() + "/index.html" << expectedSslErrors << QNetworkReply::SslHandshakeFailedError;
5569 expectedSslErrors.append(wrongError);
5570 QTest::newRow("SSL-failure-wrong-error") << "https://" + QtNetworkSettings::serverName() + "/index.html" << expectedSslErrors << QNetworkReply::SslHandshakeFailedError;
5571 expectedSslErrors.append(rightError);
5572 QTest::newRow("allErrorsInExpectedList1") << "https://" + QtNetworkSettings::serverName() + "/index.html" << expectedSslErrors << QNetworkReply::NoError;
5573 expectedSslErrors.removeAll(wrongError);
5574 QTest::newRow("allErrorsInExpectedList2") << "https://" + QtNetworkSettings::serverName() + "/index.html" << expectedSslErrors << QNetworkReply::NoError;
5575 expectedSslErrors.removeAll(rightError);
5576 QTest::newRow("SSL-failure-empty-list-again") << "https://" + QtNetworkSettings::serverName() + "/index.html" << expectedSslErrors << QNetworkReply::SslHandshakeFailedError;
5579 void tst_QNetworkReply::ignoreSslErrorsList()
5581 QFETCH(QString, url);
5582 QNetworkRequest request(url);
5583 QNetworkReplyPtr reply(manager.get(request));
5585 QFETCH(QList<QSslError>, expectedSslErrors);
5586 reply->ignoreSslErrors(expectedSslErrors);
5588 QVERIFY(waitForFinish(reply) != Timeout);
5590 QFETCH(QNetworkReply::NetworkError, expectedNetworkError);
5591 QCOMPARE(reply->error(), expectedNetworkError);
5594 void tst_QNetworkReply::ignoreSslErrorsListWithSlot_data()
5596 ignoreSslErrorsList_data();
5599 // this is not a test, just a slot called in the test below
5600 void tst_QNetworkReply::ignoreSslErrorListSlot(QNetworkReply *reply, const QList<QSslError> &)
5602 reply->ignoreSslErrors(storedExpectedSslErrors);
5605 // do the same as in ignoreSslErrorsList, but ignore the errors in the slot
5606 void tst_QNetworkReply::ignoreSslErrorsListWithSlot()
5608 QFETCH(QString, url);
5609 QNetworkRequest request(url);
5610 QNetworkReplyPtr reply(manager.get(request));
5612 QFETCH(QList<QSslError>, expectedSslErrors);
5613 // store the errors to ignore them later in the slot connected below
5614 storedExpectedSslErrors = expectedSslErrors;
5615 connect(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
5616 this, SLOT(ignoreSslErrorListSlot(QNetworkReply*,QList<QSslError>)));
5619 QVERIFY(waitForFinish(reply) != Timeout);
5621 QFETCH(QNetworkReply::NetworkError, expectedNetworkError);
5622 QCOMPARE(reply->error(), expectedNetworkError);
5625 void tst_QNetworkReply::sslConfiguration_data()
5627 QTest::addColumn<QSslConfiguration>("configuration");
5628 QTest::addColumn<bool>("works");
5630 QTest::newRow("empty") << QSslConfiguration() << false;
5631 QSslConfiguration conf = QSslConfiguration::defaultConfiguration();
5632 QTest::newRow("default") << conf << false; // does not contain test server cert
5633 QList<QSslCertificate> testServerCert = QSslCertificate::fromPath(testDataDir + "/certs/qt-test-server-cacert.pem");
5634 conf.setCaCertificates(testServerCert);
5635 QTest::newRow("set-root-cert") << conf << true;
5636 conf.setProtocol(QSsl::SecureProtocols);
5637 QTest::newRow("secure") << conf << true;
5640 void tst_QNetworkReply::sslConfiguration()
5642 QNetworkRequest request(QUrl("https://" + QtNetworkSettings::serverName() + "/index.html"));
5643 QFETCH(QSslConfiguration, configuration);
5644 request.setSslConfiguration(configuration);
5645 QNetworkReplyPtr reply(manager.get(request));
5647 QVERIFY(waitForFinish(reply) != Timeout);
5649 QFETCH(bool, works);
5650 QNetworkReply::NetworkError expectedError = works ? QNetworkReply::NoError : QNetworkReply::SslHandshakeFailedError;
5651 QCOMPARE(reply->error(), expectedError);
5656 void tst_QNetworkReply::getAndThenDeleteObject_data()
5658 QTest::addColumn<bool>("replyFirst");
5660 QTest::newRow("delete-reply-first") << true;
5661 QTest::newRow("delete-qnam-first") << false;
5664 void tst_QNetworkReply::getAndThenDeleteObject()
5666 QSKIP("unstable test - reply may be finished too early");
5667 // yes, this will leak if the testcase fails. I don't care. It must not fail then :P
5668 QNetworkAccessManager *manager = new QNetworkAccessManager();
5669 QNetworkRequest request("http://" + QtNetworkSettings::serverName() + "/qtest/bigfile");
5670 QNetworkReply *reply = manager->get(request);
5671 reply->setReadBufferSize(1);
5672 reply->setParent((QObject*)0); // must be 0 because else it is the manager
5677 QCoreApplication::instance()->processEvents();
5678 if (reply->bytesAvailable())
5680 if (stopWatch.elapsed() >= 30000)
5684 QVERIFY(reply->bytesAvailable());
5685 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
5686 QVERIFY(!reply->isFinished()); // must not be finished
5688 QFETCH(bool, replyFirst);
5699 // see https://bugs.webkit.org/show_bug.cgi?id=38935
5700 void tst_QNetworkReply::symbianOpenCDataUrlCrash()
5702 QString requestUrl("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAWCAYAAAA1vze2AAAAB3RJTUUH2AUSEgolrgBvVQAAAAlwSFlzAAALEwAACxMBAJqcGAAAAARnQU1BAACxjwv8YQUAAAHlSURBVHja5VbNShxBEK6ZaXtnHTebQPA1gngNmfaeq+QNPIlIXkC9iQdJxJNvEHLN3VkxhxxE8gTmEhAVddXZ6Z3f9Ndriz89/sHmkBQUVVT1fB9d9c3uOERUKTunIdn3HzstxGpYBDS4wZk7TAJj/wlJ90J+jnuygqs8svSj+/rGHBos3rE18XBvfU3no7NzlJfUaY/5whAwl8Lr/WDUv4ODxTMb+P5xLExe5LmO559WqTX/MQR4WZYEAtSePS4pE0qSnuhnRUcBU5Gm2k9XljU4Z26I3NRxBrd80rj2fh+KNE0FY4xevRgTjREvPFpasAK8Xli6MUbbuKw3afAGgSBXozo5u4hkmncAlkl5wx8iMGbdyQjnCFEiEwGiosj1UQA/x2rVddiVoi+l4IxE0PTDnx+mrQBvvnx9cFz3krhVvuhzFn579/aq/n5rW8fbtTqiWhIQZEo17YBvbkxOXNVndnYpTvod7AtiuN2re0+siwcB9oH8VxxrNwQQAhzyRs30n7wTI2HIN2g2QtQwjjhJIQatOq7E8bIVCLwzpl83Lvtvl+NohWWlE8UZTWEMAGCcR77fHKhPnZF5tYie6dfdxCphACmLPM+j8bYfmTryg64kV9Vh3mV8jP0b/4wO/YUPiT/8i0MLf55lSQAAAABJRU5ErkJggg==");
5703 QUrl url = QUrl::fromEncoded(requestUrl.toLatin1());
5704 QNetworkRequest req(url);
5705 QNetworkReplyPtr reply;
5707 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, req, reply));
5709 QCOMPARE(reply->url(), url);
5710 QCOMPARE(reply->error(), QNetworkReply::NoError);
5712 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), qint64(598));
5715 void tst_QNetworkReply::getFromHttpIntoBuffer_data()
5717 QTest::addColumn<QUrl>("url");
5719 QTest::newRow("rfc-internal") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt");
5722 // Please note that the whole "zero copy" download buffer API is private right now. Do not use it.
5723 void tst_QNetworkReply::getFromHttpIntoBuffer()
5726 QNetworkRequest request(url);
5727 request.setAttribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute, 1024*128); // 128 kB
5729 QNetworkAccessManager manager;
5730 QNetworkReply *reply = manager.get(request);
5731 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
5732 QTestEventLoop::instance().enterLoop(10);
5733 QVERIFY(!QTestEventLoop::instance().timeout());
5734 QVERIFY(reply->isFinished());
5736 QFile reference(testDataDir + "/rfc3252.txt");
5737 QVERIFY(reference.open(QIODevice::ReadOnly));
5739 QCOMPARE(reference.bytesAvailable(), reply->bytesAvailable());
5740 QCOMPARE(reference.size(), reply->size());
5742 // Compare the memory buffer
5743 QVariant downloadBufferAttribute = reply->attribute(QNetworkRequest::DownloadBufferAttribute);
5744 QVERIFY(downloadBufferAttribute.isValid());
5745 QSharedPointer<char> sharedPointer = downloadBufferAttribute.value<QSharedPointer<char> >();
5746 bool memoryComparison =
5747 (0 == memcmp(static_cast<void*>(reference.readAll().data()),
5748 sharedPointer.data(), reference.size()));
5749 QVERIFY(memoryComparison);
5751 // Make sure the normal reading works
5753 QCOMPARE(reply->read(42), reference.read(42));
5754 QCOMPARE(reply->getChar(0), reference.getChar(0));
5755 QCOMPARE(reply->peek(23), reference.peek(23));
5756 QCOMPARE(reply->readLine(), reference.readLine());
5757 QCOMPARE(reference.bytesAvailable(), reply->bytesAvailable());
5758 QCOMPARE(reply->readAll(), reference.readAll());
5759 QVERIFY(reply->atEnd());
5762 // FIXME we really need to consolidate all those server implementations
5763 class GetFromHttpIntoBuffer2Server : QObject {
5769 bool serverSendsContentLength;
5770 bool chunkedEncoding;
5773 GetFromHttpIntoBuffer2Server (qint64 ds, bool sscl, bool ce) : dataSize(ds), dataSent(0),
5774 client(0), serverSendsContentLength(sscl), chunkedEncoding(ce) {
5776 connect(&server, SIGNAL(newConnection()), this, SLOT(newConnectionSlot()));
5780 return server.serverPort();
5785 void newConnectionSlot() {
5786 client = server.nextPendingConnection();
5787 client->setParent(this);
5788 connect(client, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
5789 connect(client, SIGNAL(bytesWritten(qint64)), this, SLOT(bytesWrittenSlot(qint64)));
5792 void readyReadSlot() {
5794 client->write("HTTP/1.0 200 OK\n");
5795 if (serverSendsContentLength)
5796 client->write(QString("Content-Length: " + QString::number(dataSize) + "\n").toLatin1());
5797 if (chunkedEncoding)
5798 client->write(QString("Transfer-Encoding: chunked\n").toLatin1());
5799 client->write("Connection: close\n\n");
5802 void bytesWrittenSlot(qint64 amount) {
5804 if (dataSent == dataSize && client) {
5807 // chunked encoding: we have to send a last "empty" chunk
5808 if (chunkedEncoding)
5809 client->write(QString("0\r\n\r\n").toLatin1());
5811 client->disconnectFromHost();
5818 if (client && client->bytesToWrite() < 100*1024 && dataSent < dataSize) {
5819 qint64 amount = qMin(qint64(16*1024), dataSize - dataSent);
5820 QByteArray data(amount, '@');
5822 if (chunkedEncoding) {
5823 client->write(QString(QString("%1").arg(amount,0,16).toUpper() + "\r\n").toLatin1());
5824 client->write(data.constData(), amount);
5825 client->write(QString("\r\n").toLatin1());
5827 client->write(data.constData(), amount);
5835 class GetFromHttpIntoBuffer2Client : QObject {
5838 bool useDownloadBuffer;
5839 QNetworkReply *reply;
5841 QList<qint64> bytesAvailableList;
5843 GetFromHttpIntoBuffer2Client (QNetworkReply *reply, bool useDownloadBuffer, qint64 uploadSize)
5844 : useDownloadBuffer(useDownloadBuffer), reply(reply), uploadSize(uploadSize)
5846 connect(reply, SIGNAL(metaDataChanged()), this, SLOT(metaDataChangedSlot()));
5847 connect(reply, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
5848 connect(reply, SIGNAL(finished()), this, SLOT(finishedSlot()));
5852 void metaDataChangedSlot() {
5853 if (useDownloadBuffer) {
5854 QSharedPointer<char> sharedPointer = qvariant_cast<QSharedPointer<char> >(reply->attribute(QNetworkRequest::DownloadBufferAttribute));
5855 QVERIFY(!sharedPointer.isNull()); // It will be 0 if it failed
5858 // metaDataChanged needs to come before everything else
5859 QVERIFY(bytesAvailableList.isEmpty());
5862 void readyReadSlot() {
5863 QVERIFY(!reply->isFinished());
5865 qint64 bytesAvailable = reply->bytesAvailable();
5867 // bytesAvailable must never be 0
5868 QVERIFY(bytesAvailable != 0);
5870 if (bytesAvailableList.length() < 5) {
5871 // We assume that the first few times the bytes available must be less than the complete size, e.g.
5872 // the bytesAvailable() function works correctly in case of a downloadBuffer.
5873 QVERIFY(bytesAvailable < uploadSize);
5875 if (!bytesAvailableList.isEmpty()) {
5876 // Also check that the same bytesAvailable is not coming twice in a row
5877 QVERIFY(bytesAvailableList.last() != bytesAvailable);
5880 bytesAvailableList.append(bytesAvailable);
5881 // Add bytesAvailable to a list an parse
5884 void finishedSlot() {
5885 // We should have already received all readyRead
5886 QVERIFY(!bytesAvailableList.isEmpty());
5887 QVERIFY(bytesAvailableList.last() == uploadSize);
5891 void tst_QNetworkReply::getFromHttpIntoBuffer2_data()
5893 QTest::addColumn<bool>("useDownloadBuffer");
5895 QTest::newRow("use-download-buffer") << true;
5896 QTest::newRow("do-not-use-download-buffer") << false;
5899 // This test checks mostly that signal emissions are in correct order
5900 // Please note that the whole "zero copy" download buffer API is private right now. Do not use it.
5901 void tst_QNetworkReply::getFromHttpIntoBuffer2()
5903 QFETCH(bool, useDownloadBuffer);
5905 // On my Linux Desktop the results are already visible with 128 kB, however we use this to have good results.
5906 #if defined(Q_OS_WINCE_WM)
5907 // Show some mercy to non-desktop platform/s
5908 enum {UploadSize = 4*1024*1024}; // 4 MB
5910 enum {UploadSize = 32*1024*1024}; // 32 MB
5913 GetFromHttpIntoBuffer2Server server(UploadSize, true, false);
5915 QNetworkRequest request(QUrl("http://127.0.0.1:" + QString::number(server.serverPort()) + "/?bare=1"));
5916 if (useDownloadBuffer)
5917 request.setAttribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute, 1024*1024*128); // 128 MB is max allowed
5919 QNetworkAccessManager manager;
5920 QNetworkReplyPtr reply(manager.get(request));
5922 GetFromHttpIntoBuffer2Client client(reply.data(), useDownloadBuffer, UploadSize);
5924 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
5925 QTestEventLoop::instance().enterLoop(40);
5926 QCOMPARE(reply->error(), QNetworkReply::NoError);
5927 QVERIFY(!QTestEventLoop::instance().timeout());
5931 void tst_QNetworkReply::getFromHttpIntoBufferCanReadLine()
5933 QString header("HTTP/1.0 200 OK\r\nContent-Length: 7\r\n\r\nxxx\nxxx");
5935 MiniHttpServer server(header.toLatin1());
5936 server.doClose = true;
5938 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
5939 request.setAttribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute, 1024*1024*128); // 128 MB is max allowed
5940 QNetworkReplyPtr reply(manager.get(request));
5942 QVERIFY(waitForFinish(reply) == Success);
5944 QCOMPARE(reply->error(), QNetworkReply::NoError);
5945 QVERIFY(reply->canReadLine());
5946 QCOMPARE(reply->read(1), QByteArray("x"));
5947 QVERIFY(reply->canReadLine());
5948 QCOMPARE(reply->read(3), QByteArray("xx\n"));
5949 QVERIFY(!reply->canReadLine());
5950 QCOMPARE(reply->readAll(), QByteArray("xxx"));
5951 QVERIFY(!reply->canReadLine());
5956 // Is handled somewhere else too, introduced this special test to have it more accessible
5957 void tst_QNetworkReply::ioGetFromHttpWithoutContentLength()
5959 QByteArray dataToSend("HTTP/1.0 200 OK\r\n\r\nHALLO! 123!");
5960 MiniHttpServer server(dataToSend);
5961 server.doClose = true;
5963 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
5964 QNetworkReplyPtr reply(manager.get(request));
5966 QVERIFY(waitForFinish(reply) == Success);
5968 QCOMPARE(reply->url(), request.url());
5969 QVERIFY(reply->isFinished());
5970 QVERIFY(reply->error() == QNetworkReply::NoError);
5973 // Is handled somewhere else too, introduced this special test to have it more accessible
5974 void tst_QNetworkReply::ioGetFromHttpBrokenChunkedEncoding()
5976 // This is wrong chunked encoding because of the X. What actually has to follow is \r\n
5977 // and then the declaration of the final 0 chunk
5978 QByteArray dataToSend("HTTP/1.0 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n3\r\nABCX");
5979 MiniHttpServer server(dataToSend);
5980 server.doClose = false; // FIXME
5982 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
5983 QNetworkReplyPtr reply(manager.get(request));
5985 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
5986 QTestEventLoop::instance().enterLoop(10);
5988 QEXPECT_FAIL(0, "We should close the socket and not just do nothing", Continue);
5989 QVERIFY(!QTestEventLoop::instance().timeout());
5990 QEXPECT_FAIL(0, "We should close the socket and not just do nothing", Continue);
5991 QVERIFY(reply->isFinished());
5992 QCOMPARE(reply->error(), QNetworkReply::NoError);
5996 // Prepare a gzip that has one chunk that expands to the size mentioned in the bugreport.
5997 // Then have a custom HTTP server that waits after this chunk so the returning gets
5999 void tst_QNetworkReply::qtbug12908compressedHttpReply()
6001 QString header("HTTP/1.0 200 OK\r\nContent-Encoding: gzip\r\nContent-Length: 63\r\n\r\n");
6003 // dd if=/dev/zero of=qtbug-12908 bs=16384 count=1 && gzip qtbug-12908 && base64 -w 0 qtbug-12908.gz
6004 QString encodedFile("H4sICDdDaUwAA3F0YnVnLTEyOTA4AO3BMQEAAADCoPVPbQwfoAAAAAAAAAAAAAAAAAAAAIC3AYbSVKsAQAAA");
6005 QByteArray decodedFile = QByteArray::fromBase64(encodedFile.toLatin1());
6006 QCOMPARE(decodedFile.size(), 63);
6008 MiniHttpServer server(header.toLatin1() + decodedFile);
6009 server.doClose = true;
6011 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
6012 QNetworkReplyPtr reply(manager.get(request));
6014 QVERIFY(waitForFinish(reply) == Success);
6016 QCOMPARE(reply->error(), QNetworkReply::NoError);
6017 QCOMPARE(reply->size(), qint64(16384));
6018 QCOMPARE(reply->readAll(), QByteArray(16384, '\0'));
6021 void tst_QNetworkReply::compressedHttpReplyBrokenGzip()
6023 QString header("HTTP/1.0 200 OK\r\nContent-Encoding: gzip\r\nContent-Length: 63\r\n\r\n");
6025 // dd if=/dev/zero of=qtbug-12908 bs=16384 count=1 && gzip qtbug-12908 && base64 -w 0 qtbug-12908.gz
6026 // Then change "BMQ" to "BMX"
6027 QString encodedFile("H4sICDdDaUwAA3F0YnVnLTEyOTA4AO3BMXEAAADCoPVPbQwfoAAAAAAAAAAAAAAAAAAAAIC3AYbSVKsAQAAA");
6028 QByteArray decodedFile = QByteArray::fromBase64(encodedFile.toLatin1());
6029 QCOMPARE(decodedFile.size(), 63);
6031 MiniHttpServer server(header.toLatin1() + decodedFile);
6032 server.doClose = true;
6034 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
6035 QNetworkReplyPtr reply(manager.get(request));
6037 QVERIFY(waitForFinish(reply) == Failure);
6039 QCOMPARE(reply->error(), QNetworkReply::ProtocolFailure);
6042 // TODO add similar test for FTP
6043 void tst_QNetworkReply::getFromUnreachableIp()
6045 QNetworkAccessManager manager;
6047 QNetworkRequest request(QUrl("http://255.255.255.255/42/23/narf/narf/narf"));
6048 QNetworkReplyPtr reply(manager.get(request));
6050 QVERIFY(waitForFinish(reply) == Failure);
6052 QVERIFY(reply->error() != QNetworkReply::NoError);
6055 void tst_QNetworkReply::qtbug4121unknownAuthentication()
6057 MiniHttpServer server(QByteArray("HTTP/1.1 401 bla\r\nWWW-Authenticate: crap\r\nContent-Length: 0\r\n\r\n"));
6058 server.doClose = false;
6060 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
6061 QNetworkAccessManager manager;
6062 QNetworkReplyPtr reply(manager.get(request));
6064 QSignalSpy authSpy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
6065 QSignalSpy finishedSpy(&manager, SIGNAL(finished(QNetworkReply*)));
6066 QSignalSpy errorSpy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError)));
6068 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6069 QTestEventLoop::instance().enterLoop(10);
6070 QVERIFY(!QTestEventLoop::instance().timeout());
6072 QCOMPARE(authSpy.count(), 0);
6073 QCOMPARE(finishedSpy.count(), 1);
6074 QCOMPARE(errorSpy.count(), 1);
6076 QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError);
6079 void tst_QNetworkReply::authenticationCacheAfterCancel_data()
6081 QTest::addColumn<QNetworkProxy>("proxy");
6082 QTest::addColumn<bool>("proxyAuth");
6083 QTest::addColumn<QUrl>("url");
6084 for (int i = 0; i < proxies.count(); ++i) {
6085 QTest::newRow("http" + proxies.at(i).tag) << proxies.at(i).proxy << proxies.at(i).requiresAuthentication << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt");
6087 QTest::newRow("https" + proxies.at(i).tag) << proxies.at(i).proxy << proxies.at(i).requiresAuthentication << QUrl("https://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt");
6092 class AuthenticationCacheHelper : public QObject
6096 AuthenticationCacheHelper()
6099 void proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *auth)
6101 if (!proxyPassword.isNull()) {
6102 auth->setUser(proxyUserName);
6103 auth->setPassword(proxyPassword);
6104 //clear credentials, if they are asked again, they were bad
6105 proxyUserName.clear();
6106 proxyPassword.clear();
6109 void authenticationRequired(QNetworkReply*,QAuthenticator *auth)
6111 if (!httpPassword.isNull()) {
6112 auth->setUser(httpUserName);
6113 auth->setPassword(httpPassword);
6114 //clear credentials, if they are asked again, they were bad
6115 httpUserName.clear();
6116 httpPassword.clear();
6120 QString httpUserName;
6121 QString httpPassword;
6122 QString proxyUserName;
6123 QString proxyPassword;
6126 /* Purpose of this test is to check credentials are cached correctly.
6127 - If user cancels authentication dialog (i.e. nothing is set to the QAuthenticator by the callback) then this is not cached
6128 - if user supplies a wrong password, then this is not cached
6129 - if user supplies a correct user/password combination then this is cached
6131 Test is checking both the proxyAuthenticationRequired and authenticationRequired signals.
6133 void tst_QNetworkReply::authenticationCacheAfterCancel()
6135 QFETCH(QNetworkProxy, proxy);
6136 QFETCH(bool, proxyAuth);
6138 QNetworkAccessManager manager;
6140 connect(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
6141 SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
6143 manager.setProxy(proxy);
6144 QSignalSpy authSpy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
6145 QSignalSpy proxyAuthSpy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
6147 AuthenticationCacheHelper helper;
6148 connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), &helper, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
6149 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), &helper, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
6151 QNetworkRequest request(url);
6152 QNetworkReplyPtr reply;
6154 //should fail due to no credentials
6155 reply.reset(manager.get(request));
6156 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6157 QTestEventLoop::instance().enterLoop(10);
6158 QVERIFY(!QTestEventLoop::instance().timeout());
6160 QCOMPARE(reply->error(), QNetworkReply::ProxyAuthenticationRequiredError);
6161 QCOMPARE(authSpy.count(), 0);
6162 QCOMPARE(proxyAuthSpy.count(), 1);
6163 proxyAuthSpy.clear();
6165 //should fail due to bad credentials
6166 helper.proxyUserName = "qsockstest";
6167 helper.proxyPassword = "badpassword";
6168 reply.reset(manager.get(request));
6169 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6170 QTestEventLoop::instance().enterLoop(10);
6171 QVERIFY(!QTestEventLoop::instance().timeout());
6173 QEXPECT_FAIL("http+socksauth", "QTBUG-23136 - danted accepts bad authentication but blocks the connection", Continue);
6174 QEXPECT_FAIL("https+socksauth", "QTBUG-23136 - danted accepts bad authentication but blocks the connection", Continue);
6176 QCOMPARE(reply->error(), QNetworkReply::ProxyAuthenticationRequiredError);
6177 QCOMPARE(authSpy.count(), 0);
6178 QVERIFY(proxyAuthSpy.count() > 0);
6179 proxyAuthSpy.clear();
6181 //QTBUG-23136 workaround
6182 if (proxy.port() == 1081) {
6183 #ifdef QT_BUILD_INTERNAL
6184 QNetworkAccessManagerPrivate::clearCache(&manager);
6186 return; //XFAIL result above
6190 //next proxy auth should succeed, due to correct credentials
6191 helper.proxyUserName = "qsockstest";
6192 helper.proxyPassword = "password";
6195 //should fail due to no credentials
6196 reply.reset(manager.get(request));
6197 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6198 QTestEventLoop::instance().enterLoop(10);
6199 QVERIFY(!QTestEventLoop::instance().timeout());
6201 QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError);
6202 QVERIFY(authSpy.count() > 0);
6205 QVERIFY(proxyAuthSpy.count() > 0);
6206 proxyAuthSpy.clear();
6209 //should fail due to bad credentials
6210 helper.httpUserName = "baduser";
6211 helper.httpPassword = "badpassword";
6212 reply.reset(manager.get(request));
6213 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6214 QTestEventLoop::instance().enterLoop(10);
6215 QVERIFY(!QTestEventLoop::instance().timeout());
6217 QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError);
6218 QVERIFY(authSpy.count() > 0);
6221 //should be supplied from cache
6222 QCOMPARE(proxyAuthSpy.count(), 0);
6223 proxyAuthSpy.clear();
6226 //next auth should succeed, due to correct credentials
6227 helper.httpUserName = "httptest";
6228 helper.httpPassword = "httptest";
6230 reply.reset(manager.get(request));
6231 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6232 QTestEventLoop::instance().enterLoop(10);
6233 QVERIFY(!QTestEventLoop::instance().timeout());
6235 QCOMPARE(reply->error(), QNetworkReply::NoError);
6236 QVERIFY(authSpy.count() > 0);
6239 //should be supplied from cache
6240 QCOMPARE(proxyAuthSpy.count(), 0);
6241 proxyAuthSpy.clear();
6244 //next auth should use cached credentials
6245 reply.reset(manager.get(request));
6246 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6247 QTestEventLoop::instance().enterLoop(10);
6248 QVERIFY(!QTestEventLoop::instance().timeout());
6250 QCOMPARE(reply->error(), QNetworkReply::NoError);
6251 //should be supplied from cache
6252 QCOMPARE(authSpy.count(), 0);
6255 //should be supplied from cache
6256 QCOMPARE(proxyAuthSpy.count(), 0);
6257 proxyAuthSpy.clear();
6262 void tst_QNetworkReply::authenticationWithDifferentRealm()
6264 AuthenticationCacheHelper helper;
6265 QNetworkAccessManager manager;
6267 connect(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
6268 SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
6270 connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), &helper, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
6271 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), &helper, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
6273 helper.httpUserName = "httptest";
6274 helper.httpPassword = "httptest";
6276 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt"));
6277 QNetworkReply* reply = manager.get(request);
6278 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6279 QTestEventLoop::instance().enterLoop(10);
6280 QVERIFY(!QTestEventLoop::instance().timeout());
6281 QCOMPARE(reply->error(), QNetworkReply::NoError);
6283 helper.httpUserName = "httptest";
6284 helper.httpPassword = "httptest";
6286 request.setUrl(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/auth-digest/"));
6287 reply = manager.get(request);
6288 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6289 QTestEventLoop::instance().enterLoop(10);
6290 QVERIFY(!QTestEventLoop::instance().timeout());
6291 QCOMPARE(reply->error(), QNetworkReply::NoError);
6294 class QtBug13431Helper : public QObject {
6297 QNetworkReply* m_reply;
6300 void replyFinished(QNetworkReply*) {
6301 QTestEventLoop::instance().exitLoop();
6304 void onReadAndReschedule() {
6305 const qint64 bytesReceived = m_reply->bytesAvailable();
6306 if (bytesReceived && m_reply->readBufferSize()) {
6307 QByteArray data = m_reply->read(bytesReceived);
6309 const int millisecDelay = static_cast<int>(bytesReceived * 1000 / m_reply->readBufferSize());
6310 m_dlTimer.start(millisecDelay);
6314 m_dlTimer.start(200);
6319 void tst_QNetworkReply::qtbug13431replyThrottling()
6321 QtBug13431Helper helper;
6323 QNetworkAccessManager nam;
6324 connect(&nam, SIGNAL(finished(QNetworkReply*)), &helper, SLOT(replyFinished(QNetworkReply*)));
6326 // Download a bigger file
6327 QNetworkRequest netRequest(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/bigfile"));
6328 helper.m_reply = nam.get(netRequest);
6330 helper.m_reply->setReadBufferSize(36000);
6332 // Schedule a timer that tries to read
6334 connect(&helper.m_dlTimer, SIGNAL(timeout()), &helper, SLOT(onReadAndReschedule()));
6335 helper.m_dlTimer.setSingleShot(true);
6336 helper.m_dlTimer.start(0);
6338 QTestEventLoop::instance().enterLoop(30);
6339 QVERIFY(!QTestEventLoop::instance().timeout());
6340 QVERIFY(helper.m_reply->isFinished());
6341 QCOMPARE(helper.m_reply->error(), QNetworkReply::NoError);
6344 void tst_QNetworkReply::httpWithNoCredentialUsage()
6346 QNetworkAccessManager manager;
6348 QSignalSpy authSpy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
6349 QSignalSpy finishedSpy(&manager, SIGNAL(finished(QNetworkReply*)));
6351 // Get with credentials, to preload authentication cache
6353 QNetworkRequest request(QUrl("http://httptest:httptest@" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi"));
6354 QNetworkReplyPtr reply(manager.get(request));
6355 QVERIFY(waitForFinish(reply) == Success);
6356 // credentials in URL, so don't expect authentication signal
6357 QCOMPARE(authSpy.count(), 0);
6358 QCOMPARE(finishedSpy.count(), 1);
6359 finishedSpy.clear();
6362 // Get with cached credentials (normal usage)
6364 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi"));
6365 QNetworkReplyPtr reply(manager.get(request));
6366 QVERIFY(waitForFinish(reply) == Success);
6367 // credentials in cache, so don't expect authentication signal
6368 QCOMPARE(authSpy.count(), 0);
6369 QCOMPARE(finishedSpy.count(), 1);
6370 finishedSpy.clear();
6373 // Do not use cached credentials (webkit cross origin usage)
6375 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi"));
6376 request.setAttribute(QNetworkRequest::AuthenticationReuseAttribute, QNetworkRequest::Manual);
6377 QNetworkReplyPtr reply(manager.get(request));
6379 QSignalSpy errorSpy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError)));
6381 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6382 QTestEventLoop::instance().enterLoop(10);
6383 QVERIFY(!QTestEventLoop::instance().timeout());
6385 // We check if authenticationRequired was emitted, however we do not anything in it so it should be 401
6386 QCOMPARE(authSpy.count(), 1);
6387 QCOMPARE(finishedSpy.count(), 1);
6388 QCOMPARE(errorSpy.count(), 1);
6390 QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError);
6394 void tst_QNetworkReply::qtbug15311doubleContentLength()
6396 QByteArray response("HTTP/1.0 200 OK\r\nContent-Length: 3\r\nServer: bogus\r\nContent-Length: 3\r\n\r\nABC");
6397 MiniHttpServer server(response);
6398 server.doClose = true;
6400 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
6401 QNetworkReplyPtr reply(manager.get(request));
6403 QVERIFY(waitForFinish(reply) == Success);
6405 QVERIFY(reply->isFinished());
6406 QCOMPARE(reply->error(), QNetworkReply::NoError);
6407 QCOMPARE(reply->size(), qint64(3));
6408 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), qint64(3));
6409 QCOMPARE(reply->rawHeader("Content-length"), QByteArray("3, 3"));
6410 QCOMPARE(reply->readAll(), QByteArray("ABC"));
6413 void tst_QNetworkReply::qtbug18232gzipContentLengthZero()
6415 QByteArray response("HTTP/1.0 200 OK\r\nContent-Encoding: gzip\r\nContent-Length: 0\r\n\r\n");
6416 MiniHttpServer server(response);
6417 server.doClose = true;
6419 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
6420 QNetworkReplyPtr reply(manager.get(request));
6422 QVERIFY(waitForFinish(reply) == Success);
6424 QVERIFY(reply->isFinished());
6425 QCOMPARE(reply->error(), QNetworkReply::NoError);
6426 QCOMPARE(reply->size(), qint64(0));
6427 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), qint64(0));
6428 QCOMPARE(reply->readAll(), QByteArray());
6431 // Reproduced a crash in QHttpNetworkReplyPrivate::gunzipBodyPartiallyEnd
6432 // where zlib inflateEnd was called for uninitialized zlib stream
6433 void tst_QNetworkReply::qtbug22660gzipNoContentLengthEmptyContent()
6435 // Response with no Content-Length in header and empty content
6436 QByteArray response("HTTP/1.0 200 OK\r\nContent-Encoding: gzip\r\n\r\n");
6437 MiniHttpServer server(response);
6438 server.doClose = true;
6440 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
6441 QNetworkReplyPtr reply(manager.get(request));
6443 QVERIFY(waitForFinish(reply) == Success);
6445 QVERIFY(reply->isFinished());
6446 QCOMPARE(reply->error(), QNetworkReply::NoError);
6447 QCOMPARE(reply->size(), qint64(0));
6448 QVERIFY(!reply->header(QNetworkRequest::ContentLengthHeader).isValid());
6449 QCOMPARE(reply->readAll(), QByteArray());
6452 class QtBug27161Helper : public QObject {
6455 QtBug27161Helper(MiniHttpServer & server, const QByteArray & data):
6459 connect(&m_server, SIGNAL(newConnection()), this, SLOT(newConnectionSlot()));
6462 void newConnectionSlot(){
6463 connect(m_server.client, SIGNAL(bytesWritten(qint64)), this, SLOT(bytesWrittenSlot()));
6466 void bytesWrittenSlot(){
6467 disconnect(m_server.client, SIGNAL(bytesWritten(qint64)), this, SLOT(bytesWrittenSlot()));
6468 m_Timer.singleShot(100, this, SLOT(timeoutSlot()));
6472 m_server.doClose = true;
6473 // we need to emulate the bytesWrittenSlot call if the data is empty.
6474 if (m_data.size() == 0)
6475 QMetaObject::invokeMethod(&m_server, "bytesWrittenSlot", Qt::QueuedConnection);
6477 m_server.client->write(m_data);
6481 MiniHttpServer & m_server;
6486 void tst_QNetworkReply::qtbug27161httpHeaderMayBeDamaged_data(){
6487 QByteArray response("HTTP/1.0 200 OK\r\nServer: bogus\r\nContent-Length: 3\r\n\r\nABC");
6488 QTest::addColumn<QByteArray>("firstPacket");
6489 QTest::addColumn<QByteArray>("secondPacket");
6491 for (int i = 1; i < response.size(); i++){
6492 QByteArray dataTag("Iteration: ");
6493 dataTag.append(QByteArray::number(i - 1));
6494 QTest::newRow(dataTag.constData()) << response.left(i) << response.mid(i);
6499 * Purpose of this test is to check whether a content from server is parsed correctly
6500 * if it is splitted into two parts.
6502 void tst_QNetworkReply::qtbug27161httpHeaderMayBeDamaged(){
6503 QFETCH(QByteArray, firstPacket);
6504 QFETCH(QByteArray, secondPacket);
6505 MiniHttpServer server(firstPacket);
6506 server.doClose = false;
6507 QtBug27161Helper helper(server, secondPacket);
6509 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
6510 QNetworkReplyPtr reply(manager.get(request));
6512 QVERIFY(waitForFinish(reply) == Success);
6514 QVERIFY(reply->isFinished());
6515 QCOMPARE(reply->error(), QNetworkReply::NoError);
6516 QCOMPARE(reply->size(), qint64(3));
6517 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), qint64(3));
6518 QCOMPARE(reply->rawHeader("Content-length"), QByteArray("3"));
6519 QCOMPARE(reply->rawHeader("Server"), QByteArray("bogus"));
6520 QCOMPARE(reply->readAll(), QByteArray("ABC"));
6523 void tst_QNetworkReply::synchronousRequest_data()
6525 QTest::addColumn<QUrl>("url");
6526 QTest::addColumn<QString>("expected");
6527 QTest::addColumn<bool>("checkContentLength");
6528 QTest::addColumn<QString>("mimeType");
6530 // ### cache, auth, proxies
6532 QTest::newRow("http")
6533 << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt")
6534 << QString("file:" + testDataDir + "/rfc3252.txt")
6536 << QString("text/plain");
6538 QTest::newRow("http-gzip")
6539 << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/deflate/rfc3252.txt")
6540 << QString("file:" + testDataDir + "/rfc3252.txt")
6541 << false // don't check content length, because it's gzip encoded
6542 // ### we would need to enflate (un-deflate) the file content and compare the sizes
6543 << QString("text/plain");
6546 QTest::newRow("https")
6547 << QUrl("https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt")
6548 << QString("file:" + testDataDir + "/rfc3252.txt")
6550 << QString("text/plain");
6553 QTest::newRow("data")
6554 << QUrl(QString::fromLatin1("data:text/plain,hello world"))
6555 << QString("data:hello world")
6556 << true // check content length
6557 << QString("text/plain");
6559 QTest::newRow("simple-file")
6560 << QUrl::fromLocalFile(testDataDir + "/rfc3252.txt")
6561 << QString("file:" + testDataDir + "/rfc3252.txt")
6566 // FIXME add testcase for failing network etc
6567 void tst_QNetworkReply::synchronousRequest()
6570 QFETCH(QString, expected);
6571 QFETCH(bool, checkContentLength);
6572 QFETCH(QString, mimeType);
6574 QNetworkRequest request(url);
6577 // workaround for HTTPS requests: add self-signed server cert to list of CA certs,
6578 // since we cannot react to the sslErrors() signal
6579 // to fix this properly we would need to have an ignoreSslErrors() method in the
6580 // QNetworkRequest, see http://bugreports.qt-project.org/browse/QTBUG-14774
6581 if (url.scheme() == "https") {
6582 QSslConfiguration sslConf;
6583 QList<QSslCertificate> certs = QSslCertificate::fromPath(testDataDir + "/certs/qt-test-server-cacert.pem");
6584 sslConf.setCaCertificates(certs);
6585 request.setSslConfiguration(sslConf);
6589 request.setAttribute(
6590 QNetworkRequest::SynchronousRequestAttribute,
6593 QNetworkReplyPtr reply;
6594 QSignalSpy finishedSpy(&manager, SIGNAL(finished(QNetworkReply*)));
6595 QSignalSpy sslErrorsSpy(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)));
6596 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply, 0));
6597 QVERIFY(reply->isFinished());
6598 QCOMPARE(finishedSpy.count(), 0);
6599 QCOMPARE(sslErrorsSpy.count(), 0);
6601 QCOMPARE(reply->header(QNetworkRequest::ContentTypeHeader).toString(), mimeType);
6603 QByteArray expectedContent;
6605 if (expected.startsWith("file:")) {
6606 QString path = expected.mid(5);
6608 file.open(QIODevice::ReadOnly);
6609 expectedContent = file.readAll();
6610 } else if (expected.startsWith("data:")) {
6611 expectedContent = expected.mid(5).toUtf8();
6614 if (checkContentLength)
6615 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), qint64(expectedContent.size()));
6616 QCOMPARE(reply->readAll(), expectedContent);
6618 reply->deleteLater();
6622 void tst_QNetworkReply::synchronousRequestSslFailure()
6624 // test that SSL won't be accepted with self-signed certificate,
6625 // and that we do not emit the sslError signal (in the manager that is,
6626 // in the reply we don't care)
6628 QUrl url("https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt");
6629 QNetworkRequest request(url);
6630 request.setAttribute(
6631 QNetworkRequest::SynchronousRequestAttribute,
6633 QNetworkReplyPtr reply;
6634 QSignalSpy sslErrorsSpy(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)));
6635 runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply, 0);
6636 QVERIFY(reply->isFinished());
6637 QCOMPARE(reply->error(), QNetworkReply::SslHandshakeFailedError);
6638 QCOMPARE(sslErrorsSpy.count(), 0);
6642 class HttpAbortHelper : public QObject
6646 HttpAbortHelper(QNetworkReply *parent)
6650 connect(parent, SIGNAL(readyRead()), this, SLOT(readyRead()));
6661 QMetaObject::invokeMethod(&QTestEventLoop::instance(), "exitLoop", Qt::QueuedConnection);
6665 QNetworkReply *mReply;
6668 void tst_QNetworkReply::httpAbort()
6670 // FIXME Also implement one where we do a big upload and then abort().
6671 // It must not crash either.
6673 // Abort after the first readyRead()
6674 QNetworkRequest request("http://" + QtNetworkSettings::serverName() + "/qtest/bigfile");
6675 QNetworkReplyPtr reply(manager.get(request));
6676 HttpAbortHelper replyHolder(reply.data());
6677 QTestEventLoop::instance().enterLoop(10);
6678 QVERIFY(!QTestEventLoop::instance().timeout());
6679 QCOMPARE(reply->error(), QNetworkReply::OperationCanceledError);
6680 QVERIFY(reply->isFinished());
6682 // Abort immediately after the get()
6683 QNetworkReplyPtr reply2(manager.get(request));
6684 connect(reply2, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
6686 QCOMPARE(reply2->error(), QNetworkReply::OperationCanceledError);
6687 QVERIFY(reply2->isFinished());
6689 // Abort after the finished()
6690 QNetworkRequest request3("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt");
6691 QNetworkReplyPtr reply3(manager.get(request3));
6693 QVERIFY(waitForFinish(reply3) == Success);
6695 QVERIFY(reply3->isFinished());
6697 QCOMPARE(reply3->error(), QNetworkReply::NoError);
6700 void tst_QNetworkReply::dontInsertPartialContentIntoTheCache()
6702 QByteArray reply206 =
6704 "Connection: keep-alive\r\n"
6705 "Content-Type: text/plain\r\n"
6706 "Cache-control: no-cache\r\n"
6707 "Content-Range: bytes 2-6/8\r\n"
6708 "Content-length: 4\r\n"
6712 MiniHttpServer server(reply206);
6713 server.doClose = false;
6715 MySpyMemoryCache *memoryCache = new MySpyMemoryCache(&manager);
6716 manager.setCache(memoryCache);
6718 QUrl url = "http://localhost:" + QString::number(server.serverPort());
6719 QNetworkRequest request(url);
6720 request.setRawHeader("Range", "bytes=2-6");
6722 QNetworkReplyPtr reply(manager.get(request));
6724 QVERIFY(waitForFinish(reply) == Success);
6726 QVERIFY(server.totalConnections > 0);
6727 QCOMPARE(reply->readAll().constData(), "load");
6728 QCOMPARE(memoryCache->m_insertedUrls.count(), 0);
6731 void tst_QNetworkReply::httpUserAgent()
6733 QByteArray response("HTTP/1.0 200 OK\r\n\r\n");
6734 MiniHttpServer server(response);
6735 server.doClose = true;
6737 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
6738 request.setHeader(QNetworkRequest::UserAgentHeader, "abcDEFghi");
6739 QNetworkReplyPtr reply(manager.get(request));
6741 QVERIFY(waitForFinish(reply) == Success);
6743 QVERIFY(reply->isFinished());
6744 QCOMPARE(reply->error(), QNetworkReply::NoError);
6745 QVERIFY(server.receivedData.contains("\r\nUser-Agent: abcDEFghi\r\n"));
6748 void tst_QNetworkReply::synchronousAuthenticationCache()
6750 class MiniAuthServer : public MiniHttpServer {
6752 MiniAuthServer(QThread *thread) : MiniHttpServer(QByteArray(), false, thread) {};
6753 virtual void reply() {
6756 "HTTP/1.0 401 Unauthorized\r\n"
6757 "WWW-Authenticate: Basic realm=\"QNetworkAccessManager Test Realm\"\r\n"
6758 "Content-Length: 4\r\n"
6759 "Connection: close\r\n"
6760 "Content-Type: text/plain\r\n"
6763 QRegExp rx("Authorization: Basic ([^\r\n]*)\r\n");
6764 if (rx.indexIn(receivedData) > 0) {
6765 if (QByteArray::fromBase64(rx.cap(1).toLatin1()) == "login:password") {
6767 "HTTP/1.0 200 OK\r\n"
6768 "Content-Type: text/plain\r\n"
6769 "Content-Length: 2\r\n"
6774 receivedData.clear();
6775 MiniHttpServer::reply();
6779 // when using synchronous commands, we need a different event loop for
6780 // the server thread, because the client is never returning to the
6782 QScopedPointer<QThread, QThreadCleanup> serverThread(new QThread);
6783 QScopedPointer<MiniHttpServer, QDeleteLaterCleanup> server(new MiniAuthServer(serverThread.data()));
6784 server->doClose = true;
6786 //1) URL without credentials, we are not authenticated
6788 QUrl url = "http://localhost:" + QString::number(server->serverPort()) + "/path";
6789 QNetworkRequest request(url);
6790 request.setAttribute(QNetworkRequest::SynchronousRequestAttribute, true);
6792 QNetworkReplyPtr reply(manager.get(request));
6793 QVERIFY(reply->isFinished());
6794 QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError);
6797 //2) URL with credentials, we are authenticated
6799 QUrl url = "http://login:password@localhost:" + QString::number(server->serverPort()) + "/path2";
6800 QNetworkRequest request(url);
6801 request.setAttribute(QNetworkRequest::SynchronousRequestAttribute, true);
6803 QNetworkReplyPtr reply(manager.get(request));
6804 QVERIFY(reply->isFinished());
6805 QCOMPARE(reply->error(), QNetworkReply::NoError);
6806 QCOMPARE(reply->readAll().constData(), "OK");
6809 //3) URL without credentials, we are authenticated because they are cached
6811 QUrl url = "http://localhost:" + QString::number(server->serverPort()) + "/path3";
6812 QNetworkRequest request(url);
6813 request.setAttribute(QNetworkRequest::SynchronousRequestAttribute, true);
6815 QNetworkReplyPtr reply(manager.get(request));
6816 QVERIFY(reply->isFinished());
6817 QCOMPARE(reply->error(), QNetworkReply::NoError);
6818 QCOMPARE(reply->readAll().constData(), "OK");
6822 void tst_QNetworkReply::pipelining()
6824 QString urlString("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/echo.cgi?");
6825 QList<QNetworkReplyPtr> replies;
6826 for (int a = 0; a < 20; a++) {
6827 QNetworkRequest request(urlString + QString::number(a));
6828 request.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, QVariant(true));
6829 replies.append(QNetworkReplyPtr(manager.get(request)));
6830 connect(replies.at(a), SIGNAL(finished()), this, SLOT(pipeliningHelperSlot()));
6832 QTestEventLoop::instance().enterLoop(20);
6833 QVERIFY(!QTestEventLoop::instance().timeout());
6836 void tst_QNetworkReply::pipeliningHelperSlot() {
6839 // check that pipelining was used in at least one of the replies
6840 static bool pipeliningWasUsed = false;
6841 QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
6842 bool pipeliningWasUsedInReply = reply->attribute(QNetworkRequest::HttpPipeliningWasUsedAttribute).toBool();
6843 if (pipeliningWasUsedInReply)
6844 pipeliningWasUsed = true;
6846 // check that the contents match (the response to echo.cgi?3 should return 3 etc.)
6847 QString urlQueryString = reply->url().query();
6848 QString content = reply->readAll();
6849 QVERIFY2(urlQueryString == content, "data corruption with pipelining detected");
6853 if (a == 20) { // all replies have finished
6854 QTestEventLoop::instance().exitLoop();
6855 QVERIFY2(pipeliningWasUsed, "pipelining was not used in any of the replies when trying to test pipelining");
6859 void tst_QNetworkReply::closeDuringDownload_data()
6861 QTest::addColumn<QUrl>("url");
6862 QTest::newRow("http") << QUrl("http://" + QtNetworkSettings::serverName() + "/bigfile");
6863 QTest::newRow("ftp") << QUrl("ftp://" + QtNetworkSettings::serverName() + "/qtest/bigfile");
6866 void tst_QNetworkReply::closeDuringDownload()
6869 QNetworkRequest request(url);
6870 QNetworkReply* reply = manager.get(request);
6871 connect(reply, SIGNAL(readyRead()), &QTestEventLoop::instance(), SLOT(exitLoop()));
6872 QTestEventLoop::instance().enterLoop(10);
6873 QVERIFY(!QTestEventLoop::instance().timeout());
6874 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
6876 reply->deleteLater();
6877 QTest::qWait(1000); //cancelling ftp takes some time, this avoids a warning caused by test's cleanup() destroying the connection cache before the abort is finished
6880 void tst_QNetworkReply::ftpAuthentication_data()
6882 QTest::addColumn<QString>("referenceName");
6883 QTest::addColumn<QString>("url");
6884 QTest::addColumn<int>("error");
6886 QTest::newRow("invalidPassword") << (testDataDir + "/rfc3252.txt") << "ftp://ftptest:invalid@" + QtNetworkSettings::serverName() + "/home/qt-test-server/ftp/qtest/rfc3252.txt" << int(QNetworkReply::AuthenticationRequiredError);
6887 QTest::newRow("validPassword") << (testDataDir + "/rfc3252.txt") << "ftp://ftptest:password@" + QtNetworkSettings::serverName() + "/home/qt-test-server/ftp/qtest/rfc3252.txt" << int(QNetworkReply::NoError);
6890 void tst_QNetworkReply::ftpAuthentication()
6892 QFETCH(QString, referenceName);
6893 QFETCH(QString, url);
6896 QFile reference(referenceName);
6897 QVERIFY(reference.open(QIODevice::ReadOnly));
6899 QNetworkRequest request(url);
6900 QNetworkReplyPtr reply;
6901 runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply);
6903 QCOMPARE(reply->url(), request.url());
6904 QCOMPARE(reply->error(), QNetworkReply::NetworkError(error));
6907 #ifdef QT_BUILD_INTERNAL
6908 void tst_QNetworkReply::backgroundRequest_data()
6910 QTest::addColumn<QUrl>("url");
6911 QTest::addColumn<bool>("background");
6912 QTest::addColumn<int>("policy");
6913 QTest::addColumn<QNetworkReply::NetworkError>("error");
6915 QUrl httpurl("http://" + QtNetworkSettings::serverName());
6916 QUrl httpsurl("https://" + QtNetworkSettings::serverName());
6917 QUrl ftpurl("ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt");
6919 QTest::newRow("http, fg, normal") << httpurl << false << (int)QNetworkSession::NoPolicy << QNetworkReply::NoError;
6920 QTest::newRow("http, bg, normal") << httpurl << true << (int)QNetworkSession::NoPolicy << QNetworkReply::NoError;
6921 QTest::newRow("http, fg, nobg") << httpurl << false << (int)QNetworkSession::NoBackgroundTrafficPolicy << QNetworkReply::NoError;
6922 QTest::newRow("http, bg, nobg") << httpurl << true << (int)QNetworkSession::NoBackgroundTrafficPolicy << QNetworkReply::BackgroundRequestNotAllowedError;
6925 QTest::newRow("https, fg, normal") << httpsurl << false << (int)QNetworkSession::NoPolicy << QNetworkReply::NoError;
6926 QTest::newRow("https, bg, normal") << httpsurl << true << (int)QNetworkSession::NoPolicy << QNetworkReply::NoError;
6927 QTest::newRow("https, fg, nobg") << httpsurl << false << (int)QNetworkSession::NoBackgroundTrafficPolicy << QNetworkReply::NoError;
6928 QTest::newRow("https, bg, nobg") << httpsurl << true << (int)QNetworkSession::NoBackgroundTrafficPolicy << QNetworkReply::BackgroundRequestNotAllowedError;
6931 QTest::newRow("ftp, fg, normal") << ftpurl << false << (int)QNetworkSession::NoPolicy << QNetworkReply::NoError;
6932 QTest::newRow("ftp, bg, normal") << ftpurl << true << (int)QNetworkSession::NoPolicy << QNetworkReply::NoError;
6933 QTest::newRow("ftp, fg, nobg") << ftpurl << false << (int)QNetworkSession::NoBackgroundTrafficPolicy << QNetworkReply::NoError;
6934 QTest::newRow("ftp, bg, nobg") << ftpurl << true << (int)QNetworkSession::NoBackgroundTrafficPolicy << QNetworkReply::BackgroundRequestNotAllowedError;
6939 //test purpose: background requests can't be started when not allowed
6940 #ifdef QT_BUILD_INTERNAL
6941 void tst_QNetworkReply::backgroundRequest()
6943 #ifndef QT_NO_BEARERMANAGEMENT
6945 QFETCH(bool, background);
6946 QFETCH(int, policy);
6947 QFETCH(QNetworkReply::NetworkError, error);
6949 QNetworkRequest request(url);
6952 request.setAttribute(QNetworkRequest::BackgroundRequestAttribute, QVariant::fromValue(true));
6954 //this preconstructs the session so we can change policies in advance
6955 manager.setConfiguration(networkConfiguration);
6958 connect(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
6959 SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
6962 const QWeakPointer<const QNetworkSession> session = QNetworkAccessManagerPrivate::getNetworkSession(&manager);
6964 QNetworkSession::UsagePolicies original = session.data()->usagePolicies();
6965 QNetworkSessionPrivate::setUsagePolicies(*const_cast<QNetworkSession *>(session.data()), QNetworkSession::UsagePolicies(policy));
6967 QNetworkReplyPtr reply(manager.get(request));
6969 QVERIFY(waitForFinish(reply) != Timeout);
6971 QNetworkSessionPrivate::setUsagePolicies(*const_cast<QNetworkSession *>(session.data()), original);
6973 QVERIFY(reply->isFinished());
6974 QCOMPARE(reply->error(), error);
6979 #ifdef QT_BUILD_INTERNAL
6980 void tst_QNetworkReply::backgroundRequestInterruption_data()
6982 QTest::addColumn<QUrl>("url");
6983 QTest::addColumn<bool>("background");
6984 QTest::addColumn<QNetworkReply::NetworkError>("error");
6986 QUrl httpurl("http://" + QtNetworkSettings::serverName() + "/qtest/mediumfile");
6987 QUrl httpsurl("https://" + QtNetworkSettings::serverName() + "/qtest/mediumfile");
6988 QUrl ftpurl("ftp://" + QtNetworkSettings::serverName() + "/qtest/bigfile");
6990 QTest::newRow("http, fg, nobg") << httpurl << false << QNetworkReply::NoError;
6991 QTest::newRow("http, bg, nobg") << httpurl << true << QNetworkReply::BackgroundRequestNotAllowedError;
6994 QTest::newRow("https, fg, nobg") << httpsurl << false << QNetworkReply::NoError;
6995 QTest::newRow("https, bg, nobg") << httpsurl << true << QNetworkReply::BackgroundRequestNotAllowedError;
6998 QTest::newRow("ftp, fg, nobg") << ftpurl << false << QNetworkReply::NoError;
6999 QTest::newRow("ftp, bg, nobg") << ftpurl << true << QNetworkReply::BackgroundRequestNotAllowedError;
7004 //test purpose: background requests in progress are aborted when policy changes to disallow them
7005 #ifdef QT_BUILD_INTERNAL
7006 void tst_QNetworkReply::backgroundRequestInterruption()
7008 #ifndef QT_NO_BEARERMANAGEMENT
7010 QFETCH(bool, background);
7011 QFETCH(QNetworkReply::NetworkError, error);
7013 QNetworkRequest request(url);
7016 request.setAttribute(QNetworkRequest::BackgroundRequestAttribute, QVariant::fromValue(true));
7018 //this preconstructs the session so we can change policies in advance
7019 manager.setConfiguration(networkConfiguration);
7022 connect(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
7023 SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
7026 const QWeakPointer<const QNetworkSession> session = QNetworkAccessManagerPrivate::getNetworkSession(&manager);
7028 QNetworkSession::UsagePolicies original = session.data()->usagePolicies();
7029 QNetworkSessionPrivate::setUsagePolicies(*const_cast<QNetworkSession *>(session.data()), QNetworkSession::NoPolicy);
7031 request.setAttribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute, 8192);
7032 QNetworkReplyPtr reply(manager.get(request));
7033 reply->setReadBufferSize(1024);
7035 QSignalSpy spy(reply.data(), SIGNAL(readyRead()));
7036 QTRY_VERIFY(spy.count() > 0);
7038 QNetworkSessionPrivate::setUsagePolicies(*const_cast<QNetworkSession *>(session.data()), QNetworkSession::NoBackgroundTrafficPolicy);
7040 // After we have changed the policy we can download at full speed.
7041 reply->setReadBufferSize(0);
7043 QVERIFY(waitForFinish(reply) != Timeout);
7045 QNetworkSessionPrivate::setUsagePolicies(*const_cast<QNetworkSession *>(session.data()), original);
7047 QVERIFY(reply->isFinished());
7048 QCOMPARE(reply->error(), error);
7053 #ifdef QT_BUILD_INTERNAL
7054 void tst_QNetworkReply::backgroundRequestConnectInBackground_data()
7056 QTest::addColumn<QUrl>("url");
7057 QTest::addColumn<bool>("background");
7059 QUrl httpurl("http://" + QtNetworkSettings::serverName());
7060 QUrl ftpurl("ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt");
7062 QTest::newRow("http, fg") << httpurl << false;
7063 QTest::newRow("http, bg") << httpurl << true;
7065 QTest::newRow("ftp, fg") << ftpurl << false;
7066 QTest::newRow("ftp, bg") << ftpurl << true;
7070 //test purpose: check that backgroundness is propagated to the network session
7071 #ifdef QT_BUILD_INTERNAL
7072 void tst_QNetworkReply::backgroundRequestConnectInBackground()
7074 #ifndef QT_NO_BEARERMANAGEMENT
7076 QFETCH(bool, background);
7078 QNetworkRequest request(url);
7081 request.setAttribute(QNetworkRequest::BackgroundRequestAttribute, QVariant::fromValue(true));
7083 QWeakPointer<const QNetworkSession> session = QNetworkAccessManagerPrivate::getNetworkSession(&manager);
7084 //force QNAM to reopen the session.
7085 if (session && session.data()->isOpen()) {
7086 const_cast<QNetworkSession *>(session.data())->close();
7087 QCoreApplication::processEvents(); //let signals propagate inside QNAM
7090 //this preconstructs the session so we can change policies in advance
7091 manager.setConfiguration(networkConfiguration);
7093 session = QNetworkAccessManagerPrivate::getNetworkSession(&manager);
7095 QNetworkSession::UsagePolicies original = session.data()->usagePolicies();
7096 QNetworkSessionPrivate::setUsagePolicies(*const_cast<QNetworkSession *>(session.data()), QNetworkSession::NoPolicy);
7098 QNetworkReplyPtr reply(manager.get(request));
7100 QVERIFY(waitForFinish(reply) != Timeout);
7101 session = QNetworkAccessManagerPrivate::getNetworkSession(&manager);
7103 QVariant cib = session.data()->sessionProperty(QStringLiteral("ConnectInBackground"));
7105 QSKIP("inconclusive - ConnectInBackground session property not supported by the bearer plugin");
7106 QCOMPARE(cib.toBool(), background);
7107 QNetworkSessionPrivate::setUsagePolicies(*const_cast<QNetworkSession *>(session.data()), original);
7109 QSKIP("inconclusive - network session has been destroyed");
7112 QVERIFY(reply->isFinished());
7117 // NOTE: This test must be last testcase in tst_qnetworkreply!
7118 void tst_QNetworkReply::parentingRepliesToTheApp()
7120 QNetworkRequest request (QUrl("http://" + QtNetworkSettings::serverName()));
7121 manager.get(request)->setParent(this); // parent to this object
7122 manager.get(request)->setParent(qApp); // parent to the app
7125 QTEST_MAIN(tst_QNetworkReply)
7127 #include "tst_qnetworkreply.moc"