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();
409 // NOTE: This test must be last!
410 void parentingRepliesToTheApp();
415 bool tst_QNetworkReply::seedCreated = false;
421 char *toString(const QNetworkReply::NetworkError& code)
423 const QMetaObject *mo = &QNetworkReply::staticMetaObject;
424 int index = mo->indexOfEnumerator("NetworkError");
428 QMetaEnum qme = mo->enumerator(index);
429 return qstrdup(qme.valueToKey(code));
433 char *toString(const QNetworkCookie &cookie)
435 return qstrdup(cookie.toRawForm());
439 char *toString(const QList<QNetworkCookie> &list)
441 QString result = "QList(";
443 foreach (QNetworkCookie cookie, list) {
447 result += QString::fromLatin1("QNetworkCookie(%1)").arg(QLatin1String(cookie.toRawForm()));
450 return qstrdup(result.append(')').toLocal8Bit());
456 #define RUN_REQUEST(call) \
458 QString errorMsg = call; \
459 if (!errorMsg.isEmpty()) \
460 QFAIL(qPrintable(errorMsg)); \
464 static void setupSslServer(QSslSocket* serverSocket)
466 QString testDataDir = QFileInfo(QFINDTESTDATA("rfc3252.txt")).absolutePath();
467 if (testDataDir.isEmpty())
468 testDataDir = QCoreApplication::applicationDirPath();
470 serverSocket->setProtocol(QSsl::AnyProtocol);
471 serverSocket->setLocalCertificate(testDataDir + "/certs/server.pem");
472 serverSocket->setPrivateKey(testDataDir + "/certs/server.key");
476 // Does not work for POST/PUT!
477 class MiniHttpServer: public QTcpServer
481 QTcpSocket *client; // always the last one that was received
482 QByteArray dataToTransmit;
483 QByteArray receivedData;
489 int totalConnections;
491 MiniHttpServer(const QByteArray &data, bool ssl = false, QThread *thread = 0, bool useipv6 = false)
492 : client(0), dataToTransmit(data), doClose(true), doSsl(ssl), ipv6(useipv6),
493 multiple(false), totalConnections(0)
496 listen(QHostAddress::AnyIPv6);
498 listen(QHostAddress::AnyIPv4);
501 connect(thread, SIGNAL(started()), this, SLOT(threadStartedSlot()));
502 moveToThread(thread);
509 void incomingConnection(qintptr socketDescriptor)
511 //qDebug() << "incomingConnection" << socketDescriptor << "doSsl:" << doSsl << "ipv6:" << ipv6;
513 client = new QTcpSocket;
514 client->setSocketDescriptor(socketDescriptor);
515 connectSocketSignals();
518 QSslSocket *serverSocket = new QSslSocket;
519 serverSocket->setParent(this);
520 if (serverSocket->setSocketDescriptor(socketDescriptor)) {
521 connect(serverSocket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(slotSslErrors(QList<QSslError>)));
522 setupSslServer(serverSocket);
523 serverSocket->startServerEncryption();
524 client = serverSocket;
525 connectSocketSignals();
532 client->setParent(this);
536 virtual void reply() {
537 // we need to emulate the bytesWrittenSlot call if the data is empty.
538 if (dataToTransmit.size() == 0)
539 QMetaObject::invokeMethod(this, "bytesWrittenSlot", Qt::QueuedConnection);
541 client->write(dataToTransmit);
544 void connectSocketSignals()
546 //qDebug() << "connectSocketSignals" << client;
547 connect(client, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
548 connect(client, SIGNAL(bytesWritten(qint64)), this, SLOT(bytesWrittenSlot()));
549 connect(client, SIGNAL(error(QAbstractSocket::SocketError)),
550 this, SLOT(slotError(QAbstractSocket::SocketError)));
555 void slotSslErrors(const QList<QSslError>& errors)
557 qDebug() << "slotSslErrors" << client->errorString() << errors;
560 void slotError(QAbstractSocket::SocketError err)
562 qDebug() << "slotError" << err << client->errorString();
568 receivedData += client->readAll();
569 int doubleEndlPos = receivedData.indexOf("\r\n\r\n");
571 if (doubleEndlPos != -1) {
572 // multiple requests incoming. remove the bytes of the current one
574 receivedData.remove(0, doubleEndlPos+4);
580 void bytesWrittenSlot() {
581 if (doClose && client->bytesToWrite() == 0) {
582 client->disconnectFromHost();
583 disconnect(client, 0, this, 0);
587 void threadStartedSlot()
593 class MyCookieJar: public QNetworkCookieJar
596 inline QList<QNetworkCookie> allCookies() const
597 { return QNetworkCookieJar::allCookies(); }
598 inline void setAllCookies(const QList<QNetworkCookie> &cookieList)
599 { QNetworkCookieJar::setAllCookies(cookieList); }
602 class MyProxyFactory: public QNetworkProxyFactory
606 QList<QNetworkProxy> toReturn;
607 QNetworkProxyQuery lastQuery;
608 inline MyProxyFactory() { clear(); }
613 toReturn = QList<QNetworkProxy>() << QNetworkProxy::DefaultProxy;
614 lastQuery = QNetworkProxyQuery();
617 virtual QList<QNetworkProxy> queryProxy(const QNetworkProxyQuery &query)
625 class MyMemoryCache: public QAbstractNetworkCache
628 typedef QPair<QNetworkCacheMetaData, QByteArray> CachedContent;
629 typedef QHash<QByteArray, CachedContent> CacheData;
632 MyMemoryCache(QObject *parent) : QAbstractNetworkCache(parent) {}
634 QNetworkCacheMetaData metaData(const QUrl &url)
636 return cache.value(url.toEncoded()).first;
639 void updateMetaData(const QNetworkCacheMetaData &metaData)
641 cache[metaData.url().toEncoded()].first = metaData;
644 QIODevice *data(const QUrl &url)
646 CacheData::ConstIterator it = cache.find(url.toEncoded());
647 if (it == cache.constEnd())
649 QBuffer *io = new QBuffer(this);
650 io->setData(it->second);
651 io->open(QIODevice::ReadOnly);
656 bool remove(const QUrl &url)
658 cache.remove(url.toEncoded());
662 qint64 cacheSize() const
665 foreach (const CachedContent &entry, cache)
666 total += entry.second.size();
670 QIODevice *prepare(const QNetworkCacheMetaData &)
672 qFatal("%s: Should not have tried to add to the cache", Q_FUNC_INFO);
675 void insert(QIODevice *)
677 qFatal("%s: Should not have tried to add to the cache", Q_FUNC_INFO);
680 void clear() { cache.clear(); }
682 Q_DECLARE_METATYPE(MyMemoryCache::CachedContent)
683 Q_DECLARE_METATYPE(MyMemoryCache::CacheData)
685 class MySpyMemoryCache: public QAbstractNetworkCache
688 MySpyMemoryCache(QObject *parent) : QAbstractNetworkCache(parent) {}
691 qDeleteAll(m_buffers);
695 QHash<QUrl, QIODevice*> m_buffers;
696 QList<QUrl> m_insertedUrls;
698 QNetworkCacheMetaData metaData(const QUrl &)
700 return QNetworkCacheMetaData();
703 void updateMetaData(const QNetworkCacheMetaData &)
707 QIODevice *data(const QUrl &)
712 bool remove(const QUrl &url)
714 delete m_buffers.take(url);
715 return m_insertedUrls.removeAll(url) > 0;
718 qint64 cacheSize() const
723 QIODevice *prepare(const QNetworkCacheMetaData &metaData)
725 QBuffer* buffer = new QBuffer;
726 buffer->open(QIODevice::ReadWrite);
727 buffer->setProperty("url", metaData.url());
728 m_buffers.insert(metaData.url(), buffer);
732 void insert(QIODevice *buffer)
734 QUrl url = buffer->property("url").toUrl();
735 m_insertedUrls << url;
736 delete m_buffers.take(url);
739 void clear() { m_insertedUrls.clear(); }
742 class DataReader: public QObject
750 DataReader(const QNetworkReplyPtr &dev, bool acc = true) : totalBytes(0), device(dev.data()), accumulate(acc)
751 { connect(device, SIGNAL(readyRead()), SLOT(doRead()) ); }
752 DataReader(QIODevice *dev, bool acc = true) : totalBytes(0), device(dev), accumulate(acc)
754 connect(device, SIGNAL(readyRead()), SLOT(doRead()));
761 buffer.resize(device->bytesAvailable());
762 qint64 bytesRead = device->read(buffer.data(), device->bytesAvailable());
763 if (bytesRead == -1) {
764 QTestEventLoop::instance().exitLoop();
767 buffer.truncate(bytesRead);
768 totalBytes += bytesRead;
776 class SocketPair: public QObject
780 QIODevice *endPoints[2];
782 SocketPair(QObject *parent = 0)
785 endPoints[0] = endPoints[1] = 0;
793 QTcpSocket *active = new QTcpSocket(this);
794 active->connectToHost("127.0.0.1", server.serverPort());
796 // need more time as working with embedded
797 // device and testing from emualtor
798 // things tend to get slower
799 if (!active->waitForConnected(1000))
802 if (!server.waitForNewConnection(1000))
805 QTcpSocket *passive = server.nextPendingConnection();
806 passive->setParent(this);
808 endPoints[0] = active;
809 endPoints[1] = passive;
814 // A blocking tcp server (must be used in a thread) which supports SSL.
815 class BlockingTcpServer : public QTcpServer
819 BlockingTcpServer(bool ssl) : doSsl(ssl), sslSocket(0) {}
821 QTcpSocket* waitForNextConnectionSocket() {
822 waitForNewConnection(-1);
825 qFatal("%s: sslSocket should not be null after calling waitForNewConnection()",
829 //qDebug() << "returning nextPendingConnection";
830 return nextPendingConnection();
833 virtual void incomingConnection(qintptr socketDescriptor)
837 QSslSocket *serverSocket = new QSslSocket;
838 serverSocket->setParent(this);
839 serverSocket->setSocketDescriptor(socketDescriptor);
840 connect(serverSocket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(slotSslErrors(QList<QSslError>)));
841 setupSslServer(serverSocket);
842 serverSocket->startServerEncryption();
843 sslSocket = serverSocket;
847 QTcpServer::incomingConnection(socketDescriptor);
853 void slotSslErrors(const QList<QSslError>& errors)
855 qDebug() << "slotSslErrors" << sslSocket->errorString() << errors;
861 QTcpSocket* sslSocket;
864 // This server tries to send data as fast as possible (like most servers)
865 // but it measures how fast it was able to send it, which shows at which
866 // rate the reader is processing the data.
867 class FastSender: public QThread
873 enum Protocol { DebugPipe, ProvidedData };
874 const Protocol protocol;
876 const bool fillKernelBuffer;
881 QByteArray dataToTransmit;
884 // a server that sends debugpipe data
885 FastSender(qint64 size)
886 : wantedSize(size), port(-1), protocol(DebugPipe),
887 doSsl(false), fillKernelBuffer(true), transferRate(-1),
894 // a server that sends the data provided at construction time, useful for HTTP
895 FastSender(const QByteArray& data, bool https, bool fillBuffer)
896 : wantedSize(data.size()), port(-1), protocol(ProvidedData),
897 doSsl(https), fillKernelBuffer(fillBuffer), transferRate(-1),
898 dataToTransmit(data), dataIndex(0)
904 inline int serverPort() const { return port; }
906 int writeNextData(QTcpSocket* socket, qint32 size)
908 if (protocol == DebugPipe) {
910 QDataStream stream(&data, QIODevice::WriteOnly);
911 stream << QVariantMap() << QByteArray(size, 'a');
912 socket->write((char*)&size, sizeof size);
917 const QByteArray data = dataToTransmit.mid(dataIndex, size);
919 dataIndex += data.size();
920 //qDebug() << "wrote" << dataIndex << "/" << dataToTransmit.size();
924 void writeLastData(QTcpSocket* socket)
926 if (protocol == DebugPipe) {
928 QDataStream stream(&data, QIODevice::WriteOnly);
929 stream << QVariantMap() << QByteArray();
930 const qint32 size = data.size();
931 socket->write((char*)&size, sizeof size);
939 BlockingTcpServer server(doSsl);
941 port = server.serverPort();
944 QTcpSocket *client = server.waitForNextConnectionSocket();
946 // get the "request" packet
947 if (!client->waitForReadyRead(2000)) {
948 qDebug() << "FastSender:" << client->error() << "waiting for \"request\" packet";
951 client->readAll(); // we're not interested in the actual contents (e.g. HTTP request)
953 enum { BlockSize = 1024 };
955 if (fillKernelBuffer) {
957 // write a bunch of bytes to fill up the buffers
960 if (writeNextData(client, BlockSize) < BlockSize) {
961 qDebug() << "ERROR: FastSender: not enough data to write in order to fill buffers; or client is reading too fast";
964 while (client->bytesToWrite() > 0) {
965 if (!client->waitForBytesWritten(0)) {
970 //qDebug() << "Filling kernel buffer: wrote" << dataIndex << "bytes";
973 qDebug() << "FastSender: ok, kernel buffer is full after writing" << dataIndex << "bytes";
976 // Tell the client to start reading
979 // the kernel buffer is full
980 // clean up QAbstractSocket's residue:
981 while (client->bytesToWrite() > 0) {
982 qDebug() << "Still having" << client->bytesToWrite() << "bytes to write, doing that now";
983 if (!client->waitForBytesWritten(2000)) {
984 qDebug() << "ERROR: FastSender:" << client->error() << "cleaning up residue";
989 // now write in "blocking mode", this is where the rate measuring starts
992 //const qint64 writtenBefore = dataIndex;
993 //qint64 measuredTotalBytes = wantedSize - writtenBefore;
994 qint64 measuredSentBytes = 0;
995 while (dataIndex < wantedSize) {
996 const int remainingBytes = wantedSize - measuredSentBytes;
997 const int bytesToWrite = qMin(remainingBytes, static_cast<int>(BlockSize));
998 if (bytesToWrite <= 0)
999 qFatal("%s: attempt to write %d bytes", Q_FUNC_INFO, bytesToWrite);
1000 measuredSentBytes += writeNextData(client, bytesToWrite);
1002 while (client->bytesToWrite() > 0) {
1003 if (!client->waitForBytesWritten(2000)) {
1004 qDebug() << "ERROR: FastSender:" << client->error() << "during blocking write";
1008 /*qDebug() << "FastSender:" << bytesToWrite << "bytes written now;"
1009 << measuredSentBytes << "measured bytes" << measuredSentBytes + writtenBefore << "total ("
1010 << measuredSentBytes*100/measuredTotalBytes << "% complete);"
1011 << timer.elapsed() << "ms elapsed";*/
1014 transferRate = measuredSentBytes * 1000 / timer.elapsed();
1015 qDebug() << "FastSender: flushed" << measuredSentBytes << "bytes in" << timer.elapsed() << "ms: rate =" << transferRate << "B/s";
1017 // write a "close connection" packet, if the protocol needs it
1018 writeLastData(client);
1024 class RateControlledReader: public QObject
1033 qint64 totalBytesRead;
1034 RateControlledReader(QObject& senderObj, QIODevice *dev, int kbPerSec, int maxBufferSize = 0)
1035 : device(dev), readBufferSize(maxBufferSize), totalBytesRead(0)
1037 // determine how often we have to wake up
1039 if (readBufferSize == 0) {
1040 // The requirement is simply "N KB per seconds"
1041 timesPerSecond = 20;
1042 bytesToRead = kbPerSec * 1024 / timesPerSecond;
1044 // The requirement also includes "<readBufferSize> bytes at a time"
1045 bytesToRead = readBufferSize;
1046 timesPerSecond = kbPerSec * 1024 / readBufferSize;
1048 interval = 1000 / timesPerSecond; // in ms
1050 qDebug() << "RateControlledReader: going to read" << bytesToRead
1051 << "bytes every" << interval << "ms";
1052 qDebug() << "actual read rate will be"
1053 << (bytesToRead * 1000 / interval) << "bytes/sec (wanted"
1054 << kbPerSec * 1024 << "bytes/sec)";
1056 // Wait for data to be readyRead
1057 bool ok = connect(&senderObj, SIGNAL(dataReady()), this, SLOT(slotDataReady()));
1059 qFatal("%s: Cannot connect dataReady signal", Q_FUNC_INFO);
1064 QByteArray someData = device->read(device->bytesAvailable());
1066 totalBytesRead += someData.size();
1067 qDebug() << "wrapUp: found" << someData.size() << "bytes left. progress" << data.size();
1068 //qDebug() << "wrapUp: now bytesAvailable=" << device->bytesAvailable();
1072 void slotDataReady()
1074 //qDebug() << "RateControlledReader: ready to go";
1075 startTimer(interval);
1079 void timerEvent(QTimerEvent *)
1081 //qDebug() << "RateControlledReader: timerEvent bytesAvailable=" << device->bytesAvailable();
1082 if (readBufferSize > 0 && device->bytesAvailable() > readBufferSize) {
1083 // This passes all the time, except in the final flush.
1084 //qFatal("%s: Too many bytes available", Q_FUNC_INFO);
1087 qint64 bytesRead = 0;
1091 if (device->bytesAvailable() == 0) {
1092 if (stopWatch.elapsed() > 20) {
1093 qDebug() << "RateControlledReader: Not enough data available for reading, waited too much, timing out";
1096 if (!device->waitForReadyRead(5)) {
1097 qDebug() << "RateControlledReader: Not enough data available for reading, even after waiting 5ms, bailing out";
1101 QByteArray someData = device->read(bytesToRead - bytesRead);
1103 bytesRead += someData.size();
1104 //qDebug() << "RateControlledReader: successfully read" << someData.size() << "progress:" << data.size();
1105 } while (bytesRead < bytesToRead);
1106 totalBytesRead += bytesRead;
1108 if (bytesRead < bytesToRead)
1109 qWarning() << "RateControlledReader: WARNING:" << bytesToRead - bytesRead << "bytes not read";
1114 tst_QNetworkReply::tst_QNetworkReply()
1116 qRegisterMetaType<QNetworkReply *>(); // for QSignalSpy
1117 qRegisterMetaType<QAuthenticator *>();
1118 qRegisterMetaType<QNetworkProxy>();
1120 qRegisterMetaType<QList<QSslError> >();
1122 qRegisterMetaType<QNetworkReply::NetworkError>();
1124 testFileName = QDir::currentPath() + "/testfile";
1125 uniqueExtension = createUniqueExtension();
1126 cookieJar = new MyCookieJar;
1127 manager.setCookieJar(cookieJar);
1129 QHostInfo hostInfo = QHostInfo::fromName(QtNetworkSettings::serverName());
1131 proxies << ProxyData(QNetworkProxy::NoProxy, "", false);
1133 if (hostInfo.error() == QHostInfo::NoError && !hostInfo.addresses().isEmpty()) {
1134 QString proxyserver = hostInfo.addresses().first().toString();
1135 proxies << ProxyData(QNetworkProxy(QNetworkProxy::HttpProxy, proxyserver, 3128), "+proxy", false)
1136 << ProxyData(QNetworkProxy(QNetworkProxy::HttpProxy, proxyserver, 3129), "+proxyauth", true)
1137 // currently unsupported
1138 // << ProxyData(QNetworkProxy(QNetworkProxy::HttpProxy, proxyserver, 3130), "+proxyauth-ntlm", true);
1139 << ProxyData(QNetworkProxy(QNetworkProxy::Socks5Proxy, proxyserver, 1080), "+socks", false)
1140 << ProxyData(QNetworkProxy(QNetworkProxy::Socks5Proxy, proxyserver, 1081), "+socksauth", true);
1142 printf("==================================================================\n");
1143 printf("Proxy could not be looked up. No proxy will be used while testing!\n");
1144 printf("==================================================================\n");
1148 tst_QNetworkReply::~tst_QNetworkReply()
1153 void tst_QNetworkReply::authenticationRequired(QNetworkReply*, QAuthenticator* auth)
1155 auth->setUser("httptest");
1156 auth->setPassword("httptest");
1159 void tst_QNetworkReply::proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator* auth)
1161 auth->setUser("qsockstest");
1162 auth->setPassword("password");
1166 void tst_QNetworkReply::sslErrors(QNetworkReply *reply, const QList<QSslError> &errors)
1168 reply->ignoreSslErrors();
1169 QVERIFY(!errors.isEmpty());
1170 QVERIFY(!reply->sslConfiguration().isNull());
1173 void tst_QNetworkReply::storeSslConfiguration()
1175 storedSslConfiguration = QSslConfiguration();
1176 QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
1178 storedSslConfiguration = reply->sslConfiguration();
1182 QString tst_QNetworkReply::runMultipartRequest(const QNetworkRequest &request,
1183 QNetworkReplyPtr &reply,
1184 QHttpMultiPart *multiPart,
1185 const QByteArray &verb)
1188 reply.reset(manager.post(request, multiPart));
1190 reply.reset(manager.put(request, multiPart));
1192 // the code below is copied from tst_QNetworkReply::runSimpleRequest, see below
1193 reply->setParent(this);
1194 connect(reply, SIGNAL(finished()), SLOT(finished()));
1195 connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(gotError()));
1196 multiPart->setParent(reply.data());
1198 returnCode = Timeout;
1199 loop = new QEventLoop;
1200 QTimer::singleShot(25000, loop, SLOT(quit()));
1201 int code = returnCode == Timeout ? loop->exec() : returnCode;
1207 return "Request failed: " + reply->errorString();
1209 return "Network timeout";
1214 QString tst_QNetworkReply::runSimpleRequest(QNetworkAccessManager::Operation op,
1215 const QNetworkRequest &request,
1216 QNetworkReplyPtr &reply,
1217 const QByteArray &data)
1220 case QNetworkAccessManager::HeadOperation:
1221 reply.reset(manager.head(request));
1224 case QNetworkAccessManager::GetOperation:
1225 reply.reset(manager.get(request));
1228 case QNetworkAccessManager::PutOperation:
1229 reply.reset(manager.put(request, data));
1232 case QNetworkAccessManager::PostOperation:
1233 reply.reset(manager.post(request, data));
1236 case QNetworkAccessManager::DeleteOperation:
1237 reply.reset(manager.deleteResource(request));
1241 qFatal("%s: Invalid/unknown operation requested", Q_FUNC_INFO);
1243 reply->setParent(this);
1245 returnCode = Timeout;
1248 if (request.attribute(QNetworkRequest::SynchronousRequestAttribute).toBool()) {
1249 if (reply->isFinished())
1250 code = reply->error() != QNetworkReply::NoError ? Failure : Success;
1254 connect(reply, SIGNAL(finished()), SLOT(finished()));
1255 connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(gotError()));
1258 loop = new QEventLoop;
1259 QSignalSpy spy(reply.data(), SIGNAL(downloadProgress(qint64,qint64)));
1260 while (!reply->isFinished()) {
1261 QTimer::singleShot(20000, loop, SLOT(quit()));
1262 code = loop->exec();
1263 if (count == spy.count() && !reply->isFinished()) {
1267 count = spy.count();
1275 return "Request failed: " + reply->errorString();
1277 return "Network timeout";
1282 QString tst_QNetworkReply::runCustomRequest(const QNetworkRequest &request,
1283 QNetworkReplyPtr &reply,
1284 const QByteArray &verb,
1287 reply.reset(manager.sendCustomRequest(request, verb, data));
1288 reply->setParent(this);
1289 connect(reply, SIGNAL(finished()), SLOT(finished()));
1290 connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(gotError()));
1292 returnCode = Timeout;
1293 loop = new QEventLoop;
1294 QTimer::singleShot(20000, loop, SLOT(quit()));
1295 int code = returnCode == Timeout ? loop->exec() : returnCode;
1301 return "Request failed: " + reply->errorString();
1303 return "Network timeout";
1308 int tst_QNetworkReply::waitForFinish(QNetworkReplyPtr &reply)
1312 connect(reply, SIGNAL(finished()), SLOT(finished()));
1313 connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(gotError()));
1314 returnCode = Success;
1315 loop = new QEventLoop;
1316 QSignalSpy spy(reply.data(), SIGNAL(downloadProgress(qint64,qint64)));
1317 while (!reply->isFinished()) {
1318 QTimer::singleShot(5000, loop, SLOT(quit()));
1319 if ( loop->exec() == Timeout && count == spy.count() && !reply->isFinished()) {
1320 returnCode = Timeout;
1323 count = spy.count();
1331 void tst_QNetworkReply::finished()
1333 loop->exit(returnCode = Success);
1336 void tst_QNetworkReply::gotError()
1338 loop->exit(returnCode = Failure);
1339 disconnect(QObject::sender(), SIGNAL(finished()), this, 0);
1342 void tst_QNetworkReply::initTestCase()
1344 testDataDir = QFileInfo(QFINDTESTDATA("rfc3252.txt")).absolutePath();
1345 if (testDataDir.isEmpty())
1346 testDataDir = QCoreApplication::applicationDirPath();
1348 QVERIFY(QtNetworkSettings::verifyTestNetworkSettings());
1349 #if !defined Q_OS_WIN
1350 wronlyFileName = testDataDir + "/write-only";
1351 QFile wr(wronlyFileName);
1352 QVERIFY(wr.open(QIODevice::WriteOnly | QIODevice::Truncate));
1353 wr.setPermissions(QFile::WriteOwner | QFile::WriteUser);
1357 QDir::setSearchPaths("testdata", QStringList() << testDataDir);
1359 QSslSocket::defaultCaCertificates(); //preload certificates
1361 #ifndef QT_NO_BEARERMANAGEMENT
1362 netConfMan = new QNetworkConfigurationManager(this);
1363 networkConfiguration = netConfMan->defaultConfiguration();
1364 networkSession.reset(new QNetworkSession(networkConfiguration));
1365 if (!networkSession->isOpen()) {
1366 networkSession->open();
1367 QVERIFY(networkSession->waitForOpened(30000));
1371 echoProcessDir = QFINDTESTDATA("echo");
1372 QVERIFY2(!echoProcessDir.isEmpty(), qPrintable(
1373 QString::fromLatin1("Couldn't find echo dir starting from %1.").arg(QDir::currentPath())));
1376 void tst_QNetworkReply::cleanupTestCase()
1378 #if !defined Q_OS_WIN
1379 QFile::remove(wronlyFileName);
1381 #ifndef QT_NO_BEARERMANAGEMENT
1382 if (networkSession && networkSession->isOpen()) {
1383 networkSession->close();
1388 void tst_QNetworkReply::init()
1393 void tst_QNetworkReply::cleanup()
1395 QFile file(testFileName);
1396 QVERIFY(!file.exists() || file.remove());
1398 // clear the internal cache
1399 manager.clearAccessCache();
1400 manager.setProxy(QNetworkProxy());
1401 manager.setCache(0);
1404 cookieJar->setAllCookies(QList<QNetworkCookie>());
1407 void tst_QNetworkReply::stateChecking()
1409 QUrl url = QUrl("file:///");
1410 QNetworkRequest req(url); // you can't open this file, I know
1411 QNetworkReplyPtr reply(manager.get(req));
1413 QVERIFY(reply.data());
1414 QVERIFY(reply->isOpen());
1415 QVERIFY(reply->isReadable());
1416 QVERIFY(!reply->isWritable());
1418 // both behaviours are OK since we might change underlying behaviour again
1419 if (!reply->isFinished())
1420 QCOMPARE(reply->errorString(), QString("Unknown error"));
1422 QVERIFY(!reply->errorString().isEmpty());
1425 QCOMPARE(reply->manager(), &manager);
1426 QCOMPARE(reply->request(), req);
1427 QCOMPARE(int(reply->operation()), int(QNetworkAccessManager::GetOperation));
1428 // error and not error are OK since we might change underlying behaviour again
1429 if (!reply->isFinished())
1430 QCOMPARE(reply->error(), QNetworkReply::NoError);
1431 QCOMPARE(reply->url(), url);
1436 void tst_QNetworkReply::invalidProtocol()
1438 QUrl url = QUrl::fromEncoded("not-a-known-protocol://foo/bar");
1439 QNetworkRequest req(url);
1440 QNetworkReplyPtr reply;
1442 QString errorMsg = "Request failed: Protocol \"not-a-known-protocol\" is unknown";
1443 QString result = runSimpleRequest(QNetworkAccessManager::GetOperation, req, reply);
1444 QCOMPARE(result, errorMsg);
1446 QCOMPARE(reply->url(), url);
1447 QCOMPARE(reply->error(), QNetworkReply::ProtocolUnknownError);
1450 void tst_QNetworkReply::getFromData_data()
1452 QTest::addColumn<QString>("request");
1453 QTest::addColumn<QByteArray>("expected");
1454 QTest::addColumn<QString>("mimeType");
1456 const QString defaultMimeType("text/plain;charset=US-ASCII");
1458 //QTest::newRow("empty") << "data:" << QByteArray() << defaultMimeType;
1459 QTest::newRow("empty2") << "data:," << QByteArray() << defaultMimeType;
1460 QTest::newRow("just-charset_1") << "data:charset=iso-8859-1,"
1461 << QByteArray() << "text/plain;charset=iso-8859-1";
1462 QTest::newRow("just-charset_2") << "data:charset = iso-8859-1 ,"
1463 << QByteArray() << "text/plain;charset = iso-8859-1";
1464 //QTest::newRow("just-media") << "data:text/xml" << QByteArray() << "text/xml";
1465 QTest::newRow("just-media2") << "data:text/xml," << QByteArray() << "text/xml";
1467 QTest::newRow("plain_1") << "data:,foo" << QByteArray("foo") << defaultMimeType;
1468 QTest::newRow("plain_2") << "data:text/html,Hello World" << QByteArray("Hello World")
1470 QTest::newRow("plain_3") << "data:text/html;charset=utf-8,Hello World"
1471 << QByteArray("Hello World") << "text/html;charset=utf-8";
1473 QTest::newRow("pct_1") << "data:,%3Cbody%20contentEditable%3Dtrue%3E%0D%0A"
1474 << QByteArray("<body contentEditable=true>\r\n") << defaultMimeType;
1475 QTest::newRow("pct_2") << "data:text/html;charset=utf-8,%3Cbody%20contentEditable%3Dtrue%3E%0D%0A"
1476 << QByteArray("<body contentEditable=true>\r\n")
1477 << "text/html;charset=utf-8";
1479 QTest::newRow("base64-empty_1") << "data:;base64," << QByteArray() << defaultMimeType;
1480 QTest::newRow("base64-empty_2") << "data:charset=utf-8;base64," << QByteArray()
1481 << "text/plain;charset=utf-8";
1482 QTest::newRow("base64-empty_3") << "data:text/html;charset=utf-8;base64,"
1483 << QByteArray() << "text/html;charset=utf-8";
1485 QTest::newRow("base64_1") << "data:;base64,UXQgaXMgZ3JlYXQh" << QByteArray("Qt is great!")
1487 QTest::newRow("base64_2") << "data:charset=utf-8;base64,UXQgaXMgZ3JlYXQh"
1488 << QByteArray("Qt is great!") << "text/plain;charset=utf-8";
1489 QTest::newRow("base64_3") << "data:text/html;charset=utf-8;base64,UXQgaXMgZ3JlYXQh"
1490 << QByteArray("Qt is great!") << "text/html;charset=utf-8";
1492 QTest::newRow("pct-nul") << "data:,a%00g" << QByteArray("a\0g", 3) << defaultMimeType;
1493 QTest::newRow("base64-nul") << "data:;base64,YQBn" << QByteArray("a\0g", 3) << defaultMimeType;
1494 QTest::newRow("pct-nonutf8") << "data:,a%E1g" << QByteArray("a\xE1g", 3) << defaultMimeType;
1496 QTest::newRow("base64")
1497 << QString::fromLatin1("data:application/xml;base64,PGUvPg==")
1498 << QByteArray("<e/>")
1499 << "application/xml";
1501 QTest::newRow("base64, no media type")
1502 << QString::fromLatin1("data:;base64,PGUvPg==")
1503 << QByteArray("<e/>")
1506 QTest::newRow("Percent encoding")
1507 << QString::fromLatin1("data:application/xml,%3Ce%2F%3E")
1508 << QByteArray("<e/>")
1509 << "application/xml";
1511 QTest::newRow("Percent encoding, no media type")
1512 << QString::fromLatin1("data:,%3Ce%2F%3E")
1513 << QByteArray("<e/>")
1516 QTest::newRow("querychars")
1517 << QString::fromLatin1("data:,foo?x=0&y=0")
1518 << QByteArray("foo?x=0&y=0")
1521 QTest::newRow("css") << "data:text/css,div%20{%20border-right:%20solid;%20}"
1522 << QByteArray("div { border-right: solid; }")
1526 void tst_QNetworkReply::getFromData()
1528 QFETCH(QString, request);
1529 QFETCH(QByteArray, expected);
1530 QFETCH(QString, mimeType);
1532 QUrl url = QUrl::fromEncoded(request.toLatin1());
1533 QNetworkRequest req(url);
1534 QNetworkReplyPtr reply;
1536 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, req, reply));
1538 QCOMPARE(reply->url(), url);
1539 QCOMPARE(reply->error(), QNetworkReply::NoError);
1541 QCOMPARE(reply->header(QNetworkRequest::ContentTypeHeader).toString(), mimeType);
1542 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), qint64(expected.size()));
1543 QCOMPARE(reply->readAll(), expected);
1546 void tst_QNetworkReply::getFromFile()
1549 QTemporaryFile file(QDir::currentPath() + "/temp-XXXXXX");
1550 file.setAutoRemove(true);
1551 QVERIFY(file.open());
1553 QNetworkRequest request(QUrl::fromLocalFile(file.fileName()));
1554 QNetworkReplyPtr reply;
1556 static const char fileData[] = "This is some data that is in the file.\r\n";
1557 QByteArray data = QByteArray::fromRawData(fileData, sizeof fileData - 1);
1558 QVERIFY(file.write(data) == data.size());
1560 QCOMPARE(file.size(), qint64(data.size()));
1562 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
1564 QCOMPARE(reply->url(), request.url());
1565 QCOMPARE(reply->error(), QNetworkReply::NoError);
1567 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), file.size());
1568 QCOMPARE(reply->readAll(), data);
1570 // make the file bigger
1572 const int multiply = (128 * 1024) / (sizeof fileData - 1);
1573 for (int i = 0; i < multiply; ++i)
1574 file.write(fileData, sizeof fileData - 1);
1580 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
1581 QCOMPARE(reply->url(), request.url());
1582 QCOMPARE(reply->error(), QNetworkReply::NoError);
1584 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), file.size());
1585 QCOMPARE(qint64(reply->readAll().size()), file.size());
1588 void tst_QNetworkReply::getFromFileSpecial_data()
1590 QTest::addColumn<QString>("fileName");
1591 QTest::addColumn<QString>("url");
1593 QTest::newRow("resource") << ":/resource" << "qrc:/resource";
1594 QTest::newRow("search-path") << "testdata:/rfc3252.txt" << "testdata:/rfc3252.txt";
1595 QTest::newRow("bigfile-path") << "testdata:/bigfile" << "testdata:/bigfile";
1597 QTest::newRow("smb-path") << "testdata:/smb-file.txt" << "file://" + QtNetworkSettings::winServerName() + "/testshare/test.pri";
1601 void tst_QNetworkReply::getFromFileSpecial()
1603 QFETCH(QString, fileName);
1604 QFETCH(QString, url);
1606 // open the resource so we can find out its size
1607 QFile resource(fileName);
1608 QVERIFY(resource.open(QIODevice::ReadOnly));
1610 QNetworkRequest request;
1611 QNetworkReplyPtr reply;
1612 request.setUrl(url);
1613 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
1615 QCOMPARE(reply->url(), request.url());
1616 QCOMPARE(reply->error(), QNetworkReply::NoError);
1618 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), resource.size());
1619 QCOMPARE(reply->readAll(), resource.readAll());
1622 void tst_QNetworkReply::getFromFtp_data()
1624 QTest::addColumn<QString>("referenceName");
1625 QTest::addColumn<QString>("url");
1627 QTest::newRow("rfc3252.txt") << (testDataDir + "/rfc3252.txt") << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt";
1628 QTest::newRow("bigfile") << (testDataDir + "/bigfile") << "ftp://" + QtNetworkSettings::serverName() + "/qtest/bigfile";
1631 void tst_QNetworkReply::getFromFtp()
1633 QFETCH(QString, referenceName);
1634 QFETCH(QString, url);
1636 QFile reference(referenceName);
1637 QVERIFY(reference.open(QIODevice::ReadOnly));
1639 QNetworkRequest request(url);
1640 QNetworkReplyPtr reply;
1641 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
1643 QCOMPARE(reply->url(), request.url());
1644 QCOMPARE(reply->error(), QNetworkReply::NoError);
1646 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
1647 QCOMPARE(reply->readAll(), reference.readAll());
1650 void tst_QNetworkReply::getFromHttp_data()
1652 QTest::addColumn<QString>("referenceName");
1653 QTest::addColumn<QString>("url");
1655 QTest::newRow("success-internal") << (testDataDir + "/rfc3252.txt") << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt";
1656 QTest::newRow("success-external") << (testDataDir + "/rfc3252.txt") << "http://www.ietf.org/rfc/rfc3252.txt";
1657 QTest::newRow("bigfile-internal") << (testDataDir + "/bigfile") << "http://" + QtNetworkSettings::serverName() + "/qtest/bigfile";
1660 void tst_QNetworkReply::getFromHttp()
1662 QFETCH(QString, referenceName);
1663 QFETCH(QString, url);
1665 QFile reference(referenceName);
1666 QVERIFY(reference.open(QIODevice::ReadOnly));
1668 QNetworkRequest request(url);
1669 QNetworkReplyPtr reply;
1670 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
1672 QCOMPARE(reply->url(), request.url());
1673 QCOMPARE(reply->error(), QNetworkReply::NoError);
1674 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
1675 QCOMPARE(reply->size(), reference.size());
1676 // only compare when the header is set.
1677 if (reply->header(QNetworkRequest::ContentLengthHeader).isValid())
1678 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
1680 // We know our internal server is apache..
1681 if (qstrcmp(QTest::currentDataTag(), "success-internal") == 0)
1682 QVERIFY(reply->header(QNetworkRequest::ServerHeader).toString().contains("Apache"));
1684 QCOMPARE(reply->readAll(), reference.readAll());
1687 void tst_QNetworkReply::headFromHttp_data()
1689 QTest::addColumn<qint64>("referenceSize");
1690 QTest::addColumn<QUrl>("url");
1691 QTest::addColumn<QString>("contentType");
1692 QTest::addColumn<QNetworkProxy>("proxy");
1694 qint64 rfcsize = QFileInfo(testDataDir + "/rfc3252.txt").size();
1695 qint64 bigfilesize = QFileInfo(testDataDir + "/bigfile").size();
1696 qint64 indexsize = QFileInfo(testDataDir + "/index.html").size();
1698 //testing proxies, mainly for the 407 response from http proxy
1699 for (int i = 0; i < proxies.count(); ++i) {
1700 QTest::newRow("rfc" + proxies.at(i).tag) << rfcsize << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt") << "text/plain" << proxies.at(i).proxy;
1701 QTest::newRow("bigfile" + proxies.at(i).tag) << bigfilesize << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/bigfile") << "text/plain" << proxies.at(i).proxy;
1702 QTest::newRow("index" + proxies.at(i).tag) << indexsize << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/") << "text/html" << proxies.at(i).proxy;
1703 QTest::newRow("with-authentication" + proxies.at(i).tag) << rfcsize << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt") << "text/plain" << proxies.at(i).proxy;
1704 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;
1708 void tst_QNetworkReply::headFromHttp()
1710 QFETCH(qint64, referenceSize);
1712 QFETCH(QString, contentType);
1713 QFETCH(QNetworkProxy, proxy);
1715 QNetworkRequest request(url);
1716 QNetworkReplyPtr reply;
1721 manager.setProxy(proxy);
1722 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
1723 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
1724 connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
1725 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
1727 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::HeadOperation, request, reply));
1729 manager.disconnect(SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
1730 this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
1731 manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
1732 this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
1734 QVERIFY(time.elapsed() < 8000); //check authentication didn't wait for the server to timeout the http connection (15s on qt test server)
1736 QCOMPARE(reply->url(), request.url());
1737 QCOMPARE(reply->error(), QNetworkReply::NoError);
1738 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
1739 // only compare when the header is set.
1740 if (reply->header(QNetworkRequest::ContentLengthHeader).isValid() && referenceSize >= 0)
1741 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), referenceSize);
1742 if (reply->header(QNetworkRequest::ContentTypeHeader).isValid())
1743 QCOMPARE(reply->header(QNetworkRequest::ContentTypeHeader).toString(), contentType);
1746 void tst_QNetworkReply::getErrors_data()
1748 QTest::addColumn<QString>("url");
1749 QTest::addColumn<int>("error");
1750 QTest::addColumn<int>("httpStatusCode");
1751 QTest::addColumn<bool>("dataIsEmpty");
1754 QTest::newRow("empty-url") << QString() << int(QNetworkReply::ProtocolUnknownError) << 0 << true;
1755 QTest::newRow("empty-scheme-host") << (testDataDir + "/rfc3252.txt") << int(QNetworkReply::ProtocolUnknownError) << 0 << true;
1756 QTest::newRow("empty-scheme") << "//" + QtNetworkSettings::winServerName() + "/testshare/test.pri"
1757 << int(QNetworkReply::ProtocolUnknownError) << 0 << true;
1760 QTest::newRow("file-host") << "file://this-host-doesnt-exist.troll.no/foo.txt"
1761 #if !defined Q_OS_WIN
1762 << int(QNetworkReply::ProtocolInvalidOperationError) << 0 << true;
1764 << int(QNetworkReply::ContentNotFoundError) << 0 << true;
1766 QTest::newRow("file-no-path") << "file://localhost"
1767 << int(QNetworkReply::ContentOperationNotPermittedError) << 0 << true;
1768 QTest::newRow("file-is-dir") << QUrl::fromLocalFile(QDir::currentPath()).toString()
1769 << int(QNetworkReply::ContentOperationNotPermittedError) << 0 << true;
1770 QTest::newRow("file-exist") << QUrl::fromLocalFile(QDir::currentPath() + "/this-file-doesnt-exist.txt").toString()
1771 << int(QNetworkReply::ContentNotFoundError) << 0 << true;
1772 #if !defined Q_OS_WIN
1773 QTest::newRow("file-is-wronly") << QUrl::fromLocalFile(wronlyFileName).toString()
1774 << int(QNetworkReply::ContentAccessDenied) << 0 << true;
1776 if (QFile::exists("/etc/shadow"))
1777 QTest::newRow("file-permissions") << "file:/etc/shadow"
1778 << int(QNetworkReply::ContentAccessDenied) << 0 << true;
1781 QTest::newRow("ftp-host") << "ftp://this-host-doesnt-exist.troll.no/foo.txt"
1782 << int(QNetworkReply::HostNotFoundError) << 0 << true;
1783 QTest::newRow("ftp-no-path") << "ftp://" + QtNetworkSettings::serverName()
1784 << int(QNetworkReply::ContentOperationNotPermittedError) << 0 << true;
1785 QTest::newRow("ftp-is-dir") << "ftp://" + QtNetworkSettings::serverName() + "/qtest"
1786 << int(QNetworkReply::ContentOperationNotPermittedError) << 0 << true;
1787 QTest::newRow("ftp-dir-not-readable") << "ftp://" + QtNetworkSettings::serverName() + "/pub/dir-not-readable/foo.txt"
1788 << int(QNetworkReply::ContentAccessDenied) << 0 << true;
1789 QTest::newRow("ftp-file-not-readable") << "ftp://" + QtNetworkSettings::serverName() + "/pub/file-not-readable.txt"
1790 << int(QNetworkReply::ContentAccessDenied) << 0 << true;
1791 QTest::newRow("ftp-exist") << "ftp://" + QtNetworkSettings::serverName() + "/pub/this-file-doesnt-exist.txt"
1792 << int(QNetworkReply::ContentNotFoundError) << 0 << true;
1795 QTest::newRow("http-host") << "http://this-host-will-never-exist.troll.no/"
1796 << int(QNetworkReply::HostNotFoundError) << 0 << true;
1797 QTest::newRow("http-exist") << "http://" + QtNetworkSettings::serverName() + "/this-file-doesnt-exist.txt"
1798 << int(QNetworkReply::ContentNotFoundError) << 404 << false;
1799 QTest::newRow("http-authentication") << "http://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth"
1800 << int(QNetworkReply::AuthenticationRequiredError) << 401 << false;
1803 void tst_QNetworkReply::getErrors()
1805 QFETCH(QString, url);
1806 QNetworkRequest request(url);
1809 if ((qstrcmp(QTest::currentDataTag(), "file-is-wronly") == 0) ||
1810 (qstrcmp(QTest::currentDataTag(), "file-permissions") == 0)) {
1811 if (::getuid() == 0)
1812 QSKIP("Running this test as root doesn't make sense");
1816 QNetworkReplyPtr reply(manager.get(request));
1817 reply->setParent(this); // we have expect-fails
1819 if (!reply->isFinished())
1820 QCOMPARE(reply->error(), QNetworkReply::NoError);
1822 // now run the request:
1823 QVERIFY(waitForFinish(reply) != Timeout);
1826 QEXPECT_FAIL("ftp-is-dir", "QFtp cannot provide enough detail", Abort);
1827 // the line below is not necessary
1828 QEXPECT_FAIL("ftp-dir-not-readable", "QFtp cannot provide enough detail", Abort);
1829 QCOMPARE(reply->error(), QNetworkReply::NetworkError(error));
1831 QTEST(reply->readAll().isEmpty(), "dataIsEmpty");
1833 QVERIFY(reply->isFinished());
1834 QVERIFY(!reply->isRunning());
1836 QFETCH(int, httpStatusCode);
1837 if (httpStatusCode != 0) {
1838 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), httpStatusCode);
1842 static inline QByteArray md5sum(const QByteArray &data)
1844 return QCryptographicHash::hash(data, QCryptographicHash::Md5);
1847 void tst_QNetworkReply::putToFile_data()
1849 QTest::addColumn<QByteArray>("data");
1850 QTest::addColumn<QByteArray>("md5sum");
1854 QTest::newRow("empty") << data << md5sum(data);
1856 data = "This is a normal message.";
1857 QTest::newRow("generic") << data << md5sum(data);
1859 data = "This is a message to show that Qt rocks!\r\n\n";
1860 QTest::newRow("small") << data << md5sum(data);
1862 data = QByteArray("abcd\0\1\2\abcd",12);
1863 QTest::newRow("with-nul") << data << md5sum(data);
1865 data = QByteArray(4097, '\4');
1866 QTest::newRow("4k+1") << data << md5sum(data);
1868 data = QByteArray(128*1024+1, '\177');
1869 QTest::newRow("128k+1") << data << md5sum(data);
1871 data = QByteArray(2*1024*1024+1, '\177');
1872 QTest::newRow("2MB+1") << data << md5sum(data);
1875 void tst_QNetworkReply::putToFile()
1877 QFile file(testFileName);
1879 QUrl url = QUrl::fromLocalFile(file.fileName());
1880 QNetworkRequest request(url);
1881 QNetworkReplyPtr reply;
1883 QFETCH(QByteArray, data);
1885 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PutOperation, request, reply, data));
1887 QCOMPARE(reply->url(), url);
1888 QCOMPARE(reply->error(), QNetworkReply::NoError);
1889 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
1890 QVERIFY(reply->readAll().isEmpty());
1892 QVERIFY(file.open(QIODevice::ReadOnly));
1893 QCOMPARE(file.size(), qint64(data.size()));
1894 QByteArray contents = file.readAll();
1895 QCOMPARE(contents, data);
1898 void tst_QNetworkReply::putToFtp_data()
1903 void tst_QNetworkReply::putToFtp()
1905 QUrl url("ftp://" + QtNetworkSettings::serverName());
1906 url.setPath(QString("/qtest/upload/qnetworkaccess-putToFtp-%1-%2")
1907 .arg(QTest::currentDataTag())
1908 .arg(uniqueExtension));
1910 QNetworkRequest request(url);
1911 QNetworkReplyPtr reply;
1913 QFETCH(QByteArray, data);
1915 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PutOperation, request, reply, data));
1917 QCOMPARE(reply->url(), url);
1918 QCOMPARE(reply->error(), QNetworkReply::NoError);
1919 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
1920 QVERIFY(reply->readAll().isEmpty());
1922 // download the file again from FTP to make sure it was uploaded
1924 QNetworkAccessManager qnam;
1925 QNetworkRequest req(url);
1926 QNetworkReply *r = qnam.get(req);
1928 QObject::connect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
1930 QSignalSpy spy(r, SIGNAL(downloadProgress(qint64,qint64)));
1931 while (!r->isFinished()) {
1932 QTestEventLoop::instance().enterLoop(10);
1933 if (count == spy.count() && !r->isFinished())
1935 count = spy.count();
1937 QObject::disconnect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
1939 QByteArray uploaded = r->readAll();
1940 QCOMPARE(uploaded.size(), data.size());
1941 QCOMPARE(uploaded, data);
1944 QObject::connect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
1945 QTestEventLoop::instance().enterLoop(10);
1946 QObject::disconnect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
1949 void tst_QNetworkReply::putToHttp_data()
1954 void tst_QNetworkReply::putToHttp()
1956 QUrl url("http://" + QtNetworkSettings::serverName());
1957 url.setPath(QString("/dav/qnetworkaccess-putToHttp-%1-%2")
1958 .arg(QTest::currentDataTag())
1959 .arg(uniqueExtension));
1961 QNetworkRequest request(url);
1962 QNetworkReplyPtr reply;
1964 QFETCH(QByteArray, data);
1966 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PutOperation, request, reply, data));
1968 QCOMPARE(reply->url(), url);
1969 QCOMPARE(reply->error(), QNetworkReply::NoError);
1971 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 201); // 201 Created
1973 // download the file again from HTTP to make sure it was uploaded
1974 // correctly. HTTP/0.9 is enough
1976 socket.connectToHost(QtNetworkSettings::serverName(), 80);
1977 socket.write("GET " + url.toEncoded(QUrl::RemoveScheme | QUrl::RemoveAuthority) + "\r\n");
1978 if (!socket.waitForDisconnected(10000))
1979 QFAIL("Network timeout");
1981 QByteArray uploadedData = socket.readAll();
1982 QCOMPARE(uploadedData, data);
1985 void tst_QNetworkReply::putToHttpSynchronous_data()
1987 uniqueExtension = createUniqueExtension();
1991 void tst_QNetworkReply::putToHttpSynchronous()
1993 QUrl url("http://" + QtNetworkSettings::serverName());
1994 url.setPath(QString("/dav/qnetworkaccess-putToHttp-%1-%2")
1995 .arg(QTest::currentDataTag())
1996 .arg(uniqueExtension));
1998 QNetworkRequest request(url);
1999 QNetworkReplyPtr reply;
2001 QFETCH(QByteArray, data);
2003 request.setAttribute(
2004 QNetworkRequest::SynchronousRequestAttribute,
2007 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PutOperation, request, reply, data));
2009 QCOMPARE(reply->url(), url);
2010 QCOMPARE(reply->error(), QNetworkReply::NoError);
2012 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 201); // 201 Created
2014 // download the file again from HTTP to make sure it was uploaded
2015 // correctly. HTTP/0.9 is enough
2017 socket.connectToHost(QtNetworkSettings::serverName(), 80);
2018 socket.write("GET " + url.toEncoded(QUrl::RemoveScheme | QUrl::RemoveAuthority) + "\r\n");
2019 if (!socket.waitForDisconnected(10000))
2020 QFAIL("Network timeout");
2022 QByteArray uploadedData = socket.readAll();
2023 QCOMPARE(uploadedData, data);
2026 void tst_QNetworkReply::postToHttp_data()
2031 void tst_QNetworkReply::postToHttp()
2033 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi");
2035 QNetworkRequest request(url);
2036 request.setRawHeader("Content-Type", "application/octet-stream");
2037 QNetworkReplyPtr reply;
2039 QFETCH(QByteArray, data);
2041 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PostOperation, request, reply, data));
2043 QCOMPARE(reply->url(), url);
2044 QCOMPARE(reply->error(), QNetworkReply::NoError);
2046 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
2048 QFETCH(QByteArray, md5sum);
2049 QByteArray uploadedData = reply->readAll().trimmed();
2050 QCOMPARE(uploadedData, md5sum.toHex());
2053 void tst_QNetworkReply::postToHttpSynchronous_data()
2058 void tst_QNetworkReply::postToHttpSynchronous()
2060 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi");
2062 QNetworkRequest request(url);
2063 request.setRawHeader("Content-Type", "application/octet-stream");
2065 request.setAttribute(
2066 QNetworkRequest::SynchronousRequestAttribute,
2069 QNetworkReplyPtr reply;
2071 QFETCH(QByteArray, data);
2073 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PostOperation, request, reply, data));
2075 QCOMPARE(reply->url(), url);
2076 QCOMPARE(reply->error(), QNetworkReply::NoError);
2078 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
2080 QFETCH(QByteArray, md5sum);
2081 QByteArray uploadedData = reply->readAll().trimmed();
2082 QCOMPARE(uploadedData, md5sum.toHex());
2085 void tst_QNetworkReply::postToHttpMultipart_data()
2087 QTest::addColumn<QUrl>("url");
2088 QTest::addColumn<QHttpMultiPart *>("multiPart");
2089 QTest::addColumn<QByteArray>("expectedReplyData");
2090 QTest::addColumn<QByteArray>("contentType");
2092 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/multipart.cgi");
2093 QByteArray expectedData;
2098 QHttpMultiPart *emptyMultiPart = new QHttpMultiPart;
2099 QTest::newRow("empty") << url << emptyMultiPart << expectedData << QByteArray("mixed");
2101 QHttpMultiPart *emptyRelatedMultiPart = new QHttpMultiPart;
2102 emptyRelatedMultiPart->setContentType(QHttpMultiPart::RelatedType);
2103 QTest::newRow("empty-related") << url << emptyRelatedMultiPart << expectedData << QByteArray("related");
2105 QHttpMultiPart *emptyAlternativeMultiPart = new QHttpMultiPart;
2106 emptyAlternativeMultiPart->setContentType(QHttpMultiPart::AlternativeType);
2107 QTest::newRow("empty-alternative") << url << emptyAlternativeMultiPart << expectedData << QByteArray("alternative");
2113 textPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain"));
2114 textPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"text\""));
2115 textPart.setBody("7 bytes");
2116 QHttpMultiPart *multiPart1 = new QHttpMultiPart;
2117 multiPart1->setContentType(QHttpMultiPart::FormDataType);
2118 multiPart1->append(textPart);
2119 expectedData = "key: text, value: 7 bytes\n";
2120 QTest::newRow("text") << url << multiPart1 << expectedData << QByteArray("form-data");
2122 QHttpMultiPart *customMultiPart = new QHttpMultiPart;
2123 customMultiPart->append(textPart);
2124 expectedData = "header: Content-Type, value: 'text/plain'\n"
2125 "header: Content-Disposition, value: 'form-data; name=\"text\"'\n"
2126 "content: 7 bytes\n"
2128 QTest::newRow("text-custom") << url << customMultiPart << expectedData << QByteArray("custom");
2130 QHttpPart textPart2;
2131 textPart2.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain"));
2132 textPart2.setRawHeader("myRawHeader", "myValue");
2133 textPart2.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"text2\""));
2134 textPart2.setBody("some more bytes");
2135 textPart2.setBodyDevice((QIODevice *) 1); // test whether setting and unsetting of the device works
2136 textPart2.setBodyDevice(0);
2137 QHttpMultiPart *multiPart2 = new QHttpMultiPart;
2138 multiPart2->setContentType(QHttpMultiPart::FormDataType);
2139 multiPart2->append(textPart);
2140 multiPart2->append(textPart2);
2141 expectedData = "key: text2, value: some more bytes\n"
2142 "key: text, value: 7 bytes\n";
2143 QTest::newRow("text-text") << url << multiPart2 << expectedData << QByteArray("form-data");
2146 QHttpPart textPart3;
2147 textPart3.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain"));
2148 textPart3.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"text3\""));
2149 textPart3.setRawHeader("Content-Location", "http://my.test.location.tld");
2150 textPart3.setBody("even more bytes");
2151 QHttpMultiPart *multiPart3 = new QHttpMultiPart;
2152 multiPart3->setContentType(QHttpMultiPart::AlternativeType);
2153 multiPart3->append(textPart);
2154 multiPart3->append(textPart2);
2155 multiPart3->append(textPart3);
2156 expectedData = "header: Content-Type, value: 'text/plain'\n"
2157 "header: Content-Disposition, value: 'form-data; name=\"text\"'\n"
2158 "content: 7 bytes\n"
2160 "header: Content-Type, value: 'text/plain'\n"
2161 "header: myRawHeader, value: 'myValue'\n"
2162 "header: Content-Disposition, value: 'form-data; name=\"text2\"'\n"
2163 "content: some more bytes\n"
2165 "header: Content-Type, value: 'text/plain'\n"
2166 "header: Content-Disposition, value: 'form-data; name=\"text3\"'\n"
2167 "header: Content-Location, value: 'http://my.test.location.tld'\n"
2168 "content: even more bytes\n\n";
2169 QTest::newRow("text-text-text") << url << multiPart3 << expectedData << QByteArray("alternative");
2173 // text and image parts
2175 QHttpPart imagePart11;
2176 imagePart11.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
2177 imagePart11.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage\""));
2178 imagePart11.setRawHeader("Content-Location", "http://my.test.location.tld");
2179 imagePart11.setRawHeader("Content-ID", "my@id.tld");
2180 QFile *file11 = new QFile(testDataDir + "/image1.jpg");
2181 file11->open(QIODevice::ReadOnly);
2182 imagePart11.setBodyDevice(file11);
2183 QHttpMultiPart *imageMultiPart1 = new QHttpMultiPart(QHttpMultiPart::FormDataType);
2184 imageMultiPart1->append(imagePart11);
2185 file11->setParent(imageMultiPart1);
2186 expectedData = "key: testImage, value: 87ef3bb319b004ba9e5e9c9fa713776e\n"; // md5 sum of file
2187 QTest::newRow("image") << url << imageMultiPart1 << expectedData << QByteArray("form-data");
2189 QHttpPart imagePart21;
2190 imagePart21.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
2191 imagePart21.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage1\""));
2192 imagePart21.setRawHeader("Content-Location", "http://my.test.location.tld");
2193 imagePart21.setRawHeader("Content-ID", "my@id.tld");
2194 QFile *file21 = new QFile(testDataDir + "/image1.jpg");
2195 file21->open(QIODevice::ReadOnly);
2196 imagePart21.setBodyDevice(file21);
2197 QHttpMultiPart *imageMultiPart2 = new QHttpMultiPart();
2198 imageMultiPart2->setContentType(QHttpMultiPart::FormDataType);
2199 imageMultiPart2->append(textPart);
2200 imageMultiPart2->append(imagePart21);
2201 file21->setParent(imageMultiPart2);
2202 QHttpPart imagePart22;
2203 imagePart22.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
2204 imagePart22.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage2\""));
2205 QFile *file22 = new QFile(testDataDir + "/image2.jpg");
2206 file22->open(QIODevice::ReadOnly);
2207 imagePart22.setBodyDevice(file22);
2208 imageMultiPart2->append(imagePart22);
2209 file22->setParent(imageMultiPart2);
2210 expectedData = "key: testImage1, value: 87ef3bb319b004ba9e5e9c9fa713776e\n"
2211 "key: text, value: 7 bytes\n"
2212 "key: testImage2, value: 483761b893f7fb1bd2414344cd1f3dfb\n";
2213 QTest::newRow("text-image-image") << url << imageMultiPart2 << expectedData << QByteArray("form-data");
2216 QHttpPart imagePart31;
2217 imagePart31.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
2218 imagePart31.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage1\""));
2219 imagePart31.setRawHeader("Content-Location", "http://my.test.location.tld");
2220 imagePart31.setRawHeader("Content-ID", "my@id.tld");
2221 QFile *file31 = new QFile(testDataDir + "/image1.jpg");
2222 file31->open(QIODevice::ReadOnly);
2223 imagePart31.setBodyDevice(file31);
2224 QHttpMultiPart *imageMultiPart3 = new QHttpMultiPart(QHttpMultiPart::FormDataType);
2225 imageMultiPart3->append(imagePart31);
2226 file31->setParent(imageMultiPart3);
2227 QHttpPart imagePart32;
2228 imagePart32.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
2229 imagePart32.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage2\""));
2230 QFile *file32 = new QFile(testDataDir + "/image2.jpg");
2231 file32->open(QIODevice::ReadOnly);
2232 imagePart32.setBodyDevice(file31); // check that resetting works
2233 imagePart32.setBodyDevice(file32);
2234 imageMultiPart3->append(imagePart32);
2235 file32->setParent(imageMultiPart3);
2236 QHttpPart imagePart33;
2237 imagePart33.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
2238 imagePart33.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage3\""));
2239 QFile *file33 = new QFile(testDataDir + "/image3.jpg");
2240 file33->open(QIODevice::ReadOnly);
2241 imagePart33.setBodyDevice(file33);
2242 imageMultiPart3->append(imagePart33);
2243 file33->setParent(imageMultiPart3);
2244 expectedData = "key: testImage1, value: 87ef3bb319b004ba9e5e9c9fa713776e\n"
2245 "key: testImage2, value: 483761b893f7fb1bd2414344cd1f3dfb\n"
2246 "key: testImage3, value: ab0eb6fd4fcf8b4436254870b4513033\n";
2247 QTest::newRow("3-images") << url << imageMultiPart3 << expectedData << QByteArray("form-data");
2250 // note: nesting multiparts is not working currently; for that, the outputDevice would need to be public
2252 // QHttpPart imagePart41;
2253 // imagePart41.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
2254 // QFile *file41 = new QFile(testDataDir + "/image1.jpg");
2255 // file41->open(QIODevice::ReadOnly);
2256 // imagePart41.setBodyDevice(file41);
2258 // QHttpMultiPart *innerMultiPart = new QHttpMultiPart();
2259 // innerMultiPart->setContentType(QHttpMultiPart::FormDataType);
2260 // textPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant());
2261 // innerMultiPart->append(textPart);
2262 // innerMultiPart->append(imagePart41);
2263 // textPart2.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant());
2264 // innerMultiPart->append(textPart2);
2266 // QHttpPart nestedPart;
2267 // nestedPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"nestedMessage"));
2268 // nestedPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("multipart/alternative; boundary=\"" + innerMultiPart->boundary() + "\""));
2269 // innerMultiPart->outputDevice()->open(QIODevice::ReadOnly);
2270 // nestedPart.setBodyDevice(innerMultiPart->outputDevice());
2272 // QHttpMultiPart *outerMultiPart = new QHttpMultiPart;
2273 // outerMultiPart->setContentType(QHttpMultiPart::FormDataType);
2274 // outerMultiPart->append(textPart);
2275 // outerMultiPart->append(nestedPart);
2276 // outerMultiPart->append(textPart2);
2277 // expectedData = "nothing"; // the CGI.pm module running on the test server does not understand nested multiparts
2278 // openFiles.clear();
2279 // openFiles << file41;
2280 // QTest::newRow("nested") << url << outerMultiPart << expectedData << openFiles;
2283 // test setting large chunks of content with a byte array instead of a device (DISCOURAGED because of high memory consumption,
2284 // but we need to test that the behavior is correct)
2285 QHttpPart imagePart51;
2286 imagePart51.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
2287 imagePart51.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage\""));
2288 QFile *file51 = new QFile(testDataDir + "/image1.jpg");
2289 file51->open(QIODevice::ReadOnly);
2290 QByteArray imageData = file51->readAll();
2293 imagePart51.setBody("7 bytes"); // check that resetting works
2294 imagePart51.setBody(imageData);
2295 QHttpMultiPart *imageMultiPart5 = new QHttpMultiPart;
2296 imageMultiPart5->setContentType(QHttpMultiPart::FormDataType);
2297 imageMultiPart5->append(imagePart51);
2298 expectedData = "key: testImage, value: 87ef3bb319b004ba9e5e9c9fa713776e\n"; // md5 sum of file
2299 QTest::newRow("image-as-content") << url << imageMultiPart5 << expectedData << QByteArray("form-data");
2302 void tst_QNetworkReply::postToHttpMultipart()
2306 static QSet<QByteArray> boundaries;
2308 QNetworkRequest request(url);
2309 QNetworkReplyPtr reply;
2311 QFETCH(QHttpMultiPart *, multiPart);
2312 QFETCH(QByteArray, expectedReplyData);
2313 QFETCH(QByteArray, contentType);
2315 // hack for testing the setting of the content-type header by hand:
2316 if (contentType == "custom") {
2317 QByteArray contentType("multipart/custom; boundary=\"" + multiPart->boundary() + "\"");
2318 request.setHeader(QNetworkRequest::ContentTypeHeader, contentType);
2321 QVERIFY2(! boundaries.contains(multiPart->boundary()), "boundary '" + multiPart->boundary() + "' has been created twice");
2322 boundaries.insert(multiPart->boundary());
2324 RUN_REQUEST(runMultipartRequest(request, reply, multiPart, "POST"));
2325 multiPart->deleteLater();
2327 QCOMPARE(reply->url(), url);
2328 QCOMPARE(reply->error(), QNetworkReply::NoError);
2330 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
2332 QVERIFY(multiPart->boundary().count() > 20); // check that there is randomness after the "boundary_.oOo._" string
2333 QVERIFY(multiPart->boundary().count() < 70);
2334 QByteArray replyData = reply->readAll();
2336 expectedReplyData.prepend("content type: multipart/" + contentType + "; boundary=\"" + multiPart->boundary() + "\"\n");
2337 // QEXPECT_FAIL("nested", "the server does not understand nested multipart messages", Continue); // see above
2338 QCOMPARE(replyData, expectedReplyData);
2341 void tst_QNetworkReply::putToHttpMultipart_data()
2343 postToHttpMultipart_data();
2346 void tst_QNetworkReply::putToHttpMultipart()
2348 QSKIP("test server script cannot handle PUT data yet");
2351 static QSet<QByteArray> boundaries;
2353 QNetworkRequest request(url);
2354 QNetworkReplyPtr reply;
2356 QFETCH(QHttpMultiPart *, multiPart);
2357 QFETCH(QByteArray, expectedReplyData);
2358 QFETCH(QByteArray, contentType);
2360 // hack for testing the setting of the content-type header by hand:
2361 if (contentType == "custom") {
2362 QByteArray contentType("multipart/custom; boundary=\"" + multiPart->boundary() + "\"");
2363 request.setHeader(QNetworkRequest::ContentTypeHeader, contentType);
2366 QVERIFY2(! boundaries.contains(multiPart->boundary()), "boundary '" + multiPart->boundary() + "' has been created twice");
2367 boundaries.insert(multiPart->boundary());
2369 RUN_REQUEST(runMultipartRequest(request, reply, multiPart, "PUT"));
2370 multiPart->deleteLater();
2372 QCOMPARE(reply->url(), url);
2373 QCOMPARE(reply->error(), QNetworkReply::NoError);
2375 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
2377 QVERIFY(multiPart->boundary().count() > 20); // check that there is randomness after the "boundary_.oOo._" string
2378 QVERIFY(multiPart->boundary().count() < 70);
2379 QByteArray replyData = reply->readAll();
2381 expectedReplyData.prepend("content type: multipart/" + contentType + "; boundary=\"" + multiPart->boundary() + "\"\n");
2382 // QEXPECT_FAIL("nested", "the server does not understand nested multipart messages", Continue); // see above
2383 QCOMPARE(replyData, expectedReplyData);
2386 void tst_QNetworkReply::deleteFromHttp_data()
2388 QTest::addColumn<QUrl>("url");
2389 QTest::addColumn<int>("resultCode");
2390 QTest::addColumn<QNetworkReply::NetworkError>("error");
2392 // for status codes to expect, see http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
2394 QTest::newRow("405-method-not-allowed") << QUrl("http://" + QtNetworkSettings::serverName() + "/index.html") << 405 << QNetworkReply::ContentOperationNotPermittedError;
2395 QTest::newRow("200-ok") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/http-delete.cgi?200-ok") << 200 << QNetworkReply::NoError;
2396 QTest::newRow("202-accepted") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/http-delete.cgi?202-accepted") << 202 << QNetworkReply::NoError;
2397 QTest::newRow("204-no-content") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/http-delete.cgi?204-no-content") << 204 << QNetworkReply::NoError;
2398 QTest::newRow("404-not-found") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/http-delete.cgi?404-not-found") << 404 << QNetworkReply::ContentNotFoundError;
2401 void tst_QNetworkReply::deleteFromHttp()
2404 QFETCH(int, resultCode);
2405 QFETCH(QNetworkReply::NetworkError, error);
2406 QNetworkRequest request(url);
2407 QNetworkReplyPtr reply;
2408 runSimpleRequest(QNetworkAccessManager::DeleteOperation, request, reply, 0);
2409 QCOMPARE(reply->url(), url);
2410 QCOMPARE(reply->error(), error);
2411 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), resultCode);
2414 void tst_QNetworkReply::putGetDeleteGetFromHttp_data()
2416 QTest::addColumn<QUrl>("putUrl");
2417 QTest::addColumn<int>("putResultCode");
2418 QTest::addColumn<QNetworkReply::NetworkError>("putError");
2419 QTest::addColumn<QUrl>("deleteUrl");
2420 QTest::addColumn<int>("deleteResultCode");
2421 QTest::addColumn<QNetworkReply::NetworkError>("deleteError");
2422 QTest::addColumn<QUrl>("get2Url");
2423 QTest::addColumn<int>("get2ResultCode");
2424 QTest::addColumn<QNetworkReply::NetworkError>("get2Error");
2426 QUrl url("http://" + QtNetworkSettings::serverName());
2427 url.setPath(QString("/dav/qnetworkaccess-putToHttp-%1-%2")
2428 .arg(QTest::currentDataTag())
2429 .arg(uniqueExtension));
2431 // first use case: put, get (to check it is there), delete, get (to check it is not there anymore)
2432 QTest::newRow("success") << url << 201 << QNetworkReply::NoError << url << 204 << QNetworkReply::NoError << url << 404 << QNetworkReply::ContentNotFoundError;
2434 QUrl wrongUrl("http://" + QtNetworkSettings::serverName());
2435 wrongUrl.setPath(QString("/dav/qnetworkaccess-thisURLisNotAvailable"));
2437 // second use case: put, get (to check it is there), delete wrong URL, get (to check it is still there)
2438 QTest::newRow("delete-error") << url << 201 << QNetworkReply::NoError << wrongUrl << 404 << QNetworkReply::ContentNotFoundError << url << 200 << QNetworkReply::NoError;
2442 void tst_QNetworkReply::putGetDeleteGetFromHttp()
2444 QFETCH(QUrl, putUrl);
2445 QFETCH(int, putResultCode);
2446 QFETCH(QNetworkReply::NetworkError, putError);
2447 QFETCH(QUrl, deleteUrl);
2448 QFETCH(int, deleteResultCode);
2449 QFETCH(QNetworkReply::NetworkError, deleteError);
2450 QFETCH(QUrl, get2Url);
2451 QFETCH(int, get2ResultCode);
2452 QFETCH(QNetworkReply::NetworkError, get2Error);
2454 QNetworkRequest putRequest(putUrl);
2455 QNetworkRequest deleteRequest(deleteUrl);
2456 QNetworkRequest get2Request(get2Url);
2457 QNetworkReplyPtr reply;
2459 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PutOperation, putRequest, reply, 0));
2460 QCOMPARE(reply->error(), putError);
2461 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), putResultCode);
2463 runSimpleRequest(QNetworkAccessManager::GetOperation, putRequest, reply, 0);
2464 QCOMPARE(reply->error(), QNetworkReply::NoError);
2465 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2467 runSimpleRequest(QNetworkAccessManager::DeleteOperation, deleteRequest, reply, 0);
2468 QCOMPARE(reply->error(), deleteError);
2469 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), deleteResultCode);
2471 runSimpleRequest(QNetworkAccessManager::GetOperation, get2Request, reply, 0);
2472 QCOMPARE(reply->error(), get2Error);
2473 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), get2ResultCode);
2477 void tst_QNetworkReply::connectToIPv6Address_data()
2479 QTest::addColumn<QUrl>("url");
2480 QTest::addColumn<QNetworkReply::NetworkError>("error");
2481 QTest::addColumn<QByteArray>("dataToSend");
2482 QTest::addColumn<QByteArray>("hostfield");
2483 QTest::newRow("localhost") << QUrl(QByteArray("http://[::1]")) << QNetworkReply::NoError<< QByteArray("localhost") << QByteArray("[::1]");
2484 //QTest::newRow("ipv4localhost") << QUrl(QByteArray("http://127.0.0.1")) << QNetworkReply::NoError<< QByteArray("ipv4localhost") << QByteArray("127.0.0.1");
2485 //to add more test data here
2488 void tst_QNetworkReply::connectToIPv6Address()
2491 QFETCH(QNetworkReply::NetworkError, error);
2492 QFETCH(QByteArray, dataToSend);
2493 QFETCH(QByteArray, hostfield);
2495 #if !defined(HAVE_IPV6) && defined(Q_OS_UNIX)
2496 QSKIP("system doesn't support ipv6!");
2499 QByteArray httpResponse = QByteArray("HTTP/1.0 200 OK\r\nContent-Length: ");
2500 httpResponse += QByteArray::number(dataToSend.size());
2501 httpResponse += "\r\n\r\n";
2502 httpResponse += dataToSend;
2504 MiniHttpServer server(httpResponse, false, NULL/*thread*/, true/*useipv6*/);
2505 server.doClose = true;
2507 url.setPort(server.serverPort());
2508 QNetworkRequest request(url);
2510 QNetworkReplyPtr reply(manager.get(request));
2511 QVERIFY(waitForFinish(reply) == Success);
2512 QByteArray content = reply->readAll();
2513 //qDebug() << server.receivedData;
2514 QByteArray hostinfo = "\r\nHost: " + hostfield + ":" + QByteArray::number(server.serverPort()) + "\r\n";
2515 QVERIFY(server.receivedData.contains(hostinfo));
2516 QVERIFY(content == dataToSend);
2517 QCOMPARE(reply->url(), request.url());
2518 QVERIFY(reply->error() == error);
2521 void tst_QNetworkReply::sendCustomRequestToHttp_data()
2523 QTest::addColumn<QUrl>("url");
2524 QTest::addColumn<QByteArray>("verb");
2525 QTest::addColumn<QBuffer *>("device");
2526 QTest::addColumn<int>("resultCode");
2527 QTest::addColumn<QNetworkReply::NetworkError>("error");
2528 QTest::addColumn<QByteArray>("expectedContent");
2530 QTest::newRow("options") << QUrl("http://" + QtNetworkSettings::serverName()) <<
2531 QByteArray("OPTIONS") << (QBuffer *) 0 << 200 << QNetworkReply::NoError << QByteArray();
2532 QTest::newRow("trace") << QUrl("http://" + QtNetworkSettings::serverName()) <<
2533 QByteArray("TRACE") << (QBuffer *) 0 << 200 << QNetworkReply::NoError << QByteArray();
2534 QTest::newRow("connect") << QUrl("http://" + QtNetworkSettings::serverName()) <<
2535 QByteArray("CONNECT") << (QBuffer *) 0 << 400 << QNetworkReply::UnknownContentError << QByteArray(); // 400 = Bad Request
2536 QTest::newRow("nonsense") << QUrl("http://" + QtNetworkSettings::serverName()) <<
2537 QByteArray("NONSENSE") << (QBuffer *) 0 << 501 << QNetworkReply::ProtocolUnknownError << QByteArray(); // 501 = Method Not Implemented
2539 QByteArray ba("test");
2540 QBuffer *buffer = new QBuffer;
2541 buffer->setData(ba);
2542 buffer->open(QIODevice::ReadOnly);
2543 QTest::newRow("post") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi") << QByteArray("POST")
2544 << buffer << 200 << QNetworkReply::NoError << QByteArray("098f6bcd4621d373cade4e832627b4f6\n");
2546 QByteArray ba2("test");
2547 QBuffer *buffer2 = new QBuffer;
2548 buffer2->setData(ba2);
2549 buffer2->open(QIODevice::ReadOnly);
2550 QTest::newRow("put") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi") << QByteArray("PUT")
2551 << buffer2 << 200 << QNetworkReply::NoError << QByteArray("098f6bcd4621d373cade4e832627b4f6\n");
2554 void tst_QNetworkReply::sendCustomRequestToHttp()
2557 QNetworkRequest request(url);
2558 QNetworkReplyPtr reply;
2559 QFETCH(QByteArray, verb);
2560 QFETCH(QBuffer *, device);
2561 runCustomRequest(request, reply, verb, device);
2562 QCOMPARE(reply->url(), url);
2563 QFETCH(QNetworkReply::NetworkError, error);
2564 QCOMPARE(reply->error(), error);
2565 QFETCH(int, resultCode);
2566 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), resultCode);
2567 QFETCH(QByteArray, expectedContent);
2568 if (! expectedContent.isEmpty())
2569 QCOMPARE(reply->readAll(), expectedContent);
2572 void tst_QNetworkReply::ioGetFromData_data()
2574 QTest::addColumn<QString>("urlStr");
2575 QTest::addColumn<QByteArray>("data");
2577 QTest::newRow("data-empty") << "data:," << QByteArray();
2578 QTest::newRow("data-literal") << "data:,foo" << QByteArray("foo");
2579 QTest::newRow("data-pct") << "data:,%3Cbody%20contentEditable%3Dtrue%3E%0D%0A"
2580 << QByteArray("<body contentEditable=true>\r\n");
2581 QTest::newRow("data-base64") << "data:;base64,UXQgaXMgZ3JlYXQh" << QByteArray("Qt is great!");
2584 void tst_QNetworkReply::ioGetFromData()
2586 QFETCH(QString, urlStr);
2588 QUrl url = QUrl::fromEncoded(urlStr.toLatin1());
2589 QNetworkRequest request(url);
2591 QNetworkReplyPtr reply(manager.get(request));
2592 DataReader reader(reply);
2594 connect(reply, SIGNAL(finished()),
2595 &QTestEventLoop::instance(), SLOT(exitLoop()));
2596 QTestEventLoop::instance().enterLoop(10);
2597 QVERIFY(!QTestEventLoop::instance().timeout());
2599 QCOMPARE(reply->url(), request.url());
2600 QCOMPARE(reply->error(), QNetworkReply::NoError);
2602 QFETCH(QByteArray, data);
2603 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toInt(), data.size());
2604 QCOMPARE(reader.data.size(), data.size());
2605 QCOMPARE(reader.data, data);
2608 void tst_QNetworkReply::ioGetFromFileSpecial_data()
2610 getFromFileSpecial_data();
2613 void tst_QNetworkReply::ioGetFromFileSpecial()
2615 QFETCH(QString, fileName);
2616 QFETCH(QString, url);
2618 QFile resource(fileName);
2619 QVERIFY(resource.open(QIODevice::ReadOnly));
2621 QNetworkRequest request;
2622 request.setUrl(url);
2623 QNetworkReplyPtr reply(manager.get(request));
2624 DataReader reader(reply);
2626 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
2627 QTestEventLoop::instance().enterLoop(10);
2628 QVERIFY(!QTestEventLoop::instance().timeout());
2630 QCOMPARE(reply->url(), request.url());
2631 QCOMPARE(reply->error(), QNetworkReply::NoError);
2633 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), resource.size());
2634 QCOMPARE(qint64(reader.data.size()), resource.size());
2635 QCOMPARE(reader.data, resource.readAll());
2638 void tst_QNetworkReply::ioGetFromFile_data()
2643 void tst_QNetworkReply::ioGetFromFile()
2645 QTemporaryFile file(QDir::currentPath() + "/temp-XXXXXX");
2646 file.setAutoRemove(true);
2647 QVERIFY(file.open());
2649 QFETCH(QByteArray, data);
2650 QVERIFY(file.write(data) == data.size());
2652 QCOMPARE(file.size(), qint64(data.size()));
2654 QNetworkRequest request(QUrl::fromLocalFile(file.fileName()));
2655 QNetworkReplyPtr reply(manager.get(request));
2656 QVERIFY(reply->isFinished()); // a file should immediately be done
2657 DataReader reader(reply);
2659 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
2660 QTestEventLoop::instance().enterLoop(10);
2661 QVERIFY(!QTestEventLoop::instance().timeout());
2663 QCOMPARE(reply->url(), request.url());
2664 QCOMPARE(reply->error(), QNetworkReply::NoError);
2666 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), file.size());
2667 QCOMPARE(qint64(reader.data.size()), file.size());
2668 QCOMPARE(reader.data, data);
2671 void tst_QNetworkReply::ioGetFromFtp_data()
2673 QTest::addColumn<QString>("fileName");
2674 QTest::addColumn<qint64>("expectedSize");
2676 QTest::newRow("bigfile") << "bigfile" << Q_INT64_C(519240);
2678 QFile file(testDataDir + "/rfc3252.txt");
2679 QTest::newRow("rfc3252.txt") << "rfc3252.txt" << file.size();
2682 void tst_QNetworkReply::ioGetFromFtp()
2684 QFETCH(QString, fileName);
2685 QFile reference(fileName);
2686 reference.open(QIODevice::ReadOnly); // will fail for bigfile
2688 QNetworkRequest request("ftp://" + QtNetworkSettings::serverName() + "/qtest/" + fileName);
2689 QNetworkReplyPtr reply(manager.get(request));
2690 DataReader reader(reply);
2692 QVERIFY(waitForFinish(reply) == Success);
2694 QCOMPARE(reply->url(), request.url());
2695 QCOMPARE(reply->error(), QNetworkReply::NoError);
2697 QFETCH(qint64, expectedSize);
2698 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), expectedSize);
2699 QCOMPARE(qint64(reader.data.size()), expectedSize);
2701 if (reference.isOpen())
2702 QCOMPARE(reader.data, reference.readAll());
2705 void tst_QNetworkReply::ioGetFromFtpWithReuse()
2707 QString fileName = testDataDir + "/rfc3252.txt";
2708 QFile reference(fileName);
2709 reference.open(QIODevice::ReadOnly);
2711 QNetworkRequest request(QUrl("ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
2713 // two concurrent (actually, consecutive) gets:
2714 QNetworkReplyPtr reply1(manager.get(request));
2715 DataReader reader1(reply1);
2716 QNetworkReplyPtr reply2(manager.get(request));
2717 DataReader reader2(reply2);
2718 QSignalSpy spy(reply1.data(), SIGNAL(finished()));
2720 QVERIFY(waitForFinish(reply1) == Success);
2721 QVERIFY(waitForFinish(reply2) == Success);
2723 QCOMPARE(reply1->url(), request.url());
2724 QCOMPARE(reply2->url(), request.url());
2725 QCOMPARE(reply1->error(), QNetworkReply::NoError);
2726 QCOMPARE(reply2->error(), QNetworkReply::NoError);
2728 QCOMPARE(qint64(reader1.data.size()), reference.size());
2729 QCOMPARE(qint64(reader2.data.size()), reference.size());
2730 QCOMPARE(reply1->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
2731 QCOMPARE(reply2->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
2733 QByteArray referenceData = reference.readAll();
2734 QCOMPARE(reader1.data, referenceData);
2735 QCOMPARE(reader2.data, referenceData);
2738 void tst_QNetworkReply::ioGetFromHttp()
2740 QFile reference(testDataDir + "/rfc3252.txt");
2741 QVERIFY(reference.open(QIODevice::ReadOnly));
2743 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
2744 QNetworkReplyPtr reply(manager.get(request));
2745 DataReader reader(reply);
2747 QVERIFY(waitForFinish(reply) == Success);
2749 QCOMPARE(reply->url(), request.url());
2750 QCOMPARE(reply->error(), QNetworkReply::NoError);
2751 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2753 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
2754 QCOMPARE(qint64(reader.data.size()), reference.size());
2756 QCOMPARE(reader.data, reference.readAll());
2759 void tst_QNetworkReply::ioGetFromHttpWithReuseParallel()
2761 QFile reference(testDataDir + "/rfc3252.txt");
2762 QVERIFY(reference.open(QIODevice::ReadOnly));
2764 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
2765 QNetworkReplyPtr reply1(manager.get(request));
2766 QNetworkReplyPtr reply2(manager.get(request));
2767 DataReader reader1(reply1);
2768 DataReader reader2(reply2);
2769 QSignalSpy spy(reply1.data(), SIGNAL(finished()));
2771 QVERIFY(waitForFinish(reply2) == Success);
2772 QVERIFY(waitForFinish(reply1) == Success);
2774 QCOMPARE(reply1->url(), request.url());
2775 QCOMPARE(reply2->url(), request.url());
2776 QCOMPARE(reply1->error(), QNetworkReply::NoError);
2777 QCOMPARE(reply2->error(), QNetworkReply::NoError);
2778 QCOMPARE(reply1->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2779 QCOMPARE(reply2->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2781 QCOMPARE(reply1->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
2782 QCOMPARE(reply2->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
2783 QCOMPARE(qint64(reader1.data.size()), reference.size());
2784 QCOMPARE(qint64(reader2.data.size()), reference.size());
2786 QByteArray referenceData = reference.readAll();
2787 QCOMPARE(reader1.data, referenceData);
2788 QCOMPARE(reader2.data, referenceData);
2791 void tst_QNetworkReply::ioGetFromHttpWithReuseSequential()
2793 QFile reference(testDataDir + "/rfc3252.txt");
2794 QVERIFY(reference.open(QIODevice::ReadOnly));
2796 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
2798 QNetworkReplyPtr reply(manager.get(request));
2799 DataReader reader(reply);
2801 QVERIFY(waitForFinish(reply) == Success);
2803 QCOMPARE(reply->url(), request.url());
2804 QCOMPARE(reply->error(), QNetworkReply::NoError);
2805 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2807 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
2808 QCOMPARE(qint64(reader.data.size()), reference.size());
2810 QCOMPARE(reader.data, reference.readAll());
2814 // rinse and repeat:
2816 QNetworkReplyPtr reply(manager.get(request));
2817 DataReader reader(reply);
2819 QVERIFY(waitForFinish(reply) == Success);
2821 QCOMPARE(reply->url(), request.url());
2822 QCOMPARE(reply->error(), QNetworkReply::NoError);
2823 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2825 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
2826 QCOMPARE(qint64(reader.data.size()), reference.size());
2828 QCOMPARE(reader.data, reference.readAll());
2832 void tst_QNetworkReply::ioGetFromHttpWithAuth_data()
2834 QTest::addColumn<QUrl>("url");
2835 QTest::addColumn<QByteArray>("expectedData");
2836 QTest::addColumn<int>("expectedAuth");
2838 QFile reference(testDataDir + "/rfc3252.txt");
2839 reference.open(QIODevice::ReadOnly);
2840 QByteArray referenceData = reference.readAll();
2841 QTest::newRow("basic") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt") << referenceData << 1;
2842 QTest::newRow("digest") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/auth-digest/") << QByteArray("digest authentication successful\n") << 1;
2843 //if url contains username & password, then it should be used
2844 QTest::newRow("basic-in-url") << QUrl("http://httptest:httptest@" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt") << referenceData << 0;
2845 QTest::newRow("digest-in-url") << QUrl("http://httptest:httptest@" + QtNetworkSettings::serverName() + "/qtest/auth-digest/") << QByteArray("digest authentication successful\n") << 0;
2846 // if url contains incorrect credentials, expect QNAM to ask for good ones (even if cached - matches behaviour of browsers)
2847 QTest::newRow("basic-bad-user-in-url") << QUrl("http://baduser:httptest@" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt") << referenceData << 3;
2848 QTest::newRow("basic-bad-password-in-url") << QUrl("http://httptest:wrong@" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt") << referenceData << 3;
2849 QTest::newRow("digest-bad-user-in-url") << QUrl("http://baduser:httptest@" + QtNetworkSettings::serverName() + "/qtest/auth-digest/") << QByteArray("digest authentication successful\n") << 3;
2850 QTest::newRow("digest-bad-password-in-url") << QUrl("http://httptest:wrong@" + QtNetworkSettings::serverName() + "/qtest/auth-digest/") << QByteArray("digest authentication successful\n") << 3;
2853 void tst_QNetworkReply::ioGetFromHttpWithAuth()
2855 // This test sends three requests
2856 // The first two in parallel
2857 // The third after the first two finished
2860 QFETCH(QByteArray, expectedData);
2861 QFETCH(int, expectedAuth);
2862 QNetworkRequest request(url);
2864 QNetworkReplyPtr reply1(manager.get(request));
2865 QNetworkReplyPtr reply2(manager.get(request));
2866 DataReader reader1(reply1);
2867 DataReader reader2(reply2);
2868 QSignalSpy finishedspy(reply1.data(), SIGNAL(finished()));
2870 QSignalSpy authspy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2871 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
2872 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2874 QVERIFY(waitForFinish(reply2) == Success);
2875 QVERIFY(waitForFinish(reply1) == Success);
2877 manager.disconnect(SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
2878 this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2880 QCOMPARE(reply1->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2881 QCOMPARE(reply2->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2882 QCOMPARE(reader1.data, expectedData);
2883 QCOMPARE(reader2.data, expectedData);
2885 QCOMPARE(authspy.count(), (expectedAuth ? 1 : 0));
2886 expectedAuth = qMax(0, expectedAuth - 1);
2889 // rinse and repeat:
2891 QNetworkReplyPtr reply(manager.get(request));
2892 DataReader reader(reply);
2894 QSignalSpy authspy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2895 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
2896 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2898 QVERIFY(waitForFinish(reply) == Success);
2900 manager.disconnect(SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
2901 this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2903 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2904 QCOMPARE(reader.data, expectedData);
2906 QCOMPARE(authspy.count(), (expectedAuth ? 1 : 0));
2907 expectedAuth = qMax(0, expectedAuth - 1);
2910 // now check with synchronous calls:
2912 request.setAttribute(
2913 QNetworkRequest::SynchronousRequestAttribute,
2916 QSignalSpy authspy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2917 QNetworkReplyPtr replySync(manager.get(request));
2918 QVERIFY(replySync->isFinished()); // synchronous
2920 // bad credentials in a synchronous request should just fail
2921 QCOMPARE(replySync->error(), QNetworkReply::AuthenticationRequiredError);
2923 QCOMPARE(authspy.count(), 0);
2925 // we cannot use a data reader here, since that connects to the readyRead signal,
2926 // just use readAll()
2928 // the only thing we check here is that the auth cache was used when using synchronous requests
2929 QCOMPARE(replySync->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2930 QCOMPARE(replySync->readAll(), expectedData);
2934 // check that credentials are used from cache if the same url is requested without credentials
2936 url.setUserInfo(QString());
2937 request.setUrl(url);
2938 request.setAttribute(
2939 QNetworkRequest::SynchronousRequestAttribute,
2942 QSignalSpy authspy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2943 QNetworkReplyPtr replySync(manager.get(request));
2944 QVERIFY(replySync->isFinished()); // synchronous
2946 // bad credentials in a synchronous request should just fail
2947 QCOMPARE(replySync->error(), QNetworkReply::AuthenticationRequiredError);
2949 QCOMPARE(authspy.count(), 0);
2951 // we cannot use a data reader here, since that connects to the readyRead signal,
2952 // just use readAll()
2954 // the only thing we check here is that the auth cache was used when using synchronous requests
2955 QCOMPARE(replySync->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2956 QCOMPARE(replySync->readAll(), expectedData);
2961 void tst_QNetworkReply::ioGetFromHttpWithAuthSynchronous()
2963 // verify that we do not enter an endless loop with synchronous calls and wrong credentials
2964 // the case when we succeed with the login is tested in ioGetFromHttpWithAuth()
2966 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt"));
2967 request.setAttribute(
2968 QNetworkRequest::SynchronousRequestAttribute,
2971 QSignalSpy authspy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2972 QNetworkReplyPtr replySync(manager.get(request));
2973 QVERIFY(replySync->isFinished()); // synchronous
2974 QCOMPARE(replySync->error(), QNetworkReply::AuthenticationRequiredError);
2975 QCOMPARE(authspy.count(), 0);
2976 QCOMPARE(replySync->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 401);
2979 void tst_QNetworkReply::ioGetFromHttpWithProxyAuth()
2981 // This test sends three requests
2982 // The first two in parallel
2983 // The third after the first two finished
2984 QFile reference(testDataDir + "/rfc3252.txt");
2985 QVERIFY(reference.open(QIODevice::ReadOnly));
2987 QNetworkProxy proxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129);
2988 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
2990 manager.setProxy(proxy);
2991 QNetworkReplyPtr reply1(manager.get(request));
2992 QNetworkReplyPtr reply2(manager.get(request));
2993 manager.setProxy(QNetworkProxy());
2995 DataReader reader1(reply1);
2996 DataReader reader2(reply2);
2997 QSignalSpy finishedspy(reply1.data(), SIGNAL(finished()));
2999 QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3000 connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3001 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3003 QVERIFY(waitForFinish(reply2) == Success);
3004 QVERIFY(waitForFinish(reply1) == Success);
3006 manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3007 this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3009 QCOMPARE(reply1->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
3010 QCOMPARE(reply2->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
3011 QByteArray referenceData = reference.readAll();
3012 QCOMPARE(reader1.data, referenceData);
3013 QCOMPARE(reader2.data, referenceData);
3015 QCOMPARE(authspy.count(), 1);
3019 // rinse and repeat:
3021 manager.setProxy(proxy);
3022 QNetworkReplyPtr reply(manager.get(request));
3023 DataReader reader(reply);
3024 manager.setProxy(QNetworkProxy());
3026 QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3027 connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3028 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3030 QVERIFY(waitForFinish(reply) == Success);
3032 manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3033 this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3035 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
3036 QCOMPARE(reader.data, reference.readAll());
3038 QCOMPARE(authspy.count(), 0);
3041 // now check with synchronous calls:
3044 request.setAttribute(
3045 QNetworkRequest::SynchronousRequestAttribute,
3048 QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3049 QNetworkReplyPtr replySync(manager.get(request));
3050 QVERIFY(replySync->isFinished()); // synchronous
3051 QCOMPARE(authspy.count(), 0);
3053 // we cannot use a data reader here, since that connects to the readyRead signal,
3054 // just use readAll()
3056 // the only thing we check here is that the proxy auth cache was used when using synchronous requests
3057 QCOMPARE(replySync->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
3058 QCOMPARE(replySync->readAll(), reference.readAll());
3062 void tst_QNetworkReply::ioGetFromHttpWithProxyAuthSynchronous()
3064 // verify that we do not enter an endless loop with synchronous calls and wrong credentials
3065 // the case when we succeed with the login is tested in ioGetFromHttpWithAuth()
3067 QNetworkProxy proxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129);
3068 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
3069 manager.setProxy(proxy);
3070 request.setAttribute(
3071 QNetworkRequest::SynchronousRequestAttribute,
3074 QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3075 QNetworkReplyPtr replySync(manager.get(request));
3076 manager.setProxy(QNetworkProxy()); // reset
3077 QVERIFY(replySync->isFinished()); // synchronous
3078 QCOMPARE(replySync->error(), QNetworkReply::ProxyAuthenticationRequiredError);
3079 QCOMPARE(authspy.count(), 0);
3080 QCOMPARE(replySync->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 407);
3083 void tst_QNetworkReply::ioGetFromHttpWithSocksProxy()
3085 // HTTP caching proxies are tested by the above function
3086 // test SOCKSv5 proxies too
3088 QFile reference(testDataDir + "/rfc3252.txt");
3089 QVERIFY(reference.open(QIODevice::ReadOnly));
3091 QNetworkProxy proxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080);
3092 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
3094 manager.setProxy(proxy);
3095 QNetworkReplyPtr reply(manager.get(request));
3096 DataReader reader(reply);
3097 manager.setProxy(QNetworkProxy());
3099 QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3100 connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3101 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3103 QVERIFY(waitForFinish(reply) == Success);
3105 manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3106 this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3108 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
3109 QCOMPARE(reader.data, reference.readAll());
3111 QCOMPARE(authspy.count(), 0);
3114 // set an invalid proxy just to make sure that we can't load
3115 proxy = QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1079);
3117 manager.setProxy(proxy);
3118 QNetworkReplyPtr reply(manager.get(request));
3119 DataReader reader(reply);
3120 manager.setProxy(QNetworkProxy());
3122 QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3123 connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3124 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3126 QVERIFY(waitForFinish(reply) == Failure);
3128 manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3129 this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3131 QVERIFY(!reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).isValid());
3132 QVERIFY(reader.data.isEmpty());
3134 QVERIFY(int(reply->error()) > 0);
3135 QEXPECT_FAIL("", "QTcpSocket doesn't return enough information yet", Continue);
3136 QCOMPARE(int(reply->error()), int(QNetworkReply::ProxyConnectionRefusedError));
3138 QCOMPARE(authspy.count(), 0);
3143 void tst_QNetworkReply::ioGetFromHttpsWithSslErrors()
3145 QFile reference(testDataDir + "/rfc3252.txt");
3146 QVERIFY(reference.open(QIODevice::ReadOnly));
3148 QNetworkRequest request(QUrl("https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
3149 QNetworkReplyPtr reply(manager.get(request));
3150 DataReader reader(reply);
3152 QSignalSpy sslspy(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)));
3153 connect(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
3154 SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
3155 connect(reply, SIGNAL(metaDataChanged()), SLOT(storeSslConfiguration()));
3157 QVERIFY(waitForFinish(reply) == Success);
3159 manager.disconnect(SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
3160 this, SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
3162 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
3163 QCOMPARE(reader.data, reference.readAll());
3165 QCOMPARE(sslspy.count(), 1);
3167 QVERIFY(!storedSslConfiguration.isNull());
3168 QVERIFY(!reply->sslConfiguration().isNull());
3171 void tst_QNetworkReply::ioGetFromHttpsWithIgnoreSslErrors()
3173 // same as above, except that we call ignoreSslErrors and don't connect
3174 // to the sslErrors() signal (which is *still* emitted)
3176 QFile reference(testDataDir + "/rfc3252.txt");
3177 QVERIFY(reference.open(QIODevice::ReadOnly));
3179 QNetworkRequest request(QUrl("https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
3181 QNetworkReplyPtr reply(manager.get(request));
3182 reply->ignoreSslErrors();
3183 DataReader reader(reply);
3185 QSignalSpy sslspy(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)));
3186 connect(reply, SIGNAL(metaDataChanged()), SLOT(storeSslConfiguration()));
3188 QVERIFY(waitForFinish(reply) == Success);
3190 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
3191 QCOMPARE(reader.data, reference.readAll());
3193 QCOMPARE(sslspy.count(), 1);
3195 QVERIFY(!storedSslConfiguration.isNull());
3196 QVERIFY(!reply->sslConfiguration().isNull());
3199 void tst_QNetworkReply::ioGetFromHttpsWithSslHandshakeError()
3201 QFile reference(testDataDir + "/rfc3252.txt");
3202 QVERIFY(reference.open(QIODevice::ReadOnly));
3204 QNetworkRequest request(QUrl("https://" + QtNetworkSettings::serverName() + ":80"));
3206 QNetworkReplyPtr reply(manager.get(request));
3207 reply->ignoreSslErrors();
3208 DataReader reader(reply);
3210 QSignalSpy sslspy(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)));
3211 connect(reply, SIGNAL(metaDataChanged()), SLOT(storeSslConfiguration()));
3213 QVERIFY(waitForFinish(reply) == Failure);
3215 QCOMPARE(reply->error(), QNetworkReply::SslHandshakeFailedError);
3216 QCOMPARE(sslspy.count(), 0);
3220 void tst_QNetworkReply::ioGetFromHttpBrokenServer_data()
3222 QTest::addColumn<QByteArray>("dataToSend");
3223 QTest::addColumn<bool>("doDisconnect");
3225 QTest::newRow("no-newline") << QByteArray("Hello World") << false;
3227 // these are OK now, we just eat the lonely newlines
3228 //QTest::newRow("just-newline") << QByteArray("\r\n") << false;
3229 //QTest::newRow("just-2newline") << QByteArray("\r\n\r\n") << false;
3231 QTest::newRow("with-newlines") << QByteArray("Long first line\r\nLong second line") << false;
3232 QTest::newRow("with-newlines2") << QByteArray("\r\nSecond line") << false;
3233 QTest::newRow("with-newlines3") << QByteArray("ICY\r\nSecond line") << false;
3234 QTest::newRow("invalid-version") << QByteArray("HTTP/123 200 \r\n") << false;
3235 QTest::newRow("invalid-version2") << QByteArray("HTTP/a.\033 200 \r\n") << false;
3236 QTest::newRow("invalid-reply-code") << QByteArray("HTTP/1.0 fuu \r\n") << false;
3238 QTest::newRow("empty+disconnect") << QByteArray() << true;
3240 QTest::newRow("no-newline+disconnect") << QByteArray("Hello World") << true;
3241 QTest::newRow("just-newline+disconnect") << QByteArray("\r\n") << true;
3242 QTest::newRow("just-2newline+disconnect") << QByteArray("\r\n\r\n") << true;
3243 QTest::newRow("with-newlines+disconnect") << QByteArray("Long first line\r\nLong second line") << true;
3244 QTest::newRow("with-newlines2+disconnect") << QByteArray("\r\nSecond line") << true;
3245 QTest::newRow("with-newlines3+disconnect") << QByteArray("ICY\r\nSecond line") << true;
3247 QTest::newRow("invalid-version+disconnect") << QByteArray("HTTP/123 200 ") << true;
3248 QTest::newRow("invalid-version2+disconnect") << QByteArray("HTTP/a.\033 200 ") << true;
3249 QTest::newRow("invalid-reply-code+disconnect") << QByteArray("HTTP/1.0 fuu ") << true;
3251 QTest::newRow("immediate disconnect") << QByteArray("") << true;
3252 QTest::newRow("justHalfStatus+disconnect") << QByteArray("HTTP/1.1") << true;
3253 QTest::newRow("justStatus+disconnect") << QByteArray("HTTP/1.1 200 OK\r\n") << true;
3254 QTest::newRow("justStatusAndHalfHeaders+disconnect") << QByteArray("HTTP/1.1 200 OK\r\nContent-L") << true;
3256 QTest::newRow("halfContent+disconnect") << QByteArray("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\nAB") << true;
3260 void tst_QNetworkReply::ioGetFromHttpBrokenServer()
3262 QFETCH(QByteArray, dataToSend);
3263 QFETCH(bool, doDisconnect);
3264 MiniHttpServer server(dataToSend);
3265 server.doClose = doDisconnect;
3267 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
3268 QNetworkReplyPtr reply(manager.get(request));
3269 QSignalSpy spy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError)));
3271 QVERIFY(waitForFinish(reply) == Failure);
3273 QCOMPARE(reply->url(), request.url());
3274 QCOMPARE(spy.count(), 1);
3275 QVERIFY(reply->error() != QNetworkReply::NoError);
3278 void tst_QNetworkReply::ioGetFromHttpStatus100_data()
3280 QTest::addColumn<QByteArray>("dataToSend");
3281 QTest::addColumn<int>("statusCode");
3282 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;
3283 QTest::newRow("minimal") << QByteArray("HTTP/1.1 100 Continue\n\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") << 200;
3284 QTest::newRow("minimal2") << QByteArray("HTTP/1.1 100 Continue\n\nHTTP/1.0 200 OK\r\n\r\n") << 200;
3285 QTest::newRow("minimal3") << QByteArray("HTTP/1.1 100 Continue\n\nHTTP/1.0 200 OK\n\n") << 200;
3286 QTest::newRow("minimal+404") << QByteArray("HTTP/1.1 100 Continue\n\nHTTP/1.0 204 No Content\r\n\r\n") << 204;
3287 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;
3288 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;
3291 void tst_QNetworkReply::ioGetFromHttpStatus100()
3293 QFETCH(QByteArray, dataToSend);
3294 QFETCH(int, statusCode);
3295 MiniHttpServer server(dataToSend);
3296 server.doClose = true;
3298 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
3299 QNetworkReplyPtr reply(manager.get(request));
3301 QVERIFY(waitForFinish(reply) == Success);
3303 QCOMPARE(reply->url(), request.url());
3304 QCOMPARE(reply->error(), QNetworkReply::NoError);
3305 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), statusCode);
3306 QVERIFY(reply->rawHeader("bla").isNull());
3309 void tst_QNetworkReply::ioGetFromHttpNoHeaders_data()
3311 QTest::addColumn<QByteArray>("dataToSend");
3312 QTest::newRow("justStatus+noheaders+disconnect") << QByteArray("HTTP/1.0 200 OK\r\n\r\n");
3315 void tst_QNetworkReply::ioGetFromHttpNoHeaders()
3317 QFETCH(QByteArray, dataToSend);
3318 MiniHttpServer server(dataToSend);
3319 server.doClose = true;
3321 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
3322 QNetworkReplyPtr reply(manager.get(request));
3324 QVERIFY(waitForFinish(reply) == Success);
3326 QCOMPARE(reply->url(), request.url());
3327 QCOMPARE(reply->error(), QNetworkReply::NoError);
3328 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
3331 void tst_QNetworkReply::ioGetFromHttpWithCache_data()
3333 qRegisterMetaType<MyMemoryCache::CachedContent>();
3334 QTest::addColumn<QByteArray>("dataToSend");
3335 QTest::addColumn<QString>("body");
3336 QTest::addColumn<MyMemoryCache::CachedContent>("cachedReply");
3337 QTest::addColumn<int>("cacheMode");
3338 QTest::addColumn<QStringList>("extraHttpHeaders");
3339 QTest::addColumn<bool>("loadedFromCache");
3340 QTest::addColumn<bool>("networkUsed");
3342 QByteArray reply200 =
3344 "Connection: keep-alive\r\n"
3345 "Content-Type: text/plain\r\n"
3346 "Cache-control: no-cache\r\n"
3347 "Content-length: 8\r\n"
3350 QByteArray reply304 =
3351 "HTTP/1.0 304 Use Cache\r\n"
3352 "Connection: keep-alive\r\n"
3355 QTest::newRow("not-cached,always-network")
3356 << reply200 << "Reloaded" << MyMemoryCache::CachedContent() << int(QNetworkRequest::AlwaysNetwork) << QStringList() << false << true;
3357 QTest::newRow("not-cached,prefer-network")
3358 << reply200 << "Reloaded" << MyMemoryCache::CachedContent() << int(QNetworkRequest::PreferNetwork) << QStringList() << false << true;
3359 QTest::newRow("not-cached,prefer-cache")
3360 << reply200 << "Reloaded" << MyMemoryCache::CachedContent() << int(QNetworkRequest::PreferCache) << QStringList() << false << true;
3362 QDateTime present = QDateTime::currentDateTime().toUTC();
3363 QDateTime past = present.addSecs(-3600);
3364 QDateTime future = present.addSecs(3600);
3365 static const char dateFormat[] = "ddd, dd MMM yyyy hh:mm:ss 'GMT'";
3367 QNetworkCacheMetaData::RawHeaderList rawHeaders;
3368 MyMemoryCache::CachedContent content;
3369 content.second = "Not-reloaded";
3370 content.first.setLastModified(past);
3376 rawHeaders << QNetworkCacheMetaData::RawHeader("Date", QLocale::c().toString(past, dateFormat).toLatin1())
3377 << QNetworkCacheMetaData::RawHeader("Cache-control", "max-age=0"); // isn't used in cache loading
3378 content.first.setRawHeaders(rawHeaders);
3379 content.first.setLastModified(past);
3380 content.first.setExpirationDate(past);
3382 QTest::newRow("expired,200,prefer-network")
3383 << reply200 << "Reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << false << true;
3384 QTest::newRow("expired,200,prefer-cache")
3385 << reply200 << "Reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << false << true;
3387 QTest::newRow("expired,304,prefer-network")
3388 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << true << true;
3389 QTest::newRow("expired,304,prefer-cache")
3390 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << true << true;
3393 // Set to not-expired
3396 rawHeaders << QNetworkCacheMetaData::RawHeader("Date", QLocale::c().toString(past, dateFormat).toLatin1())
3397 << QNetworkCacheMetaData::RawHeader("Cache-control", "max-age=7200"); // isn't used in cache loading
3398 content.first.setRawHeaders(rawHeaders);
3399 content.first.setExpirationDate(future);
3401 QTest::newRow("not-expired,200,always-network")
3402 << reply200 << "Reloaded" << content << int(QNetworkRequest::AlwaysNetwork) << QStringList() << false << true;
3403 QTest::newRow("not-expired,200,prefer-network")
3404 << reply200 << "Not-reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << true << false;
3405 QTest::newRow("not-expired,200,prefer-cache")
3406 << reply200 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << true << false;
3407 QTest::newRow("not-expired,200,always-cache")
3408 << reply200 << "Not-reloaded" << content << int(QNetworkRequest::AlwaysCache) << QStringList() << true << false;
3410 QTest::newRow("not-expired,304,prefer-network")
3411 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << true << false;
3412 QTest::newRow("not-expired,304,prefer-cache")
3413 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << true << false;
3414 QTest::newRow("not-expired,304,always-cache")
3415 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::AlwaysCache) << QStringList() << true << false;
3418 // Set must-revalidate now
3421 rawHeaders << QNetworkCacheMetaData::RawHeader("Date", QLocale::c().toString(past, dateFormat).toLatin1())
3422 << QNetworkCacheMetaData::RawHeader("Cache-control", "max-age=7200, must-revalidate"); // must-revalidate is used
3423 content.first.setRawHeaders(rawHeaders);
3425 QTest::newRow("must-revalidate,200,always-network")
3426 << reply200 << "Reloaded" << content << int(QNetworkRequest::AlwaysNetwork) << QStringList() << false << true;
3427 QTest::newRow("must-revalidate,200,prefer-network")
3428 << reply200 << "Reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << false << true;
3429 QTest::newRow("must-revalidate,200,prefer-cache")
3430 << reply200 << "Reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << false << true;
3431 QTest::newRow("must-revalidate,200,always-cache")
3432 << reply200 << "" << content << int(QNetworkRequest::AlwaysCache) << QStringList() << false << false;
3434 QTest::newRow("must-revalidate,304,prefer-network")
3435 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << true << true;
3436 QTest::newRow("must-revalidate,304,prefer-cache")
3437 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << true << true;
3438 QTest::newRow("must-revalidate,304,always-cache")
3439 << reply304 << "" << content << int(QNetworkRequest::AlwaysCache) << QStringList() << false << false;
3445 rawHeaders << QNetworkCacheMetaData::RawHeader("Date", QLocale::c().toString(past, dateFormat).toLatin1())
3446 << QNetworkCacheMetaData::RawHeader("Cache-control", "max-age=7200"); // isn't used in cache loading
3447 content.first.setRawHeaders(rawHeaders);
3448 content.first.setExpirationDate(future);
3450 QByteArray reply206 =
3452 "Connection: keep-alive\r\n"
3453 "Content-Type: text/plain\r\n"
3454 "Cache-control: no-cache\r\n"
3455 "Content-Range: bytes 2-6/8\r\n"
3456 "Content-length: 4\r\n"
3460 QTest::newRow("partial,dontuse-cache")
3461 << reply206 << "load" << content << int(QNetworkRequest::PreferCache) << (QStringList() << "Range" << "bytes=2-6") << false << true;
3464 void tst_QNetworkReply::ioGetFromHttpWithCache()
3466 QFETCH(QByteArray, dataToSend);
3467 MiniHttpServer server(dataToSend);
3468 server.doClose = false;
3470 MyMemoryCache *memoryCache = new MyMemoryCache(&manager);
3471 manager.setCache(memoryCache);
3473 QFETCH(MyMemoryCache::CachedContent, cachedReply);
3474 QUrl url = "http://localhost:" + QString::number(server.serverPort());
3475 cachedReply.first.setUrl(url);
3476 if (!cachedReply.second.isNull())
3477 memoryCache->cache.insert(url.toEncoded(), cachedReply);
3479 QFETCH(int, cacheMode);
3480 QNetworkRequest request(url);
3481 request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, cacheMode);
3482 request.setAttribute(QNetworkRequest::CacheSaveControlAttribute, false);
3484 QFETCH(QStringList, extraHttpHeaders);
3485 QStringListIterator it(extraHttpHeaders);
3486 while (it.hasNext()) {
3487 QString header = it.next();
3488 QString value = it.next();
3489 request.setRawHeader(header.toLatin1(), value.toLatin1()); // To latin1? Deal with it!
3492 QNetworkReplyPtr reply(manager.get(request));
3494 QVERIFY(waitForFinish(reply) != Timeout);
3496 QTEST(reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool(), "loadedFromCache");
3497 QTEST(server.totalConnections > 0, "networkUsed");
3498 QFETCH(QString, body);
3499 QCOMPARE(reply->readAll().constData(), qPrintable(body));
3502 void tst_QNetworkReply::ioGetWithManyProxies_data()
3504 QTest::addColumn<QList<QNetworkProxy> >("proxyList");
3505 QTest::addColumn<QNetworkProxy>("proxyUsed");
3506 QTest::addColumn<QString>("url");
3507 QTest::addColumn<QNetworkReply::NetworkError>("expectedError");
3509 QList<QNetworkProxy> proxyList;
3511 // All of the other functions test DefaultProxy
3512 // So let's test something else
3514 // Simple tests that work:
3516 // HTTP request with HTTP caching proxy
3517 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129);
3518 QTest::newRow("http-on-http")
3519 << proxyList << proxyList.at(0)
3520 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3521 << QNetworkReply::NoError;
3523 // HTTP request with HTTP transparent proxy
3525 proxyList << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3129);
3526 QTest::newRow("http-on-http2")
3527 << proxyList << proxyList.at(0)
3528 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3529 << QNetworkReply::NoError;
3531 // HTTP request with SOCKS transparent proxy
3533 proxyList << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081);
3534 QTest::newRow("http-on-socks")
3535 << proxyList << proxyList.at(0)
3536 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3537 << QNetworkReply::NoError;
3539 // FTP request with FTP caching proxy
3541 proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121);
3542 QTest::newRow("ftp-on-ftp")
3543 << proxyList << proxyList.at(0)
3544 << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3545 << QNetworkReply::NoError;
3547 // The following test doesn't work because QFtp is too limited
3548 // It can only talk to its own kind of proxies
3550 // FTP request with SOCKSv5 transparent proxy
3552 proxyList << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081);
3553 QTest::newRow("ftp-on-socks")
3554 << proxyList << proxyList.at(0)
3555 << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3556 << QNetworkReply::NoError;
3559 // HTTPS with HTTP transparent proxy
3561 proxyList << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3129);
3562 QTest::newRow("https-on-http")
3563 << proxyList << proxyList.at(0)
3564 << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3565 << QNetworkReply::NoError;
3567 // HTTPS request with SOCKS transparent proxy
3569 proxyList << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081);
3570 QTest::newRow("https-on-socks")
3571 << proxyList << proxyList.at(0)
3572 << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3573 << QNetworkReply::NoError;
3578 // HTTP request with FTP caching proxy
3580 proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121);
3581 QTest::newRow("http-on-ftp")
3582 << proxyList << QNetworkProxy()
3583 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3584 << QNetworkReply::ProxyNotFoundError;
3586 // FTP request with HTTP caching proxy
3588 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129);
3589 QTest::newRow("ftp-on-http")
3590 << proxyList << QNetworkProxy()
3591 << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3592 << QNetworkReply::ProxyNotFoundError;
3594 // FTP request with HTTP caching proxies
3596 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
3597 << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3130);
3598 QTest::newRow("ftp-on-multiple-http")
3599 << proxyList << QNetworkProxy()
3600 << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3601 << QNetworkReply::ProxyNotFoundError;
3604 // HTTPS with HTTP caching proxy
3606 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129);
3607 QTest::newRow("https-on-httptransparent")
3608 << proxyList << QNetworkProxy()
3609 << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3610 << QNetworkReply::ProxyNotFoundError;
3612 // HTTPS with FTP caching proxy
3614 proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121);
3615 QTest::newRow("https-on-ftp")
3616 << proxyList << QNetworkProxy()
3617 << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3618 << QNetworkReply::ProxyNotFoundError;
3621 // Complex requests:
3623 // HTTP request with more than one HTTP proxy
3625 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
3626 << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3130);
3627 QTest::newRow("http-on-multiple-http")
3628 << proxyList << proxyList.at(0)
3629 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3630 << QNetworkReply::NoError;
3632 // HTTP request with HTTP + SOCKS
3634 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
3635 << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081);
3636 QTest::newRow("http-on-http+socks")
3637 << proxyList << proxyList.at(0)
3638 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3639 << QNetworkReply::NoError;
3641 // HTTP request with FTP + HTTP + SOCKS
3643 proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121)
3644 << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
3645 << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081);
3646 QTest::newRow("http-on-ftp+http+socks")
3647 << proxyList << proxyList.at(1) // second proxy should be used
3648 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3649 << QNetworkReply::NoError;
3651 // HTTP request with NoProxy + HTTP
3653 proxyList << QNetworkProxy(QNetworkProxy::NoProxy)
3654 << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129);
3655 QTest::newRow("http-on-noproxy+http")
3656 << proxyList << proxyList.at(0)
3657 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3658 << QNetworkReply::NoError;
3660 // HTTP request with FTP + NoProxy
3662 proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121)
3663 << QNetworkProxy(QNetworkProxy::NoProxy);
3664 QTest::newRow("http-on-ftp+noproxy")
3665 << proxyList << proxyList.at(1) // second proxy should be used
3666 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3667 << QNetworkReply::NoError;
3669 // FTP request with HTTP Caching + FTP
3671 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
3672 << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121);
3673 QTest::newRow("ftp-on-http+ftp")
3674 << proxyList << proxyList.at(1) // second proxy should be used
3675 << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3676 << QNetworkReply::NoError;
3679 // HTTPS request with HTTP Caching + HTTP transparent
3681 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
3682 << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3129);
3683 QTest::newRow("https-on-httpcaching+http")
3684 << proxyList << proxyList.at(1) // second proxy should be used
3685 << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3686 << QNetworkReply::NoError;
3688 // HTTPS request with FTP + HTTP C + HTTP T
3690 proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121)
3691 << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
3692 << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3129);
3693 QTest::newRow("https-on-ftp+httpcaching+http")
3694 << proxyList << proxyList.at(2) // skip the first two
3695 << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3696 << QNetworkReply::NoError;
3700 void tst_QNetworkReply::ioGetWithManyProxies()
3702 // Test proxy factories
3704 QFile reference(testDataDir + "/rfc3252.txt");
3705 QVERIFY(reference.open(QIODevice::ReadOnly));
3707 // set the proxy factory:
3708 QFETCH(QList<QNetworkProxy>, proxyList);
3709 MyProxyFactory *proxyFactory = new MyProxyFactory;
3710 proxyFactory->toReturn = proxyList;
3711 manager.setProxyFactory(proxyFactory);
3713 QFETCH(QString, url);
3715 QNetworkRequest request(theUrl);
3716 QNetworkReplyPtr reply(manager.get(request));
3717 DataReader reader(reply);
3719 QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3720 connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3721 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3723 connect(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
3724 SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
3727 QVERIFY(waitForFinish(reply) != Timeout);
3729 manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3730 this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3732 manager.disconnect(SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
3733 this, SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
3736 QFETCH(QNetworkReply::NetworkError, expectedError);
3737 QEXPECT_FAIL("ftp-on-socks", "QFtp is too limited and won't accept non-FTP proxies", Abort);
3738 QCOMPARE(reply->error(), expectedError);
3740 // Verify that the factory was called properly
3741 QCOMPARE(proxyFactory->callCount, 1);
3742 QCOMPARE(proxyFactory->lastQuery, QNetworkProxyQuery(theUrl));
3744 if (expectedError == QNetworkReply::NoError) {
3745 // request succeeded
3746 QCOMPARE(reader.data, reference.readAll());
3748 // now verify that the proxies worked:
3749 QFETCH(QNetworkProxy, proxyUsed);
3750 if (proxyUsed.type() == QNetworkProxy::NoProxy) {
3751 QCOMPARE(authspy.count(), 0);
3753 if (QByteArray(QTest::currentDataTag()).startsWith("ftp-"))
3754 return; // No authentication with current FTP or with FTP proxies
3755 QCOMPARE(authspy.count(), 1);
3756 QCOMPARE(qvariant_cast<QNetworkProxy>(authspy.at(0).at(0)), proxyUsed);
3760 QCOMPARE(authspy.count(), 0);
3764 void tst_QNetworkReply::ioPutToFileFromFile_data()
3766 QTest::addColumn<QString>("fileName");
3768 QTest::newRow("empty") << (testDataDir + "/empty");
3769 QTest::newRow("real-file") << (testDataDir + "/rfc3252.txt");
3770 QTest::newRow("resource") << ":/resource";
3771 QTest::newRow("search-path") << "testdata:/rfc3252.txt";
3774 void tst_QNetworkReply::ioPutToFileFromFile()
3776 QFETCH(QString, fileName);
3777 QFile sourceFile(fileName);
3778 QFile targetFile(testFileName);
3780 QVERIFY(sourceFile.open(QIODevice::ReadOnly));
3782 QUrl url = QUrl::fromLocalFile(targetFile.fileName());
3783 QNetworkRequest request(url);
3784 QNetworkReplyPtr reply(manager.put(request, &sourceFile));
3786 QVERIFY(waitForFinish(reply) == Success);
3788 QCOMPARE(reply->url(), url);
3789 QCOMPARE(reply->error(), QNetworkReply::NoError);
3790 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
3791 QVERIFY(reply->readAll().isEmpty());
3793 QVERIFY(sourceFile.atEnd());
3794 sourceFile.seek(0); // reset it to the beginning
3796 QVERIFY(targetFile.open(QIODevice::ReadOnly));
3797 QCOMPARE(targetFile.size(), sourceFile.size());
3798 QCOMPARE(targetFile.readAll(), sourceFile.readAll());
3801 void tst_QNetworkReply::ioPutToFileFromSocket_data()
3806 void tst_QNetworkReply::ioPutToFileFromSocket()
3808 QFile file(testFileName);
3810 QUrl url = QUrl::fromLocalFile(file.fileName());
3811 QNetworkRequest request(url);
3813 QFETCH(QByteArray, data);
3814 SocketPair socketpair;
3815 socketpair.create();
3816 QVERIFY(socketpair.endPoints[0] && socketpair.endPoints[1]);
3818 socketpair.endPoints[0]->write(data);
3819 QNetworkReplyPtr reply(manager.put(QNetworkRequest(url), socketpair.endPoints[1]));
3820 socketpair.endPoints[0]->close();
3822 QVERIFY(waitForFinish(reply) == Success);
3823 QCOMPARE(reply->error(), QNetworkReply::NoError);
3825 QCOMPARE(reply->url(), url);
3826 QCOMPARE(reply->error(), QNetworkReply::NoError);
3827 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
3828 QVERIFY(reply->readAll().isEmpty());
3830 QVERIFY(file.open(QIODevice::ReadOnly));
3831 QCOMPARE(file.size(), qint64(data.size()));
3832 QByteArray contents = file.readAll();
3833 QCOMPARE(contents, data);
3836 void tst_QNetworkReply::ioPutToFileFromLocalSocket_data()
3841 void tst_QNetworkReply::ioPutToFileFromLocalSocket()
3843 QString socketname = "networkreplytest";
3844 QLocalServer server;
3845 if (!server.listen(socketname)) {
3846 QLocalServer::removeServer(socketname);
3847 QVERIFY(server.listen(socketname));
3849 QLocalSocket active;
3850 active.connectToServer(socketname);
3851 QVERIFY2(server.waitForNewConnection(10), server.errorString().toLatin1().constData());
3852 QVERIFY2(active.waitForConnected(10), active.errorString().toLatin1().constData());
3853 QVERIFY2(server.hasPendingConnections(), server.errorString().toLatin1().constData());
3854 QLocalSocket *passive = server.nextPendingConnection();
3856 QFile file(testFileName);
3857 QUrl url = QUrl::fromLocalFile(file.fileName());
3858 QNetworkRequest request(url);
3860 QFETCH(QByteArray, data);
3863 QNetworkReplyPtr reply(manager.put(QNetworkRequest(url), passive));
3864 passive->setParent(reply.data());
3867 if (!data.isEmpty())
3868 QEXPECT_FAIL("", "QTBUG-18385", Abort);
3870 QVERIFY(waitForFinish(reply) == Success);
3871 QCOMPARE(reply->error(), QNetworkReply::NoError);
3873 QCOMPARE(reply->url(), url);
3874 QCOMPARE(reply->error(), QNetworkReply::NoError);
3875 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
3876 QVERIFY(reply->readAll().isEmpty());
3878 QVERIFY(file.open(QIODevice::ReadOnly));
3879 QCOMPARE(file.size(), qint64(data.size()));
3880 QByteArray contents = file.readAll();
3881 QCOMPARE(contents, data);
3884 // Currently no stdin/out supported for Windows CE.
3885 #ifndef QT_NO_PROCESS
3886 void tst_QNetworkReply::ioPutToFileFromProcess_data()
3891 void tst_QNetworkReply::ioPutToFileFromProcess()
3893 #if defined(Q_OS_WINCE)
3894 QSKIP("Currently no stdin/out supported for Windows CE");
3897 if (qstrcmp(QTest::currentDataTag(), "small") == 0)
3898 QSKIP("When passing a CR-LF-LF sequence through Windows stdio, it gets converted, "
3899 "so this test fails. Disabled on Windows");
3902 QFile file(testFileName);
3904 QUrl url = QUrl::fromLocalFile(file.fileName());
3905 QNetworkRequest request(url);
3907 QFETCH(QByteArray, data);
3909 QString echoExe = echoProcessDir + "/echo";
3910 process.start(echoExe, QStringList("all"));
3911 QVERIFY2(process.waitForStarted(), qPrintable(
3912 QString::fromLatin1("Could not start %1: %2").arg(echoExe, process.errorString())));
3913 process.write(data);
3914 process.closeWriteChannel();
3916 QNetworkReplyPtr reply(manager.put(QNetworkRequest(url), &process));
3918 QVERIFY(waitForFinish(reply) == Success);
3920 QCOMPARE(reply->url(), url);
3921 QCOMPARE(reply->error(), QNetworkReply::NoError);
3922 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
3923 QVERIFY(reply->readAll().isEmpty());
3925 QVERIFY(file.open(QIODevice::ReadOnly));
3926 QCOMPARE(file.size(), qint64(data.size()));
3927 QByteArray contents = file.readAll();
3928 QCOMPARE(contents, data);
3933 void tst_QNetworkReply::ioPutToFtpFromFile_data()
3935 ioPutToFileFromFile_data();
3938 void tst_QNetworkReply::ioPutToFtpFromFile()
3940 QFETCH(QString, fileName);
3941 QFile sourceFile(fileName);
3942 QVERIFY(sourceFile.open(QIODevice::ReadOnly));
3944 QUrl url("ftp://" + QtNetworkSettings::serverName());
3945 url.setPath(QString("/qtest/upload/qnetworkaccess-ioPutToFtpFromFile-%1-%2")
3946 .arg(QTest::currentDataTag())
3947 .arg(uniqueExtension));
3949 QNetworkRequest request(url);
3950 QNetworkReplyPtr reply(manager.put(request, &sourceFile));
3952 QVERIFY(waitForFinish(reply) == Success);
3954 QCOMPARE(reply->url(), url);
3955 QCOMPARE(reply->error(), QNetworkReply::NoError);
3956 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
3957 QVERIFY(reply->readAll().isEmpty());
3959 QVERIFY(sourceFile.atEnd());
3960 sourceFile.seek(0); // reset it to the beginning
3962 // download the file again from FTP to make sure it was uploaded
3964 QNetworkAccessManager qnam;
3965 QNetworkRequest req(url);
3966 QNetworkReply *r = qnam.get(req);
3968 QObject::connect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
3969 QTestEventLoop::instance().enterLoop(3);
3970 QObject::disconnect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
3972 QByteArray uploaded = r->readAll();
3973 QCOMPARE(qint64(uploaded.size()), sourceFile.size());
3974 QCOMPARE(uploaded, sourceFile.readAll());
3977 QObject::connect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
3978 QTestEventLoop::instance().enterLoop(10);
3979 QObject::disconnect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
3982 void tst_QNetworkReply::ioPutToHttpFromFile_data()
3984 ioPutToFileFromFile_data();
3987 void tst_QNetworkReply::ioPutToHttpFromFile()
3989 QFETCH(QString, fileName);
3990 QFile sourceFile(fileName);
3991 QVERIFY(sourceFile.open(QIODevice::ReadOnly));
3993 QUrl url("http://" + QtNetworkSettings::serverName());
3994 url.setPath(QString("/dav/qnetworkaccess-ioPutToHttpFromFile-%1-%2")
3995 .arg(QTest::currentDataTag())
3996 .arg(uniqueExtension));
3998 QNetworkRequest request(url);
3999 QNetworkReplyPtr reply(manager.put(request, &sourceFile));
4001 QVERIFY(waitForFinish(reply) == Success);
4003 QCOMPARE(reply->url(), url);
4004 QCOMPARE(reply->error(), QNetworkReply::NoError);
4006 // verify that the HTTP status code is 201 Created
4007 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 201);
4009 QVERIFY(sourceFile.atEnd());
4010 sourceFile.seek(0); // reset it to the beginning
4012 // download the file again from HTTP to make sure it was uploaded
4014 reply.reset(manager.get(request));
4016 QVERIFY(waitForFinish(reply) == Success);
4018 QCOMPARE(reply->url(), url);
4019 QCOMPARE(reply->error(), QNetworkReply::NoError);
4020 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
4022 QCOMPARE(reply->readAll(), sourceFile.readAll());
4025 void tst_QNetworkReply::ioPostToHttpFromFile_data()
4027 ioPutToFileFromFile_data();
4030 void tst_QNetworkReply::ioPostToHttpFromFile()
4032 QFETCH(QString, fileName);
4033 QFile sourceFile(fileName);
4034 QVERIFY(sourceFile.open(QIODevice::ReadOnly));
4036 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi");
4037 QNetworkRequest request(url);
4038 request.setRawHeader("Content-Type", "application/octet-stream");
4040 QNetworkReplyPtr reply(manager.post(request, &sourceFile));
4042 QVERIFY(waitForFinish(reply) == Success);
4044 QCOMPARE(reply->url(), url);
4045 QCOMPARE(reply->error(), QNetworkReply::NoError);
4047 // verify that the HTTP status code is 200 Ok
4048 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
4050 QVERIFY(sourceFile.atEnd());
4051 sourceFile.seek(0); // reset it to the beginning
4053 QCOMPARE(reply->readAll().trimmed(), md5sum(sourceFile.readAll()).toHex());
4056 void tst_QNetworkReply::ioPostToHttpFromSocket_data()
4058 QTest::addColumn<QByteArray>("data");
4059 QTest::addColumn<QByteArray>("md5sum");
4060 QTest::addColumn<QUrl>("url");
4061 QTest::addColumn<QNetworkProxy>("proxy");
4062 QTest::addColumn<int>("authenticationRequiredCount");
4063 QTest::addColumn<int>("proxyAuthenticationRequiredCount");
4065 for (int i = 0; i < proxies.count(); ++i)
4066 for (int auth = 0; auth < 2; ++auth) {
4069 url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi";
4071 url = "http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi";
4073 QNetworkProxy proxy = proxies.at(i).proxy;
4074 QByteArray testsuffix = QByteArray(auth ? "+auth" : "") + proxies.at(i).tag;
4075 int proxyauthcount = proxies.at(i).requiresAuthentication;
4079 QTest::newRow("empty" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount;
4081 data = "This is a normal message.";
4082 QTest::newRow("generic" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount;
4084 data = "This is a message to show that Qt rocks!\r\n\n";
4085 QTest::newRow("small" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount;
4087 data = QByteArray("abcd\0\1\2\abcd",12);
4088 QTest::newRow("with-nul" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount;
4090 data = QByteArray(4097, '\4');
4091 QTest::newRow("4k+1" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount;
4093 data = QByteArray(128*1024+1, '\177');
4094 QTest::newRow("128k+1" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount;
4098 void tst_QNetworkReply::ioPostToHttpFromSocket()
4100 QFETCH(QByteArray, data);
4102 QFETCH(QNetworkProxy, proxy);
4103 SocketPair socketpair;
4104 socketpair.create();
4105 QVERIFY(socketpair.endPoints[0] && socketpair.endPoints[1]);
4107 socketpair.endPoints[0]->write(data);
4109 QNetworkRequest request(url);
4110 request.setRawHeader("Content-Type", "application/octet-stream");
4112 manager.setProxy(proxy);
4113 QNetworkReplyPtr reply(manager.post(request, socketpair.endPoints[1]));
4114 socketpair.endPoints[0]->close();
4116 connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
4117 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
4118 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4119 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4121 QSignalSpy authenticationRequiredSpy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4122 QSignalSpy proxyAuthenticationRequiredSpy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
4124 QVERIFY(waitForFinish(reply) == Success);
4126 disconnect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
4127 this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
4128 disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4129 this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4130 QCOMPARE(reply->error(), QNetworkReply::NoError);
4132 QCOMPARE(reply->url(), url);
4133 QCOMPARE(reply->error(), QNetworkReply::NoError);
4134 // verify that the HTTP status code is 200 Ok
4135 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
4137 QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex());
4139 QTEST(authenticationRequiredSpy.count(), "authenticationRequiredCount");
4140 QTEST(proxyAuthenticationRequiredSpy.count(), "proxyAuthenticationRequiredCount");
4143 void tst_QNetworkReply::ioPostToHttpFromSocketSynchronous_data()
4145 QTest::addColumn<QByteArray>("data");
4146 QTest::addColumn<QByteArray>("md5sum");
4150 QTest::newRow("empty") << data << md5sum(data);
4152 data = "This is a normal message.";
4153 QTest::newRow("generic") << data << md5sum(data);
4155 data = "This is a message to show that Qt rocks!\r\n\n";
4156 QTest::newRow("small") << data << md5sum(data);
4158 data = QByteArray("abcd\0\1\2\abcd",12);
4159 QTest::newRow("with-nul") << data << md5sum(data);
4161 data = QByteArray(4097, '\4');
4162 QTest::newRow("4k+1") << data << md5sum(data);
4164 data = QByteArray(128*1024+1, '\177');
4165 QTest::newRow("128k+1") << data << md5sum(data);
4167 data = QByteArray(2*1024*1024+1, '\177');
4168 QTest::newRow("2MB+1") << data << md5sum(data);
4171 void tst_QNetworkReply::ioPostToHttpFromSocketSynchronous()
4173 QFETCH(QByteArray, data);
4175 SocketPair socketpair;
4176 QVERIFY(socketpair.create());
4177 QVERIFY(socketpair.endPoints[0] && socketpair.endPoints[1]);
4178 socketpair.endPoints[0]->write(data);
4179 socketpair.endPoints[0]->waitForBytesWritten(5000);
4180 // ### for 4.8: make the socket pair unbuffered, to not read everything in one go in QNetworkReplyImplPrivate::setup()
4181 QTestEventLoop::instance().enterLoop(3);
4183 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi");
4184 QNetworkRequest request(url);
4185 request.setRawHeader("Content-Type", "application/octet-stream");
4186 request.setAttribute(
4187 QNetworkRequest::SynchronousRequestAttribute,
4190 QNetworkReplyPtr reply(manager.post(request, socketpair.endPoints[1]));
4191 QVERIFY(reply->isFinished());
4192 socketpair.endPoints[0]->close();
4194 QCOMPARE(reply->error(), QNetworkReply::NoError);
4196 QCOMPARE(reply->url(), url);
4197 QCOMPARE(reply->error(), QNetworkReply::NoError);
4198 // verify that the HTTP status code is 200 Ok
4199 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
4201 QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex());
4204 // this tests checks if rewinding the POST-data to some place in the middle
4206 void tst_QNetworkReply::ioPostToHttpFromMiddleOfFileToEnd()
4208 QFile sourceFile(testDataDir + "/rfc3252.txt");
4209 QVERIFY(sourceFile.open(QIODevice::ReadOnly));
4210 // seeking to the middle
4211 sourceFile.seek(sourceFile.size() / 2);
4213 QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi";
4214 QNetworkRequest request(url);
4215 request.setRawHeader("Content-Type", "application/octet-stream");
4216 QNetworkReplyPtr reply(manager.post(request, &sourceFile));
4218 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4219 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4221 QVERIFY(waitForFinish(reply) == Success);
4223 disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4224 this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4226 // compare half data
4227 sourceFile.seek(sourceFile.size() / 2);
4228 QByteArray data = sourceFile.readAll();
4229 QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex());
4232 void tst_QNetworkReply::ioPostToHttpFromMiddleOfFileFiveBytes()
4234 QFile sourceFile(testDataDir + "/rfc3252.txt");
4235 QVERIFY(sourceFile.open(QIODevice::ReadOnly));
4236 // seeking to the middle
4237 sourceFile.seek(sourceFile.size() / 2);
4239 QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi";
4240 QNetworkRequest request(url);
4241 request.setRawHeader("Content-Type", "application/octet-stream");
4242 // only send 5 bytes
4243 request.setHeader(QNetworkRequest::ContentLengthHeader, 5);
4244 QVERIFY(request.header(QNetworkRequest::ContentLengthHeader).isValid());
4245 QNetworkReplyPtr reply(manager.post(request, &sourceFile));
4247 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4248 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4250 QVERIFY(waitForFinish(reply) == Success);
4252 disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4253 this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4255 // compare half data
4256 sourceFile.seek(sourceFile.size() / 2);
4257 QByteArray data = sourceFile.read(5);
4258 QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex());
4261 void tst_QNetworkReply::ioPostToHttpFromMiddleOfQBufferFiveBytes()
4263 // test needed since a QBuffer goes with a different codepath than the QFile
4264 // tested in ioPostToHttpFromMiddleOfFileFiveBytes
4265 QBuffer uploadBuffer;
4266 uploadBuffer.open(QIODevice::ReadWrite);
4267 uploadBuffer.write("1234567890");
4268 uploadBuffer.seek(5);
4270 QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi";
4271 QNetworkRequest request(url);
4272 request.setRawHeader("Content-Type", "application/octet-stream");
4273 QNetworkReplyPtr reply(manager.post(request, &uploadBuffer));
4275 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4276 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4278 QVERIFY(waitForFinish(reply) == Success);
4280 disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4281 this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4283 // compare half data
4284 uploadBuffer.seek(5);
4285 QByteArray data = uploadBuffer.read(5);
4286 QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex());
4290 void tst_QNetworkReply::ioPostToHttpNoBufferFlag()
4292 QByteArray data = QByteArray("daaaaaaataaaaaaa");
4293 // create a sequential QIODevice by feeding the data into a local TCP server
4294 SocketPair socketpair;
4295 socketpair.create();
4296 QVERIFY(socketpair.endPoints[0] && socketpair.endPoints[1]);
4297 socketpair.endPoints[0]->write(data);
4299 QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi";
4300 QNetworkRequest request(url);
4301 request.setRawHeader("Content-Type", "application/octet-stream");
4302 // disallow buffering
4303 request.setAttribute(QNetworkRequest::DoNotBufferUploadDataAttribute, true);
4304 request.setHeader(QNetworkRequest::ContentLengthHeader, data.size());
4305 QNetworkReplyPtr reply(manager.post(request, socketpair.endPoints[1]));
4306 socketpair.endPoints[0]->close();
4308 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4309 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4311 QVERIFY(waitForFinish(reply) == Failure);
4313 disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4314 this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4316 // verify: error code is QNetworkReply::ContentReSendError
4317 QCOMPARE(reply->error(), QNetworkReply::ContentReSendError);
4321 class SslServer : public QTcpServer {
4324 SslServer() : socket(0) {};
4325 void incomingConnection(qintptr socketDescriptor) {
4326 QSslSocket *serverSocket = new QSslSocket;
4327 serverSocket->setParent(this);
4329 if (serverSocket->setSocketDescriptor(socketDescriptor)) {
4330 QString testDataDir = QFileInfo(QFINDTESTDATA("rfc3252.txt")).absolutePath();
4331 if (testDataDir.isEmpty())
4332 testDataDir = QCoreApplication::applicationDirPath();
4334 connect(serverSocket, SIGNAL(encrypted()), this, SLOT(encryptedSlot()));
4335 connect(serverSocket, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
4336 serverSocket->setProtocol(QSsl::AnyProtocol);
4337 connect(serverSocket, SIGNAL(sslErrors(const QList<QSslError>&)), serverSocket, SLOT(ignoreSslErrors()));
4338 serverSocket->setLocalCertificate(testDataDir + "/certs/server.pem");
4339 serverSocket->setPrivateKey(testDataDir + "/certs/server.key");
4340 serverSocket->startServerEncryption();
4342 delete serverSocket;
4346 void newEncryptedConnection();
4348 void encryptedSlot() {
4349 socket = (QSslSocket*) sender();
4350 emit newEncryptedConnection();
4352 void readyReadSlot() {
4353 // for the incoming sockets, not the server socket
4354 //qDebug() << static_cast<QSslSocket*>(sender())->bytesAvailable() << static_cast<QSslSocket*>(sender())->encryptedBytesAvailable();
4361 // very similar to ioPostToHttpUploadProgress but for SSL
4362 void tst_QNetworkReply::ioPostToHttpsUploadProgress()
4364 //QFile sourceFile(testDataDir + "/bigfile");
4365 //QVERIFY(sourceFile.open(QIODevice::ReadOnly));
4366 qint64 wantedSize = 2*1024*1024; // 2 MB
4367 QByteArray sourceFile;
4368 // And in the case of SSL, the compression can fool us and let the
4369 // server send the data much faster than expected.
4370 // So better provide random data that cannot be compressed.
4371 for (int i = 0; i < wantedSize; ++i)
4372 sourceFile += (char)qrand();
4374 // emulate a minimal https server
4376 server.listen(QHostAddress(QHostAddress::LocalHost), 0);
4378 // create the request
4379 QUrl url = QUrl(QString("https://127.0.0.1:%1/").arg(server.serverPort()));
4380 QNetworkRequest request(url);
4382 request.setRawHeader("Content-Type", "application/octet-stream");
4383 QNetworkReplyPtr reply(manager.post(request, sourceFile));
4385 QSignalSpy spy(reply.data(), SIGNAL(uploadProgress(qint64,qint64)));
4386 connect(&server, SIGNAL(newEncryptedConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
4387 connect(reply, SIGNAL(sslErrors(const QList<QSslError>&)), reply.data(), SLOT(ignoreSslErrors()));
4389 // get the request started and the incoming socket connected
4390 QTestEventLoop::instance().enterLoop(10);
4391 QVERIFY(!QTestEventLoop::instance().timeout());
4392 QTcpSocket *incomingSocket = server.socket;
4393 QVERIFY(incomingSocket);
4394 disconnect(&server, SIGNAL(newEncryptedConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
4397 incomingSocket->setReadBufferSize(1*1024);
4398 QTestEventLoop::instance().enterLoop(2);
4399 // some progress should have been made
4400 QVERIFY(!spy.isEmpty());
4401 QList<QVariant> args = spy.last();
4402 QVERIFY(args.at(0).toLongLong() > 0);
4403 // but not everything!
4404 QVERIFY(args.at(0).toLongLong() != sourceFile.size());
4406 // set the read buffer to unlimited
4407 incomingSocket->setReadBufferSize(0);
4408 QTestEventLoop::instance().enterLoop(10);
4409 // progress should be finished
4410 QVERIFY(!spy.isEmpty());
4411 QList<QVariant> args3 = spy.last();
4412 QCOMPARE(args3.at(0).toLongLong(), args3.at(1).toLongLong());
4413 QCOMPARE(args3.at(0).toLongLong(), qint64(sourceFile.size()));
4415 // after sending this, the QNAM should emit finished()
4416 incomingSocket->write("HTTP/1.0 200 OK\r\n");
4417 incomingSocket->write("Content-Length: 0\r\n");
4418 incomingSocket->write("\r\n");
4420 QVERIFY(waitForFinish(reply) == Success);
4422 incomingSocket->close();
4427 void tst_QNetworkReply::ioGetFromBuiltinHttp_data()
4429 QTest::addColumn<bool>("https");
4430 QTest::addColumn<int>("bufferSize");
4431 QTest::newRow("http+unlimited") << false << 0;
4432 QTest::newRow("http+limited") << false << 4096;
4434 QTest::newRow("https+unlimited") << true << 0;
4435 QTest::newRow("https+limited") << true << 4096;
4439 void tst_QNetworkReply::ioGetFromBuiltinHttp()
4441 QSKIP("Limiting is broken right now, check QTBUG-15065");
4442 QFETCH(bool, https);
4443 QFETCH(int, bufferSize);
4445 QByteArray testData;
4446 // Make the data big enough so that it can fill the kernel buffer
4447 // (which seems to hold 202 KB here)
4448 const int wantedSize = 1200 * 1000;
4449 testData.reserve(wantedSize);
4450 // And in the case of SSL, the compression can fool us and let the
4451 // server send the data much faster than expected.
4452 // So better provide random data that cannot be compressed.
4453 for (int i = 0; i < wantedSize; ++i)
4454 testData += (char)qrand();
4456 QByteArray httpResponse = QByteArray("HTTP/1.0 200 OK\r\nContent-Length: ");
4457 httpResponse += QByteArray::number(testData.size());
4458 httpResponse += "\r\n\r\n";
4459 httpResponse += testData;
4461 qDebug() << "Server will send" << (httpResponse.size()-testData.size()) << "bytes of header and"
4462 << testData.size() << "bytes of data";
4464 const bool fillKernelBuffer = bufferSize > 0;
4465 FastSender server(httpResponse, https, fillKernelBuffer);
4467 QUrl url(QString("%1://127.0.0.1:%2/qtest/rfc3252.txt")
4468 .arg(https?"https":"http")
4469 .arg(server.serverPort()));
4470 QNetworkRequest request(url);
4471 QNetworkReplyPtr reply(manager.get(request));
4472 reply->setReadBufferSize(bufferSize);
4473 reply->ignoreSslErrors();
4474 const int rate = 200; // in kB per sec
4475 RateControlledReader reader(server, reply.data(), rate, bufferSize);
4480 QVERIFY(waitForFinish(reply) == Success);
4482 const int elapsedTime = loopTime.elapsed();
4486 qDebug() << "send rate:" << server.transferRate << "B/s";
4487 qDebug() << "receive rate:" << reader.totalBytesRead * 1000 / elapsedTime
4488 << "(it received" << reader.totalBytesRead << "bytes in" << elapsedTime << "ms)";
4490 QCOMPARE(reply->url(), request.url());
4491 QCOMPARE(reply->error(), QNetworkReply::NoError);
4492 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
4494 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), (qint64)testData.size());
4495 if (reader.data.size() < testData.size()) { // oops?
4496 QCOMPARE(reader.data, testData.mid(0, reader.data.size()));
4497 qDebug() << "The data is incomplete, the last" << testData.size() - reader.data.size() << "bytes are missing";
4498 QEXPECT_FAIL("http+limited", "Limiting is broken right now, check QTBUG-15065", Abort);
4499 QEXPECT_FAIL("https+limited", "Limiting is broken right now, check QTBUG-15065", Abort);
4501 QCOMPARE(reader.data.size(), testData.size());
4502 QCOMPARE(reader.data, testData);
4504 // OK we got the file alright, but did setReadBufferSize work?
4505 QVERIFY(server.transferRate != -1);
4506 if (bufferSize > 0) {
4507 const int allowedDeviation = 16; // TODO find out why the send rate is 13% faster currently
4508 const int minRate = rate * 1024 * (100-allowedDeviation) / 100;
4509 const int maxRate = rate * 1024 * (100+allowedDeviation) / 100;
4510 qDebug() << minRate << "<="<< server.transferRate << "<=" << maxRate << "?";
4511 QEXPECT_FAIL("http+limited", "Limiting is broken right now, check QTBUG-15065", Continue);
4512 QEXPECT_FAIL("https+limited", "Limiting is broken right now, check QTBUG-15065", Continue);
4513 QVERIFY(server.transferRate >= minRate && server.transferRate <= maxRate);
4517 void tst_QNetworkReply::ioPostToHttpUploadProgress()
4519 QFile sourceFile(testDataDir + "/bigfile");
4520 QVERIFY(sourceFile.open(QIODevice::ReadOnly));
4522 // emulate a minimal http server
4524 server.listen(QHostAddress(QHostAddress::LocalHost), 0);
4526 // create the request
4527 QUrl url = QUrl(QString("http://127.0.0.1:%1/").arg(server.serverPort()));
4528 QNetworkRequest request(url);
4529 request.setRawHeader("Content-Type", "application/octet-stream");
4530 QNetworkReplyPtr reply(manager.post(request, &sourceFile));
4531 QSignalSpy spy(reply.data(), SIGNAL(uploadProgress(qint64,qint64)));
4532 connect(&server, SIGNAL(newConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
4534 // get the request started and the incoming socket connected
4535 QTestEventLoop::instance().enterLoop(10);
4536 QVERIFY(!QTestEventLoop::instance().timeout());
4537 QTcpSocket *incomingSocket = server.nextPendingConnection();
4538 QVERIFY(incomingSocket);
4539 disconnect(&server, SIGNAL(newConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
4541 incomingSocket->setReadBufferSize(1*1024);
4542 QTestEventLoop::instance().enterLoop(5);
4543 // some progress should have been made
4544 QList<QVariant> args = spy.last();
4545 QVERIFY(!args.isEmpty());
4546 QVERIFY(args.at(0).toLongLong() > 0);
4547 // but not everything!
4548 QVERIFY(args.at(0).toLongLong() != sourceFile.size());
4550 // set the read buffer to unlimited
4551 incomingSocket->setReadBufferSize(0);
4552 QTestEventLoop::instance().enterLoop(10);
4553 // progress should be finished
4554 QList<QVariant> args3 = spy.last();
4555 QVERIFY(!args3.isEmpty());
4556 // More progress than before
4557 QVERIFY(args3.at(0).toLongLong() > args.at(0).toLongLong());
4558 QCOMPARE(args3.at(0).toLongLong(), args3.at(1).toLongLong());
4559 // And actually finished..
4560 QCOMPARE(args3.at(0).toLongLong(), sourceFile.size());
4562 // after sending this, the QNAM should emit finished()
4563 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
4564 incomingSocket->write("HTTP/1.0 200 OK\r\n");
4565 incomingSocket->write("Content-Length: 0\r\n");
4566 incomingSocket->write("\r\n");
4567 QTestEventLoop::instance().enterLoop(10);
4568 // not timeouted -> finished() was emitted
4569 QVERIFY(!QTestEventLoop::instance().timeout());
4571 incomingSocket->close();
4575 void tst_QNetworkReply::ioPostToHttpEmptyUploadProgress()
4579 QBuffer buffer(&ba,0);
4580 QVERIFY(buffer.open(QIODevice::ReadOnly));
4582 // emulate a minimal http server
4584 server.listen(QHostAddress(QHostAddress::LocalHost), 0);
4586 // create the request
4587 QUrl url = QUrl(QString("http://127.0.0.1:%1/").arg(server.serverPort()));
4588 QNetworkRequest request(url);
4589 request.setRawHeader("Content-Type", "application/octet-stream");
4590 QNetworkReplyPtr reply(manager.post(request, &buffer));
4591 QSignalSpy spy(reply.data(), SIGNAL(uploadProgress(qint64,qint64)));
4592 connect(&server, SIGNAL(newConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
4595 // get the request started and the incoming socket connected
4596 QTestEventLoop::instance().enterLoop(10);
4597 QVERIFY(!QTestEventLoop::instance().timeout());
4598 QTcpSocket *incomingSocket = server.nextPendingConnection();
4599 QVERIFY(incomingSocket);
4601 // after sending this, the QNAM should emit finished()
4602 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
4603 incomingSocket->write("HTTP/1.0 200 OK\r\n");
4604 incomingSocket->write("Content-Length: 0\r\n");
4605 incomingSocket->write("\r\n");
4606 incomingSocket->flush();
4607 QTestEventLoop::instance().enterLoop(10);
4608 // not timeouted -> finished() was emitted
4609 QVERIFY(!QTestEventLoop::instance().timeout());
4611 // final check: only 1 uploadProgress has been emitted
4612 QVERIFY(spy.length() == 1);
4613 QList<QVariant> args = spy.last();
4614 QVERIFY(!args.isEmpty());
4615 QCOMPARE(args.at(0).toLongLong(), buffer.size());
4616 QCOMPARE(args.at(0).toLongLong(), buffer.size());
4618 incomingSocket->close();
4622 void tst_QNetworkReply::lastModifiedHeaderForFile()
4624 QFileInfo fileInfo(testDataDir + "/bigfile");
4625 QVERIFY(fileInfo.exists());
4627 QUrl url = QUrl::fromLocalFile(fileInfo.filePath());
4629 QNetworkRequest request(url);
4630 QNetworkReplyPtr reply(manager.head(request));
4632 QVERIFY(waitForFinish(reply) == Success);
4634 QDateTime header = reply->header(QNetworkRequest::LastModifiedHeader).toDateTime();
4635 QCOMPARE(header, fileInfo.lastModified());
4638 void tst_QNetworkReply::lastModifiedHeaderForHttp()
4640 // Tue, 22 May 2007 12:04:57 GMT according to webserver
4641 QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/fluke.gif";
4643 QNetworkRequest request(url);
4644 QNetworkReplyPtr reply(manager.head(request));
4646 QVERIFY(waitForFinish(reply) == Success);
4648 QDateTime header = reply->header(QNetworkRequest::LastModifiedHeader).toDateTime();
4649 QDateTime realDate = QDateTime::fromString("2007-05-22T12:04:57", Qt::ISODate);
4650 realDate.setTimeSpec(Qt::UTC);
4652 QCOMPARE(header, realDate);
4655 void tst_QNetworkReply::httpCanReadLine()
4657 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
4658 QNetworkReplyPtr reply(manager.get(request));
4660 QVERIFY(waitForFinish(reply) == Success);
4662 QCOMPARE(reply->error(), QNetworkReply::NoError);
4664 QVERIFY(reply->canReadLine());
4665 QVERIFY(!reply->readAll().isEmpty());
4666 QVERIFY(!reply->canReadLine());
4669 void tst_QNetworkReply::rateControl_data()
4671 QTest::addColumn<int>("rate");
4673 QTest::newRow("15") << 15;
4674 QTest::newRow("40") << 40;
4675 QTest::newRow("73") << 73;
4676 QTest::newRow("80") << 80;
4677 QTest::newRow("125") << 125;
4678 QTest::newRow("250") << 250;
4679 QTest::newRow("1024") << 1024;
4682 void tst_QNetworkReply::rateControl()
4684 QSKIP("Test disabled -- only for manual purposes");
4685 // this function tests that we aren't reading from the network
4686 // faster than the data is being consumed.
4689 #if !defined(QT_BUILD_INTERNAL)
4690 QSKIP("backend for testing not available!");
4693 // ask for 20 seconds worth of data
4694 FastSender sender(20 * rate * 1024);
4696 QNetworkRequest request("debugpipe://localhost:" + QString::number(sender.serverPort()));
4697 QNetworkReplyPtr reply(manager.get(request));
4698 reply->setReadBufferSize(32768);
4699 QSignalSpy errorSpy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError)));
4701 RateControlledReader reader(sender, reply.data(), rate, 20);
4703 // this test is designed to run for 25 seconds at most
4707 QVERIFY(waitForFinish(reply) == Success);
4709 int elapsedTime = loopTime.elapsed();
4711 if (!errorSpy.isEmpty()) {
4712 qDebug() << "ERROR!" << errorSpy[0][0] << reply->errorString();
4715 qDebug() << "tst_QNetworkReply::rateControl" << "send rate:" << sender.transferRate;
4716 qDebug() << "tst_QNetworkReply::rateControl" << "receive rate:" << reader.totalBytesRead * 1000 / elapsedTime
4717 << "(it received" << reader.totalBytesRead << "bytes in" << elapsedTime << "ms)";
4721 QCOMPARE(reply->url(), request.url());
4722 QCOMPARE(reply->error(), QNetworkReply::NoError);
4724 QVERIFY(sender.transferRate != -1);
4725 int minRate = rate * 1024 * 9 / 10;
4726 int maxRate = rate * 1024 * 11 / 10;
4727 QVERIFY(sender.transferRate >= minRate);
4728 QVERIFY(sender.transferRate <= maxRate);
4731 void tst_QNetworkReply::downloadProgress_data()
4733 QTest::addColumn<int>("loopCount");
4735 QTest::newRow("empty") << 0;
4736 QTest::newRow("small") << 4;
4737 QTest::newRow("big") << 4096;
4740 void tst_QNetworkReply::downloadProgress()
4742 #if !defined(QT_BUILD_INTERNAL)
4743 QSKIP("backend for testing not available!");
4746 QVERIFY(server.listen());
4748 QNetworkRequest request("debugpipe://127.0.0.1:" + QString::number(server.serverPort()) + "/?bare=1");
4749 QNetworkReplyPtr reply(manager.get(request));
4750 QSignalSpy spy(reply.data(), SIGNAL(downloadProgress(qint64,qint64)));
4751 connect(reply, SIGNAL(downloadProgress(qint64,qint64)),
4752 &QTestEventLoop::instance(), SLOT(exitLoop()));
4753 QVERIFY(spy.isValid());
4754 QVERIFY(!reply->isFinished());
4755 QVERIFY(reply->isRunning());
4757 QCoreApplication::instance()->processEvents();
4758 if (!server.hasPendingConnections())
4759 server.waitForNewConnection(1000);
4760 QVERIFY(server.hasPendingConnections());
4761 QCOMPARE(spy.count(), 0);
4763 QByteArray data(128, 'a');
4764 QTcpSocket *sender = server.nextPendingConnection();
4767 QFETCH(int, loopCount);
4768 for (int i = 1; i <= loopCount; ++i) {
4769 sender->write(data);
4770 QVERIFY2(sender->waitForBytesWritten(2000), "Network timeout");
4773 QTestEventLoop::instance().enterLoop(2);
4774 QVERIFY(!QTestEventLoop::instance().timeout());
4775 QVERIFY(spy.count() > 0);
4776 QVERIFY(!reply->isFinished());
4777 QVERIFY(reply->isRunning());
4779 QList<QVariant> args = spy.last();
4780 QCOMPARE(args.at(0).toInt(), i*data.size());
4781 QCOMPARE(args.at(1).toInt(), -1);
4784 // close the connection:
4788 QTestEventLoop::instance().enterLoop(2);
4789 QCOMPARE(reply->error(), QNetworkReply::NoError);
4790 QVERIFY(!QTestEventLoop::instance().timeout());
4791 QVERIFY(spy.count() > 0);
4792 QVERIFY(!reply->isRunning());
4793 QVERIFY(reply->isFinished());
4795 QList<QVariant> args = spy.last();
4796 QCOMPARE(args.at(0).toInt(), loopCount * data.size());
4797 QCOMPARE(args.at(1).toInt(), loopCount * data.size());
4800 void tst_QNetworkReply::uploadProgress_data()
4805 void tst_QNetworkReply::uploadProgress()
4807 QFETCH(QByteArray, data);
4808 #if !defined(QT_BUILD_INTERNAL)
4809 QSKIP("backend for testing not available!");
4812 QVERIFY(server.listen());
4814 QNetworkRequest request("debugpipe://127.0.0.1:" + QString::number(server.serverPort()) + "/?bare=1");
4815 QNetworkReplyPtr reply(manager.put(request, data));
4816 QSignalSpy spy(reply.data(), SIGNAL(uploadProgress(qint64,qint64)));
4817 QSignalSpy finished(reply.data(), SIGNAL(finished()));
4818 QVERIFY(spy.isValid());
4819 QVERIFY(finished.isValid());
4821 QCoreApplication::instance()->processEvents();
4822 if (!server.hasPendingConnections())
4823 server.waitForNewConnection(1000);
4824 QVERIFY(server.hasPendingConnections());
4826 QTcpSocket *receiver = server.nextPendingConnection();
4827 if (finished.count() == 0) {
4828 // it's not finished yet, so wait for it to be
4829 QVERIFY(waitForFinish(reply) == Success);
4833 QVERIFY(finished.count() > 0);
4834 QVERIFY(spy.count() > 0);
4836 QList<QVariant> args = spy.last();
4837 QCOMPARE(args.at(0).toInt(), data.size());
4838 QCOMPARE(args.at(1).toInt(), data.size());
4841 void tst_QNetworkReply::chaining_data()
4846 void tst_QNetworkReply::chaining()
4848 QTemporaryFile sourceFile(QDir::currentPath() + "/temp-XXXXXX");
4849 sourceFile.setAutoRemove(true);
4850 QVERIFY(sourceFile.open());
4852 QFETCH(QByteArray, data);
4853 QVERIFY(sourceFile.write(data) == data.size());
4855 QCOMPARE(sourceFile.size(), qint64(data.size()));
4857 QNetworkRequest request(QUrl::fromLocalFile(sourceFile.fileName()));
4858 QNetworkReplyPtr getReply(manager.get(request));
4860 QFile targetFile(testFileName);
4861 QUrl url = QUrl::fromLocalFile(targetFile.fileName());
4862 request.setUrl(url);
4863 QNetworkReplyPtr putReply(manager.put(request, getReply.data()));
4865 QVERIFY(waitForFinish(putReply) == Success);
4867 QCOMPARE(getReply->url(), QUrl::fromLocalFile(sourceFile.fileName()));
4868 QCOMPARE(getReply->error(), QNetworkReply::NoError);
4869 QCOMPARE(getReply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), sourceFile.size());
4871 QCOMPARE(putReply->url(), url);
4872 QCOMPARE(putReply->error(), QNetworkReply::NoError);
4873 QCOMPARE(putReply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
4874 QVERIFY(putReply->readAll().isEmpty());
4876 QVERIFY(sourceFile.atEnd());
4877 sourceFile.seek(0); // reset it to the beginning
4879 QVERIFY(targetFile.open(QIODevice::ReadOnly));
4880 QCOMPARE(targetFile.size(), sourceFile.size());
4881 QCOMPARE(targetFile.readAll(), sourceFile.readAll());
4884 void tst_QNetworkReply::receiveCookiesFromHttp_data()
4886 QTest::addColumn<QString>("cookieString");
4887 QTest::addColumn<QList<QNetworkCookie> >("expectedCookiesFromHttp");
4888 QTest::addColumn<QList<QNetworkCookie> >("expectedCookiesInJar");
4890 QTest::newRow("empty") << "" << QList<QNetworkCookie>() << QList<QNetworkCookie>();
4892 QList<QNetworkCookie> header, jar;
4893 QNetworkCookie cookie("a", "b");
4895 cookie.setDomain(QtNetworkSettings::serverName());
4896 cookie.setPath("/qtest/cgi-bin/");
4898 QTest::newRow("simple-cookie") << "a=b" << header << jar;
4900 header << QNetworkCookie("c", "d");
4901 cookie.setName("c");
4902 cookie.setValue("d");
4904 QTest::newRow("two-cookies") << "a=b, c=d" << header << jar;
4905 QTest::newRow("two-cookies-2") << "a=b\nc=d" << header << jar;
4909 cookie = QNetworkCookie("a", "b");
4910 cookie.setPath("/not/part-of-path");
4912 cookie.setDomain(QtNetworkSettings::serverName());
4914 QTest::newRow("invalid-cookie-path") << "a=b; path=/not/part-of-path" << header << jar;
4917 cookie = QNetworkCookie("a", "b");
4918 cookie.setDomain(".example.com");
4921 QTest::newRow("invalid-cookie-domain") << "a=b; domain=.example.com" << header << jar;
4924 void tst_QNetworkReply::receiveCookiesFromHttp()
4926 QFETCH(QString, cookieString);
4928 QByteArray data = cookieString.toLatin1() + '\n';
4929 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/set-cookie.cgi");
4930 QNetworkRequest request(url);
4931 request.setRawHeader("Content-Type", "application/octet-stream");
4932 QNetworkReplyPtr reply;
4933 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PostOperation, request, reply, data));
4935 QCOMPARE(reply->url(), url);
4936 QCOMPARE(reply->error(), QNetworkReply::NoError);
4938 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
4940 QList<QNetworkCookie> setCookies =
4941 qvariant_cast<QList<QNetworkCookie> >(reply->header(QNetworkRequest::SetCookieHeader));
4942 QTEST(setCookies, "expectedCookiesFromHttp");
4943 QTEST(cookieJar->allCookies(), "expectedCookiesInJar");
4946 void tst_QNetworkReply::receiveCookiesFromHttpSynchronous_data()
4948 tst_QNetworkReply::receiveCookiesFromHttp_data();
4951 void tst_QNetworkReply::receiveCookiesFromHttpSynchronous()
4953 QFETCH(QString, cookieString);
4955 QByteArray data = cookieString.toLatin1() + '\n';
4956 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/set-cookie.cgi");
4958 QNetworkRequest request(url);
4959 request.setRawHeader("Content-Type", "application/octet-stream");
4960 request.setAttribute(
4961 QNetworkRequest::SynchronousRequestAttribute,
4964 QNetworkReplyPtr reply;
4965 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PostOperation, request, reply, data));
4967 QCOMPARE(reply->url(), url);
4968 QCOMPARE(reply->error(), QNetworkReply::NoError);
4970 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
4972 QList<QNetworkCookie> setCookies =
4973 qvariant_cast<QList<QNetworkCookie> >(reply->header(QNetworkRequest::SetCookieHeader));
4974 QTEST(setCookies, "expectedCookiesFromHttp");
4975 QTEST(cookieJar->allCookies(), "expectedCookiesInJar");
4978 void tst_QNetworkReply::sendCookies_data()
4980 QTest::addColumn<QList<QNetworkCookie> >("cookiesToSet");
4981 QTest::addColumn<QString>("expectedCookieString");
4983 QList<QNetworkCookie> list;
4984 QTest::newRow("empty") << list << "";
4986 QNetworkCookie cookie("a", "b");
4987 cookie.setPath("/");
4988 cookie.setDomain("example.com");
4990 QTest::newRow("no-match-domain") << list << "";
4992 cookie.setDomain(QtNetworkSettings::serverName());
4993 cookie.setPath("/something/else");
4995 QTest::newRow("no-match-path") << list << "";
4997 cookie.setPath("/");
4999 QTest::newRow("simple-cookie") << list << "a=b";
5001 cookie.setPath("/qtest");
5002 cookie.setValue("longer");
5004 QTest::newRow("two-cookies") << list << "a=longer; a=b";
5007 cookie = QNetworkCookie("a", "b");
5008 cookie.setPath("/");
5009 cookie.setDomain("." + QtNetworkSettings::serverDomainName());
5011 QTest::newRow("domain-match") << list << "a=b";
5013 // but it shouldn't match this:
5014 cookie.setDomain(QtNetworkSettings::serverDomainName());
5016 QTest::newRow("domain-match-2") << list << "a=b";
5019 void tst_QNetworkReply::sendCookies()
5021 QFETCH(QString, expectedCookieString);
5022 QFETCH(QList<QNetworkCookie>, cookiesToSet);
5023 cookieJar->setAllCookies(cookiesToSet);
5025 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/get-cookie.cgi");
5026 QNetworkRequest request(url);
5027 QNetworkReplyPtr reply;
5028 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
5030 QCOMPARE(reply->url(), url);
5031 QCOMPARE(reply->error(), QNetworkReply::NoError);
5033 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
5035 QCOMPARE(QString::fromLatin1(reply->readAll()).trimmed(), expectedCookieString);
5038 void tst_QNetworkReply::sendCookiesSynchronous_data()
5040 tst_QNetworkReply::sendCookies_data();
5043 void tst_QNetworkReply::sendCookiesSynchronous()
5045 QFETCH(QString, expectedCookieString);
5046 QFETCH(QList<QNetworkCookie>, cookiesToSet);
5047 cookieJar->setAllCookies(cookiesToSet);
5049 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/get-cookie.cgi");
5050 QNetworkRequest request(url);
5052 request.setAttribute(
5053 QNetworkRequest::SynchronousRequestAttribute,
5056 QNetworkReplyPtr reply;
5057 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
5059 QCOMPARE(reply->url(), url);
5060 QCOMPARE(reply->error(), QNetworkReply::NoError);
5062 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
5064 QCOMPARE(QString::fromLatin1(reply->readAll()).trimmed(), expectedCookieString);
5067 void tst_QNetworkReply::nestedEventLoops_slot()
5071 // 16 seconds: fluke times out in 15 seconds, which triggers a QTcpSocket error
5072 QTimer::singleShot(16000, &subloop, SLOT(quit()));
5075 QTestEventLoop::instance().exitLoop();
5078 void tst_QNetworkReply::nestedEventLoops()
5080 // Slightly fragile test, it may not be testing anything
5081 // This is certifying that we're not running into the same issue
5082 // that QHttp had (task 200432): the QTcpSocket connection is
5083 // closed by the remote end because of the kept-alive HTTP
5084 // connection timed out.
5086 // The exact time required for this to happen is not exactly
5087 // defined. Our server (Apache httpd) times out after 15
5088 // seconds. (see above)
5090 qDebug("Takes 16 seconds to run, please wait");
5092 QUrl url("http://" + QtNetworkSettings::serverName());
5093 QNetworkRequest request(url);
5094 QNetworkReplyPtr reply(manager.get(request));
5096 QSignalSpy finishedspy(reply.data(), SIGNAL(finished()));
5097 QSignalSpy errorspy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError)));
5099 connect(reply, SIGNAL(finished()), SLOT(nestedEventLoops_slot()));
5100 QTestEventLoop::instance().enterLoop(20);
5101 QVERIFY2(!QTestEventLoop::instance().timeout(), "Network timeout");
5103 QCOMPARE(finishedspy.count(), 1);
5104 QCOMPARE(errorspy.count(), 0);
5107 void tst_QNetworkReply::httpProxyCommands_data()
5109 QTest::addColumn<QUrl>("url");
5110 QTest::addColumn<QByteArray>("responseToSend");
5111 QTest::addColumn<QString>("expectedCommand");
5113 QTest::newRow("http")
5114 << QUrl("http://0.0.0.0:4443/http-request")
5115 << QByteArray("HTTP/1.0 200 OK\r\nProxy-Connection: close\r\nContent-Length: 1\r\n\r\n1")
5116 << "GET http://0.0.0.0:4443/http-request HTTP/1.";
5118 QTest::newRow("https")
5119 << QUrl("https://0.0.0.0:4443/https-request")
5120 << QByteArray("HTTP/1.0 200 Connection Established\r\n\r\n")
5121 << "CONNECT 0.0.0.0:4443 HTTP/1.";
5125 void tst_QNetworkReply::httpProxyCommands()
5128 QFETCH(QByteArray, responseToSend);
5129 QFETCH(QString, expectedCommand);
5131 MiniHttpServer proxyServer(responseToSend);
5132 QNetworkProxy proxy(QNetworkProxy::HttpProxy, "127.0.0.1", proxyServer.serverPort());
5134 manager.setProxy(proxy);
5135 QNetworkRequest request(url);
5136 request.setRawHeader("User-Agent", "QNetworkReplyAutoTest/1.0");
5137 QNetworkReplyPtr reply(manager.get(request));
5138 //clearing the proxy here causes the test to fail.
5139 //the proxy isn't used until after the bearer has been started
5140 //which is correct in general, because system proxy isn't known until that time.
5141 //removing this line is safe, as the proxy is also reset by the cleanup() function
5142 //manager.setProxy(QNetworkProxy());
5144 // wait for the finished signal
5145 QVERIFY(waitForFinish(reply) != Timeout);
5147 //qDebug() << reply->error() << reply->errorString();
5148 //qDebug() << proxyServer.receivedData;
5150 // we don't really care if the request succeeded
5151 // especially since it won't succeed in the HTTPS case
5152 // so just check that the command was correct
5154 QString receivedHeader = proxyServer.receivedData.left(expectedCommand.length());
5155 QCOMPARE(receivedHeader, expectedCommand);
5157 //QTBUG-17223 - make sure the user agent from the request is sent to proxy server even for CONNECT
5158 int uapos = proxyServer.receivedData.indexOf("User-Agent");
5159 int uaend = proxyServer.receivedData.indexOf("\r\n", uapos);
5160 QByteArray uaheader = proxyServer.receivedData.mid(uapos, uaend - uapos);
5161 QCOMPARE(uaheader, QByteArray("User-Agent: QNetworkReplyAutoTest/1.0"));
5164 class ProxyChangeHelper : public QObject {
5167 ProxyChangeHelper() : QObject(), signalCount(0) {};
5169 void finishedSlot() {
5171 if (signalCount == 2)
5172 QMetaObject::invokeMethod(&QTestEventLoop::instance(), "exitLoop", Qt::QueuedConnection);
5178 void tst_QNetworkReply::httpProxyCommandsSynchronous_data()
5180 httpProxyCommands_data();
5183 struct QThreadCleanup
5185 static inline void cleanup(QThread *thread)
5188 if (thread->wait(3000))
5191 qWarning("thread hung, leaking memory so test can finish");
5195 struct QDeleteLaterCleanup
5197 static inline void cleanup(QObject *o)
5203 void tst_QNetworkReply::httpProxyCommandsSynchronous()
5206 QFETCH(QByteArray, responseToSend);
5207 QFETCH(QString, expectedCommand);
5209 // when using synchronous commands, we need a different event loop for
5210 // the server thread, because the client is never returning to the
5212 QScopedPointer<QThread, QThreadCleanup> serverThread(new QThread);
5213 QScopedPointer<MiniHttpServer, QDeleteLaterCleanup> proxyServer(new MiniHttpServer(responseToSend, false, serverThread.data()));
5214 QNetworkProxy proxy(QNetworkProxy::HttpProxy, "127.0.0.1", proxyServer->serverPort());
5216 manager.setProxy(proxy);
5217 QNetworkRequest request(url);
5219 // send synchronous request
5220 request.setAttribute(
5221 QNetworkRequest::SynchronousRequestAttribute,
5224 QNetworkReplyPtr reply(manager.get(request));
5225 QVERIFY(reply->isFinished()); // synchronous
5226 manager.setProxy(QNetworkProxy());
5228 //qDebug() << reply->error() << reply->errorString();
5230 // we don't really care if the request succeeded
5231 // especially since it won't succeed in the HTTPS case
5232 // so just check that the command was correct
5234 QString receivedHeader = proxyServer->receivedData.left(expectedCommand.length());
5235 QCOMPARE(receivedHeader, expectedCommand);
5238 void tst_QNetworkReply::proxyChange()
5240 ProxyChangeHelper helper;
5241 MiniHttpServer proxyServer(
5242 "HTTP/1.0 200 OK\r\nProxy-Connection: keep-alive\r\n"
5243 "Content-Length: 1\r\n\r\n1");
5244 QNetworkProxy dummyProxy(QNetworkProxy::HttpProxy, "127.0.0.1", proxyServer.serverPort());
5245 QNetworkRequest req(QUrl("http://" + QtNetworkSettings::serverName()));
5246 proxyServer.doClose = false;
5248 manager.setProxy(dummyProxy);
5249 QNetworkReplyPtr reply1(manager.get(req));
5250 connect(reply1, SIGNAL(finished()), &helper, SLOT(finishedSlot()));
5252 manager.setProxy(QNetworkProxy());
5253 QNetworkReplyPtr reply2(manager.get(req));
5254 connect(reply2, SIGNAL(finished()), &helper, SLOT(finishedSlot()));
5256 QTestEventLoop::instance().enterLoop(20);
5257 QVERIFY(!QTestEventLoop::instance().timeout());
5259 // verify that the replies succeeded
5260 QCOMPARE(reply1->error(), QNetworkReply::NoError);
5261 QCOMPARE(reply1->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
5262 QVERIFY(reply1->size() == 1);
5264 QCOMPARE(reply2->error(), QNetworkReply::NoError);
5265 QCOMPARE(reply2->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
5266 QVERIFY(reply2->size() > 1);
5268 // now try again and get an error
5269 // this verifies that we reuse the already-open connection
5271 proxyServer.doClose = true;
5272 proxyServer.dataToTransmit =
5273 "HTTP/1.0 403 Forbidden\r\nProxy-Connection: close\r\n"
5274 "Content-Length: 1\r\n\r\n1";
5276 manager.setProxy(dummyProxy);
5277 QNetworkReplyPtr reply3(manager.get(req));
5279 QVERIFY(waitForFinish(reply3) == Failure);
5281 QVERIFY(int(reply3->error()) > 0);
5284 void tst_QNetworkReply::authorizationError_data()
5287 QTest::addColumn<QString>("url");
5288 QTest::addColumn<int>("errorSignalCount");
5289 QTest::addColumn<int>("finishedSignalCount");
5290 QTest::addColumn<int>("error");
5291 QTest::addColumn<int>("httpStatusCode");
5292 QTest::addColumn<QString>("httpBody");
5294 QTest::newRow("unknown-authorization-method") << "http://" + QtNetworkSettings::serverName() +
5295 "/qtest/cgi-bin/http-unknown-authentication-method.cgi?401-authorization-required" << 1 << 1
5296 << int(QNetworkReply::AuthenticationRequiredError) << 401 << "authorization required";
5297 QTest::newRow("unknown-proxy-authorization-method") << "http://" + QtNetworkSettings::serverName() +
5298 "/qtest/cgi-bin/http-unknown-authentication-method.cgi?407-proxy-authorization-required" << 1 << 1
5299 << int(QNetworkReply::ProxyAuthenticationRequiredError) << 407
5300 << "authorization required";
5303 void tst_QNetworkReply::authorizationError()
5305 QFETCH(QString, url);
5306 QNetworkRequest request(url);
5307 QNetworkReplyPtr reply(manager.get(request));
5309 QCOMPARE(reply->error(), QNetworkReply::NoError);
5311 QSignalSpy errorSpy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError)));
5312 QSignalSpy finishedSpy(reply.data(), SIGNAL(finished()));
5313 // now run the request:
5314 QVERIFY(waitForFinish(reply) == Failure);
5316 QFETCH(int, errorSignalCount);
5317 QCOMPARE(errorSpy.count(), errorSignalCount);
5318 QFETCH(int, finishedSignalCount);
5319 QCOMPARE(finishedSpy.count(), finishedSignalCount);
5321 QCOMPARE(reply->error(), QNetworkReply::NetworkError(error));
5323 QFETCH(int, httpStatusCode);
5324 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), httpStatusCode);
5326 QFETCH(QString, httpBody);
5327 QCOMPARE(qint64(reply->size()), qint64(httpBody.size()));
5328 QCOMPARE(QString(reply->readAll()), httpBody);
5331 void tst_QNetworkReply::httpConnectionCount()
5334 QVERIFY(server.listen());
5335 QCoreApplication::instance()->processEvents();
5337 for (int i = 0; i < 10; i++) {
5338 QNetworkRequest request (QUrl("http://127.0.0.1:" + QString::number(server.serverPort()) + "/" + QString::number(i)));
5339 QNetworkReply* reply = manager.get(request);
5340 reply->setParent(&server);
5343 int pendingConnectionCount = 0;
5347 while(pendingConnectionCount <= 20) {
5348 QTestEventLoop::instance().enterLoop(1);
5349 QTcpSocket *socket = server.nextPendingConnection();
5350 while (socket != 0) {
5351 pendingConnectionCount++;
5352 socket->setParent(&server);
5353 socket = server.nextPendingConnection();
5356 // at max. wait 10 sec
5357 if (time.elapsed() > 10000)
5361 QCOMPARE(pendingConnectionCount, 6);
5364 void tst_QNetworkReply::httpReUsingConnectionSequential_data()
5366 QTest::addColumn<bool>("doDeleteLater");
5367 QTest::newRow("deleteLater") << true;
5368 QTest::newRow("noDeleteLater") << false;
5371 void tst_QNetworkReply::httpReUsingConnectionSequential()
5373 QFETCH(bool, doDeleteLater);
5375 QByteArray response("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
5376 MiniHttpServer server(response);
5377 server.multiple = true;
5378 server.doClose = false;
5381 url.setScheme("http");
5382 url.setPort(server.serverPort());
5383 url.setHost("127.0.0.1");
5385 QNetworkReply* reply1 = manager.get(QNetworkRequest(url));
5386 connect(reply1, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
5387 QTestEventLoop::instance().enterLoop(2);
5388 QVERIFY(!QTestEventLoop::instance().timeout());
5389 QVERIFY(!reply1->error());
5390 int reply1port = server.client->peerPort();
5393 reply1->deleteLater();
5395 // finished received, send the next one
5396 QNetworkReply*reply2 = manager.get(QNetworkRequest(url));
5397 connect(reply2, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
5398 QTestEventLoop::instance().enterLoop(2);
5399 QVERIFY(!QTestEventLoop::instance().timeout());
5400 QVERIFY(!reply2->error());
5401 int reply2port = server.client->peerPort(); // should still be the same object
5403 QVERIFY(reply1port > 0);
5404 QCOMPARE(server.totalConnections, 1);
5405 QCOMPARE(reply2port, reply1port);
5408 reply1->deleteLater(); // only do it if it was not done earlier
5409 reply2->deleteLater();
5412 class HttpReUsingConnectionFromFinishedSlot : public QObject {
5415 QNetworkReply* reply1;
5416 QNetworkReply* reply2;
5418 QNetworkAccessManager manager;
5420 void finishedSlot() {
5421 QVERIFY(!reply1->error());
5423 QFETCH(bool, doDeleteLater);
5424 if (doDeleteLater) {
5425 reply1->deleteLater();
5429 // kick off 2nd request and exit the loop when it is done
5430 reply2 = manager.get(QNetworkRequest(url));
5431 reply2->setParent(this);
5432 connect(reply2, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
5436 void tst_QNetworkReply::httpReUsingConnectionFromFinishedSlot_data()
5438 httpReUsingConnectionSequential_data();
5441 void tst_QNetworkReply::httpReUsingConnectionFromFinishedSlot()
5443 QByteArray response("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
5444 MiniHttpServer server(response);
5445 server.multiple = true;
5446 server.doClose = false;
5448 HttpReUsingConnectionFromFinishedSlot helper;
5451 helper.url.setScheme("http");
5452 helper.url.setPort(server.serverPort());
5453 helper.url.setHost("127.0.0.1");
5456 helper.reply1 = helper.manager.get(QNetworkRequest(helper.url));
5457 helper.reply1->setParent(&helper);
5458 connect(helper.reply1, SIGNAL(finished()), &helper, SLOT(finishedSlot()));
5459 QTestEventLoop::instance().enterLoop(4);
5460 QVERIFY(!QTestEventLoop::instance().timeout());
5462 QVERIFY(helper.reply2);
5463 QVERIFY(!helper.reply2->error());
5465 QCOMPARE(server.totalConnections, 1);
5468 class HttpRecursiveCreationHelper : public QObject {
5472 HttpRecursiveCreationHelper():
5474 requestsStartedCount_finished(0),
5475 requestsStartedCount_readyRead(0),
5476 requestsFinishedCount(0)
5479 QNetworkAccessManager manager;
5480 int requestsStartedCount_finished;
5481 int requestsStartedCount_readyRead;
5482 int requestsFinishedCount;
5484 void finishedSlot() {
5485 requestsFinishedCount++;
5487 QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
5488 QVERIFY(!reply->error());
5489 QVERIFY(reply->bytesAvailable() == 27906);
5491 if (requestsFinishedCount == 60) {
5492 QTestEventLoop::instance().exitLoop();
5496 if (requestsStartedCount_finished < 30) {
5498 requestsStartedCount_finished++;
5501 reply->deleteLater();
5503 void readyReadSlot() {
5504 QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
5505 QVERIFY(!reply->error());
5507 if (requestsStartedCount_readyRead < 30 && reply->bytesAvailable() > 27906/2) {
5509 requestsStartedCount_readyRead++;
5513 QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/fluke.gif";
5514 QNetworkRequest request(url);
5515 QNetworkReply *reply = manager.get(request);
5516 reply->setParent(this);
5517 connect(reply, SIGNAL(finished()), this, SLOT(finishedSlot()));
5518 connect(reply, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
5522 void tst_QNetworkReply::httpRecursiveCreation()
5524 // this test checks if creation of new requests to the same host properly works
5525 // from readyRead() and finished() signals
5526 HttpRecursiveCreationHelper helper;
5528 QTestEventLoop::instance().enterLoop(30);
5529 QVERIFY(!QTestEventLoop::instance().timeout());
5533 void tst_QNetworkReply::ignoreSslErrorsList_data()
5535 QTest::addColumn<QString>("url");
5536 QTest::addColumn<QList<QSslError> >("expectedSslErrors");
5537 QTest::addColumn<QNetworkReply::NetworkError>("expectedNetworkError");
5539 QList<QSslError> expectedSslErrors;
5540 QList<QSslCertificate> certs = QSslCertificate::fromPath(testDataDir + "/certs/qt-test-server-cacert.pem");
5541 QSslError rightError(QSslError::SelfSignedCertificate, certs.at(0));
5542 QSslError wrongError(QSslError::SelfSignedCertificate);
5544 QTest::newRow("SSL-failure-empty-list") << "https://" + QtNetworkSettings::serverName() + "/index.html" << expectedSslErrors << QNetworkReply::SslHandshakeFailedError;
5545 expectedSslErrors.append(wrongError);
5546 QTest::newRow("SSL-failure-wrong-error") << "https://" + QtNetworkSettings::serverName() + "/index.html" << expectedSslErrors << QNetworkReply::SslHandshakeFailedError;
5547 expectedSslErrors.append(rightError);
5548 QTest::newRow("allErrorsInExpectedList1") << "https://" + QtNetworkSettings::serverName() + "/index.html" << expectedSslErrors << QNetworkReply::NoError;
5549 expectedSslErrors.removeAll(wrongError);
5550 QTest::newRow("allErrorsInExpectedList2") << "https://" + QtNetworkSettings::serverName() + "/index.html" << expectedSslErrors << QNetworkReply::NoError;
5551 expectedSslErrors.removeAll(rightError);
5552 QTest::newRow("SSL-failure-empty-list-again") << "https://" + QtNetworkSettings::serverName() + "/index.html" << expectedSslErrors << QNetworkReply::SslHandshakeFailedError;
5555 void tst_QNetworkReply::ignoreSslErrorsList()
5557 QFETCH(QString, url);
5558 QNetworkRequest request(url);
5559 QNetworkReplyPtr reply(manager.get(request));
5561 QFETCH(QList<QSslError>, expectedSslErrors);
5562 reply->ignoreSslErrors(expectedSslErrors);
5564 QVERIFY(waitForFinish(reply) != Timeout);
5566 QFETCH(QNetworkReply::NetworkError, expectedNetworkError);
5567 QCOMPARE(reply->error(), expectedNetworkError);
5570 void tst_QNetworkReply::ignoreSslErrorsListWithSlot_data()
5572 ignoreSslErrorsList_data();
5575 // this is not a test, just a slot called in the test below
5576 void tst_QNetworkReply::ignoreSslErrorListSlot(QNetworkReply *reply, const QList<QSslError> &)
5578 reply->ignoreSslErrors(storedExpectedSslErrors);
5581 // do the same as in ignoreSslErrorsList, but ignore the errors in the slot
5582 void tst_QNetworkReply::ignoreSslErrorsListWithSlot()
5584 QFETCH(QString, url);
5585 QNetworkRequest request(url);
5586 QNetworkReplyPtr reply(manager.get(request));
5588 QFETCH(QList<QSslError>, expectedSslErrors);
5589 // store the errors to ignore them later in the slot connected below
5590 storedExpectedSslErrors = expectedSslErrors;
5591 connect(&manager, SIGNAL(sslErrors(QNetworkReply *, const QList<QSslError> &)),
5592 this, SLOT(ignoreSslErrorListSlot(QNetworkReply *, const QList<QSslError> &)));
5595 QVERIFY(waitForFinish(reply) != Timeout);
5597 QFETCH(QNetworkReply::NetworkError, expectedNetworkError);
5598 QCOMPARE(reply->error(), expectedNetworkError);
5601 void tst_QNetworkReply::sslConfiguration_data()
5603 QTest::addColumn<QSslConfiguration>("configuration");
5604 QTest::addColumn<bool>("works");
5606 QTest::newRow("empty") << QSslConfiguration() << false;
5607 QSslConfiguration conf = QSslConfiguration::defaultConfiguration();
5608 QTest::newRow("default") << conf << false; // does not contain test server cert
5609 QList<QSslCertificate> testServerCert = QSslCertificate::fromPath(testDataDir + "/certs/qt-test-server-cacert.pem");
5610 conf.setCaCertificates(testServerCert);
5611 QTest::newRow("set-root-cert") << conf << true;
5612 conf.setProtocol(QSsl::SecureProtocols);
5613 QTest::newRow("secure") << conf << true;
5616 void tst_QNetworkReply::sslConfiguration()
5618 QNetworkRequest request(QUrl("https://" + QtNetworkSettings::serverName() + "/index.html"));
5619 QFETCH(QSslConfiguration, configuration);
5620 request.setSslConfiguration(configuration);
5621 QNetworkReplyPtr reply(manager.get(request));
5623 QVERIFY(waitForFinish(reply) != Timeout);
5625 QFETCH(bool, works);
5626 QNetworkReply::NetworkError expectedError = works ? QNetworkReply::NoError : QNetworkReply::SslHandshakeFailedError;
5627 QCOMPARE(reply->error(), expectedError);
5632 void tst_QNetworkReply::getAndThenDeleteObject_data()
5634 QTest::addColumn<bool>("replyFirst");
5636 QTest::newRow("delete-reply-first") << true;
5637 QTest::newRow("delete-qnam-first") << false;
5640 void tst_QNetworkReply::getAndThenDeleteObject()
5642 QSKIP("unstable test - reply may be finished too early");
5643 // yes, this will leak if the testcase fails. I don't care. It must not fail then :P
5644 QNetworkAccessManager *manager = new QNetworkAccessManager();
5645 QNetworkRequest request("http://" + QtNetworkSettings::serverName() + "/qtest/bigfile");
5646 QNetworkReply *reply = manager->get(request);
5647 reply->setReadBufferSize(1);
5648 reply->setParent((QObject*)0); // must be 0 because else it is the manager
5653 QCoreApplication::instance()->processEvents();
5654 if (reply->bytesAvailable())
5656 if (stopWatch.elapsed() >= 30000)
5660 QVERIFY(reply->bytesAvailable());
5661 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
5662 QVERIFY(!reply->isFinished()); // must not be finished
5664 QFETCH(bool, replyFirst);
5675 // see https://bugs.webkit.org/show_bug.cgi?id=38935
5676 void tst_QNetworkReply::symbianOpenCDataUrlCrash()
5678 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==");
5679 QUrl url = QUrl::fromEncoded(requestUrl.toLatin1());
5680 QNetworkRequest req(url);
5681 QNetworkReplyPtr reply;
5683 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, req, reply));
5685 QCOMPARE(reply->url(), url);
5686 QCOMPARE(reply->error(), QNetworkReply::NoError);
5688 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), qint64(598));
5691 void tst_QNetworkReply::getFromHttpIntoBuffer_data()
5693 QTest::addColumn<QUrl>("url");
5695 QTest::newRow("rfc-internal") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt");
5698 // Please note that the whole "zero copy" download buffer API is private right now. Do not use it.
5699 void tst_QNetworkReply::getFromHttpIntoBuffer()
5702 QNetworkRequest request(url);
5703 request.setAttribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute, 1024*128); // 128 kB
5705 QNetworkAccessManager manager;
5706 QNetworkReply *reply = manager.get(request);
5707 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
5708 QTestEventLoop::instance().enterLoop(10);
5709 QVERIFY(!QTestEventLoop::instance().timeout());
5710 QVERIFY(reply->isFinished());
5712 QFile reference(testDataDir + "/rfc3252.txt");
5713 QVERIFY(reference.open(QIODevice::ReadOnly));
5715 QCOMPARE(reference.bytesAvailable(), reply->bytesAvailable());
5716 QCOMPARE(reference.size(), reply->size());
5718 // Compare the memory buffer
5719 QVariant downloadBufferAttribute = reply->attribute(QNetworkRequest::DownloadBufferAttribute);
5720 QVERIFY(downloadBufferAttribute.isValid());
5721 QSharedPointer<char> sharedPointer = downloadBufferAttribute.value<QSharedPointer<char> >();
5722 bool memoryComparison =
5723 (0 == memcmp(static_cast<void*>(reference.readAll().data()),
5724 sharedPointer.data(), reference.size()));
5725 QVERIFY(memoryComparison);
5727 // Make sure the normal reading works
5729 QCOMPARE(reply->read(42), reference.read(42));
5730 QCOMPARE(reply->getChar(0), reference.getChar(0));
5731 QCOMPARE(reply->peek(23), reference.peek(23));
5732 QCOMPARE(reply->readLine(), reference.readLine());
5733 QCOMPARE(reference.bytesAvailable(), reply->bytesAvailable());
5734 QCOMPARE(reply->readAll(), reference.readAll());
5735 QVERIFY(reply->atEnd());
5738 // FIXME we really need to consolidate all those server implementations
5739 class GetFromHttpIntoBuffer2Server : QObject {
5745 bool serverSendsContentLength;
5746 bool chunkedEncoding;
5749 GetFromHttpIntoBuffer2Server (qint64 ds, bool sscl, bool ce) : dataSize(ds), dataSent(0),
5750 client(0), serverSendsContentLength(sscl), chunkedEncoding(ce) {
5752 connect(&server, SIGNAL(newConnection()), this, SLOT(newConnectionSlot()));
5756 return server.serverPort();
5761 void newConnectionSlot() {
5762 client = server.nextPendingConnection();
5763 client->setParent(this);
5764 connect(client, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
5765 connect(client, SIGNAL(bytesWritten(qint64)), this, SLOT(bytesWrittenSlot(qint64)));
5768 void readyReadSlot() {
5770 client->write("HTTP/1.0 200 OK\n");
5771 if (serverSendsContentLength)
5772 client->write(QString("Content-Length: " + QString::number(dataSize) + "\n").toAscii());
5773 if (chunkedEncoding)
5774 client->write(QString("Transfer-Encoding: chunked\n").toAscii());
5775 client->write("Connection: close\n\n");
5778 void bytesWrittenSlot(qint64 amount) {
5780 if (dataSent == dataSize && client) {
5783 // chunked encoding: we have to send a last "empty" chunk
5784 if (chunkedEncoding)
5785 client->write(QString("0\r\n\r\n").toAscii());
5787 client->disconnectFromHost();
5794 if (client && client->bytesToWrite() < 100*1024 && dataSent < dataSize) {
5795 qint64 amount = qMin(qint64(16*1024), dataSize - dataSent);
5796 QByteArray data(amount, '@');
5798 if (chunkedEncoding) {
5799 client->write(QString(QString("%1").arg(amount,0,16).toUpper() + "\r\n").toAscii());
5800 client->write(data.constData(), amount);
5801 client->write(QString("\r\n").toAscii());
5803 client->write(data.constData(), amount);
5811 class GetFromHttpIntoBuffer2Client : QObject {
5814 bool useDownloadBuffer;
5815 QNetworkReply *reply;
5817 QList<qint64> bytesAvailableList;
5819 GetFromHttpIntoBuffer2Client (QNetworkReply *reply, bool useDownloadBuffer, qint64 uploadSize)
5820 : useDownloadBuffer(useDownloadBuffer), reply(reply), uploadSize(uploadSize)
5822 connect(reply, SIGNAL(metaDataChanged()), this, SLOT(metaDataChangedSlot()));
5823 connect(reply, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
5824 connect(reply, SIGNAL(finished()), this, SLOT(finishedSlot()));
5828 void metaDataChangedSlot() {
5829 if (useDownloadBuffer) {
5830 QSharedPointer<char> sharedPointer = qvariant_cast<QSharedPointer<char> >(reply->attribute(QNetworkRequest::DownloadBufferAttribute));
5831 QVERIFY(!sharedPointer.isNull()); // It will be 0 if it failed
5834 // metaDataChanged needs to come before everything else
5835 QVERIFY(bytesAvailableList.isEmpty());
5838 void readyReadSlot() {
5839 QVERIFY(!reply->isFinished());
5841 qint64 bytesAvailable = reply->bytesAvailable();
5843 // bytesAvailable must never be 0
5844 QVERIFY(bytesAvailable != 0);
5846 if (bytesAvailableList.length() < 5) {
5847 // We assume that the first few times the bytes available must be less than the complete size, e.g.
5848 // the bytesAvailable() function works correctly in case of a downloadBuffer.
5849 QVERIFY(bytesAvailable < uploadSize);
5851 if (!bytesAvailableList.isEmpty()) {
5852 // Also check that the same bytesAvailable is not coming twice in a row
5853 QVERIFY(bytesAvailableList.last() != bytesAvailable);
5856 bytesAvailableList.append(bytesAvailable);
5857 // Add bytesAvailable to a list an parse
5860 void finishedSlot() {
5861 // We should have already received all readyRead
5862 QVERIFY(!bytesAvailableList.isEmpty());
5863 QVERIFY(bytesAvailableList.last() == uploadSize);
5867 void tst_QNetworkReply::getFromHttpIntoBuffer2_data()
5869 QTest::addColumn<bool>("useDownloadBuffer");
5871 QTest::newRow("use-download-buffer") << true;
5872 QTest::newRow("do-not-use-download-buffer") << false;
5875 // This test checks mostly that signal emissions are in correct order
5876 // Please note that the whole "zero copy" download buffer API is private right now. Do not use it.
5877 void tst_QNetworkReply::getFromHttpIntoBuffer2()
5879 QFETCH(bool, useDownloadBuffer);
5881 // On my Linux Desktop the results are already visible with 128 kB, however we use this to have good results.
5882 #if defined(Q_OS_WINCE_WM)
5883 // Show some mercy to non-desktop platform/s
5884 enum {UploadSize = 4*1024*1024}; // 4 MB
5886 enum {UploadSize = 32*1024*1024}; // 32 MB
5889 GetFromHttpIntoBuffer2Server server(UploadSize, true, false);
5891 QNetworkRequest request(QUrl("http://127.0.0.1:" + QString::number(server.serverPort()) + "/?bare=1"));
5892 if (useDownloadBuffer)
5893 request.setAttribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute, 1024*1024*128); // 128 MB is max allowed
5895 QNetworkAccessManager manager;
5896 QNetworkReplyPtr reply(manager.get(request));
5898 GetFromHttpIntoBuffer2Client client(reply.data(), useDownloadBuffer, UploadSize);
5900 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
5901 QTestEventLoop::instance().enterLoop(40);
5902 QCOMPARE(reply->error(), QNetworkReply::NoError);
5903 QVERIFY(!QTestEventLoop::instance().timeout());
5907 void tst_QNetworkReply::getFromHttpIntoBufferCanReadLine()
5909 QString header("HTTP/1.0 200 OK\r\nContent-Length: 7\r\n\r\nxxx\nxxx");
5911 MiniHttpServer server(header.toAscii());
5912 server.doClose = true;
5914 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
5915 request.setAttribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute, 1024*1024*128); // 128 MB is max allowed
5916 QNetworkReplyPtr reply(manager.get(request));
5918 QVERIFY(waitForFinish(reply) == Success);
5920 QCOMPARE(reply->error(), QNetworkReply::NoError);
5921 QVERIFY(reply->canReadLine());
5922 QCOMPARE(reply->read(1), QByteArray("x"));
5923 QVERIFY(reply->canReadLine());
5924 QCOMPARE(reply->read(3), QByteArray("xx\n"));
5925 QVERIFY(!reply->canReadLine());
5926 QCOMPARE(reply->readAll(), QByteArray("xxx"));
5927 QVERIFY(!reply->canReadLine());
5932 // Is handled somewhere else too, introduced this special test to have it more accessible
5933 void tst_QNetworkReply::ioGetFromHttpWithoutContentLength()
5935 QByteArray dataToSend("HTTP/1.0 200 OK\r\n\r\nHALLO! 123!");
5936 MiniHttpServer server(dataToSend);
5937 server.doClose = true;
5939 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
5940 QNetworkReplyPtr reply(manager.get(request));
5942 QVERIFY(waitForFinish(reply) == Success);
5944 QCOMPARE(reply->url(), request.url());
5945 QVERIFY(reply->isFinished());
5946 QVERIFY(reply->error() == QNetworkReply::NoError);
5949 // Is handled somewhere else too, introduced this special test to have it more accessible
5950 void tst_QNetworkReply::ioGetFromHttpBrokenChunkedEncoding()
5952 // This is wrong chunked encoding because of the X. What actually has to follow is \r\n
5953 // and then the declaration of the final 0 chunk
5954 QByteArray dataToSend("HTTP/1.0 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n3\r\nABCX");
5955 MiniHttpServer server(dataToSend);
5956 server.doClose = false; // FIXME
5958 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
5959 QNetworkReplyPtr reply(manager.get(request));
5961 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
5962 QTestEventLoop::instance().enterLoop(10);
5964 QEXPECT_FAIL(0, "We should close the socket and not just do nothing", Continue);
5965 QVERIFY(!QTestEventLoop::instance().timeout());
5966 QEXPECT_FAIL(0, "We should close the socket and not just do nothing", Continue);
5967 QVERIFY(reply->isFinished());
5968 QCOMPARE(reply->error(), QNetworkReply::NoError);
5972 // Prepare a gzip that has one chunk that expands to the size mentioned in the bugreport.
5973 // Then have a custom HTTP server that waits after this chunk so the returning gets
5975 void tst_QNetworkReply::qtbug12908compressedHttpReply()
5977 QString header("HTTP/1.0 200 OK\r\nContent-Encoding: gzip\r\nContent-Length: 63\r\n\r\n");
5979 // dd if=/dev/zero of=qtbug-12908 bs=16384 count=1 && gzip qtbug-12908 && base64 -w 0 qtbug-12908.gz
5980 QString encodedFile("H4sICDdDaUwAA3F0YnVnLTEyOTA4AO3BMQEAAADCoPVPbQwfoAAAAAAAAAAAAAAAAAAAAIC3AYbSVKsAQAAA");
5981 QByteArray decodedFile = QByteArray::fromBase64(encodedFile.toAscii());
5982 QCOMPARE(decodedFile.size(), 63);
5984 MiniHttpServer server(header.toAscii() + decodedFile);
5985 server.doClose = true;
5987 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
5988 QNetworkReplyPtr reply(manager.get(request));
5990 QVERIFY(waitForFinish(reply) == Success);
5992 QCOMPARE(reply->error(), QNetworkReply::NoError);
5993 QCOMPARE(reply->size(), qint64(16384));
5994 QCOMPARE(reply->readAll(), QByteArray(16384, '\0'));
5997 void tst_QNetworkReply::compressedHttpReplyBrokenGzip()
5999 QString header("HTTP/1.0 200 OK\r\nContent-Encoding: gzip\r\nContent-Length: 63\r\n\r\n");
6001 // dd if=/dev/zero of=qtbug-12908 bs=16384 count=1 && gzip qtbug-12908 && base64 -w 0 qtbug-12908.gz
6002 // Then change "BMQ" to "BMX"
6003 QString encodedFile("H4sICDdDaUwAA3F0YnVnLTEyOTA4AO3BMXEAAADCoPVPbQwfoAAAAAAAAAAAAAAAAAAAAIC3AYbSVKsAQAAA");
6004 QByteArray decodedFile = QByteArray::fromBase64(encodedFile.toAscii());
6005 QCOMPARE(decodedFile.size(), 63);
6007 MiniHttpServer server(header.toAscii() + decodedFile);
6008 server.doClose = true;
6010 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
6011 QNetworkReplyPtr reply(manager.get(request));
6013 QVERIFY(waitForFinish(reply) == Failure);
6015 QCOMPARE(reply->error(), QNetworkReply::ProtocolFailure);
6018 // TODO add similar test for FTP
6019 void tst_QNetworkReply::getFromUnreachableIp()
6021 QNetworkAccessManager manager;
6023 QNetworkRequest request(QUrl("http://255.255.255.255/42/23/narf/narf/narf"));
6024 QNetworkReplyPtr reply(manager.get(request));
6026 QVERIFY(waitForFinish(reply) == Failure);
6028 QVERIFY(reply->error() != QNetworkReply::NoError);
6031 void tst_QNetworkReply::qtbug4121unknownAuthentication()
6033 MiniHttpServer server(QByteArray("HTTP/1.1 401 bla\r\nWWW-Authenticate: crap\r\nContent-Length: 0\r\n\r\n"));
6034 server.doClose = false;
6036 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
6037 QNetworkAccessManager manager;
6038 QNetworkReplyPtr reply(manager.get(request));
6040 QSignalSpy authSpy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
6041 QSignalSpy finishedSpy(&manager, SIGNAL(finished(QNetworkReply*)));
6042 QSignalSpy errorSpy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError)));
6044 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6045 QTestEventLoop::instance().enterLoop(10);
6046 QVERIFY(!QTestEventLoop::instance().timeout());
6048 QCOMPARE(authSpy.count(), 0);
6049 QCOMPARE(finishedSpy.count(), 1);
6050 QCOMPARE(errorSpy.count(), 1);
6052 QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError);
6055 void tst_QNetworkReply::authenticationCacheAfterCancel_data()
6057 QTest::addColumn<QNetworkProxy>("proxy");
6058 QTest::addColumn<bool>("proxyAuth");
6059 QTest::addColumn<QUrl>("url");
6060 for (int i = 0; i < proxies.count(); ++i) {
6061 QTest::newRow("http" + proxies.at(i).tag) << proxies.at(i).proxy << proxies.at(i).requiresAuthentication << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt");
6063 QTest::newRow("https" + proxies.at(i).tag) << proxies.at(i).proxy << proxies.at(i).requiresAuthentication << QUrl("https://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt");
6068 class AuthenticationCacheHelper : public QObject
6072 AuthenticationCacheHelper()
6075 void proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *auth)
6077 if (!proxyPassword.isNull()) {
6078 auth->setUser(proxyUserName);
6079 auth->setPassword(proxyPassword);
6080 //clear credentials, if they are asked again, they were bad
6081 proxyUserName.clear();
6082 proxyPassword.clear();
6085 void authenticationRequired(QNetworkReply*,QAuthenticator *auth)
6087 if (!httpPassword.isNull()) {
6088 auth->setUser(httpUserName);
6089 auth->setPassword(httpPassword);
6090 //clear credentials, if they are asked again, they were bad
6091 httpUserName.clear();
6092 httpPassword.clear();
6096 QString httpUserName;
6097 QString httpPassword;
6098 QString proxyUserName;
6099 QString proxyPassword;
6102 /* Purpose of this test is to check credentials are cached correctly.
6103 - If user cancels authentication dialog (i.e. nothing is set to the QAuthenticator by the callback) then this is not cached
6104 - if user supplies a wrong password, then this is not cached
6105 - if user supplies a correct user/password combination then this is cached
6107 Test is checking both the proxyAuthenticationRequired and authenticationRequired signals.
6109 void tst_QNetworkReply::authenticationCacheAfterCancel()
6111 QFETCH(QNetworkProxy, proxy);
6112 QFETCH(bool, proxyAuth);
6114 QNetworkAccessManager manager;
6116 connect(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
6117 SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
6119 manager.setProxy(proxy);
6120 QSignalSpy authSpy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
6121 QSignalSpy proxyAuthSpy(&manager, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)));
6123 AuthenticationCacheHelper helper;
6124 connect(&manager, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)), &helper, SLOT(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)));
6125 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), &helper, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
6127 QNetworkRequest request(url);
6128 QNetworkReplyPtr reply;
6130 //should fail due to no credentials
6131 reply.reset(manager.get(request));
6132 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6133 QTestEventLoop::instance().enterLoop(10);
6134 QVERIFY(!QTestEventLoop::instance().timeout());
6136 QCOMPARE(reply->error(), QNetworkReply::ProxyAuthenticationRequiredError);
6137 QCOMPARE(authSpy.count(), 0);
6138 QCOMPARE(proxyAuthSpy.count(), 1);
6139 proxyAuthSpy.clear();
6141 //should fail due to bad credentials
6142 helper.proxyUserName = "qsockstest";
6143 helper.proxyPassword = "badpassword";
6144 reply.reset(manager.get(request));
6145 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6146 QTestEventLoop::instance().enterLoop(10);
6147 QVERIFY(!QTestEventLoop::instance().timeout());
6149 QEXPECT_FAIL("http+socksauth", "QTBUG-23136 - danted accepts bad authentication but blocks the connection", Continue);
6150 QEXPECT_FAIL("https+socksauth", "QTBUG-23136 - danted accepts bad authentication but blocks the connection", Continue);
6152 QCOMPARE(reply->error(), QNetworkReply::ProxyAuthenticationRequiredError);
6153 QCOMPARE(authSpy.count(), 0);
6154 QVERIFY(proxyAuthSpy.count() > 0);
6155 proxyAuthSpy.clear();
6157 //QTBUG-23136 workaround
6158 if (proxy.port() == 1081) {
6159 #ifdef QT_BUILD_INTERNAL
6160 QNetworkAccessManagerPrivate::clearCache(&manager);
6162 return; //XFAIL result above
6166 //next proxy auth should succeed, due to correct credentials
6167 helper.proxyUserName = "qsockstest";
6168 helper.proxyPassword = "password";
6171 //should fail due to no credentials
6172 reply.reset(manager.get(request));
6173 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6174 QTestEventLoop::instance().enterLoop(10);
6175 QVERIFY(!QTestEventLoop::instance().timeout());
6177 QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError);
6178 QVERIFY(authSpy.count() > 0);
6181 QVERIFY(proxyAuthSpy.count() > 0);
6182 proxyAuthSpy.clear();
6185 //should fail due to bad credentials
6186 helper.httpUserName = "baduser";
6187 helper.httpPassword = "badpassword";
6188 reply.reset(manager.get(request));
6189 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6190 QTestEventLoop::instance().enterLoop(10);
6191 QVERIFY(!QTestEventLoop::instance().timeout());
6193 QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError);
6194 QVERIFY(authSpy.count() > 0);
6197 //should be supplied from cache
6198 QCOMPARE(proxyAuthSpy.count(), 0);
6199 proxyAuthSpy.clear();
6202 //next auth should succeed, due to correct credentials
6203 helper.httpUserName = "httptest";
6204 helper.httpPassword = "httptest";
6206 reply.reset(manager.get(request));
6207 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6208 QTestEventLoop::instance().enterLoop(10);
6209 QVERIFY(!QTestEventLoop::instance().timeout());
6211 QCOMPARE(reply->error(), QNetworkReply::NoError);
6212 QVERIFY(authSpy.count() > 0);
6215 //should be supplied from cache
6216 QCOMPARE(proxyAuthSpy.count(), 0);
6217 proxyAuthSpy.clear();
6220 //next auth should use cached credentials
6221 reply.reset(manager.get(request));
6222 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6223 QTestEventLoop::instance().enterLoop(10);
6224 QVERIFY(!QTestEventLoop::instance().timeout());
6226 QCOMPARE(reply->error(), QNetworkReply::NoError);
6227 //should be supplied from cache
6228 QCOMPARE(authSpy.count(), 0);
6231 //should be supplied from cache
6232 QCOMPARE(proxyAuthSpy.count(), 0);
6233 proxyAuthSpy.clear();
6238 void tst_QNetworkReply::authenticationWithDifferentRealm()
6240 AuthenticationCacheHelper helper;
6241 QNetworkAccessManager manager;
6243 connect(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
6244 SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
6246 connect(&manager, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)), &helper, SLOT(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)));
6247 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), &helper, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
6249 helper.httpUserName = "httptest";
6250 helper.httpPassword = "httptest";
6252 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt"));
6253 QNetworkReply* reply = manager.get(request);
6254 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6255 QTestEventLoop::instance().enterLoop(10);
6256 QVERIFY(!QTestEventLoop::instance().timeout());
6257 QCOMPARE(reply->error(), QNetworkReply::NoError);
6259 helper.httpUserName = "httptest";
6260 helper.httpPassword = "httptest";
6262 request.setUrl(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/auth-digest/"));
6263 reply = manager.get(request);
6264 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6265 QTestEventLoop::instance().enterLoop(10);
6266 QVERIFY(!QTestEventLoop::instance().timeout());
6267 QCOMPARE(reply->error(), QNetworkReply::NoError);
6270 class QtBug13431Helper : public QObject {
6273 QNetworkReply* m_reply;
6276 void replyFinished(QNetworkReply*) {
6277 QTestEventLoop::instance().exitLoop();
6280 void onReadAndReschedule() {
6281 const qint64 bytesReceived = m_reply->bytesAvailable();
6282 if (bytesReceived && m_reply->readBufferSize()) {
6283 QByteArray data = m_reply->read(bytesReceived);
6285 const int millisecDelay = static_cast<int>(bytesReceived * 1000 / m_reply->readBufferSize());
6286 m_dlTimer.start(millisecDelay);
6290 m_dlTimer.start(200);
6295 void tst_QNetworkReply::qtbug13431replyThrottling()
6297 QtBug13431Helper helper;
6299 QNetworkAccessManager nam;
6300 connect(&nam, SIGNAL(finished(QNetworkReply*)), &helper, SLOT(replyFinished(QNetworkReply*)));
6302 // Download a bigger file
6303 QNetworkRequest netRequest(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/bigfile"));
6304 helper.m_reply = nam.get(netRequest);
6306 helper.m_reply->setReadBufferSize(36000);
6308 // Schedule a timer that tries to read
6310 connect(&helper.m_dlTimer, SIGNAL(timeout()), &helper, SLOT(onReadAndReschedule()));
6311 helper.m_dlTimer.setSingleShot(true);
6312 helper.m_dlTimer.start(0);
6314 QTestEventLoop::instance().enterLoop(30);
6315 QVERIFY(!QTestEventLoop::instance().timeout());
6316 QVERIFY(helper.m_reply->isFinished());
6317 QCOMPARE(helper.m_reply->error(), QNetworkReply::NoError);
6320 void tst_QNetworkReply::httpWithNoCredentialUsage()
6322 QNetworkAccessManager manager;
6324 QSignalSpy authSpy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
6325 QSignalSpy finishedSpy(&manager, SIGNAL(finished(QNetworkReply*)));
6327 // Get with credentials, to preload authentication cache
6329 QNetworkRequest request(QUrl("http://httptest:httptest@" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi"));
6330 QNetworkReplyPtr reply(manager.get(request));
6331 QVERIFY(waitForFinish(reply) == Success);
6332 // credentials in URL, so don't expect authentication signal
6333 QCOMPARE(authSpy.count(), 0);
6334 QCOMPARE(finishedSpy.count(), 1);
6335 finishedSpy.clear();
6338 // Get with cached credentials (normal usage)
6340 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi"));
6341 QNetworkReplyPtr reply(manager.get(request));
6342 QVERIFY(waitForFinish(reply) == Success);
6343 // credentials in cache, so don't expect authentication signal
6344 QCOMPARE(authSpy.count(), 0);
6345 QCOMPARE(finishedSpy.count(), 1);
6346 finishedSpy.clear();
6349 // Do not use cached credentials (webkit cross origin usage)
6351 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi"));
6352 request.setAttribute(QNetworkRequest::AuthenticationReuseAttribute, QNetworkRequest::Manual);
6353 QNetworkReplyPtr reply(manager.get(request));
6355 QSignalSpy errorSpy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError)));
6357 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6358 QTestEventLoop::instance().enterLoop(10);
6359 QVERIFY(!QTestEventLoop::instance().timeout());
6361 // We check if authenticationRequired was emitted, however we do not anything in it so it should be 401
6362 QCOMPARE(authSpy.count(), 1);
6363 QCOMPARE(finishedSpy.count(), 1);
6364 QCOMPARE(errorSpy.count(), 1);
6366 QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError);
6370 void tst_QNetworkReply::qtbug15311doubleContentLength()
6372 QByteArray response("HTTP/1.0 200 OK\r\nContent-Length: 3\r\nServer: bogus\r\nContent-Length: 3\r\n\r\nABC");
6373 MiniHttpServer server(response);
6374 server.doClose = true;
6376 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
6377 QNetworkReplyPtr reply(manager.get(request));
6379 QVERIFY(waitForFinish(reply) == Success);
6381 QVERIFY(reply->isFinished());
6382 QCOMPARE(reply->error(), QNetworkReply::NoError);
6383 QCOMPARE(reply->size(), qint64(3));
6384 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), qint64(3));
6385 QCOMPARE(reply->rawHeader("Content-length"), QByteArray("3, 3"));
6386 QCOMPARE(reply->readAll(), QByteArray("ABC"));
6389 void tst_QNetworkReply::qtbug18232gzipContentLengthZero()
6391 QByteArray response("HTTP/1.0 200 OK\r\nContent-Encoding: gzip\r\nContent-Length: 0\r\n\r\n");
6392 MiniHttpServer server(response);
6393 server.doClose = true;
6395 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
6396 QNetworkReplyPtr reply(manager.get(request));
6398 QVERIFY(waitForFinish(reply) == Success);
6400 QVERIFY(reply->isFinished());
6401 QCOMPARE(reply->error(), QNetworkReply::NoError);
6402 QCOMPARE(reply->size(), qint64(0));
6403 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), qint64(0));
6404 QCOMPARE(reply->readAll(), QByteArray());
6407 // Reproduced a crash in QHttpNetworkReplyPrivate::gunzipBodyPartiallyEnd
6408 // where zlib inflateEnd was called for uninitialized zlib stream
6409 void tst_QNetworkReply::qtbug22660gzipNoContentLengthEmptyContent()
6411 // Response with no Content-Length in header and empty content
6412 QByteArray response("HTTP/1.0 200 OK\r\nContent-Encoding: gzip\r\n\r\n");
6413 MiniHttpServer server(response);
6414 server.doClose = true;
6416 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
6417 QNetworkReplyPtr reply(manager.get(request));
6419 QVERIFY(waitForFinish(reply) == Success);
6421 QVERIFY(reply->isFinished());
6422 QCOMPARE(reply->error(), QNetworkReply::NoError);
6423 QCOMPARE(reply->size(), qint64(0));
6424 QVERIFY(!reply->header(QNetworkRequest::ContentLengthHeader).isValid());
6425 QCOMPARE(reply->readAll(), QByteArray());
6428 void tst_QNetworkReply::synchronousRequest_data()
6430 QTest::addColumn<QUrl>("url");
6431 QTest::addColumn<QString>("expected");
6432 QTest::addColumn<bool>("checkContentLength");
6433 QTest::addColumn<QString>("mimeType");
6435 // ### cache, auth, proxies
6437 QTest::newRow("http")
6438 << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt")
6439 << QString("file:" + testDataDir + "/rfc3252.txt")
6441 << QString("text/plain");
6443 QTest::newRow("http-gzip")
6444 << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/deflate/rfc3252.txt")
6445 << QString("file:" + testDataDir + "/rfc3252.txt")
6446 << false // don't check content length, because it's gzip encoded
6447 // ### we would need to enflate (un-deflate) the file content and compare the sizes
6448 << QString("text/plain");
6451 QTest::newRow("https")
6452 << QUrl("https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt")
6453 << QString("file:" + testDataDir + "/rfc3252.txt")
6455 << QString("text/plain");
6458 QTest::newRow("data")
6459 << QUrl(QString::fromLatin1("data:text/plain,hello world"))
6460 << QString("data:hello world")
6461 << true // check content length
6462 << QString("text/plain");
6464 QTest::newRow("simple-file")
6465 << QUrl::fromLocalFile(testDataDir + "/rfc3252.txt")
6466 << QString("file:" + testDataDir + "/rfc3252.txt")
6471 // FIXME add testcase for failing network etc
6472 void tst_QNetworkReply::synchronousRequest()
6475 QFETCH(QString, expected);
6476 QFETCH(bool, checkContentLength);
6477 QFETCH(QString, mimeType);
6479 QNetworkRequest request(url);
6482 // workaround for HTTPS requests: add self-signed server cert to list of CA certs,
6483 // since we cannot react to the sslErrors() signal
6484 // to fix this properly we would need to have an ignoreSslErrors() method in the
6485 // QNetworkRequest, see http://bugreports.qt-project.org/browse/QTBUG-14774
6486 if (url.scheme() == "https") {
6487 QSslConfiguration sslConf;
6488 QList<QSslCertificate> certs = QSslCertificate::fromPath(testDataDir + "/certs/qt-test-server-cacert.pem");
6489 sslConf.setCaCertificates(certs);
6490 request.setSslConfiguration(sslConf);
6494 request.setAttribute(
6495 QNetworkRequest::SynchronousRequestAttribute,
6498 QNetworkReplyPtr reply;
6499 QSignalSpy finishedSpy(&manager, SIGNAL(finished(QNetworkReply*)));
6500 QSignalSpy sslErrorsSpy(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)));
6501 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply, 0));
6502 QVERIFY(reply->isFinished());
6503 QCOMPARE(finishedSpy.count(), 0);
6504 QCOMPARE(sslErrorsSpy.count(), 0);
6506 QCOMPARE(reply->header(QNetworkRequest::ContentTypeHeader).toString(), mimeType);
6508 QByteArray expectedContent;
6510 if (expected.startsWith("file:")) {
6511 QString path = expected.mid(5);
6513 file.open(QIODevice::ReadOnly);
6514 expectedContent = file.readAll();
6515 } else if (expected.startsWith("data:")) {
6516 expectedContent = expected.mid(5).toUtf8();
6519 if (checkContentLength)
6520 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), qint64(expectedContent.size()));
6521 QCOMPARE(reply->readAll(), expectedContent);
6523 reply->deleteLater();
6527 void tst_QNetworkReply::synchronousRequestSslFailure()
6529 // test that SSL won't be accepted with self-signed certificate,
6530 // and that we do not emit the sslError signal (in the manager that is,
6531 // in the reply we don't care)
6533 QUrl url("https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt");
6534 QNetworkRequest request(url);
6535 request.setAttribute(
6536 QNetworkRequest::SynchronousRequestAttribute,
6538 QNetworkReplyPtr reply;
6539 QSignalSpy sslErrorsSpy(&manager, SIGNAL(sslErrors(QNetworkReply *, const QList<QSslError> &)));
6540 runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply, 0);
6541 QVERIFY(reply->isFinished());
6542 QCOMPARE(reply->error(), QNetworkReply::SslHandshakeFailedError);
6543 QCOMPARE(sslErrorsSpy.count(), 0);
6547 class HttpAbortHelper : public QObject
6551 HttpAbortHelper(QNetworkReply *parent)
6555 connect(parent, SIGNAL(readyRead()), this, SLOT(readyRead()));
6566 QMetaObject::invokeMethod(&QTestEventLoop::instance(), "exitLoop", Qt::QueuedConnection);
6570 QNetworkReply *mReply;
6573 void tst_QNetworkReply::httpAbort()
6575 // FIXME Also implement one where we do a big upload and then abort().
6576 // It must not crash either.
6578 // Abort after the first readyRead()
6579 QNetworkRequest request("http://" + QtNetworkSettings::serverName() + "/qtest/bigfile");
6580 QNetworkReplyPtr reply(manager.get(request));
6581 HttpAbortHelper replyHolder(reply.data());
6582 QTestEventLoop::instance().enterLoop(10);
6583 QVERIFY(!QTestEventLoop::instance().timeout());
6584 QCOMPARE(reply->error(), QNetworkReply::OperationCanceledError);
6585 QVERIFY(reply->isFinished());
6587 // Abort immediately after the get()
6588 QNetworkReplyPtr reply2(manager.get(request));
6589 connect(reply2, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
6591 QCOMPARE(reply2->error(), QNetworkReply::OperationCanceledError);
6592 QVERIFY(reply2->isFinished());
6594 // Abort after the finished()
6595 QNetworkRequest request3("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt");
6596 QNetworkReplyPtr reply3(manager.get(request3));
6598 QVERIFY(waitForFinish(reply3) == Success);
6600 QVERIFY(reply3->isFinished());
6602 QCOMPARE(reply3->error(), QNetworkReply::NoError);
6605 void tst_QNetworkReply::dontInsertPartialContentIntoTheCache()
6607 QByteArray reply206 =
6609 "Connection: keep-alive\r\n"
6610 "Content-Type: text/plain\r\n"
6611 "Cache-control: no-cache\r\n"
6612 "Content-Range: bytes 2-6/8\r\n"
6613 "Content-length: 4\r\n"
6617 MiniHttpServer server(reply206);
6618 server.doClose = false;
6620 MySpyMemoryCache *memoryCache = new MySpyMemoryCache(&manager);
6621 manager.setCache(memoryCache);
6623 QUrl url = "http://localhost:" + QString::number(server.serverPort());
6624 QNetworkRequest request(url);
6625 request.setRawHeader("Range", "bytes=2-6");
6627 QNetworkReplyPtr reply(manager.get(request));
6629 QVERIFY(waitForFinish(reply) == Success);
6631 QVERIFY(server.totalConnections > 0);
6632 QCOMPARE(reply->readAll().constData(), "load");
6633 QCOMPARE(memoryCache->m_insertedUrls.count(), 0);
6636 void tst_QNetworkReply::httpUserAgent()
6638 QByteArray response("HTTP/1.0 200 OK\r\n\r\n");
6639 MiniHttpServer server(response);
6640 server.doClose = true;
6642 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
6643 request.setHeader(QNetworkRequest::UserAgentHeader, "abcDEFghi");
6644 QNetworkReplyPtr reply(manager.get(request));
6646 QVERIFY(waitForFinish(reply) == Success);
6648 QVERIFY(reply->isFinished());
6649 QCOMPARE(reply->error(), QNetworkReply::NoError);
6650 QVERIFY(server.receivedData.contains("\r\nUser-Agent: abcDEFghi\r\n"));
6653 void tst_QNetworkReply::synchronousAuthenticationCache()
6655 class MiniAuthServer : public MiniHttpServer {
6657 MiniAuthServer(QThread *thread) : MiniHttpServer(QByteArray(), false, thread) {};
6658 virtual void reply() {
6661 "HTTP/1.0 401 Unauthorized\r\n"
6662 "WWW-Authenticate: Basic realm=\"QNetworkAccessManager Test Realm\"\r\n"
6663 "Content-Length: 4\r\n"
6664 "Connection: close\r\n"
6665 "Content-Type: text/plain\r\n"
6668 QRegExp rx("Authorization: Basic ([^\r\n]*)\r\n");
6669 if (rx.indexIn(receivedData) > 0) {
6670 if (QByteArray::fromBase64(rx.cap(1).toLatin1()) == "login:password") {
6672 "HTTP/1.0 200 OK\r\n"
6673 "Content-Type: text/plain\r\n"
6674 "Content-Length: 2\r\n"
6679 receivedData.clear();
6680 MiniHttpServer::reply();
6684 // when using synchronous commands, we need a different event loop for
6685 // the server thread, because the client is never returning to the
6687 QScopedPointer<QThread, QThreadCleanup> serverThread(new QThread);
6688 QScopedPointer<MiniHttpServer, QDeleteLaterCleanup> server(new MiniAuthServer(serverThread.data()));
6689 server->doClose = true;
6691 //1) URL without credentials, we are not authenticated
6693 QUrl url = "http://localhost:" + QString::number(server->serverPort()) + "/path";
6694 QNetworkRequest request(url);
6695 request.setAttribute(QNetworkRequest::SynchronousRequestAttribute, true);
6697 QNetworkReplyPtr reply(manager.get(request));
6698 QVERIFY(reply->isFinished());
6699 QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError);
6702 //2) URL with credentials, we are authenticated
6704 QUrl url = "http://login:password@localhost:" + QString::number(server->serverPort()) + "/path2";
6705 QNetworkRequest request(url);
6706 request.setAttribute(QNetworkRequest::SynchronousRequestAttribute, true);
6708 QNetworkReplyPtr reply(manager.get(request));
6709 QVERIFY(reply->isFinished());
6710 QCOMPARE(reply->error(), QNetworkReply::NoError);
6711 QCOMPARE(reply->readAll().constData(), "OK");
6714 //3) URL without credentials, we are authenticated because they are cached
6716 QUrl url = "http://localhost:" + QString::number(server->serverPort()) + "/path3";
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");
6727 void tst_QNetworkReply::pipelining()
6729 QString urlString("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/echo.cgi?");
6730 QList<QNetworkReplyPtr> replies;
6731 for (int a = 0; a < 20; a++) {
6732 QNetworkRequest request(urlString + QString::number(a));
6733 request.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, QVariant(true));
6734 replies.append(QNetworkReplyPtr(manager.get(request)));
6735 connect(replies.at(a), SIGNAL(finished()), this, SLOT(pipeliningHelperSlot()));
6737 QTestEventLoop::instance().enterLoop(20);
6738 QVERIFY(!QTestEventLoop::instance().timeout());
6741 void tst_QNetworkReply::pipeliningHelperSlot() {
6744 // check that pipelining was used in at least one of the replies
6745 static bool pipeliningWasUsed = false;
6746 QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
6747 bool pipeliningWasUsedInReply = reply->attribute(QNetworkRequest::HttpPipeliningWasUsedAttribute).toBool();
6748 if (pipeliningWasUsedInReply)
6749 pipeliningWasUsed = true;
6751 // check that the contents match (the response to echo.cgi?3 should return 3 etc.)
6752 QString urlQueryString = reply->url().query();
6753 QString content = reply->readAll();
6754 QVERIFY2(urlQueryString == content, "data corruption with pipelining detected");
6758 if (a == 20) { // all replies have finished
6759 QTestEventLoop::instance().exitLoop();
6760 QVERIFY2(pipeliningWasUsed, "pipelining was not used in any of the replies when trying to test pipelining");
6764 void tst_QNetworkReply::closeDuringDownload_data()
6766 QTest::addColumn<QUrl>("url");
6767 QTest::newRow("http") << QUrl("http://" + QtNetworkSettings::serverName() + "/bigfile");
6768 QTest::newRow("ftp") << QUrl("ftp://" + QtNetworkSettings::serverName() + "/qtest/bigfile");
6771 void tst_QNetworkReply::closeDuringDownload()
6774 QNetworkRequest request(url);
6775 QNetworkReply* reply = manager.get(request);
6776 connect(reply, SIGNAL(readyRead()), &QTestEventLoop::instance(), SLOT(exitLoop()));
6777 QTestEventLoop::instance().enterLoop(10);
6778 QVERIFY(!QTestEventLoop::instance().timeout());
6779 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
6781 reply->deleteLater();
6782 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
6785 void tst_QNetworkReply::ftpAuthentication_data()
6787 QTest::addColumn<QString>("referenceName");
6788 QTest::addColumn<QString>("url");
6789 QTest::addColumn<int>("error");
6791 QTest::newRow("invalidPassword") << (testDataDir + "/rfc3252.txt") << "ftp://ftptest:invalid@" + QtNetworkSettings::serverName() + "/home/qt-test-server/ftp/qtest/rfc3252.txt" << int(QNetworkReply::AuthenticationRequiredError);
6792 QTest::newRow("validPassword") << (testDataDir + "/rfc3252.txt") << "ftp://ftptest:password@" + QtNetworkSettings::serverName() + "/home/qt-test-server/ftp/qtest/rfc3252.txt" << int(QNetworkReply::NoError);
6795 void tst_QNetworkReply::ftpAuthentication()
6797 QFETCH(QString, referenceName);
6798 QFETCH(QString, url);
6801 QFile reference(referenceName);
6802 QVERIFY(reference.open(QIODevice::ReadOnly));
6804 QNetworkRequest request(url);
6805 QNetworkReplyPtr reply;
6806 runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply);
6808 QCOMPARE(reply->url(), request.url());
6809 QCOMPARE(reply->error(), QNetworkReply::NetworkError(error));
6812 void tst_QNetworkReply::backgroundRequest_data()
6814 QTest::addColumn<bool>("background");
6815 QTest::addColumn<int>("policy");
6816 QTest::addColumn<QNetworkReply::NetworkError>("error");
6818 QTest::newRow("fg, normal") << false << 0 << QNetworkReply::NoError;
6819 QTest::newRow("bg, normal") << true << 0 << QNetworkReply::NoError;
6820 QTest::newRow("fg, nobg") << false << (int)QNetworkSession::NoBackgroundTrafficPolicy << QNetworkReply::NoError;
6821 QTest::newRow("bg, nobg") << true << (int)QNetworkSession::NoBackgroundTrafficPolicy << QNetworkReply::BackgroundRequestNotAllowedError;
6825 void tst_QNetworkReply::backgroundRequest()
6827 #ifdef QT_BUILD_INTERNAL
6828 QFETCH(bool, background);
6829 QFETCH(int, policy);
6830 QFETCH(QNetworkReply::NetworkError, error);
6832 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName()));
6835 request.setAttribute(QNetworkRequest::BackgroundRequestAttribute, QVariant::fromValue(true));
6837 //this preconstructs the session so we can change policies in advance
6838 manager.setConfiguration(networkConfiguration);
6840 const QWeakPointer<const QNetworkSession> session = QNetworkAccessManagerPrivate::getNetworkSession(&manager);
6842 QNetworkSession::UsagePolicies original = session.data()->usagePolicies();
6843 QNetworkSessionPrivate::setUsagePolicies(*const_cast<QNetworkSession *>(session.data()), QNetworkSession::UsagePolicies(policy));
6845 QNetworkReplyPtr reply(manager.get(request));
6847 QVERIFY(waitForFinish(reply) != Timeout);
6849 QNetworkSessionPrivate::setUsagePolicies(*const_cast<QNetworkSession *>(session.data()), original);
6851 QVERIFY(reply->isFinished());
6852 QCOMPARE(reply->error(), error);
6856 // NOTE: This test must be last testcase in tst_qnetworkreply!
6857 void tst_QNetworkReply::parentingRepliesToTheApp()
6859 QNetworkRequest request (QUrl("http://" + QtNetworkSettings::serverName()));
6860 manager.get(request)->setParent(this); // parent to this object
6861 manager.get(request)->setParent(qApp); // parent to the app
6864 QTEST_MAIN(tst_QNetworkReply)
6866 #include "tst_qnetworkreply.moc"