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>
79 #ifdef QT_BUILD_INTERNAL
80 #include <QtNetwork/private/qnetworkaccessmanager_p.h>
84 # include <sys/types.h>
85 # include <unistd.h> // for getuid()
89 #include "../../../network-settings.h"
91 Q_DECLARE_METATYPE(QSharedPointer<char>)
92 Q_DECLARE_METATYPE(QNetworkReply*)
93 Q_DECLARE_METATYPE(QAuthenticator*)
94 Q_DECLARE_METATYPE(QNetworkProxy)
95 Q_DECLARE_METATYPE(QNetworkProxyQuery)
96 Q_DECLARE_METATYPE(QList<QNetworkProxy>)
97 Q_DECLARE_METATYPE(QNetworkReply::NetworkError)
98 Q_DECLARE_METATYPE(QBuffer*)
99 Q_DECLARE_METATYPE(QHttpMultiPart *)
100 Q_DECLARE_METATYPE(QList<QFile*>) // for multiparts
102 Q_DECLARE_METATYPE(QSslConfiguration)
105 class QNetworkReplyPtr: public QSharedPointer<QNetworkReply>
108 inline QNetworkReplyPtr(QNetworkReply *ptr = 0)
109 : QSharedPointer<QNetworkReply>(ptr)
112 inline operator QNetworkReply *() const { return data(); }
116 class tst_QNetworkReply: public QObject
121 ProxyData(const QNetworkProxy &p, const QByteArray &t, bool auth)
122 : tag(t), proxy(p), requiresAuthentication(auth)
126 bool requiresAuthentication;
129 static bool seedCreated;
130 static QString createUniqueExtension() {
132 qsrand(QTime(0,0,0).msecsTo(QTime::currentTime()) + QCoreApplication::applicationPid());
133 seedCreated = true; // not thread-safe, but who cares
135 QString s = QString("%1-%2-%3").arg(QTime(0,0,0).msecsTo(QTime::currentTime())).arg(QCoreApplication::applicationPid()).arg(qrand());
140 enum RunSimpleRequestReturn { Timeout = 0, Success, Failure };
142 QString testFileName;
143 QString echoProcessDir;
144 #if !defined Q_OS_WIN
145 QString wronlyFileName;
147 QString uniqueExtension;
148 QList<ProxyData> proxies;
149 QNetworkAccessManager manager;
150 MyCookieJar *cookieJar;
152 QSslConfiguration storedSslConfiguration;
153 QList<QSslError> storedExpectedSslErrors;
155 #ifndef QT_NO_BEARERMANAGEMENT
156 QNetworkConfigurationManager *netConfMan;
157 QNetworkConfiguration networkConfiguration;
158 QScopedPointer<QNetworkSession> networkSession;
163 ~tst_QNetworkReply();
164 QString runSimpleRequest(QNetworkAccessManager::Operation op, const QNetworkRequest &request,
165 QNetworkReplyPtr &reply, const QByteArray &data = QByteArray());
166 QString runMultipartRequest(const QNetworkRequest &request, QNetworkReplyPtr &reply,
167 QHttpMultiPart *multiPart, const QByteArray &verb);
169 QString runCustomRequest(const QNetworkRequest &request, QNetworkReplyPtr &reply,
170 const QByteArray &verb, QIODevice *data);
171 int waitForFinish(QNetworkReplyPtr &reply);
176 void authenticationRequired(QNetworkReply*,QAuthenticator*);
177 void proxyAuthenticationRequired(const QNetworkProxy &,QAuthenticator*);
178 void pipeliningHelperSlot();
181 void sslErrors(QNetworkReply*,const QList<QSslError> &);
182 void storeSslConfiguration();
183 void ignoreSslErrorListSlot(QNetworkReply *reply, const QList<QSslError> &);
187 void nestedEventLoops_slot();
193 void cleanupTestCase();
195 void stateChecking();
196 void invalidProtocol();
197 void getFromData_data();
200 void getFromFileSpecial_data();
201 void getFromFileSpecial();
202 void getFromFtp_data();
204 void getFromHttp_data();
206 void getErrors_data();
208 void headFromHttp_data();
210 void putToFile_data();
212 void putToFtp_data();
214 void putToHttp_data();
216 void putToHttpSynchronous_data();
217 void putToHttpSynchronous();
218 void putToHttpMultipart_data();
219 void putToHttpMultipart();
220 void postToHttp_data();
222 void postToHttpSynchronous_data();
223 void postToHttpSynchronous();
224 void postToHttpMultipart_data();
225 void postToHttpMultipart();
226 void deleteFromHttp_data();
227 void deleteFromHttp();
228 void putGetDeleteGetFromHttp_data();
229 void putGetDeleteGetFromHttp();
230 void sendCustomRequestToHttp_data();
231 void sendCustomRequestToHttp();
232 void connectToIPv6Address_data();
233 void connectToIPv6Address();
235 void ioGetFromData_data();
236 void ioGetFromData();
237 void ioGetFromFileSpecial_data();
238 void ioGetFromFileSpecial();
239 void ioGetFromFile_data();
240 void ioGetFromFile();
241 void ioGetFromFtp_data();
243 void ioGetFromFtpWithReuse();
244 void ioGetFromHttp();
246 void ioGetFromBuiltinHttp_data();
247 void ioGetFromBuiltinHttp();
248 void ioGetFromHttpWithReuseParallel();
249 void ioGetFromHttpWithReuseSequential();
250 void ioGetFromHttpWithAuth_data();
251 void ioGetFromHttpWithAuth();
252 void ioGetFromHttpWithAuthSynchronous();
253 void ioGetFromHttpWithProxyAuth();
254 void ioGetFromHttpWithProxyAuthSynchronous();
255 void ioGetFromHttpWithSocksProxy();
257 void ioGetFromHttpsWithSslErrors();
258 void ioGetFromHttpsWithIgnoreSslErrors();
259 void ioGetFromHttpsWithSslHandshakeError();
261 void ioGetFromHttpBrokenServer_data();
262 void ioGetFromHttpBrokenServer();
263 void ioGetFromHttpStatus100_data();
264 void ioGetFromHttpStatus100();
265 void ioGetFromHttpNoHeaders_data();
266 void ioGetFromHttpNoHeaders();
267 void ioGetFromHttpWithCache_data();
268 void ioGetFromHttpWithCache();
270 void ioGetWithManyProxies_data();
271 void ioGetWithManyProxies();
273 void ioPutToFileFromFile_data();
274 void ioPutToFileFromFile();
275 void ioPutToFileFromSocket_data();
276 void ioPutToFileFromSocket();
277 void ioPutToFileFromLocalSocket_data();
278 void ioPutToFileFromLocalSocket();
279 #ifndef QT_NO_PROCESS
280 void ioPutToFileFromProcess_data();
281 void ioPutToFileFromProcess();
283 void ioPutToFtpFromFile_data();
284 void ioPutToFtpFromFile();
285 void ioPutToHttpFromFile_data();
286 void ioPutToHttpFromFile();
287 void ioPostToHttpFromFile_data();
288 void ioPostToHttpFromFile();
289 void ioPostToHttpFromSocket_data();
290 void ioPostToHttpFromSocket();
291 void ioPostToHttpFromSocketSynchronous();
292 void ioPostToHttpFromSocketSynchronous_data();
293 void ioPostToHttpFromMiddleOfFileToEnd();
294 void ioPostToHttpFromMiddleOfFileFiveBytes();
295 void ioPostToHttpFromMiddleOfQBufferFiveBytes();
296 void ioPostToHttpNoBufferFlag();
297 void ioPostToHttpUploadProgress();
298 void ioPostToHttpEmptyUploadProgress();
300 void lastModifiedHeaderForFile();
301 void lastModifiedHeaderForHttp();
303 void httpCanReadLine();
305 void rateControl_data();
308 void downloadProgress_data();
309 void downloadProgress();
310 void uploadProgress_data();
311 void uploadProgress();
313 void chaining_data();
316 void receiveCookiesFromHttp_data();
317 void receiveCookiesFromHttp();
318 void receiveCookiesFromHttpSynchronous_data();
319 void receiveCookiesFromHttpSynchronous();
320 void sendCookies_data();
322 void sendCookiesSynchronous_data();
323 void sendCookiesSynchronous();
325 void nestedEventLoops();
327 void httpProxyCommands_data();
328 void httpProxyCommands();
329 void httpProxyCommandsSynchronous_data();
330 void httpProxyCommandsSynchronous();
332 void authorizationError_data();
333 void authorizationError();
335 void httpConnectionCount();
337 void httpReUsingConnectionSequential_data();
338 void httpReUsingConnectionSequential();
339 void httpReUsingConnectionFromFinishedSlot_data();
340 void httpReUsingConnectionFromFinishedSlot();
342 void httpRecursiveCreation();
345 void ioPostToHttpsUploadProgress();
346 void ignoreSslErrorsList_data();
347 void ignoreSslErrorsList();
348 void ignoreSslErrorsListWithSlot_data();
349 void ignoreSslErrorsListWithSlot();
350 void sslConfiguration_data();
351 void sslConfiguration();
354 void getAndThenDeleteObject_data();
355 void getAndThenDeleteObject();
357 void symbianOpenCDataUrlCrash();
359 void getFromHttpIntoBuffer_data();
360 void getFromHttpIntoBuffer();
361 void getFromHttpIntoBuffer2_data();
362 void getFromHttpIntoBuffer2();
363 void getFromHttpIntoBufferCanReadLine();
365 void ioGetFromHttpWithoutContentLength();
367 void ioGetFromHttpBrokenChunkedEncoding();
368 void qtbug12908compressedHttpReply();
369 void compressedHttpReplyBrokenGzip();
371 void getFromUnreachableIp();
373 void qtbug4121unknownAuthentication();
375 void qtbug13431replyThrottling();
377 void httpWithNoCredentialUsage();
379 void qtbug15311doubleContentLength();
381 void qtbug18232gzipContentLengthZero();
382 void qtbug22660gzipNoContentLengthEmptyContent();
384 void synchronousRequest_data();
385 void synchronousRequest();
387 void synchronousRequestSslFailure();
392 void dontInsertPartialContentIntoTheCache();
394 void httpUserAgent();
395 void authenticationCacheAfterCancel_data();
396 void authenticationCacheAfterCancel();
397 void authenticationWithDifferentRealm();
398 void synchronousAuthenticationCache();
401 void closeDuringDownload_data();
402 void closeDuringDownload();
404 // NOTE: This test must be last!
405 void parentingRepliesToTheApp();
410 bool tst_QNetworkReply::seedCreated = false;
416 char *toString(const QNetworkReply::NetworkError& code)
418 const QMetaObject *mo = &QNetworkReply::staticMetaObject;
419 int index = mo->indexOfEnumerator("NetworkError");
423 QMetaEnum qme = mo->enumerator(index);
424 return qstrdup(qme.valueToKey(code));
428 char *toString(const QNetworkCookie &cookie)
430 return qstrdup(cookie.toRawForm());
434 char *toString(const QList<QNetworkCookie> &list)
436 QString result = "QList(";
438 foreach (QNetworkCookie cookie, list) {
442 result += QString::fromLatin1("QNetworkCookie(%1)").arg(QLatin1String(cookie.toRawForm()));
445 return qstrdup(result.append(')').toLocal8Bit());
451 #define RUN_REQUEST(call) \
453 QString errorMsg = call; \
454 if (!errorMsg.isEmpty()) \
455 QFAIL(qPrintable(errorMsg)); \
459 static void setupSslServer(QSslSocket* serverSocket)
461 QString testDataDir = QFileInfo(QFINDTESTDATA("rfc3252.txt")).absolutePath();
462 if (testDataDir.isEmpty())
463 testDataDir = QCoreApplication::applicationDirPath();
465 serverSocket->setProtocol(QSsl::AnyProtocol);
466 serverSocket->setLocalCertificate(testDataDir + "/certs/server.pem");
467 serverSocket->setPrivateKey(testDataDir + "/certs/server.key");
471 // Does not work for POST/PUT!
472 class MiniHttpServer: public QTcpServer
476 QTcpSocket *client; // always the last one that was received
477 QByteArray dataToTransmit;
478 QByteArray receivedData;
484 int totalConnections;
486 MiniHttpServer(const QByteArray &data, bool ssl = false, QThread *thread = 0, bool useipv6 = false)
487 : client(0), dataToTransmit(data), doClose(true), doSsl(ssl), ipv6(useipv6),
488 multiple(false), totalConnections(0)
491 listen(QHostAddress::AnyIPv6);
493 listen(QHostAddress::AnyIPv4);
496 connect(thread, SIGNAL(started()), this, SLOT(threadStartedSlot()));
497 moveToThread(thread);
504 void incomingConnection(qintptr socketDescriptor)
506 //qDebug() << "incomingConnection" << socketDescriptor << "doSsl:" << doSsl << "ipv6:" << ipv6;
508 client = new QTcpSocket;
509 client->setSocketDescriptor(socketDescriptor);
510 connectSocketSignals();
513 QSslSocket *serverSocket = new QSslSocket;
514 serverSocket->setParent(this);
515 if (serverSocket->setSocketDescriptor(socketDescriptor)) {
516 connect(serverSocket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(slotSslErrors(QList<QSslError>)));
517 setupSslServer(serverSocket);
518 serverSocket->startServerEncryption();
519 client = serverSocket;
520 connectSocketSignals();
527 client->setParent(this);
531 virtual void reply() {
532 // we need to emulate the bytesWrittenSlot call if the data is empty.
533 if (dataToTransmit.size() == 0)
534 QMetaObject::invokeMethod(this, "bytesWrittenSlot", Qt::QueuedConnection);
536 client->write(dataToTransmit);
539 void connectSocketSignals()
541 //qDebug() << "connectSocketSignals" << client;
542 connect(client, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
543 connect(client, SIGNAL(bytesWritten(qint64)), this, SLOT(bytesWrittenSlot()));
544 connect(client, SIGNAL(error(QAbstractSocket::SocketError)),
545 this, SLOT(slotError(QAbstractSocket::SocketError)));
550 void slotSslErrors(const QList<QSslError>& errors)
552 qDebug() << "slotSslErrors" << client->errorString() << errors;
555 void slotError(QAbstractSocket::SocketError err)
557 qDebug() << "slotError" << err << client->errorString();
563 receivedData += client->readAll();
564 int doubleEndlPos = receivedData.indexOf("\r\n\r\n");
566 if (doubleEndlPos != -1) {
567 // multiple requests incoming. remove the bytes of the current one
569 receivedData.remove(0, doubleEndlPos+4);
575 void bytesWrittenSlot() {
576 if (doClose && client->bytesToWrite() == 0) {
577 client->disconnectFromHost();
578 disconnect(client, 0, this, 0);
582 void threadStartedSlot()
588 class MyCookieJar: public QNetworkCookieJar
591 inline QList<QNetworkCookie> allCookies() const
592 { return QNetworkCookieJar::allCookies(); }
593 inline void setAllCookies(const QList<QNetworkCookie> &cookieList)
594 { QNetworkCookieJar::setAllCookies(cookieList); }
597 class MyProxyFactory: public QNetworkProxyFactory
601 QList<QNetworkProxy> toReturn;
602 QNetworkProxyQuery lastQuery;
603 inline MyProxyFactory() { clear(); }
608 toReturn = QList<QNetworkProxy>() << QNetworkProxy::DefaultProxy;
609 lastQuery = QNetworkProxyQuery();
612 virtual QList<QNetworkProxy> queryProxy(const QNetworkProxyQuery &query)
620 class MyMemoryCache: public QAbstractNetworkCache
623 typedef QPair<QNetworkCacheMetaData, QByteArray> CachedContent;
624 typedef QHash<QByteArray, CachedContent> CacheData;
627 MyMemoryCache(QObject *parent) : QAbstractNetworkCache(parent) {}
629 QNetworkCacheMetaData metaData(const QUrl &url)
631 return cache.value(url.toEncoded()).first;
634 void updateMetaData(const QNetworkCacheMetaData &metaData)
636 cache[metaData.url().toEncoded()].first = metaData;
639 QIODevice *data(const QUrl &url)
641 CacheData::ConstIterator it = cache.find(url.toEncoded());
642 if (it == cache.constEnd())
644 QBuffer *io = new QBuffer(this);
645 io->setData(it->second);
646 io->open(QIODevice::ReadOnly);
651 bool remove(const QUrl &url)
653 cache.remove(url.toEncoded());
657 qint64 cacheSize() const
660 foreach (const CachedContent &entry, cache)
661 total += entry.second.size();
665 QIODevice *prepare(const QNetworkCacheMetaData &)
667 qFatal("%s: Should not have tried to add to the cache", Q_FUNC_INFO);
670 void insert(QIODevice *)
672 qFatal("%s: Should not have tried to add to the cache", Q_FUNC_INFO);
675 void clear() { cache.clear(); }
677 Q_DECLARE_METATYPE(MyMemoryCache::CachedContent)
678 Q_DECLARE_METATYPE(MyMemoryCache::CacheData)
680 class MySpyMemoryCache: public QAbstractNetworkCache
683 MySpyMemoryCache(QObject *parent) : QAbstractNetworkCache(parent) {}
686 qDeleteAll(m_buffers);
690 QHash<QUrl, QIODevice*> m_buffers;
691 QList<QUrl> m_insertedUrls;
693 QNetworkCacheMetaData metaData(const QUrl &)
695 return QNetworkCacheMetaData();
698 void updateMetaData(const QNetworkCacheMetaData &)
702 QIODevice *data(const QUrl &)
707 bool remove(const QUrl &url)
709 delete m_buffers.take(url);
710 return m_insertedUrls.removeAll(url) > 0;
713 qint64 cacheSize() const
718 QIODevice *prepare(const QNetworkCacheMetaData &metaData)
720 QBuffer* buffer = new QBuffer;
721 buffer->open(QIODevice::ReadWrite);
722 buffer->setProperty("url", metaData.url());
723 m_buffers.insert(metaData.url(), buffer);
727 void insert(QIODevice *buffer)
729 QUrl url = buffer->property("url").toUrl();
730 m_insertedUrls << url;
731 delete m_buffers.take(url);
734 void clear() { m_insertedUrls.clear(); }
737 class DataReader: public QObject
745 DataReader(QIODevice *dev, bool acc = true) : totalBytes(0), device(dev), accumulate(acc)
747 connect(device, SIGNAL(readyRead()), SLOT(doRead()));
754 buffer.resize(device->bytesAvailable());
755 qint64 bytesRead = device->read(buffer.data(), device->bytesAvailable());
756 if (bytesRead == -1) {
757 QTestEventLoop::instance().exitLoop();
760 buffer.truncate(bytesRead);
761 totalBytes += bytesRead;
769 class SocketPair: public QObject
773 QIODevice *endPoints[2];
775 SocketPair(QObject *parent = 0)
778 endPoints[0] = endPoints[1] = 0;
786 QTcpSocket *active = new QTcpSocket(this);
787 active->connectToHost("127.0.0.1", server.serverPort());
789 // need more time as working with embedded
790 // device and testing from emualtor
791 // things tend to get slower
792 if (!active->waitForConnected(1000))
795 if (!server.waitForNewConnection(1000))
798 QTcpSocket *passive = server.nextPendingConnection();
799 passive->setParent(this);
801 endPoints[0] = active;
802 endPoints[1] = passive;
807 // A blocking tcp server (must be used in a thread) which supports SSL.
808 class BlockingTcpServer : public QTcpServer
812 BlockingTcpServer(bool ssl) : doSsl(ssl), sslSocket(0) {}
814 QTcpSocket* waitForNextConnectionSocket() {
815 waitForNewConnection(-1);
818 qFatal("%s: sslSocket should not be null after calling waitForNewConnection()",
822 //qDebug() << "returning nextPendingConnection";
823 return nextPendingConnection();
826 virtual void incomingConnection(qintptr socketDescriptor)
830 QSslSocket *serverSocket = new QSslSocket;
831 serverSocket->setParent(this);
832 serverSocket->setSocketDescriptor(socketDescriptor);
833 connect(serverSocket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(slotSslErrors(QList<QSslError>)));
834 setupSslServer(serverSocket);
835 serverSocket->startServerEncryption();
836 sslSocket = serverSocket;
840 QTcpServer::incomingConnection(socketDescriptor);
846 void slotSslErrors(const QList<QSslError>& errors)
848 qDebug() << "slotSslErrors" << sslSocket->errorString() << errors;
854 QTcpSocket* sslSocket;
857 // This server tries to send data as fast as possible (like most servers)
858 // but it measures how fast it was able to send it, which shows at which
859 // rate the reader is processing the data.
860 class FastSender: public QThread
866 enum Protocol { DebugPipe, ProvidedData };
867 const Protocol protocol;
869 const bool fillKernelBuffer;
874 QByteArray dataToTransmit;
877 // a server that sends debugpipe data
878 FastSender(qint64 size)
879 : wantedSize(size), port(-1), protocol(DebugPipe),
880 doSsl(false), fillKernelBuffer(true), transferRate(-1),
887 // a server that sends the data provided at construction time, useful for HTTP
888 FastSender(const QByteArray& data, bool https, bool fillBuffer)
889 : wantedSize(data.size()), port(-1), protocol(ProvidedData),
890 doSsl(https), fillKernelBuffer(fillBuffer), transferRate(-1),
891 dataToTransmit(data), dataIndex(0)
897 inline int serverPort() const { return port; }
899 int writeNextData(QTcpSocket* socket, qint32 size)
901 if (protocol == DebugPipe) {
903 QDataStream stream(&data, QIODevice::WriteOnly);
904 stream << QVariantMap() << QByteArray(size, 'a');
905 socket->write((char*)&size, sizeof size);
910 const QByteArray data = dataToTransmit.mid(dataIndex, size);
912 dataIndex += data.size();
913 //qDebug() << "wrote" << dataIndex << "/" << dataToTransmit.size();
917 void writeLastData(QTcpSocket* socket)
919 if (protocol == DebugPipe) {
921 QDataStream stream(&data, QIODevice::WriteOnly);
922 stream << QVariantMap() << QByteArray();
923 const qint32 size = data.size();
924 socket->write((char*)&size, sizeof size);
932 BlockingTcpServer server(doSsl);
934 port = server.serverPort();
937 QTcpSocket *client = server.waitForNextConnectionSocket();
939 // get the "request" packet
940 if (!client->waitForReadyRead(2000)) {
941 qDebug() << "FastSender:" << client->error() << "waiting for \"request\" packet";
944 client->readAll(); // we're not interested in the actual contents (e.g. HTTP request)
946 enum { BlockSize = 1024 };
948 if (fillKernelBuffer) {
950 // write a bunch of bytes to fill up the buffers
953 if (writeNextData(client, BlockSize) < BlockSize) {
954 qDebug() << "ERROR: FastSender: not enough data to write in order to fill buffers; or client is reading too fast";
957 while (client->bytesToWrite() > 0) {
958 if (!client->waitForBytesWritten(0)) {
963 //qDebug() << "Filling kernel buffer: wrote" << dataIndex << "bytes";
966 qDebug() << "FastSender: ok, kernel buffer is full after writing" << dataIndex << "bytes";
969 // Tell the client to start reading
972 // the kernel buffer is full
973 // clean up QAbstractSocket's residue:
974 while (client->bytesToWrite() > 0) {
975 qDebug() << "Still having" << client->bytesToWrite() << "bytes to write, doing that now";
976 if (!client->waitForBytesWritten(2000)) {
977 qDebug() << "ERROR: FastSender:" << client->error() << "cleaning up residue";
982 // now write in "blocking mode", this is where the rate measuring starts
985 //const qint64 writtenBefore = dataIndex;
986 //qint64 measuredTotalBytes = wantedSize - writtenBefore;
987 qint64 measuredSentBytes = 0;
988 while (dataIndex < wantedSize) {
989 const int remainingBytes = wantedSize - measuredSentBytes;
990 const int bytesToWrite = qMin(remainingBytes, static_cast<int>(BlockSize));
991 if (bytesToWrite <= 0)
992 qFatal("%s: attempt to write %d bytes", Q_FUNC_INFO, bytesToWrite);
993 measuredSentBytes += writeNextData(client, bytesToWrite);
995 while (client->bytesToWrite() > 0) {
996 if (!client->waitForBytesWritten(2000)) {
997 qDebug() << "ERROR: FastSender:" << client->error() << "during blocking write";
1001 /*qDebug() << "FastSender:" << bytesToWrite << "bytes written now;"
1002 << measuredSentBytes << "measured bytes" << measuredSentBytes + writtenBefore << "total ("
1003 << measuredSentBytes*100/measuredTotalBytes << "% complete);"
1004 << timer.elapsed() << "ms elapsed";*/
1007 transferRate = measuredSentBytes * 1000 / timer.elapsed();
1008 qDebug() << "FastSender: flushed" << measuredSentBytes << "bytes in" << timer.elapsed() << "ms: rate =" << transferRate << "B/s";
1010 // write a "close connection" packet, if the protocol needs it
1011 writeLastData(client);
1017 class RateControlledReader: public QObject
1026 qint64 totalBytesRead;
1027 RateControlledReader(QObject& senderObj, QIODevice *dev, int kbPerSec, int maxBufferSize = 0)
1028 : device(dev), readBufferSize(maxBufferSize), totalBytesRead(0)
1030 // determine how often we have to wake up
1032 if (readBufferSize == 0) {
1033 // The requirement is simply "N KB per seconds"
1034 timesPerSecond = 20;
1035 bytesToRead = kbPerSec * 1024 / timesPerSecond;
1037 // The requirement also includes "<readBufferSize> bytes at a time"
1038 bytesToRead = readBufferSize;
1039 timesPerSecond = kbPerSec * 1024 / readBufferSize;
1041 interval = 1000 / timesPerSecond; // in ms
1043 qDebug() << "RateControlledReader: going to read" << bytesToRead
1044 << "bytes every" << interval << "ms";
1045 qDebug() << "actual read rate will be"
1046 << (bytesToRead * 1000 / interval) << "bytes/sec (wanted"
1047 << kbPerSec * 1024 << "bytes/sec)";
1049 // Wait for data to be readyRead
1050 bool ok = connect(&senderObj, SIGNAL(dataReady()), this, SLOT(slotDataReady()));
1052 qFatal("%s: Cannot connect dataReady signal", Q_FUNC_INFO);
1057 QByteArray someData = device->read(device->bytesAvailable());
1059 totalBytesRead += someData.size();
1060 qDebug() << "wrapUp: found" << someData.size() << "bytes left. progress" << data.size();
1061 //qDebug() << "wrapUp: now bytesAvailable=" << device->bytesAvailable();
1065 void slotDataReady()
1067 //qDebug() << "RateControlledReader: ready to go";
1068 startTimer(interval);
1072 void timerEvent(QTimerEvent *)
1074 //qDebug() << "RateControlledReader: timerEvent bytesAvailable=" << device->bytesAvailable();
1075 if (readBufferSize > 0 && device->bytesAvailable() > readBufferSize) {
1076 // This passes all the time, except in the final flush.
1077 //qFatal("%s: Too many bytes available", Q_FUNC_INFO);
1080 qint64 bytesRead = 0;
1084 if (device->bytesAvailable() == 0) {
1085 if (stopWatch.elapsed() > 20) {
1086 qDebug() << "RateControlledReader: Not enough data available for reading, waited too much, timing out";
1089 if (!device->waitForReadyRead(5)) {
1090 qDebug() << "RateControlledReader: Not enough data available for reading, even after waiting 5ms, bailing out";
1094 QByteArray someData = device->read(bytesToRead - bytesRead);
1096 bytesRead += someData.size();
1097 //qDebug() << "RateControlledReader: successfully read" << someData.size() << "progress:" << data.size();
1098 } while (bytesRead < bytesToRead);
1099 totalBytesRead += bytesRead;
1101 if (bytesRead < bytesToRead)
1102 qWarning() << "RateControlledReader: WARNING:" << bytesToRead - bytesRead << "bytes not read";
1107 tst_QNetworkReply::tst_QNetworkReply()
1109 qRegisterMetaType<QNetworkReply *>(); // for QSignalSpy
1110 qRegisterMetaType<QAuthenticator *>();
1111 qRegisterMetaType<QNetworkProxy>();
1113 qRegisterMetaType<QList<QSslError> >();
1115 qRegisterMetaType<QNetworkReply::NetworkError>();
1117 testFileName = QDir::currentPath() + "/testfile";
1118 uniqueExtension = createUniqueExtension();
1119 cookieJar = new MyCookieJar;
1120 manager.setCookieJar(cookieJar);
1122 QHostInfo hostInfo = QHostInfo::fromName(QtNetworkSettings::serverName());
1124 proxies << ProxyData(QNetworkProxy::NoProxy, "", false);
1126 if (hostInfo.error() == QHostInfo::NoError && !hostInfo.addresses().isEmpty()) {
1127 QString proxyserver = hostInfo.addresses().first().toString();
1128 proxies << ProxyData(QNetworkProxy(QNetworkProxy::HttpProxy, proxyserver, 3128), "+proxy", false)
1129 << ProxyData(QNetworkProxy(QNetworkProxy::HttpProxy, proxyserver, 3129), "+proxyauth", true)
1130 // currently unsupported
1131 // << ProxyData(QNetworkProxy(QNetworkProxy::HttpProxy, proxyserver, 3130), "+proxyauth-ntlm", true);
1132 << ProxyData(QNetworkProxy(QNetworkProxy::Socks5Proxy, proxyserver, 1080), "+socks", false)
1133 << ProxyData(QNetworkProxy(QNetworkProxy::Socks5Proxy, proxyserver, 1081), "+socksauth", true);
1135 printf("==================================================================\n");
1136 printf("Proxy could not be looked up. No proxy will be used while testing!\n");
1137 printf("==================================================================\n");
1141 tst_QNetworkReply::~tst_QNetworkReply()
1146 void tst_QNetworkReply::authenticationRequired(QNetworkReply*, QAuthenticator* auth)
1148 auth->setUser("httptest");
1149 auth->setPassword("httptest");
1152 void tst_QNetworkReply::proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator* auth)
1154 auth->setUser("qsockstest");
1155 auth->setPassword("password");
1159 void tst_QNetworkReply::sslErrors(QNetworkReply *reply, const QList<QSslError> &errors)
1161 reply->ignoreSslErrors();
1162 QVERIFY(!errors.isEmpty());
1163 QVERIFY(!reply->sslConfiguration().isNull());
1166 void tst_QNetworkReply::storeSslConfiguration()
1168 storedSslConfiguration = QSslConfiguration();
1169 QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
1171 storedSslConfiguration = reply->sslConfiguration();
1175 QString tst_QNetworkReply::runMultipartRequest(const QNetworkRequest &request,
1176 QNetworkReplyPtr &reply,
1177 QHttpMultiPart *multiPart,
1178 const QByteArray &verb)
1181 reply = manager.post(request, multiPart);
1183 reply = manager.put(request, multiPart);
1185 // the code below is copied from tst_QNetworkReply::runSimpleRequest, see below
1186 reply->setParent(this);
1187 connect(reply, SIGNAL(finished()), SLOT(finished()));
1188 connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(gotError()));
1189 multiPart->setParent(reply);
1191 returnCode = Timeout;
1192 loop = new QEventLoop;
1193 QTimer::singleShot(25000, loop, SLOT(quit()));
1194 int code = returnCode == Timeout ? loop->exec() : returnCode;
1200 return "Request failed: " + reply->errorString();
1202 return "Network timeout";
1207 QString tst_QNetworkReply::runSimpleRequest(QNetworkAccessManager::Operation op,
1208 const QNetworkRequest &request,
1209 QNetworkReplyPtr &reply,
1210 const QByteArray &data)
1213 case QNetworkAccessManager::HeadOperation:
1214 reply = manager.head(request);
1217 case QNetworkAccessManager::GetOperation:
1218 reply = manager.get(request);
1221 case QNetworkAccessManager::PutOperation:
1222 reply = manager.put(request, data);
1225 case QNetworkAccessManager::PostOperation:
1226 reply = manager.post(request, data);
1229 case QNetworkAccessManager::DeleteOperation:
1230 reply = manager.deleteResource(request);
1234 qFatal("%s: Invalid/unknown operation requested", Q_FUNC_INFO);
1236 reply->setParent(this);
1238 returnCode = Timeout;
1241 if (request.attribute(QNetworkRequest::SynchronousRequestAttribute).toBool()) {
1242 if (reply->isFinished())
1243 code = reply->error() != QNetworkReply::NoError ? Failure : Success;
1247 connect(reply, SIGNAL(finished()), SLOT(finished()));
1248 connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(gotError()));
1251 loop = new QEventLoop;
1252 QSignalSpy spy(reply, SIGNAL(downloadProgress(qint64,qint64)));
1253 while (!reply->isFinished()) {
1254 QTimer::singleShot(20000, loop, SLOT(quit()));
1255 code = loop->exec();
1256 if (count == spy.count() && !reply->isFinished()) {
1260 count = spy.count();
1268 return "Request failed: " + reply->errorString();
1270 return "Network timeout";
1275 QString tst_QNetworkReply::runCustomRequest(const QNetworkRequest &request,
1276 QNetworkReplyPtr &reply,
1277 const QByteArray &verb,
1280 reply = manager.sendCustomRequest(request, verb, data);
1281 reply->setParent(this);
1282 connect(reply, SIGNAL(finished()), SLOT(finished()));
1283 connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(gotError()));
1285 returnCode = Timeout;
1286 loop = new QEventLoop;
1287 QTimer::singleShot(20000, loop, SLOT(quit()));
1288 int code = returnCode == Timeout ? loop->exec() : returnCode;
1294 return "Request failed: " + reply->errorString();
1296 return "Network timeout";
1301 int tst_QNetworkReply::waitForFinish(QNetworkReplyPtr &reply)
1305 connect(reply, SIGNAL(finished()), SLOT(finished()));
1306 connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(gotError()));
1307 returnCode = Success;
1308 loop = new QEventLoop;
1309 QSignalSpy spy(reply, SIGNAL(downloadProgress(qint64,qint64)));
1310 while (!reply->isFinished()) {
1311 QTimer::singleShot(5000, loop, SLOT(quit()));
1312 if ( loop->exec() == Timeout && count == spy.count() && !reply->isFinished()) {
1313 returnCode = Timeout;
1316 count = spy.count();
1324 void tst_QNetworkReply::finished()
1326 loop->exit(returnCode = Success);
1329 void tst_QNetworkReply::gotError()
1331 loop->exit(returnCode = Failure);
1332 disconnect(QObject::sender(), SIGNAL(finished()), this, 0);
1335 void tst_QNetworkReply::initTestCase()
1337 testDataDir = QFileInfo(QFINDTESTDATA("rfc3252.txt")).absolutePath();
1338 if (testDataDir.isEmpty())
1339 testDataDir = QCoreApplication::applicationDirPath();
1341 QVERIFY(QtNetworkSettings::verifyTestNetworkSettings());
1342 #if !defined Q_OS_WIN
1343 wronlyFileName = testDataDir + "/write-only";
1344 QFile wr(wronlyFileName);
1345 QVERIFY(wr.open(QIODevice::WriteOnly | QIODevice::Truncate));
1346 wr.setPermissions(QFile::WriteOwner | QFile::WriteUser);
1350 QDir::setSearchPaths("testdata", QStringList() << testDataDir);
1352 QSslSocket::defaultCaCertificates(); //preload certificates
1354 #ifndef QT_NO_BEARERMANAGEMENT
1355 netConfMan = new QNetworkConfigurationManager(this);
1356 networkConfiguration = netConfMan->defaultConfiguration();
1357 networkSession.reset(new QNetworkSession(networkConfiguration));
1358 if (!networkSession->isOpen()) {
1359 networkSession->open();
1360 QVERIFY(networkSession->waitForOpened(30000));
1364 echoProcessDir = QFINDTESTDATA("echo");
1365 QVERIFY2(!echoProcessDir.isEmpty(), qPrintable(
1366 QString::fromLatin1("Couldn't find echo dir starting from %1.").arg(QDir::currentPath())));
1369 void tst_QNetworkReply::cleanupTestCase()
1371 #if !defined Q_OS_WIN
1372 QFile::remove(wronlyFileName);
1374 #ifndef QT_NO_BEARERMANAGEMENT
1375 if (networkSession && networkSession->isOpen()) {
1376 networkSession->close();
1381 void tst_QNetworkReply::init()
1386 void tst_QNetworkReply::cleanup()
1388 QFile file(testFileName);
1389 QVERIFY(!file.exists() || file.remove());
1391 // clear the internal cache
1392 manager.clearAccessCache();
1393 manager.setProxy(QNetworkProxy());
1394 manager.setCache(0);
1397 cookieJar->setAllCookies(QList<QNetworkCookie>());
1400 void tst_QNetworkReply::stateChecking()
1402 QUrl url = QUrl("file:///");
1403 QNetworkRequest req(url); // you can't open this file, I know
1404 QNetworkReplyPtr reply = manager.get(req);
1406 QVERIFY(reply.data());
1407 QVERIFY(reply->isOpen());
1408 QVERIFY(reply->isReadable());
1409 QVERIFY(!reply->isWritable());
1411 // both behaviours are OK since we might change underlying behaviour again
1412 if (!reply->isFinished())
1413 QCOMPARE(reply->errorString(), QString("Unknown error"));
1415 QVERIFY(!reply->errorString().isEmpty());
1418 QCOMPARE(reply->manager(), &manager);
1419 QCOMPARE(reply->request(), req);
1420 QCOMPARE(int(reply->operation()), int(QNetworkAccessManager::GetOperation));
1421 // error and not error are OK since we might change underlying behaviour again
1422 if (!reply->isFinished())
1423 QCOMPARE(reply->error(), QNetworkReply::NoError);
1424 QCOMPARE(reply->url(), url);
1429 void tst_QNetworkReply::invalidProtocol()
1431 QUrl url = QUrl::fromEncoded("not-a-known-protocol://foo/bar");
1432 QNetworkRequest req(url);
1433 QNetworkReplyPtr reply;
1435 QString errorMsg = "Request failed: Protocol \"not-a-known-protocol\" is unknown";
1436 QString result = runSimpleRequest(QNetworkAccessManager::GetOperation, req, reply);
1437 QCOMPARE(result, errorMsg);
1439 QCOMPARE(reply->url(), url);
1440 QCOMPARE(reply->error(), QNetworkReply::ProtocolUnknownError);
1443 void tst_QNetworkReply::getFromData_data()
1445 QTest::addColumn<QString>("request");
1446 QTest::addColumn<QByteArray>("expected");
1447 QTest::addColumn<QString>("mimeType");
1449 const QString defaultMimeType("text/plain;charset=US-ASCII");
1451 //QTest::newRow("empty") << "data:" << QByteArray() << defaultMimeType;
1452 QTest::newRow("empty2") << "data:," << QByteArray() << defaultMimeType;
1453 QTest::newRow("just-charset_1") << "data:charset=iso-8859-1,"
1454 << QByteArray() << "text/plain;charset=iso-8859-1";
1455 QTest::newRow("just-charset_2") << "data:charset = iso-8859-1 ,"
1456 << QByteArray() << "text/plain;charset = iso-8859-1";
1457 //QTest::newRow("just-media") << "data:text/xml" << QByteArray() << "text/xml";
1458 QTest::newRow("just-media2") << "data:text/xml," << QByteArray() << "text/xml";
1460 QTest::newRow("plain_1") << "data:,foo" << QByteArray("foo") << defaultMimeType;
1461 QTest::newRow("plain_2") << "data:text/html,Hello World" << QByteArray("Hello World")
1463 QTest::newRow("plain_3") << "data:text/html;charset=utf-8,Hello World"
1464 << QByteArray("Hello World") << "text/html;charset=utf-8";
1466 QTest::newRow("pct_1") << "data:,%3Cbody%20contentEditable%3Dtrue%3E%0D%0A"
1467 << QByteArray("<body contentEditable=true>\r\n") << defaultMimeType;
1468 QTest::newRow("pct_2") << "data:text/html;charset=utf-8,%3Cbody%20contentEditable%3Dtrue%3E%0D%0A"
1469 << QByteArray("<body contentEditable=true>\r\n")
1470 << "text/html;charset=utf-8";
1472 QTest::newRow("base64-empty_1") << "data:;base64," << QByteArray() << defaultMimeType;
1473 QTest::newRow("base64-empty_2") << "data:charset=utf-8;base64," << QByteArray()
1474 << "text/plain;charset=utf-8";
1475 QTest::newRow("base64-empty_3") << "data:text/html;charset=utf-8;base64,"
1476 << QByteArray() << "text/html;charset=utf-8";
1478 QTest::newRow("base64_1") << "data:;base64,UXQgaXMgZ3JlYXQh" << QByteArray("Qt is great!")
1480 QTest::newRow("base64_2") << "data:charset=utf-8;base64,UXQgaXMgZ3JlYXQh"
1481 << QByteArray("Qt is great!") << "text/plain;charset=utf-8";
1482 QTest::newRow("base64_3") << "data:text/html;charset=utf-8;base64,UXQgaXMgZ3JlYXQh"
1483 << QByteArray("Qt is great!") << "text/html;charset=utf-8";
1485 QTest::newRow("pct-nul") << "data:,a%00g" << QByteArray("a\0g", 3) << defaultMimeType;
1486 QTest::newRow("base64-nul") << "data:;base64,YQBn" << QByteArray("a\0g", 3) << defaultMimeType;
1487 QTest::newRow("pct-nonutf8") << "data:,a%E1g" << QByteArray("a\xE1g", 3) << defaultMimeType;
1489 QTest::newRow("base64")
1490 << QString::fromLatin1("data:application/xml;base64,PGUvPg==")
1491 << QByteArray("<e/>")
1492 << "application/xml";
1494 QTest::newRow("base64, no media type")
1495 << QString::fromLatin1("data:;base64,PGUvPg==")
1496 << QByteArray("<e/>")
1499 QTest::newRow("Percent encoding")
1500 << QString::fromLatin1("data:application/xml,%3Ce%2F%3E")
1501 << QByteArray("<e/>")
1502 << "application/xml";
1504 QTest::newRow("Percent encoding, no media type")
1505 << QString::fromLatin1("data:,%3Ce%2F%3E")
1506 << QByteArray("<e/>")
1509 QTest::newRow("querychars")
1510 << QString::fromLatin1("data:,foo?x=0&y=0")
1511 << QByteArray("foo?x=0&y=0")
1514 QTest::newRow("css") << "data:text/css,div%20{%20border-right:%20solid;%20}"
1515 << QByteArray("div { border-right: solid; }")
1519 void tst_QNetworkReply::getFromData()
1521 QFETCH(QString, request);
1522 QFETCH(QByteArray, expected);
1523 QFETCH(QString, mimeType);
1525 QUrl url = QUrl::fromEncoded(request.toLatin1());
1526 QNetworkRequest req(url);
1527 QNetworkReplyPtr reply;
1529 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, req, reply));
1531 QCOMPARE(reply->url(), url);
1532 QCOMPARE(reply->error(), QNetworkReply::NoError);
1534 QCOMPARE(reply->header(QNetworkRequest::ContentTypeHeader).toString(), mimeType);
1535 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), qint64(expected.size()));
1536 QCOMPARE(reply->readAll(), expected);
1539 void tst_QNetworkReply::getFromFile()
1542 QTemporaryFile file(QDir::currentPath() + "/temp-XXXXXX");
1543 file.setAutoRemove(true);
1544 QVERIFY(file.open());
1546 QNetworkRequest request(QUrl::fromLocalFile(file.fileName()));
1547 QNetworkReplyPtr reply;
1549 static const char fileData[] = "This is some data that is in the file.\r\n";
1550 QByteArray data = QByteArray::fromRawData(fileData, sizeof fileData - 1);
1551 QVERIFY(file.write(data) == data.size());
1553 QCOMPARE(file.size(), qint64(data.size()));
1555 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
1557 QCOMPARE(reply->url(), request.url());
1558 QCOMPARE(reply->error(), QNetworkReply::NoError);
1560 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), file.size());
1561 QCOMPARE(reply->readAll(), data);
1563 // make the file bigger
1565 const int multiply = (128 * 1024) / (sizeof fileData - 1);
1566 for (int i = 0; i < multiply; ++i)
1567 file.write(fileData, sizeof fileData - 1);
1573 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
1574 QCOMPARE(reply->url(), request.url());
1575 QCOMPARE(reply->error(), QNetworkReply::NoError);
1577 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), file.size());
1578 QCOMPARE(qint64(reply->readAll().size()), file.size());
1581 void tst_QNetworkReply::getFromFileSpecial_data()
1583 QTest::addColumn<QString>("fileName");
1584 QTest::addColumn<QString>("url");
1586 QTest::newRow("resource") << ":/resource" << "qrc:/resource";
1587 QTest::newRow("search-path") << "testdata:/rfc3252.txt" << "testdata:/rfc3252.txt";
1588 QTest::newRow("bigfile-path") << "testdata:/bigfile" << "testdata:/bigfile";
1590 QTest::newRow("smb-path") << "testdata:/smb-file.txt" << "file://" + QtNetworkSettings::winServerName() + "/testshare/test.pri";
1594 void tst_QNetworkReply::getFromFileSpecial()
1596 QFETCH(QString, fileName);
1597 QFETCH(QString, url);
1599 // open the resource so we can find out its size
1600 QFile resource(fileName);
1601 QVERIFY(resource.open(QIODevice::ReadOnly));
1603 QNetworkRequest request;
1604 QNetworkReplyPtr reply;
1605 request.setUrl(url);
1606 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
1608 QCOMPARE(reply->url(), request.url());
1609 QCOMPARE(reply->error(), QNetworkReply::NoError);
1611 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), resource.size());
1612 QCOMPARE(reply->readAll(), resource.readAll());
1615 void tst_QNetworkReply::getFromFtp_data()
1617 QTest::addColumn<QString>("referenceName");
1618 QTest::addColumn<QString>("url");
1620 QTest::newRow("rfc3252.txt") << (testDataDir + "/rfc3252.txt") << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt";
1621 QTest::newRow("bigfile") << (testDataDir + "/bigfile") << "ftp://" + QtNetworkSettings::serverName() + "/qtest/bigfile";
1624 void tst_QNetworkReply::getFromFtp()
1626 QFETCH(QString, referenceName);
1627 QFETCH(QString, url);
1629 QFile reference(referenceName);
1630 QVERIFY(reference.open(QIODevice::ReadOnly));
1632 QNetworkRequest request(url);
1633 QNetworkReplyPtr reply;
1634 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
1636 QCOMPARE(reply->url(), request.url());
1637 QCOMPARE(reply->error(), QNetworkReply::NoError);
1639 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
1640 QCOMPARE(reply->readAll(), reference.readAll());
1643 void tst_QNetworkReply::getFromHttp_data()
1645 QTest::addColumn<QString>("referenceName");
1646 QTest::addColumn<QString>("url");
1648 QTest::newRow("success-internal") << (testDataDir + "/rfc3252.txt") << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt";
1649 QTest::newRow("success-external") << (testDataDir + "/rfc3252.txt") << "http://www.ietf.org/rfc/rfc3252.txt";
1650 QTest::newRow("bigfile-internal") << (testDataDir + "/bigfile") << "http://" + QtNetworkSettings::serverName() + "/qtest/bigfile";
1653 void tst_QNetworkReply::getFromHttp()
1655 QFETCH(QString, referenceName);
1656 QFETCH(QString, url);
1658 QFile reference(referenceName);
1659 QVERIFY(reference.open(QIODevice::ReadOnly));
1661 QNetworkRequest request(url);
1662 QNetworkReplyPtr reply;
1663 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
1665 QCOMPARE(reply->url(), request.url());
1666 QCOMPARE(reply->error(), QNetworkReply::NoError);
1667 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
1668 QCOMPARE(reply->size(), reference.size());
1669 // only compare when the header is set.
1670 if (reply->header(QNetworkRequest::ContentLengthHeader).isValid())
1671 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
1673 // We know our internal server is apache..
1674 if (qstrcmp(QTest::currentDataTag(), "success-internal") == 0)
1675 QVERIFY(reply->header(QNetworkRequest::ServerHeader).toString().contains("Apache"));
1677 QCOMPARE(reply->readAll(), reference.readAll());
1680 void tst_QNetworkReply::headFromHttp_data()
1682 QTest::addColumn<qint64>("referenceSize");
1683 QTest::addColumn<QUrl>("url");
1684 QTest::addColumn<QString>("contentType");
1685 QTest::addColumn<QNetworkProxy>("proxy");
1687 qint64 rfcsize = QFileInfo(testDataDir + "/rfc3252.txt").size();
1688 qint64 bigfilesize = QFileInfo(testDataDir + "/bigfile").size();
1689 qint64 indexsize = QFileInfo(testDataDir + "/index.html").size();
1691 //testing proxies, mainly for the 407 response from http proxy
1692 for (int i = 0; i < proxies.count(); ++i) {
1693 QTest::newRow("rfc" + proxies.at(i).tag) << rfcsize << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt") << "text/plain" << proxies.at(i).proxy;
1694 QTest::newRow("bigfile" + proxies.at(i).tag) << bigfilesize << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/bigfile") << "text/plain" << proxies.at(i).proxy;
1695 QTest::newRow("index" + proxies.at(i).tag) << indexsize << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/") << "text/html" << proxies.at(i).proxy;
1696 QTest::newRow("with-authentication" + proxies.at(i).tag) << rfcsize << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt") << "text/plain" << proxies.at(i).proxy;
1697 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;
1701 void tst_QNetworkReply::headFromHttp()
1703 QFETCH(qint64, referenceSize);
1705 QFETCH(QString, contentType);
1706 QFETCH(QNetworkProxy, proxy);
1708 QNetworkRequest request(url);
1709 QNetworkReplyPtr reply;
1714 manager.setProxy(proxy);
1715 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
1716 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
1717 connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
1718 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
1720 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::HeadOperation, request, reply));
1722 manager.disconnect(SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
1723 this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
1724 manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
1725 this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
1727 QVERIFY(time.elapsed() < 8000); //check authentication didn't wait for the server to timeout the http connection (15s on qt test server)
1729 QCOMPARE(reply->url(), request.url());
1730 QCOMPARE(reply->error(), QNetworkReply::NoError);
1731 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
1732 // only compare when the header is set.
1733 if (reply->header(QNetworkRequest::ContentLengthHeader).isValid() && referenceSize >= 0)
1734 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), referenceSize);
1735 if (reply->header(QNetworkRequest::ContentTypeHeader).isValid())
1736 QCOMPARE(reply->header(QNetworkRequest::ContentTypeHeader).toString(), contentType);
1739 void tst_QNetworkReply::getErrors_data()
1741 QTest::addColumn<QString>("url");
1742 QTest::addColumn<int>("error");
1743 QTest::addColumn<int>("httpStatusCode");
1744 QTest::addColumn<bool>("dataIsEmpty");
1747 QTest::newRow("empty-url") << QString() << int(QNetworkReply::ProtocolUnknownError) << 0 << true;
1748 QTest::newRow("empty-scheme-host") << (testDataDir + "/rfc3252.txt") << int(QNetworkReply::ProtocolUnknownError) << 0 << true;
1749 QTest::newRow("empty-scheme") << "//" + QtNetworkSettings::winServerName() + "/testshare/test.pri"
1750 << int(QNetworkReply::ProtocolUnknownError) << 0 << true;
1753 QTest::newRow("file-host") << "file://this-host-doesnt-exist.troll.no/foo.txt"
1754 #if !defined Q_OS_WIN
1755 << int(QNetworkReply::ProtocolInvalidOperationError) << 0 << true;
1757 << int(QNetworkReply::ContentNotFoundError) << 0 << true;
1759 QTest::newRow("file-no-path") << "file://localhost"
1760 << int(QNetworkReply::ContentOperationNotPermittedError) << 0 << true;
1761 QTest::newRow("file-is-dir") << QUrl::fromLocalFile(QDir::currentPath()).toString()
1762 << int(QNetworkReply::ContentOperationNotPermittedError) << 0 << true;
1763 QTest::newRow("file-exist") << QUrl::fromLocalFile(QDir::currentPath() + "/this-file-doesnt-exist.txt").toString()
1764 << int(QNetworkReply::ContentNotFoundError) << 0 << true;
1765 #if !defined Q_OS_WIN
1766 QTest::newRow("file-is-wronly") << QUrl::fromLocalFile(wronlyFileName).toString()
1767 << int(QNetworkReply::ContentAccessDenied) << 0 << true;
1769 if (QFile::exists("/etc/shadow"))
1770 QTest::newRow("file-permissions") << "file:/etc/shadow"
1771 << int(QNetworkReply::ContentAccessDenied) << 0 << true;
1774 QTest::newRow("ftp-host") << "ftp://this-host-doesnt-exist.troll.no/foo.txt"
1775 << int(QNetworkReply::HostNotFoundError) << 0 << true;
1776 QTest::newRow("ftp-no-path") << "ftp://" + QtNetworkSettings::serverName()
1777 << int(QNetworkReply::ContentOperationNotPermittedError) << 0 << true;
1778 QTest::newRow("ftp-is-dir") << "ftp://" + QtNetworkSettings::serverName() + "/qtest"
1779 << int(QNetworkReply::ContentOperationNotPermittedError) << 0 << true;
1780 QTest::newRow("ftp-dir-not-readable") << "ftp://" + QtNetworkSettings::serverName() + "/pub/dir-not-readable/foo.txt"
1781 << int(QNetworkReply::ContentAccessDenied) << 0 << true;
1782 QTest::newRow("ftp-file-not-readable") << "ftp://" + QtNetworkSettings::serverName() + "/pub/file-not-readable.txt"
1783 << int(QNetworkReply::ContentAccessDenied) << 0 << true;
1784 QTest::newRow("ftp-exist") << "ftp://" + QtNetworkSettings::serverName() + "/pub/this-file-doesnt-exist.txt"
1785 << int(QNetworkReply::ContentNotFoundError) << 0 << true;
1788 QTest::newRow("http-host") << "http://this-host-will-never-exist.troll.no/"
1789 << int(QNetworkReply::HostNotFoundError) << 0 << true;
1790 QTest::newRow("http-exist") << "http://" + QtNetworkSettings::serverName() + "/this-file-doesnt-exist.txt"
1791 << int(QNetworkReply::ContentNotFoundError) << 404 << false;
1792 QTest::newRow("http-authentication") << "http://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth"
1793 << int(QNetworkReply::AuthenticationRequiredError) << 401 << false;
1796 void tst_QNetworkReply::getErrors()
1798 QFETCH(QString, url);
1799 QNetworkRequest request(url);
1802 if ((qstrcmp(QTest::currentDataTag(), "file-is-wronly") == 0) ||
1803 (qstrcmp(QTest::currentDataTag(), "file-permissions") == 0)) {
1804 if (::getuid() == 0)
1805 QSKIP("Running this test as root doesn't make sense");
1809 QNetworkReplyPtr reply = manager.get(request);
1810 reply->setParent(this); // we have expect-fails
1812 if (!reply->isFinished())
1813 QCOMPARE(reply->error(), QNetworkReply::NoError);
1815 // now run the request:
1816 QVERIFY(waitForFinish(reply) != Timeout);
1819 QEXPECT_FAIL("ftp-is-dir", "QFtp cannot provide enough detail", Abort);
1820 // the line below is not necessary
1821 QEXPECT_FAIL("ftp-dir-not-readable", "QFtp cannot provide enough detail", Abort);
1822 QCOMPARE(reply->error(), QNetworkReply::NetworkError(error));
1824 QTEST(reply->readAll().isEmpty(), "dataIsEmpty");
1826 QVERIFY(reply->isFinished());
1827 QVERIFY(!reply->isRunning());
1829 QFETCH(int, httpStatusCode);
1830 if (httpStatusCode != 0) {
1831 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), httpStatusCode);
1835 static inline QByteArray md5sum(const QByteArray &data)
1837 return QCryptographicHash::hash(data, QCryptographicHash::Md5);
1840 void tst_QNetworkReply::putToFile_data()
1842 QTest::addColumn<QByteArray>("data");
1843 QTest::addColumn<QByteArray>("md5sum");
1847 QTest::newRow("empty") << data << md5sum(data);
1849 data = "This is a normal message.";
1850 QTest::newRow("generic") << data << md5sum(data);
1852 data = "This is a message to show that Qt rocks!\r\n\n";
1853 QTest::newRow("small") << data << md5sum(data);
1855 data = QByteArray("abcd\0\1\2\abcd",12);
1856 QTest::newRow("with-nul") << data << md5sum(data);
1858 data = QByteArray(4097, '\4');
1859 QTest::newRow("4k+1") << data << md5sum(data);
1861 data = QByteArray(128*1024+1, '\177');
1862 QTest::newRow("128k+1") << data << md5sum(data);
1864 data = QByteArray(2*1024*1024+1, '\177');
1865 QTest::newRow("2MB+1") << data << md5sum(data);
1868 void tst_QNetworkReply::putToFile()
1870 QFile file(testFileName);
1872 QUrl url = QUrl::fromLocalFile(file.fileName());
1873 QNetworkRequest request(url);
1874 QNetworkReplyPtr reply;
1876 QFETCH(QByteArray, data);
1878 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PutOperation, request, reply, data));
1880 QCOMPARE(reply->url(), url);
1881 QCOMPARE(reply->error(), QNetworkReply::NoError);
1882 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
1883 QVERIFY(reply->readAll().isEmpty());
1885 QVERIFY(file.open(QIODevice::ReadOnly));
1886 QCOMPARE(file.size(), qint64(data.size()));
1887 QByteArray contents = file.readAll();
1888 QCOMPARE(contents, data);
1891 void tst_QNetworkReply::putToFtp_data()
1896 void tst_QNetworkReply::putToFtp()
1898 QUrl url("ftp://" + QtNetworkSettings::serverName());
1899 url.setPath(QString("/qtest/upload/qnetworkaccess-putToFtp-%1-%2")
1900 .arg(QTest::currentDataTag())
1901 .arg(uniqueExtension));
1903 QNetworkRequest request(url);
1904 QNetworkReplyPtr reply;
1906 QFETCH(QByteArray, data);
1908 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PutOperation, request, reply, data));
1910 QCOMPARE(reply->url(), url);
1911 QCOMPARE(reply->error(), QNetworkReply::NoError);
1912 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
1913 QVERIFY(reply->readAll().isEmpty());
1915 // download the file again from FTP to make sure it was uploaded
1917 QNetworkAccessManager qnam;
1918 QNetworkRequest req(url);
1919 QNetworkReply *r = qnam.get(req);
1921 QObject::connect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
1923 QSignalSpy spy(r, SIGNAL(downloadProgress(qint64,qint64)));
1924 while (!r->isFinished()) {
1925 QTestEventLoop::instance().enterLoop(10);
1926 if (count == spy.count() && !r->isFinished())
1928 count = spy.count();
1930 QObject::disconnect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
1932 QByteArray uploaded = r->readAll();
1933 QCOMPARE(uploaded.size(), data.size());
1934 QCOMPARE(uploaded, data);
1937 QObject::connect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
1938 QTestEventLoop::instance().enterLoop(10);
1939 QObject::disconnect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
1942 void tst_QNetworkReply::putToHttp_data()
1947 void tst_QNetworkReply::putToHttp()
1949 QUrl url("http://" + QtNetworkSettings::serverName());
1950 url.setPath(QString("/dav/qnetworkaccess-putToHttp-%1-%2")
1951 .arg(QTest::currentDataTag())
1952 .arg(uniqueExtension));
1954 QNetworkRequest request(url);
1955 QNetworkReplyPtr reply;
1957 QFETCH(QByteArray, data);
1959 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PutOperation, request, reply, data));
1961 QCOMPARE(reply->url(), url);
1962 QCOMPARE(reply->error(), QNetworkReply::NoError);
1964 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 201); // 201 Created
1966 // download the file again from HTTP to make sure it was uploaded
1967 // correctly. HTTP/0.9 is enough
1969 socket.connectToHost(QtNetworkSettings::serverName(), 80);
1970 socket.write("GET " + url.toEncoded(QUrl::RemoveScheme | QUrl::RemoveAuthority) + "\r\n");
1971 if (!socket.waitForDisconnected(10000))
1972 QFAIL("Network timeout");
1974 QByteArray uploadedData = socket.readAll();
1975 QCOMPARE(uploadedData, data);
1978 void tst_QNetworkReply::putToHttpSynchronous_data()
1980 uniqueExtension = createUniqueExtension();
1984 void tst_QNetworkReply::putToHttpSynchronous()
1986 QUrl url("http://" + QtNetworkSettings::serverName());
1987 url.setPath(QString("/dav/qnetworkaccess-putToHttp-%1-%2")
1988 .arg(QTest::currentDataTag())
1989 .arg(uniqueExtension));
1991 QNetworkRequest request(url);
1992 QNetworkReplyPtr reply;
1994 QFETCH(QByteArray, data);
1996 request.setAttribute(
1997 QNetworkRequest::SynchronousRequestAttribute,
2000 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PutOperation, request, reply, data));
2002 QCOMPARE(reply->url(), url);
2003 QCOMPARE(reply->error(), QNetworkReply::NoError);
2005 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 201); // 201 Created
2007 // download the file again from HTTP to make sure it was uploaded
2008 // correctly. HTTP/0.9 is enough
2010 socket.connectToHost(QtNetworkSettings::serverName(), 80);
2011 socket.write("GET " + url.toEncoded(QUrl::RemoveScheme | QUrl::RemoveAuthority) + "\r\n");
2012 if (!socket.waitForDisconnected(10000))
2013 QFAIL("Network timeout");
2015 QByteArray uploadedData = socket.readAll();
2016 QCOMPARE(uploadedData, data);
2019 void tst_QNetworkReply::postToHttp_data()
2024 void tst_QNetworkReply::postToHttp()
2026 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi");
2028 QNetworkRequest request(url);
2029 request.setRawHeader("Content-Type", "application/octet-stream");
2030 QNetworkReplyPtr reply;
2032 QFETCH(QByteArray, data);
2034 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PostOperation, request, reply, data));
2036 QCOMPARE(reply->url(), url);
2037 QCOMPARE(reply->error(), QNetworkReply::NoError);
2039 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
2041 QFETCH(QByteArray, md5sum);
2042 QByteArray uploadedData = reply->readAll().trimmed();
2043 QCOMPARE(uploadedData, md5sum.toHex());
2046 void tst_QNetworkReply::postToHttpSynchronous_data()
2051 void tst_QNetworkReply::postToHttpSynchronous()
2053 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi");
2055 QNetworkRequest request(url);
2056 request.setRawHeader("Content-Type", "application/octet-stream");
2058 request.setAttribute(
2059 QNetworkRequest::SynchronousRequestAttribute,
2062 QNetworkReplyPtr reply;
2064 QFETCH(QByteArray, data);
2066 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PostOperation, request, reply, data));
2068 QCOMPARE(reply->url(), url);
2069 QCOMPARE(reply->error(), QNetworkReply::NoError);
2071 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
2073 QFETCH(QByteArray, md5sum);
2074 QByteArray uploadedData = reply->readAll().trimmed();
2075 QCOMPARE(uploadedData, md5sum.toHex());
2078 void tst_QNetworkReply::postToHttpMultipart_data()
2080 QTest::addColumn<QUrl>("url");
2081 QTest::addColumn<QHttpMultiPart *>("multiPart");
2082 QTest::addColumn<QByteArray>("expectedReplyData");
2083 QTest::addColumn<QByteArray>("contentType");
2085 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/multipart.cgi");
2086 QByteArray expectedData;
2091 QHttpMultiPart *emptyMultiPart = new QHttpMultiPart;
2092 QTest::newRow("empty") << url << emptyMultiPart << expectedData << QByteArray("mixed");
2094 QHttpMultiPart *emptyRelatedMultiPart = new QHttpMultiPart;
2095 emptyRelatedMultiPart->setContentType(QHttpMultiPart::RelatedType);
2096 QTest::newRow("empty-related") << url << emptyRelatedMultiPart << expectedData << QByteArray("related");
2098 QHttpMultiPart *emptyAlternativeMultiPart = new QHttpMultiPart;
2099 emptyAlternativeMultiPart->setContentType(QHttpMultiPart::AlternativeType);
2100 QTest::newRow("empty-alternative") << url << emptyAlternativeMultiPart << expectedData << QByteArray("alternative");
2106 textPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain"));
2107 textPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"text\""));
2108 textPart.setBody("7 bytes");
2109 QHttpMultiPart *multiPart1 = new QHttpMultiPart;
2110 multiPart1->setContentType(QHttpMultiPart::FormDataType);
2111 multiPart1->append(textPart);
2112 expectedData = "key: text, value: 7 bytes\n";
2113 QTest::newRow("text") << url << multiPart1 << expectedData << QByteArray("form-data");
2115 QHttpMultiPart *customMultiPart = new QHttpMultiPart;
2116 customMultiPart->append(textPart);
2117 expectedData = "header: Content-Type, value: 'text/plain'\n"
2118 "header: Content-Disposition, value: 'form-data; name=\"text\"'\n"
2119 "content: 7 bytes\n"
2121 QTest::newRow("text-custom") << url << customMultiPart << expectedData << QByteArray("custom");
2123 QHttpPart textPart2;
2124 textPart2.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain"));
2125 textPart2.setRawHeader("myRawHeader", "myValue");
2126 textPart2.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"text2\""));
2127 textPart2.setBody("some more bytes");
2128 textPart2.setBodyDevice((QIODevice *) 1); // test whether setting and unsetting of the device works
2129 textPart2.setBodyDevice(0);
2130 QHttpMultiPart *multiPart2 = new QHttpMultiPart;
2131 multiPart2->setContentType(QHttpMultiPart::FormDataType);
2132 multiPart2->append(textPart);
2133 multiPart2->append(textPart2);
2134 expectedData = "key: text2, value: some more bytes\n"
2135 "key: text, value: 7 bytes\n";
2136 QTest::newRow("text-text") << url << multiPart2 << expectedData << QByteArray("form-data");
2139 QHttpPart textPart3;
2140 textPart3.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain"));
2141 textPart3.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"text3\""));
2142 textPart3.setRawHeader("Content-Location", "http://my.test.location.tld");
2143 textPart3.setBody("even more bytes");
2144 QHttpMultiPart *multiPart3 = new QHttpMultiPart;
2145 multiPart3->setContentType(QHttpMultiPart::AlternativeType);
2146 multiPart3->append(textPart);
2147 multiPart3->append(textPart2);
2148 multiPart3->append(textPart3);
2149 expectedData = "header: Content-Type, value: 'text/plain'\n"
2150 "header: Content-Disposition, value: 'form-data; name=\"text\"'\n"
2151 "content: 7 bytes\n"
2153 "header: Content-Type, value: 'text/plain'\n"
2154 "header: myRawHeader, value: 'myValue'\n"
2155 "header: Content-Disposition, value: 'form-data; name=\"text2\"'\n"
2156 "content: some more bytes\n"
2158 "header: Content-Type, value: 'text/plain'\n"
2159 "header: Content-Disposition, value: 'form-data; name=\"text3\"'\n"
2160 "header: Content-Location, value: 'http://my.test.location.tld'\n"
2161 "content: even more bytes\n\n";
2162 QTest::newRow("text-text-text") << url << multiPart3 << expectedData << QByteArray("alternative");
2166 // text and image parts
2168 QHttpPart imagePart11;
2169 imagePart11.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
2170 imagePart11.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage\""));
2171 imagePart11.setRawHeader("Content-Location", "http://my.test.location.tld");
2172 imagePart11.setRawHeader("Content-ID", "my@id.tld");
2173 QFile *file11 = new QFile(testDataDir + "/image1.jpg");
2174 file11->open(QIODevice::ReadOnly);
2175 imagePart11.setBodyDevice(file11);
2176 QHttpMultiPart *imageMultiPart1 = new QHttpMultiPart(QHttpMultiPart::FormDataType);
2177 imageMultiPart1->append(imagePart11);
2178 file11->setParent(imageMultiPart1);
2179 expectedData = "key: testImage, value: 87ef3bb319b004ba9e5e9c9fa713776e\n"; // md5 sum of file
2180 QTest::newRow("image") << url << imageMultiPart1 << expectedData << QByteArray("form-data");
2182 QHttpPart imagePart21;
2183 imagePart21.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
2184 imagePart21.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage1\""));
2185 imagePart21.setRawHeader("Content-Location", "http://my.test.location.tld");
2186 imagePart21.setRawHeader("Content-ID", "my@id.tld");
2187 QFile *file21 = new QFile(testDataDir + "/image1.jpg");
2188 file21->open(QIODevice::ReadOnly);
2189 imagePart21.setBodyDevice(file21);
2190 QHttpMultiPart *imageMultiPart2 = new QHttpMultiPart();
2191 imageMultiPart2->setContentType(QHttpMultiPart::FormDataType);
2192 imageMultiPart2->append(textPart);
2193 imageMultiPart2->append(imagePart21);
2194 file21->setParent(imageMultiPart2);
2195 QHttpPart imagePart22;
2196 imagePart22.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
2197 imagePart22.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage2\""));
2198 QFile *file22 = new QFile(testDataDir + "/image2.jpg");
2199 file22->open(QIODevice::ReadOnly);
2200 imagePart22.setBodyDevice(file22);
2201 imageMultiPart2->append(imagePart22);
2202 file22->setParent(imageMultiPart2);
2203 expectedData = "key: testImage1, value: 87ef3bb319b004ba9e5e9c9fa713776e\n"
2204 "key: text, value: 7 bytes\n"
2205 "key: testImage2, value: 483761b893f7fb1bd2414344cd1f3dfb\n";
2206 QTest::newRow("text-image-image") << url << imageMultiPart2 << expectedData << QByteArray("form-data");
2209 QHttpPart imagePart31;
2210 imagePart31.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
2211 imagePart31.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage1\""));
2212 imagePart31.setRawHeader("Content-Location", "http://my.test.location.tld");
2213 imagePart31.setRawHeader("Content-ID", "my@id.tld");
2214 QFile *file31 = new QFile(testDataDir + "/image1.jpg");
2215 file31->open(QIODevice::ReadOnly);
2216 imagePart31.setBodyDevice(file31);
2217 QHttpMultiPart *imageMultiPart3 = new QHttpMultiPart(QHttpMultiPart::FormDataType);
2218 imageMultiPart3->append(imagePart31);
2219 file31->setParent(imageMultiPart3);
2220 QHttpPart imagePart32;
2221 imagePart32.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
2222 imagePart32.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage2\""));
2223 QFile *file32 = new QFile(testDataDir + "/image2.jpg");
2224 file32->open(QIODevice::ReadOnly);
2225 imagePart32.setBodyDevice(file31); // check that resetting works
2226 imagePart32.setBodyDevice(file32);
2227 imageMultiPart3->append(imagePart32);
2228 file32->setParent(imageMultiPart3);
2229 QHttpPart imagePart33;
2230 imagePart33.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
2231 imagePart33.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage3\""));
2232 QFile *file33 = new QFile(testDataDir + "/image3.jpg");
2233 file33->open(QIODevice::ReadOnly);
2234 imagePart33.setBodyDevice(file33);
2235 imageMultiPart3->append(imagePart33);
2236 file33->setParent(imageMultiPart3);
2237 expectedData = "key: testImage1, value: 87ef3bb319b004ba9e5e9c9fa713776e\n"
2238 "key: testImage2, value: 483761b893f7fb1bd2414344cd1f3dfb\n"
2239 "key: testImage3, value: ab0eb6fd4fcf8b4436254870b4513033\n";
2240 QTest::newRow("3-images") << url << imageMultiPart3 << expectedData << QByteArray("form-data");
2243 // note: nesting multiparts is not working currently; for that, the outputDevice would need to be public
2245 // QHttpPart imagePart41;
2246 // imagePart41.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
2247 // QFile *file41 = new QFile(testDataDir + "/image1.jpg");
2248 // file41->open(QIODevice::ReadOnly);
2249 // imagePart41.setBodyDevice(file41);
2251 // QHttpMultiPart *innerMultiPart = new QHttpMultiPart();
2252 // innerMultiPart->setContentType(QHttpMultiPart::FormDataType);
2253 // textPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant());
2254 // innerMultiPart->append(textPart);
2255 // innerMultiPart->append(imagePart41);
2256 // textPart2.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant());
2257 // innerMultiPart->append(textPart2);
2259 // QHttpPart nestedPart;
2260 // nestedPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"nestedMessage"));
2261 // nestedPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("multipart/alternative; boundary=\"" + innerMultiPart->boundary() + "\""));
2262 // innerMultiPart->outputDevice()->open(QIODevice::ReadOnly);
2263 // nestedPart.setBodyDevice(innerMultiPart->outputDevice());
2265 // QHttpMultiPart *outerMultiPart = new QHttpMultiPart;
2266 // outerMultiPart->setContentType(QHttpMultiPart::FormDataType);
2267 // outerMultiPart->append(textPart);
2268 // outerMultiPart->append(nestedPart);
2269 // outerMultiPart->append(textPart2);
2270 // expectedData = "nothing"; // the CGI.pm module running on the test server does not understand nested multiparts
2271 // openFiles.clear();
2272 // openFiles << file41;
2273 // QTest::newRow("nested") << url << outerMultiPart << expectedData << openFiles;
2276 // test setting large chunks of content with a byte array instead of a device (DISCOURAGED because of high memory consumption,
2277 // but we need to test that the behavior is correct)
2278 QHttpPart imagePart51;
2279 imagePart51.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
2280 imagePart51.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage\""));
2281 QFile *file51 = new QFile(testDataDir + "/image1.jpg");
2282 file51->open(QIODevice::ReadOnly);
2283 QByteArray imageData = file51->readAll();
2286 imagePart51.setBody("7 bytes"); // check that resetting works
2287 imagePart51.setBody(imageData);
2288 QHttpMultiPart *imageMultiPart5 = new QHttpMultiPart;
2289 imageMultiPart5->setContentType(QHttpMultiPart::FormDataType);
2290 imageMultiPart5->append(imagePart51);
2291 expectedData = "key: testImage, value: 87ef3bb319b004ba9e5e9c9fa713776e\n"; // md5 sum of file
2292 QTest::newRow("image-as-content") << url << imageMultiPart5 << expectedData << QByteArray("form-data");
2295 void tst_QNetworkReply::postToHttpMultipart()
2299 static QSet<QByteArray> boundaries;
2301 QNetworkRequest request(url);
2302 QNetworkReplyPtr reply;
2304 QFETCH(QHttpMultiPart *, multiPart);
2305 QFETCH(QByteArray, expectedReplyData);
2306 QFETCH(QByteArray, contentType);
2308 // hack for testing the setting of the content-type header by hand:
2309 if (contentType == "custom") {
2310 QByteArray contentType("multipart/custom; boundary=\"" + multiPart->boundary() + "\"");
2311 request.setHeader(QNetworkRequest::ContentTypeHeader, contentType);
2314 QVERIFY2(! boundaries.contains(multiPart->boundary()), "boundary '" + multiPart->boundary() + "' has been created twice");
2315 boundaries.insert(multiPart->boundary());
2317 RUN_REQUEST(runMultipartRequest(request, reply, multiPart, "POST"));
2318 multiPart->deleteLater();
2320 QCOMPARE(reply->url(), url);
2321 QCOMPARE(reply->error(), QNetworkReply::NoError);
2323 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
2325 QVERIFY(multiPart->boundary().count() > 20); // check that there is randomness after the "boundary_.oOo._" string
2326 QVERIFY(multiPart->boundary().count() < 70);
2327 QByteArray replyData = reply->readAll();
2329 expectedReplyData.prepend("content type: multipart/" + contentType + "; boundary=\"" + multiPart->boundary() + "\"\n");
2330 // QEXPECT_FAIL("nested", "the server does not understand nested multipart messages", Continue); // see above
2331 QCOMPARE(replyData, expectedReplyData);
2334 void tst_QNetworkReply::putToHttpMultipart_data()
2336 postToHttpMultipart_data();
2339 void tst_QNetworkReply::putToHttpMultipart()
2341 QSKIP("test server script cannot handle PUT data yet");
2344 static QSet<QByteArray> boundaries;
2346 QNetworkRequest request(url);
2347 QNetworkReplyPtr reply;
2349 QFETCH(QHttpMultiPart *, multiPart);
2350 QFETCH(QByteArray, expectedReplyData);
2351 QFETCH(QByteArray, contentType);
2353 // hack for testing the setting of the content-type header by hand:
2354 if (contentType == "custom") {
2355 QByteArray contentType("multipart/custom; boundary=\"" + multiPart->boundary() + "\"");
2356 request.setHeader(QNetworkRequest::ContentTypeHeader, contentType);
2359 QVERIFY2(! boundaries.contains(multiPart->boundary()), "boundary '" + multiPart->boundary() + "' has been created twice");
2360 boundaries.insert(multiPart->boundary());
2362 RUN_REQUEST(runMultipartRequest(request, reply, multiPart, "PUT"));
2363 multiPart->deleteLater();
2365 QCOMPARE(reply->url(), url);
2366 QCOMPARE(reply->error(), QNetworkReply::NoError);
2368 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
2370 QVERIFY(multiPart->boundary().count() > 20); // check that there is randomness after the "boundary_.oOo._" string
2371 QVERIFY(multiPart->boundary().count() < 70);
2372 QByteArray replyData = reply->readAll();
2374 expectedReplyData.prepend("content type: multipart/" + contentType + "; boundary=\"" + multiPart->boundary() + "\"\n");
2375 // QEXPECT_FAIL("nested", "the server does not understand nested multipart messages", Continue); // see above
2376 QCOMPARE(replyData, expectedReplyData);
2379 void tst_QNetworkReply::deleteFromHttp_data()
2381 QTest::addColumn<QUrl>("url");
2382 QTest::addColumn<int>("resultCode");
2383 QTest::addColumn<QNetworkReply::NetworkError>("error");
2385 // for status codes to expect, see http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
2387 QTest::newRow("405-method-not-allowed") << QUrl("http://" + QtNetworkSettings::serverName() + "/index.html") << 405 << QNetworkReply::ContentOperationNotPermittedError;
2388 QTest::newRow("200-ok") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/http-delete.cgi?200-ok") << 200 << QNetworkReply::NoError;
2389 QTest::newRow("202-accepted") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/http-delete.cgi?202-accepted") << 202 << QNetworkReply::NoError;
2390 QTest::newRow("204-no-content") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/http-delete.cgi?204-no-content") << 204 << QNetworkReply::NoError;
2391 QTest::newRow("404-not-found") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/http-delete.cgi?404-not-found") << 404 << QNetworkReply::ContentNotFoundError;
2394 void tst_QNetworkReply::deleteFromHttp()
2397 QFETCH(int, resultCode);
2398 QFETCH(QNetworkReply::NetworkError, error);
2399 QNetworkRequest request(url);
2400 QNetworkReplyPtr reply;
2401 runSimpleRequest(QNetworkAccessManager::DeleteOperation, request, reply, 0);
2402 QCOMPARE(reply->url(), url);
2403 QCOMPARE(reply->error(), error);
2404 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), resultCode);
2407 void tst_QNetworkReply::putGetDeleteGetFromHttp_data()
2409 QTest::addColumn<QUrl>("putUrl");
2410 QTest::addColumn<int>("putResultCode");
2411 QTest::addColumn<QNetworkReply::NetworkError>("putError");
2412 QTest::addColumn<QUrl>("deleteUrl");
2413 QTest::addColumn<int>("deleteResultCode");
2414 QTest::addColumn<QNetworkReply::NetworkError>("deleteError");
2415 QTest::addColumn<QUrl>("get2Url");
2416 QTest::addColumn<int>("get2ResultCode");
2417 QTest::addColumn<QNetworkReply::NetworkError>("get2Error");
2419 QUrl url("http://" + QtNetworkSettings::serverName());
2420 url.setPath(QString("/dav/qnetworkaccess-putToHttp-%1-%2")
2421 .arg(QTest::currentDataTag())
2422 .arg(uniqueExtension));
2424 // first use case: put, get (to check it is there), delete, get (to check it is not there anymore)
2425 QTest::newRow("success") << url << 201 << QNetworkReply::NoError << url << 204 << QNetworkReply::NoError << url << 404 << QNetworkReply::ContentNotFoundError;
2427 QUrl wrongUrl("http://" + QtNetworkSettings::serverName());
2428 wrongUrl.setPath(QString("/dav/qnetworkaccess-thisURLisNotAvailable"));
2430 // second use case: put, get (to check it is there), delete wrong URL, get (to check it is still there)
2431 QTest::newRow("delete-error") << url << 201 << QNetworkReply::NoError << wrongUrl << 404 << QNetworkReply::ContentNotFoundError << url << 200 << QNetworkReply::NoError;
2435 void tst_QNetworkReply::putGetDeleteGetFromHttp()
2437 QFETCH(QUrl, putUrl);
2438 QFETCH(int, putResultCode);
2439 QFETCH(QNetworkReply::NetworkError, putError);
2440 QFETCH(QUrl, deleteUrl);
2441 QFETCH(int, deleteResultCode);
2442 QFETCH(QNetworkReply::NetworkError, deleteError);
2443 QFETCH(QUrl, get2Url);
2444 QFETCH(int, get2ResultCode);
2445 QFETCH(QNetworkReply::NetworkError, get2Error);
2447 QNetworkRequest putRequest(putUrl);
2448 QNetworkRequest deleteRequest(deleteUrl);
2449 QNetworkRequest get2Request(get2Url);
2450 QNetworkReplyPtr reply;
2452 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PutOperation, putRequest, reply, 0));
2453 QCOMPARE(reply->error(), putError);
2454 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), putResultCode);
2456 runSimpleRequest(QNetworkAccessManager::GetOperation, putRequest, reply, 0);
2457 QCOMPARE(reply->error(), QNetworkReply::NoError);
2458 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2460 runSimpleRequest(QNetworkAccessManager::DeleteOperation, deleteRequest, reply, 0);
2461 QCOMPARE(reply->error(), deleteError);
2462 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), deleteResultCode);
2464 runSimpleRequest(QNetworkAccessManager::GetOperation, get2Request, reply, 0);
2465 QCOMPARE(reply->error(), get2Error);
2466 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), get2ResultCode);
2470 void tst_QNetworkReply::connectToIPv6Address_data()
2472 QTest::addColumn<QUrl>("url");
2473 QTest::addColumn<QNetworkReply::NetworkError>("error");
2474 QTest::addColumn<QByteArray>("dataToSend");
2475 QTest::addColumn<QByteArray>("hostfield");
2476 QTest::newRow("localhost") << QUrl(QByteArray("http://[::1]")) << QNetworkReply::NoError<< QByteArray("localhost") << QByteArray("[::1]");
2477 //QTest::newRow("ipv4localhost") << QUrl(QByteArray("http://127.0.0.1")) << QNetworkReply::NoError<< QByteArray("ipv4localhost") << QByteArray("127.0.0.1");
2478 //to add more test data here
2481 void tst_QNetworkReply::connectToIPv6Address()
2484 QFETCH(QNetworkReply::NetworkError, error);
2485 QFETCH(QByteArray, dataToSend);
2486 QFETCH(QByteArray, hostfield);
2488 #if !defined(HAVE_IPV6) && defined(Q_OS_UNIX)
2489 QSKIP("system doesn't support ipv6!");
2492 QByteArray httpResponse = QByteArray("HTTP/1.0 200 OK\r\nContent-Length: ");
2493 httpResponse += QByteArray::number(dataToSend.size());
2494 httpResponse += "\r\n\r\n";
2495 httpResponse += dataToSend;
2497 MiniHttpServer server(httpResponse, false, NULL/*thread*/, true/*useipv6*/);
2498 server.doClose = true;
2500 url.setPort(server.serverPort());
2501 QNetworkRequest request(url);
2503 QNetworkReplyPtr reply = manager.get(request);
2504 QVERIFY(waitForFinish(reply) == Success);
2505 QByteArray content = reply->readAll();
2506 //qDebug() << server.receivedData;
2507 QByteArray hostinfo = "\r\nHost: " + hostfield + ":" + QByteArray::number(server.serverPort()) + "\r\n";
2508 QVERIFY(server.receivedData.contains(hostinfo));
2509 QVERIFY(content == dataToSend);
2510 QCOMPARE(reply->url(), request.url());
2511 QVERIFY(reply->error() == error);
2514 void tst_QNetworkReply::sendCustomRequestToHttp_data()
2516 QTest::addColumn<QUrl>("url");
2517 QTest::addColumn<QByteArray>("verb");
2518 QTest::addColumn<QBuffer *>("device");
2519 QTest::addColumn<int>("resultCode");
2520 QTest::addColumn<QNetworkReply::NetworkError>("error");
2521 QTest::addColumn<QByteArray>("expectedContent");
2523 QTest::newRow("options") << QUrl("http://" + QtNetworkSettings::serverName()) <<
2524 QByteArray("OPTIONS") << (QBuffer *) 0 << 200 << QNetworkReply::NoError << QByteArray();
2525 QTest::newRow("trace") << QUrl("http://" + QtNetworkSettings::serverName()) <<
2526 QByteArray("TRACE") << (QBuffer *) 0 << 200 << QNetworkReply::NoError << QByteArray();
2527 QTest::newRow("connect") << QUrl("http://" + QtNetworkSettings::serverName()) <<
2528 QByteArray("CONNECT") << (QBuffer *) 0 << 400 << QNetworkReply::UnknownContentError << QByteArray(); // 400 = Bad Request
2529 QTest::newRow("nonsense") << QUrl("http://" + QtNetworkSettings::serverName()) <<
2530 QByteArray("NONSENSE") << (QBuffer *) 0 << 501 << QNetworkReply::ProtocolUnknownError << QByteArray(); // 501 = Method Not Implemented
2532 QByteArray ba("test");
2533 QBuffer *buffer = new QBuffer;
2534 buffer->setData(ba);
2535 buffer->open(QIODevice::ReadOnly);
2536 QTest::newRow("post") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi") << QByteArray("POST")
2537 << buffer << 200 << QNetworkReply::NoError << QByteArray("098f6bcd4621d373cade4e832627b4f6\n");
2539 QByteArray ba2("test");
2540 QBuffer *buffer2 = new QBuffer;
2541 buffer2->setData(ba2);
2542 buffer2->open(QIODevice::ReadOnly);
2543 QTest::newRow("put") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi") << QByteArray("PUT")
2544 << buffer2 << 200 << QNetworkReply::NoError << QByteArray("098f6bcd4621d373cade4e832627b4f6\n");
2547 void tst_QNetworkReply::sendCustomRequestToHttp()
2550 QNetworkRequest request(url);
2551 QNetworkReplyPtr reply;
2552 QFETCH(QByteArray, verb);
2553 QFETCH(QBuffer *, device);
2554 runCustomRequest(request, reply, verb, device);
2555 QCOMPARE(reply->url(), url);
2556 QFETCH(QNetworkReply::NetworkError, error);
2557 QCOMPARE(reply->error(), error);
2558 QFETCH(int, resultCode);
2559 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), resultCode);
2560 QFETCH(QByteArray, expectedContent);
2561 if (! expectedContent.isEmpty())
2562 QCOMPARE(reply->readAll(), expectedContent);
2565 void tst_QNetworkReply::ioGetFromData_data()
2567 QTest::addColumn<QString>("urlStr");
2568 QTest::addColumn<QByteArray>("data");
2570 QTest::newRow("data-empty") << "data:," << QByteArray();
2571 QTest::newRow("data-literal") << "data:,foo" << QByteArray("foo");
2572 QTest::newRow("data-pct") << "data:,%3Cbody%20contentEditable%3Dtrue%3E%0D%0A"
2573 << QByteArray("<body contentEditable=true>\r\n");
2574 QTest::newRow("data-base64") << "data:;base64,UXQgaXMgZ3JlYXQh" << QByteArray("Qt is great!");
2577 void tst_QNetworkReply::ioGetFromData()
2579 QFETCH(QString, urlStr);
2581 QUrl url = QUrl::fromEncoded(urlStr.toLatin1());
2582 QNetworkRequest request(url);
2584 QNetworkReplyPtr reply = manager.get(request);
2585 DataReader reader(reply);
2587 connect(reply, SIGNAL(finished()),
2588 &QTestEventLoop::instance(), SLOT(exitLoop()));
2589 QTestEventLoop::instance().enterLoop(10);
2590 QVERIFY(!QTestEventLoop::instance().timeout());
2592 QCOMPARE(reply->url(), request.url());
2593 QCOMPARE(reply->error(), QNetworkReply::NoError);
2595 QFETCH(QByteArray, data);
2596 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toInt(), data.size());
2597 QCOMPARE(reader.data.size(), data.size());
2598 QCOMPARE(reader.data, data);
2601 void tst_QNetworkReply::ioGetFromFileSpecial_data()
2603 getFromFileSpecial_data();
2606 void tst_QNetworkReply::ioGetFromFileSpecial()
2608 QFETCH(QString, fileName);
2609 QFETCH(QString, url);
2611 QFile resource(fileName);
2612 QVERIFY(resource.open(QIODevice::ReadOnly));
2614 QNetworkRequest request;
2615 request.setUrl(url);
2616 QNetworkReplyPtr reply = manager.get(request);
2617 DataReader reader(reply);
2619 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
2620 QTestEventLoop::instance().enterLoop(10);
2621 QVERIFY(!QTestEventLoop::instance().timeout());
2623 QCOMPARE(reply->url(), request.url());
2624 QCOMPARE(reply->error(), QNetworkReply::NoError);
2626 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), resource.size());
2627 QCOMPARE(qint64(reader.data.size()), resource.size());
2628 QCOMPARE(reader.data, resource.readAll());
2631 void tst_QNetworkReply::ioGetFromFile_data()
2636 void tst_QNetworkReply::ioGetFromFile()
2638 QTemporaryFile file(QDir::currentPath() + "/temp-XXXXXX");
2639 file.setAutoRemove(true);
2640 QVERIFY(file.open());
2642 QFETCH(QByteArray, data);
2643 QVERIFY(file.write(data) == data.size());
2645 QCOMPARE(file.size(), qint64(data.size()));
2647 QNetworkRequest request(QUrl::fromLocalFile(file.fileName()));
2648 QNetworkReplyPtr reply = manager.get(request);
2649 QVERIFY(reply->isFinished()); // a file should immediately be done
2650 DataReader reader(reply);
2652 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
2653 QTestEventLoop::instance().enterLoop(10);
2654 QVERIFY(!QTestEventLoop::instance().timeout());
2656 QCOMPARE(reply->url(), request.url());
2657 QCOMPARE(reply->error(), QNetworkReply::NoError);
2659 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), file.size());
2660 QCOMPARE(qint64(reader.data.size()), file.size());
2661 QCOMPARE(reader.data, data);
2664 void tst_QNetworkReply::ioGetFromFtp_data()
2666 QTest::addColumn<QString>("fileName");
2667 QTest::addColumn<qint64>("expectedSize");
2669 QTest::newRow("bigfile") << "bigfile" << Q_INT64_C(519240);
2671 QFile file(testDataDir + "/rfc3252.txt");
2672 QTest::newRow("rfc3252.txt") << "rfc3252.txt" << file.size();
2675 void tst_QNetworkReply::ioGetFromFtp()
2677 QFETCH(QString, fileName);
2678 QFile reference(fileName);
2679 reference.open(QIODevice::ReadOnly); // will fail for bigfile
2681 QNetworkRequest request("ftp://" + QtNetworkSettings::serverName() + "/qtest/" + fileName);
2682 QNetworkReplyPtr reply = manager.get(request);
2683 DataReader reader(reply);
2685 QVERIFY(waitForFinish(reply) == Success);
2687 QCOMPARE(reply->url(), request.url());
2688 QCOMPARE(reply->error(), QNetworkReply::NoError);
2690 QFETCH(qint64, expectedSize);
2691 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), expectedSize);
2692 QCOMPARE(qint64(reader.data.size()), expectedSize);
2694 if (reference.isOpen())
2695 QCOMPARE(reader.data, reference.readAll());
2698 void tst_QNetworkReply::ioGetFromFtpWithReuse()
2700 QString fileName = testDataDir + "/rfc3252.txt";
2701 QFile reference(fileName);
2702 reference.open(QIODevice::ReadOnly);
2704 QNetworkRequest request(QUrl("ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
2706 // two concurrent (actually, consecutive) gets:
2707 QNetworkReplyPtr reply1 = manager.get(request);
2708 DataReader reader1(reply1);
2709 QNetworkReplyPtr reply2 = manager.get(request);
2710 DataReader reader2(reply2);
2711 QSignalSpy spy(reply1, SIGNAL(finished()));
2713 QVERIFY(waitForFinish(reply1) == Success);
2714 QVERIFY(waitForFinish(reply2) == Success);
2716 QCOMPARE(reply1->url(), request.url());
2717 QCOMPARE(reply2->url(), request.url());
2718 QCOMPARE(reply1->error(), QNetworkReply::NoError);
2719 QCOMPARE(reply2->error(), QNetworkReply::NoError);
2721 QCOMPARE(qint64(reader1.data.size()), reference.size());
2722 QCOMPARE(qint64(reader2.data.size()), reference.size());
2723 QCOMPARE(reply1->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
2724 QCOMPARE(reply2->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
2726 QByteArray referenceData = reference.readAll();
2727 QCOMPARE(reader1.data, referenceData);
2728 QCOMPARE(reader2.data, referenceData);
2731 void tst_QNetworkReply::ioGetFromHttp()
2733 QFile reference(testDataDir + "/rfc3252.txt");
2734 QVERIFY(reference.open(QIODevice::ReadOnly));
2736 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
2737 QNetworkReplyPtr reply = manager.get(request);
2738 DataReader reader(reply);
2740 QVERIFY(waitForFinish(reply) == Success);
2742 QCOMPARE(reply->url(), request.url());
2743 QCOMPARE(reply->error(), QNetworkReply::NoError);
2744 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2746 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
2747 QCOMPARE(qint64(reader.data.size()), reference.size());
2749 QCOMPARE(reader.data, reference.readAll());
2752 void tst_QNetworkReply::ioGetFromHttpWithReuseParallel()
2754 QFile reference(testDataDir + "/rfc3252.txt");
2755 QVERIFY(reference.open(QIODevice::ReadOnly));
2757 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
2758 QNetworkReplyPtr reply1 = manager.get(request);
2759 QNetworkReplyPtr reply2 = manager.get(request);
2760 DataReader reader1(reply1);
2761 DataReader reader2(reply2);
2762 QSignalSpy spy(reply1, SIGNAL(finished()));
2764 QVERIFY(waitForFinish(reply2) == Success);
2765 QVERIFY(waitForFinish(reply1) == Success);
2767 QCOMPARE(reply1->url(), request.url());
2768 QCOMPARE(reply2->url(), request.url());
2769 QCOMPARE(reply1->error(), QNetworkReply::NoError);
2770 QCOMPARE(reply2->error(), QNetworkReply::NoError);
2771 QCOMPARE(reply1->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2772 QCOMPARE(reply2->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2774 QCOMPARE(reply1->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
2775 QCOMPARE(reply2->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
2776 QCOMPARE(qint64(reader1.data.size()), reference.size());
2777 QCOMPARE(qint64(reader2.data.size()), reference.size());
2779 QByteArray referenceData = reference.readAll();
2780 QCOMPARE(reader1.data, referenceData);
2781 QCOMPARE(reader2.data, referenceData);
2784 void tst_QNetworkReply::ioGetFromHttpWithReuseSequential()
2786 QFile reference(testDataDir + "/rfc3252.txt");
2787 QVERIFY(reference.open(QIODevice::ReadOnly));
2789 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
2791 QNetworkReplyPtr reply = manager.get(request);
2792 DataReader reader(reply);
2794 QVERIFY(waitForFinish(reply) == Success);
2796 QCOMPARE(reply->url(), request.url());
2797 QCOMPARE(reply->error(), QNetworkReply::NoError);
2798 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2800 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
2801 QCOMPARE(qint64(reader.data.size()), reference.size());
2803 QCOMPARE(reader.data, reference.readAll());
2807 // rinse and repeat:
2809 QNetworkReplyPtr reply = manager.get(request);
2810 DataReader reader(reply);
2812 QVERIFY(waitForFinish(reply) == Success);
2814 QCOMPARE(reply->url(), request.url());
2815 QCOMPARE(reply->error(), QNetworkReply::NoError);
2816 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2818 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
2819 QCOMPARE(qint64(reader.data.size()), reference.size());
2821 QCOMPARE(reader.data, reference.readAll());
2825 void tst_QNetworkReply::ioGetFromHttpWithAuth_data()
2827 QTest::addColumn<QUrl>("url");
2828 QTest::addColumn<QByteArray>("expectedData");
2829 QTest::addColumn<int>("expectedAuth");
2831 QFile reference(testDataDir + "/rfc3252.txt");
2832 reference.open(QIODevice::ReadOnly);
2833 QByteArray referenceData = reference.readAll();
2834 QTest::newRow("basic") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt") << referenceData << 1;
2835 QTest::newRow("digest") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/auth-digest/") << QByteArray("digest authentication successful\n") << 1;
2836 //if url contains username & password, then it should be used
2837 QTest::newRow("basic-in-url") << QUrl("http://httptest:httptest@" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt") << referenceData << 0;
2838 QTest::newRow("digest-in-url") << QUrl("http://httptest:httptest@" + QtNetworkSettings::serverName() + "/qtest/auth-digest/") << QByteArray("digest authentication successful\n") << 0;
2839 // if url contains incorrect credentials, expect QNAM to ask for good ones (even if cached - matches behaviour of browsers)
2840 QTest::newRow("basic-bad-user-in-url") << QUrl("http://baduser:httptest@" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt") << referenceData << 3;
2841 QTest::newRow("basic-bad-password-in-url") << QUrl("http://httptest:wrong@" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt") << referenceData << 3;
2842 QTest::newRow("digest-bad-user-in-url") << QUrl("http://baduser:httptest@" + QtNetworkSettings::serverName() + "/qtest/auth-digest/") << QByteArray("digest authentication successful\n") << 3;
2843 QTest::newRow("digest-bad-password-in-url") << QUrl("http://httptest:wrong@" + QtNetworkSettings::serverName() + "/qtest/auth-digest/") << QByteArray("digest authentication successful\n") << 3;
2846 void tst_QNetworkReply::ioGetFromHttpWithAuth()
2848 // This test sends three requests
2849 // The first two in parallel
2850 // The third after the first two finished
2853 QFETCH(QByteArray, expectedData);
2854 QFETCH(int, expectedAuth);
2855 QNetworkRequest request(url);
2857 QNetworkReplyPtr reply1 = manager.get(request);
2858 QNetworkReplyPtr reply2 = manager.get(request);
2859 DataReader reader1(reply1);
2860 DataReader reader2(reply2);
2861 QSignalSpy finishedspy(reply1, SIGNAL(finished()));
2863 QSignalSpy authspy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2864 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
2865 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2867 QVERIFY(waitForFinish(reply2) == Success);
2868 QVERIFY(waitForFinish(reply1) == Success);
2870 manager.disconnect(SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
2871 this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2873 QCOMPARE(reply1->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2874 QCOMPARE(reply2->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2875 QCOMPARE(reader1.data, expectedData);
2876 QCOMPARE(reader2.data, expectedData);
2878 QCOMPARE(authspy.count(), (expectedAuth ? 1 : 0));
2879 expectedAuth = qMax(0, expectedAuth - 1);
2882 // rinse and repeat:
2884 QNetworkReplyPtr reply = manager.get(request);
2885 DataReader reader(reply);
2887 QSignalSpy authspy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2888 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
2889 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2891 QVERIFY(waitForFinish(reply) == Success);
2893 manager.disconnect(SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
2894 this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2896 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2897 QCOMPARE(reader.data, expectedData);
2899 QCOMPARE(authspy.count(), (expectedAuth ? 1 : 0));
2900 expectedAuth = qMax(0, expectedAuth - 1);
2903 // now check with synchronous calls:
2905 request.setAttribute(
2906 QNetworkRequest::SynchronousRequestAttribute,
2909 QSignalSpy authspy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2910 QNetworkReplyPtr replySync = manager.get(request);
2911 QVERIFY(replySync->isFinished()); // synchronous
2913 // bad credentials in a synchronous request should just fail
2914 QCOMPARE(replySync->error(), QNetworkReply::AuthenticationRequiredError);
2916 QCOMPARE(authspy.count(), 0);
2918 // we cannot use a data reader here, since that connects to the readyRead signal,
2919 // just use readAll()
2921 // the only thing we check here is that the auth cache was used when using synchronous requests
2922 QCOMPARE(replySync->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2923 QCOMPARE(replySync->readAll(), expectedData);
2927 // check that credentials are used from cache if the same url is requested without credentials
2929 url.setUserInfo(QString());
2930 request.setUrl(url);
2931 request.setAttribute(
2932 QNetworkRequest::SynchronousRequestAttribute,
2935 QSignalSpy authspy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2936 QNetworkReplyPtr replySync = manager.get(request);
2937 QVERIFY(replySync->isFinished()); // synchronous
2939 // bad credentials in a synchronous request should just fail
2940 QCOMPARE(replySync->error(), QNetworkReply::AuthenticationRequiredError);
2942 QCOMPARE(authspy.count(), 0);
2944 // we cannot use a data reader here, since that connects to the readyRead signal,
2945 // just use readAll()
2947 // the only thing we check here is that the auth cache was used when using synchronous requests
2948 QCOMPARE(replySync->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2949 QCOMPARE(replySync->readAll(), expectedData);
2954 void tst_QNetworkReply::ioGetFromHttpWithAuthSynchronous()
2956 // verify that we do not enter an endless loop with synchronous calls and wrong credentials
2957 // the case when we succeed with the login is tested in ioGetFromHttpWithAuth()
2959 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt"));
2960 request.setAttribute(
2961 QNetworkRequest::SynchronousRequestAttribute,
2964 QSignalSpy authspy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2965 QNetworkReplyPtr replySync = manager.get(request);
2966 QVERIFY(replySync->isFinished()); // synchronous
2967 QCOMPARE(replySync->error(), QNetworkReply::AuthenticationRequiredError);
2968 QCOMPARE(authspy.count(), 0);
2969 QCOMPARE(replySync->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 401);
2972 void tst_QNetworkReply::ioGetFromHttpWithProxyAuth()
2974 qRegisterMetaType<QNetworkProxy>(); // for QSignalSpy
2975 qRegisterMetaType<QAuthenticator *>();
2977 // This test sends three requests
2978 // The first two in parallel
2979 // The third after the first two finished
2980 QFile reference(testDataDir + "/rfc3252.txt");
2981 QVERIFY(reference.open(QIODevice::ReadOnly));
2983 QNetworkProxy proxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129);
2984 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
2986 manager.setProxy(proxy);
2987 QNetworkReplyPtr reply1 = manager.get(request);
2988 QNetworkReplyPtr reply2 = manager.get(request);
2989 manager.setProxy(QNetworkProxy());
2991 DataReader reader1(reply1);
2992 DataReader reader2(reply2);
2993 QSignalSpy finishedspy(reply1, SIGNAL(finished()));
2995 QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
2996 connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
2997 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
2999 QVERIFY(waitForFinish(reply2) == Success);
3000 QVERIFY(waitForFinish(reply1) == Success);
3002 manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3003 this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3005 QCOMPARE(reply1->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
3006 QCOMPARE(reply2->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
3007 QByteArray referenceData = reference.readAll();
3008 QCOMPARE(reader1.data, referenceData);
3009 QCOMPARE(reader2.data, referenceData);
3011 QCOMPARE(authspy.count(), 1);
3015 // rinse and repeat:
3017 manager.setProxy(proxy);
3018 QNetworkReplyPtr reply = manager.get(request);
3019 DataReader reader(reply);
3020 manager.setProxy(QNetworkProxy());
3022 QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3023 connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3024 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3026 QVERIFY(waitForFinish(reply) == Success);
3028 manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3029 this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3031 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
3032 QCOMPARE(reader.data, reference.readAll());
3034 QCOMPARE(authspy.count(), 0);
3037 // now check with synchronous calls:
3040 request.setAttribute(
3041 QNetworkRequest::SynchronousRequestAttribute,
3044 QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3045 QNetworkReplyPtr replySync = manager.get(request);
3046 QVERIFY(replySync->isFinished()); // synchronous
3047 QCOMPARE(authspy.count(), 0);
3049 // we cannot use a data reader here, since that connects to the readyRead signal,
3050 // just use readAll()
3052 // the only thing we check here is that the proxy auth cache was used when using synchronous requests
3053 QCOMPARE(replySync->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
3054 QCOMPARE(replySync->readAll(), reference.readAll());
3058 void tst_QNetworkReply::ioGetFromHttpWithProxyAuthSynchronous()
3060 // verify that we do not enter an endless loop with synchronous calls and wrong credentials
3061 // the case when we succeed with the login is tested in ioGetFromHttpWithAuth()
3063 QNetworkProxy proxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129);
3064 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
3065 manager.setProxy(proxy);
3066 request.setAttribute(
3067 QNetworkRequest::SynchronousRequestAttribute,
3070 QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3071 QNetworkReplyPtr replySync = manager.get(request);
3072 manager.setProxy(QNetworkProxy()); // reset
3073 QVERIFY(replySync->isFinished()); // synchronous
3074 QCOMPARE(replySync->error(), QNetworkReply::ProxyAuthenticationRequiredError);
3075 QCOMPARE(authspy.count(), 0);
3076 QCOMPARE(replySync->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 407);
3079 void tst_QNetworkReply::ioGetFromHttpWithSocksProxy()
3081 // HTTP caching proxies are tested by the above function
3082 // test SOCKSv5 proxies too
3084 qRegisterMetaType<QNetworkProxy>(); // for QSignalSpy
3085 qRegisterMetaType<QAuthenticator *>();
3087 QFile reference(testDataDir + "/rfc3252.txt");
3088 QVERIFY(reference.open(QIODevice::ReadOnly));
3090 QNetworkProxy proxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080);
3091 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
3093 manager.setProxy(proxy);
3094 QNetworkReplyPtr reply = manager.get(request);
3095 DataReader reader(reply);
3096 manager.setProxy(QNetworkProxy());
3098 QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3099 connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3100 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3102 QVERIFY(waitForFinish(reply) == Success);
3104 manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3105 this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3107 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
3108 QCOMPARE(reader.data, reference.readAll());
3110 QCOMPARE(authspy.count(), 0);
3113 // set an invalid proxy just to make sure that we can't load
3114 proxy = QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1079);
3116 manager.setProxy(proxy);
3117 QNetworkReplyPtr reply = manager.get(request);
3118 DataReader reader(reply);
3119 manager.setProxy(QNetworkProxy());
3121 QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3122 connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3123 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3125 QVERIFY(waitForFinish(reply) == Failure);
3127 manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3128 this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3130 QVERIFY(!reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).isValid());
3131 QVERIFY(reader.data.isEmpty());
3133 QVERIFY(int(reply->error()) > 0);
3134 QEXPECT_FAIL("", "QTcpSocket doesn't return enough information yet", Continue);
3135 QCOMPARE(int(reply->error()), int(QNetworkReply::ProxyConnectionRefusedError));
3137 QCOMPARE(authspy.count(), 0);
3142 void tst_QNetworkReply::ioGetFromHttpsWithSslErrors()
3144 qRegisterMetaType<QNetworkReply*>(); // for QSignalSpy
3145 qRegisterMetaType<QList<QSslError> >();
3147 QFile reference(testDataDir + "/rfc3252.txt");
3148 QVERIFY(reference.open(QIODevice::ReadOnly));
3150 QNetworkRequest request(QUrl("https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
3151 QNetworkReplyPtr reply = manager.get(request);
3152 DataReader reader(reply);
3154 QSignalSpy sslspy(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)));
3155 connect(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
3156 SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
3157 connect(reply, SIGNAL(metaDataChanged()), SLOT(storeSslConfiguration()));
3159 QVERIFY(waitForFinish(reply) == Success);
3161 manager.disconnect(SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
3162 this, SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
3164 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
3165 QCOMPARE(reader.data, reference.readAll());
3167 QCOMPARE(sslspy.count(), 1);
3169 QVERIFY(!storedSslConfiguration.isNull());
3170 QVERIFY(!reply->sslConfiguration().isNull());
3173 void tst_QNetworkReply::ioGetFromHttpsWithIgnoreSslErrors()
3175 // same as above, except that we call ignoreSslErrors and don't connect
3176 // to the sslErrors() signal (which is *still* emitted)
3178 qRegisterMetaType<QNetworkReply*>(); // for QSignalSpy
3179 qRegisterMetaType<QList<QSslError> >();
3181 QFile reference(testDataDir + "/rfc3252.txt");
3182 QVERIFY(reference.open(QIODevice::ReadOnly));
3184 QNetworkRequest request(QUrl("https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
3186 QNetworkReplyPtr reply = manager.get(request);
3187 reply->ignoreSslErrors();
3188 DataReader reader(reply);
3190 QSignalSpy sslspy(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)));
3191 connect(reply, SIGNAL(metaDataChanged()), SLOT(storeSslConfiguration()));
3193 QVERIFY(waitForFinish(reply) == Success);
3195 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
3196 QCOMPARE(reader.data, reference.readAll());
3198 QCOMPARE(sslspy.count(), 1);
3200 QVERIFY(!storedSslConfiguration.isNull());
3201 QVERIFY(!reply->sslConfiguration().isNull());
3204 void tst_QNetworkReply::ioGetFromHttpsWithSslHandshakeError()
3206 qRegisterMetaType<QNetworkReply*>(); // for QSignalSpy
3207 qRegisterMetaType<QList<QSslError> >();
3209 QFile reference(testDataDir + "/rfc3252.txt");
3210 QVERIFY(reference.open(QIODevice::ReadOnly));
3212 QNetworkRequest request(QUrl("https://" + QtNetworkSettings::serverName() + ":80"));
3214 QNetworkReplyPtr reply = manager.get(request);
3215 reply->ignoreSslErrors();
3216 DataReader reader(reply);
3218 QSignalSpy sslspy(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)));
3219 connect(reply, SIGNAL(metaDataChanged()), SLOT(storeSslConfiguration()));
3221 QVERIFY(waitForFinish(reply) == Failure);
3223 QCOMPARE(reply->error(), QNetworkReply::SslHandshakeFailedError);
3224 QCOMPARE(sslspy.count(), 0);
3228 void tst_QNetworkReply::ioGetFromHttpBrokenServer_data()
3230 QTest::addColumn<QByteArray>("dataToSend");
3231 QTest::addColumn<bool>("doDisconnect");
3233 QTest::newRow("no-newline") << QByteArray("Hello World") << false;
3235 // these are OK now, we just eat the lonely newlines
3236 //QTest::newRow("just-newline") << QByteArray("\r\n") << false;
3237 //QTest::newRow("just-2newline") << QByteArray("\r\n\r\n") << false;
3239 QTest::newRow("with-newlines") << QByteArray("Long first line\r\nLong second line") << false;
3240 QTest::newRow("with-newlines2") << QByteArray("\r\nSecond line") << false;
3241 QTest::newRow("with-newlines3") << QByteArray("ICY\r\nSecond line") << false;
3242 QTest::newRow("invalid-version") << QByteArray("HTTP/123 200 \r\n") << false;
3243 QTest::newRow("invalid-version2") << QByteArray("HTTP/a.\033 200 \r\n") << false;
3244 QTest::newRow("invalid-reply-code") << QByteArray("HTTP/1.0 fuu \r\n") << false;
3246 QTest::newRow("empty+disconnect") << QByteArray() << true;
3248 QTest::newRow("no-newline+disconnect") << QByteArray("Hello World") << true;
3249 QTest::newRow("just-newline+disconnect") << QByteArray("\r\n") << true;
3250 QTest::newRow("just-2newline+disconnect") << QByteArray("\r\n\r\n") << true;
3251 QTest::newRow("with-newlines+disconnect") << QByteArray("Long first line\r\nLong second line") << true;
3252 QTest::newRow("with-newlines2+disconnect") << QByteArray("\r\nSecond line") << true;
3253 QTest::newRow("with-newlines3+disconnect") << QByteArray("ICY\r\nSecond line") << true;
3255 QTest::newRow("invalid-version+disconnect") << QByteArray("HTTP/123 200 ") << true;
3256 QTest::newRow("invalid-version2+disconnect") << QByteArray("HTTP/a.\033 200 ") << true;
3257 QTest::newRow("invalid-reply-code+disconnect") << QByteArray("HTTP/1.0 fuu ") << true;
3259 QTest::newRow("immediate disconnect") << QByteArray("") << true;
3260 QTest::newRow("justHalfStatus+disconnect") << QByteArray("HTTP/1.1") << true;
3261 QTest::newRow("justStatus+disconnect") << QByteArray("HTTP/1.1 200 OK\r\n") << true;
3262 QTest::newRow("justStatusAndHalfHeaders+disconnect") << QByteArray("HTTP/1.1 200 OK\r\nContent-L") << true;
3264 QTest::newRow("halfContent+disconnect") << QByteArray("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\nAB") << true;
3268 void tst_QNetworkReply::ioGetFromHttpBrokenServer()
3270 QFETCH(QByteArray, dataToSend);
3271 QFETCH(bool, doDisconnect);
3272 MiniHttpServer server(dataToSend);
3273 server.doClose = doDisconnect;
3275 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
3276 QNetworkReplyPtr reply = manager.get(request);
3277 QSignalSpy spy(reply, SIGNAL(error(QNetworkReply::NetworkError)));
3279 QVERIFY(waitForFinish(reply) == Failure);
3281 QCOMPARE(reply->url(), request.url());
3282 QCOMPARE(spy.count(), 1);
3283 QVERIFY(reply->error() != QNetworkReply::NoError);
3286 void tst_QNetworkReply::ioGetFromHttpStatus100_data()
3288 QTest::addColumn<QByteArray>("dataToSend");
3289 QTest::addColumn<int>("statusCode");
3290 QTest::newRow("normal") << QByteArray("HTTP/1.1 100 Continue\r\n\r\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") << 200;
3291 QTest::newRow("minimal") << QByteArray("HTTP/1.1 100 Continue\n\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") << 200;
3292 QTest::newRow("minimal2") << QByteArray("HTTP/1.1 100 Continue\n\nHTTP/1.0 200 OK\r\n\r\n") << 200;
3293 QTest::newRow("minimal3") << QByteArray("HTTP/1.1 100 Continue\n\nHTTP/1.0 200 OK\n\n") << 200;
3294 QTest::newRow("minimal+404") << QByteArray("HTTP/1.1 100 Continue\n\nHTTP/1.0 204 No Content\r\n\r\n") << 204;
3295 QTest::newRow("with_headers") << QByteArray("HTTP/1.1 100 Continue\r\nBla: x\r\n\r\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") << 200;
3296 QTest::newRow("with_headers2") << QByteArray("HTTP/1.1 100 Continue\nBla: x\n\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") << 200;
3299 void tst_QNetworkReply::ioGetFromHttpStatus100()
3301 QFETCH(QByteArray, dataToSend);
3302 QFETCH(int, statusCode);
3303 MiniHttpServer server(dataToSend);
3304 server.doClose = true;
3306 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
3307 QNetworkReplyPtr reply = manager.get(request);
3309 QVERIFY(waitForFinish(reply) == Success);
3311 QCOMPARE(reply->url(), request.url());
3312 QCOMPARE(reply->error(), QNetworkReply::NoError);
3313 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), statusCode);
3314 QVERIFY(reply->rawHeader("bla").isNull());
3317 void tst_QNetworkReply::ioGetFromHttpNoHeaders_data()
3319 QTest::addColumn<QByteArray>("dataToSend");
3320 QTest::newRow("justStatus+noheaders+disconnect") << QByteArray("HTTP/1.0 200 OK\r\n\r\n");
3323 void tst_QNetworkReply::ioGetFromHttpNoHeaders()
3325 QFETCH(QByteArray, dataToSend);
3326 MiniHttpServer server(dataToSend);
3327 server.doClose = true;
3329 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
3330 QNetworkReplyPtr reply = manager.get(request);
3332 QVERIFY(waitForFinish(reply) == Success);
3334 QCOMPARE(reply->url(), request.url());
3335 QCOMPARE(reply->error(), QNetworkReply::NoError);
3336 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
3339 void tst_QNetworkReply::ioGetFromHttpWithCache_data()
3341 qRegisterMetaType<MyMemoryCache::CachedContent>();
3342 QTest::addColumn<QByteArray>("dataToSend");
3343 QTest::addColumn<QString>("body");
3344 QTest::addColumn<MyMemoryCache::CachedContent>("cachedReply");
3345 QTest::addColumn<int>("cacheMode");
3346 QTest::addColumn<QStringList>("extraHttpHeaders");
3347 QTest::addColumn<bool>("loadedFromCache");
3348 QTest::addColumn<bool>("networkUsed");
3350 QByteArray reply200 =
3352 "Connection: keep-alive\r\n"
3353 "Content-Type: text/plain\r\n"
3354 "Cache-control: no-cache\r\n"
3355 "Content-length: 8\r\n"
3358 QByteArray reply304 =
3359 "HTTP/1.0 304 Use Cache\r\n"
3360 "Connection: keep-alive\r\n"
3363 QTest::newRow("not-cached,always-network")
3364 << reply200 << "Reloaded" << MyMemoryCache::CachedContent() << int(QNetworkRequest::AlwaysNetwork) << QStringList() << false << true;
3365 QTest::newRow("not-cached,prefer-network")
3366 << reply200 << "Reloaded" << MyMemoryCache::CachedContent() << int(QNetworkRequest::PreferNetwork) << QStringList() << false << true;
3367 QTest::newRow("not-cached,prefer-cache")
3368 << reply200 << "Reloaded" << MyMemoryCache::CachedContent() << int(QNetworkRequest::PreferCache) << QStringList() << false << true;
3370 QDateTime present = QDateTime::currentDateTime().toUTC();
3371 QDateTime past = present.addSecs(-3600);
3372 QDateTime future = present.addSecs(3600);
3373 static const char dateFormat[] = "ddd, dd MMM yyyy hh:mm:ss 'GMT'";
3375 QNetworkCacheMetaData::RawHeaderList rawHeaders;
3376 MyMemoryCache::CachedContent content;
3377 content.second = "Not-reloaded";
3378 content.first.setLastModified(past);
3384 rawHeaders << QNetworkCacheMetaData::RawHeader("Date", QLocale::c().toString(past, dateFormat).toLatin1())
3385 << QNetworkCacheMetaData::RawHeader("Cache-control", "max-age=0"); // isn't used in cache loading
3386 content.first.setRawHeaders(rawHeaders);
3387 content.first.setLastModified(past);
3389 QTest::newRow("expired,200,prefer-network")
3390 << reply200 << "Reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << false << true;
3391 QTest::newRow("expired,200,prefer-cache")
3392 << reply200 << "Reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << false << true;
3394 QTest::newRow("expired,304,prefer-network")
3395 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << true << true;
3396 QTest::newRow("expired,304,prefer-cache")
3397 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << true << true;
3400 // Set to not-expired
3403 rawHeaders << QNetworkCacheMetaData::RawHeader("Date", QLocale::c().toString(past, dateFormat).toLatin1())
3404 << QNetworkCacheMetaData::RawHeader("Cache-control", "max-age=7200"); // isn't used in cache loading
3405 content.first.setRawHeaders(rawHeaders);
3406 content.first.setExpirationDate(future);
3408 QTest::newRow("not-expired,200,always-network")
3409 << reply200 << "Reloaded" << content << int(QNetworkRequest::AlwaysNetwork) << QStringList() << false << true;
3410 QTest::newRow("not-expired,200,prefer-network")
3411 << reply200 << "Not-reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << true << false;
3412 QTest::newRow("not-expired,200,prefer-cache")
3413 << reply200 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << true << false;
3414 QTest::newRow("not-expired,200,always-cache")
3415 << reply200 << "Not-reloaded" << content << int(QNetworkRequest::AlwaysCache) << QStringList() << true << false;
3417 QTest::newRow("not-expired,304,prefer-network")
3418 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << true << false;
3419 QTest::newRow("not-expired,304,prefer-cache")
3420 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << true << false;
3421 QTest::newRow("not-expired,304,always-cache")
3422 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::AlwaysCache) << QStringList() << true << false;
3425 // Set must-revalidate now
3428 rawHeaders << QNetworkCacheMetaData::RawHeader("Date", QLocale::c().toString(past, dateFormat).toLatin1())
3429 << QNetworkCacheMetaData::RawHeader("Cache-control", "max-age=7200, must-revalidate"); // must-revalidate is used
3430 content.first.setRawHeaders(rawHeaders);
3432 QTest::newRow("must-revalidate,200,always-network")
3433 << reply200 << "Reloaded" << content << int(QNetworkRequest::AlwaysNetwork) << QStringList() << false << true;
3434 QTest::newRow("must-revalidate,200,prefer-network")
3435 << reply200 << "Reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << false << true;
3436 QTest::newRow("must-revalidate,200,prefer-cache")
3437 << reply200 << "Reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << false << true;
3438 QTest::newRow("must-revalidate,200,always-cache")
3439 << reply200 << "" << content << int(QNetworkRequest::AlwaysCache) << QStringList() << false << false;
3441 QTest::newRow("must-revalidate,304,prefer-network")
3442 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << true << true;
3443 QTest::newRow("must-revalidate,304,prefer-cache")
3444 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << true << true;
3445 QTest::newRow("must-revalidate,304,always-cache")
3446 << reply304 << "" << content << int(QNetworkRequest::AlwaysCache) << QStringList() << false << false;
3452 rawHeaders << QNetworkCacheMetaData::RawHeader("Date", QLocale::c().toString(past, dateFormat).toLatin1())
3453 << QNetworkCacheMetaData::RawHeader("Cache-control", "max-age=7200"); // isn't used in cache loading
3454 content.first.setRawHeaders(rawHeaders);
3455 content.first.setExpirationDate(future);
3457 QByteArray reply206 =
3459 "Connection: keep-alive\r\n"
3460 "Content-Type: text/plain\r\n"
3461 "Cache-control: no-cache\r\n"
3462 "Content-Range: bytes 2-6/8\r\n"
3463 "Content-length: 4\r\n"
3467 QTest::newRow("partial,dontuse-cache")
3468 << reply206 << "load" << content << int(QNetworkRequest::PreferCache) << (QStringList() << "Range" << "bytes=2-6") << false << true;
3471 void tst_QNetworkReply::ioGetFromHttpWithCache()
3473 QFETCH(QByteArray, dataToSend);
3474 MiniHttpServer server(dataToSend);
3475 server.doClose = false;
3477 MyMemoryCache *memoryCache = new MyMemoryCache(&manager);
3478 manager.setCache(memoryCache);
3480 QFETCH(MyMemoryCache::CachedContent, cachedReply);
3481 QUrl url = "http://localhost:" + QString::number(server.serverPort());
3482 cachedReply.first.setUrl(url);
3483 if (!cachedReply.second.isNull())
3484 memoryCache->cache.insert(url.toEncoded(), cachedReply);
3486 QFETCH(int, cacheMode);
3487 QNetworkRequest request(url);
3488 request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, cacheMode);
3489 request.setAttribute(QNetworkRequest::CacheSaveControlAttribute, false);
3491 QFETCH(QStringList, extraHttpHeaders);
3492 QStringListIterator it(extraHttpHeaders);
3493 while (it.hasNext()) {
3494 QString header = it.next();
3495 QString value = it.next();
3496 request.setRawHeader(header.toLatin1(), value.toLatin1()); // To latin1? Deal with it!
3499 QNetworkReplyPtr reply = manager.get(request);
3501 QVERIFY(waitForFinish(reply) != Timeout);
3503 QTEST(reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool(), "loadedFromCache");
3504 QTEST(server.totalConnections > 0, "networkUsed");
3505 QFETCH(QString, body);
3506 QCOMPARE(reply->readAll().constData(), qPrintable(body));
3509 void tst_QNetworkReply::ioGetWithManyProxies_data()
3511 QTest::addColumn<QList<QNetworkProxy> >("proxyList");
3512 QTest::addColumn<QNetworkProxy>("proxyUsed");
3513 QTest::addColumn<QString>("url");
3514 QTest::addColumn<QNetworkReply::NetworkError>("expectedError");
3516 QList<QNetworkProxy> proxyList;
3518 // All of the other functions test DefaultProxy
3519 // So let's test something else
3521 // Simple tests that work:
3523 // HTTP request with HTTP caching proxy
3524 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129);
3525 QTest::newRow("http-on-http")
3526 << proxyList << proxyList.at(0)
3527 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3528 << QNetworkReply::NoError;
3530 // HTTP request with HTTP transparent proxy
3532 proxyList << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3129);
3533 QTest::newRow("http-on-http2")
3534 << proxyList << proxyList.at(0)
3535 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3536 << QNetworkReply::NoError;
3538 // HTTP request with SOCKS transparent proxy
3540 proxyList << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081);
3541 QTest::newRow("http-on-socks")
3542 << proxyList << proxyList.at(0)
3543 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3544 << QNetworkReply::NoError;
3546 // FTP request with FTP caching proxy
3548 proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121);
3549 QTest::newRow("ftp-on-ftp")
3550 << proxyList << proxyList.at(0)
3551 << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3552 << QNetworkReply::NoError;
3554 // The following test doesn't work because QFtp is too limited
3555 // It can only talk to its own kind of proxies
3557 // FTP request with SOCKSv5 transparent proxy
3559 proxyList << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081);
3560 QTest::newRow("ftp-on-socks")
3561 << proxyList << proxyList.at(0)
3562 << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3563 << QNetworkReply::NoError;
3566 // HTTPS with HTTP transparent proxy
3568 proxyList << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3129);
3569 QTest::newRow("https-on-http")
3570 << proxyList << proxyList.at(0)
3571 << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3572 << QNetworkReply::NoError;
3574 // HTTPS request with SOCKS transparent proxy
3576 proxyList << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081);
3577 QTest::newRow("https-on-socks")
3578 << proxyList << proxyList.at(0)
3579 << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3580 << QNetworkReply::NoError;
3585 // HTTP request with FTP caching proxy
3587 proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121);
3588 QTest::newRow("http-on-ftp")
3589 << proxyList << QNetworkProxy()
3590 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3591 << QNetworkReply::ProxyNotFoundError;
3593 // FTP request with HTTP caching proxy
3595 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129);
3596 QTest::newRow("ftp-on-http")
3597 << proxyList << QNetworkProxy()
3598 << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3599 << QNetworkReply::ProxyNotFoundError;
3601 // FTP request with HTTP caching proxies
3603 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
3604 << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3130);
3605 QTest::newRow("ftp-on-multiple-http")
3606 << proxyList << QNetworkProxy()
3607 << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3608 << QNetworkReply::ProxyNotFoundError;
3611 // HTTPS with HTTP caching proxy
3613 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129);
3614 QTest::newRow("https-on-httptransparent")
3615 << proxyList << QNetworkProxy()
3616 << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3617 << QNetworkReply::ProxyNotFoundError;
3619 // HTTPS with FTP caching proxy
3621 proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121);
3622 QTest::newRow("https-on-ftp")
3623 << proxyList << QNetworkProxy()
3624 << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3625 << QNetworkReply::ProxyNotFoundError;
3628 // Complex requests:
3630 // HTTP request with more than one HTTP proxy
3632 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
3633 << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3130);
3634 QTest::newRow("http-on-multiple-http")
3635 << proxyList << proxyList.at(0)
3636 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3637 << QNetworkReply::NoError;
3639 // HTTP request with HTTP + SOCKS
3641 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
3642 << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081);
3643 QTest::newRow("http-on-http+socks")
3644 << proxyList << proxyList.at(0)
3645 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3646 << QNetworkReply::NoError;
3648 // HTTP request with FTP + HTTP + SOCKS
3650 proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121)
3651 << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
3652 << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081);
3653 QTest::newRow("http-on-ftp+http+socks")
3654 << proxyList << proxyList.at(1) // second proxy should be used
3655 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3656 << QNetworkReply::NoError;
3658 // HTTP request with NoProxy + HTTP
3660 proxyList << QNetworkProxy(QNetworkProxy::NoProxy)
3661 << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129);
3662 QTest::newRow("http-on-noproxy+http")
3663 << proxyList << proxyList.at(0)
3664 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3665 << QNetworkReply::NoError;
3667 // HTTP request with FTP + NoProxy
3669 proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121)
3670 << QNetworkProxy(QNetworkProxy::NoProxy);
3671 QTest::newRow("http-on-ftp+noproxy")
3672 << proxyList << proxyList.at(1) // second proxy should be used
3673 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3674 << QNetworkReply::NoError;
3676 // FTP request with HTTP Caching + FTP
3678 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
3679 << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121);
3680 QTest::newRow("ftp-on-http+ftp")
3681 << proxyList << proxyList.at(1) // second proxy should be used
3682 << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3683 << QNetworkReply::NoError;
3686 // HTTPS request with HTTP Caching + HTTP transparent
3688 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
3689 << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3129);
3690 QTest::newRow("https-on-httpcaching+http")
3691 << proxyList << proxyList.at(1) // second proxy should be used
3692 << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3693 << QNetworkReply::NoError;
3695 // HTTPS request with FTP + HTTP C + HTTP T
3697 proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121)
3698 << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
3699 << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3129);
3700 QTest::newRow("https-on-ftp+httpcaching+http")
3701 << proxyList << proxyList.at(2) // skip the first two
3702 << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3703 << QNetworkReply::NoError;
3707 void tst_QNetworkReply::ioGetWithManyProxies()
3709 // Test proxy factories
3711 qRegisterMetaType<QNetworkProxy>(); // for QSignalSpy
3712 qRegisterMetaType<QAuthenticator *>();
3714 QFile reference(testDataDir + "/rfc3252.txt");
3715 QVERIFY(reference.open(QIODevice::ReadOnly));
3717 // set the proxy factory:
3718 QFETCH(QList<QNetworkProxy>, proxyList);
3719 MyProxyFactory *proxyFactory = new MyProxyFactory;
3720 proxyFactory->toReturn = proxyList;
3721 manager.setProxyFactory(proxyFactory);
3723 QFETCH(QString, url);
3725 QNetworkRequest request(theUrl);
3726 QNetworkReplyPtr reply = manager.get(request);
3727 DataReader reader(reply);
3729 QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3730 connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3731 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3733 connect(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
3734 SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
3737 QVERIFY(waitForFinish(reply) != Timeout);
3739 manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3740 this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3742 manager.disconnect(SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
3743 this, SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
3746 QFETCH(QNetworkReply::NetworkError, expectedError);
3747 QEXPECT_FAIL("ftp-on-socks", "QFtp is too limited and won't accept non-FTP proxies", Abort);
3748 QCOMPARE(reply->error(), expectedError);
3750 // Verify that the factory was called properly
3751 QCOMPARE(proxyFactory->callCount, 1);
3752 QCOMPARE(proxyFactory->lastQuery, QNetworkProxyQuery(theUrl));
3754 if (expectedError == QNetworkReply::NoError) {
3755 // request succeeded
3756 QCOMPARE(reader.data, reference.readAll());
3758 // now verify that the proxies worked:
3759 QFETCH(QNetworkProxy, proxyUsed);
3760 if (proxyUsed.type() == QNetworkProxy::NoProxy) {
3761 QCOMPARE(authspy.count(), 0);
3763 if (QByteArray(QTest::currentDataTag()).startsWith("ftp-"))
3764 return; // No authentication with current FTP or with FTP proxies
3765 QCOMPARE(authspy.count(), 1);
3766 QCOMPARE(qvariant_cast<QNetworkProxy>(authspy.at(0).at(0)), proxyUsed);
3770 QCOMPARE(authspy.count(), 0);
3774 void tst_QNetworkReply::ioPutToFileFromFile_data()
3776 QTest::addColumn<QString>("fileName");
3778 QTest::newRow("empty") << (testDataDir + "/empty");
3779 QTest::newRow("real-file") << (testDataDir + "/rfc3252.txt");
3780 QTest::newRow("resource") << ":/resource";
3781 QTest::newRow("search-path") << "testdata:/rfc3252.txt";
3784 void tst_QNetworkReply::ioPutToFileFromFile()
3786 QFETCH(QString, fileName);
3787 QFile sourceFile(fileName);
3788 QFile targetFile(testFileName);
3790 QVERIFY(sourceFile.open(QIODevice::ReadOnly));
3792 QUrl url = QUrl::fromLocalFile(targetFile.fileName());
3793 QNetworkRequest request(url);
3794 QNetworkReplyPtr reply = manager.put(request, &sourceFile);
3796 QVERIFY(waitForFinish(reply) == Success);
3798 QCOMPARE(reply->url(), url);
3799 QCOMPARE(reply->error(), QNetworkReply::NoError);
3800 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
3801 QVERIFY(reply->readAll().isEmpty());
3803 QVERIFY(sourceFile.atEnd());
3804 sourceFile.seek(0); // reset it to the beginning
3806 QVERIFY(targetFile.open(QIODevice::ReadOnly));
3807 QCOMPARE(targetFile.size(), sourceFile.size());
3808 QCOMPARE(targetFile.readAll(), sourceFile.readAll());
3811 void tst_QNetworkReply::ioPutToFileFromSocket_data()
3816 void tst_QNetworkReply::ioPutToFileFromSocket()
3818 QFile file(testFileName);
3820 QUrl url = QUrl::fromLocalFile(file.fileName());
3821 QNetworkRequest request(url);
3823 QFETCH(QByteArray, data);
3824 SocketPair socketpair;
3825 socketpair.create();
3826 QVERIFY(socketpair.endPoints[0] && socketpair.endPoints[1]);
3828 socketpair.endPoints[0]->write(data);
3829 QNetworkReplyPtr reply = manager.put(QNetworkRequest(url), socketpair.endPoints[1]);
3830 socketpair.endPoints[0]->close();
3832 QVERIFY(waitForFinish(reply) == Success);
3833 QCOMPARE(reply->error(), QNetworkReply::NoError);
3835 QCOMPARE(reply->url(), url);
3836 QCOMPARE(reply->error(), QNetworkReply::NoError);
3837 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
3838 QVERIFY(reply->readAll().isEmpty());
3840 QVERIFY(file.open(QIODevice::ReadOnly));
3841 QCOMPARE(file.size(), qint64(data.size()));
3842 QByteArray contents = file.readAll();
3843 QCOMPARE(contents, data);
3846 void tst_QNetworkReply::ioPutToFileFromLocalSocket_data()
3851 void tst_QNetworkReply::ioPutToFileFromLocalSocket()
3853 QString socketname = "networkreplytest";
3854 QLocalServer server;
3855 if (!server.listen(socketname)) {
3856 QLocalServer::removeServer(socketname);
3857 QVERIFY(server.listen(socketname));
3859 QLocalSocket active;
3860 active.connectToServer(socketname);
3861 QVERIFY2(server.waitForNewConnection(10), server.errorString().toLatin1().constData());
3862 QVERIFY2(active.waitForConnected(10), active.errorString().toLatin1().constData());
3863 QVERIFY2(server.hasPendingConnections(), server.errorString().toLatin1().constData());
3864 QLocalSocket *passive = server.nextPendingConnection();
3866 QFile file(testFileName);
3867 QUrl url = QUrl::fromLocalFile(file.fileName());
3868 QNetworkRequest request(url);
3870 QFETCH(QByteArray, data);
3873 QNetworkReplyPtr reply = manager.put(QNetworkRequest(url), passive);
3874 passive->setParent(reply);
3876 QVERIFY(waitForFinish(reply) == Success);
3877 QCOMPARE(reply->error(), QNetworkReply::NoError);
3879 QCOMPARE(reply->url(), url);
3880 QCOMPARE(reply->error(), QNetworkReply::NoError);
3881 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
3882 QVERIFY(reply->readAll().isEmpty());
3884 QVERIFY(file.open(QIODevice::ReadOnly));
3885 QCOMPARE(file.size(), qint64(data.size()));
3886 QByteArray contents = file.readAll();
3887 QCOMPARE(contents, data);
3890 // Currently no stdin/out supported for Windows CE.
3891 #ifndef QT_NO_PROCESS
3892 void tst_QNetworkReply::ioPutToFileFromProcess_data()
3897 void tst_QNetworkReply::ioPutToFileFromProcess()
3899 #if defined(Q_OS_WINCE)
3900 QSKIP("Currently no stdin/out supported for Windows CE");
3903 if (qstrcmp(QTest::currentDataTag(), "small") == 0)
3904 QSKIP("When passing a CR-LF-LF sequence through Windows stdio, it gets converted, "
3905 "so this test fails. Disabled on Windows");
3908 QFile file(testFileName);
3910 QUrl url = QUrl::fromLocalFile(file.fileName());
3911 QNetworkRequest request(url);
3913 QFETCH(QByteArray, data);
3915 QString echoExe = echoProcessDir + "/echo";
3916 process.start(echoExe, QStringList("all"));
3917 QVERIFY2(process.waitForStarted(), qPrintable(
3918 QString::fromLatin1("Could not start %1: %2").arg(echoExe, process.errorString())));
3919 process.write(data);
3920 process.closeWriteChannel();
3922 QNetworkReplyPtr reply = manager.put(QNetworkRequest(url), &process);
3924 QVERIFY(waitForFinish(reply) == Success);
3926 QCOMPARE(reply->url(), url);
3927 QCOMPARE(reply->error(), QNetworkReply::NoError);
3928 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
3929 QVERIFY(reply->readAll().isEmpty());
3931 QVERIFY(file.open(QIODevice::ReadOnly));
3932 QCOMPARE(file.size(), qint64(data.size()));
3933 QByteArray contents = file.readAll();
3934 QCOMPARE(contents, data);
3939 void tst_QNetworkReply::ioPutToFtpFromFile_data()
3941 ioPutToFileFromFile_data();
3944 void tst_QNetworkReply::ioPutToFtpFromFile()
3946 QFETCH(QString, fileName);
3947 QFile sourceFile(fileName);
3948 QVERIFY(sourceFile.open(QIODevice::ReadOnly));
3950 QUrl url("ftp://" + QtNetworkSettings::serverName());
3951 url.setPath(QString("/qtest/upload/qnetworkaccess-ioPutToFtpFromFile-%1-%2")
3952 .arg(QTest::currentDataTag())
3953 .arg(uniqueExtension));
3955 QNetworkRequest request(url);
3956 QNetworkReplyPtr reply = manager.put(request, &sourceFile);
3958 QVERIFY(waitForFinish(reply) == Success);
3960 QCOMPARE(reply->url(), url);
3961 QCOMPARE(reply->error(), QNetworkReply::NoError);
3962 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
3963 QVERIFY(reply->readAll().isEmpty());
3965 QVERIFY(sourceFile.atEnd());
3966 sourceFile.seek(0); // reset it to the beginning
3968 // download the file again from FTP to make sure it was uploaded
3970 QNetworkAccessManager qnam;
3971 QNetworkRequest req(url);
3972 QNetworkReply *r = qnam.get(req);
3974 QObject::connect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
3975 QTestEventLoop::instance().enterLoop(3);
3976 QObject::disconnect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
3978 QByteArray uploaded = r->readAll();
3979 QCOMPARE(qint64(uploaded.size()), sourceFile.size());
3980 QCOMPARE(uploaded, sourceFile.readAll());
3983 QObject::connect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
3984 QTestEventLoop::instance().enterLoop(10);
3985 QObject::disconnect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
3988 void tst_QNetworkReply::ioPutToHttpFromFile_data()
3990 ioPutToFileFromFile_data();
3993 void tst_QNetworkReply::ioPutToHttpFromFile()
3995 QFETCH(QString, fileName);
3996 QFile sourceFile(fileName);
3997 QVERIFY(sourceFile.open(QIODevice::ReadOnly));
3999 QUrl url("http://" + QtNetworkSettings::serverName());
4000 url.setPath(QString("/dav/qnetworkaccess-ioPutToHttpFromFile-%1-%2")
4001 .arg(QTest::currentDataTag())
4002 .arg(uniqueExtension));
4004 QNetworkRequest request(url);
4005 QNetworkReplyPtr reply = manager.put(request, &sourceFile);
4007 QVERIFY(waitForFinish(reply) == Success);
4009 QCOMPARE(reply->url(), url);
4010 QCOMPARE(reply->error(), QNetworkReply::NoError);
4012 // verify that the HTTP status code is 201 Created
4013 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 201);
4015 QVERIFY(sourceFile.atEnd());
4016 sourceFile.seek(0); // reset it to the beginning
4018 // download the file again from HTTP to make sure it was uploaded
4020 reply = manager.get(request);
4022 QVERIFY(waitForFinish(reply) == Success);
4024 QCOMPARE(reply->url(), url);
4025 QCOMPARE(reply->error(), QNetworkReply::NoError);
4026 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
4028 QCOMPARE(reply->readAll(), sourceFile.readAll());
4031 void tst_QNetworkReply::ioPostToHttpFromFile_data()
4033 ioPutToFileFromFile_data();
4036 void tst_QNetworkReply::ioPostToHttpFromFile()
4038 QFETCH(QString, fileName);
4039 QFile sourceFile(fileName);
4040 QVERIFY(sourceFile.open(QIODevice::ReadOnly));
4042 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi");
4043 QNetworkRequest request(url);
4044 request.setRawHeader("Content-Type", "application/octet-stream");
4046 QNetworkReplyPtr reply = manager.post(request, &sourceFile);
4048 QVERIFY(waitForFinish(reply) == Success);
4050 QCOMPARE(reply->url(), url);
4051 QCOMPARE(reply->error(), QNetworkReply::NoError);
4053 // verify that the HTTP status code is 200 Ok
4054 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
4056 QVERIFY(sourceFile.atEnd());
4057 sourceFile.seek(0); // reset it to the beginning
4059 QCOMPARE(reply->readAll().trimmed(), md5sum(sourceFile.readAll()).toHex());
4062 void tst_QNetworkReply::ioPostToHttpFromSocket_data()
4064 QTest::addColumn<QByteArray>("data");
4065 QTest::addColumn<QByteArray>("md5sum");
4066 QTest::addColumn<QUrl>("url");
4067 QTest::addColumn<QNetworkProxy>("proxy");
4068 QTest::addColumn<int>("authenticationRequiredCount");
4069 QTest::addColumn<int>("proxyAuthenticationRequiredCount");
4071 for (int i = 0; i < proxies.count(); ++i)
4072 for (int auth = 0; auth < 2; ++auth) {
4075 url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi";
4077 url = "http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi";
4079 QNetworkProxy proxy = proxies.at(i).proxy;
4080 QByteArray testsuffix = QByteArray(auth ? "+auth" : "") + proxies.at(i).tag;
4081 int proxyauthcount = proxies.at(i).requiresAuthentication;
4085 QTest::newRow("empty" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount;
4087 data = "This is a normal message.";
4088 QTest::newRow("generic" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount;
4090 data = "This is a message to show that Qt rocks!\r\n\n";
4091 QTest::newRow("small" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount;
4093 data = QByteArray("abcd\0\1\2\abcd",12);
4094 QTest::newRow("with-nul" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount;
4096 data = QByteArray(4097, '\4');
4097 QTest::newRow("4k+1" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount;
4099 data = QByteArray(128*1024+1, '\177');
4100 QTest::newRow("128k+1" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount;
4104 void tst_QNetworkReply::ioPostToHttpFromSocket()
4106 qRegisterMetaType<QNetworkProxy>(); // for QSignalSpy
4107 qRegisterMetaType<QAuthenticator *>();
4108 qRegisterMetaType<QNetworkReply *>();
4110 QFETCH(QByteArray, data);
4112 QFETCH(QNetworkProxy, proxy);
4113 SocketPair socketpair;
4114 socketpair.create();
4115 QVERIFY(socketpair.endPoints[0] && socketpair.endPoints[1]);
4117 socketpair.endPoints[0]->write(data);
4119 QNetworkRequest request(url);
4120 request.setRawHeader("Content-Type", "application/octet-stream");
4122 manager.setProxy(proxy);
4123 QNetworkReplyPtr reply = manager.post(request, socketpair.endPoints[1]);
4124 socketpair.endPoints[0]->close();
4126 connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
4127 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
4128 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4129 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4131 QSignalSpy authenticationRequiredSpy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4132 QSignalSpy proxyAuthenticationRequiredSpy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
4134 QVERIFY(waitForFinish(reply) == Success);
4136 disconnect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
4137 this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
4138 disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4139 this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4140 QCOMPARE(reply->error(), QNetworkReply::NoError);
4142 QCOMPARE(reply->url(), url);
4143 QCOMPARE(reply->error(), QNetworkReply::NoError);
4144 // verify that the HTTP status code is 200 Ok
4145 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
4147 QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex());
4149 QTEST(authenticationRequiredSpy.count(), "authenticationRequiredCount");
4150 QTEST(proxyAuthenticationRequiredSpy.count(), "proxyAuthenticationRequiredCount");
4153 void tst_QNetworkReply::ioPostToHttpFromSocketSynchronous_data()
4155 QTest::addColumn<QByteArray>("data");
4156 QTest::addColumn<QByteArray>("md5sum");
4160 QTest::newRow("empty") << data << md5sum(data);
4162 data = "This is a normal message.";
4163 QTest::newRow("generic") << data << md5sum(data);
4165 data = "This is a message to show that Qt rocks!\r\n\n";
4166 QTest::newRow("small") << data << md5sum(data);
4168 data = QByteArray("abcd\0\1\2\abcd",12);
4169 QTest::newRow("with-nul") << data << md5sum(data);
4171 data = QByteArray(4097, '\4');
4172 QTest::newRow("4k+1") << data << md5sum(data);
4174 data = QByteArray(128*1024+1, '\177');
4175 QTest::newRow("128k+1") << data << md5sum(data);
4177 data = QByteArray(2*1024*1024+1, '\177');
4178 QTest::newRow("2MB+1") << data << md5sum(data);
4181 void tst_QNetworkReply::ioPostToHttpFromSocketSynchronous()
4183 QFETCH(QByteArray, data);
4185 SocketPair socketpair;
4186 QVERIFY(socketpair.create());
4187 QVERIFY(socketpair.endPoints[0] && socketpair.endPoints[1]);
4188 socketpair.endPoints[0]->write(data);
4189 socketpair.endPoints[0]->waitForBytesWritten(5000);
4190 // ### for 4.8: make the socket pair unbuffered, to not read everything in one go in QNetworkReplyImplPrivate::setup()
4191 QTestEventLoop::instance().enterLoop(3);
4193 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi");
4194 QNetworkRequest request(url);
4195 request.setRawHeader("Content-Type", "application/octet-stream");
4196 request.setAttribute(
4197 QNetworkRequest::SynchronousRequestAttribute,
4200 QNetworkReplyPtr reply = manager.post(request, socketpair.endPoints[1]);
4201 QVERIFY(reply->isFinished());
4202 socketpair.endPoints[0]->close();
4204 QCOMPARE(reply->error(), QNetworkReply::NoError);
4206 QCOMPARE(reply->url(), url);
4207 QCOMPARE(reply->error(), QNetworkReply::NoError);
4208 // verify that the HTTP status code is 200 Ok
4209 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
4211 QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex());
4214 // this tests checks if rewinding the POST-data to some place in the middle
4216 void tst_QNetworkReply::ioPostToHttpFromMiddleOfFileToEnd()
4218 QFile sourceFile(testDataDir + "/rfc3252.txt");
4219 QVERIFY(sourceFile.open(QIODevice::ReadOnly));
4220 // seeking to the middle
4221 sourceFile.seek(sourceFile.size() / 2);
4223 QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi";
4224 QNetworkRequest request(url);
4225 request.setRawHeader("Content-Type", "application/octet-stream");
4226 QNetworkReplyPtr reply = manager.post(request, &sourceFile);
4228 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4229 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4231 QVERIFY(waitForFinish(reply) == Success);
4233 disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4234 this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4236 // compare half data
4237 sourceFile.seek(sourceFile.size() / 2);
4238 QByteArray data = sourceFile.readAll();
4239 QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex());
4242 void tst_QNetworkReply::ioPostToHttpFromMiddleOfFileFiveBytes()
4244 QFile sourceFile(testDataDir + "/rfc3252.txt");
4245 QVERIFY(sourceFile.open(QIODevice::ReadOnly));
4246 // seeking to the middle
4247 sourceFile.seek(sourceFile.size() / 2);
4249 QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi";
4250 QNetworkRequest request(url);
4251 request.setRawHeader("Content-Type", "application/octet-stream");
4252 // only send 5 bytes
4253 request.setHeader(QNetworkRequest::ContentLengthHeader, 5);
4254 QVERIFY(request.header(QNetworkRequest::ContentLengthHeader).isValid());
4255 QNetworkReplyPtr reply = manager.post(request, &sourceFile);
4257 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4258 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4260 QVERIFY(waitForFinish(reply) == Success);
4262 disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4263 this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4265 // compare half data
4266 sourceFile.seek(sourceFile.size() / 2);
4267 QByteArray data = sourceFile.read(5);
4268 QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex());
4271 void tst_QNetworkReply::ioPostToHttpFromMiddleOfQBufferFiveBytes()
4273 // test needed since a QBuffer goes with a different codepath than the QFile
4274 // tested in ioPostToHttpFromMiddleOfFileFiveBytes
4275 QBuffer uploadBuffer;
4276 uploadBuffer.open(QIODevice::ReadWrite);
4277 uploadBuffer.write("1234567890");
4278 uploadBuffer.seek(5);
4280 QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi";
4281 QNetworkRequest request(url);
4282 request.setRawHeader("Content-Type", "application/octet-stream");
4283 QNetworkReplyPtr reply = manager.post(request, &uploadBuffer);
4285 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4286 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4288 QVERIFY(waitForFinish(reply) == Success);
4290 disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4291 this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4293 // compare half data
4294 uploadBuffer.seek(5);
4295 QByteArray data = uploadBuffer.read(5);
4296 QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex());
4300 void tst_QNetworkReply::ioPostToHttpNoBufferFlag()
4302 QByteArray data = QByteArray("daaaaaaataaaaaaa");
4303 // create a sequential QIODevice by feeding the data into a local TCP server
4304 SocketPair socketpair;
4305 socketpair.create();
4306 QVERIFY(socketpair.endPoints[0] && socketpair.endPoints[1]);
4307 socketpair.endPoints[0]->write(data);
4309 QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi";
4310 QNetworkRequest request(url);
4311 request.setRawHeader("Content-Type", "application/octet-stream");
4312 // disallow buffering
4313 request.setAttribute(QNetworkRequest::DoNotBufferUploadDataAttribute, true);
4314 request.setHeader(QNetworkRequest::ContentLengthHeader, data.size());
4315 QNetworkReplyPtr reply = manager.post(request, socketpair.endPoints[1]);
4316 socketpair.endPoints[0]->close();
4318 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4319 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4321 QVERIFY(waitForFinish(reply) == Failure);
4323 disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4324 this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4326 // verify: error code is QNetworkReply::ContentReSendError
4327 QCOMPARE(reply->error(), QNetworkReply::ContentReSendError);
4331 class SslServer : public QTcpServer {
4334 SslServer() : socket(0) {};
4335 void incomingConnection(qintptr socketDescriptor) {
4336 QSslSocket *serverSocket = new QSslSocket;
4337 serverSocket->setParent(this);
4339 if (serverSocket->setSocketDescriptor(socketDescriptor)) {
4340 QString testDataDir = QFileInfo(QFINDTESTDATA("rfc3252.txt")).absolutePath();
4341 if (testDataDir.isEmpty())
4342 testDataDir = QCoreApplication::applicationDirPath();
4344 connect(serverSocket, SIGNAL(encrypted()), this, SLOT(encryptedSlot()));
4345 connect(serverSocket, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
4346 serverSocket->setProtocol(QSsl::AnyProtocol);
4347 connect(serverSocket, SIGNAL(sslErrors(const QList<QSslError>&)), serverSocket, SLOT(ignoreSslErrors()));
4348 serverSocket->setLocalCertificate(testDataDir + "/certs/server.pem");
4349 serverSocket->setPrivateKey(testDataDir + "/certs/server.key");
4350 serverSocket->startServerEncryption();
4352 delete serverSocket;
4356 void newEncryptedConnection();
4358 void encryptedSlot() {
4359 socket = (QSslSocket*) sender();
4360 emit newEncryptedConnection();
4362 void readyReadSlot() {
4363 // for the incoming sockets, not the server socket
4364 //qDebug() << static_cast<QSslSocket*>(sender())->bytesAvailable() << static_cast<QSslSocket*>(sender())->encryptedBytesAvailable();
4371 // very similar to ioPostToHttpUploadProgress but for SSL
4372 void tst_QNetworkReply::ioPostToHttpsUploadProgress()
4374 //QFile sourceFile(testDataDir + "/bigfile");
4375 //QVERIFY(sourceFile.open(QIODevice::ReadOnly));
4376 qint64 wantedSize = 2*1024*1024; // 2 MB
4377 QByteArray sourceFile;
4378 // And in the case of SSL, the compression can fool us and let the
4379 // server send the data much faster than expected.
4380 // So better provide random data that cannot be compressed.
4381 for (int i = 0; i < wantedSize; ++i)
4382 sourceFile += (char)qrand();
4384 // emulate a minimal https server
4386 server.listen(QHostAddress(QHostAddress::LocalHost), 0);
4388 // create the request
4389 QUrl url = QUrl(QString("https://127.0.0.1:%1/").arg(server.serverPort()));
4390 QNetworkRequest request(url);
4392 request.setRawHeader("Content-Type", "application/octet-stream");
4393 QNetworkReplyPtr reply = manager.post(request, sourceFile);
4395 QSignalSpy spy(reply, SIGNAL(uploadProgress(qint64,qint64)));
4396 connect(&server, SIGNAL(newEncryptedConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
4397 connect(reply, SIGNAL(sslErrors(const QList<QSslError>&)), reply, SLOT(ignoreSslErrors()));
4399 // get the request started and the incoming socket connected
4400 QTestEventLoop::instance().enterLoop(10);
4401 QVERIFY(!QTestEventLoop::instance().timeout());
4402 QTcpSocket *incomingSocket = server.socket;
4403 QVERIFY(incomingSocket);
4404 disconnect(&server, SIGNAL(newEncryptedConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
4407 incomingSocket->setReadBufferSize(1*1024);
4408 QTestEventLoop::instance().enterLoop(2);
4409 // some progress should have been made
4410 QVERIFY(!spy.isEmpty());
4411 QList<QVariant> args = spy.last();
4412 QVERIFY(args.at(0).toLongLong() > 0);
4413 // but not everything!
4414 QVERIFY(args.at(0).toLongLong() != sourceFile.size());
4416 // set the read buffer to unlimited
4417 incomingSocket->setReadBufferSize(0);
4418 QTestEventLoop::instance().enterLoop(10);
4419 // progress should be finished
4420 QVERIFY(!spy.isEmpty());
4421 QList<QVariant> args3 = spy.last();
4422 QCOMPARE(args3.at(0).toLongLong(), args3.at(1).toLongLong());
4423 QCOMPARE(args3.at(0).toLongLong(), qint64(sourceFile.size()));
4425 // after sending this, the QNAM should emit finished()
4426 incomingSocket->write("HTTP/1.0 200 OK\r\n");
4427 incomingSocket->write("Content-Length: 0\r\n");
4428 incomingSocket->write("\r\n");
4430 QVERIFY(waitForFinish(reply) == Success);
4432 incomingSocket->close();
4437 void tst_QNetworkReply::ioGetFromBuiltinHttp_data()
4439 QTest::addColumn<bool>("https");
4440 QTest::addColumn<int>("bufferSize");
4441 QTest::newRow("http+unlimited") << false << 0;
4442 QTest::newRow("http+limited") << false << 4096;
4444 QTest::newRow("https+unlimited") << true << 0;
4445 QTest::newRow("https+limited") << true << 4096;
4449 void tst_QNetworkReply::ioGetFromBuiltinHttp()
4451 QSKIP("Limiting is broken right now, check QTBUG-15065");
4452 QFETCH(bool, https);
4453 QFETCH(int, bufferSize);
4455 QByteArray testData;
4456 // Make the data big enough so that it can fill the kernel buffer
4457 // (which seems to hold 202 KB here)
4458 const int wantedSize = 1200 * 1000;
4459 testData.reserve(wantedSize);
4460 // And in the case of SSL, the compression can fool us and let the
4461 // server send the data much faster than expected.
4462 // So better provide random data that cannot be compressed.
4463 for (int i = 0; i < wantedSize; ++i)
4464 testData += (char)qrand();
4466 QByteArray httpResponse = QByteArray("HTTP/1.0 200 OK\r\nContent-Length: ");
4467 httpResponse += QByteArray::number(testData.size());
4468 httpResponse += "\r\n\r\n";
4469 httpResponse += testData;
4471 qDebug() << "Server will send" << (httpResponse.size()-testData.size()) << "bytes of header and"
4472 << testData.size() << "bytes of data";
4474 const bool fillKernelBuffer = bufferSize > 0;
4475 FastSender server(httpResponse, https, fillKernelBuffer);
4477 QUrl url(QString("%1://127.0.0.1:%2/qtest/rfc3252.txt")
4478 .arg(https?"https":"http")
4479 .arg(server.serverPort()));
4480 QNetworkRequest request(url);
4481 QNetworkReplyPtr reply = manager.get(request);
4482 reply->setReadBufferSize(bufferSize);
4483 reply->ignoreSslErrors();
4484 const int rate = 200; // in kB per sec
4485 RateControlledReader reader(server, reply, rate, bufferSize);
4490 QVERIFY(waitForFinish(reply) == Success);
4492 const int elapsedTime = loopTime.elapsed();
4496 qDebug() << "send rate:" << server.transferRate << "B/s";
4497 qDebug() << "receive rate:" << reader.totalBytesRead * 1000 / elapsedTime
4498 << "(it received" << reader.totalBytesRead << "bytes in" << elapsedTime << "ms)";
4500 QCOMPARE(reply->url(), request.url());
4501 QCOMPARE(reply->error(), QNetworkReply::NoError);
4502 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
4504 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), (qint64)testData.size());
4505 if (reader.data.size() < testData.size()) { // oops?
4506 QCOMPARE(reader.data, testData.mid(0, reader.data.size()));
4507 qDebug() << "The data is incomplete, the last" << testData.size() - reader.data.size() << "bytes are missing";
4508 QEXPECT_FAIL("http+limited", "Limiting is broken right now, check QTBUG-15065", Abort);
4509 QEXPECT_FAIL("https+limited", "Limiting is broken right now, check QTBUG-15065", Abort);
4511 QCOMPARE(reader.data.size(), testData.size());
4512 QCOMPARE(reader.data, testData);
4514 // OK we got the file alright, but did setReadBufferSize work?
4515 QVERIFY(server.transferRate != -1);
4516 if (bufferSize > 0) {
4517 const int allowedDeviation = 16; // TODO find out why the send rate is 13% faster currently
4518 const int minRate = rate * 1024 * (100-allowedDeviation) / 100;
4519 const int maxRate = rate * 1024 * (100+allowedDeviation) / 100;
4520 qDebug() << minRate << "<="<< server.transferRate << "<=" << maxRate << "?";
4521 QEXPECT_FAIL("http+limited", "Limiting is broken right now, check QTBUG-15065", Continue);
4522 QEXPECT_FAIL("https+limited", "Limiting is broken right now, check QTBUG-15065", Continue);
4523 QVERIFY(server.transferRate >= minRate && server.transferRate <= maxRate);
4527 void tst_QNetworkReply::ioPostToHttpUploadProgress()
4529 QFile sourceFile(testDataDir + "/bigfile");
4530 QVERIFY(sourceFile.open(QIODevice::ReadOnly));
4532 // emulate a minimal http server
4534 server.listen(QHostAddress(QHostAddress::LocalHost), 0);
4536 // create the request
4537 QUrl url = QUrl(QString("http://127.0.0.1:%1/").arg(server.serverPort()));
4538 QNetworkRequest request(url);
4539 request.setRawHeader("Content-Type", "application/octet-stream");
4540 QNetworkReplyPtr reply = manager.post(request, &sourceFile);
4541 QSignalSpy spy(reply, SIGNAL(uploadProgress(qint64,qint64)));
4542 connect(&server, SIGNAL(newConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
4544 // get the request started and the incoming socket connected
4545 QTestEventLoop::instance().enterLoop(10);
4546 QVERIFY(!QTestEventLoop::instance().timeout());
4547 QTcpSocket *incomingSocket = server.nextPendingConnection();
4548 QVERIFY(incomingSocket);
4549 disconnect(&server, SIGNAL(newConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
4551 incomingSocket->setReadBufferSize(1*1024);
4552 QTestEventLoop::instance().enterLoop(5);
4553 // some progress should have been made
4554 QList<QVariant> args = spy.last();
4555 QVERIFY(!args.isEmpty());
4556 QVERIFY(args.at(0).toLongLong() > 0);
4557 // but not everything!
4558 QVERIFY(args.at(0).toLongLong() != sourceFile.size());
4560 // set the read buffer to unlimited
4561 incomingSocket->setReadBufferSize(0);
4562 QTestEventLoop::instance().enterLoop(10);
4563 // progress should be finished
4564 QList<QVariant> args3 = spy.last();
4565 QVERIFY(!args3.isEmpty());
4566 // More progress than before
4567 QVERIFY(args3.at(0).toLongLong() > args.at(0).toLongLong());
4568 QCOMPARE(args3.at(0).toLongLong(), args3.at(1).toLongLong());
4569 // And actually finished..
4570 QCOMPARE(args3.at(0).toLongLong(), sourceFile.size());
4572 // after sending this, the QNAM should emit finished()
4573 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
4574 incomingSocket->write("HTTP/1.0 200 OK\r\n");
4575 incomingSocket->write("Content-Length: 0\r\n");
4576 incomingSocket->write("\r\n");
4577 QTestEventLoop::instance().enterLoop(10);
4578 // not timeouted -> finished() was emitted
4579 QVERIFY(!QTestEventLoop::instance().timeout());
4581 incomingSocket->close();
4585 void tst_QNetworkReply::ioPostToHttpEmptyUploadProgress()
4589 QBuffer buffer(&ba,0);
4590 QVERIFY(buffer.open(QIODevice::ReadOnly));
4592 // emulate a minimal http server
4594 server.listen(QHostAddress(QHostAddress::LocalHost), 0);
4596 // create the request
4597 QUrl url = QUrl(QString("http://127.0.0.1:%1/").arg(server.serverPort()));
4598 QNetworkRequest request(url);
4599 request.setRawHeader("Content-Type", "application/octet-stream");
4600 QNetworkReplyPtr reply = manager.post(request, &buffer);
4601 QSignalSpy spy(reply, SIGNAL(uploadProgress(qint64,qint64)));
4602 connect(&server, SIGNAL(newConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
4605 // get the request started and the incoming socket connected
4606 QTestEventLoop::instance().enterLoop(10);
4607 QVERIFY(!QTestEventLoop::instance().timeout());
4608 QTcpSocket *incomingSocket = server.nextPendingConnection();
4609 QVERIFY(incomingSocket);
4611 // after sending this, the QNAM should emit finished()
4612 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
4613 incomingSocket->write("HTTP/1.0 200 OK\r\n");
4614 incomingSocket->write("Content-Length: 0\r\n");
4615 incomingSocket->write("\r\n");
4616 incomingSocket->flush();
4617 QTestEventLoop::instance().enterLoop(10);
4618 // not timeouted -> finished() was emitted
4619 QVERIFY(!QTestEventLoop::instance().timeout());
4621 // final check: only 1 uploadProgress has been emitted
4622 QVERIFY(spy.length() == 1);
4623 QList<QVariant> args = spy.last();
4624 QVERIFY(!args.isEmpty());
4625 QCOMPARE(args.at(0).toLongLong(), buffer.size());
4626 QCOMPARE(args.at(0).toLongLong(), buffer.size());
4628 incomingSocket->close();
4632 void tst_QNetworkReply::lastModifiedHeaderForFile()
4634 QFileInfo fileInfo(testDataDir + "/bigfile");
4635 QVERIFY(fileInfo.exists());
4637 QUrl url = QUrl::fromLocalFile(fileInfo.filePath());
4639 QNetworkRequest request(url);
4640 QNetworkReplyPtr reply = manager.head(request);
4642 QVERIFY(waitForFinish(reply) == Success);
4644 QDateTime header = reply->header(QNetworkRequest::LastModifiedHeader).toDateTime();
4645 QCOMPARE(header, fileInfo.lastModified());
4648 void tst_QNetworkReply::lastModifiedHeaderForHttp()
4650 // Tue, 22 May 2007 12:04:57 GMT according to webserver
4651 QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/fluke.gif";
4653 QNetworkRequest request(url);
4654 QNetworkReplyPtr reply = manager.head(request);
4656 QVERIFY(waitForFinish(reply) == Success);
4658 QDateTime header = reply->header(QNetworkRequest::LastModifiedHeader).toDateTime();
4659 QDateTime realDate = QDateTime::fromString("2007-05-22T12:04:57", Qt::ISODate);
4660 realDate.setTimeSpec(Qt::UTC);
4662 QCOMPARE(header, realDate);
4665 void tst_QNetworkReply::httpCanReadLine()
4667 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
4668 QNetworkReplyPtr reply = manager.get(request);
4670 QVERIFY(waitForFinish(reply) == Success);
4672 QCOMPARE(reply->error(), QNetworkReply::NoError);
4674 QVERIFY(reply->canReadLine());
4675 QVERIFY(!reply->readAll().isEmpty());
4676 QVERIFY(!reply->canReadLine());
4679 void tst_QNetworkReply::rateControl_data()
4681 QTest::addColumn<int>("rate");
4683 QTest::newRow("15") << 15;
4684 QTest::newRow("40") << 40;
4685 QTest::newRow("73") << 73;
4686 QTest::newRow("80") << 80;
4687 QTest::newRow("125") << 125;
4688 QTest::newRow("250") << 250;
4689 QTest::newRow("1024") << 1024;
4692 void tst_QNetworkReply::rateControl()
4694 QSKIP("Test disabled -- only for manual purposes");
4695 // this function tests that we aren't reading from the network
4696 // faster than the data is being consumed.
4699 #if !defined(QT_BUILD_INTERNAL)
4700 QSKIP("backend for testing not available!");
4703 // ask for 20 seconds worth of data
4704 FastSender sender(20 * rate * 1024);
4706 QNetworkRequest request("debugpipe://localhost:" + QString::number(sender.serverPort()));
4707 QNetworkReplyPtr reply = manager.get(request);
4708 reply->setReadBufferSize(32768);
4709 qRegisterMetaType<QNetworkReply::NetworkError>("QNetworkReply::NetworkError");
4710 QSignalSpy errorSpy(reply, SIGNAL(error(QNetworkReply::NetworkError)));
4712 RateControlledReader reader(sender, reply, rate, 20);
4714 // this test is designed to run for 25 seconds at most
4718 QVERIFY(waitForFinish(reply) == Success);
4720 int elapsedTime = loopTime.elapsed();
4722 if (!errorSpy.isEmpty()) {
4723 qDebug() << "ERROR!" << errorSpy[0][0] << reply->errorString();
4726 qDebug() << "tst_QNetworkReply::rateControl" << "send rate:" << sender.transferRate;
4727 qDebug() << "tst_QNetworkReply::rateControl" << "receive rate:" << reader.totalBytesRead * 1000 / elapsedTime
4728 << "(it received" << reader.totalBytesRead << "bytes in" << elapsedTime << "ms)";
4732 QCOMPARE(reply->url(), request.url());
4733 QCOMPARE(reply->error(), QNetworkReply::NoError);
4735 QVERIFY(sender.transferRate != -1);
4736 int minRate = rate * 1024 * 9 / 10;
4737 int maxRate = rate * 1024 * 11 / 10;
4738 QVERIFY(sender.transferRate >= minRate);
4739 QVERIFY(sender.transferRate <= maxRate);
4742 void tst_QNetworkReply::downloadProgress_data()
4744 QTest::addColumn<int>("loopCount");
4746 QTest::newRow("empty") << 0;
4747 QTest::newRow("small") << 4;
4748 QTest::newRow("big") << 4096;
4751 void tst_QNetworkReply::downloadProgress()
4753 #if !defined(QT_BUILD_INTERNAL)
4754 QSKIP("backend for testing not available!");
4757 QVERIFY(server.listen());
4759 QNetworkRequest request("debugpipe://127.0.0.1:" + QString::number(server.serverPort()) + "/?bare=1");
4760 QNetworkReplyPtr reply = manager.get(request);
4761 QSignalSpy spy(reply, SIGNAL(downloadProgress(qint64,qint64)));
4762 connect(reply, SIGNAL(downloadProgress(qint64,qint64)),
4763 &QTestEventLoop::instance(), SLOT(exitLoop()));
4764 QVERIFY(spy.isValid());
4765 QVERIFY(!reply->isFinished());
4766 QVERIFY(reply->isRunning());
4768 QCoreApplication::instance()->processEvents();
4769 if (!server.hasPendingConnections())
4770 server.waitForNewConnection(1000);
4771 QVERIFY(server.hasPendingConnections());
4772 QCOMPARE(spy.count(), 0);
4774 QByteArray data(128, 'a');
4775 QTcpSocket *sender = server.nextPendingConnection();
4778 QFETCH(int, loopCount);
4779 for (int i = 1; i <= loopCount; ++i) {
4780 sender->write(data);
4781 QVERIFY2(sender->waitForBytesWritten(2000), "Network timeout");
4784 QTestEventLoop::instance().enterLoop(2);
4785 QVERIFY(!QTestEventLoop::instance().timeout());
4786 QVERIFY(spy.count() > 0);
4787 QVERIFY(!reply->isFinished());
4788 QVERIFY(reply->isRunning());
4790 QList<QVariant> args = spy.last();
4791 QCOMPARE(args.at(0).toInt(), i*data.size());
4792 QCOMPARE(args.at(1).toInt(), -1);
4795 // close the connection:
4799 QTestEventLoop::instance().enterLoop(2);
4800 QCOMPARE(reply->error(), QNetworkReply::NoError);
4801 QVERIFY(!QTestEventLoop::instance().timeout());
4802 QVERIFY(spy.count() > 0);
4803 QVERIFY(!reply->isRunning());
4804 QVERIFY(reply->isFinished());
4806 QList<QVariant> args = spy.last();
4807 QCOMPARE(args.at(0).toInt(), loopCount * data.size());
4808 QCOMPARE(args.at(1).toInt(), loopCount * data.size());
4811 void tst_QNetworkReply::uploadProgress_data()
4816 void tst_QNetworkReply::uploadProgress()
4818 QFETCH(QByteArray, data);
4819 #if !defined(QT_BUILD_INTERNAL)
4820 QSKIP("backend for testing not available!");
4823 QVERIFY(server.listen());
4825 QNetworkRequest request("debugpipe://127.0.0.1:" + QString::number(server.serverPort()) + "/?bare=1");
4826 QNetworkReplyPtr reply = manager.put(request, data);
4827 QSignalSpy spy(reply, SIGNAL(uploadProgress(qint64,qint64)));
4828 QSignalSpy finished(reply, SIGNAL(finished()));
4829 QVERIFY(spy.isValid());
4830 QVERIFY(finished.isValid());
4832 QCoreApplication::instance()->processEvents();
4833 if (!server.hasPendingConnections())
4834 server.waitForNewConnection(1000);
4835 QVERIFY(server.hasPendingConnections());
4837 QTcpSocket *receiver = server.nextPendingConnection();
4838 if (finished.count() == 0) {
4839 // it's not finished yet, so wait for it to be
4840 QVERIFY(waitForFinish(reply) == Success);
4844 QVERIFY(finished.count() > 0);
4845 QVERIFY(spy.count() > 0);
4847 QList<QVariant> args = spy.last();
4848 QCOMPARE(args.at(0).toInt(), data.size());
4849 QCOMPARE(args.at(1).toInt(), data.size());
4852 void tst_QNetworkReply::chaining_data()
4857 void tst_QNetworkReply::chaining()
4859 QTemporaryFile sourceFile(QDir::currentPath() + "/temp-XXXXXX");
4860 sourceFile.setAutoRemove(true);
4861 QVERIFY(sourceFile.open());
4863 QFETCH(QByteArray, data);
4864 QVERIFY(sourceFile.write(data) == data.size());
4866 QCOMPARE(sourceFile.size(), qint64(data.size()));
4868 QNetworkRequest request(QUrl::fromLocalFile(sourceFile.fileName()));
4869 QNetworkReplyPtr getReply = manager.get(request);
4871 QFile targetFile(testFileName);
4872 QUrl url = QUrl::fromLocalFile(targetFile.fileName());
4873 request.setUrl(url);
4874 QNetworkReplyPtr putReply = manager.put(request, getReply);
4876 QVERIFY(waitForFinish(putReply) == Success);
4878 QCOMPARE(getReply->url(), QUrl::fromLocalFile(sourceFile.fileName()));
4879 QCOMPARE(getReply->error(), QNetworkReply::NoError);
4880 QCOMPARE(getReply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), sourceFile.size());
4882 QCOMPARE(putReply->url(), url);
4883 QCOMPARE(putReply->error(), QNetworkReply::NoError);
4884 QCOMPARE(putReply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
4885 QVERIFY(putReply->readAll().isEmpty());
4887 QVERIFY(sourceFile.atEnd());
4888 sourceFile.seek(0); // reset it to the beginning
4890 QVERIFY(targetFile.open(QIODevice::ReadOnly));
4891 QCOMPARE(targetFile.size(), sourceFile.size());
4892 QCOMPARE(targetFile.readAll(), sourceFile.readAll());
4895 void tst_QNetworkReply::receiveCookiesFromHttp_data()
4897 QTest::addColumn<QString>("cookieString");
4898 QTest::addColumn<QList<QNetworkCookie> >("expectedCookiesFromHttp");
4899 QTest::addColumn<QList<QNetworkCookie> >("expectedCookiesInJar");
4901 QTest::newRow("empty") << "" << QList<QNetworkCookie>() << QList<QNetworkCookie>();
4903 QList<QNetworkCookie> header, jar;
4904 QNetworkCookie cookie("a", "b");
4906 cookie.setDomain(QtNetworkSettings::serverName());
4907 cookie.setPath("/qtest/cgi-bin/");
4909 QTest::newRow("simple-cookie") << "a=b" << header << jar;
4911 header << QNetworkCookie("c", "d");
4912 cookie.setName("c");
4913 cookie.setValue("d");
4915 QTest::newRow("two-cookies") << "a=b, c=d" << header << jar;
4916 QTest::newRow("two-cookies-2") << "a=b\nc=d" << header << jar;
4920 cookie = QNetworkCookie("a", "b");
4921 cookie.setPath("/not/part-of-path");
4923 cookie.setDomain(QtNetworkSettings::serverName());
4925 QTest::newRow("invalid-cookie-path") << "a=b; path=/not/part-of-path" << header << jar;
4928 cookie = QNetworkCookie("a", "b");
4929 cookie.setDomain(".example.com");
4932 QTest::newRow("invalid-cookie-domain") << "a=b; domain=.example.com" << header << jar;
4935 void tst_QNetworkReply::receiveCookiesFromHttp()
4937 QFETCH(QString, cookieString);
4939 QByteArray data = cookieString.toLatin1() + '\n';
4940 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/set-cookie.cgi");
4941 QNetworkRequest request(url);
4942 request.setRawHeader("Content-Type", "application/octet-stream");
4943 QNetworkReplyPtr reply;
4944 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PostOperation, request, reply, data));
4946 QCOMPARE(reply->url(), url);
4947 QCOMPARE(reply->error(), QNetworkReply::NoError);
4949 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
4951 QList<QNetworkCookie> setCookies =
4952 qvariant_cast<QList<QNetworkCookie> >(reply->header(QNetworkRequest::SetCookieHeader));
4953 QTEST(setCookies, "expectedCookiesFromHttp");
4954 QTEST(cookieJar->allCookies(), "expectedCookiesInJar");
4957 void tst_QNetworkReply::receiveCookiesFromHttpSynchronous_data()
4959 tst_QNetworkReply::receiveCookiesFromHttp_data();
4962 void tst_QNetworkReply::receiveCookiesFromHttpSynchronous()
4964 QFETCH(QString, cookieString);
4966 QByteArray data = cookieString.toLatin1() + '\n';
4967 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/set-cookie.cgi");
4969 QNetworkRequest request(url);
4970 request.setRawHeader("Content-Type", "application/octet-stream");
4971 request.setAttribute(
4972 QNetworkRequest::SynchronousRequestAttribute,
4975 QNetworkReplyPtr reply;
4976 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PostOperation, request, reply, data));
4978 QCOMPARE(reply->url(), url);
4979 QCOMPARE(reply->error(), QNetworkReply::NoError);
4981 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
4983 QList<QNetworkCookie> setCookies =
4984 qvariant_cast<QList<QNetworkCookie> >(reply->header(QNetworkRequest::SetCookieHeader));
4985 QTEST(setCookies, "expectedCookiesFromHttp");
4986 QTEST(cookieJar->allCookies(), "expectedCookiesInJar");
4989 void tst_QNetworkReply::sendCookies_data()
4991 QTest::addColumn<QList<QNetworkCookie> >("cookiesToSet");
4992 QTest::addColumn<QString>("expectedCookieString");
4994 QList<QNetworkCookie> list;
4995 QTest::newRow("empty") << list << "";
4997 QNetworkCookie cookie("a", "b");
4998 cookie.setPath("/");
4999 cookie.setDomain("example.com");
5001 QTest::newRow("no-match-domain") << list << "";
5003 cookie.setDomain(QtNetworkSettings::serverName());
5004 cookie.setPath("/something/else");
5006 QTest::newRow("no-match-path") << list << "";
5008 cookie.setPath("/");
5010 QTest::newRow("simple-cookie") << list << "a=b";
5012 cookie.setPath("/qtest");
5013 cookie.setValue("longer");
5015 QTest::newRow("two-cookies") << list << "a=longer; a=b";
5018 cookie = QNetworkCookie("a", "b");
5019 cookie.setPath("/");
5020 cookie.setDomain("." + QtNetworkSettings::serverDomainName());
5022 QTest::newRow("domain-match") << list << "a=b";
5024 // but it shouldn't match this:
5025 cookie.setDomain(QtNetworkSettings::serverDomainName());
5027 QTest::newRow("domain-match-2") << list << "a=b";
5030 void tst_QNetworkReply::sendCookies()
5032 QFETCH(QString, expectedCookieString);
5033 QFETCH(QList<QNetworkCookie>, cookiesToSet);
5034 cookieJar->setAllCookies(cookiesToSet);
5036 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/get-cookie.cgi");
5037 QNetworkRequest request(url);
5038 QNetworkReplyPtr reply;
5039 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
5041 QCOMPARE(reply->url(), url);
5042 QCOMPARE(reply->error(), QNetworkReply::NoError);
5044 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
5046 QCOMPARE(QString::fromLatin1(reply->readAll()).trimmed(), expectedCookieString);
5049 void tst_QNetworkReply::sendCookiesSynchronous_data()
5051 tst_QNetworkReply::sendCookies_data();
5054 void tst_QNetworkReply::sendCookiesSynchronous()
5056 QFETCH(QString, expectedCookieString);
5057 QFETCH(QList<QNetworkCookie>, cookiesToSet);
5058 cookieJar->setAllCookies(cookiesToSet);
5060 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/get-cookie.cgi");
5061 QNetworkRequest request(url);
5063 request.setAttribute(
5064 QNetworkRequest::SynchronousRequestAttribute,
5067 QNetworkReplyPtr reply;
5068 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
5070 QCOMPARE(reply->url(), url);
5071 QCOMPARE(reply->error(), QNetworkReply::NoError);
5073 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
5075 QCOMPARE(QString::fromLatin1(reply->readAll()).trimmed(), expectedCookieString);
5078 void tst_QNetworkReply::nestedEventLoops_slot()
5082 // 16 seconds: fluke times out in 15 seconds, which triggers a QTcpSocket error
5083 QTimer::singleShot(16000, &subloop, SLOT(quit()));
5086 QTestEventLoop::instance().exitLoop();
5089 void tst_QNetworkReply::nestedEventLoops()
5091 // Slightly fragile test, it may not be testing anything
5092 // This is certifying that we're not running into the same issue
5093 // that QHttp had (task 200432): the QTcpSocket connection is
5094 // closed by the remote end because of the kept-alive HTTP
5095 // connection timed out.
5097 // The exact time required for this to happen is not exactly
5098 // defined. Our server (Apache httpd) times out after 15
5099 // seconds. (see above)
5101 qDebug("Takes 16 seconds to run, please wait");
5102 qRegisterMetaType<QNetworkReply::NetworkError>();
5104 QUrl url("http://" + QtNetworkSettings::serverName());
5105 QNetworkRequest request(url);
5106 QNetworkReplyPtr reply = manager.get(request);
5108 QSignalSpy finishedspy(reply, SIGNAL(finished()));
5109 QSignalSpy errorspy(reply, SIGNAL(error(QNetworkReply::NetworkError)));
5111 connect(reply, SIGNAL(finished()), SLOT(nestedEventLoops_slot()));
5112 QTestEventLoop::instance().enterLoop(20);
5113 QVERIFY2(!QTestEventLoop::instance().timeout(), "Network timeout");
5115 QCOMPARE(finishedspy.count(), 1);
5116 QCOMPARE(errorspy.count(), 0);
5119 void tst_QNetworkReply::httpProxyCommands_data()
5121 QTest::addColumn<QUrl>("url");
5122 QTest::addColumn<QByteArray>("responseToSend");
5123 QTest::addColumn<QString>("expectedCommand");
5125 QTest::newRow("http")
5126 << QUrl("http://0.0.0.0:4443/http-request")
5127 << QByteArray("HTTP/1.0 200 OK\r\nProxy-Connection: close\r\nContent-Length: 1\r\n\r\n1")
5128 << "GET http://0.0.0.0:4443/http-request HTTP/1.";
5130 QTest::newRow("https")
5131 << QUrl("https://0.0.0.0:4443/https-request")
5132 << QByteArray("HTTP/1.0 200 Connection Established\r\n\r\n")
5133 << "CONNECT 0.0.0.0:4443 HTTP/1.";
5137 void tst_QNetworkReply::httpProxyCommands()
5140 QFETCH(QByteArray, responseToSend);
5141 QFETCH(QString, expectedCommand);
5143 MiniHttpServer proxyServer(responseToSend);
5144 QNetworkProxy proxy(QNetworkProxy::HttpProxy, "127.0.0.1", proxyServer.serverPort());
5146 manager.setProxy(proxy);
5147 QNetworkRequest request(url);
5148 request.setRawHeader("User-Agent", "QNetworkReplyAutoTest/1.0");
5149 QNetworkReplyPtr reply = manager.get(request);
5150 //clearing the proxy here causes the test to fail.
5151 //the proxy isn't used until after the bearer has been started
5152 //which is correct in general, because system proxy isn't known until that time.
5153 //removing this line is safe, as the proxy is also reset by the cleanup() function
5154 //manager.setProxy(QNetworkProxy());
5156 // wait for the finished signal
5157 QVERIFY(waitForFinish(reply) != Timeout);
5159 //qDebug() << reply->error() << reply->errorString();
5160 //qDebug() << proxyServer.receivedData;
5162 // we don't really care if the request succeeded
5163 // especially since it won't succeed in the HTTPS case
5164 // so just check that the command was correct
5166 QString receivedHeader = proxyServer.receivedData.left(expectedCommand.length());
5167 QCOMPARE(receivedHeader, expectedCommand);
5169 //QTBUG-17223 - make sure the user agent from the request is sent to proxy server even for CONNECT
5170 int uapos = proxyServer.receivedData.indexOf("User-Agent");
5171 int uaend = proxyServer.receivedData.indexOf("\r\n", uapos);
5172 QByteArray uaheader = proxyServer.receivedData.mid(uapos, uaend - uapos);
5173 QCOMPARE(uaheader, QByteArray("User-Agent: QNetworkReplyAutoTest/1.0"));
5176 class ProxyChangeHelper : public QObject {
5179 ProxyChangeHelper() : QObject(), signalCount(0) {};
5181 void finishedSlot() {
5183 if (signalCount == 2)
5184 QMetaObject::invokeMethod(&QTestEventLoop::instance(), "exitLoop", Qt::QueuedConnection);
5190 void tst_QNetworkReply::httpProxyCommandsSynchronous_data()
5192 httpProxyCommands_data();
5195 struct QThreadCleanup
5197 static inline void cleanup(QThread *thread)
5200 if (thread->wait(3000))
5203 qWarning("thread hung, leaking memory so test can finish");
5207 struct QDeleteLaterCleanup
5209 static inline void cleanup(QObject *o)
5215 void tst_QNetworkReply::httpProxyCommandsSynchronous()
5218 QFETCH(QByteArray, responseToSend);
5219 QFETCH(QString, expectedCommand);
5221 // when using synchronous commands, we need a different event loop for
5222 // the server thread, because the client is never returning to the
5224 QScopedPointer<QThread, QThreadCleanup> serverThread(new QThread);
5225 QScopedPointer<MiniHttpServer, QDeleteLaterCleanup> proxyServer(new MiniHttpServer(responseToSend, false, serverThread.data()));
5226 QNetworkProxy proxy(QNetworkProxy::HttpProxy, "127.0.0.1", proxyServer->serverPort());
5228 manager.setProxy(proxy);
5229 QNetworkRequest request(url);
5231 // send synchronous request
5232 request.setAttribute(
5233 QNetworkRequest::SynchronousRequestAttribute,
5236 QNetworkReplyPtr reply = manager.get(request);
5237 QVERIFY(reply->isFinished()); // synchronous
5238 manager.setProxy(QNetworkProxy());
5240 //qDebug() << reply->error() << reply->errorString();
5242 // we don't really care if the request succeeded
5243 // especially since it won't succeed in the HTTPS case
5244 // so just check that the command was correct
5246 QString receivedHeader = proxyServer->receivedData.left(expectedCommand.length());
5247 QCOMPARE(receivedHeader, expectedCommand);
5250 void tst_QNetworkReply::proxyChange()
5252 ProxyChangeHelper helper;
5253 MiniHttpServer proxyServer(
5254 "HTTP/1.0 200 OK\r\nProxy-Connection: keep-alive\r\n"
5255 "Content-Length: 1\r\n\r\n1");
5256 QNetworkProxy dummyProxy(QNetworkProxy::HttpProxy, "127.0.0.1", proxyServer.serverPort());
5257 QNetworkRequest req(QUrl("http://" + QtNetworkSettings::serverName()));
5258 proxyServer.doClose = false;
5260 manager.setProxy(dummyProxy);
5261 QNetworkReplyPtr reply1 = manager.get(req);
5262 connect(reply1, SIGNAL(finished()), &helper, SLOT(finishedSlot()));
5264 manager.setProxy(QNetworkProxy());
5265 QNetworkReplyPtr reply2 = manager.get(req);
5266 connect(reply2, SIGNAL(finished()), &helper, SLOT(finishedSlot()));
5268 QTestEventLoop::instance().enterLoop(20);
5269 QVERIFY(!QTestEventLoop::instance().timeout());
5271 // verify that the replies succeeded
5272 QCOMPARE(reply1->error(), QNetworkReply::NoError);
5273 QCOMPARE(reply1->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
5274 QVERIFY(reply1->size() == 1);
5276 QCOMPARE(reply2->error(), QNetworkReply::NoError);
5277 QCOMPARE(reply2->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
5278 QVERIFY(reply2->size() > 1);
5280 // now try again and get an error
5281 // this verifies that we reuse the already-open connection
5283 proxyServer.doClose = true;
5284 proxyServer.dataToTransmit =
5285 "HTTP/1.0 403 Forbidden\r\nProxy-Connection: close\r\n"
5286 "Content-Length: 1\r\n\r\n1";
5288 manager.setProxy(dummyProxy);
5289 QNetworkReplyPtr reply3 = manager.get(req);
5291 QVERIFY(waitForFinish(reply3) == Failure);
5293 QVERIFY(int(reply3->error()) > 0);
5296 void tst_QNetworkReply::authorizationError_data()
5299 QTest::addColumn<QString>("url");
5300 QTest::addColumn<int>("errorSignalCount");
5301 QTest::addColumn<int>("finishedSignalCount");
5302 QTest::addColumn<int>("error");
5303 QTest::addColumn<int>("httpStatusCode");
5304 QTest::addColumn<QString>("httpBody");
5306 QTest::newRow("unknown-authorization-method") << "http://" + QtNetworkSettings::serverName() +
5307 "/qtest/cgi-bin/http-unknown-authentication-method.cgi?401-authorization-required" << 1 << 1
5308 << int(QNetworkReply::AuthenticationRequiredError) << 401 << "authorization required";
5309 QTest::newRow("unknown-proxy-authorization-method") << "http://" + QtNetworkSettings::serverName() +
5310 "/qtest/cgi-bin/http-unknown-authentication-method.cgi?407-proxy-authorization-required" << 1 << 1
5311 << int(QNetworkReply::ProxyAuthenticationRequiredError) << 407
5312 << "authorization required";
5315 void tst_QNetworkReply::authorizationError()
5317 QFETCH(QString, url);
5318 QNetworkRequest request(url);
5319 QNetworkReplyPtr reply = manager.get(request);
5321 QCOMPARE(reply->error(), QNetworkReply::NoError);
5323 qRegisterMetaType<QNetworkReply::NetworkError>("QNetworkReply::NetworkError");
5324 QSignalSpy errorSpy(reply, SIGNAL(error(QNetworkReply::NetworkError)));
5325 QSignalSpy finishedSpy(reply, SIGNAL(finished()));
5326 // now run the request:
5327 QVERIFY(waitForFinish(reply) == Failure);
5329 QFETCH(int, errorSignalCount);
5330 QCOMPARE(errorSpy.count(), errorSignalCount);
5331 QFETCH(int, finishedSignalCount);
5332 QCOMPARE(finishedSpy.count(), finishedSignalCount);
5334 QCOMPARE(reply->error(), QNetworkReply::NetworkError(error));
5336 QFETCH(int, httpStatusCode);
5337 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), httpStatusCode);
5339 QFETCH(QString, httpBody);
5340 QCOMPARE(qint64(reply->size()), qint64(httpBody.size()));
5341 QCOMPARE(QString(reply->readAll()), httpBody);
5344 void tst_QNetworkReply::httpConnectionCount()
5347 QVERIFY(server.listen());
5348 QCoreApplication::instance()->processEvents();
5350 for (int i = 0; i < 10; i++) {
5351 QNetworkRequest request (QUrl("http://127.0.0.1:" + QString::number(server.serverPort()) + "/" + QString::number(i)));
5352 QNetworkReply* reply = manager.get(request);
5353 reply->setParent(&server);
5356 int pendingConnectionCount = 0;
5360 while(pendingConnectionCount <= 20) {
5361 QTestEventLoop::instance().enterLoop(1);
5362 QTcpSocket *socket = server.nextPendingConnection();
5363 while (socket != 0) {
5364 pendingConnectionCount++;
5365 socket->setParent(&server);
5366 socket = server.nextPendingConnection();
5369 // at max. wait 10 sec
5370 if (time.elapsed() > 10000)
5374 QCOMPARE(pendingConnectionCount, 6);
5377 void tst_QNetworkReply::httpReUsingConnectionSequential_data()
5379 QTest::addColumn<bool>("doDeleteLater");
5380 QTest::newRow("deleteLater") << true;
5381 QTest::newRow("noDeleteLater") << false;
5384 void tst_QNetworkReply::httpReUsingConnectionSequential()
5386 QFETCH(bool, doDeleteLater);
5388 QByteArray response("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
5389 MiniHttpServer server(response);
5390 server.multiple = true;
5391 server.doClose = false;
5394 url.setScheme("http");
5395 url.setPort(server.serverPort());
5396 url.setHost("127.0.0.1");
5398 QNetworkReply* reply1 = manager.get(QNetworkRequest(url));
5399 connect(reply1, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
5400 QTestEventLoop::instance().enterLoop(2);
5401 QVERIFY(!QTestEventLoop::instance().timeout());
5402 QVERIFY(!reply1->error());
5403 int reply1port = server.client->peerPort();
5406 reply1->deleteLater();
5408 // finished received, send the next one
5409 QNetworkReply*reply2 = manager.get(QNetworkRequest(url));
5410 connect(reply2, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
5411 QTestEventLoop::instance().enterLoop(2);
5412 QVERIFY(!QTestEventLoop::instance().timeout());
5413 QVERIFY(!reply2->error());
5414 int reply2port = server.client->peerPort(); // should still be the same object
5416 QVERIFY(reply1port > 0);
5417 QCOMPARE(server.totalConnections, 1);
5418 QCOMPARE(reply2port, reply1port);
5421 reply1->deleteLater(); // only do it if it was not done earlier
5422 reply2->deleteLater();
5425 class HttpReUsingConnectionFromFinishedSlot : public QObject {
5428 QNetworkReply* reply1;
5429 QNetworkReply* reply2;
5431 QNetworkAccessManager manager;
5433 void finishedSlot() {
5434 QVERIFY(!reply1->error());
5436 QFETCH(bool, doDeleteLater);
5437 if (doDeleteLater) {
5438 reply1->deleteLater();
5442 // kick off 2nd request and exit the loop when it is done
5443 reply2 = manager.get(QNetworkRequest(url));
5444 reply2->setParent(this);
5445 connect(reply2, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
5449 void tst_QNetworkReply::httpReUsingConnectionFromFinishedSlot_data()
5451 httpReUsingConnectionSequential_data();
5454 void tst_QNetworkReply::httpReUsingConnectionFromFinishedSlot()
5456 QByteArray response("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
5457 MiniHttpServer server(response);
5458 server.multiple = true;
5459 server.doClose = false;
5461 HttpReUsingConnectionFromFinishedSlot helper;
5464 helper.url.setScheme("http");
5465 helper.url.setPort(server.serverPort());
5466 helper.url.setHost("127.0.0.1");
5469 helper.reply1 = helper.manager.get(QNetworkRequest(helper.url));
5470 helper.reply1->setParent(&helper);
5471 connect(helper.reply1, SIGNAL(finished()), &helper, SLOT(finishedSlot()));
5472 QTestEventLoop::instance().enterLoop(4);
5473 QVERIFY(!QTestEventLoop::instance().timeout());
5475 QVERIFY(helper.reply2);
5476 QVERIFY(!helper.reply2->error());
5478 QCOMPARE(server.totalConnections, 1);
5481 class HttpRecursiveCreationHelper : public QObject {
5485 HttpRecursiveCreationHelper():
5487 requestsStartedCount_finished(0),
5488 requestsStartedCount_readyRead(0),
5489 requestsFinishedCount(0)
5492 QNetworkAccessManager manager;
5493 int requestsStartedCount_finished;
5494 int requestsStartedCount_readyRead;
5495 int requestsFinishedCount;
5497 void finishedSlot() {
5498 requestsFinishedCount++;
5500 QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
5501 QVERIFY(!reply->error());
5502 QVERIFY(reply->bytesAvailable() == 27906);
5504 if (requestsFinishedCount == 60) {
5505 QTestEventLoop::instance().exitLoop();
5509 if (requestsStartedCount_finished < 30) {
5511 requestsStartedCount_finished++;
5514 reply->deleteLater();
5516 void readyReadSlot() {
5517 QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
5518 QVERIFY(!reply->error());
5520 if (requestsStartedCount_readyRead < 30 && reply->bytesAvailable() > 27906/2) {
5522 requestsStartedCount_readyRead++;
5526 QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/fluke.gif";
5527 QNetworkRequest request(url);
5528 QNetworkReply *reply = manager.get(request);
5529 reply->setParent(this);
5530 connect(reply, SIGNAL(finished()), this, SLOT(finishedSlot()));
5531 connect(reply, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
5535 void tst_QNetworkReply::httpRecursiveCreation()
5537 // this test checks if creation of new requests to the same host properly works
5538 // from readyRead() and finished() signals
5539 HttpRecursiveCreationHelper helper;
5541 QTestEventLoop::instance().enterLoop(30);
5542 QVERIFY(!QTestEventLoop::instance().timeout());
5546 void tst_QNetworkReply::ignoreSslErrorsList_data()
5548 QTest::addColumn<QString>("url");
5549 QTest::addColumn<QList<QSslError> >("expectedSslErrors");
5550 QTest::addColumn<QNetworkReply::NetworkError>("expectedNetworkError");
5552 QList<QSslError> expectedSslErrors;
5553 QList<QSslCertificate> certs = QSslCertificate::fromPath(testDataDir + "/certs/qt-test-server-cacert.pem");
5554 QSslError rightError(QSslError::SelfSignedCertificate, certs.at(0));
5555 QSslError wrongError(QSslError::SelfSignedCertificate);
5557 QTest::newRow("SSL-failure-empty-list") << "https://" + QtNetworkSettings::serverName() + "/index.html" << expectedSslErrors << QNetworkReply::SslHandshakeFailedError;
5558 expectedSslErrors.append(wrongError);
5559 QTest::newRow("SSL-failure-wrong-error") << "https://" + QtNetworkSettings::serverName() + "/index.html" << expectedSslErrors << QNetworkReply::SslHandshakeFailedError;
5560 expectedSslErrors.append(rightError);
5561 QTest::newRow("allErrorsInExpectedList1") << "https://" + QtNetworkSettings::serverName() + "/index.html" << expectedSslErrors << QNetworkReply::NoError;
5562 expectedSslErrors.removeAll(wrongError);
5563 QTest::newRow("allErrorsInExpectedList2") << "https://" + QtNetworkSettings::serverName() + "/index.html" << expectedSslErrors << QNetworkReply::NoError;
5564 expectedSslErrors.removeAll(rightError);
5565 QTest::newRow("SSL-failure-empty-list-again") << "https://" + QtNetworkSettings::serverName() + "/index.html" << expectedSslErrors << QNetworkReply::SslHandshakeFailedError;
5568 void tst_QNetworkReply::ignoreSslErrorsList()
5570 QFETCH(QString, url);
5571 QNetworkRequest request(url);
5572 QNetworkReplyPtr reply = manager.get(request);
5574 QFETCH(QList<QSslError>, expectedSslErrors);
5575 reply->ignoreSslErrors(expectedSslErrors);
5577 QVERIFY(waitForFinish(reply) != Timeout);
5579 QFETCH(QNetworkReply::NetworkError, expectedNetworkError);
5580 QCOMPARE(reply->error(), expectedNetworkError);
5583 void tst_QNetworkReply::ignoreSslErrorsListWithSlot_data()
5585 ignoreSslErrorsList_data();
5588 // this is not a test, just a slot called in the test below
5589 void tst_QNetworkReply::ignoreSslErrorListSlot(QNetworkReply *reply, const QList<QSslError> &)
5591 reply->ignoreSslErrors(storedExpectedSslErrors);
5594 // do the same as in ignoreSslErrorsList, but ignore the errors in the slot
5595 void tst_QNetworkReply::ignoreSslErrorsListWithSlot()
5597 QFETCH(QString, url);
5598 QNetworkRequest request(url);
5599 QNetworkReplyPtr reply = manager.get(request);
5601 QFETCH(QList<QSslError>, expectedSslErrors);
5602 // store the errors to ignore them later in the slot connected below
5603 storedExpectedSslErrors = expectedSslErrors;
5604 connect(&manager, SIGNAL(sslErrors(QNetworkReply *, const QList<QSslError> &)),
5605 this, SLOT(ignoreSslErrorListSlot(QNetworkReply *, const QList<QSslError> &)));
5608 QVERIFY(waitForFinish(reply) != Timeout);
5610 QFETCH(QNetworkReply::NetworkError, expectedNetworkError);
5611 QCOMPARE(reply->error(), expectedNetworkError);
5614 void tst_QNetworkReply::sslConfiguration_data()
5616 QTest::addColumn<QSslConfiguration>("configuration");
5617 QTest::addColumn<bool>("works");
5619 QTest::newRow("empty") << QSslConfiguration() << false;
5620 QSslConfiguration conf = QSslConfiguration::defaultConfiguration();
5621 QTest::newRow("default") << conf << false; // does not contain test server cert
5622 QList<QSslCertificate> testServerCert = QSslCertificate::fromPath(testDataDir + "/certs/qt-test-server-cacert.pem");
5623 conf.setCaCertificates(testServerCert);
5624 QTest::newRow("set-root-cert") << conf << true;
5625 conf.setProtocol(QSsl::SecureProtocols);
5626 QTest::newRow("secure") << conf << true;
5629 void tst_QNetworkReply::sslConfiguration()
5631 QNetworkRequest request(QUrl("https://" + QtNetworkSettings::serverName() + "/index.html"));
5632 QFETCH(QSslConfiguration, configuration);
5633 request.setSslConfiguration(configuration);
5634 QNetworkReplyPtr reply = manager.get(request);
5636 QVERIFY(waitForFinish(reply) != Timeout);
5638 QFETCH(bool, works);
5639 QNetworkReply::NetworkError expectedError = works ? QNetworkReply::NoError : QNetworkReply::SslHandshakeFailedError;
5640 QCOMPARE(reply->error(), expectedError);
5645 void tst_QNetworkReply::getAndThenDeleteObject_data()
5647 QTest::addColumn<bool>("replyFirst");
5649 QTest::newRow("delete-reply-first") << true;
5650 QTest::newRow("delete-qnam-first") << false;
5653 void tst_QNetworkReply::getAndThenDeleteObject()
5655 // yes, this will leak if the testcase fails. I don't care. It must not fail then :P
5656 QNetworkAccessManager *manager = new QNetworkAccessManager();
5657 QNetworkRequest request("http://" + QtNetworkSettings::serverName() + "/qtest/bigfile");
5658 QNetworkReply *reply = manager->get(request);
5659 reply->setReadBufferSize(1);
5660 reply->setParent((QObject*)0); // must be 0 because else it is the manager
5665 QCoreApplication::instance()->processEvents();
5666 if (reply->bytesAvailable())
5668 if (stopWatch.elapsed() >= 30000)
5672 QVERIFY(reply->bytesAvailable());
5673 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
5674 QVERIFY(!reply->isFinished()); // must not be finished
5676 QFETCH(bool, replyFirst);
5687 // see https://bugs.webkit.org/show_bug.cgi?id=38935
5688 void tst_QNetworkReply::symbianOpenCDataUrlCrash()
5690 QString requestUrl("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAWCAYAAAA1vze2AAAAB3RJTUUH2AUSEgolrgBvVQAAAAlwSFlzAAALEwAACxMBAJqcGAAAAARnQU1BAACxjwv8YQUAAAHlSURBVHja5VbNShxBEK6ZaXtnHTebQPA1gngNmfaeq+QNPIlIXkC9iQdJxJNvEHLN3VkxhxxE8gTmEhAVddXZ6Z3f9Ndriz89/sHmkBQUVVT1fB9d9c3uOERUKTunIdn3HzstxGpYBDS4wZk7TAJj/wlJ90J+jnuygqs8svSj+/rGHBos3rE18XBvfU3no7NzlJfUaY/5whAwl8Lr/WDUv4ODxTMb+P5xLExe5LmO559WqTX/MQR4WZYEAtSePS4pE0qSnuhnRUcBU5Gm2k9XljU4Z26I3NRxBrd80rj2fh+KNE0FY4xevRgTjREvPFpasAK8Xli6MUbbuKw3afAGgSBXozo5u4hkmncAlkl5wx8iMGbdyQjnCFEiEwGiosj1UQA/x2rVddiVoi+l4IxE0PTDnx+mrQBvvnx9cFz3krhVvuhzFn579/aq/n5rW8fbtTqiWhIQZEo17YBvbkxOXNVndnYpTvod7AtiuN2re0+siwcB9oH8VxxrNwQQAhzyRs30n7wTI2HIN2g2QtQwjjhJIQatOq7E8bIVCLwzpl83Lvtvl+NohWWlE8UZTWEMAGCcR77fHKhPnZF5tYie6dfdxCphACmLPM+j8bYfmTryg64kV9Vh3mV8jP0b/4wO/YUPiT/8i0MLf55lSQAAAABJRU5ErkJggg==");
5691 QUrl url = QUrl::fromEncoded(requestUrl.toLatin1());
5692 QNetworkRequest req(url);
5693 QNetworkReplyPtr reply;
5695 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, req, reply));
5697 QCOMPARE(reply->url(), url);
5698 QCOMPARE(reply->error(), QNetworkReply::NoError);
5700 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), qint64(598));
5703 void tst_QNetworkReply::getFromHttpIntoBuffer_data()
5705 QTest::addColumn<QUrl>("url");
5707 QTest::newRow("rfc-internal") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt");
5710 // Please note that the whole "zero copy" download buffer API is private right now. Do not use it.
5711 void tst_QNetworkReply::getFromHttpIntoBuffer()
5714 QNetworkRequest request(url);
5715 request.setAttribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute, 1024*128); // 128 kB
5717 QNetworkAccessManager manager;
5718 QNetworkReply *reply = manager.get(request);
5719 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
5720 QTestEventLoop::instance().enterLoop(10);
5721 QVERIFY(!QTestEventLoop::instance().timeout());
5722 QVERIFY(reply->isFinished());
5724 QFile reference(testDataDir + "/rfc3252.txt");
5725 QVERIFY(reference.open(QIODevice::ReadOnly));
5727 QCOMPARE(reference.bytesAvailable(), reply->bytesAvailable());
5728 QCOMPARE(reference.size(), reply->size());
5730 // Compare the memory buffer
5731 QVariant downloadBufferAttribute = reply->attribute(QNetworkRequest::DownloadBufferAttribute);
5732 QVERIFY(downloadBufferAttribute.isValid());
5733 QSharedPointer<char> sharedPointer = downloadBufferAttribute.value<QSharedPointer<char> >();
5734 bool memoryComparison =
5735 (0 == memcmp(static_cast<void*>(reference.readAll().data()),
5736 sharedPointer.data(), reference.size()));
5737 QVERIFY(memoryComparison);
5739 // Make sure the normal reading works
5741 QCOMPARE(reply->read(42), reference.read(42));
5742 QCOMPARE(reply->getChar(0), reference.getChar(0));
5743 QCOMPARE(reply->peek(23), reference.peek(23));
5744 QCOMPARE(reply->readLine(), reference.readLine());
5745 QCOMPARE(reference.bytesAvailable(), reply->bytesAvailable());
5746 QCOMPARE(reply->readAll(), reference.readAll());
5747 QVERIFY(reply->atEnd());
5750 // FIXME we really need to consolidate all those server implementations
5751 class GetFromHttpIntoBuffer2Server : QObject {
5757 bool serverSendsContentLength;
5758 bool chunkedEncoding;
5761 GetFromHttpIntoBuffer2Server (qint64 ds, bool sscl, bool ce) : dataSize(ds), dataSent(0),
5762 client(0), serverSendsContentLength(sscl), chunkedEncoding(ce) {
5764 connect(&server, SIGNAL(newConnection()), this, SLOT(newConnectionSlot()));
5768 return server.serverPort();
5773 void newConnectionSlot() {
5774 client = server.nextPendingConnection();
5775 client->setParent(this);
5776 connect(client, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
5777 connect(client, SIGNAL(bytesWritten(qint64)), this, SLOT(bytesWrittenSlot(qint64)));
5780 void readyReadSlot() {
5782 client->write("HTTP/1.0 200 OK\n");
5783 if (serverSendsContentLength)
5784 client->write(QString("Content-Length: " + QString::number(dataSize) + "\n").toAscii());
5785 if (chunkedEncoding)
5786 client->write(QString("Transfer-Encoding: chunked\n").toAscii());
5787 client->write("Connection: close\n\n");
5790 void bytesWrittenSlot(qint64 amount) {
5792 if (dataSent == dataSize && client) {
5795 // chunked encoding: we have to send a last "empty" chunk
5796 if (chunkedEncoding)
5797 client->write(QString("0\r\n\r\n").toAscii());
5799 client->disconnectFromHost();
5806 if (client && client->bytesToWrite() < 100*1024 && dataSent < dataSize) {
5807 qint64 amount = qMin(qint64(16*1024), dataSize - dataSent);
5808 QByteArray data(amount, '@');
5810 if (chunkedEncoding) {
5811 client->write(QString(QString("%1").arg(amount,0,16).toUpper() + "\r\n").toAscii());
5812 client->write(data.constData(), amount);
5813 client->write(QString("\r\n").toAscii());
5815 client->write(data.constData(), amount);
5823 class GetFromHttpIntoBuffer2Client : QObject {
5826 bool useDownloadBuffer;
5827 QNetworkReply *reply;
5829 QList<qint64> bytesAvailableList;
5831 GetFromHttpIntoBuffer2Client (QNetworkReply *reply, bool useDownloadBuffer, qint64 uploadSize)
5832 : useDownloadBuffer(useDownloadBuffer), reply(reply), uploadSize(uploadSize)
5834 connect(reply, SIGNAL(metaDataChanged()), this, SLOT(metaDataChangedSlot()));
5835 connect(reply, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
5836 connect(reply, SIGNAL(finished()), this, SLOT(finishedSlot()));
5840 void metaDataChangedSlot() {
5841 if (useDownloadBuffer) {
5842 QSharedPointer<char> sharedPointer = qvariant_cast<QSharedPointer<char> >(reply->attribute(QNetworkRequest::DownloadBufferAttribute));
5843 QVERIFY(!sharedPointer.isNull()); // It will be 0 if it failed
5846 // metaDataChanged needs to come before everything else
5847 QVERIFY(bytesAvailableList.isEmpty());
5850 void readyReadSlot() {
5851 QVERIFY(!reply->isFinished());
5853 qint64 bytesAvailable = reply->bytesAvailable();
5855 // bytesAvailable must never be 0
5856 QVERIFY(bytesAvailable != 0);
5858 if (bytesAvailableList.length() < 5) {
5859 // We assume that the first few times the bytes available must be less than the complete size, e.g.
5860 // the bytesAvailable() function works correctly in case of a downloadBuffer.
5861 QVERIFY(bytesAvailable < uploadSize);
5863 if (!bytesAvailableList.isEmpty()) {
5864 // Also check that the same bytesAvailable is not coming twice in a row
5865 QVERIFY(bytesAvailableList.last() != bytesAvailable);
5868 bytesAvailableList.append(bytesAvailable);
5869 // Add bytesAvailable to a list an parse
5872 void finishedSlot() {
5873 // We should have already received all readyRead
5874 QVERIFY(!bytesAvailableList.isEmpty());
5875 QVERIFY(bytesAvailableList.last() == uploadSize);
5879 void tst_QNetworkReply::getFromHttpIntoBuffer2_data()
5881 QTest::addColumn<bool>("useDownloadBuffer");
5883 QTest::newRow("use-download-buffer") << true;
5884 QTest::newRow("do-not-use-download-buffer") << false;
5887 // This test checks mostly that signal emissions are in correct order
5888 // Please note that the whole "zero copy" download buffer API is private right now. Do not use it.
5889 void tst_QNetworkReply::getFromHttpIntoBuffer2()
5891 QFETCH(bool, useDownloadBuffer);
5893 // On my Linux Desktop the results are already visible with 128 kB, however we use this to have good results.
5894 #if defined(Q_OS_WINCE_WM)
5895 // Show some mercy to non-desktop platform/s
5896 enum {UploadSize = 4*1024*1024}; // 4 MB
5898 enum {UploadSize = 32*1024*1024}; // 32 MB
5901 GetFromHttpIntoBuffer2Server server(UploadSize, true, false);
5903 QNetworkRequest request(QUrl("http://127.0.0.1:" + QString::number(server.serverPort()) + "/?bare=1"));
5904 if (useDownloadBuffer)
5905 request.setAttribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute, 1024*1024*128); // 128 MB is max allowed
5907 QNetworkAccessManager manager;
5908 QNetworkReplyPtr reply = manager.get(request);
5910 GetFromHttpIntoBuffer2Client client(reply, useDownloadBuffer, UploadSize);
5912 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
5913 QTestEventLoop::instance().enterLoop(40);
5914 QCOMPARE(reply->error(), QNetworkReply::NoError);
5915 QVERIFY(!QTestEventLoop::instance().timeout());
5919 void tst_QNetworkReply::getFromHttpIntoBufferCanReadLine()
5921 QString header("HTTP/1.0 200 OK\r\nContent-Length: 7\r\n\r\nxxx\nxxx");
5923 MiniHttpServer server(header.toAscii());
5924 server.doClose = true;
5926 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
5927 request.setAttribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute, 1024*1024*128); // 128 MB is max allowed
5928 QNetworkReplyPtr reply = manager.get(request);
5930 QVERIFY(waitForFinish(reply) == Success);
5932 QCOMPARE(reply->error(), QNetworkReply::NoError);
5933 QVERIFY(reply->canReadLine());
5934 QCOMPARE(reply->read(1), QByteArray("x"));
5935 QVERIFY(reply->canReadLine());
5936 QCOMPARE(reply->read(3), QByteArray("xx\n"));
5937 QVERIFY(!reply->canReadLine());
5938 QCOMPARE(reply->readAll(), QByteArray("xxx"));
5939 QVERIFY(!reply->canReadLine());
5944 // Is handled somewhere else too, introduced this special test to have it more accessible
5945 void tst_QNetworkReply::ioGetFromHttpWithoutContentLength()
5947 QByteArray dataToSend("HTTP/1.0 200 OK\r\n\r\nHALLO! 123!");
5948 MiniHttpServer server(dataToSend);
5949 server.doClose = true;
5951 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
5952 QNetworkReplyPtr reply = manager.get(request);
5954 QVERIFY(waitForFinish(reply) == Success);
5956 QCOMPARE(reply->url(), request.url());
5957 QVERIFY(reply->isFinished());
5958 QVERIFY(reply->error() == QNetworkReply::NoError);
5961 // Is handled somewhere else too, introduced this special test to have it more accessible
5962 void tst_QNetworkReply::ioGetFromHttpBrokenChunkedEncoding()
5964 // This is wrong chunked encoding because of the X. What actually has to follow is \r\n
5965 // and then the declaration of the final 0 chunk
5966 QByteArray dataToSend("HTTP/1.0 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n3\r\nABCX");
5967 MiniHttpServer server(dataToSend);
5968 server.doClose = false; // FIXME
5970 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
5971 QNetworkReplyPtr reply = manager.get(request);
5973 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
5974 QTestEventLoop::instance().enterLoop(10);
5976 QEXPECT_FAIL(0, "We should close the socket and not just do nothing", Continue);
5977 QVERIFY(!QTestEventLoop::instance().timeout());
5978 QEXPECT_FAIL(0, "We should close the socket and not just do nothing", Continue);
5979 QVERIFY(reply->isFinished());
5980 QCOMPARE(reply->error(), QNetworkReply::NoError);
5984 // Prepare a gzip that has one chunk that expands to the size mentioned in the bugreport.
5985 // Then have a custom HTTP server that waits after this chunk so the returning gets
5987 void tst_QNetworkReply::qtbug12908compressedHttpReply()
5989 QString header("HTTP/1.0 200 OK\r\nContent-Encoding: gzip\r\nContent-Length: 63\r\n\r\n");
5991 // dd if=/dev/zero of=qtbug-12908 bs=16384 count=1 && gzip qtbug-12908 && base64 -w 0 qtbug-12908.gz
5992 QString encodedFile("H4sICDdDaUwAA3F0YnVnLTEyOTA4AO3BMQEAAADCoPVPbQwfoAAAAAAAAAAAAAAAAAAAAIC3AYbSVKsAQAAA");
5993 QByteArray decodedFile = QByteArray::fromBase64(encodedFile.toAscii());
5994 QCOMPARE(decodedFile.size(), 63);
5996 MiniHttpServer server(header.toAscii() + decodedFile);
5997 server.doClose = true;
5999 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
6000 QNetworkReplyPtr reply = manager.get(request);
6002 QVERIFY(waitForFinish(reply) == Success);
6004 QCOMPARE(reply->error(), QNetworkReply::NoError);
6005 QCOMPARE(reply->size(), qint64(16384));
6006 QCOMPARE(reply->readAll(), QByteArray(16384, '\0'));
6009 void tst_QNetworkReply::compressedHttpReplyBrokenGzip()
6011 QString header("HTTP/1.0 200 OK\r\nContent-Encoding: gzip\r\nContent-Length: 63\r\n\r\n");
6013 // dd if=/dev/zero of=qtbug-12908 bs=16384 count=1 && gzip qtbug-12908 && base64 -w 0 qtbug-12908.gz
6014 // Then change "BMQ" to "BMX"
6015 QString encodedFile("H4sICDdDaUwAA3F0YnVnLTEyOTA4AO3BMXEAAADCoPVPbQwfoAAAAAAAAAAAAAAAAAAAAIC3AYbSVKsAQAAA");
6016 QByteArray decodedFile = QByteArray::fromBase64(encodedFile.toAscii());
6017 QCOMPARE(decodedFile.size(), 63);
6019 MiniHttpServer server(header.toAscii() + decodedFile);
6020 server.doClose = true;
6022 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
6023 QNetworkReplyPtr reply = manager.get(request);
6025 QVERIFY(waitForFinish(reply) == Failure);
6027 QCOMPARE(reply->error(), QNetworkReply::ProtocolFailure);
6030 // TODO add similar test for FTP
6031 void tst_QNetworkReply::getFromUnreachableIp()
6033 QNetworkAccessManager manager;
6035 QNetworkRequest request(QUrl("http://255.255.255.255/42/23/narf/narf/narf"));
6036 QNetworkReplyPtr reply = manager.get(request);
6038 QVERIFY(waitForFinish(reply) == Failure);
6040 QVERIFY(reply->error() != QNetworkReply::NoError);
6043 void tst_QNetworkReply::qtbug4121unknownAuthentication()
6045 MiniHttpServer server(QByteArray("HTTP/1.1 401 bla\r\nWWW-Authenticate: crap\r\nContent-Length: 0\r\n\r\n"));
6046 server.doClose = false;
6048 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
6049 QNetworkAccessManager manager;
6050 QNetworkReplyPtr reply = manager.get(request);
6052 qRegisterMetaType<QNetworkReply*>("QNetworkReply*");
6053 qRegisterMetaType<QAuthenticator*>("QAuthenticator*");
6054 QSignalSpy authSpy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
6055 QSignalSpy finishedSpy(&manager, SIGNAL(finished(QNetworkReply*)));
6056 qRegisterMetaType<QNetworkReply::NetworkError>("QNetworkReply::NetworkError");
6057 QSignalSpy errorSpy(reply, SIGNAL(error(QNetworkReply::NetworkError)));
6059 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6060 QTestEventLoop::instance().enterLoop(10);
6061 QVERIFY(!QTestEventLoop::instance().timeout());
6063 QCOMPARE(authSpy.count(), 0);
6064 QCOMPARE(finishedSpy.count(), 1);
6065 QCOMPARE(errorSpy.count(), 1);
6067 QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError);
6070 void tst_QNetworkReply::authenticationCacheAfterCancel_data()
6072 QTest::addColumn<QNetworkProxy>("proxy");
6073 QTest::addColumn<bool>("proxyAuth");
6074 QTest::addColumn<QUrl>("url");
6075 for (int i = 0; i < proxies.count(); ++i) {
6076 QTest::newRow("http" + proxies.at(i).tag) << proxies.at(i).proxy << proxies.at(i).requiresAuthentication << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt");
6078 QTest::newRow("https" + proxies.at(i).tag) << proxies.at(i).proxy << proxies.at(i).requiresAuthentication << QUrl("https://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt");
6083 class AuthenticationCacheHelper : public QObject
6087 AuthenticationCacheHelper()
6090 void proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *auth)
6092 if (!proxyPassword.isNull()) {
6093 auth->setUser(proxyUserName);
6094 auth->setPassword(proxyPassword);
6095 //clear credentials, if they are asked again, they were bad
6096 proxyUserName.clear();
6097 proxyPassword.clear();
6100 void authenticationRequired(QNetworkReply*,QAuthenticator *auth)
6102 if (!httpPassword.isNull()) {
6103 auth->setUser(httpUserName);
6104 auth->setPassword(httpPassword);
6105 //clear credentials, if they are asked again, they were bad
6106 httpUserName.clear();
6107 httpPassword.clear();
6111 QString httpUserName;
6112 QString httpPassword;
6113 QString proxyUserName;
6114 QString proxyPassword;
6117 /* Purpose of this test is to check credentials are cached correctly.
6118 - If user cancels authentication dialog (i.e. nothing is set to the QAuthenticator by the callback) then this is not cached
6119 - if user supplies a wrong password, then this is not cached
6120 - if user supplies a correct user/password combination then this is cached
6122 Test is checking both the proxyAuthenticationRequired and authenticationRequired signals.
6124 void tst_QNetworkReply::authenticationCacheAfterCancel()
6126 QFETCH(QNetworkProxy, proxy);
6127 QFETCH(bool, proxyAuth);
6129 QNetworkAccessManager manager;
6131 connect(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
6132 SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
6134 manager.setProxy(proxy);
6135 QSignalSpy authSpy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
6136 QSignalSpy proxyAuthSpy(&manager, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)));
6138 AuthenticationCacheHelper helper;
6139 connect(&manager, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)), &helper, SLOT(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)));
6140 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), &helper, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
6142 QNetworkRequest request(url);
6143 QNetworkReplyPtr reply;
6145 //should fail due to no credentials
6146 reply = manager.get(request);
6147 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6148 QTestEventLoop::instance().enterLoop(10);
6149 QVERIFY(!QTestEventLoop::instance().timeout());
6151 QCOMPARE(reply->error(), QNetworkReply::ProxyAuthenticationRequiredError);
6152 QCOMPARE(authSpy.count(), 0);
6153 QCOMPARE(proxyAuthSpy.count(), 1);
6154 proxyAuthSpy.clear();
6156 //should fail due to bad credentials
6157 helper.proxyUserName = "qsockstest";
6158 helper.proxyPassword = "badpassword";
6159 reply = manager.get(request);
6160 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6161 QTestEventLoop::instance().enterLoop(10);
6162 QVERIFY(!QTestEventLoop::instance().timeout());
6164 QEXPECT_FAIL("http+socksauth", "QTBUG-23136 - danted accepts bad authentication but blocks the connection", Continue);
6165 QEXPECT_FAIL("https+socksauth", "QTBUG-23136 - danted accepts bad authentication but blocks the connection", Continue);
6167 QCOMPARE(reply->error(), QNetworkReply::ProxyAuthenticationRequiredError);
6168 QCOMPARE(authSpy.count(), 0);
6169 QVERIFY(proxyAuthSpy.count() > 0);
6170 proxyAuthSpy.clear();
6172 //QTBUG-23136 workaround
6173 if (proxy.port() == 1081) {
6174 #ifdef QT_BUILD_INTERNAL
6175 QNetworkAccessManagerPrivate::clearCache(&manager);
6177 return; //XFAIL result above
6181 //next proxy auth should succeed, due to correct credentials
6182 helper.proxyUserName = "qsockstest";
6183 helper.proxyPassword = "password";
6186 //should fail due to no credentials
6187 reply = manager.get(request);
6188 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6189 QTestEventLoop::instance().enterLoop(10);
6190 QVERIFY(!QTestEventLoop::instance().timeout());
6192 QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError);
6193 QVERIFY(authSpy.count() > 0);
6196 QVERIFY(proxyAuthSpy.count() > 0);
6197 proxyAuthSpy.clear();
6200 //should fail due to bad credentials
6201 helper.httpUserName = "baduser";
6202 helper.httpPassword = "badpassword";
6203 reply = manager.get(request);
6204 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6205 QTestEventLoop::instance().enterLoop(10);
6206 QVERIFY(!QTestEventLoop::instance().timeout());
6208 QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError);
6209 QVERIFY(authSpy.count() > 0);
6212 //should be supplied from cache
6213 QCOMPARE(proxyAuthSpy.count(), 0);
6214 proxyAuthSpy.clear();
6217 //next auth should succeed, due to correct credentials
6218 helper.httpUserName = "httptest";
6219 helper.httpPassword = "httptest";
6221 reply = 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 QVERIFY(authSpy.count() > 0);
6230 //should be supplied from cache
6231 QCOMPARE(proxyAuthSpy.count(), 0);
6232 proxyAuthSpy.clear();
6235 //next auth should use cached credentials
6236 reply = manager.get(request);
6237 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6238 QTestEventLoop::instance().enterLoop(10);
6239 QVERIFY(!QTestEventLoop::instance().timeout());
6241 QCOMPARE(reply->error(), QNetworkReply::NoError);
6242 //should be supplied from cache
6243 QCOMPARE(authSpy.count(), 0);
6246 //should be supplied from cache
6247 QCOMPARE(proxyAuthSpy.count(), 0);
6248 proxyAuthSpy.clear();
6253 void tst_QNetworkReply::authenticationWithDifferentRealm()
6255 AuthenticationCacheHelper helper;
6256 QNetworkAccessManager manager;
6258 connect(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
6259 SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
6261 connect(&manager, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)), &helper, SLOT(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)));
6262 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), &helper, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
6264 helper.httpUserName = "httptest";
6265 helper.httpPassword = "httptest";
6267 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt"));
6268 QNetworkReply* reply = manager.get(request);
6269 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6270 QTestEventLoop::instance().enterLoop(10);
6271 QVERIFY(!QTestEventLoop::instance().timeout());
6272 QCOMPARE(reply->error(), QNetworkReply::NoError);
6274 helper.httpUserName = "httptest";
6275 helper.httpPassword = "httptest";
6277 request.setUrl(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/auth-digest/"));
6278 reply = manager.get(request);
6279 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6280 QTestEventLoop::instance().enterLoop(10);
6281 QVERIFY(!QTestEventLoop::instance().timeout());
6282 QCOMPARE(reply->error(), QNetworkReply::NoError);
6285 class QtBug13431Helper : public QObject {
6288 QNetworkReply* m_reply;
6291 void replyFinished(QNetworkReply*) {
6292 QTestEventLoop::instance().exitLoop();
6295 void onReadAndReschedule() {
6296 const qint64 bytesReceived = m_reply->bytesAvailable();
6297 if (bytesReceived && m_reply->readBufferSize()) {
6298 QByteArray data = m_reply->read(bytesReceived);
6300 const int millisecDelay = static_cast<int>(bytesReceived * 1000 / m_reply->readBufferSize());
6301 m_dlTimer.start(millisecDelay);
6305 m_dlTimer.start(200);
6310 void tst_QNetworkReply::qtbug13431replyThrottling()
6312 QtBug13431Helper helper;
6314 QNetworkAccessManager nam;
6315 connect(&nam, SIGNAL(finished(QNetworkReply*)), &helper, SLOT(replyFinished(QNetworkReply*)));
6317 // Download a bigger file
6318 QNetworkRequest netRequest(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/bigfile"));
6319 helper.m_reply = nam.get(netRequest);
6321 helper.m_reply->setReadBufferSize(36000);
6323 // Schedule a timer that tries to read
6325 connect(&helper.m_dlTimer, SIGNAL(timeout()), &helper, SLOT(onReadAndReschedule()));
6326 helper.m_dlTimer.setSingleShot(true);
6327 helper.m_dlTimer.start(0);
6329 QTestEventLoop::instance().enterLoop(30);
6330 QVERIFY(!QTestEventLoop::instance().timeout());
6331 QVERIFY(helper.m_reply->isFinished());
6332 QCOMPARE(helper.m_reply->error(), QNetworkReply::NoError);
6335 void tst_QNetworkReply::httpWithNoCredentialUsage()
6337 QNetworkRequest request(QUrl("http://httptest:httptest@" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi"));
6338 // Do not use credentials
6339 request.setAttribute(QNetworkRequest::AuthenticationReuseAttribute, QNetworkRequest::Manual);
6340 QNetworkAccessManager manager;
6341 QNetworkReplyPtr reply = manager.get(request);
6343 qRegisterMetaType<QNetworkReply*>("QNetworkReply*");
6344 qRegisterMetaType<QAuthenticator*>("QAuthenticator*");
6345 QSignalSpy authSpy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
6346 QSignalSpy finishedSpy(&manager, SIGNAL(finished(QNetworkReply*)));
6347 qRegisterMetaType<QNetworkReply::NetworkError>("QNetworkReply::NetworkError");
6348 QSignalSpy errorSpy(reply, SIGNAL(error(QNetworkReply::NetworkError)));
6350 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6351 QTestEventLoop::instance().enterLoop(10);
6352 QVERIFY(!QTestEventLoop::instance().timeout());
6354 // We check if authenticationRequired was emitted, however we do not anything in it so it should be 401
6355 QCOMPARE(authSpy.count(), 1);
6356 QCOMPARE(finishedSpy.count(), 1);
6357 QCOMPARE(errorSpy.count(), 1);
6359 QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError);
6362 void tst_QNetworkReply::qtbug15311doubleContentLength()
6364 QByteArray response("HTTP/1.0 200 OK\r\nContent-Length: 3\r\nServer: bogus\r\nContent-Length: 3\r\n\r\nABC");
6365 MiniHttpServer server(response);
6366 server.doClose = true;
6368 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
6369 QNetworkReplyPtr reply = manager.get(request);
6371 QVERIFY(waitForFinish(reply) == Success);
6373 QVERIFY(reply->isFinished());
6374 QCOMPARE(reply->error(), QNetworkReply::NoError);
6375 QCOMPARE(reply->size(), qint64(3));
6376 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), qint64(3));
6377 QCOMPARE(reply->rawHeader("Content-length"), QByteArray("3, 3"));
6378 QCOMPARE(reply->readAll(), QByteArray("ABC"));
6381 void tst_QNetworkReply::qtbug18232gzipContentLengthZero()
6383 QByteArray response("HTTP/1.0 200 OK\r\nContent-Encoding: gzip\r\nContent-Length: 0\r\n\r\n");
6384 MiniHttpServer server(response);
6385 server.doClose = true;
6387 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
6388 QNetworkReplyPtr reply = manager.get(request);
6390 QVERIFY(waitForFinish(reply) == Success);
6392 QVERIFY(reply->isFinished());
6393 QCOMPARE(reply->error(), QNetworkReply::NoError);
6394 QCOMPARE(reply->size(), qint64(0));
6395 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), qint64(0));
6396 QCOMPARE(reply->readAll(), QByteArray());
6399 // Reproduced a crash in QHttpNetworkReplyPrivate::gunzipBodyPartiallyEnd
6400 // where zlib inflateEnd was called for uninitialized zlib stream
6401 void tst_QNetworkReply::qtbug22660gzipNoContentLengthEmptyContent()
6403 // Response with no Content-Length in header and empty content
6404 QByteArray response("HTTP/1.0 200 OK\r\nContent-Encoding: gzip\r\n\r\n");
6405 MiniHttpServer server(response);
6406 server.doClose = true;
6408 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
6409 QNetworkReplyPtr reply = manager.get(request);
6411 QVERIFY(waitForFinish(reply) == Success);
6413 QVERIFY(reply->isFinished());
6414 QCOMPARE(reply->error(), QNetworkReply::NoError);
6415 QCOMPARE(reply->size(), qint64(0));
6416 QVERIFY(!reply->header(QNetworkRequest::ContentLengthHeader).isValid());
6417 QCOMPARE(reply->readAll(), QByteArray());
6420 void tst_QNetworkReply::synchronousRequest_data()
6422 QTest::addColumn<QUrl>("url");
6423 QTest::addColumn<QString>("expected");
6424 QTest::addColumn<bool>("checkContentLength");
6425 QTest::addColumn<QString>("mimeType");
6427 // ### cache, auth, proxies
6429 QTest::newRow("http")
6430 << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt")
6431 << QString("file:" + testDataDir + "/rfc3252.txt")
6433 << QString("text/plain");
6435 QTest::newRow("http-gzip")
6436 << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/deflate/rfc3252.txt")
6437 << QString("file:" + testDataDir + "/rfc3252.txt")
6438 << false // don't check content length, because it's gzip encoded
6439 // ### we would need to enflate (un-deflate) the file content and compare the sizes
6440 << QString("text/plain");
6443 QTest::newRow("https")
6444 << QUrl("https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt")
6445 << QString("file:" + testDataDir + "/rfc3252.txt")
6447 << QString("text/plain");
6450 QTest::newRow("data")
6451 << QUrl(QString::fromLatin1("data:text/plain,hello world"))
6452 << QString("data:hello world")
6453 << true // check content length
6454 << QString("text/plain");
6456 QTest::newRow("simple-file")
6457 << QUrl::fromLocalFile(testDataDir + "/rfc3252.txt")
6458 << QString("file:" + testDataDir + "/rfc3252.txt")
6463 // FIXME add testcase for failing network etc
6464 void tst_QNetworkReply::synchronousRequest()
6467 QFETCH(QString, expected);
6468 QFETCH(bool, checkContentLength);
6469 QFETCH(QString, mimeType);
6471 QNetworkRequest request(url);
6474 // workaround for HTTPS requests: add self-signed server cert to list of CA certs,
6475 // since we cannot react to the sslErrors() signal
6476 // to fix this properly we would need to have an ignoreSslErrors() method in the
6477 // QNetworkRequest, see http://bugreports.qt-project.org/browse/QTBUG-14774
6478 if (url.scheme() == "https") {
6479 QSslConfiguration sslConf;
6480 QList<QSslCertificate> certs = QSslCertificate::fromPath(testDataDir + "/certs/qt-test-server-cacert.pem");
6481 sslConf.setCaCertificates(certs);
6482 request.setSslConfiguration(sslConf);
6486 request.setAttribute(
6487 QNetworkRequest::SynchronousRequestAttribute,
6490 QNetworkReplyPtr reply;
6491 QSignalSpy finishedSpy(&manager, SIGNAL(finished(QNetworkReply*)));
6492 QSignalSpy sslErrorsSpy(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)));
6493 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply, 0));
6494 QVERIFY(reply->isFinished());
6495 QCOMPARE(finishedSpy.count(), 0);
6496 QCOMPARE(sslErrorsSpy.count(), 0);
6498 QCOMPARE(reply->header(QNetworkRequest::ContentTypeHeader).toString(), mimeType);
6500 QByteArray expectedContent;
6502 if (expected.startsWith("file:")) {
6503 QString path = expected.mid(5);
6505 file.open(QIODevice::ReadOnly);
6506 expectedContent = file.readAll();
6507 } else if (expected.startsWith("data:")) {
6508 expectedContent = expected.mid(5).toUtf8();
6511 if (checkContentLength)
6512 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), qint64(expectedContent.size()));
6513 QCOMPARE(reply->readAll(), expectedContent);
6515 reply->deleteLater();
6519 void tst_QNetworkReply::synchronousRequestSslFailure()
6521 // test that SSL won't be accepted with self-signed certificate,
6522 // and that we do not emit the sslError signal (in the manager that is,
6523 // in the reply we don't care)
6525 QUrl url("https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt");
6526 QNetworkRequest request(url);
6527 request.setAttribute(
6528 QNetworkRequest::SynchronousRequestAttribute,
6530 QNetworkReplyPtr reply;
6531 QSignalSpy sslErrorsSpy(&manager, SIGNAL(sslErrors(QNetworkReply *, const QList<QSslError> &)));
6532 runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply, 0);
6533 QVERIFY(reply->isFinished());
6534 QCOMPARE(reply->error(), QNetworkReply::SslHandshakeFailedError);
6535 QCOMPARE(sslErrorsSpy.count(), 0);
6539 class HttpAbortHelper : public QObject
6543 HttpAbortHelper(QNetworkReply *parent)
6547 connect(parent, SIGNAL(readyRead()), this, SLOT(readyRead()));
6558 QMetaObject::invokeMethod(&QTestEventLoop::instance(), "exitLoop", Qt::QueuedConnection);
6562 QNetworkReply *mReply;
6565 void tst_QNetworkReply::httpAbort()
6567 // FIXME Also implement one where we do a big upload and then abort().
6568 // It must not crash either.
6570 // Abort after the first readyRead()
6571 QNetworkRequest request("http://" + QtNetworkSettings::serverName() + "/qtest/bigfile");
6572 QNetworkReplyPtr reply;
6573 reply = manager.get(request);
6574 HttpAbortHelper replyHolder(reply);
6575 QTestEventLoop::instance().enterLoop(10);
6576 QVERIFY(!QTestEventLoop::instance().timeout());
6577 QCOMPARE(reply->error(), QNetworkReply::OperationCanceledError);
6578 QVERIFY(reply->isFinished());
6580 // Abort immediately after the get()
6581 QNetworkReplyPtr reply2 = manager.get(request);
6582 connect(reply2, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
6584 QCOMPARE(reply2->error(), QNetworkReply::OperationCanceledError);
6585 QVERIFY(reply2->isFinished());
6587 // Abort after the finished()
6588 QNetworkRequest request3("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt");
6589 QNetworkReplyPtr reply3 = manager.get(request3);
6591 QVERIFY(waitForFinish(reply3) == Success);
6593 QVERIFY(reply3->isFinished());
6595 QCOMPARE(reply3->error(), QNetworkReply::NoError);
6598 void tst_QNetworkReply::dontInsertPartialContentIntoTheCache()
6600 QByteArray reply206 =
6602 "Connection: keep-alive\r\n"
6603 "Content-Type: text/plain\r\n"
6604 "Cache-control: no-cache\r\n"
6605 "Content-Range: bytes 2-6/8\r\n"
6606 "Content-length: 4\r\n"
6610 MiniHttpServer server(reply206);
6611 server.doClose = false;
6613 MySpyMemoryCache *memoryCache = new MySpyMemoryCache(&manager);
6614 manager.setCache(memoryCache);
6616 QUrl url = "http://localhost:" + QString::number(server.serverPort());
6617 QNetworkRequest request(url);
6618 request.setRawHeader("Range", "bytes=2-6");
6620 QNetworkReplyPtr reply = manager.get(request);
6622 QVERIFY(waitForFinish(reply) == Success);
6624 QVERIFY(server.totalConnections > 0);
6625 QCOMPARE(reply->readAll().constData(), "load");
6626 QCOMPARE(memoryCache->m_insertedUrls.count(), 0);
6629 void tst_QNetworkReply::httpUserAgent()
6631 QByteArray response("HTTP/1.0 200 OK\r\n\r\n");
6632 MiniHttpServer server(response);
6633 server.doClose = true;
6635 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
6636 request.setHeader(QNetworkRequest::UserAgentHeader, "abcDEFghi");
6637 QNetworkReplyPtr reply = manager.get(request);
6639 QVERIFY(waitForFinish(reply) == Success);
6641 QVERIFY(reply->isFinished());
6642 QCOMPARE(reply->error(), QNetworkReply::NoError);
6643 QVERIFY(server.receivedData.contains("\r\nUser-Agent: abcDEFghi\r\n"));
6646 void tst_QNetworkReply::synchronousAuthenticationCache()
6648 class MiniAuthServer : public MiniHttpServer {
6650 MiniAuthServer(QThread *thread) : MiniHttpServer(QByteArray(), false, thread) {};
6651 virtual void reply() {
6654 "HTTP/1.0 401 Unauthorized\r\n"
6655 "WWW-Authenticate: Basic realm=\"QNetworkAccessManager Test Realm\"\r\n"
6656 "Content-Length: 4\r\n"
6657 "Connection: close\r\n"
6658 "Content-Type: text/plain\r\n"
6661 QRegExp rx("Authorization: Basic ([^\r\n]*)\r\n");
6662 if (rx.indexIn(receivedData) > 0) {
6663 if (QByteArray::fromBase64(rx.cap(1).toLatin1()) == "login:password") {
6665 "HTTP/1.0 200 OK\r\n"
6666 "Content-Type: text/plain\r\n"
6667 "Content-Length: 2\r\n"
6672 receivedData.clear();
6673 MiniHttpServer::reply();
6677 // when using synchronous commands, we need a different event loop for
6678 // the server thread, because the client is never returning to the
6680 QScopedPointer<QThread, QThreadCleanup> serverThread(new QThread);
6681 QScopedPointer<MiniHttpServer, QDeleteLaterCleanup> server(new MiniAuthServer(serverThread.data()));
6682 server->doClose = true;
6684 //1) URL without credentials, we are not authenticated
6686 QUrl url = "http://localhost:" + QString::number(server->serverPort()) + "/path";
6687 QNetworkRequest request(url);
6688 request.setAttribute(QNetworkRequest::SynchronousRequestAttribute, true);
6690 QNetworkReplyPtr reply = manager.get(request);
6691 QVERIFY(reply->isFinished());
6692 QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError);
6695 //2) URL with credentials, we are authenticated
6697 QUrl url = "http://login:password@localhost:" + QString::number(server->serverPort()) + "/path2";
6698 QNetworkRequest request(url);
6699 request.setAttribute(QNetworkRequest::SynchronousRequestAttribute, true);
6701 QNetworkReplyPtr reply = manager.get(request);
6702 QVERIFY(reply->isFinished());
6703 QCOMPARE(reply->error(), QNetworkReply::NoError);
6704 QCOMPARE(reply->readAll().constData(), "OK");
6707 //3) URL without credentials, we are authenticated because they are cached
6709 QUrl url = "http://localhost:" + QString::number(server->serverPort()) + "/path3";
6710 QNetworkRequest request(url);
6711 request.setAttribute(QNetworkRequest::SynchronousRequestAttribute, true);
6713 QNetworkReplyPtr reply = manager.get(request);
6714 QVERIFY(reply->isFinished());
6715 QCOMPARE(reply->error(), QNetworkReply::NoError);
6716 QCOMPARE(reply->readAll().constData(), "OK");
6720 void tst_QNetworkReply::pipelining()
6722 QString urlString("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/echo.cgi?");
6723 QList<QNetworkReplyPtr> replies;
6724 for (int a = 0; a < 20; a++) {
6725 QNetworkRequest request(urlString + QString::number(a));
6726 request.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, QVariant(true));
6727 replies.append(manager.get(request));
6728 connect(replies.at(a), SIGNAL(finished()), this, SLOT(pipeliningHelperSlot()));
6730 QTestEventLoop::instance().enterLoop(20);
6731 QVERIFY(!QTestEventLoop::instance().timeout());
6734 void tst_QNetworkReply::pipeliningHelperSlot() {
6737 // check that pipelining was used in at least one of the replies
6738 static bool pipeliningWasUsed = false;
6739 QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
6740 bool pipeliningWasUsedInReply = reply->attribute(QNetworkRequest::HttpPipeliningWasUsedAttribute).toBool();
6741 if (pipeliningWasUsedInReply)
6742 pipeliningWasUsed = true;
6744 // check that the contents match (the response to echo.cgi?3 should return 3 etc.)
6745 QString urlQueryString = reply->url().queryItems().at(0).first;
6746 QString content = reply->readAll();
6747 QVERIFY2(urlQueryString == content, "data corruption with pipelining detected");
6751 if (a == 20) { // all replies have finished
6752 QTestEventLoop::instance().exitLoop();
6753 QVERIFY2(pipeliningWasUsed, "pipelining was not used in any of the replies when trying to test pipelining");
6757 void tst_QNetworkReply::closeDuringDownload_data()
6759 QTest::addColumn<QUrl>("url");
6760 QTest::newRow("http") << QUrl("http://" + QtNetworkSettings::serverName() + "/bigfile");
6761 QTest::newRow("ftp") << QUrl("ftp://" + QtNetworkSettings::serverName() + "/qtest/bigfile");
6764 void tst_QNetworkReply::closeDuringDownload()
6767 QNetworkRequest request(url);
6768 QNetworkReply* reply = manager.get(request);
6769 connect(reply, SIGNAL(readyRead()), &QTestEventLoop::instance(), SLOT(exitLoop()));
6770 QTestEventLoop::instance().enterLoop(10);
6771 QVERIFY(!QTestEventLoop::instance().timeout());
6772 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
6774 reply->deleteLater();
6775 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
6778 // NOTE: This test must be last testcase in tst_qnetworkreply!
6779 void tst_QNetworkReply::parentingRepliesToTheApp()
6781 QNetworkRequest request (QUrl("http://" + QtNetworkSettings::serverName()));
6782 manager.get(request)->setParent(this); // parent to this object
6783 manager.get(request)->setParent(qApp); // parent to the app
6786 QTEST_MAIN(tst_QNetworkReply)
6788 #include "tst_qnetworkreply.moc"