1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the test suite of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
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/qnetworkaccessmanager_p.h>
85 # include <sys/types.h>
86 # include <unistd.h> // for getuid()
90 #include "../../../network-settings.h"
92 Q_DECLARE_METATYPE(QSharedPointer<char>)
93 Q_DECLARE_METATYPE(QNetworkReply*)
94 Q_DECLARE_METATYPE(QAuthenticator*)
95 Q_DECLARE_METATYPE(QNetworkProxy)
96 Q_DECLARE_METATYPE(QNetworkProxyQuery)
97 Q_DECLARE_METATYPE(QList<QNetworkProxy>)
98 Q_DECLARE_METATYPE(QNetworkReply::NetworkError)
99 Q_DECLARE_METATYPE(QBuffer*)
100 Q_DECLARE_METATYPE(QHttpMultiPart *)
101 Q_DECLARE_METATYPE(QList<QFile*>) // for multiparts
103 Q_DECLARE_METATYPE(QSslConfiguration)
106 typedef QSharedPointer<QNetworkReply> QNetworkReplyPtr;
109 class tst_QNetworkReply: public QObject
114 ProxyData(const QNetworkProxy &p, const QByteArray &t, bool auth)
115 : tag(t), proxy(p), requiresAuthentication(auth)
119 bool requiresAuthentication;
122 static bool seedCreated;
123 static QString createUniqueExtension() {
125 qsrand(QTime(0,0,0).msecsTo(QTime::currentTime()) + QCoreApplication::applicationPid());
126 seedCreated = true; // not thread-safe, but who cares
128 QString s = QString("%1-%2-%3").arg(QTime(0,0,0).msecsTo(QTime::currentTime())).arg(QCoreApplication::applicationPid()).arg(qrand());
133 enum RunSimpleRequestReturn { Timeout = 0, Success, Failure };
135 QString testFileName;
136 QString echoProcessDir;
137 #if !defined Q_OS_WIN
138 QString wronlyFileName;
140 QString uniqueExtension;
141 QList<ProxyData> proxies;
142 QNetworkAccessManager manager;
143 MyCookieJar *cookieJar;
145 QSslConfiguration storedSslConfiguration;
146 QList<QSslError> storedExpectedSslErrors;
148 #ifndef QT_NO_BEARERMANAGEMENT
149 QNetworkConfigurationManager *netConfMan;
150 QNetworkConfiguration networkConfiguration;
151 QScopedPointer<QNetworkSession> networkSession;
154 using QObject::connect;
155 static bool connect(const QNetworkReplyPtr &ptr, const char *signal, const QObject *receiver, const char *slot, Qt::ConnectionType ct = Qt::AutoConnection)
156 { return connect(ptr.data(), signal, receiver, slot, ct); }
157 bool connect(const QNetworkReplyPtr &ptr, const char *signal, const char *slot, Qt::ConnectionType ct = Qt::AutoConnection)
158 { return connect(ptr.data(), signal, slot, ct); }
162 ~tst_QNetworkReply();
163 QString runSimpleRequest(QNetworkAccessManager::Operation op, const QNetworkRequest &request,
164 QNetworkReplyPtr &reply, const QByteArray &data = QByteArray());
165 QString runMultipartRequest(const QNetworkRequest &request, QNetworkReplyPtr &reply,
166 QHttpMultiPart *multiPart, const QByteArray &verb);
168 QString runCustomRequest(const QNetworkRequest &request, QNetworkReplyPtr &reply,
169 const QByteArray &verb, QIODevice *data);
170 int waitForFinish(QNetworkReplyPtr &reply);
175 void authenticationRequired(QNetworkReply*,QAuthenticator*);
176 void proxyAuthenticationRequired(const QNetworkProxy &,QAuthenticator*);
177 void pipeliningHelperSlot();
180 void sslErrors(QNetworkReply*,const QList<QSslError> &);
181 void storeSslConfiguration();
182 void ignoreSslErrorListSlot(QNetworkReply *reply, const QList<QSslError> &);
186 void nestedEventLoops_slot();
192 void cleanupTestCase();
194 void stateChecking();
195 void invalidProtocol();
196 void getFromData_data();
199 void getFromFileSpecial_data();
200 void getFromFileSpecial();
201 void getFromFtp_data();
203 void getFromHttp_data();
205 void getErrors_data();
207 void headFromHttp_data();
209 void putToFile_data();
211 void putToFtp_data();
213 void putToHttp_data();
215 void putToHttpSynchronous_data();
216 void putToHttpSynchronous();
217 void putToHttpMultipart_data();
218 void putToHttpMultipart();
219 void postToHttp_data();
221 void postToHttpSynchronous_data();
222 void postToHttpSynchronous();
223 void postToHttpMultipart_data();
224 void postToHttpMultipart();
225 void deleteFromHttp_data();
226 void deleteFromHttp();
227 void putGetDeleteGetFromHttp_data();
228 void putGetDeleteGetFromHttp();
229 void sendCustomRequestToHttp_data();
230 void sendCustomRequestToHttp();
231 void connectToIPv6Address_data();
232 void connectToIPv6Address();
234 void ioGetFromData_data();
235 void ioGetFromData();
236 void ioGetFromFileSpecial_data();
237 void ioGetFromFileSpecial();
238 void ioGetFromFile_data();
239 void ioGetFromFile();
240 void ioGetFromFtp_data();
242 void ioGetFromFtpWithReuse();
243 void ioGetFromHttp();
245 void ioGetFromBuiltinHttp_data();
246 void ioGetFromBuiltinHttp();
247 void ioGetFromHttpWithReuseParallel();
248 void ioGetFromHttpWithReuseSequential();
249 void ioGetFromHttpWithAuth_data();
250 void ioGetFromHttpWithAuth();
251 void ioGetFromHttpWithAuthSynchronous();
252 void ioGetFromHttpWithProxyAuth();
253 void ioGetFromHttpWithProxyAuthSynchronous();
254 void ioGetFromHttpWithSocksProxy();
256 void ioGetFromHttpsWithSslErrors();
257 void ioGetFromHttpsWithIgnoreSslErrors();
258 void ioGetFromHttpsWithSslHandshakeError();
260 void ioGetFromHttpBrokenServer_data();
261 void ioGetFromHttpBrokenServer();
262 void ioGetFromHttpStatus100_data();
263 void ioGetFromHttpStatus100();
264 void ioGetFromHttpNoHeaders_data();
265 void ioGetFromHttpNoHeaders();
266 void ioGetFromHttpWithCache_data();
267 void ioGetFromHttpWithCache();
269 void ioGetWithManyProxies_data();
270 void ioGetWithManyProxies();
272 void ioPutToFileFromFile_data();
273 void ioPutToFileFromFile();
274 void ioPutToFileFromSocket_data();
275 void ioPutToFileFromSocket();
276 void ioPutToFileFromLocalSocket_data();
277 void ioPutToFileFromLocalSocket();
278 #ifndef QT_NO_PROCESS
279 void ioPutToFileFromProcess_data();
280 void ioPutToFileFromProcess();
282 void ioPutToFtpFromFile_data();
283 void ioPutToFtpFromFile();
284 void ioPutToHttpFromFile_data();
285 void ioPutToHttpFromFile();
286 void ioPostToHttpFromFile_data();
287 void ioPostToHttpFromFile();
288 void ioPostToHttpFromSocket_data();
289 void ioPostToHttpFromSocket();
290 void ioPostToHttpFromSocketSynchronous();
291 void ioPostToHttpFromSocketSynchronous_data();
292 void ioPostToHttpFromMiddleOfFileToEnd();
293 void ioPostToHttpFromMiddleOfFileFiveBytes();
294 void ioPostToHttpFromMiddleOfQBufferFiveBytes();
295 void ioPostToHttpNoBufferFlag();
296 void ioPostToHttpUploadProgress();
297 void ioPostToHttpEmptyUploadProgress();
299 void lastModifiedHeaderForFile();
300 void lastModifiedHeaderForHttp();
302 void httpCanReadLine();
304 void rateControl_data();
307 void downloadProgress_data();
308 void downloadProgress();
309 void uploadProgress_data();
310 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 synchronousRequest_data();
384 void synchronousRequest();
386 void synchronousRequestSslFailure();
391 void dontInsertPartialContentIntoTheCache();
393 void httpUserAgent();
394 void authenticationCacheAfterCancel_data();
395 void authenticationCacheAfterCancel();
396 void authenticationWithDifferentRealm();
397 void synchronousAuthenticationCache();
400 void closeDuringDownload_data();
401 void closeDuringDownload();
403 void ftpAuthentication_data();
404 void ftpAuthentication();
406 void backgroundRequest_data();
407 void backgroundRequest();
408 void backgroundRequestInterruption_data();
409 void backgroundRequestInterruption();
410 void backgroundRequestConnectInBackground_data();
411 void backgroundRequestConnectInBackground();
413 // NOTE: This test must be last!
414 void parentingRepliesToTheApp();
419 bool tst_QNetworkReply::seedCreated = false;
425 char *toString(const QNetworkReply::NetworkError& code)
427 const QMetaObject *mo = &QNetworkReply::staticMetaObject;
428 int index = mo->indexOfEnumerator("NetworkError");
432 QMetaEnum qme = mo->enumerator(index);
433 return qstrdup(qme.valueToKey(code));
437 char *toString(const QNetworkCookie &cookie)
439 return qstrdup(cookie.toRawForm());
443 char *toString(const QList<QNetworkCookie> &list)
445 QString result = "QList(";
447 foreach (QNetworkCookie cookie, list) {
451 result += QString::fromLatin1("QNetworkCookie(%1)").arg(QLatin1String(cookie.toRawForm()));
454 return qstrdup(result.append(')').toLocal8Bit());
460 #define RUN_REQUEST(call) \
462 QString errorMsg = call; \
463 if (!errorMsg.isEmpty()) \
464 QFAIL(qPrintable(errorMsg)); \
468 static void setupSslServer(QSslSocket* serverSocket)
470 QString testDataDir = QFileInfo(QFINDTESTDATA("rfc3252.txt")).absolutePath();
471 if (testDataDir.isEmpty())
472 testDataDir = QCoreApplication::applicationDirPath();
474 serverSocket->setProtocol(QSsl::AnyProtocol);
475 serverSocket->setLocalCertificate(testDataDir + "/certs/server.pem");
476 serverSocket->setPrivateKey(testDataDir + "/certs/server.key");
480 // Does not work for POST/PUT!
481 class MiniHttpServer: public QTcpServer
485 QTcpSocket *client; // always the last one that was received
486 QByteArray dataToTransmit;
487 QByteArray receivedData;
493 int totalConnections;
495 MiniHttpServer(const QByteArray &data, bool ssl = false, QThread *thread = 0, bool useipv6 = false)
496 : client(0), dataToTransmit(data), doClose(true), doSsl(ssl), ipv6(useipv6),
497 multiple(false), totalConnections(0)
500 listen(QHostAddress::AnyIPv6);
502 listen(QHostAddress::AnyIPv4);
505 connect(thread, SIGNAL(started()), this, SLOT(threadStartedSlot()));
506 moveToThread(thread);
513 void incomingConnection(qintptr socketDescriptor)
515 //qDebug() << "incomingConnection" << socketDescriptor << "doSsl:" << doSsl << "ipv6:" << ipv6;
517 client = new QTcpSocket;
518 client->setSocketDescriptor(socketDescriptor);
519 connectSocketSignals();
522 QSslSocket *serverSocket = new QSslSocket;
523 serverSocket->setParent(this);
524 if (serverSocket->setSocketDescriptor(socketDescriptor)) {
525 connect(serverSocket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(slotSslErrors(QList<QSslError>)));
526 setupSslServer(serverSocket);
527 serverSocket->startServerEncryption();
528 client = serverSocket;
529 connectSocketSignals();
536 client->setParent(this);
540 virtual void reply() {
541 // we need to emulate the bytesWrittenSlot call if the data is empty.
542 if (dataToTransmit.size() == 0)
543 QMetaObject::invokeMethod(this, "bytesWrittenSlot", Qt::QueuedConnection);
545 client->write(dataToTransmit);
548 void connectSocketSignals()
550 //qDebug() << "connectSocketSignals" << client;
551 connect(client, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
552 connect(client, SIGNAL(bytesWritten(qint64)), this, SLOT(bytesWrittenSlot()));
553 connect(client, SIGNAL(error(QAbstractSocket::SocketError)),
554 this, SLOT(slotError(QAbstractSocket::SocketError)));
559 void slotSslErrors(const QList<QSslError>& errors)
561 qDebug() << "slotSslErrors" << client->errorString() << errors;
564 void slotError(QAbstractSocket::SocketError err)
566 qDebug() << "slotError" << err << client->errorString();
572 receivedData += client->readAll();
573 int doubleEndlPos = receivedData.indexOf("\r\n\r\n");
575 if (doubleEndlPos != -1) {
576 // multiple requests incoming. remove the bytes of the current one
578 receivedData.remove(0, doubleEndlPos+4);
584 void bytesWrittenSlot() {
585 if (doClose && client->bytesToWrite() == 0) {
586 client->disconnectFromHost();
587 disconnect(client, 0, this, 0);
591 void threadStartedSlot()
597 class MyCookieJar: public QNetworkCookieJar
600 inline QList<QNetworkCookie> allCookies() const
601 { return QNetworkCookieJar::allCookies(); }
602 inline void setAllCookies(const QList<QNetworkCookie> &cookieList)
603 { QNetworkCookieJar::setAllCookies(cookieList); }
606 class MyProxyFactory: public QNetworkProxyFactory
610 QList<QNetworkProxy> toReturn;
611 QNetworkProxyQuery lastQuery;
612 inline MyProxyFactory() { clear(); }
617 toReturn = QList<QNetworkProxy>() << QNetworkProxy::DefaultProxy;
618 lastQuery = QNetworkProxyQuery();
621 virtual QList<QNetworkProxy> queryProxy(const QNetworkProxyQuery &query)
629 class MyMemoryCache: public QAbstractNetworkCache
632 typedef QPair<QNetworkCacheMetaData, QByteArray> CachedContent;
633 typedef QHash<QByteArray, CachedContent> CacheData;
636 MyMemoryCache(QObject *parent) : QAbstractNetworkCache(parent) {}
638 QNetworkCacheMetaData metaData(const QUrl &url)
640 return cache.value(url.toEncoded()).first;
643 void updateMetaData(const QNetworkCacheMetaData &metaData)
645 cache[metaData.url().toEncoded()].first = metaData;
648 QIODevice *data(const QUrl &url)
650 CacheData::ConstIterator it = cache.find(url.toEncoded());
651 if (it == cache.constEnd())
653 QBuffer *io = new QBuffer(this);
654 io->setData(it->second);
655 io->open(QIODevice::ReadOnly);
660 bool remove(const QUrl &url)
662 cache.remove(url.toEncoded());
666 qint64 cacheSize() const
669 foreach (const CachedContent &entry, cache)
670 total += entry.second.size();
674 QIODevice *prepare(const QNetworkCacheMetaData &)
676 qFatal("%s: Should not have tried to add to the cache", Q_FUNC_INFO);
679 void insert(QIODevice *)
681 qFatal("%s: Should not have tried to add to the cache", Q_FUNC_INFO);
684 void clear() { cache.clear(); }
686 Q_DECLARE_METATYPE(MyMemoryCache::CachedContent)
687 Q_DECLARE_METATYPE(MyMemoryCache::CacheData)
689 class MySpyMemoryCache: public QAbstractNetworkCache
692 MySpyMemoryCache(QObject *parent) : QAbstractNetworkCache(parent) {}
695 qDeleteAll(m_buffers);
699 QHash<QUrl, QIODevice*> m_buffers;
700 QList<QUrl> m_insertedUrls;
702 QNetworkCacheMetaData metaData(const QUrl &)
704 return QNetworkCacheMetaData();
707 void updateMetaData(const QNetworkCacheMetaData &)
711 QIODevice *data(const QUrl &)
716 bool remove(const QUrl &url)
718 delete m_buffers.take(url);
719 return m_insertedUrls.removeAll(url) > 0;
722 qint64 cacheSize() const
727 QIODevice *prepare(const QNetworkCacheMetaData &metaData)
729 QBuffer* buffer = new QBuffer;
730 buffer->open(QIODevice::ReadWrite);
731 buffer->setProperty("url", metaData.url());
732 m_buffers.insert(metaData.url(), buffer);
736 void insert(QIODevice *buffer)
738 QUrl url = buffer->property("url").toUrl();
739 m_insertedUrls << url;
740 delete m_buffers.take(url);
743 void clear() { m_insertedUrls.clear(); }
746 class DataReader: public QObject
754 DataReader(const QNetworkReplyPtr &dev, bool acc = true) : totalBytes(0), device(dev.data()), accumulate(acc)
755 { connect(device, SIGNAL(readyRead()), SLOT(doRead()) ); }
756 DataReader(QIODevice *dev, bool acc = true) : totalBytes(0), device(dev), accumulate(acc)
758 connect(device, SIGNAL(readyRead()), SLOT(doRead()));
765 buffer.resize(device->bytesAvailable());
766 qint64 bytesRead = device->read(buffer.data(), device->bytesAvailable());
767 if (bytesRead == -1) {
768 QTestEventLoop::instance().exitLoop();
771 buffer.truncate(bytesRead);
772 totalBytes += bytesRead;
780 class SocketPair: public QObject
784 QIODevice *endPoints[2];
786 SocketPair(QObject *parent = 0)
789 endPoints[0] = endPoints[1] = 0;
797 QTcpSocket *active = new QTcpSocket(this);
798 active->connectToHost("127.0.0.1", server.serverPort());
800 // need more time as working with embedded
801 // device and testing from emualtor
802 // things tend to get slower
803 if (!active->waitForConnected(1000))
806 if (!server.waitForNewConnection(1000))
809 QTcpSocket *passive = server.nextPendingConnection();
810 passive->setParent(this);
812 endPoints[0] = active;
813 endPoints[1] = passive;
818 // A blocking tcp server (must be used in a thread) which supports SSL.
819 class BlockingTcpServer : public QTcpServer
823 BlockingTcpServer(bool ssl) : doSsl(ssl), sslSocket(0) {}
825 QTcpSocket* waitForNextConnectionSocket() {
826 waitForNewConnection(-1);
829 qFatal("%s: sslSocket should not be null after calling waitForNewConnection()",
833 //qDebug() << "returning nextPendingConnection";
834 return nextPendingConnection();
837 virtual void incomingConnection(qintptr socketDescriptor)
841 QSslSocket *serverSocket = new QSslSocket;
842 serverSocket->setParent(this);
843 serverSocket->setSocketDescriptor(socketDescriptor);
844 connect(serverSocket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(slotSslErrors(QList<QSslError>)));
845 setupSslServer(serverSocket);
846 serverSocket->startServerEncryption();
847 sslSocket = serverSocket;
851 QTcpServer::incomingConnection(socketDescriptor);
857 void slotSslErrors(const QList<QSslError>& errors)
859 qDebug() << "slotSslErrors" << sslSocket->errorString() << errors;
865 QTcpSocket* sslSocket;
868 // This server tries to send data as fast as possible (like most servers)
869 // but it measures how fast it was able to send it, which shows at which
870 // rate the reader is processing the data.
871 class FastSender: public QThread
877 enum Protocol { DebugPipe, ProvidedData };
878 const Protocol protocol;
880 const bool fillKernelBuffer;
885 QByteArray dataToTransmit;
888 // a server that sends debugpipe data
889 FastSender(qint64 size)
890 : wantedSize(size), port(-1), protocol(DebugPipe),
891 doSsl(false), fillKernelBuffer(true), transferRate(-1),
898 // a server that sends the data provided at construction time, useful for HTTP
899 FastSender(const QByteArray& data, bool https, bool fillBuffer)
900 : wantedSize(data.size()), port(-1), protocol(ProvidedData),
901 doSsl(https), fillKernelBuffer(fillBuffer), transferRate(-1),
902 dataToTransmit(data), dataIndex(0)
908 inline int serverPort() const { return port; }
910 int writeNextData(QTcpSocket* socket, qint32 size)
912 if (protocol == DebugPipe) {
914 QDataStream stream(&data, QIODevice::WriteOnly);
915 stream << QVariantMap() << QByteArray(size, 'a');
916 socket->write((char*)&size, sizeof size);
921 const QByteArray data = dataToTransmit.mid(dataIndex, size);
923 dataIndex += data.size();
924 //qDebug() << "wrote" << dataIndex << "/" << dataToTransmit.size();
928 void writeLastData(QTcpSocket* socket)
930 if (protocol == DebugPipe) {
932 QDataStream stream(&data, QIODevice::WriteOnly);
933 stream << QVariantMap() << QByteArray();
934 const qint32 size = data.size();
935 socket->write((char*)&size, sizeof size);
943 BlockingTcpServer server(doSsl);
945 port = server.serverPort();
948 QTcpSocket *client = server.waitForNextConnectionSocket();
950 // get the "request" packet
951 if (!client->waitForReadyRead(2000)) {
952 qDebug() << "FastSender:" << client->error() << "waiting for \"request\" packet";
955 client->readAll(); // we're not interested in the actual contents (e.g. HTTP request)
957 enum { BlockSize = 1024 };
959 if (fillKernelBuffer) {
961 // write a bunch of bytes to fill up the buffers
964 if (writeNextData(client, BlockSize) < BlockSize) {
965 qDebug() << "ERROR: FastSender: not enough data to write in order to fill buffers; or client is reading too fast";
968 while (client->bytesToWrite() > 0) {
969 if (!client->waitForBytesWritten(0)) {
974 //qDebug() << "Filling kernel buffer: wrote" << dataIndex << "bytes";
977 qDebug() << "FastSender: ok, kernel buffer is full after writing" << dataIndex << "bytes";
980 // Tell the client to start reading
983 // the kernel buffer is full
984 // clean up QAbstractSocket's residue:
985 while (client->bytesToWrite() > 0) {
986 qDebug() << "Still having" << client->bytesToWrite() << "bytes to write, doing that now";
987 if (!client->waitForBytesWritten(2000)) {
988 qDebug() << "ERROR: FastSender:" << client->error() << "cleaning up residue";
993 // now write in "blocking mode", this is where the rate measuring starts
996 //const qint64 writtenBefore = dataIndex;
997 //qint64 measuredTotalBytes = wantedSize - writtenBefore;
998 qint64 measuredSentBytes = 0;
999 while (dataIndex < wantedSize) {
1000 const int remainingBytes = wantedSize - measuredSentBytes;
1001 const int bytesToWrite = qMin(remainingBytes, static_cast<int>(BlockSize));
1002 if (bytesToWrite <= 0)
1003 qFatal("%s: attempt to write %d bytes", Q_FUNC_INFO, bytesToWrite);
1004 measuredSentBytes += writeNextData(client, bytesToWrite);
1006 while (client->bytesToWrite() > 0) {
1007 if (!client->waitForBytesWritten(2000)) {
1008 qDebug() << "ERROR: FastSender:" << client->error() << "during blocking write";
1012 /*qDebug() << "FastSender:" << bytesToWrite << "bytes written now;"
1013 << measuredSentBytes << "measured bytes" << measuredSentBytes + writtenBefore << "total ("
1014 << measuredSentBytes*100/measuredTotalBytes << "% complete);"
1015 << timer.elapsed() << "ms elapsed";*/
1018 transferRate = measuredSentBytes * 1000 / timer.elapsed();
1019 qDebug() << "FastSender: flushed" << measuredSentBytes << "bytes in" << timer.elapsed() << "ms: rate =" << transferRate << "B/s";
1021 // write a "close connection" packet, if the protocol needs it
1022 writeLastData(client);
1028 class RateControlledReader: public QObject
1037 qint64 totalBytesRead;
1038 RateControlledReader(QObject& senderObj, QIODevice *dev, int kbPerSec, int maxBufferSize = 0)
1039 : device(dev), readBufferSize(maxBufferSize), totalBytesRead(0)
1041 // determine how often we have to wake up
1043 if (readBufferSize == 0) {
1044 // The requirement is simply "N KB per seconds"
1045 timesPerSecond = 20;
1046 bytesToRead = kbPerSec * 1024 / timesPerSecond;
1048 // The requirement also includes "<readBufferSize> bytes at a time"
1049 bytesToRead = readBufferSize;
1050 timesPerSecond = kbPerSec * 1024 / readBufferSize;
1052 interval = 1000 / timesPerSecond; // in ms
1054 qDebug() << "RateControlledReader: going to read" << bytesToRead
1055 << "bytes every" << interval << "ms";
1056 qDebug() << "actual read rate will be"
1057 << (bytesToRead * 1000 / interval) << "bytes/sec (wanted"
1058 << kbPerSec * 1024 << "bytes/sec)";
1060 // Wait for data to be readyRead
1061 bool ok = connect(&senderObj, SIGNAL(dataReady()), this, SLOT(slotDataReady()));
1063 qFatal("%s: Cannot connect dataReady signal", Q_FUNC_INFO);
1068 QByteArray someData = device->read(device->bytesAvailable());
1070 totalBytesRead += someData.size();
1071 qDebug() << "wrapUp: found" << someData.size() << "bytes left. progress" << data.size();
1072 //qDebug() << "wrapUp: now bytesAvailable=" << device->bytesAvailable();
1076 void slotDataReady()
1078 //qDebug() << "RateControlledReader: ready to go";
1079 startTimer(interval);
1083 void timerEvent(QTimerEvent *)
1085 //qDebug() << "RateControlledReader: timerEvent bytesAvailable=" << device->bytesAvailable();
1086 if (readBufferSize > 0 && device->bytesAvailable() > readBufferSize) {
1087 // This passes all the time, except in the final flush.
1088 //qFatal("%s: Too many bytes available", Q_FUNC_INFO);
1091 qint64 bytesRead = 0;
1095 if (device->bytesAvailable() == 0) {
1096 if (stopWatch.elapsed() > 20) {
1097 qDebug() << "RateControlledReader: Not enough data available for reading, waited too much, timing out";
1100 if (!device->waitForReadyRead(5)) {
1101 qDebug() << "RateControlledReader: Not enough data available for reading, even after waiting 5ms, bailing out";
1105 QByteArray someData = device->read(bytesToRead - bytesRead);
1107 bytesRead += someData.size();
1108 //qDebug() << "RateControlledReader: successfully read" << someData.size() << "progress:" << data.size();
1109 } while (bytesRead < bytesToRead);
1110 totalBytesRead += bytesRead;
1112 if (bytesRead < bytesToRead)
1113 qWarning() << "RateControlledReader: WARNING:" << bytesToRead - bytesRead << "bytes not read";
1118 tst_QNetworkReply::tst_QNetworkReply()
1120 qRegisterMetaType<QNetworkReply *>(); // for QSignalSpy
1121 qRegisterMetaType<QAuthenticator *>();
1122 qRegisterMetaType<QNetworkProxy>();
1124 qRegisterMetaType<QList<QSslError> >();
1126 qRegisterMetaType<QNetworkReply::NetworkError>();
1128 uniqueExtension = createUniqueExtension();
1129 testFileName = QDir::currentPath() + "/testfile" + uniqueExtension;
1130 cookieJar = new MyCookieJar;
1131 manager.setCookieJar(cookieJar);
1133 QHostInfo hostInfo = QHostInfo::fromName(QtNetworkSettings::serverName());
1135 proxies << ProxyData(QNetworkProxy::NoProxy, "", false);
1137 if (hostInfo.error() == QHostInfo::NoError && !hostInfo.addresses().isEmpty()) {
1138 QString proxyserver = hostInfo.addresses().first().toString();
1139 proxies << ProxyData(QNetworkProxy(QNetworkProxy::HttpProxy, proxyserver, 3128), "+proxy", false)
1140 << ProxyData(QNetworkProxy(QNetworkProxy::HttpProxy, proxyserver, 3129), "+proxyauth", true)
1141 // currently unsupported
1142 // << ProxyData(QNetworkProxy(QNetworkProxy::HttpProxy, proxyserver, 3130), "+proxyauth-ntlm", true);
1143 << ProxyData(QNetworkProxy(QNetworkProxy::Socks5Proxy, proxyserver, 1080), "+socks", false)
1144 << ProxyData(QNetworkProxy(QNetworkProxy::Socks5Proxy, proxyserver, 1081), "+socksauth", true);
1146 printf("==================================================================\n");
1147 printf("Proxy could not be looked up. No proxy will be used while testing!\n");
1148 printf("==================================================================\n");
1152 tst_QNetworkReply::~tst_QNetworkReply()
1157 void tst_QNetworkReply::authenticationRequired(QNetworkReply*, QAuthenticator* auth)
1159 auth->setUser("httptest");
1160 auth->setPassword("httptest");
1163 void tst_QNetworkReply::proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator* auth)
1165 auth->setUser("qsockstest");
1166 auth->setPassword("password");
1170 void tst_QNetworkReply::sslErrors(QNetworkReply *reply, const QList<QSslError> &errors)
1172 reply->ignoreSslErrors();
1173 QVERIFY(!errors.isEmpty());
1174 QVERIFY(!reply->sslConfiguration().isNull());
1177 void tst_QNetworkReply::storeSslConfiguration()
1179 storedSslConfiguration = QSslConfiguration();
1180 QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
1182 storedSslConfiguration = reply->sslConfiguration();
1186 QString tst_QNetworkReply::runMultipartRequest(const QNetworkRequest &request,
1187 QNetworkReplyPtr &reply,
1188 QHttpMultiPart *multiPart,
1189 const QByteArray &verb)
1192 reply.reset(manager.post(request, multiPart));
1194 reply.reset(manager.put(request, multiPart));
1196 // the code below is copied from tst_QNetworkReply::runSimpleRequest, see below
1197 reply->setParent(this);
1198 connect(reply, SIGNAL(finished()), SLOT(finished()));
1199 connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(gotError()));
1200 multiPart->setParent(reply.data());
1202 returnCode = Timeout;
1203 loop = new QEventLoop;
1204 QTimer::singleShot(25000, loop, SLOT(quit()));
1205 int code = returnCode == Timeout ? loop->exec() : returnCode;
1211 return "Request failed: " + reply->errorString();
1213 return "Network timeout";
1218 QString tst_QNetworkReply::runSimpleRequest(QNetworkAccessManager::Operation op,
1219 const QNetworkRequest &request,
1220 QNetworkReplyPtr &reply,
1221 const QByteArray &data)
1224 case QNetworkAccessManager::HeadOperation:
1225 reply.reset(manager.head(request));
1228 case QNetworkAccessManager::GetOperation:
1229 reply.reset(manager.get(request));
1232 case QNetworkAccessManager::PutOperation:
1233 reply.reset(manager.put(request, data));
1236 case QNetworkAccessManager::PostOperation:
1237 reply.reset(manager.post(request, data));
1240 case QNetworkAccessManager::DeleteOperation:
1241 reply.reset(manager.deleteResource(request));
1245 qFatal("%s: Invalid/unknown operation requested", Q_FUNC_INFO);
1247 reply->setParent(this);
1249 returnCode = Timeout;
1252 if (request.attribute(QNetworkRequest::SynchronousRequestAttribute).toBool()) {
1253 if (reply->isFinished())
1254 code = reply->error() != QNetworkReply::NoError ? Failure : Success;
1258 connect(reply, SIGNAL(finished()), SLOT(finished()));
1259 connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(gotError()));
1262 loop = new QEventLoop;
1263 QSignalSpy spy(reply.data(), SIGNAL(downloadProgress(qint64,qint64)));
1264 while (!reply->isFinished()) {
1265 QTimer::singleShot(20000, loop, SLOT(quit()));
1266 code = loop->exec();
1267 if (count == spy.count() && !reply->isFinished()) {
1271 count = spy.count();
1279 return "Request failed: " + reply->errorString();
1281 return "Network timeout";
1286 QString tst_QNetworkReply::runCustomRequest(const QNetworkRequest &request,
1287 QNetworkReplyPtr &reply,
1288 const QByteArray &verb,
1291 reply.reset(manager.sendCustomRequest(request, verb, data));
1292 reply->setParent(this);
1293 connect(reply, SIGNAL(finished()), SLOT(finished()));
1294 connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(gotError()));
1296 returnCode = Timeout;
1297 loop = new QEventLoop;
1298 QTimer::singleShot(20000, loop, SLOT(quit()));
1299 int code = returnCode == Timeout ? loop->exec() : returnCode;
1305 return "Request failed: " + reply->errorString();
1307 return "Network timeout";
1312 int tst_QNetworkReply::waitForFinish(QNetworkReplyPtr &reply)
1316 connect(reply, SIGNAL(finished()), SLOT(finished()));
1317 connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(gotError()));
1318 returnCode = Success;
1319 loop = new QEventLoop;
1320 QSignalSpy spy(reply.data(), SIGNAL(downloadProgress(qint64,qint64)));
1321 while (!reply->isFinished()) {
1322 QTimer::singleShot(5000, loop, SLOT(quit()));
1323 if ( loop->exec() == Timeout && count == spy.count() && !reply->isFinished()) {
1324 returnCode = Timeout;
1327 count = spy.count();
1335 void tst_QNetworkReply::finished()
1337 loop->exit(returnCode = Success);
1340 void tst_QNetworkReply::gotError()
1342 loop->exit(returnCode = Failure);
1343 disconnect(QObject::sender(), SIGNAL(finished()), this, 0);
1346 void tst_QNetworkReply::initTestCase()
1348 testDataDir = QFileInfo(QFINDTESTDATA("rfc3252.txt")).absolutePath();
1349 if (testDataDir.isEmpty())
1350 testDataDir = QCoreApplication::applicationDirPath();
1352 QVERIFY(QtNetworkSettings::verifyTestNetworkSettings());
1353 #if !defined Q_OS_WIN
1354 wronlyFileName = testDataDir + "/write-only" + uniqueExtension;
1355 QFile wr(wronlyFileName);
1356 QVERIFY(wr.open(QIODevice::WriteOnly | QIODevice::Truncate));
1357 wr.setPermissions(QFile::WriteOwner | QFile::WriteUser);
1361 QDir::setSearchPaths("testdata", QStringList() << testDataDir);
1363 QSslSocket::defaultCaCertificates(); //preload certificates
1365 #ifndef QT_NO_BEARERMANAGEMENT
1366 netConfMan = new QNetworkConfigurationManager(this);
1367 networkConfiguration = netConfMan->defaultConfiguration();
1368 networkSession.reset(new QNetworkSession(networkConfiguration));
1369 if (!networkSession->isOpen()) {
1370 networkSession->open();
1371 QVERIFY(networkSession->waitForOpened(30000));
1375 echoProcessDir = QFINDTESTDATA("echo");
1376 QVERIFY2(!echoProcessDir.isEmpty(), qPrintable(
1377 QString::fromLatin1("Couldn't find echo dir starting from %1.").arg(QDir::currentPath())));
1380 void tst_QNetworkReply::cleanupTestCase()
1382 #if !defined Q_OS_WIN
1383 QFile::remove(wronlyFileName);
1385 #ifndef QT_NO_BEARERMANAGEMENT
1386 if (networkSession && networkSession->isOpen()) {
1387 networkSession->close();
1392 void tst_QNetworkReply::init()
1397 void tst_QNetworkReply::cleanup()
1399 QFile file(testFileName);
1400 QVERIFY(!file.exists() || file.remove());
1402 // clear the internal cache
1403 manager.clearAccessCache();
1404 manager.setProxy(QNetworkProxy());
1405 manager.setCache(0);
1408 cookieJar->setAllCookies(QList<QNetworkCookie>());
1410 // disconnect manager signals
1411 manager.disconnect(SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)));
1412 manager.disconnect(SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
1413 manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
1416 void tst_QNetworkReply::stateChecking()
1418 QUrl url = QUrl("file:///");
1419 QNetworkRequest req(url); // you can't open this file, I know
1420 QNetworkReplyPtr reply(manager.get(req));
1422 QVERIFY(reply.data());
1423 QVERIFY(reply->isOpen());
1424 QVERIFY(reply->isReadable());
1425 QVERIFY(!reply->isWritable());
1427 // both behaviours are OK since we might change underlying behaviour again
1428 if (!reply->isFinished())
1429 QCOMPARE(reply->errorString(), QString("Unknown error"));
1431 QVERIFY(!reply->errorString().isEmpty());
1434 QCOMPARE(reply->manager(), &manager);
1435 QCOMPARE(reply->request(), req);
1436 QCOMPARE(int(reply->operation()), int(QNetworkAccessManager::GetOperation));
1437 // error and not error are OK since we might change underlying behaviour again
1438 if (!reply->isFinished())
1439 QCOMPARE(reply->error(), QNetworkReply::NoError);
1440 QCOMPARE(reply->url(), url);
1445 void tst_QNetworkReply::invalidProtocol()
1447 QUrl url = QUrl::fromEncoded("not-a-known-protocol://foo/bar");
1448 QNetworkRequest req(url);
1449 QNetworkReplyPtr reply;
1451 QString errorMsg = "Request failed: Protocol \"not-a-known-protocol\" is unknown";
1452 QString result = runSimpleRequest(QNetworkAccessManager::GetOperation, req, reply);
1453 QCOMPARE(result, errorMsg);
1455 QCOMPARE(reply->url(), url);
1456 QCOMPARE(reply->error(), QNetworkReply::ProtocolUnknownError);
1459 void tst_QNetworkReply::getFromData_data()
1461 QTest::addColumn<QString>("request");
1462 QTest::addColumn<QByteArray>("expected");
1463 QTest::addColumn<QString>("mimeType");
1465 const QString defaultMimeType("text/plain;charset=US-ASCII");
1467 //QTest::newRow("empty") << "data:" << QByteArray() << defaultMimeType;
1468 QTest::newRow("empty2") << "data:," << QByteArray() << defaultMimeType;
1469 QTest::newRow("just-charset_1") << "data:charset=iso-8859-1,"
1470 << QByteArray() << "text/plain;charset=iso-8859-1";
1471 QTest::newRow("just-charset_2") << "data:charset = iso-8859-1 ,"
1472 << QByteArray() << "text/plain;charset = iso-8859-1";
1473 //QTest::newRow("just-media") << "data:text/xml" << QByteArray() << "text/xml";
1474 QTest::newRow("just-media2") << "data:text/xml," << QByteArray() << "text/xml";
1476 QTest::newRow("plain_1") << "data:,foo" << QByteArray("foo") << defaultMimeType;
1477 QTest::newRow("plain_2") << "data:text/html,Hello World" << QByteArray("Hello World")
1479 QTest::newRow("plain_3") << "data:text/html;charset=utf-8,Hello World"
1480 << QByteArray("Hello World") << "text/html;charset=utf-8";
1482 QTest::newRow("pct_1") << "data:,%3Cbody%20contentEditable%3Dtrue%3E%0D%0A"
1483 << QByteArray("<body contentEditable=true>\r\n") << defaultMimeType;
1484 QTest::newRow("pct_2") << "data:text/html;charset=utf-8,%3Cbody%20contentEditable%3Dtrue%3E%0D%0A"
1485 << QByteArray("<body contentEditable=true>\r\n")
1486 << "text/html;charset=utf-8";
1488 QTest::newRow("base64-empty_1") << "data:;base64," << QByteArray() << defaultMimeType;
1489 QTest::newRow("base64-empty_2") << "data:charset=utf-8;base64," << QByteArray()
1490 << "text/plain;charset=utf-8";
1491 QTest::newRow("base64-empty_3") << "data:text/html;charset=utf-8;base64,"
1492 << QByteArray() << "text/html;charset=utf-8";
1494 QTest::newRow("base64_1") << "data:;base64,UXQgaXMgZ3JlYXQh" << QByteArray("Qt is great!")
1496 QTest::newRow("base64_2") << "data:charset=utf-8;base64,UXQgaXMgZ3JlYXQh"
1497 << QByteArray("Qt is great!") << "text/plain;charset=utf-8";
1498 QTest::newRow("base64_3") << "data:text/html;charset=utf-8;base64,UXQgaXMgZ3JlYXQh"
1499 << QByteArray("Qt is great!") << "text/html;charset=utf-8";
1501 QTest::newRow("pct-nul") << "data:,a%00g" << QByteArray("a\0g", 3) << defaultMimeType;
1502 QTest::newRow("base64-nul") << "data:;base64,YQBn" << QByteArray("a\0g", 3) << defaultMimeType;
1503 QTest::newRow("pct-nonutf8") << "data:,a%E1g" << QByteArray("a\xE1g", 3) << defaultMimeType;
1505 QTest::newRow("base64")
1506 << QString::fromLatin1("data:application/xml;base64,PGUvPg==")
1507 << QByteArray("<e/>")
1508 << "application/xml";
1510 QTest::newRow("base64, no media type")
1511 << QString::fromLatin1("data:;base64,PGUvPg==")
1512 << QByteArray("<e/>")
1515 QTest::newRow("Percent encoding")
1516 << QString::fromLatin1("data:application/xml,%3Ce%2F%3E")
1517 << QByteArray("<e/>")
1518 << "application/xml";
1520 QTest::newRow("Percent encoding, no media type")
1521 << QString::fromLatin1("data:,%3Ce%2F%3E")
1522 << QByteArray("<e/>")
1525 QTest::newRow("querychars")
1526 << QString::fromLatin1("data:,foo?x=0&y=0")
1527 << QByteArray("foo?x=0&y=0")
1530 QTest::newRow("css") << "data:text/css,div%20{%20border-right:%20solid;%20}"
1531 << QByteArray("div { border-right: solid; }")
1535 void tst_QNetworkReply::getFromData()
1537 QFETCH(QString, request);
1538 QFETCH(QByteArray, expected);
1539 QFETCH(QString, mimeType);
1541 QUrl url = QUrl::fromEncoded(request.toLatin1());
1542 QNetworkRequest req(url);
1543 QNetworkReplyPtr reply;
1545 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, req, reply));
1547 QCOMPARE(reply->url(), url);
1548 QCOMPARE(reply->error(), QNetworkReply::NoError);
1550 QCOMPARE(reply->header(QNetworkRequest::ContentTypeHeader).toString(), mimeType);
1551 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), qint64(expected.size()));
1552 QCOMPARE(reply->readAll(), expected);
1555 void tst_QNetworkReply::getFromFile()
1558 QTemporaryFile file(QDir::currentPath() + "/temp-XXXXXX");
1559 file.setAutoRemove(true);
1560 QVERIFY(file.open());
1562 QNetworkRequest request(QUrl::fromLocalFile(file.fileName()));
1563 QNetworkReplyPtr reply;
1565 static const char fileData[] = "This is some data that is in the file.\r\n";
1566 QByteArray data = QByteArray::fromRawData(fileData, sizeof fileData - 1);
1567 QVERIFY(file.write(data) == data.size());
1569 QCOMPARE(file.size(), qint64(data.size()));
1571 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
1573 QCOMPARE(reply->url(), request.url());
1574 QCOMPARE(reply->error(), QNetworkReply::NoError);
1576 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), file.size());
1577 QCOMPARE(reply->readAll(), data);
1579 // make the file bigger
1581 const int multiply = (128 * 1024) / (sizeof fileData - 1);
1582 for (int i = 0; i < multiply; ++i)
1583 file.write(fileData, sizeof fileData - 1);
1589 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
1590 QCOMPARE(reply->url(), request.url());
1591 QCOMPARE(reply->error(), QNetworkReply::NoError);
1593 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), file.size());
1594 QCOMPARE(qint64(reply->readAll().size()), file.size());
1597 void tst_QNetworkReply::getFromFileSpecial_data()
1599 QTest::addColumn<QString>("fileName");
1600 QTest::addColumn<QString>("url");
1602 QTest::newRow("resource") << ":/resource" << "qrc:/resource";
1603 QTest::newRow("search-path") << "testdata:/rfc3252.txt" << "testdata:/rfc3252.txt";
1604 QTest::newRow("bigfile-path") << "testdata:/bigfile" << "testdata:/bigfile";
1606 QTest::newRow("smb-path") << "testdata:/smb-file.txt" << "file://" + QtNetworkSettings::winServerName() + "/testshare/test.pri";
1610 void tst_QNetworkReply::getFromFileSpecial()
1612 QFETCH(QString, fileName);
1613 QFETCH(QString, url);
1615 // open the resource so we can find out its size
1616 QFile resource(fileName);
1617 QVERIFY(resource.open(QIODevice::ReadOnly));
1619 QNetworkRequest request;
1620 QNetworkReplyPtr reply;
1621 request.setUrl(url);
1622 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
1624 QCOMPARE(reply->url(), request.url());
1625 QCOMPARE(reply->error(), QNetworkReply::NoError);
1627 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), resource.size());
1628 QCOMPARE(reply->readAll(), resource.readAll());
1631 void tst_QNetworkReply::getFromFtp_data()
1633 QTest::addColumn<QString>("referenceName");
1634 QTest::addColumn<QString>("url");
1636 QTest::newRow("rfc3252.txt") << (testDataDir + "/rfc3252.txt") << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt";
1637 QTest::newRow("bigfile") << (testDataDir + "/bigfile") << "ftp://" + QtNetworkSettings::serverName() + "/qtest/bigfile";
1640 void tst_QNetworkReply::getFromFtp()
1642 QFETCH(QString, referenceName);
1643 QFETCH(QString, url);
1645 QFile reference(referenceName);
1646 QVERIFY(reference.open(QIODevice::ReadOnly));
1648 QNetworkRequest request(url);
1649 QNetworkReplyPtr reply;
1650 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
1652 QCOMPARE(reply->url(), request.url());
1653 QCOMPARE(reply->error(), QNetworkReply::NoError);
1655 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
1656 QCOMPARE(reply->readAll(), reference.readAll());
1659 void tst_QNetworkReply::getFromHttp_data()
1661 QTest::addColumn<QString>("referenceName");
1662 QTest::addColumn<QString>("url");
1664 QTest::newRow("success-internal") << (testDataDir + "/rfc3252.txt") << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt";
1665 QTest::newRow("success-external") << (testDataDir + "/rfc3252.txt") << "http://www.ietf.org/rfc/rfc3252.txt";
1666 QTest::newRow("bigfile-internal") << (testDataDir + "/bigfile") << "http://" + QtNetworkSettings::serverName() + "/qtest/bigfile";
1669 void tst_QNetworkReply::getFromHttp()
1671 QFETCH(QString, referenceName);
1672 QFETCH(QString, url);
1674 QFile reference(referenceName);
1675 QVERIFY(reference.open(QIODevice::ReadOnly));
1677 QNetworkRequest request(url);
1678 QNetworkReplyPtr reply;
1679 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
1681 QCOMPARE(reply->url(), request.url());
1682 QCOMPARE(reply->error(), QNetworkReply::NoError);
1683 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
1684 QCOMPARE(reply->size(), reference.size());
1685 // only compare when the header is set.
1686 if (reply->header(QNetworkRequest::ContentLengthHeader).isValid())
1687 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
1689 // We know our internal server is apache..
1690 if (qstrcmp(QTest::currentDataTag(), "success-internal") == 0)
1691 QVERIFY(reply->header(QNetworkRequest::ServerHeader).toString().contains("Apache"));
1693 QCOMPARE(reply->readAll(), reference.readAll());
1696 void tst_QNetworkReply::headFromHttp_data()
1698 QTest::addColumn<qint64>("referenceSize");
1699 QTest::addColumn<QUrl>("url");
1700 QTest::addColumn<QString>("contentType");
1701 QTest::addColumn<QNetworkProxy>("proxy");
1703 qint64 rfcsize = QFileInfo(testDataDir + "/rfc3252.txt").size();
1704 qint64 bigfilesize = QFileInfo(testDataDir + "/bigfile").size();
1705 qint64 indexsize = QFileInfo(testDataDir + "/index.html").size();
1707 //testing proxies, mainly for the 407 response from http proxy
1708 for (int i = 0; i < proxies.count(); ++i) {
1709 QTest::newRow("rfc" + proxies.at(i).tag) << rfcsize << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt") << "text/plain" << proxies.at(i).proxy;
1710 QTest::newRow("bigfile" + proxies.at(i).tag) << bigfilesize << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/bigfile") << "text/plain" << proxies.at(i).proxy;
1711 QTest::newRow("index" + proxies.at(i).tag) << indexsize << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/") << "text/html" << proxies.at(i).proxy;
1712 QTest::newRow("with-authentication" + proxies.at(i).tag) << rfcsize << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt") << "text/plain" << proxies.at(i).proxy;
1713 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;
1717 void tst_QNetworkReply::headFromHttp()
1719 QFETCH(qint64, referenceSize);
1721 QFETCH(QString, contentType);
1722 QFETCH(QNetworkProxy, proxy);
1724 QNetworkRequest request(url);
1725 QNetworkReplyPtr reply;
1730 manager.setProxy(proxy);
1731 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
1732 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
1733 connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
1734 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
1736 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::HeadOperation, request, reply));
1738 manager.disconnect(SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
1739 this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
1740 manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
1741 this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
1743 QVERIFY(time.elapsed() < 8000); //check authentication didn't wait for the server to timeout the http connection (15s on qt test server)
1745 QCOMPARE(reply->url(), request.url());
1746 QCOMPARE(reply->error(), QNetworkReply::NoError);
1747 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
1748 // only compare when the header is set.
1749 if (reply->header(QNetworkRequest::ContentLengthHeader).isValid() && referenceSize >= 0)
1750 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), referenceSize);
1751 if (reply->header(QNetworkRequest::ContentTypeHeader).isValid())
1752 QCOMPARE(reply->header(QNetworkRequest::ContentTypeHeader).toString(), contentType);
1755 void tst_QNetworkReply::getErrors_data()
1757 QTest::addColumn<QString>("url");
1758 QTest::addColumn<int>("error");
1759 QTest::addColumn<int>("httpStatusCode");
1760 QTest::addColumn<bool>("dataIsEmpty");
1763 QTest::newRow("empty-url") << QString() << int(QNetworkReply::ProtocolUnknownError) << 0 << true;
1764 QTest::newRow("empty-scheme-host") << (testDataDir + "/rfc3252.txt") << int(QNetworkReply::ProtocolUnknownError) << 0 << true;
1765 QTest::newRow("empty-scheme") << "//" + QtNetworkSettings::winServerName() + "/testshare/test.pri"
1766 << int(QNetworkReply::ProtocolUnknownError) << 0 << true;
1769 QTest::newRow("file-host") << "file://this-host-doesnt-exist.troll.no/foo.txt"
1770 #if !defined Q_OS_WIN
1771 << int(QNetworkReply::ProtocolInvalidOperationError) << 0 << true;
1773 << int(QNetworkReply::ContentNotFoundError) << 0 << true;
1775 QTest::newRow("file-no-path") << "file://localhost"
1776 << int(QNetworkReply::ContentOperationNotPermittedError) << 0 << true;
1777 QTest::newRow("file-is-dir") << QUrl::fromLocalFile(QDir::currentPath()).toString()
1778 << int(QNetworkReply::ContentOperationNotPermittedError) << 0 << true;
1779 QTest::newRow("file-exist") << QUrl::fromLocalFile(QDir::currentPath() + "/this-file-doesnt-exist.txt").toString()
1780 << int(QNetworkReply::ContentNotFoundError) << 0 << true;
1781 #if !defined Q_OS_WIN
1782 QTest::newRow("file-is-wronly") << QUrl::fromLocalFile(wronlyFileName).toString()
1783 << int(QNetworkReply::ContentAccessDenied) << 0 << true;
1785 if (QFile::exists("/etc/shadow"))
1786 QTest::newRow("file-permissions") << "file:/etc/shadow"
1787 << int(QNetworkReply::ContentAccessDenied) << 0 << true;
1790 QTest::newRow("ftp-host") << "ftp://this-host-doesnt-exist.troll.no/foo.txt"
1791 << int(QNetworkReply::HostNotFoundError) << 0 << true;
1792 QTest::newRow("ftp-no-path") << "ftp://" + QtNetworkSettings::serverName()
1793 << int(QNetworkReply::ContentOperationNotPermittedError) << 0 << true;
1794 QTest::newRow("ftp-is-dir") << "ftp://" + QtNetworkSettings::serverName() + "/qtest"
1795 << int(QNetworkReply::ContentOperationNotPermittedError) << 0 << true;
1796 QTest::newRow("ftp-dir-not-readable") << "ftp://" + QtNetworkSettings::serverName() + "/pub/dir-not-readable/foo.txt"
1797 << int(QNetworkReply::ContentAccessDenied) << 0 << true;
1798 QTest::newRow("ftp-file-not-readable") << "ftp://" + QtNetworkSettings::serverName() + "/pub/file-not-readable.txt"
1799 << int(QNetworkReply::ContentAccessDenied) << 0 << true;
1800 QTest::newRow("ftp-exist") << "ftp://" + QtNetworkSettings::serverName() + "/pub/this-file-doesnt-exist.txt"
1801 << int(QNetworkReply::ContentNotFoundError) << 0 << true;
1804 QTest::newRow("http-host") << "http://this-host-will-never-exist.troll.no/"
1805 << int(QNetworkReply::HostNotFoundError) << 0 << true;
1806 QTest::newRow("http-exist") << "http://" + QtNetworkSettings::serverName() + "/this-file-doesnt-exist.txt"
1807 << int(QNetworkReply::ContentNotFoundError) << 404 << false;
1808 QTest::newRow("http-authentication") << "http://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth"
1809 << int(QNetworkReply::AuthenticationRequiredError) << 401 << false;
1812 void tst_QNetworkReply::getErrors()
1814 QFETCH(QString, url);
1815 QNetworkRequest request(url);
1818 if ((qstrcmp(QTest::currentDataTag(), "file-is-wronly") == 0) ||
1819 (qstrcmp(QTest::currentDataTag(), "file-permissions") == 0)) {
1820 if (::getuid() == 0)
1821 QSKIP("Running this test as root doesn't make sense");
1825 QNetworkReplyPtr reply(manager.get(request));
1826 reply->setParent(this); // we have expect-fails
1828 if (!reply->isFinished())
1829 QCOMPARE(reply->error(), QNetworkReply::NoError);
1831 // now run the request:
1832 QVERIFY(waitForFinish(reply) != Timeout);
1835 QEXPECT_FAIL("ftp-is-dir", "QFtp cannot provide enough detail", Abort);
1836 // the line below is not necessary
1837 QEXPECT_FAIL("ftp-dir-not-readable", "QFtp cannot provide enough detail", Abort);
1838 QCOMPARE(reply->error(), QNetworkReply::NetworkError(error));
1840 QTEST(reply->readAll().isEmpty(), "dataIsEmpty");
1842 QVERIFY(reply->isFinished());
1843 QVERIFY(!reply->isRunning());
1845 QFETCH(int, httpStatusCode);
1846 if (httpStatusCode != 0) {
1847 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), httpStatusCode);
1851 static inline QByteArray md5sum(const QByteArray &data)
1853 return QCryptographicHash::hash(data, QCryptographicHash::Md5);
1856 void tst_QNetworkReply::putToFile_data()
1858 QTest::addColumn<QByteArray>("data");
1859 QTest::addColumn<QByteArray>("md5sum");
1863 QTest::newRow("empty") << data << md5sum(data);
1865 data = "This is a normal message.";
1866 QTest::newRow("generic") << data << md5sum(data);
1868 data = "This is a message to show that Qt rocks!\r\n\n";
1869 QTest::newRow("small") << data << md5sum(data);
1871 data = QByteArray("abcd\0\1\2\abcd",12);
1872 QTest::newRow("with-nul") << data << md5sum(data);
1874 data = QByteArray(4097, '\4');
1875 QTest::newRow("4k+1") << data << md5sum(data);
1877 data = QByteArray(128*1024+1, '\177');
1878 QTest::newRow("128k+1") << data << md5sum(data);
1880 data = QByteArray(2*1024*1024+1, '\177');
1881 QTest::newRow("2MB+1") << data << md5sum(data);
1884 void tst_QNetworkReply::putToFile()
1886 QFile file(testFileName);
1888 QUrl url = QUrl::fromLocalFile(file.fileName());
1889 QNetworkRequest request(url);
1890 QNetworkReplyPtr reply;
1892 QFETCH(QByteArray, data);
1894 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PutOperation, request, reply, data));
1896 QCOMPARE(reply->url(), url);
1897 QCOMPARE(reply->error(), QNetworkReply::NoError);
1898 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
1899 QVERIFY(reply->readAll().isEmpty());
1901 QVERIFY(file.open(QIODevice::ReadOnly));
1902 QCOMPARE(file.size(), qint64(data.size()));
1903 QByteArray contents = file.readAll();
1904 QCOMPARE(contents, data);
1907 void tst_QNetworkReply::putToFtp_data()
1912 void tst_QNetworkReply::putToFtp()
1914 QUrl url("ftp://" + QtNetworkSettings::serverName());
1915 url.setPath(QString("/qtest/upload/qnetworkaccess-putToFtp-%1-%2")
1916 .arg(QTest::currentDataTag())
1917 .arg(uniqueExtension));
1919 QNetworkRequest request(url);
1920 QNetworkReplyPtr reply;
1922 QFETCH(QByteArray, data);
1924 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PutOperation, request, reply, data));
1926 QCOMPARE(reply->url(), url);
1927 QCOMPARE(reply->error(), QNetworkReply::NoError);
1928 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
1929 QVERIFY(reply->readAll().isEmpty());
1931 // download the file again from FTP to make sure it was uploaded
1933 QNetworkAccessManager qnam;
1934 QNetworkRequest req(url);
1935 QNetworkReply *r = qnam.get(req);
1937 QObject::connect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
1939 QSignalSpy spy(r, SIGNAL(downloadProgress(qint64,qint64)));
1940 while (!r->isFinished()) {
1941 QTestEventLoop::instance().enterLoop(10);
1942 if (count == spy.count() && !r->isFinished())
1944 count = spy.count();
1946 QObject::disconnect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
1948 QByteArray uploaded = r->readAll();
1949 QCOMPARE(uploaded.size(), data.size());
1950 QCOMPARE(uploaded, data);
1953 QObject::connect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
1954 QTestEventLoop::instance().enterLoop(10);
1955 QObject::disconnect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
1958 void tst_QNetworkReply::putToHttp_data()
1963 void tst_QNetworkReply::putToHttp()
1965 QUrl url("http://" + QtNetworkSettings::serverName());
1966 url.setPath(QString("/dav/qnetworkaccess-putToHttp-%1-%2")
1967 .arg(QTest::currentDataTag())
1968 .arg(uniqueExtension));
1970 QNetworkRequest request(url);
1971 QNetworkReplyPtr reply;
1973 QFETCH(QByteArray, data);
1975 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PutOperation, request, reply, data));
1977 QCOMPARE(reply->url(), url);
1978 QCOMPARE(reply->error(), QNetworkReply::NoError);
1980 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 201); // 201 Created
1982 // download the file again from HTTP to make sure it was uploaded
1983 // correctly. HTTP/0.9 is enough
1985 socket.connectToHost(QtNetworkSettings::serverName(), 80);
1986 socket.write("GET " + url.toEncoded(QUrl::RemoveScheme | QUrl::RemoveAuthority) + "\r\n");
1987 if (!socket.waitForDisconnected(10000))
1988 QFAIL("Network timeout");
1990 QByteArray uploadedData = socket.readAll();
1991 QCOMPARE(uploadedData, data);
1994 void tst_QNetworkReply::putToHttpSynchronous_data()
1996 uniqueExtension = createUniqueExtension();
2000 void tst_QNetworkReply::putToHttpSynchronous()
2002 QUrl url("http://" + QtNetworkSettings::serverName());
2003 url.setPath(QString("/dav/qnetworkaccess-putToHttp-%1-%2")
2004 .arg(QTest::currentDataTag())
2005 .arg(uniqueExtension));
2007 QNetworkRequest request(url);
2008 QNetworkReplyPtr reply;
2010 QFETCH(QByteArray, data);
2012 request.setAttribute(
2013 QNetworkRequest::SynchronousRequestAttribute,
2016 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PutOperation, request, reply, data));
2018 QCOMPARE(reply->url(), url);
2019 QCOMPARE(reply->error(), QNetworkReply::NoError);
2021 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 201); // 201 Created
2023 // download the file again from HTTP to make sure it was uploaded
2024 // correctly. HTTP/0.9 is enough
2026 socket.connectToHost(QtNetworkSettings::serverName(), 80);
2027 socket.write("GET " + url.toEncoded(QUrl::RemoveScheme | QUrl::RemoveAuthority) + "\r\n");
2028 if (!socket.waitForDisconnected(10000))
2029 QFAIL("Network timeout");
2031 QByteArray uploadedData = socket.readAll();
2032 QCOMPARE(uploadedData, data);
2035 void tst_QNetworkReply::postToHttp_data()
2040 void tst_QNetworkReply::postToHttp()
2042 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi");
2044 QNetworkRequest request(url);
2045 request.setRawHeader("Content-Type", "application/octet-stream");
2046 QNetworkReplyPtr reply;
2048 QFETCH(QByteArray, data);
2050 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PostOperation, request, reply, data));
2052 QCOMPARE(reply->url(), url);
2053 QCOMPARE(reply->error(), QNetworkReply::NoError);
2055 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
2057 QFETCH(QByteArray, md5sum);
2058 QByteArray uploadedData = reply->readAll().trimmed();
2059 QCOMPARE(uploadedData, md5sum.toHex());
2062 void tst_QNetworkReply::postToHttpSynchronous_data()
2067 void tst_QNetworkReply::postToHttpSynchronous()
2069 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi");
2071 QNetworkRequest request(url);
2072 request.setRawHeader("Content-Type", "application/octet-stream");
2074 request.setAttribute(
2075 QNetworkRequest::SynchronousRequestAttribute,
2078 QNetworkReplyPtr reply;
2080 QFETCH(QByteArray, data);
2082 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PostOperation, request, reply, data));
2084 QCOMPARE(reply->url(), url);
2085 QCOMPARE(reply->error(), QNetworkReply::NoError);
2087 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
2089 QFETCH(QByteArray, md5sum);
2090 QByteArray uploadedData = reply->readAll().trimmed();
2091 QCOMPARE(uploadedData, md5sum.toHex());
2094 void tst_QNetworkReply::postToHttpMultipart_data()
2096 QTest::addColumn<QUrl>("url");
2097 QTest::addColumn<QHttpMultiPart *>("multiPart");
2098 QTest::addColumn<QByteArray>("expectedReplyData");
2099 QTest::addColumn<QByteArray>("contentType");
2101 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/multipart.cgi");
2102 QByteArray expectedData;
2107 QHttpMultiPart *emptyMultiPart = new QHttpMultiPart;
2108 QTest::newRow("empty") << url << emptyMultiPart << expectedData << QByteArray("mixed");
2110 QHttpMultiPart *emptyRelatedMultiPart = new QHttpMultiPart;
2111 emptyRelatedMultiPart->setContentType(QHttpMultiPart::RelatedType);
2112 QTest::newRow("empty-related") << url << emptyRelatedMultiPart << expectedData << QByteArray("related");
2114 QHttpMultiPart *emptyAlternativeMultiPart = new QHttpMultiPart;
2115 emptyAlternativeMultiPart->setContentType(QHttpMultiPart::AlternativeType);
2116 QTest::newRow("empty-alternative") << url << emptyAlternativeMultiPart << expectedData << QByteArray("alternative");
2122 textPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain"));
2123 textPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"text\""));
2124 textPart.setBody("7 bytes");
2125 QHttpMultiPart *multiPart1 = new QHttpMultiPart;
2126 multiPart1->setContentType(QHttpMultiPart::FormDataType);
2127 multiPart1->append(textPart);
2128 expectedData = "key: text, value: 7 bytes\n";
2129 QTest::newRow("text") << url << multiPart1 << expectedData << QByteArray("form-data");
2131 QHttpMultiPart *customMultiPart = new QHttpMultiPart;
2132 customMultiPart->append(textPart);
2133 expectedData = "header: Content-Type, value: 'text/plain'\n"
2134 "header: Content-Disposition, value: 'form-data; name=\"text\"'\n"
2135 "content: 7 bytes\n"
2137 QTest::newRow("text-custom") << url << customMultiPart << expectedData << QByteArray("custom");
2139 QHttpPart textPart2;
2140 textPart2.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain"));
2141 textPart2.setRawHeader("myRawHeader", "myValue");
2142 textPart2.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"text2\""));
2143 textPart2.setBody("some more bytes");
2144 textPart2.setBodyDevice((QIODevice *) 1); // test whether setting and unsetting of the device works
2145 textPart2.setBodyDevice(0);
2146 QHttpMultiPart *multiPart2 = new QHttpMultiPart;
2147 multiPart2->setContentType(QHttpMultiPart::FormDataType);
2148 multiPart2->append(textPart);
2149 multiPart2->append(textPart2);
2150 expectedData = "key: text2, value: some more bytes\n"
2151 "key: text, value: 7 bytes\n";
2152 QTest::newRow("text-text") << url << multiPart2 << expectedData << QByteArray("form-data");
2155 QHttpPart textPart3;
2156 textPart3.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain"));
2157 textPart3.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"text3\""));
2158 textPart3.setRawHeader("Content-Location", "http://my.test.location.tld");
2159 textPart3.setBody("even more bytes");
2160 QHttpMultiPart *multiPart3 = new QHttpMultiPart;
2161 multiPart3->setContentType(QHttpMultiPart::AlternativeType);
2162 multiPart3->append(textPart);
2163 multiPart3->append(textPart2);
2164 multiPart3->append(textPart3);
2165 expectedData = "header: Content-Type, value: 'text/plain'\n"
2166 "header: Content-Disposition, value: 'form-data; name=\"text\"'\n"
2167 "content: 7 bytes\n"
2169 "header: Content-Type, value: 'text/plain'\n"
2170 "header: myRawHeader, value: 'myValue'\n"
2171 "header: Content-Disposition, value: 'form-data; name=\"text2\"'\n"
2172 "content: some more bytes\n"
2174 "header: Content-Type, value: 'text/plain'\n"
2175 "header: Content-Disposition, value: 'form-data; name=\"text3\"'\n"
2176 "header: Content-Location, value: 'http://my.test.location.tld'\n"
2177 "content: even more bytes\n\n";
2178 QTest::newRow("text-text-text") << url << multiPart3 << expectedData << QByteArray("alternative");
2182 // text and image parts
2184 QHttpPart imagePart11;
2185 imagePart11.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
2186 imagePart11.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage\""));
2187 imagePart11.setRawHeader("Content-Location", "http://my.test.location.tld");
2188 imagePart11.setRawHeader("Content-ID", "my@id.tld");
2189 QFile *file11 = new QFile(testDataDir + "/image1.jpg");
2190 file11->open(QIODevice::ReadOnly);
2191 imagePart11.setBodyDevice(file11);
2192 QHttpMultiPart *imageMultiPart1 = new QHttpMultiPart(QHttpMultiPart::FormDataType);
2193 imageMultiPart1->append(imagePart11);
2194 file11->setParent(imageMultiPart1);
2195 expectedData = "key: testImage, value: 87ef3bb319b004ba9e5e9c9fa713776e\n"; // md5 sum of file
2196 QTest::newRow("image") << url << imageMultiPart1 << expectedData << QByteArray("form-data");
2198 QHttpPart imagePart21;
2199 imagePart21.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
2200 imagePart21.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage1\""));
2201 imagePart21.setRawHeader("Content-Location", "http://my.test.location.tld");
2202 imagePart21.setRawHeader("Content-ID", "my@id.tld");
2203 QFile *file21 = new QFile(testDataDir + "/image1.jpg");
2204 file21->open(QIODevice::ReadOnly);
2205 imagePart21.setBodyDevice(file21);
2206 QHttpMultiPart *imageMultiPart2 = new QHttpMultiPart();
2207 imageMultiPart2->setContentType(QHttpMultiPart::FormDataType);
2208 imageMultiPart2->append(textPart);
2209 imageMultiPart2->append(imagePart21);
2210 file21->setParent(imageMultiPart2);
2211 QHttpPart imagePart22;
2212 imagePart22.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
2213 imagePart22.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage2\""));
2214 QFile *file22 = new QFile(testDataDir + "/image2.jpg");
2215 file22->open(QIODevice::ReadOnly);
2216 imagePart22.setBodyDevice(file22);
2217 imageMultiPart2->append(imagePart22);
2218 file22->setParent(imageMultiPart2);
2219 expectedData = "key: testImage1, value: 87ef3bb319b004ba9e5e9c9fa713776e\n"
2220 "key: text, value: 7 bytes\n"
2221 "key: testImage2, value: 483761b893f7fb1bd2414344cd1f3dfb\n";
2222 QTest::newRow("text-image-image") << url << imageMultiPart2 << expectedData << QByteArray("form-data");
2225 QHttpPart imagePart31;
2226 imagePart31.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
2227 imagePart31.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage1\""));
2228 imagePart31.setRawHeader("Content-Location", "http://my.test.location.tld");
2229 imagePart31.setRawHeader("Content-ID", "my@id.tld");
2230 QFile *file31 = new QFile(testDataDir + "/image1.jpg");
2231 file31->open(QIODevice::ReadOnly);
2232 imagePart31.setBodyDevice(file31);
2233 QHttpMultiPart *imageMultiPart3 = new QHttpMultiPart(QHttpMultiPart::FormDataType);
2234 imageMultiPart3->append(imagePart31);
2235 file31->setParent(imageMultiPart3);
2236 QHttpPart imagePart32;
2237 imagePart32.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
2238 imagePart32.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage2\""));
2239 QFile *file32 = new QFile(testDataDir + "/image2.jpg");
2240 file32->open(QIODevice::ReadOnly);
2241 imagePart32.setBodyDevice(file31); // check that resetting works
2242 imagePart32.setBodyDevice(file32);
2243 imageMultiPart3->append(imagePart32);
2244 file32->setParent(imageMultiPart3);
2245 QHttpPart imagePart33;
2246 imagePart33.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
2247 imagePart33.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage3\""));
2248 QFile *file33 = new QFile(testDataDir + "/image3.jpg");
2249 file33->open(QIODevice::ReadOnly);
2250 imagePart33.setBodyDevice(file33);
2251 imageMultiPart3->append(imagePart33);
2252 file33->setParent(imageMultiPart3);
2253 expectedData = "key: testImage1, value: 87ef3bb319b004ba9e5e9c9fa713776e\n"
2254 "key: testImage2, value: 483761b893f7fb1bd2414344cd1f3dfb\n"
2255 "key: testImage3, value: ab0eb6fd4fcf8b4436254870b4513033\n";
2256 QTest::newRow("3-images") << url << imageMultiPart3 << expectedData << QByteArray("form-data");
2259 // note: nesting multiparts is not working currently; for that, the outputDevice would need to be public
2261 // QHttpPart imagePart41;
2262 // imagePart41.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
2263 // QFile *file41 = new QFile(testDataDir + "/image1.jpg");
2264 // file41->open(QIODevice::ReadOnly);
2265 // imagePart41.setBodyDevice(file41);
2267 // QHttpMultiPart *innerMultiPart = new QHttpMultiPart();
2268 // innerMultiPart->setContentType(QHttpMultiPart::FormDataType);
2269 // textPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant());
2270 // innerMultiPart->append(textPart);
2271 // innerMultiPart->append(imagePart41);
2272 // textPart2.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant());
2273 // innerMultiPart->append(textPart2);
2275 // QHttpPart nestedPart;
2276 // nestedPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"nestedMessage"));
2277 // nestedPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("multipart/alternative; boundary=\"" + innerMultiPart->boundary() + "\""));
2278 // innerMultiPart->outputDevice()->open(QIODevice::ReadOnly);
2279 // nestedPart.setBodyDevice(innerMultiPart->outputDevice());
2281 // QHttpMultiPart *outerMultiPart = new QHttpMultiPart;
2282 // outerMultiPart->setContentType(QHttpMultiPart::FormDataType);
2283 // outerMultiPart->append(textPart);
2284 // outerMultiPart->append(nestedPart);
2285 // outerMultiPart->append(textPart2);
2286 // expectedData = "nothing"; // the CGI.pm module running on the test server does not understand nested multiparts
2287 // openFiles.clear();
2288 // openFiles << file41;
2289 // QTest::newRow("nested") << url << outerMultiPart << expectedData << openFiles;
2292 // test setting large chunks of content with a byte array instead of a device (DISCOURAGED because of high memory consumption,
2293 // but we need to test that the behavior is correct)
2294 QHttpPart imagePart51;
2295 imagePart51.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
2296 imagePart51.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage\""));
2297 QFile *file51 = new QFile(testDataDir + "/image1.jpg");
2298 file51->open(QIODevice::ReadOnly);
2299 QByteArray imageData = file51->readAll();
2302 imagePart51.setBody("7 bytes"); // check that resetting works
2303 imagePart51.setBody(imageData);
2304 QHttpMultiPart *imageMultiPart5 = new QHttpMultiPart;
2305 imageMultiPart5->setContentType(QHttpMultiPart::FormDataType);
2306 imageMultiPart5->append(imagePart51);
2307 expectedData = "key: testImage, value: 87ef3bb319b004ba9e5e9c9fa713776e\n"; // md5 sum of file
2308 QTest::newRow("image-as-content") << url << imageMultiPart5 << expectedData << QByteArray("form-data");
2311 void tst_QNetworkReply::postToHttpMultipart()
2315 static QSet<QByteArray> boundaries;
2317 QNetworkRequest request(url);
2318 QNetworkReplyPtr reply;
2320 QFETCH(QHttpMultiPart *, multiPart);
2321 QFETCH(QByteArray, expectedReplyData);
2322 QFETCH(QByteArray, contentType);
2324 // hack for testing the setting of the content-type header by hand:
2325 if (contentType == "custom") {
2326 QByteArray contentType("multipart/custom; boundary=\"" + multiPart->boundary() + "\"");
2327 request.setHeader(QNetworkRequest::ContentTypeHeader, contentType);
2330 QVERIFY2(! boundaries.contains(multiPart->boundary()), "boundary '" + multiPart->boundary() + "' has been created twice");
2331 boundaries.insert(multiPart->boundary());
2333 RUN_REQUEST(runMultipartRequest(request, reply, multiPart, "POST"));
2334 multiPart->deleteLater();
2336 QCOMPARE(reply->url(), url);
2337 QCOMPARE(reply->error(), QNetworkReply::NoError);
2339 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
2341 QVERIFY(multiPart->boundary().count() > 20); // check that there is randomness after the "boundary_.oOo._" string
2342 QVERIFY(multiPart->boundary().count() < 70);
2343 QByteArray replyData = reply->readAll();
2345 expectedReplyData.prepend("content type: multipart/" + contentType + "; boundary=\"" + multiPart->boundary() + "\"\n");
2346 // QEXPECT_FAIL("nested", "the server does not understand nested multipart messages", Continue); // see above
2347 QCOMPARE(replyData, expectedReplyData);
2350 void tst_QNetworkReply::putToHttpMultipart_data()
2352 postToHttpMultipart_data();
2355 void tst_QNetworkReply::putToHttpMultipart()
2357 QSKIP("test server script cannot handle PUT data yet");
2360 static QSet<QByteArray> boundaries;
2362 QNetworkRequest request(url);
2363 QNetworkReplyPtr reply;
2365 QFETCH(QHttpMultiPart *, multiPart);
2366 QFETCH(QByteArray, expectedReplyData);
2367 QFETCH(QByteArray, contentType);
2369 // hack for testing the setting of the content-type header by hand:
2370 if (contentType == "custom") {
2371 QByteArray contentType("multipart/custom; boundary=\"" + multiPart->boundary() + "\"");
2372 request.setHeader(QNetworkRequest::ContentTypeHeader, contentType);
2375 QVERIFY2(! boundaries.contains(multiPart->boundary()), "boundary '" + multiPart->boundary() + "' has been created twice");
2376 boundaries.insert(multiPart->boundary());
2378 RUN_REQUEST(runMultipartRequest(request, reply, multiPart, "PUT"));
2379 multiPart->deleteLater();
2381 QCOMPARE(reply->url(), url);
2382 QCOMPARE(reply->error(), QNetworkReply::NoError);
2384 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
2386 QVERIFY(multiPart->boundary().count() > 20); // check that there is randomness after the "boundary_.oOo._" string
2387 QVERIFY(multiPart->boundary().count() < 70);
2388 QByteArray replyData = reply->readAll();
2390 expectedReplyData.prepend("content type: multipart/" + contentType + "; boundary=\"" + multiPart->boundary() + "\"\n");
2391 // QEXPECT_FAIL("nested", "the server does not understand nested multipart messages", Continue); // see above
2392 QCOMPARE(replyData, expectedReplyData);
2395 void tst_QNetworkReply::deleteFromHttp_data()
2397 QTest::addColumn<QUrl>("url");
2398 QTest::addColumn<int>("resultCode");
2399 QTest::addColumn<QNetworkReply::NetworkError>("error");
2401 // for status codes to expect, see http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
2403 QTest::newRow("405-method-not-allowed") << QUrl("http://" + QtNetworkSettings::serverName() + "/index.html") << 405 << QNetworkReply::ContentOperationNotPermittedError;
2404 QTest::newRow("200-ok") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/http-delete.cgi?200-ok") << 200 << QNetworkReply::NoError;
2405 QTest::newRow("202-accepted") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/http-delete.cgi?202-accepted") << 202 << QNetworkReply::NoError;
2406 QTest::newRow("204-no-content") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/http-delete.cgi?204-no-content") << 204 << QNetworkReply::NoError;
2407 QTest::newRow("404-not-found") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/http-delete.cgi?404-not-found") << 404 << QNetworkReply::ContentNotFoundError;
2410 void tst_QNetworkReply::deleteFromHttp()
2413 QFETCH(int, resultCode);
2414 QFETCH(QNetworkReply::NetworkError, error);
2415 QNetworkRequest request(url);
2416 QNetworkReplyPtr reply;
2417 runSimpleRequest(QNetworkAccessManager::DeleteOperation, request, reply, 0);
2418 QCOMPARE(reply->url(), url);
2419 QCOMPARE(reply->error(), error);
2420 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), resultCode);
2423 void tst_QNetworkReply::putGetDeleteGetFromHttp_data()
2425 QTest::addColumn<QUrl>("putUrl");
2426 QTest::addColumn<int>("putResultCode");
2427 QTest::addColumn<QNetworkReply::NetworkError>("putError");
2428 QTest::addColumn<QUrl>("deleteUrl");
2429 QTest::addColumn<int>("deleteResultCode");
2430 QTest::addColumn<QNetworkReply::NetworkError>("deleteError");
2431 QTest::addColumn<QUrl>("get2Url");
2432 QTest::addColumn<int>("get2ResultCode");
2433 QTest::addColumn<QNetworkReply::NetworkError>("get2Error");
2435 QUrl url("http://" + QtNetworkSettings::serverName());
2436 url.setPath(QString("/dav/qnetworkaccess-putToHttp-%1-%2")
2437 .arg(QTest::currentDataTag())
2438 .arg(uniqueExtension));
2440 // first use case: put, get (to check it is there), delete, get (to check it is not there anymore)
2441 QTest::newRow("success") << url << 201 << QNetworkReply::NoError << url << 204 << QNetworkReply::NoError << url << 404 << QNetworkReply::ContentNotFoundError;
2443 QUrl wrongUrl("http://" + QtNetworkSettings::serverName());
2444 wrongUrl.setPath(QString("/dav/qnetworkaccess-thisURLisNotAvailable"));
2446 // second use case: put, get (to check it is there), delete wrong URL, get (to check it is still there)
2447 QTest::newRow("delete-error") << url << 201 << QNetworkReply::NoError << wrongUrl << 404 << QNetworkReply::ContentNotFoundError << url << 200 << QNetworkReply::NoError;
2451 void tst_QNetworkReply::putGetDeleteGetFromHttp()
2453 QFETCH(QUrl, putUrl);
2454 QFETCH(int, putResultCode);
2455 QFETCH(QNetworkReply::NetworkError, putError);
2456 QFETCH(QUrl, deleteUrl);
2457 QFETCH(int, deleteResultCode);
2458 QFETCH(QNetworkReply::NetworkError, deleteError);
2459 QFETCH(QUrl, get2Url);
2460 QFETCH(int, get2ResultCode);
2461 QFETCH(QNetworkReply::NetworkError, get2Error);
2463 QNetworkRequest putRequest(putUrl);
2464 QNetworkRequest deleteRequest(deleteUrl);
2465 QNetworkRequest get2Request(get2Url);
2466 QNetworkReplyPtr reply;
2468 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PutOperation, putRequest, reply, 0));
2469 QCOMPARE(reply->error(), putError);
2470 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), putResultCode);
2472 runSimpleRequest(QNetworkAccessManager::GetOperation, putRequest, reply, 0);
2473 QCOMPARE(reply->error(), QNetworkReply::NoError);
2474 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2476 runSimpleRequest(QNetworkAccessManager::DeleteOperation, deleteRequest, reply, 0);
2477 QCOMPARE(reply->error(), deleteError);
2478 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), deleteResultCode);
2480 runSimpleRequest(QNetworkAccessManager::GetOperation, get2Request, reply, 0);
2481 QCOMPARE(reply->error(), get2Error);
2482 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), get2ResultCode);
2486 void tst_QNetworkReply::connectToIPv6Address_data()
2488 QTest::addColumn<QUrl>("url");
2489 QTest::addColumn<QNetworkReply::NetworkError>("error");
2490 QTest::addColumn<QByteArray>("dataToSend");
2491 QTest::addColumn<QByteArray>("hostfield");
2492 QTest::newRow("localhost") << QUrl(QByteArray("http://[::1]")) << QNetworkReply::NoError<< QByteArray("localhost") << QByteArray("[::1]");
2493 //QTest::newRow("ipv4localhost") << QUrl(QByteArray("http://127.0.0.1")) << QNetworkReply::NoError<< QByteArray("ipv4localhost") << QByteArray("127.0.0.1");
2494 //to add more test data here
2497 void tst_QNetworkReply::connectToIPv6Address()
2500 QFETCH(QNetworkReply::NetworkError, error);
2501 QFETCH(QByteArray, dataToSend);
2502 QFETCH(QByteArray, hostfield);
2504 if (!QtNetworkSettings::hasIPv6())
2505 QSKIP("system doesn't support ipv6!");
2507 QByteArray httpResponse = QByteArray("HTTP/1.0 200 OK\r\nContent-Length: ");
2508 httpResponse += QByteArray::number(dataToSend.size());
2509 httpResponse += "\r\n\r\n";
2510 httpResponse += dataToSend;
2512 MiniHttpServer server(httpResponse, false, NULL/*thread*/, true/*useipv6*/);
2513 server.doClose = true;
2515 url.setPort(server.serverPort());
2516 QNetworkRequest request(url);
2518 QNetworkReplyPtr reply(manager.get(request));
2519 QVERIFY(waitForFinish(reply) == Success);
2520 QByteArray content = reply->readAll();
2521 //qDebug() << server.receivedData;
2522 QByteArray hostinfo = "\r\nHost: " + hostfield + ":" + QByteArray::number(server.serverPort()) + "\r\n";
2523 QVERIFY(server.receivedData.contains(hostinfo));
2524 QVERIFY(content == dataToSend);
2525 QCOMPARE(reply->url(), request.url());
2526 QVERIFY(reply->error() == error);
2529 void tst_QNetworkReply::sendCustomRequestToHttp_data()
2531 QTest::addColumn<QUrl>("url");
2532 QTest::addColumn<QByteArray>("verb");
2533 QTest::addColumn<QBuffer *>("device");
2534 QTest::addColumn<int>("resultCode");
2535 QTest::addColumn<QNetworkReply::NetworkError>("error");
2536 QTest::addColumn<QByteArray>("expectedContent");
2538 QTest::newRow("options") << QUrl("http://" + QtNetworkSettings::serverName()) <<
2539 QByteArray("OPTIONS") << (QBuffer *) 0 << 200 << QNetworkReply::NoError << QByteArray();
2540 QTest::newRow("trace") << QUrl("http://" + QtNetworkSettings::serverName()) <<
2541 QByteArray("TRACE") << (QBuffer *) 0 << 200 << QNetworkReply::NoError << QByteArray();
2542 QTest::newRow("connect") << QUrl("http://" + QtNetworkSettings::serverName()) <<
2543 QByteArray("CONNECT") << (QBuffer *) 0 << 400 << QNetworkReply::UnknownContentError << QByteArray(); // 400 = Bad Request
2544 QTest::newRow("nonsense") << QUrl("http://" + QtNetworkSettings::serverName()) <<
2545 QByteArray("NONSENSE") << (QBuffer *) 0 << 501 << QNetworkReply::ProtocolUnknownError << QByteArray(); // 501 = Method Not Implemented
2547 QByteArray ba("test");
2548 QBuffer *buffer = new QBuffer;
2549 buffer->setData(ba);
2550 buffer->open(QIODevice::ReadOnly);
2551 QTest::newRow("post") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi") << QByteArray("POST")
2552 << buffer << 200 << QNetworkReply::NoError << QByteArray("098f6bcd4621d373cade4e832627b4f6\n");
2554 QByteArray ba2("test");
2555 QBuffer *buffer2 = new QBuffer;
2556 buffer2->setData(ba2);
2557 buffer2->open(QIODevice::ReadOnly);
2558 QTest::newRow("put") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi") << QByteArray("PUT")
2559 << buffer2 << 200 << QNetworkReply::NoError << QByteArray("098f6bcd4621d373cade4e832627b4f6\n");
2562 void tst_QNetworkReply::sendCustomRequestToHttp()
2565 QNetworkRequest request(url);
2566 QNetworkReplyPtr reply;
2567 QFETCH(QByteArray, verb);
2568 QFETCH(QBuffer *, device);
2569 runCustomRequest(request, reply, verb, device);
2570 QCOMPARE(reply->url(), url);
2571 QFETCH(QNetworkReply::NetworkError, error);
2572 QCOMPARE(reply->error(), error);
2573 QFETCH(int, resultCode);
2574 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), resultCode);
2575 QFETCH(QByteArray, expectedContent);
2576 if (! expectedContent.isEmpty())
2577 QCOMPARE(reply->readAll(), expectedContent);
2580 void tst_QNetworkReply::ioGetFromData_data()
2582 QTest::addColumn<QString>("urlStr");
2583 QTest::addColumn<QByteArray>("data");
2585 QTest::newRow("data-empty") << "data:," << QByteArray();
2586 QTest::newRow("data-literal") << "data:,foo" << QByteArray("foo");
2587 QTest::newRow("data-pct") << "data:,%3Cbody%20contentEditable%3Dtrue%3E%0D%0A"
2588 << QByteArray("<body contentEditable=true>\r\n");
2589 QTest::newRow("data-base64") << "data:;base64,UXQgaXMgZ3JlYXQh" << QByteArray("Qt is great!");
2592 void tst_QNetworkReply::ioGetFromData()
2594 QFETCH(QString, urlStr);
2596 QUrl url = QUrl::fromEncoded(urlStr.toLatin1());
2597 QNetworkRequest request(url);
2599 QNetworkReplyPtr reply(manager.get(request));
2600 DataReader reader(reply);
2602 connect(reply, SIGNAL(finished()),
2603 &QTestEventLoop::instance(), SLOT(exitLoop()));
2604 QTestEventLoop::instance().enterLoop(10);
2605 QVERIFY(!QTestEventLoop::instance().timeout());
2607 QCOMPARE(reply->url(), request.url());
2608 QCOMPARE(reply->error(), QNetworkReply::NoError);
2610 QFETCH(QByteArray, data);
2611 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toInt(), data.size());
2612 QCOMPARE(reader.data.size(), data.size());
2613 QCOMPARE(reader.data, data);
2616 void tst_QNetworkReply::ioGetFromFileSpecial_data()
2618 getFromFileSpecial_data();
2621 void tst_QNetworkReply::ioGetFromFileSpecial()
2623 QFETCH(QString, fileName);
2624 QFETCH(QString, url);
2626 QFile resource(fileName);
2627 QVERIFY(resource.open(QIODevice::ReadOnly));
2629 QNetworkRequest request;
2630 request.setUrl(url);
2631 QNetworkReplyPtr reply(manager.get(request));
2632 DataReader reader(reply);
2634 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
2635 QTestEventLoop::instance().enterLoop(10);
2636 QVERIFY(!QTestEventLoop::instance().timeout());
2638 QCOMPARE(reply->url(), request.url());
2639 QCOMPARE(reply->error(), QNetworkReply::NoError);
2641 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), resource.size());
2642 QCOMPARE(qint64(reader.data.size()), resource.size());
2643 QCOMPARE(reader.data, resource.readAll());
2646 void tst_QNetworkReply::ioGetFromFile_data()
2651 void tst_QNetworkReply::ioGetFromFile()
2653 QTemporaryFile file(QDir::currentPath() + "/temp-XXXXXX");
2654 file.setAutoRemove(true);
2655 QVERIFY(file.open());
2657 QFETCH(QByteArray, data);
2658 QVERIFY(file.write(data) == data.size());
2660 QCOMPARE(file.size(), qint64(data.size()));
2662 QNetworkRequest request(QUrl::fromLocalFile(file.fileName()));
2663 QNetworkReplyPtr reply(manager.get(request));
2664 QVERIFY(reply->isFinished()); // a file should immediately be done
2665 DataReader reader(reply);
2667 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
2668 QTestEventLoop::instance().enterLoop(10);
2669 QVERIFY(!QTestEventLoop::instance().timeout());
2671 QCOMPARE(reply->url(), request.url());
2672 QCOMPARE(reply->error(), QNetworkReply::NoError);
2674 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), file.size());
2675 QCOMPARE(qint64(reader.data.size()), file.size());
2676 QCOMPARE(reader.data, data);
2679 void tst_QNetworkReply::ioGetFromFtp_data()
2681 QTest::addColumn<QString>("fileName");
2682 QTest::addColumn<qint64>("expectedSize");
2684 QTest::newRow("bigfile") << "bigfile" << Q_INT64_C(519240);
2686 QFile file(testDataDir + "/rfc3252.txt");
2687 QTest::newRow("rfc3252.txt") << "rfc3252.txt" << file.size();
2690 void tst_QNetworkReply::ioGetFromFtp()
2692 QFETCH(QString, fileName);
2693 QFile reference(fileName);
2694 reference.open(QIODevice::ReadOnly); // will fail for bigfile
2696 QNetworkRequest request("ftp://" + QtNetworkSettings::serverName() + "/qtest/" + fileName);
2697 QNetworkReplyPtr reply(manager.get(request));
2698 DataReader reader(reply);
2700 QVERIFY(waitForFinish(reply) == Success);
2702 QCOMPARE(reply->url(), request.url());
2703 QCOMPARE(reply->error(), QNetworkReply::NoError);
2705 QFETCH(qint64, expectedSize);
2706 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), expectedSize);
2707 QCOMPARE(qint64(reader.data.size()), expectedSize);
2709 if (reference.isOpen())
2710 QCOMPARE(reader.data, reference.readAll());
2713 void tst_QNetworkReply::ioGetFromFtpWithReuse()
2715 QString fileName = testDataDir + "/rfc3252.txt";
2716 QFile reference(fileName);
2717 reference.open(QIODevice::ReadOnly);
2719 QNetworkRequest request(QUrl("ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
2721 // two concurrent (actually, consecutive) gets:
2722 QNetworkReplyPtr reply1(manager.get(request));
2723 DataReader reader1(reply1);
2724 QNetworkReplyPtr reply2(manager.get(request));
2725 DataReader reader2(reply2);
2726 QSignalSpy spy(reply1.data(), SIGNAL(finished()));
2728 QVERIFY(waitForFinish(reply1) == Success);
2729 QVERIFY(waitForFinish(reply2) == Success);
2731 QCOMPARE(reply1->url(), request.url());
2732 QCOMPARE(reply2->url(), request.url());
2733 QCOMPARE(reply1->error(), QNetworkReply::NoError);
2734 QCOMPARE(reply2->error(), QNetworkReply::NoError);
2736 QCOMPARE(qint64(reader1.data.size()), reference.size());
2737 QCOMPARE(qint64(reader2.data.size()), reference.size());
2738 QCOMPARE(reply1->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
2739 QCOMPARE(reply2->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
2741 QByteArray referenceData = reference.readAll();
2742 QCOMPARE(reader1.data, referenceData);
2743 QCOMPARE(reader2.data, referenceData);
2746 void tst_QNetworkReply::ioGetFromHttp()
2748 QFile reference(testDataDir + "/rfc3252.txt");
2749 QVERIFY(reference.open(QIODevice::ReadOnly));
2751 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
2752 QNetworkReplyPtr reply(manager.get(request));
2753 DataReader reader(reply);
2755 QVERIFY(waitForFinish(reply) == Success);
2757 QCOMPARE(reply->url(), request.url());
2758 QCOMPARE(reply->error(), QNetworkReply::NoError);
2759 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2761 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
2762 QCOMPARE(qint64(reader.data.size()), reference.size());
2764 QCOMPARE(reader.data, reference.readAll());
2767 void tst_QNetworkReply::ioGetFromHttpWithReuseParallel()
2769 QFile reference(testDataDir + "/rfc3252.txt");
2770 QVERIFY(reference.open(QIODevice::ReadOnly));
2772 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
2773 QNetworkReplyPtr reply1(manager.get(request));
2774 QNetworkReplyPtr reply2(manager.get(request));
2775 DataReader reader1(reply1);
2776 DataReader reader2(reply2);
2777 QSignalSpy spy(reply1.data(), SIGNAL(finished()));
2779 QVERIFY(waitForFinish(reply2) == Success);
2780 QVERIFY(waitForFinish(reply1) == Success);
2782 QCOMPARE(reply1->url(), request.url());
2783 QCOMPARE(reply2->url(), request.url());
2784 QCOMPARE(reply1->error(), QNetworkReply::NoError);
2785 QCOMPARE(reply2->error(), QNetworkReply::NoError);
2786 QCOMPARE(reply1->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2787 QCOMPARE(reply2->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2789 QCOMPARE(reply1->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
2790 QCOMPARE(reply2->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
2791 QCOMPARE(qint64(reader1.data.size()), reference.size());
2792 QCOMPARE(qint64(reader2.data.size()), reference.size());
2794 QByteArray referenceData = reference.readAll();
2795 QCOMPARE(reader1.data, referenceData);
2796 QCOMPARE(reader2.data, referenceData);
2799 void tst_QNetworkReply::ioGetFromHttpWithReuseSequential()
2801 QFile reference(testDataDir + "/rfc3252.txt");
2802 QVERIFY(reference.open(QIODevice::ReadOnly));
2804 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
2806 QNetworkReplyPtr reply(manager.get(request));
2807 DataReader reader(reply);
2809 QVERIFY(waitForFinish(reply) == Success);
2811 QCOMPARE(reply->url(), request.url());
2812 QCOMPARE(reply->error(), QNetworkReply::NoError);
2813 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2815 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
2816 QCOMPARE(qint64(reader.data.size()), reference.size());
2818 QCOMPARE(reader.data, reference.readAll());
2822 // rinse and repeat:
2824 QNetworkReplyPtr reply(manager.get(request));
2825 DataReader reader(reply);
2827 QVERIFY(waitForFinish(reply) == Success);
2829 QCOMPARE(reply->url(), request.url());
2830 QCOMPARE(reply->error(), QNetworkReply::NoError);
2831 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2833 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
2834 QCOMPARE(qint64(reader.data.size()), reference.size());
2836 QCOMPARE(reader.data, reference.readAll());
2840 void tst_QNetworkReply::ioGetFromHttpWithAuth_data()
2842 QTest::addColumn<QUrl>("url");
2843 QTest::addColumn<QByteArray>("expectedData");
2844 QTest::addColumn<int>("expectedAuth");
2846 QFile reference(testDataDir + "/rfc3252.txt");
2847 reference.open(QIODevice::ReadOnly);
2848 QByteArray referenceData = reference.readAll();
2849 QTest::newRow("basic") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt") << referenceData << 1;
2850 QTest::newRow("digest") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/auth-digest/") << QByteArray("digest authentication successful\n") << 1;
2851 //if url contains username & password, then it should be used
2852 QTest::newRow("basic-in-url") << QUrl("http://httptest:httptest@" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt") << referenceData << 0;
2853 QTest::newRow("digest-in-url") << QUrl("http://httptest:httptest@" + QtNetworkSettings::serverName() + "/qtest/auth-digest/") << QByteArray("digest authentication successful\n") << 0;
2854 // if url contains incorrect credentials, expect QNAM to ask for good ones (even if cached - matches behaviour of browsers)
2855 QTest::newRow("basic-bad-user-in-url") << QUrl("http://baduser:httptest@" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt") << referenceData << 3;
2856 QTest::newRow("basic-bad-password-in-url") << QUrl("http://httptest:wrong@" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt") << referenceData << 3;
2857 QTest::newRow("digest-bad-user-in-url") << QUrl("http://baduser:httptest@" + QtNetworkSettings::serverName() + "/qtest/auth-digest/") << QByteArray("digest authentication successful\n") << 3;
2858 QTest::newRow("digest-bad-password-in-url") << QUrl("http://httptest:wrong@" + QtNetworkSettings::serverName() + "/qtest/auth-digest/") << QByteArray("digest authentication successful\n") << 3;
2861 void tst_QNetworkReply::ioGetFromHttpWithAuth()
2863 // This test sends three requests
2864 // The first two in parallel
2865 // The third after the first two finished
2868 QFETCH(QByteArray, expectedData);
2869 QFETCH(int, expectedAuth);
2870 QNetworkRequest request(url);
2872 QNetworkReplyPtr reply1(manager.get(request));
2873 QNetworkReplyPtr reply2(manager.get(request));
2874 DataReader reader1(reply1);
2875 DataReader reader2(reply2);
2876 QSignalSpy finishedspy(reply1.data(), SIGNAL(finished()));
2878 QSignalSpy authspy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2879 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
2880 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2882 QVERIFY(waitForFinish(reply2) == Success);
2883 QVERIFY(waitForFinish(reply1) == Success);
2885 manager.disconnect(SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
2886 this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2888 QCOMPARE(reply1->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2889 QCOMPARE(reply2->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2890 QCOMPARE(reader1.data, expectedData);
2891 QCOMPARE(reader2.data, expectedData);
2893 QCOMPARE(authspy.count(), (expectedAuth ? 1 : 0));
2894 expectedAuth = qMax(0, expectedAuth - 1);
2897 // rinse and repeat:
2899 QNetworkReplyPtr reply(manager.get(request));
2900 DataReader reader(reply);
2902 QSignalSpy authspy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2903 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
2904 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2906 QVERIFY(waitForFinish(reply) == Success);
2908 manager.disconnect(SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
2909 this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2911 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2912 QCOMPARE(reader.data, expectedData);
2914 QCOMPARE(authspy.count(), (expectedAuth ? 1 : 0));
2915 expectedAuth = qMax(0, expectedAuth - 1);
2918 // now check with synchronous calls:
2920 request.setAttribute(
2921 QNetworkRequest::SynchronousRequestAttribute,
2924 QSignalSpy authspy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2925 QNetworkReplyPtr replySync(manager.get(request));
2926 QVERIFY(replySync->isFinished()); // synchronous
2928 // bad credentials in a synchronous request should just fail
2929 QCOMPARE(replySync->error(), QNetworkReply::AuthenticationRequiredError);
2931 QCOMPARE(authspy.count(), 0);
2933 // we cannot use a data reader here, since that connects to the readyRead signal,
2934 // just use readAll()
2936 // the only thing we check here is that the auth cache was used when using synchronous requests
2937 QCOMPARE(replySync->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2938 QCOMPARE(replySync->readAll(), expectedData);
2942 // check that credentials are used from cache if the same url is requested without credentials
2944 url.setUserInfo(QString());
2945 request.setUrl(url);
2946 request.setAttribute(
2947 QNetworkRequest::SynchronousRequestAttribute,
2950 QSignalSpy authspy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2951 QNetworkReplyPtr replySync(manager.get(request));
2952 QVERIFY(replySync->isFinished()); // synchronous
2954 // bad credentials in a synchronous request should just fail
2955 QCOMPARE(replySync->error(), QNetworkReply::AuthenticationRequiredError);
2957 QCOMPARE(authspy.count(), 0);
2959 // we cannot use a data reader here, since that connects to the readyRead signal,
2960 // just use readAll()
2962 // the only thing we check here is that the auth cache was used when using synchronous requests
2963 QCOMPARE(replySync->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2964 QCOMPARE(replySync->readAll(), expectedData);
2969 void tst_QNetworkReply::ioGetFromHttpWithAuthSynchronous()
2971 // verify that we do not enter an endless loop with synchronous calls and wrong credentials
2972 // the case when we succeed with the login is tested in ioGetFromHttpWithAuth()
2974 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt"));
2975 request.setAttribute(
2976 QNetworkRequest::SynchronousRequestAttribute,
2979 QSignalSpy authspy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2980 QNetworkReplyPtr replySync(manager.get(request));
2981 QVERIFY(replySync->isFinished()); // synchronous
2982 QCOMPARE(replySync->error(), QNetworkReply::AuthenticationRequiredError);
2983 QCOMPARE(authspy.count(), 0);
2984 QCOMPARE(replySync->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 401);
2987 void tst_QNetworkReply::ioGetFromHttpWithProxyAuth()
2989 // This test sends three requests
2990 // The first two in parallel
2991 // The third after the first two finished
2992 QFile reference(testDataDir + "/rfc3252.txt");
2993 QVERIFY(reference.open(QIODevice::ReadOnly));
2995 QNetworkProxy proxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129);
2996 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
2998 manager.setProxy(proxy);
2999 QNetworkReplyPtr reply1(manager.get(request));
3000 QNetworkReplyPtr reply2(manager.get(request));
3001 manager.setProxy(QNetworkProxy());
3003 DataReader reader1(reply1);
3004 DataReader reader2(reply2);
3005 QSignalSpy finishedspy(reply1.data(), SIGNAL(finished()));
3007 QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3008 connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3009 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3011 QVERIFY(waitForFinish(reply2) == Success);
3012 QVERIFY(waitForFinish(reply1) == Success);
3014 manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3015 this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3017 QCOMPARE(reply1->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
3018 QCOMPARE(reply2->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
3019 QByteArray referenceData = reference.readAll();
3020 QCOMPARE(reader1.data, referenceData);
3021 QCOMPARE(reader2.data, referenceData);
3023 QCOMPARE(authspy.count(), 1);
3027 // rinse and repeat:
3029 manager.setProxy(proxy);
3030 QNetworkReplyPtr reply(manager.get(request));
3031 DataReader reader(reply);
3032 manager.setProxy(QNetworkProxy());
3034 QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3035 connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3036 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3038 QVERIFY(waitForFinish(reply) == Success);
3040 manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3041 this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3043 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
3044 QCOMPARE(reader.data, reference.readAll());
3046 QCOMPARE(authspy.count(), 0);
3049 // now check with synchronous calls:
3052 request.setAttribute(
3053 QNetworkRequest::SynchronousRequestAttribute,
3056 QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3057 QNetworkReplyPtr replySync(manager.get(request));
3058 QVERIFY(replySync->isFinished()); // synchronous
3059 QCOMPARE(authspy.count(), 0);
3061 // we cannot use a data reader here, since that connects to the readyRead signal,
3062 // just use readAll()
3064 // the only thing we check here is that the proxy auth cache was used when using synchronous requests
3065 QCOMPARE(replySync->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
3066 QCOMPARE(replySync->readAll(), reference.readAll());
3070 void tst_QNetworkReply::ioGetFromHttpWithProxyAuthSynchronous()
3072 // verify that we do not enter an endless loop with synchronous calls and wrong credentials
3073 // the case when we succeed with the login is tested in ioGetFromHttpWithAuth()
3075 QNetworkProxy proxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129);
3076 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
3077 manager.setProxy(proxy);
3078 request.setAttribute(
3079 QNetworkRequest::SynchronousRequestAttribute,
3082 QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3083 QNetworkReplyPtr replySync(manager.get(request));
3084 manager.setProxy(QNetworkProxy()); // reset
3085 QVERIFY(replySync->isFinished()); // synchronous
3086 QCOMPARE(replySync->error(), QNetworkReply::ProxyAuthenticationRequiredError);
3087 QCOMPARE(authspy.count(), 0);
3088 QCOMPARE(replySync->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 407);
3091 void tst_QNetworkReply::ioGetFromHttpWithSocksProxy()
3093 // HTTP caching proxies are tested by the above function
3094 // test SOCKSv5 proxies too
3096 QFile reference(testDataDir + "/rfc3252.txt");
3097 QVERIFY(reference.open(QIODevice::ReadOnly));
3099 QNetworkProxy proxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080);
3100 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
3102 manager.setProxy(proxy);
3103 QNetworkReplyPtr reply(manager.get(request));
3104 DataReader reader(reply);
3105 manager.setProxy(QNetworkProxy());
3107 QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3108 connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3109 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3111 QVERIFY(waitForFinish(reply) == Success);
3113 manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3114 this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3116 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
3117 QCOMPARE(reader.data, reference.readAll());
3119 QCOMPARE(authspy.count(), 0);
3122 // set an invalid proxy just to make sure that we can't load
3123 proxy = QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1079);
3125 manager.setProxy(proxy);
3126 QNetworkReplyPtr reply(manager.get(request));
3127 DataReader reader(reply);
3128 manager.setProxy(QNetworkProxy());
3130 QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3131 connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3132 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3134 QVERIFY(waitForFinish(reply) == Failure);
3136 manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3137 this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3139 QVERIFY(!reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).isValid());
3140 QVERIFY(reader.data.isEmpty());
3142 QVERIFY(int(reply->error()) > 0);
3143 QEXPECT_FAIL("", "QTcpSocket doesn't return enough information yet", Continue);
3144 QCOMPARE(int(reply->error()), int(QNetworkReply::ProxyConnectionRefusedError));
3146 QCOMPARE(authspy.count(), 0);
3151 void tst_QNetworkReply::ioGetFromHttpsWithSslErrors()
3153 QFile reference(testDataDir + "/rfc3252.txt");
3154 QVERIFY(reference.open(QIODevice::ReadOnly));
3156 QNetworkRequest request(QUrl("https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
3157 QNetworkReplyPtr reply(manager.get(request));
3158 DataReader reader(reply);
3160 QSignalSpy sslspy(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)));
3161 connect(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
3162 SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
3163 connect(reply, SIGNAL(metaDataChanged()), SLOT(storeSslConfiguration()));
3165 QVERIFY(waitForFinish(reply) == Success);
3167 manager.disconnect(SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
3168 this, SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
3170 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
3171 QCOMPARE(reader.data, reference.readAll());
3173 QCOMPARE(sslspy.count(), 1);
3175 QVERIFY(!storedSslConfiguration.isNull());
3176 QVERIFY(!reply->sslConfiguration().isNull());
3179 void tst_QNetworkReply::ioGetFromHttpsWithIgnoreSslErrors()
3181 // same as above, except that we call ignoreSslErrors and don't connect
3182 // to the sslErrors() signal (which is *still* emitted)
3184 QFile reference(testDataDir + "/rfc3252.txt");
3185 QVERIFY(reference.open(QIODevice::ReadOnly));
3187 QNetworkRequest request(QUrl("https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
3189 QNetworkReplyPtr reply(manager.get(request));
3190 reply->ignoreSslErrors();
3191 DataReader reader(reply);
3193 QSignalSpy sslspy(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)));
3194 connect(reply, SIGNAL(metaDataChanged()), SLOT(storeSslConfiguration()));
3196 QVERIFY(waitForFinish(reply) == Success);
3198 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
3199 QCOMPARE(reader.data, reference.readAll());
3201 QCOMPARE(sslspy.count(), 1);
3203 QVERIFY(!storedSslConfiguration.isNull());
3204 QVERIFY(!reply->sslConfiguration().isNull());
3207 void tst_QNetworkReply::ioGetFromHttpsWithSslHandshakeError()
3209 QFile reference(testDataDir + "/rfc3252.txt");
3210 QVERIFY(reference.open(QIODevice::ReadOnly));
3212 QNetworkRequest request(QUrl("https://" + QtNetworkSettings::serverName() + ":80"));
3214 QNetworkReplyPtr reply(manager.get(request));
3215 reply->ignoreSslErrors();
3216 DataReader reader(reply);
3218 QSignalSpy sslspy(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)));
3219 connect(reply, SIGNAL(metaDataChanged()), SLOT(storeSslConfiguration()));
3221 QVERIFY(waitForFinish(reply) == Failure);
3223 QCOMPARE(reply->error(), QNetworkReply::SslHandshakeFailedError);
3224 QCOMPARE(sslspy.count(), 0);
3228 void tst_QNetworkReply::ioGetFromHttpBrokenServer_data()
3230 QTest::addColumn<QByteArray>("dataToSend");
3231 QTest::addColumn<bool>("doDisconnect");
3233 QTest::newRow("no-newline") << QByteArray("Hello World") << false;
3235 // these are OK now, we just eat the lonely newlines
3236 //QTest::newRow("just-newline") << QByteArray("\r\n") << false;
3237 //QTest::newRow("just-2newline") << QByteArray("\r\n\r\n") << false;
3239 QTest::newRow("with-newlines") << QByteArray("Long first line\r\nLong second line") << false;
3240 QTest::newRow("with-newlines2") << QByteArray("\r\nSecond line") << false;
3241 QTest::newRow("with-newlines3") << QByteArray("ICY\r\nSecond line") << false;
3242 QTest::newRow("invalid-version") << QByteArray("HTTP/123 200 \r\n") << false;
3243 QTest::newRow("invalid-version2") << QByteArray("HTTP/a.\033 200 \r\n") << false;
3244 QTest::newRow("invalid-reply-code") << QByteArray("HTTP/1.0 fuu \r\n") << false;
3246 QTest::newRow("empty+disconnect") << QByteArray() << true;
3248 QTest::newRow("no-newline+disconnect") << QByteArray("Hello World") << true;
3249 QTest::newRow("just-newline+disconnect") << QByteArray("\r\n") << true;
3250 QTest::newRow("just-2newline+disconnect") << QByteArray("\r\n\r\n") << true;
3251 QTest::newRow("with-newlines+disconnect") << QByteArray("Long first line\r\nLong second line") << true;
3252 QTest::newRow("with-newlines2+disconnect") << QByteArray("\r\nSecond line") << true;
3253 QTest::newRow("with-newlines3+disconnect") << QByteArray("ICY\r\nSecond line") << true;
3255 QTest::newRow("invalid-version+disconnect") << QByteArray("HTTP/123 200 ") << true;
3256 QTest::newRow("invalid-version2+disconnect") << QByteArray("HTTP/a.\033 200 ") << true;
3257 QTest::newRow("invalid-reply-code+disconnect") << QByteArray("HTTP/1.0 fuu ") << true;
3259 QTest::newRow("immediate disconnect") << QByteArray("") << true;
3260 QTest::newRow("justHalfStatus+disconnect") << QByteArray("HTTP/1.1") << true;
3261 QTest::newRow("justStatus+disconnect") << QByteArray("HTTP/1.1 200 OK\r\n") << true;
3262 QTest::newRow("justStatusAndHalfHeaders+disconnect") << QByteArray("HTTP/1.1 200 OK\r\nContent-L") << true;
3264 QTest::newRow("halfContent+disconnect") << QByteArray("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\nAB") << true;
3268 void tst_QNetworkReply::ioGetFromHttpBrokenServer()
3270 QFETCH(QByteArray, dataToSend);
3271 QFETCH(bool, doDisconnect);
3272 MiniHttpServer server(dataToSend);
3273 server.doClose = doDisconnect;
3275 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
3276 QNetworkReplyPtr reply(manager.get(request));
3277 QSignalSpy spy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError)));
3279 QVERIFY(waitForFinish(reply) == Failure);
3281 QCOMPARE(reply->url(), request.url());
3282 QCOMPARE(spy.count(), 1);
3283 QVERIFY(reply->error() != QNetworkReply::NoError);
3286 void tst_QNetworkReply::ioGetFromHttpStatus100_data()
3288 QTest::addColumn<QByteArray>("dataToSend");
3289 QTest::addColumn<int>("statusCode");
3290 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;
3291 QTest::newRow("minimal") << QByteArray("HTTP/1.1 100 Continue\n\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") << 200;
3292 QTest::newRow("minimal2") << QByteArray("HTTP/1.1 100 Continue\n\nHTTP/1.0 200 OK\r\n\r\n") << 200;
3293 QTest::newRow("minimal3") << QByteArray("HTTP/1.1 100 Continue\n\nHTTP/1.0 200 OK\n\n") << 200;
3294 QTest::newRow("minimal+404") << QByteArray("HTTP/1.1 100 Continue\n\nHTTP/1.0 204 No Content\r\n\r\n") << 204;
3295 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;
3296 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;
3299 void tst_QNetworkReply::ioGetFromHttpStatus100()
3301 QFETCH(QByteArray, dataToSend);
3302 QFETCH(int, statusCode);
3303 MiniHttpServer server(dataToSend);
3304 server.doClose = true;
3306 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
3307 QNetworkReplyPtr reply(manager.get(request));
3309 QVERIFY(waitForFinish(reply) == Success);
3311 QCOMPARE(reply->url(), request.url());
3312 QCOMPARE(reply->error(), QNetworkReply::NoError);
3313 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), statusCode);
3314 QVERIFY(reply->rawHeader("bla").isNull());
3317 void tst_QNetworkReply::ioGetFromHttpNoHeaders_data()
3319 QTest::addColumn<QByteArray>("dataToSend");
3320 QTest::newRow("justStatus+noheaders+disconnect") << QByteArray("HTTP/1.0 200 OK\r\n\r\n");
3323 void tst_QNetworkReply::ioGetFromHttpNoHeaders()
3325 QFETCH(QByteArray, dataToSend);
3326 MiniHttpServer server(dataToSend);
3327 server.doClose = true;
3329 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
3330 QNetworkReplyPtr reply(manager.get(request));
3332 QVERIFY(waitForFinish(reply) == Success);
3334 QCOMPARE(reply->url(), request.url());
3335 QCOMPARE(reply->error(), QNetworkReply::NoError);
3336 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
3339 void tst_QNetworkReply::ioGetFromHttpWithCache_data()
3341 qRegisterMetaType<MyMemoryCache::CachedContent>();
3342 QTest::addColumn<QByteArray>("dataToSend");
3343 QTest::addColumn<QString>("body");
3344 QTest::addColumn<MyMemoryCache::CachedContent>("cachedReply");
3345 QTest::addColumn<int>("cacheMode");
3346 QTest::addColumn<QStringList>("extraHttpHeaders");
3347 QTest::addColumn<bool>("loadedFromCache");
3348 QTest::addColumn<bool>("networkUsed");
3350 QByteArray reply200 =
3352 "Connection: keep-alive\r\n"
3353 "Content-Type: text/plain\r\n"
3354 "Cache-control: no-cache\r\n"
3355 "Content-length: 8\r\n"
3358 QByteArray reply304 =
3359 "HTTP/1.0 304 Use Cache\r\n"
3360 "Connection: keep-alive\r\n"
3363 QTest::newRow("not-cached,always-network")
3364 << reply200 << "Reloaded" << MyMemoryCache::CachedContent() << int(QNetworkRequest::AlwaysNetwork) << QStringList() << false << true;
3365 QTest::newRow("not-cached,prefer-network")
3366 << reply200 << "Reloaded" << MyMemoryCache::CachedContent() << int(QNetworkRequest::PreferNetwork) << QStringList() << false << true;
3367 QTest::newRow("not-cached,prefer-cache")
3368 << reply200 << "Reloaded" << MyMemoryCache::CachedContent() << int(QNetworkRequest::PreferCache) << QStringList() << false << true;
3370 QDateTime present = QDateTime::currentDateTime().toUTC();
3371 QDateTime past = present.addSecs(-3600);
3372 QDateTime future = present.addSecs(3600);
3373 static const char dateFormat[] = "ddd, dd MMM yyyy hh:mm:ss 'GMT'";
3375 QNetworkCacheMetaData::RawHeaderList rawHeaders;
3376 MyMemoryCache::CachedContent content;
3377 content.second = "Not-reloaded";
3378 content.first.setLastModified(past);
3384 rawHeaders << QNetworkCacheMetaData::RawHeader("Date", QLocale::c().toString(past, dateFormat).toLatin1())
3385 << QNetworkCacheMetaData::RawHeader("Cache-control", "max-age=0"); // isn't used in cache loading
3386 content.first.setRawHeaders(rawHeaders);
3387 content.first.setLastModified(past);
3388 content.first.setExpirationDate(past);
3390 QTest::newRow("expired,200,prefer-network")
3391 << reply200 << "Reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << false << true;
3392 QTest::newRow("expired,200,prefer-cache")
3393 << reply200 << "Reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << false << true;
3395 QTest::newRow("expired,304,prefer-network")
3396 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << true << true;
3397 QTest::newRow("expired,304,prefer-cache")
3398 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << true << true;
3401 // Set to not-expired
3404 rawHeaders << QNetworkCacheMetaData::RawHeader("Date", QLocale::c().toString(past, dateFormat).toLatin1())
3405 << QNetworkCacheMetaData::RawHeader("Cache-control", "max-age=7200"); // isn't used in cache loading
3406 content.first.setRawHeaders(rawHeaders);
3407 content.first.setExpirationDate(future);
3409 QTest::newRow("not-expired,200,always-network")
3410 << reply200 << "Reloaded" << content << int(QNetworkRequest::AlwaysNetwork) << QStringList() << false << true;
3411 QTest::newRow("not-expired,200,prefer-network")
3412 << reply200 << "Not-reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << true << false;
3413 QTest::newRow("not-expired,200,prefer-cache")
3414 << reply200 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << true << false;
3415 QTest::newRow("not-expired,200,always-cache")
3416 << reply200 << "Not-reloaded" << content << int(QNetworkRequest::AlwaysCache) << QStringList() << true << false;
3418 QTest::newRow("not-expired,304,prefer-network")
3419 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << true << false;
3420 QTest::newRow("not-expired,304,prefer-cache")
3421 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << true << false;
3422 QTest::newRow("not-expired,304,always-cache")
3423 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::AlwaysCache) << QStringList() << true << false;
3426 // Set must-revalidate now
3429 rawHeaders << QNetworkCacheMetaData::RawHeader("Date", QLocale::c().toString(past, dateFormat).toLatin1())
3430 << QNetworkCacheMetaData::RawHeader("Cache-control", "max-age=7200, must-revalidate"); // must-revalidate is used
3431 content.first.setRawHeaders(rawHeaders);
3433 QTest::newRow("must-revalidate,200,always-network")
3434 << reply200 << "Reloaded" << content << int(QNetworkRequest::AlwaysNetwork) << QStringList() << false << true;
3435 QTest::newRow("must-revalidate,200,prefer-network")
3436 << reply200 << "Reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << false << true;
3437 QTest::newRow("must-revalidate,200,prefer-cache")
3438 << reply200 << "Reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << false << true;
3439 QTest::newRow("must-revalidate,200,always-cache")
3440 << reply200 << "" << content << int(QNetworkRequest::AlwaysCache) << QStringList() << false << false;
3442 QTest::newRow("must-revalidate,304,prefer-network")
3443 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << true << true;
3444 QTest::newRow("must-revalidate,304,prefer-cache")
3445 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << true << true;
3446 QTest::newRow("must-revalidate,304,always-cache")
3447 << reply304 << "" << content << int(QNetworkRequest::AlwaysCache) << QStringList() << false << false;
3453 rawHeaders << QNetworkCacheMetaData::RawHeader("Date", QLocale::c().toString(past, dateFormat).toLatin1())
3454 << QNetworkCacheMetaData::RawHeader("Cache-control", "max-age=7200"); // isn't used in cache loading
3455 content.first.setRawHeaders(rawHeaders);
3456 content.first.setExpirationDate(future);
3458 QByteArray reply206 =
3460 "Connection: keep-alive\r\n"
3461 "Content-Type: text/plain\r\n"
3462 "Cache-control: no-cache\r\n"
3463 "Content-Range: bytes 2-6/8\r\n"
3464 "Content-length: 4\r\n"
3468 QTest::newRow("partial,dontuse-cache")
3469 << reply206 << "load" << content << int(QNetworkRequest::PreferCache) << (QStringList() << "Range" << "bytes=2-6") << false << true;
3472 void tst_QNetworkReply::ioGetFromHttpWithCache()
3474 QFETCH(QByteArray, dataToSend);
3475 MiniHttpServer server(dataToSend);
3476 server.doClose = false;
3478 MyMemoryCache *memoryCache = new MyMemoryCache(&manager);
3479 manager.setCache(memoryCache);
3481 QFETCH(MyMemoryCache::CachedContent, cachedReply);
3482 QUrl url = "http://localhost:" + QString::number(server.serverPort());
3483 cachedReply.first.setUrl(url);
3484 if (!cachedReply.second.isNull())
3485 memoryCache->cache.insert(url.toEncoded(), cachedReply);
3487 QFETCH(int, cacheMode);
3488 QNetworkRequest request(url);
3489 request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, cacheMode);
3490 request.setAttribute(QNetworkRequest::CacheSaveControlAttribute, false);
3492 QFETCH(QStringList, extraHttpHeaders);
3493 QStringListIterator it(extraHttpHeaders);
3494 while (it.hasNext()) {
3495 QString header = it.next();
3496 QString value = it.next();
3497 request.setRawHeader(header.toLatin1(), value.toLatin1()); // To latin1? Deal with it!
3500 QNetworkReplyPtr reply(manager.get(request));
3502 QVERIFY(waitForFinish(reply) != Timeout);
3504 QTEST(reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool(), "loadedFromCache");
3505 QTEST(server.totalConnections > 0, "networkUsed");
3506 QFETCH(QString, body);
3507 QCOMPARE(reply->readAll().constData(), qPrintable(body));
3510 void tst_QNetworkReply::ioGetWithManyProxies_data()
3512 QTest::addColumn<QList<QNetworkProxy> >("proxyList");
3513 QTest::addColumn<QNetworkProxy>("proxyUsed");
3514 QTest::addColumn<QString>("url");
3515 QTest::addColumn<QNetworkReply::NetworkError>("expectedError");
3517 QList<QNetworkProxy> proxyList;
3519 // All of the other functions test DefaultProxy
3520 // So let's test something else
3522 // Simple tests that work:
3524 // HTTP request with HTTP caching proxy
3525 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129);
3526 QTest::newRow("http-on-http")
3527 << proxyList << proxyList.at(0)
3528 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3529 << QNetworkReply::NoError;
3531 // HTTP request with HTTP transparent proxy
3533 proxyList << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3129);
3534 QTest::newRow("http-on-http2")
3535 << proxyList << proxyList.at(0)
3536 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3537 << QNetworkReply::NoError;
3539 // HTTP request with SOCKS transparent proxy
3541 proxyList << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081);
3542 QTest::newRow("http-on-socks")
3543 << proxyList << proxyList.at(0)
3544 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3545 << QNetworkReply::NoError;
3547 // FTP request with FTP caching proxy
3549 proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121);
3550 QTest::newRow("ftp-on-ftp")
3551 << proxyList << proxyList.at(0)
3552 << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3553 << QNetworkReply::NoError;
3555 // The following test doesn't work because QFtp is too limited
3556 // It can only talk to its own kind of proxies
3558 // FTP request with SOCKSv5 transparent proxy
3560 proxyList << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081);
3561 QTest::newRow("ftp-on-socks")
3562 << proxyList << proxyList.at(0)
3563 << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3564 << QNetworkReply::NoError;
3567 // HTTPS with HTTP transparent proxy
3569 proxyList << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3129);
3570 QTest::newRow("https-on-http")
3571 << proxyList << proxyList.at(0)
3572 << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3573 << QNetworkReply::NoError;
3575 // HTTPS request with SOCKS transparent proxy
3577 proxyList << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081);
3578 QTest::newRow("https-on-socks")
3579 << proxyList << proxyList.at(0)
3580 << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3581 << QNetworkReply::NoError;
3586 // HTTP request with FTP caching proxy
3588 proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121);
3589 QTest::newRow("http-on-ftp")
3590 << proxyList << QNetworkProxy()
3591 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3592 << QNetworkReply::ProxyNotFoundError;
3594 // FTP request with HTTP caching proxy
3596 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129);
3597 QTest::newRow("ftp-on-http")
3598 << proxyList << QNetworkProxy()
3599 << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3600 << QNetworkReply::ProxyNotFoundError;
3602 // FTP request with HTTP caching proxies
3604 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
3605 << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3130);
3606 QTest::newRow("ftp-on-multiple-http")
3607 << proxyList << QNetworkProxy()
3608 << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3609 << QNetworkReply::ProxyNotFoundError;
3612 // HTTPS with HTTP caching proxy
3614 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129);
3615 QTest::newRow("https-on-httptransparent")
3616 << proxyList << QNetworkProxy()
3617 << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3618 << QNetworkReply::ProxyNotFoundError;
3620 // HTTPS with FTP caching proxy
3622 proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121);
3623 QTest::newRow("https-on-ftp")
3624 << proxyList << QNetworkProxy()
3625 << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3626 << QNetworkReply::ProxyNotFoundError;
3629 // Complex requests:
3631 // HTTP request with more than one HTTP proxy
3633 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
3634 << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3130);
3635 QTest::newRow("http-on-multiple-http")
3636 << proxyList << proxyList.at(0)
3637 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3638 << QNetworkReply::NoError;
3640 // HTTP request with HTTP + SOCKS
3642 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
3643 << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081);
3644 QTest::newRow("http-on-http+socks")
3645 << proxyList << proxyList.at(0)
3646 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3647 << QNetworkReply::NoError;
3649 // HTTP request with FTP + HTTP + SOCKS
3651 proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121)
3652 << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
3653 << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081);
3654 QTest::newRow("http-on-ftp+http+socks")
3655 << proxyList << proxyList.at(1) // second proxy should be used
3656 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3657 << QNetworkReply::NoError;
3659 // HTTP request with NoProxy + HTTP
3661 proxyList << QNetworkProxy(QNetworkProxy::NoProxy)
3662 << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129);
3663 QTest::newRow("http-on-noproxy+http")
3664 << proxyList << proxyList.at(0)
3665 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3666 << QNetworkReply::NoError;
3668 // HTTP request with FTP + NoProxy
3670 proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121)
3671 << QNetworkProxy(QNetworkProxy::NoProxy);
3672 QTest::newRow("http-on-ftp+noproxy")
3673 << proxyList << proxyList.at(1) // second proxy should be used
3674 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3675 << QNetworkReply::NoError;
3677 // FTP request with HTTP Caching + FTP
3679 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
3680 << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121);
3681 QTest::newRow("ftp-on-http+ftp")
3682 << proxyList << proxyList.at(1) // second proxy should be used
3683 << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3684 << QNetworkReply::NoError;
3687 // HTTPS request with HTTP Caching + HTTP transparent
3689 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
3690 << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3129);
3691 QTest::newRow("https-on-httpcaching+http")
3692 << proxyList << proxyList.at(1) // second proxy should be used
3693 << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3694 << QNetworkReply::NoError;
3696 // HTTPS request with FTP + HTTP C + HTTP T
3698 proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121)
3699 << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
3700 << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3129);
3701 QTest::newRow("https-on-ftp+httpcaching+http")
3702 << proxyList << proxyList.at(2) // skip the first two
3703 << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3704 << QNetworkReply::NoError;
3708 void tst_QNetworkReply::ioGetWithManyProxies()
3710 // Test proxy factories
3712 QFile reference(testDataDir + "/rfc3252.txt");
3713 QVERIFY(reference.open(QIODevice::ReadOnly));
3715 // set the proxy factory:
3716 QFETCH(QList<QNetworkProxy>, proxyList);
3717 MyProxyFactory *proxyFactory = new MyProxyFactory;
3718 proxyFactory->toReturn = proxyList;
3719 manager.setProxyFactory(proxyFactory);
3721 QFETCH(QString, url);
3723 QNetworkRequest request(theUrl);
3724 QNetworkReplyPtr reply(manager.get(request));
3725 DataReader reader(reply);
3727 QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3728 connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3729 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3731 connect(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
3732 SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
3735 QVERIFY(waitForFinish(reply) != Timeout);
3737 manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3738 this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3740 manager.disconnect(SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
3741 this, SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
3744 QFETCH(QNetworkReply::NetworkError, expectedError);
3745 QEXPECT_FAIL("ftp-on-socks", "QFtp is too limited and won't accept non-FTP proxies", Abort);
3746 QCOMPARE(reply->error(), expectedError);
3748 // Verify that the factory was called properly
3749 QCOMPARE(proxyFactory->callCount, 1);
3750 QCOMPARE(proxyFactory->lastQuery, QNetworkProxyQuery(theUrl));
3752 if (expectedError == QNetworkReply::NoError) {
3753 // request succeeded
3754 QCOMPARE(reader.data, reference.readAll());
3756 // now verify that the proxies worked:
3757 QFETCH(QNetworkProxy, proxyUsed);
3758 if (proxyUsed.type() == QNetworkProxy::NoProxy) {
3759 QCOMPARE(authspy.count(), 0);
3761 if (QByteArray(QTest::currentDataTag()).startsWith("ftp-"))
3762 return; // No authentication with current FTP or with FTP proxies
3763 QCOMPARE(authspy.count(), 1);
3764 QCOMPARE(qvariant_cast<QNetworkProxy>(authspy.at(0).at(0)), proxyUsed);
3768 QCOMPARE(authspy.count(), 0);
3772 void tst_QNetworkReply::ioPutToFileFromFile_data()
3774 QTest::addColumn<QString>("fileName");
3776 QTest::newRow("empty") << (testDataDir + "/empty");
3777 QTest::newRow("real-file") << (testDataDir + "/rfc3252.txt");
3778 QTest::newRow("resource") << ":/resource";
3779 QTest::newRow("search-path") << "testdata:/rfc3252.txt";
3782 void tst_QNetworkReply::ioPutToFileFromFile()
3784 QFETCH(QString, fileName);
3785 QFile sourceFile(fileName);
3786 QFile targetFile(testFileName);
3788 QVERIFY(sourceFile.open(QIODevice::ReadOnly));
3790 QUrl url = QUrl::fromLocalFile(targetFile.fileName());
3791 QNetworkRequest request(url);
3792 QNetworkReplyPtr reply(manager.put(request, &sourceFile));
3794 QVERIFY(waitForFinish(reply) == Success);
3796 QCOMPARE(reply->url(), url);
3797 QCOMPARE(reply->error(), QNetworkReply::NoError);
3798 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
3799 QVERIFY(reply->readAll().isEmpty());
3801 QVERIFY(sourceFile.atEnd());
3802 sourceFile.seek(0); // reset it to the beginning
3804 QVERIFY(targetFile.open(QIODevice::ReadOnly));
3805 QCOMPARE(targetFile.size(), sourceFile.size());
3806 QCOMPARE(targetFile.readAll(), sourceFile.readAll());
3809 void tst_QNetworkReply::ioPutToFileFromSocket_data()
3814 void tst_QNetworkReply::ioPutToFileFromSocket()
3816 QFile file(testFileName);
3818 QUrl url = QUrl::fromLocalFile(file.fileName());
3819 QNetworkRequest request(url);
3821 QFETCH(QByteArray, data);
3822 SocketPair socketpair;
3823 QTRY_VERIFY(socketpair.create()); //QTRY_VERIFY as a workaround for QTBUG-24451
3826 //128k and 2M tests regularly fail. Assumed same characteristics as ioPostToHttpFromSocket
3827 if (data.size() > 1000)
3828 QSKIP("unstable on windows - QTBUG-25386");
3830 socketpair.endPoints[0]->write(data);
3831 QNetworkReplyPtr reply(manager.put(QNetworkRequest(url), socketpair.endPoints[1]));
3832 socketpair.endPoints[0]->close();
3834 QVERIFY(waitForFinish(reply) == Success);
3835 QCOMPARE(reply->error(), QNetworkReply::NoError);
3837 QCOMPARE(reply->url(), url);
3838 QCOMPARE(reply->error(), QNetworkReply::NoError);
3839 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
3840 QVERIFY(reply->readAll().isEmpty());
3842 QVERIFY(file.open(QIODevice::ReadOnly));
3843 QCOMPARE(file.size(), qint64(data.size()));
3844 QByteArray contents = file.readAll();
3845 QCOMPARE(contents, data);
3848 void tst_QNetworkReply::ioPutToFileFromLocalSocket_data()
3853 void tst_QNetworkReply::ioPutToFileFromLocalSocket()
3855 QString socketname = "networkreplytest";
3856 QLocalServer server;
3857 if (!server.listen(socketname)) {
3858 QLocalServer::removeServer(socketname);
3859 QVERIFY(server.listen(socketname));
3861 QLocalSocket active;
3862 active.connectToServer(socketname);
3863 QVERIFY2(server.waitForNewConnection(10), server.errorString().toLatin1().constData());
3864 QVERIFY2(active.waitForConnected(10), active.errorString().toLatin1().constData());
3865 QVERIFY2(server.hasPendingConnections(), server.errorString().toLatin1().constData());
3866 QLocalSocket *passive = server.nextPendingConnection();
3868 QFile file(testFileName);
3869 QUrl url = QUrl::fromLocalFile(file.fileName());
3870 QNetworkRequest request(url);
3872 QFETCH(QByteArray, data);
3875 QNetworkReplyPtr reply(manager.put(QNetworkRequest(url), passive));
3876 passive->setParent(reply.data());
3879 if (!data.isEmpty())
3880 QEXPECT_FAIL("", "QTBUG-18385", Abort);
3882 QVERIFY(waitForFinish(reply) == Success);
3883 QCOMPARE(reply->error(), QNetworkReply::NoError);
3885 QCOMPARE(reply->url(), url);
3886 QCOMPARE(reply->error(), QNetworkReply::NoError);
3887 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
3888 QVERIFY(reply->readAll().isEmpty());
3890 QVERIFY(file.open(QIODevice::ReadOnly));
3891 QCOMPARE(file.size(), qint64(data.size()));
3892 QByteArray contents = file.readAll();
3893 QCOMPARE(contents, data);
3896 // Currently no stdin/out supported for Windows CE.
3897 #ifndef QT_NO_PROCESS
3898 void tst_QNetworkReply::ioPutToFileFromProcess_data()
3903 void tst_QNetworkReply::ioPutToFileFromProcess()
3905 #if defined(Q_OS_WINCE)
3906 QSKIP("Currently no stdin/out supported for Windows CE");
3909 if (qstrcmp(QTest::currentDataTag(), "small") == 0)
3910 QSKIP("When passing a CR-LF-LF sequence through Windows stdio, it gets converted, "
3911 "so this test fails. Disabled on Windows");
3914 QFile file(testFileName);
3916 QUrl url = QUrl::fromLocalFile(file.fileName());
3917 QNetworkRequest request(url);
3919 QFETCH(QByteArray, data);
3921 QString echoExe = echoProcessDir + "/echo";
3922 process.start(echoExe, QStringList("all"));
3923 QVERIFY2(process.waitForStarted(), qPrintable(
3924 QString::fromLatin1("Could not start %1: %2").arg(echoExe, process.errorString())));
3925 process.write(data);
3926 process.closeWriteChannel();
3928 QNetworkReplyPtr reply(manager.put(QNetworkRequest(url), &process));
3930 QVERIFY(waitForFinish(reply) == Success);
3932 QCOMPARE(reply->url(), url);
3933 QCOMPARE(reply->error(), QNetworkReply::NoError);
3934 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
3935 QVERIFY(reply->readAll().isEmpty());
3937 QVERIFY(file.open(QIODevice::ReadOnly));
3938 QCOMPARE(file.size(), qint64(data.size()));
3939 QByteArray contents = file.readAll();
3940 QCOMPARE(contents, data);
3945 void tst_QNetworkReply::ioPutToFtpFromFile_data()
3947 ioPutToFileFromFile_data();
3950 void tst_QNetworkReply::ioPutToFtpFromFile()
3952 QFETCH(QString, fileName);
3953 QFile sourceFile(fileName);
3954 QVERIFY(sourceFile.open(QIODevice::ReadOnly));
3956 QUrl url("ftp://" + QtNetworkSettings::serverName());
3957 url.setPath(QString("/qtest/upload/qnetworkaccess-ioPutToFtpFromFile-%1-%2")
3958 .arg(QTest::currentDataTag())
3959 .arg(uniqueExtension));
3961 QNetworkRequest request(url);
3962 QNetworkReplyPtr reply(manager.put(request, &sourceFile));
3964 QVERIFY(waitForFinish(reply) == Success);
3966 QCOMPARE(reply->url(), url);
3967 QCOMPARE(reply->error(), QNetworkReply::NoError);
3968 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
3969 QVERIFY(reply->readAll().isEmpty());
3971 QVERIFY(sourceFile.atEnd());
3972 sourceFile.seek(0); // reset it to the beginning
3974 // download the file again from FTP to make sure it was uploaded
3976 QNetworkAccessManager qnam;
3977 QNetworkRequest req(url);
3978 QNetworkReply *r = qnam.get(req);
3980 QObject::connect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
3981 QTestEventLoop::instance().enterLoop(3);
3982 QObject::disconnect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
3984 QByteArray uploaded = r->readAll();
3985 QCOMPARE(qint64(uploaded.size()), sourceFile.size());
3986 QCOMPARE(uploaded, sourceFile.readAll());
3989 QObject::connect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
3990 QTestEventLoop::instance().enterLoop(10);
3991 QObject::disconnect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
3994 void tst_QNetworkReply::ioPutToHttpFromFile_data()
3996 ioPutToFileFromFile_data();
3999 void tst_QNetworkReply::ioPutToHttpFromFile()
4001 QFETCH(QString, fileName);
4002 QFile sourceFile(fileName);
4003 QVERIFY(sourceFile.open(QIODevice::ReadOnly));
4005 QUrl url("http://" + QtNetworkSettings::serverName());
4006 url.setPath(QString("/dav/qnetworkaccess-ioPutToHttpFromFile-%1-%2")
4007 .arg(QTest::currentDataTag())
4008 .arg(uniqueExtension));
4010 QNetworkRequest request(url);
4011 QNetworkReplyPtr reply(manager.put(request, &sourceFile));
4013 QVERIFY(waitForFinish(reply) == Success);
4015 QCOMPARE(reply->url(), url);
4016 QCOMPARE(reply->error(), QNetworkReply::NoError);
4018 // verify that the HTTP status code is 201 Created
4019 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 201);
4021 QVERIFY(sourceFile.atEnd());
4022 sourceFile.seek(0); // reset it to the beginning
4024 // download the file again from HTTP to make sure it was uploaded
4026 reply.reset(manager.get(request));
4028 QVERIFY(waitForFinish(reply) == Success);
4030 QCOMPARE(reply->url(), url);
4031 QCOMPARE(reply->error(), QNetworkReply::NoError);
4032 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
4034 QCOMPARE(reply->readAll(), sourceFile.readAll());
4037 void tst_QNetworkReply::ioPostToHttpFromFile_data()
4039 ioPutToFileFromFile_data();
4042 void tst_QNetworkReply::ioPostToHttpFromFile()
4044 QFETCH(QString, fileName);
4045 QFile sourceFile(fileName);
4046 QVERIFY(sourceFile.open(QIODevice::ReadOnly));
4048 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi");
4049 QNetworkRequest request(url);
4050 request.setRawHeader("Content-Type", "application/octet-stream");
4052 QNetworkReplyPtr reply(manager.post(request, &sourceFile));
4054 QVERIFY(waitForFinish(reply) == Success);
4056 QCOMPARE(reply->url(), url);
4057 QCOMPARE(reply->error(), QNetworkReply::NoError);
4059 // verify that the HTTP status code is 200 Ok
4060 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
4062 QVERIFY(sourceFile.atEnd());
4063 sourceFile.seek(0); // reset it to the beginning
4065 QCOMPARE(reply->readAll().trimmed(), md5sum(sourceFile.readAll()).toHex());
4068 void tst_QNetworkReply::ioPostToHttpFromSocket_data()
4070 QTest::addColumn<QByteArray>("data");
4071 QTest::addColumn<QByteArray>("md5sum");
4072 QTest::addColumn<QUrl>("url");
4073 QTest::addColumn<QNetworkProxy>("proxy");
4074 QTest::addColumn<int>("authenticationRequiredCount");
4075 QTest::addColumn<int>("proxyAuthenticationRequiredCount");
4077 for (int i = 0; i < proxies.count(); ++i)
4078 for (int auth = 0; auth < 2; ++auth) {
4081 url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi";
4083 url = "http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi";
4085 QNetworkProxy proxy = proxies.at(i).proxy;
4086 QByteArray testsuffix = QByteArray(auth ? "+auth" : "") + proxies.at(i).tag;
4087 int proxyauthcount = proxies.at(i).requiresAuthentication;
4091 QTest::newRow("empty" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount;
4093 data = "This is a normal message.";
4094 QTest::newRow("generic" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount;
4096 data = "This is a message to show that Qt rocks!\r\n\n";
4097 QTest::newRow("small" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount;
4099 data = QByteArray("abcd\0\1\2\abcd",12);
4100 QTest::newRow("with-nul" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount;
4102 data = QByteArray(4097, '\4');
4103 QTest::newRow("4k+1" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount;
4105 data = QByteArray(128*1024+1, '\177');
4106 QTest::newRow("128k+1" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount;
4110 void tst_QNetworkReply::ioPostToHttpFromSocket()
4112 QFETCH(QByteArray, data);
4114 QFETCH(QNetworkProxy, proxy);
4116 //QTBUG-25386 hits one of the 128k tests 50% of the time, one of the 4k tests rarely (but at least 1%)
4117 if (data.size() > 1000)
4118 QSKIP("unstable on windows - QTBUG-25386");
4120 SocketPair socketpair;
4121 QTRY_VERIFY(socketpair.create()); //QTRY_VERIFY as a workaround for QTBUG-24451
4123 socketpair.endPoints[0]->write(data);
4125 QNetworkRequest request(url);
4126 request.setRawHeader("Content-Type", "application/octet-stream");
4128 manager.setProxy(proxy);
4129 QNetworkReplyPtr reply(manager.post(request, socketpair.endPoints[1]));
4130 socketpair.endPoints[0]->close();
4132 connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
4133 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
4134 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4135 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4137 QSignalSpy authenticationRequiredSpy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4138 QSignalSpy proxyAuthenticationRequiredSpy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
4140 QVERIFY(waitForFinish(reply) == Success);
4142 disconnect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
4143 this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
4144 disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4145 this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4146 QCOMPARE(reply->error(), QNetworkReply::NoError);
4148 QCOMPARE(reply->url(), url);
4149 QCOMPARE(reply->error(), QNetworkReply::NoError);
4150 // verify that the HTTP status code is 200 Ok
4151 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
4153 QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex());
4155 QTEST(authenticationRequiredSpy.count(), "authenticationRequiredCount");
4156 QTEST(proxyAuthenticationRequiredSpy.count(), "proxyAuthenticationRequiredCount");
4159 void tst_QNetworkReply::ioPostToHttpFromSocketSynchronous_data()
4161 QTest::addColumn<QByteArray>("data");
4162 QTest::addColumn<QByteArray>("md5sum");
4166 QTest::newRow("empty") << data << md5sum(data);
4168 data = "This is a normal message.";
4169 QTest::newRow("generic") << data << md5sum(data);
4171 data = "This is a message to show that Qt rocks!\r\n\n";
4172 QTest::newRow("small") << data << md5sum(data);
4174 data = QByteArray("abcd\0\1\2\abcd",12);
4175 QTest::newRow("with-nul") << data << md5sum(data);
4177 data = QByteArray(4097, '\4');
4178 QTest::newRow("4k+1") << data << md5sum(data);
4180 data = QByteArray(128*1024+1, '\177');
4181 QTest::newRow("128k+1") << data << md5sum(data);
4183 data = QByteArray(2*1024*1024+1, '\177');
4184 QTest::newRow("2MB+1") << data << md5sum(data);
4187 void tst_QNetworkReply::ioPostToHttpFromSocketSynchronous()
4189 QFETCH(QByteArray, data);
4191 SocketPair socketpair;
4192 QTRY_VERIFY(socketpair.create()); //QTRY_VERIFY as a workaround for QTBUG-24451
4193 socketpair.endPoints[0]->write(data);
4194 socketpair.endPoints[0]->waitForBytesWritten(5000);
4195 // ### for 4.8: make the socket pair unbuffered, to not read everything in one go in QNetworkReplyImplPrivate::setup()
4196 QTestEventLoop::instance().enterLoop(3);
4198 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi");
4199 QNetworkRequest request(url);
4200 request.setRawHeader("Content-Type", "application/octet-stream");
4201 request.setAttribute(
4202 QNetworkRequest::SynchronousRequestAttribute,
4205 QNetworkReplyPtr reply(manager.post(request, socketpair.endPoints[1]));
4206 QVERIFY(reply->isFinished());
4207 socketpair.endPoints[0]->close();
4209 QCOMPARE(reply->error(), QNetworkReply::NoError);
4211 QCOMPARE(reply->url(), url);
4212 QCOMPARE(reply->error(), QNetworkReply::NoError);
4213 // verify that the HTTP status code is 200 Ok
4214 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
4216 QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex());
4219 // this tests checks if rewinding the POST-data to some place in the middle
4221 void tst_QNetworkReply::ioPostToHttpFromMiddleOfFileToEnd()
4223 QFile sourceFile(testDataDir + "/rfc3252.txt");
4224 QVERIFY(sourceFile.open(QIODevice::ReadOnly));
4225 // seeking to the middle
4226 sourceFile.seek(sourceFile.size() / 2);
4228 QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi";
4229 QNetworkRequest request(url);
4230 request.setRawHeader("Content-Type", "application/octet-stream");
4231 QNetworkReplyPtr reply(manager.post(request, &sourceFile));
4233 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4234 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4236 QVERIFY(waitForFinish(reply) == Success);
4238 disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4239 this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4241 // compare half data
4242 sourceFile.seek(sourceFile.size() / 2);
4243 QByteArray data = sourceFile.readAll();
4244 QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex());
4247 void tst_QNetworkReply::ioPostToHttpFromMiddleOfFileFiveBytes()
4249 QFile sourceFile(testDataDir + "/rfc3252.txt");
4250 QVERIFY(sourceFile.open(QIODevice::ReadOnly));
4251 // seeking to the middle
4252 sourceFile.seek(sourceFile.size() / 2);
4254 QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi";
4255 QNetworkRequest request(url);
4256 request.setRawHeader("Content-Type", "application/octet-stream");
4257 // only send 5 bytes
4258 request.setHeader(QNetworkRequest::ContentLengthHeader, 5);
4259 QVERIFY(request.header(QNetworkRequest::ContentLengthHeader).isValid());
4260 QNetworkReplyPtr reply(manager.post(request, &sourceFile));
4262 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4263 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4265 QVERIFY(waitForFinish(reply) == Success);
4267 disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4268 this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4270 // compare half data
4271 sourceFile.seek(sourceFile.size() / 2);
4272 QByteArray data = sourceFile.read(5);
4273 QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex());
4276 void tst_QNetworkReply::ioPostToHttpFromMiddleOfQBufferFiveBytes()
4278 // test needed since a QBuffer goes with a different codepath than the QFile
4279 // tested in ioPostToHttpFromMiddleOfFileFiveBytes
4280 QBuffer uploadBuffer;
4281 uploadBuffer.open(QIODevice::ReadWrite);
4282 uploadBuffer.write("1234567890");
4283 uploadBuffer.seek(5);
4285 QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi";
4286 QNetworkRequest request(url);
4287 request.setRawHeader("Content-Type", "application/octet-stream");
4288 QNetworkReplyPtr reply(manager.post(request, &uploadBuffer));
4290 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4291 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4293 QVERIFY(waitForFinish(reply) == Success);
4295 disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4296 this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4298 // compare half data
4299 uploadBuffer.seek(5);
4300 QByteArray data = uploadBuffer.read(5);
4301 QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex());
4305 void tst_QNetworkReply::ioPostToHttpNoBufferFlag()
4307 QByteArray data = QByteArray("daaaaaaataaaaaaa");
4308 // create a sequential QIODevice by feeding the data into a local TCP server
4309 SocketPair socketpair;
4310 QTRY_VERIFY(socketpair.create()); //QTRY_VERIFY as a workaround for QTBUG-24451
4311 socketpair.endPoints[0]->write(data);
4313 QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi";
4314 QNetworkRequest request(url);
4315 request.setRawHeader("Content-Type", "application/octet-stream");
4316 // disallow buffering
4317 request.setAttribute(QNetworkRequest::DoNotBufferUploadDataAttribute, true);
4318 request.setHeader(QNetworkRequest::ContentLengthHeader, data.size());
4319 QNetworkReplyPtr reply(manager.post(request, socketpair.endPoints[1]));
4320 socketpair.endPoints[0]->close();
4322 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4323 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4325 QVERIFY(waitForFinish(reply) == Failure);
4327 disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4328 this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4330 // verify: error code is QNetworkReply::ContentReSendError
4331 QCOMPARE(reply->error(), QNetworkReply::ContentReSendError);
4335 class SslServer : public QTcpServer {
4338 SslServer() : socket(0) {};
4339 void incomingConnection(qintptr socketDescriptor) {
4340 QSslSocket *serverSocket = new QSslSocket;
4341 serverSocket->setParent(this);
4343 if (serverSocket->setSocketDescriptor(socketDescriptor)) {
4344 QString testDataDir = QFileInfo(QFINDTESTDATA("rfc3252.txt")).absolutePath();
4345 if (testDataDir.isEmpty())
4346 testDataDir = QCoreApplication::applicationDirPath();
4348 connect(serverSocket, SIGNAL(encrypted()), this, SLOT(encryptedSlot()));
4349 connect(serverSocket, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
4350 serverSocket->setProtocol(QSsl::AnyProtocol);
4351 connect(serverSocket, SIGNAL(sslErrors(const QList<QSslError>&)), serverSocket, SLOT(ignoreSslErrors()));
4352 serverSocket->setLocalCertificate(testDataDir + "/certs/server.pem");
4353 serverSocket->setPrivateKey(testDataDir + "/certs/server.key");
4354 serverSocket->startServerEncryption();
4356 delete serverSocket;
4360 void newEncryptedConnection();
4362 void encryptedSlot() {
4363 socket = (QSslSocket*) sender();
4364 emit newEncryptedConnection();
4366 void readyReadSlot() {
4367 // for the incoming sockets, not the server socket
4368 //qDebug() << static_cast<QSslSocket*>(sender())->bytesAvailable() << static_cast<QSslSocket*>(sender())->encryptedBytesAvailable();
4375 // very similar to ioPostToHttpUploadProgress but for SSL
4376 void tst_QNetworkReply::ioPostToHttpsUploadProgress()
4378 //QFile sourceFile(testDataDir + "/bigfile");
4379 //QVERIFY(sourceFile.open(QIODevice::ReadOnly));
4380 qint64 wantedSize = 2*1024*1024; // 2 MB
4381 QByteArray sourceFile;
4382 // And in the case of SSL, the compression can fool us and let the
4383 // server send the data much faster than expected.
4384 // So better provide random data that cannot be compressed.
4385 for (int i = 0; i < wantedSize; ++i)
4386 sourceFile += (char)qrand();
4388 // emulate a minimal https server
4390 server.listen(QHostAddress(QHostAddress::LocalHost), 0);
4392 // create the request
4393 QUrl url = QUrl(QString("https://127.0.0.1:%1/").arg(server.serverPort()));
4394 QNetworkRequest request(url);
4396 request.setRawHeader("Content-Type", "application/octet-stream");
4397 QNetworkReplyPtr reply(manager.post(request, sourceFile));
4399 QSignalSpy spy(reply.data(), SIGNAL(uploadProgress(qint64,qint64)));
4400 connect(&server, SIGNAL(newEncryptedConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
4401 connect(reply, SIGNAL(sslErrors(const QList<QSslError>&)), reply.data(), SLOT(ignoreSslErrors()));
4403 // get the request started and the incoming socket connected
4404 QTestEventLoop::instance().enterLoop(10);
4405 QVERIFY(!QTestEventLoop::instance().timeout());
4406 QTcpSocket *incomingSocket = server.socket;
4407 QVERIFY(incomingSocket);
4408 disconnect(&server, SIGNAL(newEncryptedConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
4411 incomingSocket->setReadBufferSize(1*1024);
4412 // some progress should have been made
4413 QTRY_VERIFY(!spy.isEmpty());
4414 QList<QVariant> args = spy.last();
4415 QVERIFY(args.at(0).toLongLong() > 0);
4416 // but not everything!
4417 QVERIFY(args.at(0).toLongLong() != sourceFile.size());
4419 // set the read buffer to unlimited
4420 incomingSocket->setReadBufferSize(0);
4421 QTestEventLoop::instance().enterLoop(10);
4422 // progress should be finished
4423 QVERIFY(!spy.isEmpty());
4424 QList<QVariant> args3 = spy.last();
4425 QCOMPARE(args3.at(0).toLongLong(), args3.at(1).toLongLong());
4426 QCOMPARE(args3.at(0).toLongLong(), qint64(sourceFile.size()));
4428 // after sending this, the QNAM should emit finished()
4429 incomingSocket->write("HTTP/1.0 200 OK\r\n");
4430 incomingSocket->write("Content-Length: 0\r\n");
4431 incomingSocket->write("\r\n");
4433 QVERIFY(waitForFinish(reply) == Success);
4435 incomingSocket->close();
4440 void tst_QNetworkReply::ioGetFromBuiltinHttp_data()
4442 QTest::addColumn<bool>("https");
4443 QTest::addColumn<int>("bufferSize");
4444 QTest::newRow("http+unlimited") << false << 0;
4445 QTest::newRow("http+limited") << false << 4096;
4447 QTest::newRow("https+unlimited") << true << 0;
4448 QTest::newRow("https+limited") << true << 4096;
4452 void tst_QNetworkReply::ioGetFromBuiltinHttp()
4454 QFETCH(bool, https);
4455 QFETCH(int, bufferSize);
4457 QByteArray testData;
4458 // Make the data big enough so that it can fill the kernel buffer
4459 // (which seems to hold 202 KB here)
4460 const int wantedSize = 1200 * 1000;
4461 testData.reserve(wantedSize);
4462 // And in the case of SSL, the compression can fool us and let the
4463 // server send the data much faster than expected.
4464 // So better provide random data that cannot be compressed.
4465 for (int i = 0; i < wantedSize; ++i)
4466 testData += (char)qrand();
4468 QByteArray httpResponse = QByteArray("HTTP/1.0 200 OK\r\nContent-Length: ");
4469 httpResponse += QByteArray::number(testData.size());
4470 httpResponse += "\r\n\r\n";
4471 httpResponse += testData;
4473 qDebug() << "Server will send" << (httpResponse.size()-testData.size()) << "bytes of header and"
4474 << testData.size() << "bytes of data";
4476 const bool fillKernelBuffer = bufferSize > 0;
4477 FastSender server(httpResponse, https, fillKernelBuffer);
4479 QUrl url(QString("%1://127.0.0.1:%2/qtest/rfc3252.txt")
4480 .arg(https?"https":"http")
4481 .arg(server.serverPort()));
4482 QNetworkRequest request(url);
4483 QNetworkReplyPtr reply(manager.get(request));
4484 reply->setReadBufferSize(bufferSize);
4485 reply->ignoreSslErrors();
4486 const int rate = 200; // in kB per sec
4487 RateControlledReader reader(server, reply.data(), rate, bufferSize);
4492 QVERIFY(waitForFinish(reply) == Success);
4494 const int elapsedTime = loopTime.elapsed();
4498 qDebug() << "send rate:" << server.transferRate << "B/s";
4499 qDebug() << "receive rate:" << reader.totalBytesRead * 1000 / elapsedTime
4500 << "(it received" << reader.totalBytesRead << "bytes in" << elapsedTime << "ms)";
4502 QCOMPARE(reply->url(), request.url());
4503 QCOMPARE(reply->error(), QNetworkReply::NoError);
4504 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
4506 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), (qint64)testData.size());
4507 if (reader.data.size() < testData.size()) { // oops?
4508 QCOMPARE(reader.data, testData.mid(0, reader.data.size()));
4509 qDebug() << "The data is incomplete, the last" << testData.size() - reader.data.size() << "bytes are missing";
4511 QCOMPARE(reader.data.size(), testData.size());
4512 QCOMPARE(reader.data, testData);
4514 // OK we got the file alright, but did setReadBufferSize work?
4515 QVERIFY(server.transferRate != -1);
4516 if (bufferSize > 0) {
4517 const int allowedDeviation = 16; // TODO find out why the send rate is 13% faster currently
4518 const int minRate = rate * 1024 * (100-allowedDeviation) / 100;
4519 const int maxRate = rate * 1024 * (100+allowedDeviation) / 100;
4520 qDebug() << minRate << "<="<< server.transferRate << "<=" << maxRate << "?";
4521 // The test takes too long to run if sending enough data to overwhelm the
4522 // reciever's kernel buffers.
4523 //QEXPECT_FAIL("http+limited", "Limiting is broken right now, check QTBUG-15065", Continue);
4524 //QEXPECT_FAIL("https+limited", "Limiting is broken right now, check QTBUG-15065", Continue);
4525 //QVERIFY(server.transferRate >= minRate && server.transferRate <= maxRate);
4529 void tst_QNetworkReply::ioPostToHttpUploadProgress()
4531 QFile sourceFile(testDataDir + "/bigfile");
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 QList<QVariant> args = spy.last();
4557 QVERIFY(!args.isEmpty());
4558 QVERIFY(args.at(0).toLongLong() > 0);
4559 // but not everything!
4560 QVERIFY(args.at(0).toLongLong() != sourceFile.size());
4562 // set the read buffer to unlimited
4563 incomingSocket->setReadBufferSize(0);
4564 QTestEventLoop::instance().enterLoop(10);
4565 // progress should be finished
4566 QList<QVariant> args3 = spy.last();
4567 QVERIFY(!args3.isEmpty());
4568 // More progress than before
4569 QVERIFY(args3.at(0).toLongLong() > args.at(0).toLongLong());
4570 QCOMPARE(args3.at(0).toLongLong(), args3.at(1).toLongLong());
4571 // And actually finished..
4572 QCOMPARE(args3.at(0).toLongLong(), sourceFile.size());
4574 // after sending this, the QNAM should emit finished()
4575 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
4576 incomingSocket->write("HTTP/1.0 200 OK\r\n");
4577 incomingSocket->write("Content-Length: 0\r\n");
4578 incomingSocket->write("\r\n");
4579 QTestEventLoop::instance().enterLoop(10);
4580 // not timeouted -> finished() was emitted
4581 QVERIFY(!QTestEventLoop::instance().timeout());
4583 incomingSocket->close();
4587 void tst_QNetworkReply::ioPostToHttpEmptyUploadProgress()
4591 QBuffer buffer(&ba,0);
4592 QVERIFY(buffer.open(QIODevice::ReadOnly));
4594 // emulate a minimal http server
4596 server.listen(QHostAddress(QHostAddress::LocalHost), 0);
4598 // create the request
4599 QUrl url = QUrl(QString("http://127.0.0.1:%1/").arg(server.serverPort()));
4600 QNetworkRequest request(url);
4601 request.setRawHeader("Content-Type", "application/octet-stream");
4602 QNetworkReplyPtr reply(manager.post(request, &buffer));
4603 QSignalSpy spy(reply.data(), SIGNAL(uploadProgress(qint64,qint64)));
4604 connect(&server, SIGNAL(newConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
4607 // get the request started and the incoming socket connected
4608 QTestEventLoop::instance().enterLoop(10);
4609 QVERIFY(!QTestEventLoop::instance().timeout());
4610 QTcpSocket *incomingSocket = server.nextPendingConnection();
4611 QVERIFY(incomingSocket);
4613 // after sending this, the QNAM should emit finished()
4614 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
4615 incomingSocket->write("HTTP/1.0 200 OK\r\n");
4616 incomingSocket->write("Content-Length: 0\r\n");
4617 incomingSocket->write("\r\n");
4618 incomingSocket->flush();
4619 QTestEventLoop::instance().enterLoop(10);
4620 // not timeouted -> finished() was emitted
4621 QVERIFY(!QTestEventLoop::instance().timeout());
4623 // final check: only 1 uploadProgress has been emitted
4624 QVERIFY(spy.length() == 1);
4625 QList<QVariant> args = spy.last();
4626 QVERIFY(!args.isEmpty());
4627 QCOMPARE(args.at(0).toLongLong(), buffer.size());
4628 QCOMPARE(args.at(0).toLongLong(), buffer.size());
4630 incomingSocket->close();
4634 void tst_QNetworkReply::lastModifiedHeaderForFile()
4636 QFileInfo fileInfo(testDataDir + "/bigfile");
4637 QVERIFY(fileInfo.exists());
4639 QUrl url = QUrl::fromLocalFile(fileInfo.filePath());
4641 QNetworkRequest request(url);
4642 QNetworkReplyPtr reply(manager.head(request));
4644 QVERIFY(waitForFinish(reply) == Success);
4646 QDateTime header = reply->header(QNetworkRequest::LastModifiedHeader).toDateTime();
4647 QCOMPARE(header, fileInfo.lastModified());
4650 void tst_QNetworkReply::lastModifiedHeaderForHttp()
4652 // Tue, 22 May 2007 12:04:57 GMT according to webserver
4653 QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/fluke.gif";
4655 QNetworkRequest request(url);
4656 QNetworkReplyPtr reply(manager.head(request));
4658 QVERIFY(waitForFinish(reply) == Success);
4660 QDateTime header = reply->header(QNetworkRequest::LastModifiedHeader).toDateTime();
4661 QDateTime realDate = QDateTime::fromString("2007-05-22T12:04:57", Qt::ISODate);
4662 realDate.setTimeSpec(Qt::UTC);
4664 QCOMPARE(header, realDate);
4667 void tst_QNetworkReply::httpCanReadLine()
4669 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
4670 QNetworkReplyPtr reply(manager.get(request));
4672 QVERIFY(waitForFinish(reply) == Success);
4674 QCOMPARE(reply->error(), QNetworkReply::NoError);
4676 QVERIFY(reply->canReadLine());
4677 QVERIFY(!reply->readAll().isEmpty());
4678 QVERIFY(!reply->canReadLine());
4681 void tst_QNetworkReply::rateControl_data()
4683 QTest::addColumn<int>("rate");
4685 QTest::newRow("15") << 15;
4686 QTest::newRow("40") << 40;
4687 QTest::newRow("73") << 73;
4688 QTest::newRow("80") << 80;
4689 QTest::newRow("125") << 125;
4690 QTest::newRow("250") << 250;
4691 QTest::newRow("1024") << 1024;
4694 void tst_QNetworkReply::rateControl()
4696 QSKIP("Test disabled -- only for manual purposes");
4697 // this function tests that we aren't reading from the network
4698 // faster than the data is being consumed.
4701 #if !defined(QT_BUILD_INTERNAL)
4702 QSKIP("backend for testing not available!");
4705 // ask for 20 seconds worth of data
4706 FastSender sender(20 * rate * 1024);
4708 QNetworkRequest request("debugpipe://localhost:" + QString::number(sender.serverPort()));
4709 QNetworkReplyPtr reply(manager.get(request));
4710 reply->setReadBufferSize(32768);
4711 QSignalSpy errorSpy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError)));
4713 RateControlledReader reader(sender, reply.data(), rate, 20);
4715 // this test is designed to run for 25 seconds at most
4719 QVERIFY(waitForFinish(reply) == Success);
4721 int elapsedTime = loopTime.elapsed();
4723 if (!errorSpy.isEmpty()) {
4724 qDebug() << "ERROR!" << errorSpy[0][0] << reply->errorString();
4727 qDebug() << "tst_QNetworkReply::rateControl" << "send rate:" << sender.transferRate;
4728 qDebug() << "tst_QNetworkReply::rateControl" << "receive rate:" << reader.totalBytesRead * 1000 / elapsedTime
4729 << "(it received" << reader.totalBytesRead << "bytes in" << elapsedTime << "ms)";
4733 QCOMPARE(reply->url(), request.url());
4734 QCOMPARE(reply->error(), QNetworkReply::NoError);
4736 QVERIFY(sender.transferRate != -1);
4737 int minRate = rate * 1024 * 9 / 10;
4738 int maxRate = rate * 1024 * 11 / 10;
4739 QVERIFY(sender.transferRate >= minRate);
4740 QVERIFY(sender.transferRate <= maxRate);
4743 void tst_QNetworkReply::downloadProgress_data()
4745 QTest::addColumn<int>("loopCount");
4747 QTest::newRow("empty") << 0;
4748 QTest::newRow("small") << 4;
4749 QTest::newRow("big") << 4096;
4752 void tst_QNetworkReply::downloadProgress()
4754 #if !defined(QT_BUILD_INTERNAL)
4755 QSKIP("backend for testing not available!");
4758 QVERIFY(server.listen());
4760 QNetworkRequest request("debugpipe://127.0.0.1:" + QString::number(server.serverPort()) + "/?bare=1");
4761 QNetworkReplyPtr reply(manager.get(request));
4762 QSignalSpy spy(reply.data(), SIGNAL(downloadProgress(qint64,qint64)));
4763 connect(reply, SIGNAL(downloadProgress(qint64,qint64)),
4764 &QTestEventLoop::instance(), SLOT(exitLoop()));
4765 QVERIFY(spy.isValid());
4766 QVERIFY(!reply->isFinished());
4767 QVERIFY(reply->isRunning());
4769 QCoreApplication::instance()->processEvents();
4770 if (!server.hasPendingConnections())
4771 server.waitForNewConnection(1000);
4772 QVERIFY(server.hasPendingConnections());
4773 QCOMPARE(spy.count(), 0);
4775 QByteArray data(128, 'a');
4776 QTcpSocket *sender = server.nextPendingConnection();
4779 QFETCH(int, loopCount);
4780 for (int i = 1; i <= loopCount; ++i) {
4781 sender->write(data);
4782 QVERIFY2(sender->waitForBytesWritten(2000), "Network timeout");
4785 QTestEventLoop::instance().enterLoop(2);
4786 QVERIFY(!QTestEventLoop::instance().timeout());
4787 QVERIFY(spy.count() > 0);
4788 QVERIFY(!reply->isFinished());
4789 QVERIFY(reply->isRunning());
4791 QList<QVariant> args = spy.last();
4792 QCOMPARE(args.at(0).toInt(), i*data.size());
4793 QCOMPARE(args.at(1).toInt(), -1);
4796 // close the connection:
4800 QTestEventLoop::instance().enterLoop(2);
4801 QCOMPARE(reply->error(), QNetworkReply::NoError);
4802 QVERIFY(!QTestEventLoop::instance().timeout());
4803 QVERIFY(spy.count() > 0);
4804 QVERIFY(!reply->isRunning());
4805 QVERIFY(reply->isFinished());
4807 QList<QVariant> args = spy.last();
4808 QCOMPARE(args.at(0).toInt(), loopCount * data.size());
4809 QCOMPARE(args.at(1).toInt(), loopCount * data.size());
4812 void tst_QNetworkReply::uploadProgress_data()
4817 void tst_QNetworkReply::uploadProgress()
4819 QFETCH(QByteArray, data);
4820 #if !defined(QT_BUILD_INTERNAL)
4821 QSKIP("backend for testing not available!");
4824 QVERIFY(server.listen());
4826 QNetworkRequest request("debugpipe://127.0.0.1:" + QString::number(server.serverPort()) + "/?bare=1");
4827 QNetworkReplyPtr reply(manager.put(request, data));
4828 QSignalSpy spy(reply.data(), SIGNAL(uploadProgress(qint64,qint64)));
4829 QSignalSpy finished(reply.data(), SIGNAL(finished()));
4830 QVERIFY(spy.isValid());
4831 QVERIFY(finished.isValid());
4833 QCoreApplication::instance()->processEvents();
4834 if (!server.hasPendingConnections())
4835 server.waitForNewConnection(1000);
4836 QVERIFY(server.hasPendingConnections());
4838 QTcpSocket *receiver = server.nextPendingConnection();
4839 if (finished.count() == 0) {
4840 // it's not finished yet, so wait for it to be
4841 QVERIFY(waitForFinish(reply) == Success);
4845 QVERIFY(finished.count() > 0);
4846 QVERIFY(spy.count() > 0);
4848 QList<QVariant> args = spy.last();
4849 QCOMPARE(args.at(0).toInt(), data.size());
4850 QCOMPARE(args.at(1).toInt(), data.size());
4853 void tst_QNetworkReply::chaining_data()
4858 void tst_QNetworkReply::chaining()
4860 QTemporaryFile sourceFile(QDir::currentPath() + "/temp-XXXXXX");
4861 sourceFile.setAutoRemove(true);
4862 QVERIFY(sourceFile.open());
4864 QFETCH(QByteArray, data);
4865 QVERIFY(sourceFile.write(data) == data.size());
4867 QCOMPARE(sourceFile.size(), qint64(data.size()));
4869 QNetworkRequest request(QUrl::fromLocalFile(sourceFile.fileName()));
4870 QNetworkReplyPtr getReply(manager.get(request));
4872 QFile targetFile(testFileName);
4873 QUrl url = QUrl::fromLocalFile(targetFile.fileName());
4874 request.setUrl(url);
4875 QNetworkReplyPtr putReply(manager.put(request, getReply.data()));
4877 QVERIFY(waitForFinish(putReply) == Success);
4879 QCOMPARE(getReply->url(), QUrl::fromLocalFile(sourceFile.fileName()));
4880 QCOMPARE(getReply->error(), QNetworkReply::NoError);
4881 QCOMPARE(getReply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), sourceFile.size());
4883 QCOMPARE(putReply->url(), url);
4884 QCOMPARE(putReply->error(), QNetworkReply::NoError);
4885 QCOMPARE(putReply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
4886 QVERIFY(putReply->readAll().isEmpty());
4888 QVERIFY(sourceFile.atEnd());
4889 sourceFile.seek(0); // reset it to the beginning
4891 QVERIFY(targetFile.open(QIODevice::ReadOnly));
4892 QCOMPARE(targetFile.size(), sourceFile.size());
4893 QCOMPARE(targetFile.readAll(), sourceFile.readAll());
4896 void tst_QNetworkReply::receiveCookiesFromHttp_data()
4898 QTest::addColumn<QString>("cookieString");
4899 QTest::addColumn<QList<QNetworkCookie> >("expectedCookiesFromHttp");
4900 QTest::addColumn<QList<QNetworkCookie> >("expectedCookiesInJar");
4902 QTest::newRow("empty") << "" << QList<QNetworkCookie>() << QList<QNetworkCookie>();
4904 QList<QNetworkCookie> header, jar;
4905 QNetworkCookie cookie("a", "b");
4907 cookie.setDomain(QtNetworkSettings::serverName());
4908 cookie.setPath("/qtest/cgi-bin/");
4910 QTest::newRow("simple-cookie") << "a=b" << header << jar;
4912 header << QNetworkCookie("c", "d");
4913 cookie.setName("c");
4914 cookie.setValue("d");
4916 QTest::newRow("two-cookies") << "a=b, c=d" << header << jar;
4917 QTest::newRow("two-cookies-2") << "a=b\nc=d" << header << jar;
4921 cookie = QNetworkCookie("a", "b");
4922 cookie.setPath("/not/part-of-path");
4924 cookie.setDomain(QtNetworkSettings::serverName());
4926 QTest::newRow("invalid-cookie-path") << "a=b; path=/not/part-of-path" << header << jar;
4929 cookie = QNetworkCookie("a", "b");
4930 cookie.setDomain(".example.com");
4933 QTest::newRow("invalid-cookie-domain") << "a=b; domain=.example.com" << header << jar;
4936 void tst_QNetworkReply::receiveCookiesFromHttp()
4938 QFETCH(QString, cookieString);
4940 QByteArray data = cookieString.toLatin1() + '\n';
4941 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/set-cookie.cgi");
4942 QNetworkRequest request(url);
4943 request.setRawHeader("Content-Type", "application/octet-stream");
4944 QNetworkReplyPtr reply;
4945 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PostOperation, request, reply, data));
4947 QCOMPARE(reply->url(), url);
4948 QCOMPARE(reply->error(), QNetworkReply::NoError);
4950 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
4952 QList<QNetworkCookie> setCookies =
4953 qvariant_cast<QList<QNetworkCookie> >(reply->header(QNetworkRequest::SetCookieHeader));
4954 QTEST(setCookies, "expectedCookiesFromHttp");
4955 QTEST(cookieJar->allCookies(), "expectedCookiesInJar");
4958 void tst_QNetworkReply::receiveCookiesFromHttpSynchronous_data()
4960 tst_QNetworkReply::receiveCookiesFromHttp_data();
4963 void tst_QNetworkReply::receiveCookiesFromHttpSynchronous()
4965 QFETCH(QString, cookieString);
4967 QByteArray data = cookieString.toLatin1() + '\n';
4968 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/set-cookie.cgi");
4970 QNetworkRequest request(url);
4971 request.setRawHeader("Content-Type", "application/octet-stream");
4972 request.setAttribute(
4973 QNetworkRequest::SynchronousRequestAttribute,
4976 QNetworkReplyPtr reply;
4977 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PostOperation, request, reply, data));
4979 QCOMPARE(reply->url(), url);
4980 QCOMPARE(reply->error(), QNetworkReply::NoError);
4982 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
4984 QList<QNetworkCookie> setCookies =
4985 qvariant_cast<QList<QNetworkCookie> >(reply->header(QNetworkRequest::SetCookieHeader));
4986 QTEST(setCookies, "expectedCookiesFromHttp");
4987 QTEST(cookieJar->allCookies(), "expectedCookiesInJar");
4990 void tst_QNetworkReply::sendCookies_data()
4992 QTest::addColumn<QList<QNetworkCookie> >("cookiesToSet");
4993 QTest::addColumn<QString>("expectedCookieString");
4995 QList<QNetworkCookie> list;
4996 QTest::newRow("empty") << list << "";
4998 QNetworkCookie cookie("a", "b");
4999 cookie.setPath("/");
5000 cookie.setDomain("example.com");
5002 QTest::newRow("no-match-domain") << list << "";
5004 cookie.setDomain(QtNetworkSettings::serverName());
5005 cookie.setPath("/something/else");
5007 QTest::newRow("no-match-path") << list << "";
5009 cookie.setPath("/");
5011 QTest::newRow("simple-cookie") << list << "a=b";
5013 cookie.setPath("/qtest");
5014 cookie.setValue("longer");
5016 QTest::newRow("two-cookies") << list << "a=longer; a=b";
5019 cookie = QNetworkCookie("a", "b");
5020 cookie.setPath("/");
5021 cookie.setDomain("." + QtNetworkSettings::serverDomainName());
5023 QTest::newRow("domain-match") << list << "a=b";
5025 // but it shouldn't match this:
5026 cookie.setDomain(QtNetworkSettings::serverDomainName());
5028 QTest::newRow("domain-match-2") << list << "a=b";
5031 void tst_QNetworkReply::sendCookies()
5033 QFETCH(QString, expectedCookieString);
5034 QFETCH(QList<QNetworkCookie>, cookiesToSet);
5035 cookieJar->setAllCookies(cookiesToSet);
5037 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/get-cookie.cgi");
5038 QNetworkRequest request(url);
5039 QNetworkReplyPtr reply;
5040 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
5042 QCOMPARE(reply->url(), url);
5043 QCOMPARE(reply->error(), QNetworkReply::NoError);
5045 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
5047 QCOMPARE(QString::fromLatin1(reply->readAll()).trimmed(), expectedCookieString);
5050 void tst_QNetworkReply::sendCookiesSynchronous_data()
5052 tst_QNetworkReply::sendCookies_data();
5055 void tst_QNetworkReply::sendCookiesSynchronous()
5057 QFETCH(QString, expectedCookieString);
5058 QFETCH(QList<QNetworkCookie>, cookiesToSet);
5059 cookieJar->setAllCookies(cookiesToSet);
5061 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/get-cookie.cgi");
5062 QNetworkRequest request(url);
5064 request.setAttribute(
5065 QNetworkRequest::SynchronousRequestAttribute,
5068 QNetworkReplyPtr reply;
5069 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
5071 QCOMPARE(reply->url(), url);
5072 QCOMPARE(reply->error(), QNetworkReply::NoError);
5074 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
5076 QCOMPARE(QString::fromLatin1(reply->readAll()).trimmed(), expectedCookieString);
5079 void tst_QNetworkReply::nestedEventLoops_slot()
5083 // 16 seconds: fluke times out in 15 seconds, which triggers a QTcpSocket error
5084 QTimer::singleShot(16000, &subloop, SLOT(quit()));
5087 QTestEventLoop::instance().exitLoop();
5090 void tst_QNetworkReply::nestedEventLoops()
5092 // Slightly fragile test, it may not be testing anything
5093 // This is certifying that we're not running into the same issue
5094 // that QHttp had (task 200432): the QTcpSocket connection is
5095 // closed by the remote end because of the kept-alive HTTP
5096 // connection timed out.
5098 // The exact time required for this to happen is not exactly
5099 // defined. Our server (Apache httpd) times out after 15
5100 // seconds. (see above)
5102 qDebug("Takes 16 seconds to run, please wait");
5104 QUrl url("http://" + QtNetworkSettings::serverName());
5105 QNetworkRequest request(url);
5106 QNetworkReplyPtr reply(manager.get(request));
5108 QSignalSpy finishedspy(reply.data(), SIGNAL(finished()));
5109 QSignalSpy errorspy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError)));
5111 connect(reply, SIGNAL(finished()), SLOT(nestedEventLoops_slot()));
5112 QTestEventLoop::instance().enterLoop(20);
5113 QVERIFY2(!QTestEventLoop::instance().timeout(), "Network timeout");
5115 QCOMPARE(finishedspy.count(), 1);
5116 QCOMPARE(errorspy.count(), 0);
5119 void tst_QNetworkReply::httpProxyCommands_data()
5121 QTest::addColumn<QUrl>("url");
5122 QTest::addColumn<QByteArray>("responseToSend");
5123 QTest::addColumn<QString>("expectedCommand");
5125 QTest::newRow("http")
5126 << QUrl("http://0.0.0.0:4443/http-request")
5127 << QByteArray("HTTP/1.0 200 OK\r\nProxy-Connection: close\r\nContent-Length: 1\r\n\r\n1")
5128 << "GET http://0.0.0.0:4443/http-request HTTP/1.";
5130 QTest::newRow("https")
5131 << QUrl("https://0.0.0.0:4443/https-request")
5132 << QByteArray("HTTP/1.0 200 Connection Established\r\n\r\n")
5133 << "CONNECT 0.0.0.0:4443 HTTP/1.";
5137 void tst_QNetworkReply::httpProxyCommands()
5140 QFETCH(QByteArray, responseToSend);
5141 QFETCH(QString, expectedCommand);
5143 MiniHttpServer proxyServer(responseToSend);
5144 QNetworkProxy proxy(QNetworkProxy::HttpProxy, "127.0.0.1", proxyServer.serverPort());
5146 manager.setProxy(proxy);
5147 QNetworkRequest request(url);
5148 request.setRawHeader("User-Agent", "QNetworkReplyAutoTest/1.0");
5149 QNetworkReplyPtr reply(manager.get(request));
5150 //clearing the proxy here causes the test to fail.
5151 //the proxy isn't used until after the bearer has been started
5152 //which is correct in general, because system proxy isn't known until that time.
5153 //removing this line is safe, as the proxy is also reset by the cleanup() function
5154 //manager.setProxy(QNetworkProxy());
5156 // wait for the finished signal
5157 QVERIFY(waitForFinish(reply) != Timeout);
5159 //qDebug() << reply->error() << reply->errorString();
5160 //qDebug() << proxyServer.receivedData;
5162 // we don't really care if the request succeeded
5163 // especially since it won't succeed in the HTTPS case
5164 // so just check that the command was correct
5166 QString receivedHeader = proxyServer.receivedData.left(expectedCommand.length());
5167 QCOMPARE(receivedHeader, expectedCommand);
5169 //QTBUG-17223 - make sure the user agent from the request is sent to proxy server even for CONNECT
5170 int uapos = proxyServer.receivedData.indexOf("User-Agent");
5171 int uaend = proxyServer.receivedData.indexOf("\r\n", uapos);
5172 QByteArray uaheader = proxyServer.receivedData.mid(uapos, uaend - uapos);
5173 QCOMPARE(uaheader, QByteArray("User-Agent: QNetworkReplyAutoTest/1.0"));
5176 class ProxyChangeHelper : public QObject {
5179 ProxyChangeHelper() : QObject(), signalCount(0) {};
5181 void finishedSlot() {
5183 if (signalCount == 2)
5184 QMetaObject::invokeMethod(&QTestEventLoop::instance(), "exitLoop", Qt::QueuedConnection);
5190 void tst_QNetworkReply::httpProxyCommandsSynchronous_data()
5192 httpProxyCommands_data();
5195 struct QThreadCleanup
5197 static inline void cleanup(QThread *thread)
5200 if (thread->wait(3000))
5203 qWarning("thread hung, leaking memory so test can finish");
5207 struct QDeleteLaterCleanup
5209 static inline void cleanup(QObject *o)
5215 void tst_QNetworkReply::httpProxyCommandsSynchronous()
5218 QFETCH(QByteArray, responseToSend);
5219 QFETCH(QString, expectedCommand);
5221 // when using synchronous commands, we need a different event loop for
5222 // the server thread, because the client is never returning to the
5224 QScopedPointer<QThread, QThreadCleanup> serverThread(new QThread);
5225 QScopedPointer<MiniHttpServer, QDeleteLaterCleanup> proxyServer(new MiniHttpServer(responseToSend, false, serverThread.data()));
5226 QNetworkProxy proxy(QNetworkProxy::HttpProxy, "127.0.0.1", proxyServer->serverPort());
5228 manager.setProxy(proxy);
5229 QNetworkRequest request(url);
5231 // send synchronous request
5232 request.setAttribute(
5233 QNetworkRequest::SynchronousRequestAttribute,
5236 QNetworkReplyPtr reply(manager.get(request));
5237 QVERIFY(reply->isFinished()); // synchronous
5238 manager.setProxy(QNetworkProxy());
5240 //qDebug() << reply->error() << reply->errorString();
5242 // we don't really care if the request succeeded
5243 // especially since it won't succeed in the HTTPS case
5244 // so just check that the command was correct
5246 QString receivedHeader = proxyServer->receivedData.left(expectedCommand.length());
5247 QCOMPARE(receivedHeader, expectedCommand);
5250 void tst_QNetworkReply::proxyChange()
5252 ProxyChangeHelper helper;
5253 MiniHttpServer proxyServer(
5254 "HTTP/1.0 200 OK\r\nProxy-Connection: keep-alive\r\n"
5255 "Content-Length: 1\r\n\r\n1");
5256 QNetworkProxy dummyProxy(QNetworkProxy::HttpProxy, "127.0.0.1", proxyServer.serverPort());
5257 QNetworkRequest req(QUrl("http://" + QtNetworkSettings::serverName()));
5258 proxyServer.doClose = false;
5260 manager.setProxy(dummyProxy);
5261 QNetworkReplyPtr reply1(manager.get(req));
5262 connect(reply1, SIGNAL(finished()), &helper, SLOT(finishedSlot()));
5264 manager.setProxy(QNetworkProxy());
5265 QNetworkReplyPtr reply2(manager.get(req));
5266 connect(reply2, SIGNAL(finished()), &helper, SLOT(finishedSlot()));
5268 QTestEventLoop::instance().enterLoop(20);
5269 QVERIFY(!QTestEventLoop::instance().timeout());
5271 // verify that the replies succeeded
5272 QCOMPARE(reply1->error(), QNetworkReply::NoError);
5273 QCOMPARE(reply1->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
5274 QVERIFY(reply1->size() == 1);
5276 QCOMPARE(reply2->error(), QNetworkReply::NoError);
5277 QCOMPARE(reply2->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
5278 QVERIFY(reply2->size() > 1);
5280 // now try again and get an error
5281 // this verifies that we reuse the already-open connection
5283 proxyServer.doClose = true;
5284 proxyServer.dataToTransmit =
5285 "HTTP/1.0 403 Forbidden\r\nProxy-Connection: close\r\n"
5286 "Content-Length: 1\r\n\r\n1";
5288 manager.setProxy(dummyProxy);
5289 QNetworkReplyPtr reply3(manager.get(req));
5291 QVERIFY(waitForFinish(reply3) == Failure);
5293 QVERIFY(int(reply3->error()) > 0);
5296 void tst_QNetworkReply::authorizationError_data()
5299 QTest::addColumn<QString>("url");
5300 QTest::addColumn<int>("errorSignalCount");
5301 QTest::addColumn<int>("finishedSignalCount");
5302 QTest::addColumn<int>("error");
5303 QTest::addColumn<int>("httpStatusCode");
5304 QTest::addColumn<QString>("httpBody");
5306 QTest::newRow("unknown-authorization-method") << "http://" + QtNetworkSettings::serverName() +
5307 "/qtest/cgi-bin/http-unknown-authentication-method.cgi?401-authorization-required" << 1 << 1
5308 << int(QNetworkReply::AuthenticationRequiredError) << 401 << "authorization required";
5309 QTest::newRow("unknown-proxy-authorization-method") << "http://" + QtNetworkSettings::serverName() +
5310 "/qtest/cgi-bin/http-unknown-authentication-method.cgi?407-proxy-authorization-required" << 1 << 1
5311 << int(QNetworkReply::ProxyAuthenticationRequiredError) << 407
5312 << "authorization required";
5315 void tst_QNetworkReply::authorizationError()
5317 QFETCH(QString, url);
5318 QNetworkRequest request(url);
5319 QNetworkReplyPtr reply(manager.get(request));
5321 QCOMPARE(reply->error(), QNetworkReply::NoError);
5323 QSignalSpy errorSpy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError)));
5324 QSignalSpy finishedSpy(reply.data(), SIGNAL(finished()));
5325 // now run the request:
5326 QVERIFY(waitForFinish(reply) == Failure);
5328 QFETCH(int, errorSignalCount);
5329 QCOMPARE(errorSpy.count(), errorSignalCount);
5330 QFETCH(int, finishedSignalCount);
5331 QCOMPARE(finishedSpy.count(), finishedSignalCount);
5333 QCOMPARE(reply->error(), QNetworkReply::NetworkError(error));
5335 QFETCH(int, httpStatusCode);
5336 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), httpStatusCode);
5338 QFETCH(QString, httpBody);
5339 QCOMPARE(qint64(reply->size()), qint64(httpBody.size()));
5340 QCOMPARE(QString(reply->readAll()), httpBody);
5343 void tst_QNetworkReply::httpConnectionCount()
5346 QVERIFY(server.listen());
5347 QCoreApplication::instance()->processEvents();
5349 for (int i = 0; i < 10; i++) {
5350 QNetworkRequest request (QUrl("http://127.0.0.1:" + QString::number(server.serverPort()) + "/" + QString::number(i)));
5351 QNetworkReply* reply = manager.get(request);
5352 reply->setParent(&server);
5355 int pendingConnectionCount = 0;
5359 while(pendingConnectionCount <= 20) {
5360 QTestEventLoop::instance().enterLoop(1);
5361 QTcpSocket *socket = server.nextPendingConnection();
5362 while (socket != 0) {
5363 pendingConnectionCount++;
5364 socket->setParent(&server);
5365 socket = server.nextPendingConnection();
5368 // at max. wait 10 sec
5369 if (time.elapsed() > 10000)
5373 QCOMPARE(pendingConnectionCount, 6);
5376 void tst_QNetworkReply::httpReUsingConnectionSequential_data()
5378 QTest::addColumn<bool>("doDeleteLater");
5379 QTest::newRow("deleteLater") << true;
5380 QTest::newRow("noDeleteLater") << false;
5383 void tst_QNetworkReply::httpReUsingConnectionSequential()
5385 QFETCH(bool, doDeleteLater);
5387 QByteArray response("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
5388 MiniHttpServer server(response);
5389 server.multiple = true;
5390 server.doClose = false;
5393 url.setScheme("http");
5394 url.setPort(server.serverPort());
5395 url.setHost("127.0.0.1");
5397 QNetworkReply* reply1 = manager.get(QNetworkRequest(url));
5398 connect(reply1, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
5399 QTestEventLoop::instance().enterLoop(2);
5400 QVERIFY(!QTestEventLoop::instance().timeout());
5401 QVERIFY(!reply1->error());
5402 int reply1port = server.client->peerPort();
5405 reply1->deleteLater();
5407 // finished received, send the next one
5408 QNetworkReply*reply2 = manager.get(QNetworkRequest(url));
5409 connect(reply2, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
5410 QTestEventLoop::instance().enterLoop(2);
5411 QVERIFY(!QTestEventLoop::instance().timeout());
5412 QVERIFY(!reply2->error());
5413 int reply2port = server.client->peerPort(); // should still be the same object
5415 QVERIFY(reply1port > 0);
5416 QCOMPARE(server.totalConnections, 1);
5417 QCOMPARE(reply2port, reply1port);
5420 reply1->deleteLater(); // only do it if it was not done earlier
5421 reply2->deleteLater();
5424 class HttpReUsingConnectionFromFinishedSlot : public QObject {
5427 QNetworkReply* reply1;
5428 QNetworkReply* reply2;
5430 QNetworkAccessManager manager;
5432 void finishedSlot() {
5433 QVERIFY(!reply1->error());
5435 QFETCH(bool, doDeleteLater);
5436 if (doDeleteLater) {
5437 reply1->deleteLater();
5441 // kick off 2nd request and exit the loop when it is done
5442 reply2 = manager.get(QNetworkRequest(url));
5443 reply2->setParent(this);
5444 connect(reply2, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
5448 void tst_QNetworkReply::httpReUsingConnectionFromFinishedSlot_data()
5450 httpReUsingConnectionSequential_data();
5453 void tst_QNetworkReply::httpReUsingConnectionFromFinishedSlot()
5455 QByteArray response("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
5456 MiniHttpServer server(response);
5457 server.multiple = true;
5458 server.doClose = false;
5460 HttpReUsingConnectionFromFinishedSlot helper;
5463 helper.url.setScheme("http");
5464 helper.url.setPort(server.serverPort());
5465 helper.url.setHost("127.0.0.1");
5468 helper.reply1 = helper.manager.get(QNetworkRequest(helper.url));
5469 helper.reply1->setParent(&helper);
5470 connect(helper.reply1, SIGNAL(finished()), &helper, SLOT(finishedSlot()));
5471 QTestEventLoop::instance().enterLoop(4);
5472 QVERIFY(!QTestEventLoop::instance().timeout());
5474 QVERIFY(helper.reply2);
5475 QVERIFY(!helper.reply2->error());
5477 QCOMPARE(server.totalConnections, 1);
5480 class HttpRecursiveCreationHelper : public QObject {
5484 HttpRecursiveCreationHelper():
5486 requestsStartedCount_finished(0),
5487 requestsStartedCount_readyRead(0),
5488 requestsFinishedCount(0)
5491 QNetworkAccessManager manager;
5492 int requestsStartedCount_finished;
5493 int requestsStartedCount_readyRead;
5494 int requestsFinishedCount;
5496 void finishedSlot() {
5497 requestsFinishedCount++;
5499 QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
5500 QVERIFY(!reply->error());
5501 QVERIFY(reply->bytesAvailable() == 27906);
5503 if (requestsFinishedCount == 60) {
5504 QTestEventLoop::instance().exitLoop();
5508 if (requestsStartedCount_finished < 30) {
5510 requestsStartedCount_finished++;
5513 reply->deleteLater();
5515 void readyReadSlot() {
5516 QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
5517 QVERIFY(!reply->error());
5519 if (requestsStartedCount_readyRead < 30 && reply->bytesAvailable() > 27906/2) {
5521 requestsStartedCount_readyRead++;
5525 QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/fluke.gif";
5526 QNetworkRequest request(url);
5527 QNetworkReply *reply = manager.get(request);
5528 reply->setParent(this);
5529 connect(reply, SIGNAL(finished()), this, SLOT(finishedSlot()));
5530 connect(reply, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
5534 void tst_QNetworkReply::httpRecursiveCreation()
5536 // this test checks if creation of new requests to the same host properly works
5537 // from readyRead() and finished() signals
5538 HttpRecursiveCreationHelper helper;
5540 QTestEventLoop::instance().enterLoop(30);
5541 QVERIFY(!QTestEventLoop::instance().timeout());
5545 void tst_QNetworkReply::ignoreSslErrorsList_data()
5547 QTest::addColumn<QString>("url");
5548 QTest::addColumn<QList<QSslError> >("expectedSslErrors");
5549 QTest::addColumn<QNetworkReply::NetworkError>("expectedNetworkError");
5551 QList<QSslError> expectedSslErrors;
5552 QList<QSslCertificate> certs = QSslCertificate::fromPath(testDataDir + "/certs/qt-test-server-cacert.pem");
5553 QSslError rightError(QSslError::SelfSignedCertificate, certs.at(0));
5554 QSslError wrongError(QSslError::SelfSignedCertificate);
5556 QTest::newRow("SSL-failure-empty-list") << "https://" + QtNetworkSettings::serverName() + "/index.html" << expectedSslErrors << QNetworkReply::SslHandshakeFailedError;
5557 expectedSslErrors.append(wrongError);
5558 QTest::newRow("SSL-failure-wrong-error") << "https://" + QtNetworkSettings::serverName() + "/index.html" << expectedSslErrors << QNetworkReply::SslHandshakeFailedError;
5559 expectedSslErrors.append(rightError);
5560 QTest::newRow("allErrorsInExpectedList1") << "https://" + QtNetworkSettings::serverName() + "/index.html" << expectedSslErrors << QNetworkReply::NoError;
5561 expectedSslErrors.removeAll(wrongError);
5562 QTest::newRow("allErrorsInExpectedList2") << "https://" + QtNetworkSettings::serverName() + "/index.html" << expectedSslErrors << QNetworkReply::NoError;
5563 expectedSslErrors.removeAll(rightError);
5564 QTest::newRow("SSL-failure-empty-list-again") << "https://" + QtNetworkSettings::serverName() + "/index.html" << expectedSslErrors << QNetworkReply::SslHandshakeFailedError;
5567 void tst_QNetworkReply::ignoreSslErrorsList()
5569 QFETCH(QString, url);
5570 QNetworkRequest request(url);
5571 QNetworkReplyPtr reply(manager.get(request));
5573 QFETCH(QList<QSslError>, expectedSslErrors);
5574 reply->ignoreSslErrors(expectedSslErrors);
5576 QVERIFY(waitForFinish(reply) != Timeout);
5578 QFETCH(QNetworkReply::NetworkError, expectedNetworkError);
5579 QCOMPARE(reply->error(), expectedNetworkError);
5582 void tst_QNetworkReply::ignoreSslErrorsListWithSlot_data()
5584 ignoreSslErrorsList_data();
5587 // this is not a test, just a slot called in the test below
5588 void tst_QNetworkReply::ignoreSslErrorListSlot(QNetworkReply *reply, const QList<QSslError> &)
5590 reply->ignoreSslErrors(storedExpectedSslErrors);
5593 // do the same as in ignoreSslErrorsList, but ignore the errors in the slot
5594 void tst_QNetworkReply::ignoreSslErrorsListWithSlot()
5596 QFETCH(QString, url);
5597 QNetworkRequest request(url);
5598 QNetworkReplyPtr reply(manager.get(request));
5600 QFETCH(QList<QSslError>, expectedSslErrors);
5601 // store the errors to ignore them later in the slot connected below
5602 storedExpectedSslErrors = expectedSslErrors;
5603 connect(&manager, SIGNAL(sslErrors(QNetworkReply *, const QList<QSslError> &)),
5604 this, SLOT(ignoreSslErrorListSlot(QNetworkReply *, const QList<QSslError> &)));
5607 QVERIFY(waitForFinish(reply) != Timeout);
5609 QFETCH(QNetworkReply::NetworkError, expectedNetworkError);
5610 QCOMPARE(reply->error(), expectedNetworkError);
5613 void tst_QNetworkReply::sslConfiguration_data()
5615 QTest::addColumn<QSslConfiguration>("configuration");
5616 QTest::addColumn<bool>("works");
5618 QTest::newRow("empty") << QSslConfiguration() << false;
5619 QSslConfiguration conf = QSslConfiguration::defaultConfiguration();
5620 QTest::newRow("default") << conf << false; // does not contain test server cert
5621 QList<QSslCertificate> testServerCert = QSslCertificate::fromPath(testDataDir + "/certs/qt-test-server-cacert.pem");
5622 conf.setCaCertificates(testServerCert);
5623 QTest::newRow("set-root-cert") << conf << true;
5624 conf.setProtocol(QSsl::SecureProtocols);
5625 QTest::newRow("secure") << conf << true;
5628 void tst_QNetworkReply::sslConfiguration()
5630 QNetworkRequest request(QUrl("https://" + QtNetworkSettings::serverName() + "/index.html"));
5631 QFETCH(QSslConfiguration, configuration);
5632 request.setSslConfiguration(configuration);
5633 QNetworkReplyPtr reply(manager.get(request));
5635 QVERIFY(waitForFinish(reply) != Timeout);
5637 QFETCH(bool, works);
5638 QNetworkReply::NetworkError expectedError = works ? QNetworkReply::NoError : QNetworkReply::SslHandshakeFailedError;
5639 QCOMPARE(reply->error(), expectedError);
5644 void tst_QNetworkReply::getAndThenDeleteObject_data()
5646 QTest::addColumn<bool>("replyFirst");
5648 QTest::newRow("delete-reply-first") << true;
5649 QTest::newRow("delete-qnam-first") << false;
5652 void tst_QNetworkReply::getAndThenDeleteObject()
5654 QSKIP("unstable test - reply may be finished too early");
5655 // yes, this will leak if the testcase fails. I don't care. It must not fail then :P
5656 QNetworkAccessManager *manager = new QNetworkAccessManager();
5657 QNetworkRequest request("http://" + QtNetworkSettings::serverName() + "/qtest/bigfile");
5658 QNetworkReply *reply = manager->get(request);
5659 reply->setReadBufferSize(1);
5660 reply->setParent((QObject*)0); // must be 0 because else it is the manager
5665 QCoreApplication::instance()->processEvents();
5666 if (reply->bytesAvailable())
5668 if (stopWatch.elapsed() >= 30000)
5672 QVERIFY(reply->bytesAvailable());
5673 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
5674 QVERIFY(!reply->isFinished()); // must not be finished
5676 QFETCH(bool, replyFirst);
5687 // see https://bugs.webkit.org/show_bug.cgi?id=38935
5688 void tst_QNetworkReply::symbianOpenCDataUrlCrash()
5690 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==");
5691 QUrl url = QUrl::fromEncoded(requestUrl.toLatin1());
5692 QNetworkRequest req(url);
5693 QNetworkReplyPtr reply;
5695 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, req, reply));
5697 QCOMPARE(reply->url(), url);
5698 QCOMPARE(reply->error(), QNetworkReply::NoError);
5700 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), qint64(598));
5703 void tst_QNetworkReply::getFromHttpIntoBuffer_data()
5705 QTest::addColumn<QUrl>("url");
5707 QTest::newRow("rfc-internal") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt");
5710 // Please note that the whole "zero copy" download buffer API is private right now. Do not use it.
5711 void tst_QNetworkReply::getFromHttpIntoBuffer()
5714 QNetworkRequest request(url);
5715 request.setAttribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute, 1024*128); // 128 kB
5717 QNetworkAccessManager manager;
5718 QNetworkReply *reply = manager.get(request);
5719 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
5720 QTestEventLoop::instance().enterLoop(10);
5721 QVERIFY(!QTestEventLoop::instance().timeout());
5722 QVERIFY(reply->isFinished());
5724 QFile reference(testDataDir + "/rfc3252.txt");
5725 QVERIFY(reference.open(QIODevice::ReadOnly));
5727 QCOMPARE(reference.bytesAvailable(), reply->bytesAvailable());
5728 QCOMPARE(reference.size(), reply->size());
5730 // Compare the memory buffer
5731 QVariant downloadBufferAttribute = reply->attribute(QNetworkRequest::DownloadBufferAttribute);
5732 QVERIFY(downloadBufferAttribute.isValid());
5733 QSharedPointer<char> sharedPointer = downloadBufferAttribute.value<QSharedPointer<char> >();
5734 bool memoryComparison =
5735 (0 == memcmp(static_cast<void*>(reference.readAll().data()),
5736 sharedPointer.data(), reference.size()));
5737 QVERIFY(memoryComparison);
5739 // Make sure the normal reading works
5741 QCOMPARE(reply->read(42), reference.read(42));
5742 QCOMPARE(reply->getChar(0), reference.getChar(0));
5743 QCOMPARE(reply->peek(23), reference.peek(23));
5744 QCOMPARE(reply->readLine(), reference.readLine());
5745 QCOMPARE(reference.bytesAvailable(), reply->bytesAvailable());
5746 QCOMPARE(reply->readAll(), reference.readAll());
5747 QVERIFY(reply->atEnd());
5750 // FIXME we really need to consolidate all those server implementations
5751 class GetFromHttpIntoBuffer2Server : QObject {
5757 bool serverSendsContentLength;
5758 bool chunkedEncoding;
5761 GetFromHttpIntoBuffer2Server (qint64 ds, bool sscl, bool ce) : dataSize(ds), dataSent(0),
5762 client(0), serverSendsContentLength(sscl), chunkedEncoding(ce) {
5764 connect(&server, SIGNAL(newConnection()), this, SLOT(newConnectionSlot()));
5768 return server.serverPort();
5773 void newConnectionSlot() {
5774 client = server.nextPendingConnection();
5775 client->setParent(this);
5776 connect(client, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
5777 connect(client, SIGNAL(bytesWritten(qint64)), this, SLOT(bytesWrittenSlot(qint64)));
5780 void readyReadSlot() {
5782 client->write("HTTP/1.0 200 OK\n");
5783 if (serverSendsContentLength)
5784 client->write(QString("Content-Length: " + QString::number(dataSize) + "\n").toLatin1());
5785 if (chunkedEncoding)
5786 client->write(QString("Transfer-Encoding: chunked\n").toLatin1());
5787 client->write("Connection: close\n\n");
5790 void bytesWrittenSlot(qint64 amount) {
5792 if (dataSent == dataSize && client) {
5795 // chunked encoding: we have to send a last "empty" chunk
5796 if (chunkedEncoding)
5797 client->write(QString("0\r\n\r\n").toLatin1());
5799 client->disconnectFromHost();
5806 if (client && client->bytesToWrite() < 100*1024 && dataSent < dataSize) {
5807 qint64 amount = qMin(qint64(16*1024), dataSize - dataSent);
5808 QByteArray data(amount, '@');
5810 if (chunkedEncoding) {
5811 client->write(QString(QString("%1").arg(amount,0,16).toUpper() + "\r\n").toLatin1());
5812 client->write(data.constData(), amount);
5813 client->write(QString("\r\n").toLatin1());
5815 client->write(data.constData(), amount);
5823 class GetFromHttpIntoBuffer2Client : QObject {
5826 bool useDownloadBuffer;
5827 QNetworkReply *reply;
5829 QList<qint64> bytesAvailableList;
5831 GetFromHttpIntoBuffer2Client (QNetworkReply *reply, bool useDownloadBuffer, qint64 uploadSize)
5832 : useDownloadBuffer(useDownloadBuffer), reply(reply), uploadSize(uploadSize)
5834 connect(reply, SIGNAL(metaDataChanged()), this, SLOT(metaDataChangedSlot()));
5835 connect(reply, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
5836 connect(reply, SIGNAL(finished()), this, SLOT(finishedSlot()));
5840 void metaDataChangedSlot() {
5841 if (useDownloadBuffer) {
5842 QSharedPointer<char> sharedPointer = qvariant_cast<QSharedPointer<char> >(reply->attribute(QNetworkRequest::DownloadBufferAttribute));
5843 QVERIFY(!sharedPointer.isNull()); // It will be 0 if it failed
5846 // metaDataChanged needs to come before everything else
5847 QVERIFY(bytesAvailableList.isEmpty());
5850 void readyReadSlot() {
5851 QVERIFY(!reply->isFinished());
5853 qint64 bytesAvailable = reply->bytesAvailable();
5855 // bytesAvailable must never be 0
5856 QVERIFY(bytesAvailable != 0);
5858 if (bytesAvailableList.length() < 5) {
5859 // We assume that the first few times the bytes available must be less than the complete size, e.g.
5860 // the bytesAvailable() function works correctly in case of a downloadBuffer.
5861 QVERIFY(bytesAvailable < uploadSize);
5863 if (!bytesAvailableList.isEmpty()) {
5864 // Also check that the same bytesAvailable is not coming twice in a row
5865 QVERIFY(bytesAvailableList.last() != bytesAvailable);
5868 bytesAvailableList.append(bytesAvailable);
5869 // Add bytesAvailable to a list an parse
5872 void finishedSlot() {
5873 // We should have already received all readyRead
5874 QVERIFY(!bytesAvailableList.isEmpty());
5875 QVERIFY(bytesAvailableList.last() == uploadSize);
5879 void tst_QNetworkReply::getFromHttpIntoBuffer2_data()
5881 QTest::addColumn<bool>("useDownloadBuffer");
5883 QTest::newRow("use-download-buffer") << true;
5884 QTest::newRow("do-not-use-download-buffer") << false;
5887 // This test checks mostly that signal emissions are in correct order
5888 // Please note that the whole "zero copy" download buffer API is private right now. Do not use it.
5889 void tst_QNetworkReply::getFromHttpIntoBuffer2()
5891 QFETCH(bool, useDownloadBuffer);
5893 // On my Linux Desktop the results are already visible with 128 kB, however we use this to have good results.
5894 #if defined(Q_OS_WINCE_WM)
5895 // Show some mercy to non-desktop platform/s
5896 enum {UploadSize = 4*1024*1024}; // 4 MB
5898 enum {UploadSize = 32*1024*1024}; // 32 MB
5901 GetFromHttpIntoBuffer2Server server(UploadSize, true, false);
5903 QNetworkRequest request(QUrl("http://127.0.0.1:" + QString::number(server.serverPort()) + "/?bare=1"));
5904 if (useDownloadBuffer)
5905 request.setAttribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute, 1024*1024*128); // 128 MB is max allowed
5907 QNetworkAccessManager manager;
5908 QNetworkReplyPtr reply(manager.get(request));
5910 GetFromHttpIntoBuffer2Client client(reply.data(), useDownloadBuffer, UploadSize);
5912 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
5913 QTestEventLoop::instance().enterLoop(40);
5914 QCOMPARE(reply->error(), QNetworkReply::NoError);
5915 QVERIFY(!QTestEventLoop::instance().timeout());
5919 void tst_QNetworkReply::getFromHttpIntoBufferCanReadLine()
5921 QString header("HTTP/1.0 200 OK\r\nContent-Length: 7\r\n\r\nxxx\nxxx");
5923 MiniHttpServer server(header.toLatin1());
5924 server.doClose = true;
5926 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
5927 request.setAttribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute, 1024*1024*128); // 128 MB is max allowed
5928 QNetworkReplyPtr reply(manager.get(request));
5930 QVERIFY(waitForFinish(reply) == Success);
5932 QCOMPARE(reply->error(), QNetworkReply::NoError);
5933 QVERIFY(reply->canReadLine());
5934 QCOMPARE(reply->read(1), QByteArray("x"));
5935 QVERIFY(reply->canReadLine());
5936 QCOMPARE(reply->read(3), QByteArray("xx\n"));
5937 QVERIFY(!reply->canReadLine());
5938 QCOMPARE(reply->readAll(), QByteArray("xxx"));
5939 QVERIFY(!reply->canReadLine());
5944 // Is handled somewhere else too, introduced this special test to have it more accessible
5945 void tst_QNetworkReply::ioGetFromHttpWithoutContentLength()
5947 QByteArray dataToSend("HTTP/1.0 200 OK\r\n\r\nHALLO! 123!");
5948 MiniHttpServer server(dataToSend);
5949 server.doClose = true;
5951 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
5952 QNetworkReplyPtr reply(manager.get(request));
5954 QVERIFY(waitForFinish(reply) == Success);
5956 QCOMPARE(reply->url(), request.url());
5957 QVERIFY(reply->isFinished());
5958 QVERIFY(reply->error() == QNetworkReply::NoError);
5961 // Is handled somewhere else too, introduced this special test to have it more accessible
5962 void tst_QNetworkReply::ioGetFromHttpBrokenChunkedEncoding()
5964 // This is wrong chunked encoding because of the X. What actually has to follow is \r\n
5965 // and then the declaration of the final 0 chunk
5966 QByteArray dataToSend("HTTP/1.0 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n3\r\nABCX");
5967 MiniHttpServer server(dataToSend);
5968 server.doClose = false; // FIXME
5970 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
5971 QNetworkReplyPtr reply(manager.get(request));
5973 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
5974 QTestEventLoop::instance().enterLoop(10);
5976 QEXPECT_FAIL(0, "We should close the socket and not just do nothing", Continue);
5977 QVERIFY(!QTestEventLoop::instance().timeout());
5978 QEXPECT_FAIL(0, "We should close the socket and not just do nothing", Continue);
5979 QVERIFY(reply->isFinished());
5980 QCOMPARE(reply->error(), QNetworkReply::NoError);
5984 // Prepare a gzip that has one chunk that expands to the size mentioned in the bugreport.
5985 // Then have a custom HTTP server that waits after this chunk so the returning gets
5987 void tst_QNetworkReply::qtbug12908compressedHttpReply()
5989 QString header("HTTP/1.0 200 OK\r\nContent-Encoding: gzip\r\nContent-Length: 63\r\n\r\n");
5991 // dd if=/dev/zero of=qtbug-12908 bs=16384 count=1 && gzip qtbug-12908 && base64 -w 0 qtbug-12908.gz
5992 QString encodedFile("H4sICDdDaUwAA3F0YnVnLTEyOTA4AO3BMQEAAADCoPVPbQwfoAAAAAAAAAAAAAAAAAAAAIC3AYbSVKsAQAAA");
5993 QByteArray decodedFile = QByteArray::fromBase64(encodedFile.toLatin1());
5994 QCOMPARE(decodedFile.size(), 63);
5996 MiniHttpServer server(header.toLatin1() + decodedFile);
5997 server.doClose = true;
5999 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
6000 QNetworkReplyPtr reply(manager.get(request));
6002 QVERIFY(waitForFinish(reply) == Success);
6004 QCOMPARE(reply->error(), QNetworkReply::NoError);
6005 QCOMPARE(reply->size(), qint64(16384));
6006 QCOMPARE(reply->readAll(), QByteArray(16384, '\0'));
6009 void tst_QNetworkReply::compressedHttpReplyBrokenGzip()
6011 QString header("HTTP/1.0 200 OK\r\nContent-Encoding: gzip\r\nContent-Length: 63\r\n\r\n");
6013 // dd if=/dev/zero of=qtbug-12908 bs=16384 count=1 && gzip qtbug-12908 && base64 -w 0 qtbug-12908.gz
6014 // Then change "BMQ" to "BMX"
6015 QString encodedFile("H4sICDdDaUwAA3F0YnVnLTEyOTA4AO3BMXEAAADCoPVPbQwfoAAAAAAAAAAAAAAAAAAAAIC3AYbSVKsAQAAA");
6016 QByteArray decodedFile = QByteArray::fromBase64(encodedFile.toLatin1());
6017 QCOMPARE(decodedFile.size(), 63);
6019 MiniHttpServer server(header.toLatin1() + decodedFile);
6020 server.doClose = true;
6022 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
6023 QNetworkReplyPtr reply(manager.get(request));
6025 QVERIFY(waitForFinish(reply) == Failure);
6027 QCOMPARE(reply->error(), QNetworkReply::ProtocolFailure);
6030 // TODO add similar test for FTP
6031 void tst_QNetworkReply::getFromUnreachableIp()
6033 QNetworkAccessManager manager;
6035 QNetworkRequest request(QUrl("http://255.255.255.255/42/23/narf/narf/narf"));
6036 QNetworkReplyPtr reply(manager.get(request));
6038 QVERIFY(waitForFinish(reply) == Failure);
6040 QVERIFY(reply->error() != QNetworkReply::NoError);
6043 void tst_QNetworkReply::qtbug4121unknownAuthentication()
6045 MiniHttpServer server(QByteArray("HTTP/1.1 401 bla\r\nWWW-Authenticate: crap\r\nContent-Length: 0\r\n\r\n"));
6046 server.doClose = false;
6048 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
6049 QNetworkAccessManager manager;
6050 QNetworkReplyPtr reply(manager.get(request));
6052 QSignalSpy authSpy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
6053 QSignalSpy finishedSpy(&manager, SIGNAL(finished(QNetworkReply*)));
6054 QSignalSpy errorSpy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError)));
6056 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6057 QTestEventLoop::instance().enterLoop(10);
6058 QVERIFY(!QTestEventLoop::instance().timeout());
6060 QCOMPARE(authSpy.count(), 0);
6061 QCOMPARE(finishedSpy.count(), 1);
6062 QCOMPARE(errorSpy.count(), 1);
6064 QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError);
6067 void tst_QNetworkReply::authenticationCacheAfterCancel_data()
6069 QTest::addColumn<QNetworkProxy>("proxy");
6070 QTest::addColumn<bool>("proxyAuth");
6071 QTest::addColumn<QUrl>("url");
6072 for (int i = 0; i < proxies.count(); ++i) {
6073 QTest::newRow("http" + proxies.at(i).tag) << proxies.at(i).proxy << proxies.at(i).requiresAuthentication << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt");
6075 QTest::newRow("https" + proxies.at(i).tag) << proxies.at(i).proxy << proxies.at(i).requiresAuthentication << QUrl("https://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt");
6080 class AuthenticationCacheHelper : public QObject
6084 AuthenticationCacheHelper()
6087 void proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *auth)
6089 if (!proxyPassword.isNull()) {
6090 auth->setUser(proxyUserName);
6091 auth->setPassword(proxyPassword);
6092 //clear credentials, if they are asked again, they were bad
6093 proxyUserName.clear();
6094 proxyPassword.clear();
6097 void authenticationRequired(QNetworkReply*,QAuthenticator *auth)
6099 if (!httpPassword.isNull()) {
6100 auth->setUser(httpUserName);
6101 auth->setPassword(httpPassword);
6102 //clear credentials, if they are asked again, they were bad
6103 httpUserName.clear();
6104 httpPassword.clear();
6108 QString httpUserName;
6109 QString httpPassword;
6110 QString proxyUserName;
6111 QString proxyPassword;
6114 /* Purpose of this test is to check credentials are cached correctly.
6115 - If user cancels authentication dialog (i.e. nothing is set to the QAuthenticator by the callback) then this is not cached
6116 - if user supplies a wrong password, then this is not cached
6117 - if user supplies a correct user/password combination then this is cached
6119 Test is checking both the proxyAuthenticationRequired and authenticationRequired signals.
6121 void tst_QNetworkReply::authenticationCacheAfterCancel()
6123 QFETCH(QNetworkProxy, proxy);
6124 QFETCH(bool, proxyAuth);
6126 QNetworkAccessManager manager;
6128 connect(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
6129 SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
6131 manager.setProxy(proxy);
6132 QSignalSpy authSpy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
6133 QSignalSpy proxyAuthSpy(&manager, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)));
6135 AuthenticationCacheHelper helper;
6136 connect(&manager, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)), &helper, SLOT(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)));
6137 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), &helper, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
6139 QNetworkRequest request(url);
6140 QNetworkReplyPtr reply;
6142 //should fail due to no credentials
6143 reply.reset(manager.get(request));
6144 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6145 QTestEventLoop::instance().enterLoop(10);
6146 QVERIFY(!QTestEventLoop::instance().timeout());
6148 QCOMPARE(reply->error(), QNetworkReply::ProxyAuthenticationRequiredError);
6149 QCOMPARE(authSpy.count(), 0);
6150 QCOMPARE(proxyAuthSpy.count(), 1);
6151 proxyAuthSpy.clear();
6153 //should fail due to bad credentials
6154 helper.proxyUserName = "qsockstest";
6155 helper.proxyPassword = "badpassword";
6156 reply.reset(manager.get(request));
6157 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6158 QTestEventLoop::instance().enterLoop(10);
6159 QVERIFY(!QTestEventLoop::instance().timeout());
6161 QEXPECT_FAIL("http+socksauth", "QTBUG-23136 - danted accepts bad authentication but blocks the connection", Continue);
6162 QEXPECT_FAIL("https+socksauth", "QTBUG-23136 - danted accepts bad authentication but blocks the connection", Continue);
6164 QCOMPARE(reply->error(), QNetworkReply::ProxyAuthenticationRequiredError);
6165 QCOMPARE(authSpy.count(), 0);
6166 QVERIFY(proxyAuthSpy.count() > 0);
6167 proxyAuthSpy.clear();
6169 //QTBUG-23136 workaround
6170 if (proxy.port() == 1081) {
6171 #ifdef QT_BUILD_INTERNAL
6172 QNetworkAccessManagerPrivate::clearCache(&manager);
6174 return; //XFAIL result above
6178 //next proxy auth should succeed, due to correct credentials
6179 helper.proxyUserName = "qsockstest";
6180 helper.proxyPassword = "password";
6183 //should fail due to no credentials
6184 reply.reset(manager.get(request));
6185 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6186 QTestEventLoop::instance().enterLoop(10);
6187 QVERIFY(!QTestEventLoop::instance().timeout());
6189 QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError);
6190 QVERIFY(authSpy.count() > 0);
6193 QVERIFY(proxyAuthSpy.count() > 0);
6194 proxyAuthSpy.clear();
6197 //should fail due to bad credentials
6198 helper.httpUserName = "baduser";
6199 helper.httpPassword = "badpassword";
6200 reply.reset(manager.get(request));
6201 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6202 QTestEventLoop::instance().enterLoop(10);
6203 QVERIFY(!QTestEventLoop::instance().timeout());
6205 QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError);
6206 QVERIFY(authSpy.count() > 0);
6209 //should be supplied from cache
6210 QCOMPARE(proxyAuthSpy.count(), 0);
6211 proxyAuthSpy.clear();
6214 //next auth should succeed, due to correct credentials
6215 helper.httpUserName = "httptest";
6216 helper.httpPassword = "httptest";
6218 reply.reset(manager.get(request));
6219 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6220 QTestEventLoop::instance().enterLoop(10);
6221 QVERIFY(!QTestEventLoop::instance().timeout());
6223 QCOMPARE(reply->error(), QNetworkReply::NoError);
6224 QVERIFY(authSpy.count() > 0);
6227 //should be supplied from cache
6228 QCOMPARE(proxyAuthSpy.count(), 0);
6229 proxyAuthSpy.clear();
6232 //next auth should use cached credentials
6233 reply.reset(manager.get(request));
6234 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6235 QTestEventLoop::instance().enterLoop(10);
6236 QVERIFY(!QTestEventLoop::instance().timeout());
6238 QCOMPARE(reply->error(), QNetworkReply::NoError);
6239 //should be supplied from cache
6240 QCOMPARE(authSpy.count(), 0);
6243 //should be supplied from cache
6244 QCOMPARE(proxyAuthSpy.count(), 0);
6245 proxyAuthSpy.clear();
6250 void tst_QNetworkReply::authenticationWithDifferentRealm()
6252 AuthenticationCacheHelper helper;
6253 QNetworkAccessManager manager;
6255 connect(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
6256 SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
6258 connect(&manager, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)), &helper, SLOT(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)));
6259 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), &helper, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
6261 helper.httpUserName = "httptest";
6262 helper.httpPassword = "httptest";
6264 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt"));
6265 QNetworkReply* reply = manager.get(request);
6266 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6267 QTestEventLoop::instance().enterLoop(10);
6268 QVERIFY(!QTestEventLoop::instance().timeout());
6269 QCOMPARE(reply->error(), QNetworkReply::NoError);
6271 helper.httpUserName = "httptest";
6272 helper.httpPassword = "httptest";
6274 request.setUrl(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/auth-digest/"));
6275 reply = manager.get(request);
6276 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6277 QTestEventLoop::instance().enterLoop(10);
6278 QVERIFY(!QTestEventLoop::instance().timeout());
6279 QCOMPARE(reply->error(), QNetworkReply::NoError);
6282 class QtBug13431Helper : public QObject {
6285 QNetworkReply* m_reply;
6288 void replyFinished(QNetworkReply*) {
6289 QTestEventLoop::instance().exitLoop();
6292 void onReadAndReschedule() {
6293 const qint64 bytesReceived = m_reply->bytesAvailable();
6294 if (bytesReceived && m_reply->readBufferSize()) {
6295 QByteArray data = m_reply->read(bytesReceived);
6297 const int millisecDelay = static_cast<int>(bytesReceived * 1000 / m_reply->readBufferSize());
6298 m_dlTimer.start(millisecDelay);
6302 m_dlTimer.start(200);
6307 void tst_QNetworkReply::qtbug13431replyThrottling()
6309 QtBug13431Helper helper;
6311 QNetworkAccessManager nam;
6312 connect(&nam, SIGNAL(finished(QNetworkReply*)), &helper, SLOT(replyFinished(QNetworkReply*)));
6314 // Download a bigger file
6315 QNetworkRequest netRequest(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/bigfile"));
6316 helper.m_reply = nam.get(netRequest);
6318 helper.m_reply->setReadBufferSize(36000);
6320 // Schedule a timer that tries to read
6322 connect(&helper.m_dlTimer, SIGNAL(timeout()), &helper, SLOT(onReadAndReschedule()));
6323 helper.m_dlTimer.setSingleShot(true);
6324 helper.m_dlTimer.start(0);
6326 QTestEventLoop::instance().enterLoop(30);
6327 QVERIFY(!QTestEventLoop::instance().timeout());
6328 QVERIFY(helper.m_reply->isFinished());
6329 QCOMPARE(helper.m_reply->error(), QNetworkReply::NoError);
6332 void tst_QNetworkReply::httpWithNoCredentialUsage()
6334 QNetworkAccessManager manager;
6336 QSignalSpy authSpy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
6337 QSignalSpy finishedSpy(&manager, SIGNAL(finished(QNetworkReply*)));
6339 // Get with credentials, to preload authentication cache
6341 QNetworkRequest request(QUrl("http://httptest:httptest@" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi"));
6342 QNetworkReplyPtr reply(manager.get(request));
6343 QVERIFY(waitForFinish(reply) == Success);
6344 // credentials in URL, so don't expect authentication signal
6345 QCOMPARE(authSpy.count(), 0);
6346 QCOMPARE(finishedSpy.count(), 1);
6347 finishedSpy.clear();
6350 // Get with cached credentials (normal usage)
6352 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi"));
6353 QNetworkReplyPtr reply(manager.get(request));
6354 QVERIFY(waitForFinish(reply) == Success);
6355 // credentials in cache, so don't expect authentication signal
6356 QCOMPARE(authSpy.count(), 0);
6357 QCOMPARE(finishedSpy.count(), 1);
6358 finishedSpy.clear();
6361 // Do not use cached credentials (webkit cross origin usage)
6363 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi"));
6364 request.setAttribute(QNetworkRequest::AuthenticationReuseAttribute, QNetworkRequest::Manual);
6365 QNetworkReplyPtr reply(manager.get(request));
6367 QSignalSpy errorSpy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError)));
6369 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6370 QTestEventLoop::instance().enterLoop(10);
6371 QVERIFY(!QTestEventLoop::instance().timeout());
6373 // We check if authenticationRequired was emitted, however we do not anything in it so it should be 401
6374 QCOMPARE(authSpy.count(), 1);
6375 QCOMPARE(finishedSpy.count(), 1);
6376 QCOMPARE(errorSpy.count(), 1);
6378 QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError);
6382 void tst_QNetworkReply::qtbug15311doubleContentLength()
6384 QByteArray response("HTTP/1.0 200 OK\r\nContent-Length: 3\r\nServer: bogus\r\nContent-Length: 3\r\n\r\nABC");
6385 MiniHttpServer server(response);
6386 server.doClose = true;
6388 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
6389 QNetworkReplyPtr reply(manager.get(request));
6391 QVERIFY(waitForFinish(reply) == Success);
6393 QVERIFY(reply->isFinished());
6394 QCOMPARE(reply->error(), QNetworkReply::NoError);
6395 QCOMPARE(reply->size(), qint64(3));
6396 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), qint64(3));
6397 QCOMPARE(reply->rawHeader("Content-length"), QByteArray("3, 3"));
6398 QCOMPARE(reply->readAll(), QByteArray("ABC"));
6401 void tst_QNetworkReply::qtbug18232gzipContentLengthZero()
6403 QByteArray response("HTTP/1.0 200 OK\r\nContent-Encoding: gzip\r\nContent-Length: 0\r\n\r\n");
6404 MiniHttpServer server(response);
6405 server.doClose = true;
6407 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
6408 QNetworkReplyPtr reply(manager.get(request));
6410 QVERIFY(waitForFinish(reply) == Success);
6412 QVERIFY(reply->isFinished());
6413 QCOMPARE(reply->error(), QNetworkReply::NoError);
6414 QCOMPARE(reply->size(), qint64(0));
6415 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), qint64(0));
6416 QCOMPARE(reply->readAll(), QByteArray());
6419 // Reproduced a crash in QHttpNetworkReplyPrivate::gunzipBodyPartiallyEnd
6420 // where zlib inflateEnd was called for uninitialized zlib stream
6421 void tst_QNetworkReply::qtbug22660gzipNoContentLengthEmptyContent()
6423 // Response with no Content-Length in header and empty content
6424 QByteArray response("HTTP/1.0 200 OK\r\nContent-Encoding: gzip\r\n\r\n");
6425 MiniHttpServer server(response);
6426 server.doClose = true;
6428 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
6429 QNetworkReplyPtr reply(manager.get(request));
6431 QVERIFY(waitForFinish(reply) == Success);
6433 QVERIFY(reply->isFinished());
6434 QCOMPARE(reply->error(), QNetworkReply::NoError);
6435 QCOMPARE(reply->size(), qint64(0));
6436 QVERIFY(!reply->header(QNetworkRequest::ContentLengthHeader).isValid());
6437 QCOMPARE(reply->readAll(), QByteArray());
6440 void tst_QNetworkReply::synchronousRequest_data()
6442 QTest::addColumn<QUrl>("url");
6443 QTest::addColumn<QString>("expected");
6444 QTest::addColumn<bool>("checkContentLength");
6445 QTest::addColumn<QString>("mimeType");
6447 // ### cache, auth, proxies
6449 QTest::newRow("http")
6450 << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt")
6451 << QString("file:" + testDataDir + "/rfc3252.txt")
6453 << QString("text/plain");
6455 QTest::newRow("http-gzip")
6456 << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/deflate/rfc3252.txt")
6457 << QString("file:" + testDataDir + "/rfc3252.txt")
6458 << false // don't check content length, because it's gzip encoded
6459 // ### we would need to enflate (un-deflate) the file content and compare the sizes
6460 << QString("text/plain");
6463 QTest::newRow("https")
6464 << QUrl("https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt")
6465 << QString("file:" + testDataDir + "/rfc3252.txt")
6467 << QString("text/plain");
6470 QTest::newRow("data")
6471 << QUrl(QString::fromLatin1("data:text/plain,hello world"))
6472 << QString("data:hello world")
6473 << true // check content length
6474 << QString("text/plain");
6476 QTest::newRow("simple-file")
6477 << QUrl::fromLocalFile(testDataDir + "/rfc3252.txt")
6478 << QString("file:" + testDataDir + "/rfc3252.txt")
6483 // FIXME add testcase for failing network etc
6484 void tst_QNetworkReply::synchronousRequest()
6487 QFETCH(QString, expected);
6488 QFETCH(bool, checkContentLength);
6489 QFETCH(QString, mimeType);
6491 QNetworkRequest request(url);
6494 // workaround for HTTPS requests: add self-signed server cert to list of CA certs,
6495 // since we cannot react to the sslErrors() signal
6496 // to fix this properly we would need to have an ignoreSslErrors() method in the
6497 // QNetworkRequest, see http://bugreports.qt-project.org/browse/QTBUG-14774
6498 if (url.scheme() == "https") {
6499 QSslConfiguration sslConf;
6500 QList<QSslCertificate> certs = QSslCertificate::fromPath(testDataDir + "/certs/qt-test-server-cacert.pem");
6501 sslConf.setCaCertificates(certs);
6502 request.setSslConfiguration(sslConf);
6506 request.setAttribute(
6507 QNetworkRequest::SynchronousRequestAttribute,
6510 QNetworkReplyPtr reply;
6511 QSignalSpy finishedSpy(&manager, SIGNAL(finished(QNetworkReply*)));
6512 QSignalSpy sslErrorsSpy(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)));
6513 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply, 0));
6514 QVERIFY(reply->isFinished());
6515 QCOMPARE(finishedSpy.count(), 0);
6516 QCOMPARE(sslErrorsSpy.count(), 0);
6518 QCOMPARE(reply->header(QNetworkRequest::ContentTypeHeader).toString(), mimeType);
6520 QByteArray expectedContent;
6522 if (expected.startsWith("file:")) {
6523 QString path = expected.mid(5);
6525 file.open(QIODevice::ReadOnly);
6526 expectedContent = file.readAll();
6527 } else if (expected.startsWith("data:")) {
6528 expectedContent = expected.mid(5).toUtf8();
6531 if (checkContentLength)
6532 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), qint64(expectedContent.size()));
6533 QCOMPARE(reply->readAll(), expectedContent);
6535 reply->deleteLater();
6539 void tst_QNetworkReply::synchronousRequestSslFailure()
6541 // test that SSL won't be accepted with self-signed certificate,
6542 // and that we do not emit the sslError signal (in the manager that is,
6543 // in the reply we don't care)
6545 QUrl url("https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt");
6546 QNetworkRequest request(url);
6547 request.setAttribute(
6548 QNetworkRequest::SynchronousRequestAttribute,
6550 QNetworkReplyPtr reply;
6551 QSignalSpy sslErrorsSpy(&manager, SIGNAL(sslErrors(QNetworkReply *, const QList<QSslError> &)));
6552 runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply, 0);
6553 QVERIFY(reply->isFinished());
6554 QCOMPARE(reply->error(), QNetworkReply::SslHandshakeFailedError);
6555 QCOMPARE(sslErrorsSpy.count(), 0);
6559 class HttpAbortHelper : public QObject
6563 HttpAbortHelper(QNetworkReply *parent)
6567 connect(parent, SIGNAL(readyRead()), this, SLOT(readyRead()));
6578 QMetaObject::invokeMethod(&QTestEventLoop::instance(), "exitLoop", Qt::QueuedConnection);
6582 QNetworkReply *mReply;
6585 void tst_QNetworkReply::httpAbort()
6587 // FIXME Also implement one where we do a big upload and then abort().
6588 // It must not crash either.
6590 // Abort after the first readyRead()
6591 QNetworkRequest request("http://" + QtNetworkSettings::serverName() + "/qtest/bigfile");
6592 QNetworkReplyPtr reply(manager.get(request));
6593 HttpAbortHelper replyHolder(reply.data());
6594 QTestEventLoop::instance().enterLoop(10);
6595 QVERIFY(!QTestEventLoop::instance().timeout());
6596 QCOMPARE(reply->error(), QNetworkReply::OperationCanceledError);
6597 QVERIFY(reply->isFinished());
6599 // Abort immediately after the get()
6600 QNetworkReplyPtr reply2(manager.get(request));
6601 connect(reply2, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
6603 QCOMPARE(reply2->error(), QNetworkReply::OperationCanceledError);
6604 QVERIFY(reply2->isFinished());
6606 // Abort after the finished()
6607 QNetworkRequest request3("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt");
6608 QNetworkReplyPtr reply3(manager.get(request3));
6610 QVERIFY(waitForFinish(reply3) == Success);
6612 QVERIFY(reply3->isFinished());
6614 QCOMPARE(reply3->error(), QNetworkReply::NoError);
6617 void tst_QNetworkReply::dontInsertPartialContentIntoTheCache()
6619 QByteArray reply206 =
6621 "Connection: keep-alive\r\n"
6622 "Content-Type: text/plain\r\n"
6623 "Cache-control: no-cache\r\n"
6624 "Content-Range: bytes 2-6/8\r\n"
6625 "Content-length: 4\r\n"
6629 MiniHttpServer server(reply206);
6630 server.doClose = false;
6632 MySpyMemoryCache *memoryCache = new MySpyMemoryCache(&manager);
6633 manager.setCache(memoryCache);
6635 QUrl url = "http://localhost:" + QString::number(server.serverPort());
6636 QNetworkRequest request(url);
6637 request.setRawHeader("Range", "bytes=2-6");
6639 QNetworkReplyPtr reply(manager.get(request));
6641 QVERIFY(waitForFinish(reply) == Success);
6643 QVERIFY(server.totalConnections > 0);
6644 QCOMPARE(reply->readAll().constData(), "load");
6645 QCOMPARE(memoryCache->m_insertedUrls.count(), 0);
6648 void tst_QNetworkReply::httpUserAgent()
6650 QByteArray response("HTTP/1.0 200 OK\r\n\r\n");
6651 MiniHttpServer server(response);
6652 server.doClose = true;
6654 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
6655 request.setHeader(QNetworkRequest::UserAgentHeader, "abcDEFghi");
6656 QNetworkReplyPtr reply(manager.get(request));
6658 QVERIFY(waitForFinish(reply) == Success);
6660 QVERIFY(reply->isFinished());
6661 QCOMPARE(reply->error(), QNetworkReply::NoError);
6662 QVERIFY(server.receivedData.contains("\r\nUser-Agent: abcDEFghi\r\n"));
6665 void tst_QNetworkReply::synchronousAuthenticationCache()
6667 class MiniAuthServer : public MiniHttpServer {
6669 MiniAuthServer(QThread *thread) : MiniHttpServer(QByteArray(), false, thread) {};
6670 virtual void reply() {
6673 "HTTP/1.0 401 Unauthorized\r\n"
6674 "WWW-Authenticate: Basic realm=\"QNetworkAccessManager Test Realm\"\r\n"
6675 "Content-Length: 4\r\n"
6676 "Connection: close\r\n"
6677 "Content-Type: text/plain\r\n"
6680 QRegExp rx("Authorization: Basic ([^\r\n]*)\r\n");
6681 if (rx.indexIn(receivedData) > 0) {
6682 if (QByteArray::fromBase64(rx.cap(1).toLatin1()) == "login:password") {
6684 "HTTP/1.0 200 OK\r\n"
6685 "Content-Type: text/plain\r\n"
6686 "Content-Length: 2\r\n"
6691 receivedData.clear();
6692 MiniHttpServer::reply();
6696 // when using synchronous commands, we need a different event loop for
6697 // the server thread, because the client is never returning to the
6699 QScopedPointer<QThread, QThreadCleanup> serverThread(new QThread);
6700 QScopedPointer<MiniHttpServer, QDeleteLaterCleanup> server(new MiniAuthServer(serverThread.data()));
6701 server->doClose = true;
6703 //1) URL without credentials, we are not authenticated
6705 QUrl url = "http://localhost:" + QString::number(server->serverPort()) + "/path";
6706 QNetworkRequest request(url);
6707 request.setAttribute(QNetworkRequest::SynchronousRequestAttribute, true);
6709 QNetworkReplyPtr reply(manager.get(request));
6710 QVERIFY(reply->isFinished());
6711 QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError);
6714 //2) URL with credentials, we are authenticated
6716 QUrl url = "http://login:password@localhost:" + QString::number(server->serverPort()) + "/path2";
6717 QNetworkRequest request(url);
6718 request.setAttribute(QNetworkRequest::SynchronousRequestAttribute, true);
6720 QNetworkReplyPtr reply(manager.get(request));
6721 QVERIFY(reply->isFinished());
6722 QCOMPARE(reply->error(), QNetworkReply::NoError);
6723 QCOMPARE(reply->readAll().constData(), "OK");
6726 //3) URL without credentials, we are authenticated because they are cached
6728 QUrl url = "http://localhost:" + QString::number(server->serverPort()) + "/path3";
6729 QNetworkRequest request(url);
6730 request.setAttribute(QNetworkRequest::SynchronousRequestAttribute, true);
6732 QNetworkReplyPtr reply(manager.get(request));
6733 QVERIFY(reply->isFinished());
6734 QCOMPARE(reply->error(), QNetworkReply::NoError);
6735 QCOMPARE(reply->readAll().constData(), "OK");
6739 void tst_QNetworkReply::pipelining()
6741 QString urlString("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/echo.cgi?");
6742 QList<QNetworkReplyPtr> replies;
6743 for (int a = 0; a < 20; a++) {
6744 QNetworkRequest request(urlString + QString::number(a));
6745 request.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, QVariant(true));
6746 replies.append(QNetworkReplyPtr(manager.get(request)));
6747 connect(replies.at(a), SIGNAL(finished()), this, SLOT(pipeliningHelperSlot()));
6749 QTestEventLoop::instance().enterLoop(20);
6750 QVERIFY(!QTestEventLoop::instance().timeout());
6753 void tst_QNetworkReply::pipeliningHelperSlot() {
6756 // check that pipelining was used in at least one of the replies
6757 static bool pipeliningWasUsed = false;
6758 QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
6759 bool pipeliningWasUsedInReply = reply->attribute(QNetworkRequest::HttpPipeliningWasUsedAttribute).toBool();
6760 if (pipeliningWasUsedInReply)
6761 pipeliningWasUsed = true;
6763 // check that the contents match (the response to echo.cgi?3 should return 3 etc.)
6764 QString urlQueryString = reply->url().query();
6765 QString content = reply->readAll();
6766 QVERIFY2(urlQueryString == content, "data corruption with pipelining detected");
6770 if (a == 20) { // all replies have finished
6771 QTestEventLoop::instance().exitLoop();
6772 QVERIFY2(pipeliningWasUsed, "pipelining was not used in any of the replies when trying to test pipelining");
6776 void tst_QNetworkReply::closeDuringDownload_data()
6778 QTest::addColumn<QUrl>("url");
6779 QTest::newRow("http") << QUrl("http://" + QtNetworkSettings::serverName() + "/bigfile");
6780 QTest::newRow("ftp") << QUrl("ftp://" + QtNetworkSettings::serverName() + "/qtest/bigfile");
6783 void tst_QNetworkReply::closeDuringDownload()
6786 QNetworkRequest request(url);
6787 QNetworkReply* reply = manager.get(request);
6788 connect(reply, SIGNAL(readyRead()), &QTestEventLoop::instance(), SLOT(exitLoop()));
6789 QTestEventLoop::instance().enterLoop(10);
6790 QVERIFY(!QTestEventLoop::instance().timeout());
6791 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
6793 reply->deleteLater();
6794 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
6797 void tst_QNetworkReply::ftpAuthentication_data()
6799 QTest::addColumn<QString>("referenceName");
6800 QTest::addColumn<QString>("url");
6801 QTest::addColumn<int>("error");
6803 QTest::newRow("invalidPassword") << (testDataDir + "/rfc3252.txt") << "ftp://ftptest:invalid@" + QtNetworkSettings::serverName() + "/home/qt-test-server/ftp/qtest/rfc3252.txt" << int(QNetworkReply::AuthenticationRequiredError);
6804 QTest::newRow("validPassword") << (testDataDir + "/rfc3252.txt") << "ftp://ftptest:password@" + QtNetworkSettings::serverName() + "/home/qt-test-server/ftp/qtest/rfc3252.txt" << int(QNetworkReply::NoError);
6807 void tst_QNetworkReply::ftpAuthentication()
6809 QFETCH(QString, referenceName);
6810 QFETCH(QString, url);
6813 QFile reference(referenceName);
6814 QVERIFY(reference.open(QIODevice::ReadOnly));
6816 QNetworkRequest request(url);
6817 QNetworkReplyPtr reply;
6818 runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply);
6820 QCOMPARE(reply->url(), request.url());
6821 QCOMPARE(reply->error(), QNetworkReply::NetworkError(error));
6824 void tst_QNetworkReply::backgroundRequest_data()
6826 QTest::addColumn<QUrl>("url");
6827 QTest::addColumn<bool>("background");
6828 QTest::addColumn<int>("policy");
6829 QTest::addColumn<QNetworkReply::NetworkError>("error");
6831 QUrl httpurl("http://" + QtNetworkSettings::serverName());
6832 QUrl httpsurl("https://" + QtNetworkSettings::serverName());
6833 QUrl ftpurl("ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt");
6835 QTest::newRow("http, fg, normal") << httpurl << false << (int)QNetworkSession::NoPolicy << QNetworkReply::NoError;
6836 QTest::newRow("http, bg, normal") << httpurl << true << (int)QNetworkSession::NoPolicy << QNetworkReply::NoError;
6837 QTest::newRow("http, fg, nobg") << httpurl << false << (int)QNetworkSession::NoBackgroundTrafficPolicy << QNetworkReply::NoError;
6838 QTest::newRow("http, bg, nobg") << httpurl << true << (int)QNetworkSession::NoBackgroundTrafficPolicy << QNetworkReply::BackgroundRequestNotAllowedError;
6841 QTest::newRow("https, fg, normal") << httpsurl << false << (int)QNetworkSession::NoPolicy << QNetworkReply::NoError;
6842 QTest::newRow("https, bg, normal") << httpsurl << true << (int)QNetworkSession::NoPolicy << QNetworkReply::NoError;
6843 QTest::newRow("https, fg, nobg") << httpsurl << false << (int)QNetworkSession::NoBackgroundTrafficPolicy << QNetworkReply::NoError;
6844 QTest::newRow("https, bg, nobg") << httpsurl << true << (int)QNetworkSession::NoBackgroundTrafficPolicy << QNetworkReply::BackgroundRequestNotAllowedError;
6847 QTest::newRow("ftp, fg, normal") << ftpurl << false << (int)QNetworkSession::NoPolicy << QNetworkReply::NoError;
6848 QTest::newRow("ftp, bg, normal") << ftpurl << true << (int)QNetworkSession::NoPolicy << QNetworkReply::NoError;
6849 QTest::newRow("ftp, fg, nobg") << ftpurl << false << (int)QNetworkSession::NoBackgroundTrafficPolicy << QNetworkReply::NoError;
6850 QTest::newRow("ftp, bg, nobg") << ftpurl << true << (int)QNetworkSession::NoBackgroundTrafficPolicy << QNetworkReply::BackgroundRequestNotAllowedError;
6854 //test purpose: background requests can't be started when not allowed
6855 void tst_QNetworkReply::backgroundRequest()
6857 #ifdef QT_BUILD_INTERNAL
6858 #ifndef QT_NO_BEARERMANAGEMENT
6860 QFETCH(bool, background);
6861 QFETCH(int, policy);
6862 QFETCH(QNetworkReply::NetworkError, error);
6864 QNetworkRequest request(url);
6867 request.setAttribute(QNetworkRequest::BackgroundRequestAttribute, QVariant::fromValue(true));
6869 //this preconstructs the session so we can change policies in advance
6870 manager.setConfiguration(networkConfiguration);
6873 connect(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
6874 SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
6877 const QWeakPointer<const QNetworkSession> session = QNetworkAccessManagerPrivate::getNetworkSession(&manager);
6879 QNetworkSession::UsagePolicies original = session.data()->usagePolicies();
6880 QNetworkSessionPrivate::setUsagePolicies(*const_cast<QNetworkSession *>(session.data()), QNetworkSession::UsagePolicies(policy));
6882 QNetworkReplyPtr reply(manager.get(request));
6884 QVERIFY(waitForFinish(reply) != Timeout);
6886 QNetworkSessionPrivate::setUsagePolicies(*const_cast<QNetworkSession *>(session.data()), original);
6888 QVERIFY(reply->isFinished());
6889 QCOMPARE(reply->error(), error);
6894 void tst_QNetworkReply::backgroundRequestInterruption_data()
6896 QTest::addColumn<QUrl>("url");
6897 QTest::addColumn<bool>("background");
6898 QTest::addColumn<QNetworkReply::NetworkError>("error");
6900 QUrl httpurl("http://" + QtNetworkSettings::serverName() + "/qtest/mediumfile");
6901 QUrl httpsurl("https://" + QtNetworkSettings::serverName() + "/qtest/mediumfile");
6902 QUrl ftpurl("ftp://" + QtNetworkSettings::serverName() + "/qtest/bigfile");
6904 QTest::newRow("http, fg, nobg") << httpurl << false << QNetworkReply::NoError;
6905 QTest::newRow("http, bg, nobg") << httpurl << true << QNetworkReply::BackgroundRequestNotAllowedError;
6908 QTest::newRow("https, fg, nobg") << httpsurl << false << QNetworkReply::NoError;
6909 QTest::newRow("https, bg, nobg") << httpsurl << true << QNetworkReply::BackgroundRequestNotAllowedError;
6912 QTest::newRow("ftp, fg, nobg") << ftpurl << false << QNetworkReply::NoError;
6913 QTest::newRow("ftp, bg, nobg") << ftpurl << true << QNetworkReply::BackgroundRequestNotAllowedError;
6917 //test purpose: background requests in progress are aborted when policy changes to disallow them
6918 void tst_QNetworkReply::backgroundRequestInterruption()
6920 #ifdef QT_BUILD_INTERNAL
6921 #ifndef QT_NO_BEARERMANAGEMENT
6923 QFETCH(bool, background);
6924 QFETCH(QNetworkReply::NetworkError, error);
6926 QNetworkRequest request(url);
6929 request.setAttribute(QNetworkRequest::BackgroundRequestAttribute, QVariant::fromValue(true));
6931 //this preconstructs the session so we can change policies in advance
6932 manager.setConfiguration(networkConfiguration);
6935 connect(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
6936 SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
6939 const QWeakPointer<const QNetworkSession> session = QNetworkAccessManagerPrivate::getNetworkSession(&manager);
6941 QNetworkSession::UsagePolicies original = session.data()->usagePolicies();
6942 QNetworkSessionPrivate::setUsagePolicies(*const_cast<QNetworkSession *>(session.data()), QNetworkSession::NoPolicy);
6944 request.setAttribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute, 8192);
6945 QNetworkReplyPtr reply(manager.get(request));
6946 reply->setReadBufferSize(1024);
6948 QSignalSpy spy(reply.data(), SIGNAL(readyRead()));
6949 QTRY_VERIFY(spy.count() > 0);
6951 QNetworkSessionPrivate::setUsagePolicies(*const_cast<QNetworkSession *>(session.data()), QNetworkSession::NoBackgroundTrafficPolicy);
6953 // After we have changed the policy we can download at full speed.
6954 reply->setReadBufferSize(0);
6956 QVERIFY(waitForFinish(reply) != Timeout);
6958 QNetworkSessionPrivate::setUsagePolicies(*const_cast<QNetworkSession *>(session.data()), original);
6960 QVERIFY(reply->isFinished());
6961 QCOMPARE(reply->error(), error);
6966 void tst_QNetworkReply::backgroundRequestConnectInBackground_data()
6968 QTest::addColumn<QUrl>("url");
6969 QTest::addColumn<bool>("background");
6971 QUrl httpurl("http://" + QtNetworkSettings::serverName());
6972 QUrl ftpurl("ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt");
6974 QTest::newRow("http, fg") << httpurl << false;
6975 QTest::newRow("http, bg") << httpurl << true;
6977 QTest::newRow("ftp, fg") << ftpurl << false;
6978 QTest::newRow("ftp, bg") << ftpurl << true;
6981 //test purpose: check that backgroundness is propagated to the network session
6982 void tst_QNetworkReply::backgroundRequestConnectInBackground()
6984 #ifdef QT_BUILD_INTERNAL
6985 #ifndef QT_NO_BEARERMANAGEMENT
6987 QFETCH(bool, background);
6989 QNetworkRequest request(url);
6992 request.setAttribute(QNetworkRequest::BackgroundRequestAttribute, QVariant::fromValue(true));
6994 QWeakPointer<const QNetworkSession> session = QNetworkAccessManagerPrivate::getNetworkSession(&manager);
6995 //force QNAM to reopen the session.
6996 if (session && session.data()->isOpen()) {
6997 const_cast<QNetworkSession *>(session.data())->close();
6998 QCoreApplication::processEvents(); //let signals propagate inside QNAM
7001 //this preconstructs the session so we can change policies in advance
7002 manager.setConfiguration(networkConfiguration);
7004 session = QNetworkAccessManagerPrivate::getNetworkSession(&manager);
7006 QNetworkSession::UsagePolicies original = session.data()->usagePolicies();
7007 QNetworkSessionPrivate::setUsagePolicies(*const_cast<QNetworkSession *>(session.data()), QNetworkSession::NoPolicy);
7009 QNetworkReplyPtr reply(manager.get(request));
7011 QVERIFY(waitForFinish(reply) != Timeout);
7012 session = QNetworkAccessManagerPrivate::getNetworkSession(&manager);
7014 QVariant cib = session.data()->sessionProperty(QStringLiteral("ConnectInBackground"));
7016 QSKIP("inconclusive - ConnectInBackground session property not supported by the bearer plugin");
7017 QCOMPARE(cib.toBool(), background);
7018 QNetworkSessionPrivate::setUsagePolicies(*const_cast<QNetworkSession *>(session.data()), original);
7020 QSKIP("inconclusive - network session has been destroyed");
7023 QVERIFY(reply->isFinished());
7028 // NOTE: This test must be last testcase in tst_qnetworkreply!
7029 void tst_QNetworkReply::parentingRepliesToTheApp()
7031 QNetworkRequest request (QUrl("http://" + QtNetworkSettings::serverName()));
7032 manager.get(request)->setParent(this); // parent to this object
7033 manager.get(request)->setParent(qApp); // parent to the app
7036 QTEST_MAIN(tst_QNetworkReply)
7038 #include "tst_qnetworkreply.moc"