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 typedef QSharedPointer<QNetworkReply> QNetworkReplyPtr;
108 class tst_QNetworkReply: public QObject
113 ProxyData(const QNetworkProxy &p, const QByteArray &t, bool auth)
114 : tag(t), proxy(p), requiresAuthentication(auth)
118 bool requiresAuthentication;
121 static bool seedCreated;
122 static QString createUniqueExtension() {
124 qsrand(QTime(0,0,0).msecsTo(QTime::currentTime()) + QCoreApplication::applicationPid());
125 seedCreated = true; // not thread-safe, but who cares
127 QString s = QString("%1-%2-%3").arg(QTime(0,0,0).msecsTo(QTime::currentTime())).arg(QCoreApplication::applicationPid()).arg(qrand());
132 enum RunSimpleRequestReturn { Timeout = 0, Success, Failure };
134 QString testFileName;
135 QString echoProcessDir;
136 #if !defined Q_OS_WIN
137 QString wronlyFileName;
139 QString uniqueExtension;
140 QList<ProxyData> proxies;
141 QNetworkAccessManager manager;
142 MyCookieJar *cookieJar;
144 QSslConfiguration storedSslConfiguration;
145 QList<QSslError> storedExpectedSslErrors;
147 #ifndef QT_NO_BEARERMANAGEMENT
148 QNetworkConfigurationManager *netConfMan;
149 QNetworkConfiguration networkConfiguration;
150 QScopedPointer<QNetworkSession> networkSession;
153 using QObject::connect;
154 static bool connect(const QNetworkReplyPtr &ptr, const char *signal, const QObject *receiver, const char *slot, Qt::ConnectionType ct = Qt::AutoConnection)
155 { return connect(ptr.data(), signal, receiver, slot, ct); }
156 bool connect(const QNetworkReplyPtr &ptr, const char *signal, const char *slot, Qt::ConnectionType ct = Qt::AutoConnection)
157 { return connect(ptr.data(), signal, slot, ct); }
161 ~tst_QNetworkReply();
162 QString runSimpleRequest(QNetworkAccessManager::Operation op, const QNetworkRequest &request,
163 QNetworkReplyPtr &reply, const QByteArray &data = QByteArray());
164 QString runMultipartRequest(const QNetworkRequest &request, QNetworkReplyPtr &reply,
165 QHttpMultiPart *multiPart, const QByteArray &verb);
167 QString runCustomRequest(const QNetworkRequest &request, QNetworkReplyPtr &reply,
168 const QByteArray &verb, QIODevice *data);
169 int waitForFinish(QNetworkReplyPtr &reply);
174 void authenticationRequired(QNetworkReply*,QAuthenticator*);
175 void proxyAuthenticationRequired(const QNetworkProxy &,QAuthenticator*);
176 void pipeliningHelperSlot();
179 void sslErrors(QNetworkReply*,const QList<QSslError> &);
180 void storeSslConfiguration();
181 void ignoreSslErrorListSlot(QNetworkReply *reply, const QList<QSslError> &);
185 void nestedEventLoops_slot();
191 void cleanupTestCase();
193 void stateChecking();
194 void invalidProtocol();
195 void getFromData_data();
198 void getFromFileSpecial_data();
199 void getFromFileSpecial();
200 void getFromFtp_data();
202 void getFromHttp_data();
204 void getErrors_data();
206 void headFromHttp_data();
208 void putToFile_data();
210 void putToFtp_data();
212 void putToHttp_data();
214 void putToHttpSynchronous_data();
215 void putToHttpSynchronous();
216 void putToHttpMultipart_data();
217 void putToHttpMultipart();
218 void postToHttp_data();
220 void postToHttpSynchronous_data();
221 void postToHttpSynchronous();
222 void postToHttpMultipart_data();
223 void postToHttpMultipart();
224 void deleteFromHttp_data();
225 void deleteFromHttp();
226 void putGetDeleteGetFromHttp_data();
227 void putGetDeleteGetFromHttp();
228 void sendCustomRequestToHttp_data();
229 void sendCustomRequestToHttp();
230 void connectToIPv6Address_data();
231 void connectToIPv6Address();
233 void ioGetFromData_data();
234 void ioGetFromData();
235 void ioGetFromFileSpecial_data();
236 void ioGetFromFileSpecial();
237 void ioGetFromFile_data();
238 void ioGetFromFile();
239 void ioGetFromFtp_data();
241 void ioGetFromFtpWithReuse();
242 void ioGetFromHttp();
244 void ioGetFromBuiltinHttp_data();
245 void ioGetFromBuiltinHttp();
246 void ioGetFromHttpWithReuseParallel();
247 void ioGetFromHttpWithReuseSequential();
248 void ioGetFromHttpWithAuth_data();
249 void ioGetFromHttpWithAuth();
250 void ioGetFromHttpWithAuthSynchronous();
251 void ioGetFromHttpWithProxyAuth();
252 void ioGetFromHttpWithProxyAuthSynchronous();
253 void ioGetFromHttpWithSocksProxy();
255 void ioGetFromHttpsWithSslErrors();
256 void ioGetFromHttpsWithIgnoreSslErrors();
257 void ioGetFromHttpsWithSslHandshakeError();
259 void ioGetFromHttpBrokenServer_data();
260 void ioGetFromHttpBrokenServer();
261 void ioGetFromHttpStatus100_data();
262 void ioGetFromHttpStatus100();
263 void ioGetFromHttpNoHeaders_data();
264 void ioGetFromHttpNoHeaders();
265 void ioGetFromHttpWithCache_data();
266 void ioGetFromHttpWithCache();
268 void ioGetWithManyProxies_data();
269 void ioGetWithManyProxies();
271 void ioPutToFileFromFile_data();
272 void ioPutToFileFromFile();
273 void ioPutToFileFromSocket_data();
274 void ioPutToFileFromSocket();
275 void ioPutToFileFromLocalSocket_data();
276 void ioPutToFileFromLocalSocket();
277 #ifndef QT_NO_PROCESS
278 void ioPutToFileFromProcess_data();
279 void ioPutToFileFromProcess();
281 void ioPutToFtpFromFile_data();
282 void ioPutToFtpFromFile();
283 void ioPutToHttpFromFile_data();
284 void ioPutToHttpFromFile();
285 void ioPostToHttpFromFile_data();
286 void ioPostToHttpFromFile();
287 void ioPostToHttpFromSocket_data();
288 void ioPostToHttpFromSocket();
289 void ioPostToHttpFromSocketSynchronous();
290 void ioPostToHttpFromSocketSynchronous_data();
291 void ioPostToHttpFromMiddleOfFileToEnd();
292 void ioPostToHttpFromMiddleOfFileFiveBytes();
293 void ioPostToHttpFromMiddleOfQBufferFiveBytes();
294 void ioPostToHttpNoBufferFlag();
295 void ioPostToHttpUploadProgress();
296 void ioPostToHttpEmptyUploadProgress();
298 void lastModifiedHeaderForFile();
299 void lastModifiedHeaderForHttp();
301 void httpCanReadLine();
303 void rateControl_data();
306 void downloadProgress_data();
307 void downloadProgress();
308 void uploadProgress_data();
309 void uploadProgress();
311 void chaining_data();
314 void receiveCookiesFromHttp_data();
315 void receiveCookiesFromHttp();
316 void receiveCookiesFromHttpSynchronous_data();
317 void receiveCookiesFromHttpSynchronous();
318 void sendCookies_data();
320 void sendCookiesSynchronous_data();
321 void sendCookiesSynchronous();
323 void nestedEventLoops();
325 void httpProxyCommands_data();
326 void httpProxyCommands();
327 void httpProxyCommandsSynchronous_data();
328 void httpProxyCommandsSynchronous();
330 void authorizationError_data();
331 void authorizationError();
333 void httpConnectionCount();
335 void httpReUsingConnectionSequential_data();
336 void httpReUsingConnectionSequential();
337 void httpReUsingConnectionFromFinishedSlot_data();
338 void httpReUsingConnectionFromFinishedSlot();
340 void httpRecursiveCreation();
343 void ioPostToHttpsUploadProgress();
344 void ignoreSslErrorsList_data();
345 void ignoreSslErrorsList();
346 void ignoreSslErrorsListWithSlot_data();
347 void ignoreSslErrorsListWithSlot();
348 void sslConfiguration_data();
349 void sslConfiguration();
352 void getAndThenDeleteObject_data();
353 void getAndThenDeleteObject();
355 void symbianOpenCDataUrlCrash();
357 void getFromHttpIntoBuffer_data();
358 void getFromHttpIntoBuffer();
359 void getFromHttpIntoBuffer2_data();
360 void getFromHttpIntoBuffer2();
361 void getFromHttpIntoBufferCanReadLine();
363 void ioGetFromHttpWithoutContentLength();
365 void ioGetFromHttpBrokenChunkedEncoding();
366 void qtbug12908compressedHttpReply();
367 void compressedHttpReplyBrokenGzip();
369 void getFromUnreachableIp();
371 void qtbug4121unknownAuthentication();
373 void qtbug13431replyThrottling();
375 void httpWithNoCredentialUsage();
377 void qtbug15311doubleContentLength();
379 void qtbug18232gzipContentLengthZero();
380 void qtbug22660gzipNoContentLengthEmptyContent();
382 void synchronousRequest_data();
383 void synchronousRequest();
385 void synchronousRequestSslFailure();
390 void dontInsertPartialContentIntoTheCache();
392 void httpUserAgent();
393 void authenticationCacheAfterCancel_data();
394 void authenticationCacheAfterCancel();
395 void authenticationWithDifferentRealm();
396 void synchronousAuthenticationCache();
399 void closeDuringDownload_data();
400 void closeDuringDownload();
402 void ftpAuthentication_data();
403 void ftpAuthentication();
405 // NOTE: This test must be last!
406 void parentingRepliesToTheApp();
411 bool tst_QNetworkReply::seedCreated = false;
417 char *toString(const QNetworkReply::NetworkError& code)
419 const QMetaObject *mo = &QNetworkReply::staticMetaObject;
420 int index = mo->indexOfEnumerator("NetworkError");
424 QMetaEnum qme = mo->enumerator(index);
425 return qstrdup(qme.valueToKey(code));
429 char *toString(const QNetworkCookie &cookie)
431 return qstrdup(cookie.toRawForm());
435 char *toString(const QList<QNetworkCookie> &list)
437 QString result = "QList(";
439 foreach (QNetworkCookie cookie, list) {
443 result += QString::fromLatin1("QNetworkCookie(%1)").arg(QLatin1String(cookie.toRawForm()));
446 return qstrdup(result.append(')').toLocal8Bit());
452 #define RUN_REQUEST(call) \
454 QString errorMsg = call; \
455 if (!errorMsg.isEmpty()) \
456 QFAIL(qPrintable(errorMsg)); \
460 static void setupSslServer(QSslSocket* serverSocket)
462 QString testDataDir = QFileInfo(QFINDTESTDATA("rfc3252.txt")).absolutePath();
463 if (testDataDir.isEmpty())
464 testDataDir = QCoreApplication::applicationDirPath();
466 serverSocket->setProtocol(QSsl::AnyProtocol);
467 serverSocket->setLocalCertificate(testDataDir + "/certs/server.pem");
468 serverSocket->setPrivateKey(testDataDir + "/certs/server.key");
472 // Does not work for POST/PUT!
473 class MiniHttpServer: public QTcpServer
477 QTcpSocket *client; // always the last one that was received
478 QByteArray dataToTransmit;
479 QByteArray receivedData;
485 int totalConnections;
487 MiniHttpServer(const QByteArray &data, bool ssl = false, QThread *thread = 0, bool useipv6 = false)
488 : client(0), dataToTransmit(data), doClose(true), doSsl(ssl), ipv6(useipv6),
489 multiple(false), totalConnections(0)
492 listen(QHostAddress::AnyIPv6);
494 listen(QHostAddress::AnyIPv4);
497 connect(thread, SIGNAL(started()), this, SLOT(threadStartedSlot()));
498 moveToThread(thread);
505 void incomingConnection(qintptr socketDescriptor)
507 //qDebug() << "incomingConnection" << socketDescriptor << "doSsl:" << doSsl << "ipv6:" << ipv6;
509 client = new QTcpSocket;
510 client->setSocketDescriptor(socketDescriptor);
511 connectSocketSignals();
514 QSslSocket *serverSocket = new QSslSocket;
515 serverSocket->setParent(this);
516 if (serverSocket->setSocketDescriptor(socketDescriptor)) {
517 connect(serverSocket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(slotSslErrors(QList<QSslError>)));
518 setupSslServer(serverSocket);
519 serverSocket->startServerEncryption();
520 client = serverSocket;
521 connectSocketSignals();
528 client->setParent(this);
532 virtual void reply() {
533 // we need to emulate the bytesWrittenSlot call if the data is empty.
534 if (dataToTransmit.size() == 0)
535 QMetaObject::invokeMethod(this, "bytesWrittenSlot", Qt::QueuedConnection);
537 client->write(dataToTransmit);
540 void connectSocketSignals()
542 //qDebug() << "connectSocketSignals" << client;
543 connect(client, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
544 connect(client, SIGNAL(bytesWritten(qint64)), this, SLOT(bytesWrittenSlot()));
545 connect(client, SIGNAL(error(QAbstractSocket::SocketError)),
546 this, SLOT(slotError(QAbstractSocket::SocketError)));
551 void slotSslErrors(const QList<QSslError>& errors)
553 qDebug() << "slotSslErrors" << client->errorString() << errors;
556 void slotError(QAbstractSocket::SocketError err)
558 qDebug() << "slotError" << err << client->errorString();
564 receivedData += client->readAll();
565 int doubleEndlPos = receivedData.indexOf("\r\n\r\n");
567 if (doubleEndlPos != -1) {
568 // multiple requests incoming. remove the bytes of the current one
570 receivedData.remove(0, doubleEndlPos+4);
576 void bytesWrittenSlot() {
577 if (doClose && client->bytesToWrite() == 0) {
578 client->disconnectFromHost();
579 disconnect(client, 0, this, 0);
583 void threadStartedSlot()
589 class MyCookieJar: public QNetworkCookieJar
592 inline QList<QNetworkCookie> allCookies() const
593 { return QNetworkCookieJar::allCookies(); }
594 inline void setAllCookies(const QList<QNetworkCookie> &cookieList)
595 { QNetworkCookieJar::setAllCookies(cookieList); }
598 class MyProxyFactory: public QNetworkProxyFactory
602 QList<QNetworkProxy> toReturn;
603 QNetworkProxyQuery lastQuery;
604 inline MyProxyFactory() { clear(); }
609 toReturn = QList<QNetworkProxy>() << QNetworkProxy::DefaultProxy;
610 lastQuery = QNetworkProxyQuery();
613 virtual QList<QNetworkProxy> queryProxy(const QNetworkProxyQuery &query)
621 class MyMemoryCache: public QAbstractNetworkCache
624 typedef QPair<QNetworkCacheMetaData, QByteArray> CachedContent;
625 typedef QHash<QByteArray, CachedContent> CacheData;
628 MyMemoryCache(QObject *parent) : QAbstractNetworkCache(parent) {}
630 QNetworkCacheMetaData metaData(const QUrl &url)
632 return cache.value(url.toEncoded()).first;
635 void updateMetaData(const QNetworkCacheMetaData &metaData)
637 cache[metaData.url().toEncoded()].first = metaData;
640 QIODevice *data(const QUrl &url)
642 CacheData::ConstIterator it = cache.find(url.toEncoded());
643 if (it == cache.constEnd())
645 QBuffer *io = new QBuffer(this);
646 io->setData(it->second);
647 io->open(QIODevice::ReadOnly);
652 bool remove(const QUrl &url)
654 cache.remove(url.toEncoded());
658 qint64 cacheSize() const
661 foreach (const CachedContent &entry, cache)
662 total += entry.second.size();
666 QIODevice *prepare(const QNetworkCacheMetaData &)
668 qFatal("%s: Should not have tried to add to the cache", Q_FUNC_INFO);
671 void insert(QIODevice *)
673 qFatal("%s: Should not have tried to add to the cache", Q_FUNC_INFO);
676 void clear() { cache.clear(); }
678 Q_DECLARE_METATYPE(MyMemoryCache::CachedContent)
679 Q_DECLARE_METATYPE(MyMemoryCache::CacheData)
681 class MySpyMemoryCache: public QAbstractNetworkCache
684 MySpyMemoryCache(QObject *parent) : QAbstractNetworkCache(parent) {}
687 qDeleteAll(m_buffers);
691 QHash<QUrl, QIODevice*> m_buffers;
692 QList<QUrl> m_insertedUrls;
694 QNetworkCacheMetaData metaData(const QUrl &)
696 return QNetworkCacheMetaData();
699 void updateMetaData(const QNetworkCacheMetaData &)
703 QIODevice *data(const QUrl &)
708 bool remove(const QUrl &url)
710 delete m_buffers.take(url);
711 return m_insertedUrls.removeAll(url) > 0;
714 qint64 cacheSize() const
719 QIODevice *prepare(const QNetworkCacheMetaData &metaData)
721 QBuffer* buffer = new QBuffer;
722 buffer->open(QIODevice::ReadWrite);
723 buffer->setProperty("url", metaData.url());
724 m_buffers.insert(metaData.url(), buffer);
728 void insert(QIODevice *buffer)
730 QUrl url = buffer->property("url").toUrl();
731 m_insertedUrls << url;
732 delete m_buffers.take(url);
735 void clear() { m_insertedUrls.clear(); }
738 class DataReader: public QObject
746 DataReader(const QNetworkReplyPtr &dev, bool acc = true) : totalBytes(0), device(dev.data()), accumulate(acc)
747 { connect(device, SIGNAL(readyRead()), SLOT(doRead()) ); }
748 DataReader(QIODevice *dev, bool acc = true) : totalBytes(0), device(dev), accumulate(acc)
750 connect(device, SIGNAL(readyRead()), SLOT(doRead()));
757 buffer.resize(device->bytesAvailable());
758 qint64 bytesRead = device->read(buffer.data(), device->bytesAvailable());
759 if (bytesRead == -1) {
760 QTestEventLoop::instance().exitLoop();
763 buffer.truncate(bytesRead);
764 totalBytes += bytesRead;
772 class SocketPair: public QObject
776 QIODevice *endPoints[2];
778 SocketPair(QObject *parent = 0)
781 endPoints[0] = endPoints[1] = 0;
789 QTcpSocket *active = new QTcpSocket(this);
790 active->connectToHost("127.0.0.1", server.serverPort());
792 // need more time as working with embedded
793 // device and testing from emualtor
794 // things tend to get slower
795 if (!active->waitForConnected(1000))
798 if (!server.waitForNewConnection(1000))
801 QTcpSocket *passive = server.nextPendingConnection();
802 passive->setParent(this);
804 endPoints[0] = active;
805 endPoints[1] = passive;
810 // A blocking tcp server (must be used in a thread) which supports SSL.
811 class BlockingTcpServer : public QTcpServer
815 BlockingTcpServer(bool ssl) : doSsl(ssl), sslSocket(0) {}
817 QTcpSocket* waitForNextConnectionSocket() {
818 waitForNewConnection(-1);
821 qFatal("%s: sslSocket should not be null after calling waitForNewConnection()",
825 //qDebug() << "returning nextPendingConnection";
826 return nextPendingConnection();
829 virtual void incomingConnection(qintptr socketDescriptor)
833 QSslSocket *serverSocket = new QSslSocket;
834 serverSocket->setParent(this);
835 serverSocket->setSocketDescriptor(socketDescriptor);
836 connect(serverSocket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(slotSslErrors(QList<QSslError>)));
837 setupSslServer(serverSocket);
838 serverSocket->startServerEncryption();
839 sslSocket = serverSocket;
843 QTcpServer::incomingConnection(socketDescriptor);
849 void slotSslErrors(const QList<QSslError>& errors)
851 qDebug() << "slotSslErrors" << sslSocket->errorString() << errors;
857 QTcpSocket* sslSocket;
860 // This server tries to send data as fast as possible (like most servers)
861 // but it measures how fast it was able to send it, which shows at which
862 // rate the reader is processing the data.
863 class FastSender: public QThread
869 enum Protocol { DebugPipe, ProvidedData };
870 const Protocol protocol;
872 const bool fillKernelBuffer;
877 QByteArray dataToTransmit;
880 // a server that sends debugpipe data
881 FastSender(qint64 size)
882 : wantedSize(size), port(-1), protocol(DebugPipe),
883 doSsl(false), fillKernelBuffer(true), transferRate(-1),
890 // a server that sends the data provided at construction time, useful for HTTP
891 FastSender(const QByteArray& data, bool https, bool fillBuffer)
892 : wantedSize(data.size()), port(-1), protocol(ProvidedData),
893 doSsl(https), fillKernelBuffer(fillBuffer), transferRate(-1),
894 dataToTransmit(data), dataIndex(0)
900 inline int serverPort() const { return port; }
902 int writeNextData(QTcpSocket* socket, qint32 size)
904 if (protocol == DebugPipe) {
906 QDataStream stream(&data, QIODevice::WriteOnly);
907 stream << QVariantMap() << QByteArray(size, 'a');
908 socket->write((char*)&size, sizeof size);
913 const QByteArray data = dataToTransmit.mid(dataIndex, size);
915 dataIndex += data.size();
916 //qDebug() << "wrote" << dataIndex << "/" << dataToTransmit.size();
920 void writeLastData(QTcpSocket* socket)
922 if (protocol == DebugPipe) {
924 QDataStream stream(&data, QIODevice::WriteOnly);
925 stream << QVariantMap() << QByteArray();
926 const qint32 size = data.size();
927 socket->write((char*)&size, sizeof size);
935 BlockingTcpServer server(doSsl);
937 port = server.serverPort();
940 QTcpSocket *client = server.waitForNextConnectionSocket();
942 // get the "request" packet
943 if (!client->waitForReadyRead(2000)) {
944 qDebug() << "FastSender:" << client->error() << "waiting for \"request\" packet";
947 client->readAll(); // we're not interested in the actual contents (e.g. HTTP request)
949 enum { BlockSize = 1024 };
951 if (fillKernelBuffer) {
953 // write a bunch of bytes to fill up the buffers
956 if (writeNextData(client, BlockSize) < BlockSize) {
957 qDebug() << "ERROR: FastSender: not enough data to write in order to fill buffers; or client is reading too fast";
960 while (client->bytesToWrite() > 0) {
961 if (!client->waitForBytesWritten(0)) {
966 //qDebug() << "Filling kernel buffer: wrote" << dataIndex << "bytes";
969 qDebug() << "FastSender: ok, kernel buffer is full after writing" << dataIndex << "bytes";
972 // Tell the client to start reading
975 // the kernel buffer is full
976 // clean up QAbstractSocket's residue:
977 while (client->bytesToWrite() > 0) {
978 qDebug() << "Still having" << client->bytesToWrite() << "bytes to write, doing that now";
979 if (!client->waitForBytesWritten(2000)) {
980 qDebug() << "ERROR: FastSender:" << client->error() << "cleaning up residue";
985 // now write in "blocking mode", this is where the rate measuring starts
988 //const qint64 writtenBefore = dataIndex;
989 //qint64 measuredTotalBytes = wantedSize - writtenBefore;
990 qint64 measuredSentBytes = 0;
991 while (dataIndex < wantedSize) {
992 const int remainingBytes = wantedSize - measuredSentBytes;
993 const int bytesToWrite = qMin(remainingBytes, static_cast<int>(BlockSize));
994 if (bytesToWrite <= 0)
995 qFatal("%s: attempt to write %d bytes", Q_FUNC_INFO, bytesToWrite);
996 measuredSentBytes += writeNextData(client, bytesToWrite);
998 while (client->bytesToWrite() > 0) {
999 if (!client->waitForBytesWritten(2000)) {
1000 qDebug() << "ERROR: FastSender:" << client->error() << "during blocking write";
1004 /*qDebug() << "FastSender:" << bytesToWrite << "bytes written now;"
1005 << measuredSentBytes << "measured bytes" << measuredSentBytes + writtenBefore << "total ("
1006 << measuredSentBytes*100/measuredTotalBytes << "% complete);"
1007 << timer.elapsed() << "ms elapsed";*/
1010 transferRate = measuredSentBytes * 1000 / timer.elapsed();
1011 qDebug() << "FastSender: flushed" << measuredSentBytes << "bytes in" << timer.elapsed() << "ms: rate =" << transferRate << "B/s";
1013 // write a "close connection" packet, if the protocol needs it
1014 writeLastData(client);
1020 class RateControlledReader: public QObject
1029 qint64 totalBytesRead;
1030 RateControlledReader(QObject& senderObj, QIODevice *dev, int kbPerSec, int maxBufferSize = 0)
1031 : device(dev), readBufferSize(maxBufferSize), totalBytesRead(0)
1033 // determine how often we have to wake up
1035 if (readBufferSize == 0) {
1036 // The requirement is simply "N KB per seconds"
1037 timesPerSecond = 20;
1038 bytesToRead = kbPerSec * 1024 / timesPerSecond;
1040 // The requirement also includes "<readBufferSize> bytes at a time"
1041 bytesToRead = readBufferSize;
1042 timesPerSecond = kbPerSec * 1024 / readBufferSize;
1044 interval = 1000 / timesPerSecond; // in ms
1046 qDebug() << "RateControlledReader: going to read" << bytesToRead
1047 << "bytes every" << interval << "ms";
1048 qDebug() << "actual read rate will be"
1049 << (bytesToRead * 1000 / interval) << "bytes/sec (wanted"
1050 << kbPerSec * 1024 << "bytes/sec)";
1052 // Wait for data to be readyRead
1053 bool ok = connect(&senderObj, SIGNAL(dataReady()), this, SLOT(slotDataReady()));
1055 qFatal("%s: Cannot connect dataReady signal", Q_FUNC_INFO);
1060 QByteArray someData = device->read(device->bytesAvailable());
1062 totalBytesRead += someData.size();
1063 qDebug() << "wrapUp: found" << someData.size() << "bytes left. progress" << data.size();
1064 //qDebug() << "wrapUp: now bytesAvailable=" << device->bytesAvailable();
1068 void slotDataReady()
1070 //qDebug() << "RateControlledReader: ready to go";
1071 startTimer(interval);
1075 void timerEvent(QTimerEvent *)
1077 //qDebug() << "RateControlledReader: timerEvent bytesAvailable=" << device->bytesAvailable();
1078 if (readBufferSize > 0 && device->bytesAvailable() > readBufferSize) {
1079 // This passes all the time, except in the final flush.
1080 //qFatal("%s: Too many bytes available", Q_FUNC_INFO);
1083 qint64 bytesRead = 0;
1087 if (device->bytesAvailable() == 0) {
1088 if (stopWatch.elapsed() > 20) {
1089 qDebug() << "RateControlledReader: Not enough data available for reading, waited too much, timing out";
1092 if (!device->waitForReadyRead(5)) {
1093 qDebug() << "RateControlledReader: Not enough data available for reading, even after waiting 5ms, bailing out";
1097 QByteArray someData = device->read(bytesToRead - bytesRead);
1099 bytesRead += someData.size();
1100 //qDebug() << "RateControlledReader: successfully read" << someData.size() << "progress:" << data.size();
1101 } while (bytesRead < bytesToRead);
1102 totalBytesRead += bytesRead;
1104 if (bytesRead < bytesToRead)
1105 qWarning() << "RateControlledReader: WARNING:" << bytesToRead - bytesRead << "bytes not read";
1110 tst_QNetworkReply::tst_QNetworkReply()
1112 qRegisterMetaType<QNetworkReply *>(); // for QSignalSpy
1113 qRegisterMetaType<QAuthenticator *>();
1114 qRegisterMetaType<QNetworkProxy>();
1116 qRegisterMetaType<QList<QSslError> >();
1118 qRegisterMetaType<QNetworkReply::NetworkError>();
1120 testFileName = QDir::currentPath() + "/testfile";
1121 uniqueExtension = createUniqueExtension();
1122 cookieJar = new MyCookieJar;
1123 manager.setCookieJar(cookieJar);
1125 QHostInfo hostInfo = QHostInfo::fromName(QtNetworkSettings::serverName());
1127 proxies << ProxyData(QNetworkProxy::NoProxy, "", false);
1129 if (hostInfo.error() == QHostInfo::NoError && !hostInfo.addresses().isEmpty()) {
1130 QString proxyserver = hostInfo.addresses().first().toString();
1131 proxies << ProxyData(QNetworkProxy(QNetworkProxy::HttpProxy, proxyserver, 3128), "+proxy", false)
1132 << ProxyData(QNetworkProxy(QNetworkProxy::HttpProxy, proxyserver, 3129), "+proxyauth", true)
1133 // currently unsupported
1134 // << ProxyData(QNetworkProxy(QNetworkProxy::HttpProxy, proxyserver, 3130), "+proxyauth-ntlm", true);
1135 << ProxyData(QNetworkProxy(QNetworkProxy::Socks5Proxy, proxyserver, 1080), "+socks", false)
1136 << ProxyData(QNetworkProxy(QNetworkProxy::Socks5Proxy, proxyserver, 1081), "+socksauth", true);
1138 printf("==================================================================\n");
1139 printf("Proxy could not be looked up. No proxy will be used while testing!\n");
1140 printf("==================================================================\n");
1144 tst_QNetworkReply::~tst_QNetworkReply()
1149 void tst_QNetworkReply::authenticationRequired(QNetworkReply*, QAuthenticator* auth)
1151 auth->setUser("httptest");
1152 auth->setPassword("httptest");
1155 void tst_QNetworkReply::proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator* auth)
1157 auth->setUser("qsockstest");
1158 auth->setPassword("password");
1162 void tst_QNetworkReply::sslErrors(QNetworkReply *reply, const QList<QSslError> &errors)
1164 reply->ignoreSslErrors();
1165 QVERIFY(!errors.isEmpty());
1166 QVERIFY(!reply->sslConfiguration().isNull());
1169 void tst_QNetworkReply::storeSslConfiguration()
1171 storedSslConfiguration = QSslConfiguration();
1172 QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
1174 storedSslConfiguration = reply->sslConfiguration();
1178 QString tst_QNetworkReply::runMultipartRequest(const QNetworkRequest &request,
1179 QNetworkReplyPtr &reply,
1180 QHttpMultiPart *multiPart,
1181 const QByteArray &verb)
1184 reply.reset(manager.post(request, multiPart));
1186 reply.reset(manager.put(request, multiPart));
1188 // the code below is copied from tst_QNetworkReply::runSimpleRequest, see below
1189 reply->setParent(this);
1190 connect(reply, SIGNAL(finished()), SLOT(finished()));
1191 connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(gotError()));
1192 multiPart->setParent(reply.data());
1194 returnCode = Timeout;
1195 loop = new QEventLoop;
1196 QTimer::singleShot(25000, loop, SLOT(quit()));
1197 int code = returnCode == Timeout ? loop->exec() : returnCode;
1203 return "Request failed: " + reply->errorString();
1205 return "Network timeout";
1210 QString tst_QNetworkReply::runSimpleRequest(QNetworkAccessManager::Operation op,
1211 const QNetworkRequest &request,
1212 QNetworkReplyPtr &reply,
1213 const QByteArray &data)
1216 case QNetworkAccessManager::HeadOperation:
1217 reply.reset(manager.head(request));
1220 case QNetworkAccessManager::GetOperation:
1221 reply.reset(manager.get(request));
1224 case QNetworkAccessManager::PutOperation:
1225 reply.reset(manager.put(request, data));
1228 case QNetworkAccessManager::PostOperation:
1229 reply.reset(manager.post(request, data));
1232 case QNetworkAccessManager::DeleteOperation:
1233 reply.reset(manager.deleteResource(request));
1237 qFatal("%s: Invalid/unknown operation requested", Q_FUNC_INFO);
1239 reply->setParent(this);
1241 returnCode = Timeout;
1244 if (request.attribute(QNetworkRequest::SynchronousRequestAttribute).toBool()) {
1245 if (reply->isFinished())
1246 code = reply->error() != QNetworkReply::NoError ? Failure : Success;
1250 connect(reply, SIGNAL(finished()), SLOT(finished()));
1251 connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(gotError()));
1254 loop = new QEventLoop;
1255 QSignalSpy spy(reply.data(), SIGNAL(downloadProgress(qint64,qint64)));
1256 while (!reply->isFinished()) {
1257 QTimer::singleShot(20000, loop, SLOT(quit()));
1258 code = loop->exec();
1259 if (count == spy.count() && !reply->isFinished()) {
1263 count = spy.count();
1271 return "Request failed: " + reply->errorString();
1273 return "Network timeout";
1278 QString tst_QNetworkReply::runCustomRequest(const QNetworkRequest &request,
1279 QNetworkReplyPtr &reply,
1280 const QByteArray &verb,
1283 reply.reset(manager.sendCustomRequest(request, verb, data));
1284 reply->setParent(this);
1285 connect(reply, SIGNAL(finished()), SLOT(finished()));
1286 connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(gotError()));
1288 returnCode = Timeout;
1289 loop = new QEventLoop;
1290 QTimer::singleShot(20000, loop, SLOT(quit()));
1291 int code = returnCode == Timeout ? loop->exec() : returnCode;
1297 return "Request failed: " + reply->errorString();
1299 return "Network timeout";
1304 int tst_QNetworkReply::waitForFinish(QNetworkReplyPtr &reply)
1308 connect(reply, SIGNAL(finished()), SLOT(finished()));
1309 connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(gotError()));
1310 returnCode = Success;
1311 loop = new QEventLoop;
1312 QSignalSpy spy(reply.data(), SIGNAL(downloadProgress(qint64,qint64)));
1313 while (!reply->isFinished()) {
1314 QTimer::singleShot(5000, loop, SLOT(quit()));
1315 if ( loop->exec() == Timeout && count == spy.count() && !reply->isFinished()) {
1316 returnCode = Timeout;
1319 count = spy.count();
1327 void tst_QNetworkReply::finished()
1329 loop->exit(returnCode = Success);
1332 void tst_QNetworkReply::gotError()
1334 loop->exit(returnCode = Failure);
1335 disconnect(QObject::sender(), SIGNAL(finished()), this, 0);
1338 void tst_QNetworkReply::initTestCase()
1340 testDataDir = QFileInfo(QFINDTESTDATA("rfc3252.txt")).absolutePath();
1341 if (testDataDir.isEmpty())
1342 testDataDir = QCoreApplication::applicationDirPath();
1344 QVERIFY(QtNetworkSettings::verifyTestNetworkSettings());
1345 #if !defined Q_OS_WIN
1346 wronlyFileName = testDataDir + "/write-only";
1347 QFile wr(wronlyFileName);
1348 QVERIFY(wr.open(QIODevice::WriteOnly | QIODevice::Truncate));
1349 wr.setPermissions(QFile::WriteOwner | QFile::WriteUser);
1353 QDir::setSearchPaths("testdata", QStringList() << testDataDir);
1355 QSslSocket::defaultCaCertificates(); //preload certificates
1357 #ifndef QT_NO_BEARERMANAGEMENT
1358 netConfMan = new QNetworkConfigurationManager(this);
1359 networkConfiguration = netConfMan->defaultConfiguration();
1360 networkSession.reset(new QNetworkSession(networkConfiguration));
1361 if (!networkSession->isOpen()) {
1362 networkSession->open();
1363 QVERIFY(networkSession->waitForOpened(30000));
1367 echoProcessDir = QFINDTESTDATA("echo");
1368 QVERIFY2(!echoProcessDir.isEmpty(), qPrintable(
1369 QString::fromLatin1("Couldn't find echo dir starting from %1.").arg(QDir::currentPath())));
1372 void tst_QNetworkReply::cleanupTestCase()
1374 #if !defined Q_OS_WIN
1375 QFile::remove(wronlyFileName);
1377 #ifndef QT_NO_BEARERMANAGEMENT
1378 if (networkSession && networkSession->isOpen()) {
1379 networkSession->close();
1384 void tst_QNetworkReply::init()
1389 void tst_QNetworkReply::cleanup()
1391 QFile file(testFileName);
1392 QVERIFY(!file.exists() || file.remove());
1394 // clear the internal cache
1395 manager.clearAccessCache();
1396 manager.setProxy(QNetworkProxy());
1397 manager.setCache(0);
1400 cookieJar->setAllCookies(QList<QNetworkCookie>());
1403 void tst_QNetworkReply::stateChecking()
1405 QUrl url = QUrl("file:///");
1406 QNetworkRequest req(url); // you can't open this file, I know
1407 QNetworkReplyPtr reply(manager.get(req));
1409 QVERIFY(reply.data());
1410 QVERIFY(reply->isOpen());
1411 QVERIFY(reply->isReadable());
1412 QVERIFY(!reply->isWritable());
1414 // both behaviours are OK since we might change underlying behaviour again
1415 if (!reply->isFinished())
1416 QCOMPARE(reply->errorString(), QString("Unknown error"));
1418 QVERIFY(!reply->errorString().isEmpty());
1421 QCOMPARE(reply->manager(), &manager);
1422 QCOMPARE(reply->request(), req);
1423 QCOMPARE(int(reply->operation()), int(QNetworkAccessManager::GetOperation));
1424 // error and not error are OK since we might change underlying behaviour again
1425 if (!reply->isFinished())
1426 QCOMPARE(reply->error(), QNetworkReply::NoError);
1427 QCOMPARE(reply->url(), url);
1432 void tst_QNetworkReply::invalidProtocol()
1434 QUrl url = QUrl::fromEncoded("not-a-known-protocol://foo/bar");
1435 QNetworkRequest req(url);
1436 QNetworkReplyPtr reply;
1438 QString errorMsg = "Request failed: Protocol \"not-a-known-protocol\" is unknown";
1439 QString result = runSimpleRequest(QNetworkAccessManager::GetOperation, req, reply);
1440 QCOMPARE(result, errorMsg);
1442 QCOMPARE(reply->url(), url);
1443 QCOMPARE(reply->error(), QNetworkReply::ProtocolUnknownError);
1446 void tst_QNetworkReply::getFromData_data()
1448 QTest::addColumn<QString>("request");
1449 QTest::addColumn<QByteArray>("expected");
1450 QTest::addColumn<QString>("mimeType");
1452 const QString defaultMimeType("text/plain;charset=US-ASCII");
1454 //QTest::newRow("empty") << "data:" << QByteArray() << defaultMimeType;
1455 QTest::newRow("empty2") << "data:," << QByteArray() << defaultMimeType;
1456 QTest::newRow("just-charset_1") << "data:charset=iso-8859-1,"
1457 << QByteArray() << "text/plain;charset=iso-8859-1";
1458 QTest::newRow("just-charset_2") << "data:charset = iso-8859-1 ,"
1459 << QByteArray() << "text/plain;charset = iso-8859-1";
1460 //QTest::newRow("just-media") << "data:text/xml" << QByteArray() << "text/xml";
1461 QTest::newRow("just-media2") << "data:text/xml," << QByteArray() << "text/xml";
1463 QTest::newRow("plain_1") << "data:,foo" << QByteArray("foo") << defaultMimeType;
1464 QTest::newRow("plain_2") << "data:text/html,Hello World" << QByteArray("Hello World")
1466 QTest::newRow("plain_3") << "data:text/html;charset=utf-8,Hello World"
1467 << QByteArray("Hello World") << "text/html;charset=utf-8";
1469 QTest::newRow("pct_1") << "data:,%3Cbody%20contentEditable%3Dtrue%3E%0D%0A"
1470 << QByteArray("<body contentEditable=true>\r\n") << defaultMimeType;
1471 QTest::newRow("pct_2") << "data:text/html;charset=utf-8,%3Cbody%20contentEditable%3Dtrue%3E%0D%0A"
1472 << QByteArray("<body contentEditable=true>\r\n")
1473 << "text/html;charset=utf-8";
1475 QTest::newRow("base64-empty_1") << "data:;base64," << QByteArray() << defaultMimeType;
1476 QTest::newRow("base64-empty_2") << "data:charset=utf-8;base64," << QByteArray()
1477 << "text/plain;charset=utf-8";
1478 QTest::newRow("base64-empty_3") << "data:text/html;charset=utf-8;base64,"
1479 << QByteArray() << "text/html;charset=utf-8";
1481 QTest::newRow("base64_1") << "data:;base64,UXQgaXMgZ3JlYXQh" << QByteArray("Qt is great!")
1483 QTest::newRow("base64_2") << "data:charset=utf-8;base64,UXQgaXMgZ3JlYXQh"
1484 << QByteArray("Qt is great!") << "text/plain;charset=utf-8";
1485 QTest::newRow("base64_3") << "data:text/html;charset=utf-8;base64,UXQgaXMgZ3JlYXQh"
1486 << QByteArray("Qt is great!") << "text/html;charset=utf-8";
1488 QTest::newRow("pct-nul") << "data:,a%00g" << QByteArray("a\0g", 3) << defaultMimeType;
1489 QTest::newRow("base64-nul") << "data:;base64,YQBn" << QByteArray("a\0g", 3) << defaultMimeType;
1490 QTest::newRow("pct-nonutf8") << "data:,a%E1g" << QByteArray("a\xE1g", 3) << defaultMimeType;
1492 QTest::newRow("base64")
1493 << QString::fromLatin1("data:application/xml;base64,PGUvPg==")
1494 << QByteArray("<e/>")
1495 << "application/xml";
1497 QTest::newRow("base64, no media type")
1498 << QString::fromLatin1("data:;base64,PGUvPg==")
1499 << QByteArray("<e/>")
1502 QTest::newRow("Percent encoding")
1503 << QString::fromLatin1("data:application/xml,%3Ce%2F%3E")
1504 << QByteArray("<e/>")
1505 << "application/xml";
1507 QTest::newRow("Percent encoding, no media type")
1508 << QString::fromLatin1("data:,%3Ce%2F%3E")
1509 << QByteArray("<e/>")
1512 QTest::newRow("querychars")
1513 << QString::fromLatin1("data:,foo?x=0&y=0")
1514 << QByteArray("foo?x=0&y=0")
1517 QTest::newRow("css") << "data:text/css,div%20{%20border-right:%20solid;%20}"
1518 << QByteArray("div { border-right: solid; }")
1522 void tst_QNetworkReply::getFromData()
1524 QFETCH(QString, request);
1525 QFETCH(QByteArray, expected);
1526 QFETCH(QString, mimeType);
1528 QUrl url = QUrl::fromEncoded(request.toLatin1());
1529 QNetworkRequest req(url);
1530 QNetworkReplyPtr reply;
1532 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, req, reply));
1534 QCOMPARE(reply->url(), url);
1535 QCOMPARE(reply->error(), QNetworkReply::NoError);
1537 QCOMPARE(reply->header(QNetworkRequest::ContentTypeHeader).toString(), mimeType);
1538 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), qint64(expected.size()));
1539 QCOMPARE(reply->readAll(), expected);
1542 void tst_QNetworkReply::getFromFile()
1545 QTemporaryFile file(QDir::currentPath() + "/temp-XXXXXX");
1546 file.setAutoRemove(true);
1547 QVERIFY(file.open());
1549 QNetworkRequest request(QUrl::fromLocalFile(file.fileName()));
1550 QNetworkReplyPtr reply;
1552 static const char fileData[] = "This is some data that is in the file.\r\n";
1553 QByteArray data = QByteArray::fromRawData(fileData, sizeof fileData - 1);
1554 QVERIFY(file.write(data) == data.size());
1556 QCOMPARE(file.size(), qint64(data.size()));
1558 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
1560 QCOMPARE(reply->url(), request.url());
1561 QCOMPARE(reply->error(), QNetworkReply::NoError);
1563 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), file.size());
1564 QCOMPARE(reply->readAll(), data);
1566 // make the file bigger
1568 const int multiply = (128 * 1024) / (sizeof fileData - 1);
1569 for (int i = 0; i < multiply; ++i)
1570 file.write(fileData, sizeof fileData - 1);
1576 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
1577 QCOMPARE(reply->url(), request.url());
1578 QCOMPARE(reply->error(), QNetworkReply::NoError);
1580 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), file.size());
1581 QCOMPARE(qint64(reply->readAll().size()), file.size());
1584 void tst_QNetworkReply::getFromFileSpecial_data()
1586 QTest::addColumn<QString>("fileName");
1587 QTest::addColumn<QString>("url");
1589 QTest::newRow("resource") << ":/resource" << "qrc:/resource";
1590 QTest::newRow("search-path") << "testdata:/rfc3252.txt" << "testdata:/rfc3252.txt";
1591 QTest::newRow("bigfile-path") << "testdata:/bigfile" << "testdata:/bigfile";
1593 QTest::newRow("smb-path") << "testdata:/smb-file.txt" << "file://" + QtNetworkSettings::winServerName() + "/testshare/test.pri";
1597 void tst_QNetworkReply::getFromFileSpecial()
1599 QFETCH(QString, fileName);
1600 QFETCH(QString, url);
1602 // open the resource so we can find out its size
1603 QFile resource(fileName);
1604 QVERIFY(resource.open(QIODevice::ReadOnly));
1606 QNetworkRequest request;
1607 QNetworkReplyPtr reply;
1608 request.setUrl(url);
1609 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
1611 QCOMPARE(reply->url(), request.url());
1612 QCOMPARE(reply->error(), QNetworkReply::NoError);
1614 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), resource.size());
1615 QCOMPARE(reply->readAll(), resource.readAll());
1618 void tst_QNetworkReply::getFromFtp_data()
1620 QTest::addColumn<QString>("referenceName");
1621 QTest::addColumn<QString>("url");
1623 QTest::newRow("rfc3252.txt") << (testDataDir + "/rfc3252.txt") << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt";
1624 QTest::newRow("bigfile") << (testDataDir + "/bigfile") << "ftp://" + QtNetworkSettings::serverName() + "/qtest/bigfile";
1627 void tst_QNetworkReply::getFromFtp()
1629 QFETCH(QString, referenceName);
1630 QFETCH(QString, url);
1632 QFile reference(referenceName);
1633 QVERIFY(reference.open(QIODevice::ReadOnly));
1635 QNetworkRequest request(url);
1636 QNetworkReplyPtr reply;
1637 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
1639 QCOMPARE(reply->url(), request.url());
1640 QCOMPARE(reply->error(), QNetworkReply::NoError);
1642 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
1643 QCOMPARE(reply->readAll(), reference.readAll());
1646 void tst_QNetworkReply::getFromHttp_data()
1648 QTest::addColumn<QString>("referenceName");
1649 QTest::addColumn<QString>("url");
1651 QTest::newRow("success-internal") << (testDataDir + "/rfc3252.txt") << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt";
1652 QTest::newRow("success-external") << (testDataDir + "/rfc3252.txt") << "http://www.ietf.org/rfc/rfc3252.txt";
1653 QTest::newRow("bigfile-internal") << (testDataDir + "/bigfile") << "http://" + QtNetworkSettings::serverName() + "/qtest/bigfile";
1656 void tst_QNetworkReply::getFromHttp()
1658 QFETCH(QString, referenceName);
1659 QFETCH(QString, url);
1661 QFile reference(referenceName);
1662 QVERIFY(reference.open(QIODevice::ReadOnly));
1664 QNetworkRequest request(url);
1665 QNetworkReplyPtr reply;
1666 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
1668 QCOMPARE(reply->url(), request.url());
1669 QCOMPARE(reply->error(), QNetworkReply::NoError);
1670 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
1671 QCOMPARE(reply->size(), reference.size());
1672 // only compare when the header is set.
1673 if (reply->header(QNetworkRequest::ContentLengthHeader).isValid())
1674 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
1676 // We know our internal server is apache..
1677 if (qstrcmp(QTest::currentDataTag(), "success-internal") == 0)
1678 QVERIFY(reply->header(QNetworkRequest::ServerHeader).toString().contains("Apache"));
1680 QCOMPARE(reply->readAll(), reference.readAll());
1683 void tst_QNetworkReply::headFromHttp_data()
1685 QTest::addColumn<qint64>("referenceSize");
1686 QTest::addColumn<QUrl>("url");
1687 QTest::addColumn<QString>("contentType");
1688 QTest::addColumn<QNetworkProxy>("proxy");
1690 qint64 rfcsize = QFileInfo(testDataDir + "/rfc3252.txt").size();
1691 qint64 bigfilesize = QFileInfo(testDataDir + "/bigfile").size();
1692 qint64 indexsize = QFileInfo(testDataDir + "/index.html").size();
1694 //testing proxies, mainly for the 407 response from http proxy
1695 for (int i = 0; i < proxies.count(); ++i) {
1696 QTest::newRow("rfc" + proxies.at(i).tag) << rfcsize << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt") << "text/plain" << proxies.at(i).proxy;
1697 QTest::newRow("bigfile" + proxies.at(i).tag) << bigfilesize << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/bigfile") << "text/plain" << proxies.at(i).proxy;
1698 QTest::newRow("index" + proxies.at(i).tag) << indexsize << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/") << "text/html" << proxies.at(i).proxy;
1699 QTest::newRow("with-authentication" + proxies.at(i).tag) << rfcsize << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt") << "text/plain" << proxies.at(i).proxy;
1700 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;
1704 void tst_QNetworkReply::headFromHttp()
1706 QFETCH(qint64, referenceSize);
1708 QFETCH(QString, contentType);
1709 QFETCH(QNetworkProxy, proxy);
1711 QNetworkRequest request(url);
1712 QNetworkReplyPtr reply;
1717 manager.setProxy(proxy);
1718 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
1719 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
1720 connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
1721 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
1723 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::HeadOperation, request, reply));
1725 manager.disconnect(SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
1726 this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
1727 manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
1728 this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
1730 QVERIFY(time.elapsed() < 8000); //check authentication didn't wait for the server to timeout the http connection (15s on qt test server)
1732 QCOMPARE(reply->url(), request.url());
1733 QCOMPARE(reply->error(), QNetworkReply::NoError);
1734 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
1735 // only compare when the header is set.
1736 if (reply->header(QNetworkRequest::ContentLengthHeader).isValid() && referenceSize >= 0)
1737 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), referenceSize);
1738 if (reply->header(QNetworkRequest::ContentTypeHeader).isValid())
1739 QCOMPARE(reply->header(QNetworkRequest::ContentTypeHeader).toString(), contentType);
1742 void tst_QNetworkReply::getErrors_data()
1744 QTest::addColumn<QString>("url");
1745 QTest::addColumn<int>("error");
1746 QTest::addColumn<int>("httpStatusCode");
1747 QTest::addColumn<bool>("dataIsEmpty");
1750 QTest::newRow("empty-url") << QString() << int(QNetworkReply::ProtocolUnknownError) << 0 << true;
1751 QTest::newRow("empty-scheme-host") << (testDataDir + "/rfc3252.txt") << int(QNetworkReply::ProtocolUnknownError) << 0 << true;
1752 QTest::newRow("empty-scheme") << "//" + QtNetworkSettings::winServerName() + "/testshare/test.pri"
1753 << int(QNetworkReply::ProtocolUnknownError) << 0 << true;
1756 QTest::newRow("file-host") << "file://this-host-doesnt-exist.troll.no/foo.txt"
1757 #if !defined Q_OS_WIN
1758 << int(QNetworkReply::ProtocolInvalidOperationError) << 0 << true;
1760 << int(QNetworkReply::ContentNotFoundError) << 0 << true;
1762 QTest::newRow("file-no-path") << "file://localhost"
1763 << int(QNetworkReply::ContentOperationNotPermittedError) << 0 << true;
1764 QTest::newRow("file-is-dir") << QUrl::fromLocalFile(QDir::currentPath()).toString()
1765 << int(QNetworkReply::ContentOperationNotPermittedError) << 0 << true;
1766 QTest::newRow("file-exist") << QUrl::fromLocalFile(QDir::currentPath() + "/this-file-doesnt-exist.txt").toString()
1767 << int(QNetworkReply::ContentNotFoundError) << 0 << true;
1768 #if !defined Q_OS_WIN
1769 QTest::newRow("file-is-wronly") << QUrl::fromLocalFile(wronlyFileName).toString()
1770 << int(QNetworkReply::ContentAccessDenied) << 0 << true;
1772 if (QFile::exists("/etc/shadow"))
1773 QTest::newRow("file-permissions") << "file:/etc/shadow"
1774 << int(QNetworkReply::ContentAccessDenied) << 0 << true;
1777 QTest::newRow("ftp-host") << "ftp://this-host-doesnt-exist.troll.no/foo.txt"
1778 << int(QNetworkReply::HostNotFoundError) << 0 << true;
1779 QTest::newRow("ftp-no-path") << "ftp://" + QtNetworkSettings::serverName()
1780 << int(QNetworkReply::ContentOperationNotPermittedError) << 0 << true;
1781 QTest::newRow("ftp-is-dir") << "ftp://" + QtNetworkSettings::serverName() + "/qtest"
1782 << int(QNetworkReply::ContentOperationNotPermittedError) << 0 << true;
1783 QTest::newRow("ftp-dir-not-readable") << "ftp://" + QtNetworkSettings::serverName() + "/pub/dir-not-readable/foo.txt"
1784 << int(QNetworkReply::ContentAccessDenied) << 0 << true;
1785 QTest::newRow("ftp-file-not-readable") << "ftp://" + QtNetworkSettings::serverName() + "/pub/file-not-readable.txt"
1786 << int(QNetworkReply::ContentAccessDenied) << 0 << true;
1787 QTest::newRow("ftp-exist") << "ftp://" + QtNetworkSettings::serverName() + "/pub/this-file-doesnt-exist.txt"
1788 << int(QNetworkReply::ContentNotFoundError) << 0 << true;
1791 QTest::newRow("http-host") << "http://this-host-will-never-exist.troll.no/"
1792 << int(QNetworkReply::HostNotFoundError) << 0 << true;
1793 QTest::newRow("http-exist") << "http://" + QtNetworkSettings::serverName() + "/this-file-doesnt-exist.txt"
1794 << int(QNetworkReply::ContentNotFoundError) << 404 << false;
1795 QTest::newRow("http-authentication") << "http://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth"
1796 << int(QNetworkReply::AuthenticationRequiredError) << 401 << false;
1799 void tst_QNetworkReply::getErrors()
1801 QFETCH(QString, url);
1802 QNetworkRequest request(url);
1805 if ((qstrcmp(QTest::currentDataTag(), "file-is-wronly") == 0) ||
1806 (qstrcmp(QTest::currentDataTag(), "file-permissions") == 0)) {
1807 if (::getuid() == 0)
1808 QSKIP("Running this test as root doesn't make sense");
1812 QNetworkReplyPtr reply(manager.get(request));
1813 reply->setParent(this); // we have expect-fails
1815 if (!reply->isFinished())
1816 QCOMPARE(reply->error(), QNetworkReply::NoError);
1818 // now run the request:
1819 QVERIFY(waitForFinish(reply) != Timeout);
1822 QEXPECT_FAIL("ftp-is-dir", "QFtp cannot provide enough detail", Abort);
1823 // the line below is not necessary
1824 QEXPECT_FAIL("ftp-dir-not-readable", "QFtp cannot provide enough detail", Abort);
1825 QCOMPARE(reply->error(), QNetworkReply::NetworkError(error));
1827 QTEST(reply->readAll().isEmpty(), "dataIsEmpty");
1829 QVERIFY(reply->isFinished());
1830 QVERIFY(!reply->isRunning());
1832 QFETCH(int, httpStatusCode);
1833 if (httpStatusCode != 0) {
1834 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), httpStatusCode);
1838 static inline QByteArray md5sum(const QByteArray &data)
1840 return QCryptographicHash::hash(data, QCryptographicHash::Md5);
1843 void tst_QNetworkReply::putToFile_data()
1845 QTest::addColumn<QByteArray>("data");
1846 QTest::addColumn<QByteArray>("md5sum");
1850 QTest::newRow("empty") << data << md5sum(data);
1852 data = "This is a normal message.";
1853 QTest::newRow("generic") << data << md5sum(data);
1855 data = "This is a message to show that Qt rocks!\r\n\n";
1856 QTest::newRow("small") << data << md5sum(data);
1858 data = QByteArray("abcd\0\1\2\abcd",12);
1859 QTest::newRow("with-nul") << data << md5sum(data);
1861 data = QByteArray(4097, '\4');
1862 QTest::newRow("4k+1") << data << md5sum(data);
1864 data = QByteArray(128*1024+1, '\177');
1865 QTest::newRow("128k+1") << data << md5sum(data);
1867 data = QByteArray(2*1024*1024+1, '\177');
1868 QTest::newRow("2MB+1") << data << md5sum(data);
1871 void tst_QNetworkReply::putToFile()
1873 QFile file(testFileName);
1875 QUrl url = QUrl::fromLocalFile(file.fileName());
1876 QNetworkRequest request(url);
1877 QNetworkReplyPtr reply;
1879 QFETCH(QByteArray, data);
1881 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PutOperation, request, reply, data));
1883 QCOMPARE(reply->url(), url);
1884 QCOMPARE(reply->error(), QNetworkReply::NoError);
1885 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
1886 QVERIFY(reply->readAll().isEmpty());
1888 QVERIFY(file.open(QIODevice::ReadOnly));
1889 QCOMPARE(file.size(), qint64(data.size()));
1890 QByteArray contents = file.readAll();
1891 QCOMPARE(contents, data);
1894 void tst_QNetworkReply::putToFtp_data()
1899 void tst_QNetworkReply::putToFtp()
1901 QUrl url("ftp://" + QtNetworkSettings::serverName());
1902 url.setPath(QString("/qtest/upload/qnetworkaccess-putToFtp-%1-%2")
1903 .arg(QTest::currentDataTag())
1904 .arg(uniqueExtension));
1906 QNetworkRequest request(url);
1907 QNetworkReplyPtr reply;
1909 QFETCH(QByteArray, data);
1911 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PutOperation, request, reply, data));
1913 QCOMPARE(reply->url(), url);
1914 QCOMPARE(reply->error(), QNetworkReply::NoError);
1915 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
1916 QVERIFY(reply->readAll().isEmpty());
1918 // download the file again from FTP to make sure it was uploaded
1920 QNetworkAccessManager qnam;
1921 QNetworkRequest req(url);
1922 QNetworkReply *r = qnam.get(req);
1924 QObject::connect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
1926 QSignalSpy spy(r, SIGNAL(downloadProgress(qint64,qint64)));
1927 while (!r->isFinished()) {
1928 QTestEventLoop::instance().enterLoop(10);
1929 if (count == spy.count() && !r->isFinished())
1931 count = spy.count();
1933 QObject::disconnect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
1935 QByteArray uploaded = r->readAll();
1936 QCOMPARE(uploaded.size(), data.size());
1937 QCOMPARE(uploaded, data);
1940 QObject::connect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
1941 QTestEventLoop::instance().enterLoop(10);
1942 QObject::disconnect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
1945 void tst_QNetworkReply::putToHttp_data()
1950 void tst_QNetworkReply::putToHttp()
1952 QUrl url("http://" + QtNetworkSettings::serverName());
1953 url.setPath(QString("/dav/qnetworkaccess-putToHttp-%1-%2")
1954 .arg(QTest::currentDataTag())
1955 .arg(uniqueExtension));
1957 QNetworkRequest request(url);
1958 QNetworkReplyPtr reply;
1960 QFETCH(QByteArray, data);
1962 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PutOperation, request, reply, data));
1964 QCOMPARE(reply->url(), url);
1965 QCOMPARE(reply->error(), QNetworkReply::NoError);
1967 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 201); // 201 Created
1969 // download the file again from HTTP to make sure it was uploaded
1970 // correctly. HTTP/0.9 is enough
1972 socket.connectToHost(QtNetworkSettings::serverName(), 80);
1973 socket.write("GET " + url.toEncoded(QUrl::RemoveScheme | QUrl::RemoveAuthority) + "\r\n");
1974 if (!socket.waitForDisconnected(10000))
1975 QFAIL("Network timeout");
1977 QByteArray uploadedData = socket.readAll();
1978 QCOMPARE(uploadedData, data);
1981 void tst_QNetworkReply::putToHttpSynchronous_data()
1983 uniqueExtension = createUniqueExtension();
1987 void tst_QNetworkReply::putToHttpSynchronous()
1989 QUrl url("http://" + QtNetworkSettings::serverName());
1990 url.setPath(QString("/dav/qnetworkaccess-putToHttp-%1-%2")
1991 .arg(QTest::currentDataTag())
1992 .arg(uniqueExtension));
1994 QNetworkRequest request(url);
1995 QNetworkReplyPtr reply;
1997 QFETCH(QByteArray, data);
1999 request.setAttribute(
2000 QNetworkRequest::SynchronousRequestAttribute,
2003 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PutOperation, request, reply, data));
2005 QCOMPARE(reply->url(), url);
2006 QCOMPARE(reply->error(), QNetworkReply::NoError);
2008 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 201); // 201 Created
2010 // download the file again from HTTP to make sure it was uploaded
2011 // correctly. HTTP/0.9 is enough
2013 socket.connectToHost(QtNetworkSettings::serverName(), 80);
2014 socket.write("GET " + url.toEncoded(QUrl::RemoveScheme | QUrl::RemoveAuthority) + "\r\n");
2015 if (!socket.waitForDisconnected(10000))
2016 QFAIL("Network timeout");
2018 QByteArray uploadedData = socket.readAll();
2019 QCOMPARE(uploadedData, data);
2022 void tst_QNetworkReply::postToHttp_data()
2027 void tst_QNetworkReply::postToHttp()
2029 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi");
2031 QNetworkRequest request(url);
2032 request.setRawHeader("Content-Type", "application/octet-stream");
2033 QNetworkReplyPtr reply;
2035 QFETCH(QByteArray, data);
2037 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PostOperation, request, reply, data));
2039 QCOMPARE(reply->url(), url);
2040 QCOMPARE(reply->error(), QNetworkReply::NoError);
2042 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
2044 QFETCH(QByteArray, md5sum);
2045 QByteArray uploadedData = reply->readAll().trimmed();
2046 QCOMPARE(uploadedData, md5sum.toHex());
2049 void tst_QNetworkReply::postToHttpSynchronous_data()
2054 void tst_QNetworkReply::postToHttpSynchronous()
2056 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi");
2058 QNetworkRequest request(url);
2059 request.setRawHeader("Content-Type", "application/octet-stream");
2061 request.setAttribute(
2062 QNetworkRequest::SynchronousRequestAttribute,
2065 QNetworkReplyPtr reply;
2067 QFETCH(QByteArray, data);
2069 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PostOperation, request, reply, data));
2071 QCOMPARE(reply->url(), url);
2072 QCOMPARE(reply->error(), QNetworkReply::NoError);
2074 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
2076 QFETCH(QByteArray, md5sum);
2077 QByteArray uploadedData = reply->readAll().trimmed();
2078 QCOMPARE(uploadedData, md5sum.toHex());
2081 void tst_QNetworkReply::postToHttpMultipart_data()
2083 QTest::addColumn<QUrl>("url");
2084 QTest::addColumn<QHttpMultiPart *>("multiPart");
2085 QTest::addColumn<QByteArray>("expectedReplyData");
2086 QTest::addColumn<QByteArray>("contentType");
2088 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/multipart.cgi");
2089 QByteArray expectedData;
2094 QHttpMultiPart *emptyMultiPart = new QHttpMultiPart;
2095 QTest::newRow("empty") << url << emptyMultiPart << expectedData << QByteArray("mixed");
2097 QHttpMultiPart *emptyRelatedMultiPart = new QHttpMultiPart;
2098 emptyRelatedMultiPart->setContentType(QHttpMultiPart::RelatedType);
2099 QTest::newRow("empty-related") << url << emptyRelatedMultiPart << expectedData << QByteArray("related");
2101 QHttpMultiPart *emptyAlternativeMultiPart = new QHttpMultiPart;
2102 emptyAlternativeMultiPart->setContentType(QHttpMultiPart::AlternativeType);
2103 QTest::newRow("empty-alternative") << url << emptyAlternativeMultiPart << expectedData << QByteArray("alternative");
2109 textPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain"));
2110 textPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"text\""));
2111 textPart.setBody("7 bytes");
2112 QHttpMultiPart *multiPart1 = new QHttpMultiPart;
2113 multiPart1->setContentType(QHttpMultiPart::FormDataType);
2114 multiPart1->append(textPart);
2115 expectedData = "key: text, value: 7 bytes\n";
2116 QTest::newRow("text") << url << multiPart1 << expectedData << QByteArray("form-data");
2118 QHttpMultiPart *customMultiPart = new QHttpMultiPart;
2119 customMultiPart->append(textPart);
2120 expectedData = "header: Content-Type, value: 'text/plain'\n"
2121 "header: Content-Disposition, value: 'form-data; name=\"text\"'\n"
2122 "content: 7 bytes\n"
2124 QTest::newRow("text-custom") << url << customMultiPart << expectedData << QByteArray("custom");
2126 QHttpPart textPart2;
2127 textPart2.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain"));
2128 textPart2.setRawHeader("myRawHeader", "myValue");
2129 textPart2.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"text2\""));
2130 textPart2.setBody("some more bytes");
2131 textPart2.setBodyDevice((QIODevice *) 1); // test whether setting and unsetting of the device works
2132 textPart2.setBodyDevice(0);
2133 QHttpMultiPart *multiPart2 = new QHttpMultiPart;
2134 multiPart2->setContentType(QHttpMultiPart::FormDataType);
2135 multiPart2->append(textPart);
2136 multiPart2->append(textPart2);
2137 expectedData = "key: text2, value: some more bytes\n"
2138 "key: text, value: 7 bytes\n";
2139 QTest::newRow("text-text") << url << multiPart2 << expectedData << QByteArray("form-data");
2142 QHttpPart textPart3;
2143 textPart3.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain"));
2144 textPart3.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"text3\""));
2145 textPart3.setRawHeader("Content-Location", "http://my.test.location.tld");
2146 textPart3.setBody("even more bytes");
2147 QHttpMultiPart *multiPart3 = new QHttpMultiPart;
2148 multiPart3->setContentType(QHttpMultiPart::AlternativeType);
2149 multiPart3->append(textPart);
2150 multiPart3->append(textPart2);
2151 multiPart3->append(textPart3);
2152 expectedData = "header: Content-Type, value: 'text/plain'\n"
2153 "header: Content-Disposition, value: 'form-data; name=\"text\"'\n"
2154 "content: 7 bytes\n"
2156 "header: Content-Type, value: 'text/plain'\n"
2157 "header: myRawHeader, value: 'myValue'\n"
2158 "header: Content-Disposition, value: 'form-data; name=\"text2\"'\n"
2159 "content: some more bytes\n"
2161 "header: Content-Type, value: 'text/plain'\n"
2162 "header: Content-Disposition, value: 'form-data; name=\"text3\"'\n"
2163 "header: Content-Location, value: 'http://my.test.location.tld'\n"
2164 "content: even more bytes\n\n";
2165 QTest::newRow("text-text-text") << url << multiPart3 << expectedData << QByteArray("alternative");
2169 // text and image parts
2171 QHttpPart imagePart11;
2172 imagePart11.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
2173 imagePart11.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage\""));
2174 imagePart11.setRawHeader("Content-Location", "http://my.test.location.tld");
2175 imagePart11.setRawHeader("Content-ID", "my@id.tld");
2176 QFile *file11 = new QFile(testDataDir + "/image1.jpg");
2177 file11->open(QIODevice::ReadOnly);
2178 imagePart11.setBodyDevice(file11);
2179 QHttpMultiPart *imageMultiPart1 = new QHttpMultiPart(QHttpMultiPart::FormDataType);
2180 imageMultiPart1->append(imagePart11);
2181 file11->setParent(imageMultiPart1);
2182 expectedData = "key: testImage, value: 87ef3bb319b004ba9e5e9c9fa713776e\n"; // md5 sum of file
2183 QTest::newRow("image") << url << imageMultiPart1 << expectedData << QByteArray("form-data");
2185 QHttpPart imagePart21;
2186 imagePart21.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
2187 imagePart21.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage1\""));
2188 imagePart21.setRawHeader("Content-Location", "http://my.test.location.tld");
2189 imagePart21.setRawHeader("Content-ID", "my@id.tld");
2190 QFile *file21 = new QFile(testDataDir + "/image1.jpg");
2191 file21->open(QIODevice::ReadOnly);
2192 imagePart21.setBodyDevice(file21);
2193 QHttpMultiPart *imageMultiPart2 = new QHttpMultiPart();
2194 imageMultiPart2->setContentType(QHttpMultiPart::FormDataType);
2195 imageMultiPart2->append(textPart);
2196 imageMultiPart2->append(imagePart21);
2197 file21->setParent(imageMultiPart2);
2198 QHttpPart imagePart22;
2199 imagePart22.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
2200 imagePart22.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage2\""));
2201 QFile *file22 = new QFile(testDataDir + "/image2.jpg");
2202 file22->open(QIODevice::ReadOnly);
2203 imagePart22.setBodyDevice(file22);
2204 imageMultiPart2->append(imagePart22);
2205 file22->setParent(imageMultiPart2);
2206 expectedData = "key: testImage1, value: 87ef3bb319b004ba9e5e9c9fa713776e\n"
2207 "key: text, value: 7 bytes\n"
2208 "key: testImage2, value: 483761b893f7fb1bd2414344cd1f3dfb\n";
2209 QTest::newRow("text-image-image") << url << imageMultiPart2 << expectedData << QByteArray("form-data");
2212 QHttpPart imagePart31;
2213 imagePart31.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
2214 imagePart31.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage1\""));
2215 imagePart31.setRawHeader("Content-Location", "http://my.test.location.tld");
2216 imagePart31.setRawHeader("Content-ID", "my@id.tld");
2217 QFile *file31 = new QFile(testDataDir + "/image1.jpg");
2218 file31->open(QIODevice::ReadOnly);
2219 imagePart31.setBodyDevice(file31);
2220 QHttpMultiPart *imageMultiPart3 = new QHttpMultiPart(QHttpMultiPart::FormDataType);
2221 imageMultiPart3->append(imagePart31);
2222 file31->setParent(imageMultiPart3);
2223 QHttpPart imagePart32;
2224 imagePart32.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
2225 imagePart32.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage2\""));
2226 QFile *file32 = new QFile(testDataDir + "/image2.jpg");
2227 file32->open(QIODevice::ReadOnly);
2228 imagePart32.setBodyDevice(file31); // check that resetting works
2229 imagePart32.setBodyDevice(file32);
2230 imageMultiPart3->append(imagePart32);
2231 file32->setParent(imageMultiPart3);
2232 QHttpPart imagePart33;
2233 imagePart33.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
2234 imagePart33.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage3\""));
2235 QFile *file33 = new QFile(testDataDir + "/image3.jpg");
2236 file33->open(QIODevice::ReadOnly);
2237 imagePart33.setBodyDevice(file33);
2238 imageMultiPart3->append(imagePart33);
2239 file33->setParent(imageMultiPart3);
2240 expectedData = "key: testImage1, value: 87ef3bb319b004ba9e5e9c9fa713776e\n"
2241 "key: testImage2, value: 483761b893f7fb1bd2414344cd1f3dfb\n"
2242 "key: testImage3, value: ab0eb6fd4fcf8b4436254870b4513033\n";
2243 QTest::newRow("3-images") << url << imageMultiPart3 << expectedData << QByteArray("form-data");
2246 // note: nesting multiparts is not working currently; for that, the outputDevice would need to be public
2248 // QHttpPart imagePart41;
2249 // imagePart41.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
2250 // QFile *file41 = new QFile(testDataDir + "/image1.jpg");
2251 // file41->open(QIODevice::ReadOnly);
2252 // imagePart41.setBodyDevice(file41);
2254 // QHttpMultiPart *innerMultiPart = new QHttpMultiPart();
2255 // innerMultiPart->setContentType(QHttpMultiPart::FormDataType);
2256 // textPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant());
2257 // innerMultiPart->append(textPart);
2258 // innerMultiPart->append(imagePart41);
2259 // textPart2.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant());
2260 // innerMultiPart->append(textPart2);
2262 // QHttpPart nestedPart;
2263 // nestedPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"nestedMessage"));
2264 // nestedPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("multipart/alternative; boundary=\"" + innerMultiPart->boundary() + "\""));
2265 // innerMultiPart->outputDevice()->open(QIODevice::ReadOnly);
2266 // nestedPart.setBodyDevice(innerMultiPart->outputDevice());
2268 // QHttpMultiPart *outerMultiPart = new QHttpMultiPart;
2269 // outerMultiPart->setContentType(QHttpMultiPart::FormDataType);
2270 // outerMultiPart->append(textPart);
2271 // outerMultiPart->append(nestedPart);
2272 // outerMultiPart->append(textPart2);
2273 // expectedData = "nothing"; // the CGI.pm module running on the test server does not understand nested multiparts
2274 // openFiles.clear();
2275 // openFiles << file41;
2276 // QTest::newRow("nested") << url << outerMultiPart << expectedData << openFiles;
2279 // test setting large chunks of content with a byte array instead of a device (DISCOURAGED because of high memory consumption,
2280 // but we need to test that the behavior is correct)
2281 QHttpPart imagePart51;
2282 imagePart51.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
2283 imagePart51.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage\""));
2284 QFile *file51 = new QFile(testDataDir + "/image1.jpg");
2285 file51->open(QIODevice::ReadOnly);
2286 QByteArray imageData = file51->readAll();
2289 imagePart51.setBody("7 bytes"); // check that resetting works
2290 imagePart51.setBody(imageData);
2291 QHttpMultiPart *imageMultiPart5 = new QHttpMultiPart;
2292 imageMultiPart5->setContentType(QHttpMultiPart::FormDataType);
2293 imageMultiPart5->append(imagePart51);
2294 expectedData = "key: testImage, value: 87ef3bb319b004ba9e5e9c9fa713776e\n"; // md5 sum of file
2295 QTest::newRow("image-as-content") << url << imageMultiPart5 << expectedData << QByteArray("form-data");
2298 void tst_QNetworkReply::postToHttpMultipart()
2302 static QSet<QByteArray> boundaries;
2304 QNetworkRequest request(url);
2305 QNetworkReplyPtr reply;
2307 QFETCH(QHttpMultiPart *, multiPart);
2308 QFETCH(QByteArray, expectedReplyData);
2309 QFETCH(QByteArray, contentType);
2311 // hack for testing the setting of the content-type header by hand:
2312 if (contentType == "custom") {
2313 QByteArray contentType("multipart/custom; boundary=\"" + multiPart->boundary() + "\"");
2314 request.setHeader(QNetworkRequest::ContentTypeHeader, contentType);
2317 QVERIFY2(! boundaries.contains(multiPart->boundary()), "boundary '" + multiPart->boundary() + "' has been created twice");
2318 boundaries.insert(multiPart->boundary());
2320 RUN_REQUEST(runMultipartRequest(request, reply, multiPart, "POST"));
2321 multiPart->deleteLater();
2323 QCOMPARE(reply->url(), url);
2324 QCOMPARE(reply->error(), QNetworkReply::NoError);
2326 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
2328 QVERIFY(multiPart->boundary().count() > 20); // check that there is randomness after the "boundary_.oOo._" string
2329 QVERIFY(multiPart->boundary().count() < 70);
2330 QByteArray replyData = reply->readAll();
2332 expectedReplyData.prepend("content type: multipart/" + contentType + "; boundary=\"" + multiPart->boundary() + "\"\n");
2333 // QEXPECT_FAIL("nested", "the server does not understand nested multipart messages", Continue); // see above
2334 QCOMPARE(replyData, expectedReplyData);
2337 void tst_QNetworkReply::putToHttpMultipart_data()
2339 postToHttpMultipart_data();
2342 void tst_QNetworkReply::putToHttpMultipart()
2344 QSKIP("test server script cannot handle PUT data yet");
2347 static QSet<QByteArray> boundaries;
2349 QNetworkRequest request(url);
2350 QNetworkReplyPtr reply;
2352 QFETCH(QHttpMultiPart *, multiPart);
2353 QFETCH(QByteArray, expectedReplyData);
2354 QFETCH(QByteArray, contentType);
2356 // hack for testing the setting of the content-type header by hand:
2357 if (contentType == "custom") {
2358 QByteArray contentType("multipart/custom; boundary=\"" + multiPart->boundary() + "\"");
2359 request.setHeader(QNetworkRequest::ContentTypeHeader, contentType);
2362 QVERIFY2(! boundaries.contains(multiPart->boundary()), "boundary '" + multiPart->boundary() + "' has been created twice");
2363 boundaries.insert(multiPart->boundary());
2365 RUN_REQUEST(runMultipartRequest(request, reply, multiPart, "PUT"));
2366 multiPart->deleteLater();
2368 QCOMPARE(reply->url(), url);
2369 QCOMPARE(reply->error(), QNetworkReply::NoError);
2371 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
2373 QVERIFY(multiPart->boundary().count() > 20); // check that there is randomness after the "boundary_.oOo._" string
2374 QVERIFY(multiPart->boundary().count() < 70);
2375 QByteArray replyData = reply->readAll();
2377 expectedReplyData.prepend("content type: multipart/" + contentType + "; boundary=\"" + multiPart->boundary() + "\"\n");
2378 // QEXPECT_FAIL("nested", "the server does not understand nested multipart messages", Continue); // see above
2379 QCOMPARE(replyData, expectedReplyData);
2382 void tst_QNetworkReply::deleteFromHttp_data()
2384 QTest::addColumn<QUrl>("url");
2385 QTest::addColumn<int>("resultCode");
2386 QTest::addColumn<QNetworkReply::NetworkError>("error");
2388 // for status codes to expect, see http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
2390 QTest::newRow("405-method-not-allowed") << QUrl("http://" + QtNetworkSettings::serverName() + "/index.html") << 405 << QNetworkReply::ContentOperationNotPermittedError;
2391 QTest::newRow("200-ok") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/http-delete.cgi?200-ok") << 200 << QNetworkReply::NoError;
2392 QTest::newRow("202-accepted") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/http-delete.cgi?202-accepted") << 202 << QNetworkReply::NoError;
2393 QTest::newRow("204-no-content") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/http-delete.cgi?204-no-content") << 204 << QNetworkReply::NoError;
2394 QTest::newRow("404-not-found") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/http-delete.cgi?404-not-found") << 404 << QNetworkReply::ContentNotFoundError;
2397 void tst_QNetworkReply::deleteFromHttp()
2400 QFETCH(int, resultCode);
2401 QFETCH(QNetworkReply::NetworkError, error);
2402 QNetworkRequest request(url);
2403 QNetworkReplyPtr reply;
2404 runSimpleRequest(QNetworkAccessManager::DeleteOperation, request, reply, 0);
2405 QCOMPARE(reply->url(), url);
2406 QCOMPARE(reply->error(), error);
2407 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), resultCode);
2410 void tst_QNetworkReply::putGetDeleteGetFromHttp_data()
2412 QTest::addColumn<QUrl>("putUrl");
2413 QTest::addColumn<int>("putResultCode");
2414 QTest::addColumn<QNetworkReply::NetworkError>("putError");
2415 QTest::addColumn<QUrl>("deleteUrl");
2416 QTest::addColumn<int>("deleteResultCode");
2417 QTest::addColumn<QNetworkReply::NetworkError>("deleteError");
2418 QTest::addColumn<QUrl>("get2Url");
2419 QTest::addColumn<int>("get2ResultCode");
2420 QTest::addColumn<QNetworkReply::NetworkError>("get2Error");
2422 QUrl url("http://" + QtNetworkSettings::serverName());
2423 url.setPath(QString("/dav/qnetworkaccess-putToHttp-%1-%2")
2424 .arg(QTest::currentDataTag())
2425 .arg(uniqueExtension));
2427 // first use case: put, get (to check it is there), delete, get (to check it is not there anymore)
2428 QTest::newRow("success") << url << 201 << QNetworkReply::NoError << url << 204 << QNetworkReply::NoError << url << 404 << QNetworkReply::ContentNotFoundError;
2430 QUrl wrongUrl("http://" + QtNetworkSettings::serverName());
2431 wrongUrl.setPath(QString("/dav/qnetworkaccess-thisURLisNotAvailable"));
2433 // second use case: put, get (to check it is there), delete wrong URL, get (to check it is still there)
2434 QTest::newRow("delete-error") << url << 201 << QNetworkReply::NoError << wrongUrl << 404 << QNetworkReply::ContentNotFoundError << url << 200 << QNetworkReply::NoError;
2438 void tst_QNetworkReply::putGetDeleteGetFromHttp()
2440 QFETCH(QUrl, putUrl);
2441 QFETCH(int, putResultCode);
2442 QFETCH(QNetworkReply::NetworkError, putError);
2443 QFETCH(QUrl, deleteUrl);
2444 QFETCH(int, deleteResultCode);
2445 QFETCH(QNetworkReply::NetworkError, deleteError);
2446 QFETCH(QUrl, get2Url);
2447 QFETCH(int, get2ResultCode);
2448 QFETCH(QNetworkReply::NetworkError, get2Error);
2450 QNetworkRequest putRequest(putUrl);
2451 QNetworkRequest deleteRequest(deleteUrl);
2452 QNetworkRequest get2Request(get2Url);
2453 QNetworkReplyPtr reply;
2455 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PutOperation, putRequest, reply, 0));
2456 QCOMPARE(reply->error(), putError);
2457 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), putResultCode);
2459 runSimpleRequest(QNetworkAccessManager::GetOperation, putRequest, reply, 0);
2460 QCOMPARE(reply->error(), QNetworkReply::NoError);
2461 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2463 runSimpleRequest(QNetworkAccessManager::DeleteOperation, deleteRequest, reply, 0);
2464 QCOMPARE(reply->error(), deleteError);
2465 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), deleteResultCode);
2467 runSimpleRequest(QNetworkAccessManager::GetOperation, get2Request, reply, 0);
2468 QCOMPARE(reply->error(), get2Error);
2469 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), get2ResultCode);
2473 void tst_QNetworkReply::connectToIPv6Address_data()
2475 QTest::addColumn<QUrl>("url");
2476 QTest::addColumn<QNetworkReply::NetworkError>("error");
2477 QTest::addColumn<QByteArray>("dataToSend");
2478 QTest::addColumn<QByteArray>("hostfield");
2479 QTest::newRow("localhost") << QUrl(QByteArray("http://[::1]")) << QNetworkReply::NoError<< QByteArray("localhost") << QByteArray("[::1]");
2480 //QTest::newRow("ipv4localhost") << QUrl(QByteArray("http://127.0.0.1")) << QNetworkReply::NoError<< QByteArray("ipv4localhost") << QByteArray("127.0.0.1");
2481 //to add more test data here
2484 void tst_QNetworkReply::connectToIPv6Address()
2487 QFETCH(QNetworkReply::NetworkError, error);
2488 QFETCH(QByteArray, dataToSend);
2489 QFETCH(QByteArray, hostfield);
2491 #if !defined(HAVE_IPV6) && defined(Q_OS_UNIX)
2492 QSKIP("system doesn't support ipv6!");
2495 QByteArray httpResponse = QByteArray("HTTP/1.0 200 OK\r\nContent-Length: ");
2496 httpResponse += QByteArray::number(dataToSend.size());
2497 httpResponse += "\r\n\r\n";
2498 httpResponse += dataToSend;
2500 MiniHttpServer server(httpResponse, false, NULL/*thread*/, true/*useipv6*/);
2501 server.doClose = true;
2503 url.setPort(server.serverPort());
2504 QNetworkRequest request(url);
2506 QNetworkReplyPtr reply(manager.get(request));
2507 QVERIFY(waitForFinish(reply) == Success);
2508 QByteArray content = reply->readAll();
2509 //qDebug() << server.receivedData;
2510 QByteArray hostinfo = "\r\nHost: " + hostfield + ":" + QByteArray::number(server.serverPort()) + "\r\n";
2511 QVERIFY(server.receivedData.contains(hostinfo));
2512 QVERIFY(content == dataToSend);
2513 QCOMPARE(reply->url(), request.url());
2514 QVERIFY(reply->error() == error);
2517 void tst_QNetworkReply::sendCustomRequestToHttp_data()
2519 QTest::addColumn<QUrl>("url");
2520 QTest::addColumn<QByteArray>("verb");
2521 QTest::addColumn<QBuffer *>("device");
2522 QTest::addColumn<int>("resultCode");
2523 QTest::addColumn<QNetworkReply::NetworkError>("error");
2524 QTest::addColumn<QByteArray>("expectedContent");
2526 QTest::newRow("options") << QUrl("http://" + QtNetworkSettings::serverName()) <<
2527 QByteArray("OPTIONS") << (QBuffer *) 0 << 200 << QNetworkReply::NoError << QByteArray();
2528 QTest::newRow("trace") << QUrl("http://" + QtNetworkSettings::serverName()) <<
2529 QByteArray("TRACE") << (QBuffer *) 0 << 200 << QNetworkReply::NoError << QByteArray();
2530 QTest::newRow("connect") << QUrl("http://" + QtNetworkSettings::serverName()) <<
2531 QByteArray("CONNECT") << (QBuffer *) 0 << 400 << QNetworkReply::UnknownContentError << QByteArray(); // 400 = Bad Request
2532 QTest::newRow("nonsense") << QUrl("http://" + QtNetworkSettings::serverName()) <<
2533 QByteArray("NONSENSE") << (QBuffer *) 0 << 501 << QNetworkReply::ProtocolUnknownError << QByteArray(); // 501 = Method Not Implemented
2535 QByteArray ba("test");
2536 QBuffer *buffer = new QBuffer;
2537 buffer->setData(ba);
2538 buffer->open(QIODevice::ReadOnly);
2539 QTest::newRow("post") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi") << QByteArray("POST")
2540 << buffer << 200 << QNetworkReply::NoError << QByteArray("098f6bcd4621d373cade4e832627b4f6\n");
2542 QByteArray ba2("test");
2543 QBuffer *buffer2 = new QBuffer;
2544 buffer2->setData(ba2);
2545 buffer2->open(QIODevice::ReadOnly);
2546 QTest::newRow("put") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi") << QByteArray("PUT")
2547 << buffer2 << 200 << QNetworkReply::NoError << QByteArray("098f6bcd4621d373cade4e832627b4f6\n");
2550 void tst_QNetworkReply::sendCustomRequestToHttp()
2553 QNetworkRequest request(url);
2554 QNetworkReplyPtr reply;
2555 QFETCH(QByteArray, verb);
2556 QFETCH(QBuffer *, device);
2557 runCustomRequest(request, reply, verb, device);
2558 QCOMPARE(reply->url(), url);
2559 QFETCH(QNetworkReply::NetworkError, error);
2560 QCOMPARE(reply->error(), error);
2561 QFETCH(int, resultCode);
2562 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), resultCode);
2563 QFETCH(QByteArray, expectedContent);
2564 if (! expectedContent.isEmpty())
2565 QCOMPARE(reply->readAll(), expectedContent);
2568 void tst_QNetworkReply::ioGetFromData_data()
2570 QTest::addColumn<QString>("urlStr");
2571 QTest::addColumn<QByteArray>("data");
2573 QTest::newRow("data-empty") << "data:," << QByteArray();
2574 QTest::newRow("data-literal") << "data:,foo" << QByteArray("foo");
2575 QTest::newRow("data-pct") << "data:,%3Cbody%20contentEditable%3Dtrue%3E%0D%0A"
2576 << QByteArray("<body contentEditable=true>\r\n");
2577 QTest::newRow("data-base64") << "data:;base64,UXQgaXMgZ3JlYXQh" << QByteArray("Qt is great!");
2580 void tst_QNetworkReply::ioGetFromData()
2582 QFETCH(QString, urlStr);
2584 QUrl url = QUrl::fromEncoded(urlStr.toLatin1());
2585 QNetworkRequest request(url);
2587 QNetworkReplyPtr reply(manager.get(request));
2588 DataReader reader(reply);
2590 connect(reply, SIGNAL(finished()),
2591 &QTestEventLoop::instance(), SLOT(exitLoop()));
2592 QTestEventLoop::instance().enterLoop(10);
2593 QVERIFY(!QTestEventLoop::instance().timeout());
2595 QCOMPARE(reply->url(), request.url());
2596 QCOMPARE(reply->error(), QNetworkReply::NoError);
2598 QFETCH(QByteArray, data);
2599 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toInt(), data.size());
2600 QCOMPARE(reader.data.size(), data.size());
2601 QCOMPARE(reader.data, data);
2604 void tst_QNetworkReply::ioGetFromFileSpecial_data()
2606 getFromFileSpecial_data();
2609 void tst_QNetworkReply::ioGetFromFileSpecial()
2611 QFETCH(QString, fileName);
2612 QFETCH(QString, url);
2614 QFile resource(fileName);
2615 QVERIFY(resource.open(QIODevice::ReadOnly));
2617 QNetworkRequest request;
2618 request.setUrl(url);
2619 QNetworkReplyPtr reply(manager.get(request));
2620 DataReader reader(reply);
2622 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
2623 QTestEventLoop::instance().enterLoop(10);
2624 QVERIFY(!QTestEventLoop::instance().timeout());
2626 QCOMPARE(reply->url(), request.url());
2627 QCOMPARE(reply->error(), QNetworkReply::NoError);
2629 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), resource.size());
2630 QCOMPARE(qint64(reader.data.size()), resource.size());
2631 QCOMPARE(reader.data, resource.readAll());
2634 void tst_QNetworkReply::ioGetFromFile_data()
2639 void tst_QNetworkReply::ioGetFromFile()
2641 QTemporaryFile file(QDir::currentPath() + "/temp-XXXXXX");
2642 file.setAutoRemove(true);
2643 QVERIFY(file.open());
2645 QFETCH(QByteArray, data);
2646 QVERIFY(file.write(data) == data.size());
2648 QCOMPARE(file.size(), qint64(data.size()));
2650 QNetworkRequest request(QUrl::fromLocalFile(file.fileName()));
2651 QNetworkReplyPtr reply(manager.get(request));
2652 QVERIFY(reply->isFinished()); // a file should immediately be done
2653 DataReader reader(reply);
2655 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
2656 QTestEventLoop::instance().enterLoop(10);
2657 QVERIFY(!QTestEventLoop::instance().timeout());
2659 QCOMPARE(reply->url(), request.url());
2660 QCOMPARE(reply->error(), QNetworkReply::NoError);
2662 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), file.size());
2663 QCOMPARE(qint64(reader.data.size()), file.size());
2664 QCOMPARE(reader.data, data);
2667 void tst_QNetworkReply::ioGetFromFtp_data()
2669 QTest::addColumn<QString>("fileName");
2670 QTest::addColumn<qint64>("expectedSize");
2672 QTest::newRow("bigfile") << "bigfile" << Q_INT64_C(519240);
2674 QFile file(testDataDir + "/rfc3252.txt");
2675 QTest::newRow("rfc3252.txt") << "rfc3252.txt" << file.size();
2678 void tst_QNetworkReply::ioGetFromFtp()
2680 QFETCH(QString, fileName);
2681 QFile reference(fileName);
2682 reference.open(QIODevice::ReadOnly); // will fail for bigfile
2684 QNetworkRequest request("ftp://" + QtNetworkSettings::serverName() + "/qtest/" + fileName);
2685 QNetworkReplyPtr reply(manager.get(request));
2686 DataReader reader(reply);
2688 QVERIFY(waitForFinish(reply) == Success);
2690 QCOMPARE(reply->url(), request.url());
2691 QCOMPARE(reply->error(), QNetworkReply::NoError);
2693 QFETCH(qint64, expectedSize);
2694 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), expectedSize);
2695 QCOMPARE(qint64(reader.data.size()), expectedSize);
2697 if (reference.isOpen())
2698 QCOMPARE(reader.data, reference.readAll());
2701 void tst_QNetworkReply::ioGetFromFtpWithReuse()
2703 QString fileName = testDataDir + "/rfc3252.txt";
2704 QFile reference(fileName);
2705 reference.open(QIODevice::ReadOnly);
2707 QNetworkRequest request(QUrl("ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
2709 // two concurrent (actually, consecutive) gets:
2710 QNetworkReplyPtr reply1(manager.get(request));
2711 DataReader reader1(reply1);
2712 QNetworkReplyPtr reply2(manager.get(request));
2713 DataReader reader2(reply2);
2714 QSignalSpy spy(reply1.data(), SIGNAL(finished()));
2716 QVERIFY(waitForFinish(reply1) == Success);
2717 QVERIFY(waitForFinish(reply2) == Success);
2719 QCOMPARE(reply1->url(), request.url());
2720 QCOMPARE(reply2->url(), request.url());
2721 QCOMPARE(reply1->error(), QNetworkReply::NoError);
2722 QCOMPARE(reply2->error(), QNetworkReply::NoError);
2724 QCOMPARE(qint64(reader1.data.size()), reference.size());
2725 QCOMPARE(qint64(reader2.data.size()), reference.size());
2726 QCOMPARE(reply1->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
2727 QCOMPARE(reply2->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
2729 QByteArray referenceData = reference.readAll();
2730 QCOMPARE(reader1.data, referenceData);
2731 QCOMPARE(reader2.data, referenceData);
2734 void tst_QNetworkReply::ioGetFromHttp()
2736 QFile reference(testDataDir + "/rfc3252.txt");
2737 QVERIFY(reference.open(QIODevice::ReadOnly));
2739 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
2740 QNetworkReplyPtr reply(manager.get(request));
2741 DataReader reader(reply);
2743 QVERIFY(waitForFinish(reply) == Success);
2745 QCOMPARE(reply->url(), request.url());
2746 QCOMPARE(reply->error(), QNetworkReply::NoError);
2747 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2749 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
2750 QCOMPARE(qint64(reader.data.size()), reference.size());
2752 QCOMPARE(reader.data, reference.readAll());
2755 void tst_QNetworkReply::ioGetFromHttpWithReuseParallel()
2757 QFile reference(testDataDir + "/rfc3252.txt");
2758 QVERIFY(reference.open(QIODevice::ReadOnly));
2760 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
2761 QNetworkReplyPtr reply1(manager.get(request));
2762 QNetworkReplyPtr reply2(manager.get(request));
2763 DataReader reader1(reply1);
2764 DataReader reader2(reply2);
2765 QSignalSpy spy(reply1.data(), SIGNAL(finished()));
2767 QVERIFY(waitForFinish(reply2) == Success);
2768 QVERIFY(waitForFinish(reply1) == Success);
2770 QCOMPARE(reply1->url(), request.url());
2771 QCOMPARE(reply2->url(), request.url());
2772 QCOMPARE(reply1->error(), QNetworkReply::NoError);
2773 QCOMPARE(reply2->error(), QNetworkReply::NoError);
2774 QCOMPARE(reply1->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2775 QCOMPARE(reply2->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2777 QCOMPARE(reply1->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
2778 QCOMPARE(reply2->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
2779 QCOMPARE(qint64(reader1.data.size()), reference.size());
2780 QCOMPARE(qint64(reader2.data.size()), reference.size());
2782 QByteArray referenceData = reference.readAll();
2783 QCOMPARE(reader1.data, referenceData);
2784 QCOMPARE(reader2.data, referenceData);
2787 void tst_QNetworkReply::ioGetFromHttpWithReuseSequential()
2789 QFile reference(testDataDir + "/rfc3252.txt");
2790 QVERIFY(reference.open(QIODevice::ReadOnly));
2792 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
2794 QNetworkReplyPtr reply(manager.get(request));
2795 DataReader reader(reply);
2797 QVERIFY(waitForFinish(reply) == Success);
2799 QCOMPARE(reply->url(), request.url());
2800 QCOMPARE(reply->error(), QNetworkReply::NoError);
2801 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2803 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
2804 QCOMPARE(qint64(reader.data.size()), reference.size());
2806 QCOMPARE(reader.data, reference.readAll());
2810 // rinse and repeat:
2812 QNetworkReplyPtr reply(manager.get(request));
2813 DataReader reader(reply);
2815 QVERIFY(waitForFinish(reply) == Success);
2817 QCOMPARE(reply->url(), request.url());
2818 QCOMPARE(reply->error(), QNetworkReply::NoError);
2819 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2821 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
2822 QCOMPARE(qint64(reader.data.size()), reference.size());
2824 QCOMPARE(reader.data, reference.readAll());
2828 void tst_QNetworkReply::ioGetFromHttpWithAuth_data()
2830 QTest::addColumn<QUrl>("url");
2831 QTest::addColumn<QByteArray>("expectedData");
2832 QTest::addColumn<int>("expectedAuth");
2834 QFile reference(testDataDir + "/rfc3252.txt");
2835 reference.open(QIODevice::ReadOnly);
2836 QByteArray referenceData = reference.readAll();
2837 QTest::newRow("basic") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt") << referenceData << 1;
2838 QTest::newRow("digest") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/auth-digest/") << QByteArray("digest authentication successful\n") << 1;
2839 //if url contains username & password, then it should be used
2840 QTest::newRow("basic-in-url") << QUrl("http://httptest:httptest@" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt") << referenceData << 0;
2841 QTest::newRow("digest-in-url") << QUrl("http://httptest:httptest@" + QtNetworkSettings::serverName() + "/qtest/auth-digest/") << QByteArray("digest authentication successful\n") << 0;
2842 // if url contains incorrect credentials, expect QNAM to ask for good ones (even if cached - matches behaviour of browsers)
2843 QTest::newRow("basic-bad-user-in-url") << QUrl("http://baduser:httptest@" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt") << referenceData << 3;
2844 QTest::newRow("basic-bad-password-in-url") << QUrl("http://httptest:wrong@" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt") << referenceData << 3;
2845 QTest::newRow("digest-bad-user-in-url") << QUrl("http://baduser:httptest@" + QtNetworkSettings::serverName() + "/qtest/auth-digest/") << QByteArray("digest authentication successful\n") << 3;
2846 QTest::newRow("digest-bad-password-in-url") << QUrl("http://httptest:wrong@" + QtNetworkSettings::serverName() + "/qtest/auth-digest/") << QByteArray("digest authentication successful\n") << 3;
2849 void tst_QNetworkReply::ioGetFromHttpWithAuth()
2851 // This test sends three requests
2852 // The first two in parallel
2853 // The third after the first two finished
2856 QFETCH(QByteArray, expectedData);
2857 QFETCH(int, expectedAuth);
2858 QNetworkRequest request(url);
2860 QNetworkReplyPtr reply1(manager.get(request));
2861 QNetworkReplyPtr reply2(manager.get(request));
2862 DataReader reader1(reply1);
2863 DataReader reader2(reply2);
2864 QSignalSpy finishedspy(reply1.data(), SIGNAL(finished()));
2866 QSignalSpy authspy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2867 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
2868 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2870 QVERIFY(waitForFinish(reply2) == Success);
2871 QVERIFY(waitForFinish(reply1) == Success);
2873 manager.disconnect(SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
2874 this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2876 QCOMPARE(reply1->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2877 QCOMPARE(reply2->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2878 QCOMPARE(reader1.data, expectedData);
2879 QCOMPARE(reader2.data, expectedData);
2881 QCOMPARE(authspy.count(), (expectedAuth ? 1 : 0));
2882 expectedAuth = qMax(0, expectedAuth - 1);
2885 // rinse and repeat:
2887 QNetworkReplyPtr reply(manager.get(request));
2888 DataReader reader(reply);
2890 QSignalSpy authspy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2891 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
2892 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2894 QVERIFY(waitForFinish(reply) == Success);
2896 manager.disconnect(SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
2897 this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2899 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2900 QCOMPARE(reader.data, expectedData);
2902 QCOMPARE(authspy.count(), (expectedAuth ? 1 : 0));
2903 expectedAuth = qMax(0, expectedAuth - 1);
2906 // now check with synchronous calls:
2908 request.setAttribute(
2909 QNetworkRequest::SynchronousRequestAttribute,
2912 QSignalSpy authspy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2913 QNetworkReplyPtr replySync(manager.get(request));
2914 QVERIFY(replySync->isFinished()); // synchronous
2916 // bad credentials in a synchronous request should just fail
2917 QCOMPARE(replySync->error(), QNetworkReply::AuthenticationRequiredError);
2919 QCOMPARE(authspy.count(), 0);
2921 // we cannot use a data reader here, since that connects to the readyRead signal,
2922 // just use readAll()
2924 // the only thing we check here is that the auth cache was used when using synchronous requests
2925 QCOMPARE(replySync->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2926 QCOMPARE(replySync->readAll(), expectedData);
2930 // check that credentials are used from cache if the same url is requested without credentials
2932 url.setUserInfo(QString());
2933 request.setUrl(url);
2934 request.setAttribute(
2935 QNetworkRequest::SynchronousRequestAttribute,
2938 QSignalSpy authspy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2939 QNetworkReplyPtr replySync(manager.get(request));
2940 QVERIFY(replySync->isFinished()); // synchronous
2942 // bad credentials in a synchronous request should just fail
2943 QCOMPARE(replySync->error(), QNetworkReply::AuthenticationRequiredError);
2945 QCOMPARE(authspy.count(), 0);
2947 // we cannot use a data reader here, since that connects to the readyRead signal,
2948 // just use readAll()
2950 // the only thing we check here is that the auth cache was used when using synchronous requests
2951 QCOMPARE(replySync->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
2952 QCOMPARE(replySync->readAll(), expectedData);
2957 void tst_QNetworkReply::ioGetFromHttpWithAuthSynchronous()
2959 // verify that we do not enter an endless loop with synchronous calls and wrong credentials
2960 // the case when we succeed with the login is tested in ioGetFromHttpWithAuth()
2962 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt"));
2963 request.setAttribute(
2964 QNetworkRequest::SynchronousRequestAttribute,
2967 QSignalSpy authspy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
2968 QNetworkReplyPtr replySync(manager.get(request));
2969 QVERIFY(replySync->isFinished()); // synchronous
2970 QCOMPARE(replySync->error(), QNetworkReply::AuthenticationRequiredError);
2971 QCOMPARE(authspy.count(), 0);
2972 QCOMPARE(replySync->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 401);
2975 void tst_QNetworkReply::ioGetFromHttpWithProxyAuth()
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.data(), 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 QFile reference(testDataDir + "/rfc3252.txt");
3085 QVERIFY(reference.open(QIODevice::ReadOnly));
3087 QNetworkProxy proxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080);
3088 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
3090 manager.setProxy(proxy);
3091 QNetworkReplyPtr reply(manager.get(request));
3092 DataReader reader(reply);
3093 manager.setProxy(QNetworkProxy());
3095 QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3096 connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3097 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3099 QVERIFY(waitForFinish(reply) == Success);
3101 manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3102 this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3104 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
3105 QCOMPARE(reader.data, reference.readAll());
3107 QCOMPARE(authspy.count(), 0);
3110 // set an invalid proxy just to make sure that we can't load
3111 proxy = QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1079);
3113 manager.setProxy(proxy);
3114 QNetworkReplyPtr reply(manager.get(request));
3115 DataReader reader(reply);
3116 manager.setProxy(QNetworkProxy());
3118 QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3119 connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3120 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3122 QVERIFY(waitForFinish(reply) == Failure);
3124 manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3125 this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3127 QVERIFY(!reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).isValid());
3128 QVERIFY(reader.data.isEmpty());
3130 QVERIFY(int(reply->error()) > 0);
3131 QEXPECT_FAIL("", "QTcpSocket doesn't return enough information yet", Continue);
3132 QCOMPARE(int(reply->error()), int(QNetworkReply::ProxyConnectionRefusedError));
3134 QCOMPARE(authspy.count(), 0);
3139 void tst_QNetworkReply::ioGetFromHttpsWithSslErrors()
3141 QFile reference(testDataDir + "/rfc3252.txt");
3142 QVERIFY(reference.open(QIODevice::ReadOnly));
3144 QNetworkRequest request(QUrl("https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
3145 QNetworkReplyPtr reply(manager.get(request));
3146 DataReader reader(reply);
3148 QSignalSpy sslspy(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)));
3149 connect(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
3150 SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
3151 connect(reply, SIGNAL(metaDataChanged()), SLOT(storeSslConfiguration()));
3153 QVERIFY(waitForFinish(reply) == Success);
3155 manager.disconnect(SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
3156 this, SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
3158 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
3159 QCOMPARE(reader.data, reference.readAll());
3161 QCOMPARE(sslspy.count(), 1);
3163 QVERIFY(!storedSslConfiguration.isNull());
3164 QVERIFY(!reply->sslConfiguration().isNull());
3167 void tst_QNetworkReply::ioGetFromHttpsWithIgnoreSslErrors()
3169 // same as above, except that we call ignoreSslErrors and don't connect
3170 // to the sslErrors() signal (which is *still* emitted)
3172 QFile reference(testDataDir + "/rfc3252.txt");
3173 QVERIFY(reference.open(QIODevice::ReadOnly));
3175 QNetworkRequest request(QUrl("https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
3177 QNetworkReplyPtr reply(manager.get(request));
3178 reply->ignoreSslErrors();
3179 DataReader reader(reply);
3181 QSignalSpy sslspy(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)));
3182 connect(reply, SIGNAL(metaDataChanged()), SLOT(storeSslConfiguration()));
3184 QVERIFY(waitForFinish(reply) == Success);
3186 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
3187 QCOMPARE(reader.data, reference.readAll());
3189 QCOMPARE(sslspy.count(), 1);
3191 QVERIFY(!storedSslConfiguration.isNull());
3192 QVERIFY(!reply->sslConfiguration().isNull());
3195 void tst_QNetworkReply::ioGetFromHttpsWithSslHandshakeError()
3197 QFile reference(testDataDir + "/rfc3252.txt");
3198 QVERIFY(reference.open(QIODevice::ReadOnly));
3200 QNetworkRequest request(QUrl("https://" + QtNetworkSettings::serverName() + ":80"));
3202 QNetworkReplyPtr reply(manager.get(request));
3203 reply->ignoreSslErrors();
3204 DataReader reader(reply);
3206 QSignalSpy sslspy(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)));
3207 connect(reply, SIGNAL(metaDataChanged()), SLOT(storeSslConfiguration()));
3209 QVERIFY(waitForFinish(reply) == Failure);
3211 QCOMPARE(reply->error(), QNetworkReply::SslHandshakeFailedError);
3212 QCOMPARE(sslspy.count(), 0);
3216 void tst_QNetworkReply::ioGetFromHttpBrokenServer_data()
3218 QTest::addColumn<QByteArray>("dataToSend");
3219 QTest::addColumn<bool>("doDisconnect");
3221 QTest::newRow("no-newline") << QByteArray("Hello World") << false;
3223 // these are OK now, we just eat the lonely newlines
3224 //QTest::newRow("just-newline") << QByteArray("\r\n") << false;
3225 //QTest::newRow("just-2newline") << QByteArray("\r\n\r\n") << false;
3227 QTest::newRow("with-newlines") << QByteArray("Long first line\r\nLong second line") << false;
3228 QTest::newRow("with-newlines2") << QByteArray("\r\nSecond line") << false;
3229 QTest::newRow("with-newlines3") << QByteArray("ICY\r\nSecond line") << false;
3230 QTest::newRow("invalid-version") << QByteArray("HTTP/123 200 \r\n") << false;
3231 QTest::newRow("invalid-version2") << QByteArray("HTTP/a.\033 200 \r\n") << false;
3232 QTest::newRow("invalid-reply-code") << QByteArray("HTTP/1.0 fuu \r\n") << false;
3234 QTest::newRow("empty+disconnect") << QByteArray() << true;
3236 QTest::newRow("no-newline+disconnect") << QByteArray("Hello World") << true;
3237 QTest::newRow("just-newline+disconnect") << QByteArray("\r\n") << true;
3238 QTest::newRow("just-2newline+disconnect") << QByteArray("\r\n\r\n") << true;
3239 QTest::newRow("with-newlines+disconnect") << QByteArray("Long first line\r\nLong second line") << true;
3240 QTest::newRow("with-newlines2+disconnect") << QByteArray("\r\nSecond line") << true;
3241 QTest::newRow("with-newlines3+disconnect") << QByteArray("ICY\r\nSecond line") << true;
3243 QTest::newRow("invalid-version+disconnect") << QByteArray("HTTP/123 200 ") << true;
3244 QTest::newRow("invalid-version2+disconnect") << QByteArray("HTTP/a.\033 200 ") << true;
3245 QTest::newRow("invalid-reply-code+disconnect") << QByteArray("HTTP/1.0 fuu ") << true;
3247 QTest::newRow("immediate disconnect") << QByteArray("") << true;
3248 QTest::newRow("justHalfStatus+disconnect") << QByteArray("HTTP/1.1") << true;
3249 QTest::newRow("justStatus+disconnect") << QByteArray("HTTP/1.1 200 OK\r\n") << true;
3250 QTest::newRow("justStatusAndHalfHeaders+disconnect") << QByteArray("HTTP/1.1 200 OK\r\nContent-L") << true;
3252 QTest::newRow("halfContent+disconnect") << QByteArray("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\nAB") << true;
3256 void tst_QNetworkReply::ioGetFromHttpBrokenServer()
3258 QFETCH(QByteArray, dataToSend);
3259 QFETCH(bool, doDisconnect);
3260 MiniHttpServer server(dataToSend);
3261 server.doClose = doDisconnect;
3263 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
3264 QNetworkReplyPtr reply(manager.get(request));
3265 QSignalSpy spy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError)));
3267 QVERIFY(waitForFinish(reply) == Failure);
3269 QCOMPARE(reply->url(), request.url());
3270 QCOMPARE(spy.count(), 1);
3271 QVERIFY(reply->error() != QNetworkReply::NoError);
3274 void tst_QNetworkReply::ioGetFromHttpStatus100_data()
3276 QTest::addColumn<QByteArray>("dataToSend");
3277 QTest::addColumn<int>("statusCode");
3278 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;
3279 QTest::newRow("minimal") << QByteArray("HTTP/1.1 100 Continue\n\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") << 200;
3280 QTest::newRow("minimal2") << QByteArray("HTTP/1.1 100 Continue\n\nHTTP/1.0 200 OK\r\n\r\n") << 200;
3281 QTest::newRow("minimal3") << QByteArray("HTTP/1.1 100 Continue\n\nHTTP/1.0 200 OK\n\n") << 200;
3282 QTest::newRow("minimal+404") << QByteArray("HTTP/1.1 100 Continue\n\nHTTP/1.0 204 No Content\r\n\r\n") << 204;
3283 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;
3284 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;
3287 void tst_QNetworkReply::ioGetFromHttpStatus100()
3289 QFETCH(QByteArray, dataToSend);
3290 QFETCH(int, statusCode);
3291 MiniHttpServer server(dataToSend);
3292 server.doClose = true;
3294 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
3295 QNetworkReplyPtr reply(manager.get(request));
3297 QVERIFY(waitForFinish(reply) == Success);
3299 QCOMPARE(reply->url(), request.url());
3300 QCOMPARE(reply->error(), QNetworkReply::NoError);
3301 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), statusCode);
3302 QVERIFY(reply->rawHeader("bla").isNull());
3305 void tst_QNetworkReply::ioGetFromHttpNoHeaders_data()
3307 QTest::addColumn<QByteArray>("dataToSend");
3308 QTest::newRow("justStatus+noheaders+disconnect") << QByteArray("HTTP/1.0 200 OK\r\n\r\n");
3311 void tst_QNetworkReply::ioGetFromHttpNoHeaders()
3313 QFETCH(QByteArray, dataToSend);
3314 MiniHttpServer server(dataToSend);
3315 server.doClose = true;
3317 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
3318 QNetworkReplyPtr reply(manager.get(request));
3320 QVERIFY(waitForFinish(reply) == Success);
3322 QCOMPARE(reply->url(), request.url());
3323 QCOMPARE(reply->error(), QNetworkReply::NoError);
3324 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
3327 void tst_QNetworkReply::ioGetFromHttpWithCache_data()
3329 qRegisterMetaType<MyMemoryCache::CachedContent>();
3330 QTest::addColumn<QByteArray>("dataToSend");
3331 QTest::addColumn<QString>("body");
3332 QTest::addColumn<MyMemoryCache::CachedContent>("cachedReply");
3333 QTest::addColumn<int>("cacheMode");
3334 QTest::addColumn<QStringList>("extraHttpHeaders");
3335 QTest::addColumn<bool>("loadedFromCache");
3336 QTest::addColumn<bool>("networkUsed");
3338 QByteArray reply200 =
3340 "Connection: keep-alive\r\n"
3341 "Content-Type: text/plain\r\n"
3342 "Cache-control: no-cache\r\n"
3343 "Content-length: 8\r\n"
3346 QByteArray reply304 =
3347 "HTTP/1.0 304 Use Cache\r\n"
3348 "Connection: keep-alive\r\n"
3351 QTest::newRow("not-cached,always-network")
3352 << reply200 << "Reloaded" << MyMemoryCache::CachedContent() << int(QNetworkRequest::AlwaysNetwork) << QStringList() << false << true;
3353 QTest::newRow("not-cached,prefer-network")
3354 << reply200 << "Reloaded" << MyMemoryCache::CachedContent() << int(QNetworkRequest::PreferNetwork) << QStringList() << false << true;
3355 QTest::newRow("not-cached,prefer-cache")
3356 << reply200 << "Reloaded" << MyMemoryCache::CachedContent() << int(QNetworkRequest::PreferCache) << QStringList() << false << true;
3358 QDateTime present = QDateTime::currentDateTime().toUTC();
3359 QDateTime past = present.addSecs(-3600);
3360 QDateTime future = present.addSecs(3600);
3361 static const char dateFormat[] = "ddd, dd MMM yyyy hh:mm:ss 'GMT'";
3363 QNetworkCacheMetaData::RawHeaderList rawHeaders;
3364 MyMemoryCache::CachedContent content;
3365 content.second = "Not-reloaded";
3366 content.first.setLastModified(past);
3372 rawHeaders << QNetworkCacheMetaData::RawHeader("Date", QLocale::c().toString(past, dateFormat).toLatin1())
3373 << QNetworkCacheMetaData::RawHeader("Cache-control", "max-age=0"); // isn't used in cache loading
3374 content.first.setRawHeaders(rawHeaders);
3375 content.first.setLastModified(past);
3376 content.first.setExpirationDate(past);
3378 QTest::newRow("expired,200,prefer-network")
3379 << reply200 << "Reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << false << true;
3380 QTest::newRow("expired,200,prefer-cache")
3381 << reply200 << "Reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << false << true;
3383 QTest::newRow("expired,304,prefer-network")
3384 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << true << true;
3385 QTest::newRow("expired,304,prefer-cache")
3386 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << true << true;
3389 // Set to not-expired
3392 rawHeaders << QNetworkCacheMetaData::RawHeader("Date", QLocale::c().toString(past, dateFormat).toLatin1())
3393 << QNetworkCacheMetaData::RawHeader("Cache-control", "max-age=7200"); // isn't used in cache loading
3394 content.first.setRawHeaders(rawHeaders);
3395 content.first.setExpirationDate(future);
3397 QTest::newRow("not-expired,200,always-network")
3398 << reply200 << "Reloaded" << content << int(QNetworkRequest::AlwaysNetwork) << QStringList() << false << true;
3399 QTest::newRow("not-expired,200,prefer-network")
3400 << reply200 << "Not-reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << true << false;
3401 QTest::newRow("not-expired,200,prefer-cache")
3402 << reply200 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << true << false;
3403 QTest::newRow("not-expired,200,always-cache")
3404 << reply200 << "Not-reloaded" << content << int(QNetworkRequest::AlwaysCache) << QStringList() << true << false;
3406 QTest::newRow("not-expired,304,prefer-network")
3407 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << true << false;
3408 QTest::newRow("not-expired,304,prefer-cache")
3409 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << true << false;
3410 QTest::newRow("not-expired,304,always-cache")
3411 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::AlwaysCache) << QStringList() << true << false;
3414 // Set must-revalidate now
3417 rawHeaders << QNetworkCacheMetaData::RawHeader("Date", QLocale::c().toString(past, dateFormat).toLatin1())
3418 << QNetworkCacheMetaData::RawHeader("Cache-control", "max-age=7200, must-revalidate"); // must-revalidate is used
3419 content.first.setRawHeaders(rawHeaders);
3421 QTest::newRow("must-revalidate,200,always-network")
3422 << reply200 << "Reloaded" << content << int(QNetworkRequest::AlwaysNetwork) << QStringList() << false << true;
3423 QTest::newRow("must-revalidate,200,prefer-network")
3424 << reply200 << "Reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << false << true;
3425 QTest::newRow("must-revalidate,200,prefer-cache")
3426 << reply200 << "Reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << false << true;
3427 QTest::newRow("must-revalidate,200,always-cache")
3428 << reply200 << "" << content << int(QNetworkRequest::AlwaysCache) << QStringList() << false << false;
3430 QTest::newRow("must-revalidate,304,prefer-network")
3431 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << true << true;
3432 QTest::newRow("must-revalidate,304,prefer-cache")
3433 << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << true << true;
3434 QTest::newRow("must-revalidate,304,always-cache")
3435 << reply304 << "" << content << int(QNetworkRequest::AlwaysCache) << QStringList() << false << false;
3441 rawHeaders << QNetworkCacheMetaData::RawHeader("Date", QLocale::c().toString(past, dateFormat).toLatin1())
3442 << QNetworkCacheMetaData::RawHeader("Cache-control", "max-age=7200"); // isn't used in cache loading
3443 content.first.setRawHeaders(rawHeaders);
3444 content.first.setExpirationDate(future);
3446 QByteArray reply206 =
3448 "Connection: keep-alive\r\n"
3449 "Content-Type: text/plain\r\n"
3450 "Cache-control: no-cache\r\n"
3451 "Content-Range: bytes 2-6/8\r\n"
3452 "Content-length: 4\r\n"
3456 QTest::newRow("partial,dontuse-cache")
3457 << reply206 << "load" << content << int(QNetworkRequest::PreferCache) << (QStringList() << "Range" << "bytes=2-6") << false << true;
3460 void tst_QNetworkReply::ioGetFromHttpWithCache()
3462 QFETCH(QByteArray, dataToSend);
3463 MiniHttpServer server(dataToSend);
3464 server.doClose = false;
3466 MyMemoryCache *memoryCache = new MyMemoryCache(&manager);
3467 manager.setCache(memoryCache);
3469 QFETCH(MyMemoryCache::CachedContent, cachedReply);
3470 QUrl url = "http://localhost:" + QString::number(server.serverPort());
3471 cachedReply.first.setUrl(url);
3472 if (!cachedReply.second.isNull())
3473 memoryCache->cache.insert(url.toEncoded(), cachedReply);
3475 QFETCH(int, cacheMode);
3476 QNetworkRequest request(url);
3477 request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, cacheMode);
3478 request.setAttribute(QNetworkRequest::CacheSaveControlAttribute, false);
3480 QFETCH(QStringList, extraHttpHeaders);
3481 QStringListIterator it(extraHttpHeaders);
3482 while (it.hasNext()) {
3483 QString header = it.next();
3484 QString value = it.next();
3485 request.setRawHeader(header.toLatin1(), value.toLatin1()); // To latin1? Deal with it!
3488 QNetworkReplyPtr reply(manager.get(request));
3490 QVERIFY(waitForFinish(reply) != Timeout);
3492 QTEST(reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool(), "loadedFromCache");
3493 QTEST(server.totalConnections > 0, "networkUsed");
3494 QFETCH(QString, body);
3495 QCOMPARE(reply->readAll().constData(), qPrintable(body));
3498 void tst_QNetworkReply::ioGetWithManyProxies_data()
3500 QTest::addColumn<QList<QNetworkProxy> >("proxyList");
3501 QTest::addColumn<QNetworkProxy>("proxyUsed");
3502 QTest::addColumn<QString>("url");
3503 QTest::addColumn<QNetworkReply::NetworkError>("expectedError");
3505 QList<QNetworkProxy> proxyList;
3507 // All of the other functions test DefaultProxy
3508 // So let's test something else
3510 // Simple tests that work:
3512 // HTTP request with HTTP caching proxy
3513 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129);
3514 QTest::newRow("http-on-http")
3515 << proxyList << proxyList.at(0)
3516 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3517 << QNetworkReply::NoError;
3519 // HTTP request with HTTP transparent proxy
3521 proxyList << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3129);
3522 QTest::newRow("http-on-http2")
3523 << proxyList << proxyList.at(0)
3524 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3525 << QNetworkReply::NoError;
3527 // HTTP request with SOCKS transparent proxy
3529 proxyList << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081);
3530 QTest::newRow("http-on-socks")
3531 << proxyList << proxyList.at(0)
3532 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3533 << QNetworkReply::NoError;
3535 // FTP request with FTP caching proxy
3537 proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121);
3538 QTest::newRow("ftp-on-ftp")
3539 << proxyList << proxyList.at(0)
3540 << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3541 << QNetworkReply::NoError;
3543 // The following test doesn't work because QFtp is too limited
3544 // It can only talk to its own kind of proxies
3546 // FTP request with SOCKSv5 transparent proxy
3548 proxyList << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081);
3549 QTest::newRow("ftp-on-socks")
3550 << proxyList << proxyList.at(0)
3551 << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3552 << QNetworkReply::NoError;
3555 // HTTPS with HTTP transparent proxy
3557 proxyList << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3129);
3558 QTest::newRow("https-on-http")
3559 << proxyList << proxyList.at(0)
3560 << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3561 << QNetworkReply::NoError;
3563 // HTTPS request with SOCKS transparent proxy
3565 proxyList << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081);
3566 QTest::newRow("https-on-socks")
3567 << proxyList << proxyList.at(0)
3568 << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3569 << QNetworkReply::NoError;
3574 // HTTP request with FTP caching proxy
3576 proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121);
3577 QTest::newRow("http-on-ftp")
3578 << proxyList << QNetworkProxy()
3579 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3580 << QNetworkReply::ProxyNotFoundError;
3582 // FTP request with HTTP caching proxy
3584 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129);
3585 QTest::newRow("ftp-on-http")
3586 << proxyList << QNetworkProxy()
3587 << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3588 << QNetworkReply::ProxyNotFoundError;
3590 // FTP request with HTTP caching proxies
3592 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
3593 << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3130);
3594 QTest::newRow("ftp-on-multiple-http")
3595 << proxyList << QNetworkProxy()
3596 << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3597 << QNetworkReply::ProxyNotFoundError;
3600 // HTTPS with HTTP caching proxy
3602 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129);
3603 QTest::newRow("https-on-httptransparent")
3604 << proxyList << QNetworkProxy()
3605 << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3606 << QNetworkReply::ProxyNotFoundError;
3608 // HTTPS with FTP caching proxy
3610 proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121);
3611 QTest::newRow("https-on-ftp")
3612 << proxyList << QNetworkProxy()
3613 << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3614 << QNetworkReply::ProxyNotFoundError;
3617 // Complex requests:
3619 // HTTP request with more than one HTTP proxy
3621 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
3622 << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3130);
3623 QTest::newRow("http-on-multiple-http")
3624 << proxyList << proxyList.at(0)
3625 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3626 << QNetworkReply::NoError;
3628 // HTTP request with HTTP + SOCKS
3630 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
3631 << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081);
3632 QTest::newRow("http-on-http+socks")
3633 << proxyList << proxyList.at(0)
3634 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3635 << QNetworkReply::NoError;
3637 // HTTP request with FTP + HTTP + SOCKS
3639 proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121)
3640 << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
3641 << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081);
3642 QTest::newRow("http-on-ftp+http+socks")
3643 << proxyList << proxyList.at(1) // second proxy should be used
3644 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3645 << QNetworkReply::NoError;
3647 // HTTP request with NoProxy + HTTP
3649 proxyList << QNetworkProxy(QNetworkProxy::NoProxy)
3650 << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129);
3651 QTest::newRow("http-on-noproxy+http")
3652 << proxyList << proxyList.at(0)
3653 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3654 << QNetworkReply::NoError;
3656 // HTTP request with FTP + NoProxy
3658 proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121)
3659 << QNetworkProxy(QNetworkProxy::NoProxy);
3660 QTest::newRow("http-on-ftp+noproxy")
3661 << proxyList << proxyList.at(1) // second proxy should be used
3662 << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3663 << QNetworkReply::NoError;
3665 // FTP request with HTTP Caching + FTP
3667 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
3668 << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121);
3669 QTest::newRow("ftp-on-http+ftp")
3670 << proxyList << proxyList.at(1) // second proxy should be used
3671 << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3672 << QNetworkReply::NoError;
3675 // HTTPS request with HTTP Caching + HTTP transparent
3677 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
3678 << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3129);
3679 QTest::newRow("https-on-httpcaching+http")
3680 << proxyList << proxyList.at(1) // second proxy should be used
3681 << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3682 << QNetworkReply::NoError;
3684 // HTTPS request with FTP + HTTP C + HTTP T
3686 proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121)
3687 << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
3688 << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3129);
3689 QTest::newRow("https-on-ftp+httpcaching+http")
3690 << proxyList << proxyList.at(2) // skip the first two
3691 << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
3692 << QNetworkReply::NoError;
3696 void tst_QNetworkReply::ioGetWithManyProxies()
3698 // Test proxy factories
3700 QFile reference(testDataDir + "/rfc3252.txt");
3701 QVERIFY(reference.open(QIODevice::ReadOnly));
3703 // set the proxy factory:
3704 QFETCH(QList<QNetworkProxy>, proxyList);
3705 MyProxyFactory *proxyFactory = new MyProxyFactory;
3706 proxyFactory->toReturn = proxyList;
3707 manager.setProxyFactory(proxyFactory);
3709 QFETCH(QString, url);
3711 QNetworkRequest request(theUrl);
3712 QNetworkReplyPtr reply(manager.get(request));
3713 DataReader reader(reply);
3715 QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3716 connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3717 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3719 connect(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
3720 SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
3723 QVERIFY(waitForFinish(reply) != Timeout);
3725 manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3726 this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3728 manager.disconnect(SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
3729 this, SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
3732 QFETCH(QNetworkReply::NetworkError, expectedError);
3733 QEXPECT_FAIL("ftp-on-socks", "QFtp is too limited and won't accept non-FTP proxies", Abort);
3734 QCOMPARE(reply->error(), expectedError);
3736 // Verify that the factory was called properly
3737 QCOMPARE(proxyFactory->callCount, 1);
3738 QCOMPARE(proxyFactory->lastQuery, QNetworkProxyQuery(theUrl));
3740 if (expectedError == QNetworkReply::NoError) {
3741 // request succeeded
3742 QCOMPARE(reader.data, reference.readAll());
3744 // now verify that the proxies worked:
3745 QFETCH(QNetworkProxy, proxyUsed);
3746 if (proxyUsed.type() == QNetworkProxy::NoProxy) {
3747 QCOMPARE(authspy.count(), 0);
3749 if (QByteArray(QTest::currentDataTag()).startsWith("ftp-"))
3750 return; // No authentication with current FTP or with FTP proxies
3751 QCOMPARE(authspy.count(), 1);
3752 QCOMPARE(qvariant_cast<QNetworkProxy>(authspy.at(0).at(0)), proxyUsed);
3756 QCOMPARE(authspy.count(), 0);
3760 void tst_QNetworkReply::ioPutToFileFromFile_data()
3762 QTest::addColumn<QString>("fileName");
3764 QTest::newRow("empty") << (testDataDir + "/empty");
3765 QTest::newRow("real-file") << (testDataDir + "/rfc3252.txt");
3766 QTest::newRow("resource") << ":/resource";
3767 QTest::newRow("search-path") << "testdata:/rfc3252.txt";
3770 void tst_QNetworkReply::ioPutToFileFromFile()
3772 QFETCH(QString, fileName);
3773 QFile sourceFile(fileName);
3774 QFile targetFile(testFileName);
3776 QVERIFY(sourceFile.open(QIODevice::ReadOnly));
3778 QUrl url = QUrl::fromLocalFile(targetFile.fileName());
3779 QNetworkRequest request(url);
3780 QNetworkReplyPtr reply(manager.put(request, &sourceFile));
3782 QVERIFY(waitForFinish(reply) == Success);
3784 QCOMPARE(reply->url(), url);
3785 QCOMPARE(reply->error(), QNetworkReply::NoError);
3786 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
3787 QVERIFY(reply->readAll().isEmpty());
3789 QVERIFY(sourceFile.atEnd());
3790 sourceFile.seek(0); // reset it to the beginning
3792 QVERIFY(targetFile.open(QIODevice::ReadOnly));
3793 QCOMPARE(targetFile.size(), sourceFile.size());
3794 QCOMPARE(targetFile.readAll(), sourceFile.readAll());
3797 void tst_QNetworkReply::ioPutToFileFromSocket_data()
3802 void tst_QNetworkReply::ioPutToFileFromSocket()
3804 QFile file(testFileName);
3806 QUrl url = QUrl::fromLocalFile(file.fileName());
3807 QNetworkRequest request(url);
3809 QFETCH(QByteArray, data);
3810 SocketPair socketpair;
3811 socketpair.create();
3812 QVERIFY(socketpair.endPoints[0] && socketpair.endPoints[1]);
3814 socketpair.endPoints[0]->write(data);
3815 QNetworkReplyPtr reply(manager.put(QNetworkRequest(url), socketpair.endPoints[1]));
3816 socketpair.endPoints[0]->close();
3818 QVERIFY(waitForFinish(reply) == Success);
3819 QCOMPARE(reply->error(), QNetworkReply::NoError);
3821 QCOMPARE(reply->url(), url);
3822 QCOMPARE(reply->error(), QNetworkReply::NoError);
3823 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
3824 QVERIFY(reply->readAll().isEmpty());
3826 QVERIFY(file.open(QIODevice::ReadOnly));
3827 QCOMPARE(file.size(), qint64(data.size()));
3828 QByteArray contents = file.readAll();
3829 QCOMPARE(contents, data);
3832 void tst_QNetworkReply::ioPutToFileFromLocalSocket_data()
3837 void tst_QNetworkReply::ioPutToFileFromLocalSocket()
3839 QString socketname = "networkreplytest";
3840 QLocalServer server;
3841 if (!server.listen(socketname)) {
3842 QLocalServer::removeServer(socketname);
3843 QVERIFY(server.listen(socketname));
3845 QLocalSocket active;
3846 active.connectToServer(socketname);
3847 QVERIFY2(server.waitForNewConnection(10), server.errorString().toLatin1().constData());
3848 QVERIFY2(active.waitForConnected(10), active.errorString().toLatin1().constData());
3849 QVERIFY2(server.hasPendingConnections(), server.errorString().toLatin1().constData());
3850 QLocalSocket *passive = server.nextPendingConnection();
3852 QFile file(testFileName);
3853 QUrl url = QUrl::fromLocalFile(file.fileName());
3854 QNetworkRequest request(url);
3856 QFETCH(QByteArray, data);
3859 QNetworkReplyPtr reply(manager.put(QNetworkRequest(url), passive));
3860 passive->setParent(reply.data());
3863 if (!data.isEmpty())
3864 QEXPECT_FAIL("", "QTBUG-18385", Abort);
3866 QVERIFY(waitForFinish(reply) == Success);
3867 QCOMPARE(reply->error(), QNetworkReply::NoError);
3869 QCOMPARE(reply->url(), url);
3870 QCOMPARE(reply->error(), QNetworkReply::NoError);
3871 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
3872 QVERIFY(reply->readAll().isEmpty());
3874 QVERIFY(file.open(QIODevice::ReadOnly));
3875 QCOMPARE(file.size(), qint64(data.size()));
3876 QByteArray contents = file.readAll();
3877 QCOMPARE(contents, data);
3880 // Currently no stdin/out supported for Windows CE.
3881 #ifndef QT_NO_PROCESS
3882 void tst_QNetworkReply::ioPutToFileFromProcess_data()
3887 void tst_QNetworkReply::ioPutToFileFromProcess()
3889 #if defined(Q_OS_WINCE)
3890 QSKIP("Currently no stdin/out supported for Windows CE");
3893 if (qstrcmp(QTest::currentDataTag(), "small") == 0)
3894 QSKIP("When passing a CR-LF-LF sequence through Windows stdio, it gets converted, "
3895 "so this test fails. Disabled on Windows");
3898 QFile file(testFileName);
3900 QUrl url = QUrl::fromLocalFile(file.fileName());
3901 QNetworkRequest request(url);
3903 QFETCH(QByteArray, data);
3905 QString echoExe = echoProcessDir + "/echo";
3906 process.start(echoExe, QStringList("all"));
3907 QVERIFY2(process.waitForStarted(), qPrintable(
3908 QString::fromLatin1("Could not start %1: %2").arg(echoExe, process.errorString())));
3909 process.write(data);
3910 process.closeWriteChannel();
3912 QNetworkReplyPtr reply(manager.put(QNetworkRequest(url), &process));
3914 QVERIFY(waitForFinish(reply) == Success);
3916 QCOMPARE(reply->url(), url);
3917 QCOMPARE(reply->error(), QNetworkReply::NoError);
3918 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
3919 QVERIFY(reply->readAll().isEmpty());
3921 QVERIFY(file.open(QIODevice::ReadOnly));
3922 QCOMPARE(file.size(), qint64(data.size()));
3923 QByteArray contents = file.readAll();
3924 QCOMPARE(contents, data);
3929 void tst_QNetworkReply::ioPutToFtpFromFile_data()
3931 ioPutToFileFromFile_data();
3934 void tst_QNetworkReply::ioPutToFtpFromFile()
3936 QFETCH(QString, fileName);
3937 QFile sourceFile(fileName);
3938 QVERIFY(sourceFile.open(QIODevice::ReadOnly));
3940 QUrl url("ftp://" + QtNetworkSettings::serverName());
3941 url.setPath(QString("/qtest/upload/qnetworkaccess-ioPutToFtpFromFile-%1-%2")
3942 .arg(QTest::currentDataTag())
3943 .arg(uniqueExtension));
3945 QNetworkRequest request(url);
3946 QNetworkReplyPtr reply(manager.put(request, &sourceFile));
3948 QVERIFY(waitForFinish(reply) == Success);
3950 QCOMPARE(reply->url(), url);
3951 QCOMPARE(reply->error(), QNetworkReply::NoError);
3952 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
3953 QVERIFY(reply->readAll().isEmpty());
3955 QVERIFY(sourceFile.atEnd());
3956 sourceFile.seek(0); // reset it to the beginning
3958 // download the file again from FTP to make sure it was uploaded
3960 QNetworkAccessManager qnam;
3961 QNetworkRequest req(url);
3962 QNetworkReply *r = qnam.get(req);
3964 QObject::connect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
3965 QTestEventLoop::instance().enterLoop(3);
3966 QObject::disconnect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
3968 QByteArray uploaded = r->readAll();
3969 QCOMPARE(qint64(uploaded.size()), sourceFile.size());
3970 QCOMPARE(uploaded, sourceFile.readAll());
3973 QObject::connect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
3974 QTestEventLoop::instance().enterLoop(10);
3975 QObject::disconnect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
3978 void tst_QNetworkReply::ioPutToHttpFromFile_data()
3980 ioPutToFileFromFile_data();
3983 void tst_QNetworkReply::ioPutToHttpFromFile()
3985 QFETCH(QString, fileName);
3986 QFile sourceFile(fileName);
3987 QVERIFY(sourceFile.open(QIODevice::ReadOnly));
3989 QUrl url("http://" + QtNetworkSettings::serverName());
3990 url.setPath(QString("/dav/qnetworkaccess-ioPutToHttpFromFile-%1-%2")
3991 .arg(QTest::currentDataTag())
3992 .arg(uniqueExtension));
3994 QNetworkRequest request(url);
3995 QNetworkReplyPtr reply(manager.put(request, &sourceFile));
3997 QVERIFY(waitForFinish(reply) == Success);
3999 QCOMPARE(reply->url(), url);
4000 QCOMPARE(reply->error(), QNetworkReply::NoError);
4002 // verify that the HTTP status code is 201 Created
4003 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 201);
4005 QVERIFY(sourceFile.atEnd());
4006 sourceFile.seek(0); // reset it to the beginning
4008 // download the file again from HTTP to make sure it was uploaded
4010 reply.reset(manager.get(request));
4012 QVERIFY(waitForFinish(reply) == Success);
4014 QCOMPARE(reply->url(), url);
4015 QCOMPARE(reply->error(), QNetworkReply::NoError);
4016 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
4018 QCOMPARE(reply->readAll(), sourceFile.readAll());
4021 void tst_QNetworkReply::ioPostToHttpFromFile_data()
4023 ioPutToFileFromFile_data();
4026 void tst_QNetworkReply::ioPostToHttpFromFile()
4028 QFETCH(QString, fileName);
4029 QFile sourceFile(fileName);
4030 QVERIFY(sourceFile.open(QIODevice::ReadOnly));
4032 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi");
4033 QNetworkRequest request(url);
4034 request.setRawHeader("Content-Type", "application/octet-stream");
4036 QNetworkReplyPtr reply(manager.post(request, &sourceFile));
4038 QVERIFY(waitForFinish(reply) == Success);
4040 QCOMPARE(reply->url(), url);
4041 QCOMPARE(reply->error(), QNetworkReply::NoError);
4043 // verify that the HTTP status code is 200 Ok
4044 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
4046 QVERIFY(sourceFile.atEnd());
4047 sourceFile.seek(0); // reset it to the beginning
4049 QCOMPARE(reply->readAll().trimmed(), md5sum(sourceFile.readAll()).toHex());
4052 void tst_QNetworkReply::ioPostToHttpFromSocket_data()
4054 QTest::addColumn<QByteArray>("data");
4055 QTest::addColumn<QByteArray>("md5sum");
4056 QTest::addColumn<QUrl>("url");
4057 QTest::addColumn<QNetworkProxy>("proxy");
4058 QTest::addColumn<int>("authenticationRequiredCount");
4059 QTest::addColumn<int>("proxyAuthenticationRequiredCount");
4061 for (int i = 0; i < proxies.count(); ++i)
4062 for (int auth = 0; auth < 2; ++auth) {
4065 url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi";
4067 url = "http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi";
4069 QNetworkProxy proxy = proxies.at(i).proxy;
4070 QByteArray testsuffix = QByteArray(auth ? "+auth" : "") + proxies.at(i).tag;
4071 int proxyauthcount = proxies.at(i).requiresAuthentication;
4075 QTest::newRow("empty" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount;
4077 data = "This is a normal message.";
4078 QTest::newRow("generic" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount;
4080 data = "This is a message to show that Qt rocks!\r\n\n";
4081 QTest::newRow("small" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount;
4083 data = QByteArray("abcd\0\1\2\abcd",12);
4084 QTest::newRow("with-nul" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount;
4086 data = QByteArray(4097, '\4');
4087 QTest::newRow("4k+1" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount;
4089 data = QByteArray(128*1024+1, '\177');
4090 QTest::newRow("128k+1" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount;
4094 void tst_QNetworkReply::ioPostToHttpFromSocket()
4096 QFETCH(QByteArray, data);
4098 QFETCH(QNetworkProxy, proxy);
4099 SocketPair socketpair;
4100 socketpair.create();
4101 QVERIFY(socketpair.endPoints[0] && socketpair.endPoints[1]);
4103 socketpair.endPoints[0]->write(data);
4105 QNetworkRequest request(url);
4106 request.setRawHeader("Content-Type", "application/octet-stream");
4108 manager.setProxy(proxy);
4109 QNetworkReplyPtr reply(manager.post(request, socketpair.endPoints[1]));
4110 socketpair.endPoints[0]->close();
4112 connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
4113 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
4114 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4115 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4117 QSignalSpy authenticationRequiredSpy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4118 QSignalSpy proxyAuthenticationRequiredSpy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
4120 QVERIFY(waitForFinish(reply) == Success);
4122 disconnect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
4123 this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
4124 disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4125 this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4126 QCOMPARE(reply->error(), QNetworkReply::NoError);
4128 QCOMPARE(reply->url(), url);
4129 QCOMPARE(reply->error(), QNetworkReply::NoError);
4130 // verify that the HTTP status code is 200 Ok
4131 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
4133 QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex());
4135 QTEST(authenticationRequiredSpy.count(), "authenticationRequiredCount");
4136 QTEST(proxyAuthenticationRequiredSpy.count(), "proxyAuthenticationRequiredCount");
4139 void tst_QNetworkReply::ioPostToHttpFromSocketSynchronous_data()
4141 QTest::addColumn<QByteArray>("data");
4142 QTest::addColumn<QByteArray>("md5sum");
4146 QTest::newRow("empty") << data << md5sum(data);
4148 data = "This is a normal message.";
4149 QTest::newRow("generic") << data << md5sum(data);
4151 data = "This is a message to show that Qt rocks!\r\n\n";
4152 QTest::newRow("small") << data << md5sum(data);
4154 data = QByteArray("abcd\0\1\2\abcd",12);
4155 QTest::newRow("with-nul") << data << md5sum(data);
4157 data = QByteArray(4097, '\4');
4158 QTest::newRow("4k+1") << data << md5sum(data);
4160 data = QByteArray(128*1024+1, '\177');
4161 QTest::newRow("128k+1") << data << md5sum(data);
4163 data = QByteArray(2*1024*1024+1, '\177');
4164 QTest::newRow("2MB+1") << data << md5sum(data);
4167 void tst_QNetworkReply::ioPostToHttpFromSocketSynchronous()
4169 QFETCH(QByteArray, data);
4171 SocketPair socketpair;
4172 QVERIFY(socketpair.create());
4173 QVERIFY(socketpair.endPoints[0] && socketpair.endPoints[1]);
4174 socketpair.endPoints[0]->write(data);
4175 socketpair.endPoints[0]->waitForBytesWritten(5000);
4176 // ### for 4.8: make the socket pair unbuffered, to not read everything in one go in QNetworkReplyImplPrivate::setup()
4177 QTestEventLoop::instance().enterLoop(3);
4179 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi");
4180 QNetworkRequest request(url);
4181 request.setRawHeader("Content-Type", "application/octet-stream");
4182 request.setAttribute(
4183 QNetworkRequest::SynchronousRequestAttribute,
4186 QNetworkReplyPtr reply(manager.post(request, socketpair.endPoints[1]));
4187 QVERIFY(reply->isFinished());
4188 socketpair.endPoints[0]->close();
4190 QCOMPARE(reply->error(), QNetworkReply::NoError);
4192 QCOMPARE(reply->url(), url);
4193 QCOMPARE(reply->error(), QNetworkReply::NoError);
4194 // verify that the HTTP status code is 200 Ok
4195 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
4197 QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex());
4200 // this tests checks if rewinding the POST-data to some place in the middle
4202 void tst_QNetworkReply::ioPostToHttpFromMiddleOfFileToEnd()
4204 QFile sourceFile(testDataDir + "/rfc3252.txt");
4205 QVERIFY(sourceFile.open(QIODevice::ReadOnly));
4206 // seeking to the middle
4207 sourceFile.seek(sourceFile.size() / 2);
4209 QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi";
4210 QNetworkRequest request(url);
4211 request.setRawHeader("Content-Type", "application/octet-stream");
4212 QNetworkReplyPtr reply(manager.post(request, &sourceFile));
4214 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4215 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4217 QVERIFY(waitForFinish(reply) == Success);
4219 disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4220 this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4222 // compare half data
4223 sourceFile.seek(sourceFile.size() / 2);
4224 QByteArray data = sourceFile.readAll();
4225 QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex());
4228 void tst_QNetworkReply::ioPostToHttpFromMiddleOfFileFiveBytes()
4230 QFile sourceFile(testDataDir + "/rfc3252.txt");
4231 QVERIFY(sourceFile.open(QIODevice::ReadOnly));
4232 // seeking to the middle
4233 sourceFile.seek(sourceFile.size() / 2);
4235 QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi";
4236 QNetworkRequest request(url);
4237 request.setRawHeader("Content-Type", "application/octet-stream");
4238 // only send 5 bytes
4239 request.setHeader(QNetworkRequest::ContentLengthHeader, 5);
4240 QVERIFY(request.header(QNetworkRequest::ContentLengthHeader).isValid());
4241 QNetworkReplyPtr reply(manager.post(request, &sourceFile));
4243 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4244 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4246 QVERIFY(waitForFinish(reply) == Success);
4248 disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4249 this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4251 // compare half data
4252 sourceFile.seek(sourceFile.size() / 2);
4253 QByteArray data = sourceFile.read(5);
4254 QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex());
4257 void tst_QNetworkReply::ioPostToHttpFromMiddleOfQBufferFiveBytes()
4259 // test needed since a QBuffer goes with a different codepath than the QFile
4260 // tested in ioPostToHttpFromMiddleOfFileFiveBytes
4261 QBuffer uploadBuffer;
4262 uploadBuffer.open(QIODevice::ReadWrite);
4263 uploadBuffer.write("1234567890");
4264 uploadBuffer.seek(5);
4266 QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi";
4267 QNetworkRequest request(url);
4268 request.setRawHeader("Content-Type", "application/octet-stream");
4269 QNetworkReplyPtr reply(manager.post(request, &uploadBuffer));
4271 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4272 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4274 QVERIFY(waitForFinish(reply) == Success);
4276 disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4277 this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4279 // compare half data
4280 uploadBuffer.seek(5);
4281 QByteArray data = uploadBuffer.read(5);
4282 QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex());
4286 void tst_QNetworkReply::ioPostToHttpNoBufferFlag()
4288 QByteArray data = QByteArray("daaaaaaataaaaaaa");
4289 // create a sequential QIODevice by feeding the data into a local TCP server
4290 SocketPair socketpair;
4291 socketpair.create();
4292 QVERIFY(socketpair.endPoints[0] && socketpair.endPoints[1]);
4293 socketpair.endPoints[0]->write(data);
4295 QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi";
4296 QNetworkRequest request(url);
4297 request.setRawHeader("Content-Type", "application/octet-stream");
4298 // disallow buffering
4299 request.setAttribute(QNetworkRequest::DoNotBufferUploadDataAttribute, true);
4300 request.setHeader(QNetworkRequest::ContentLengthHeader, data.size());
4301 QNetworkReplyPtr reply(manager.post(request, socketpair.endPoints[1]));
4302 socketpair.endPoints[0]->close();
4304 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4305 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4307 QVERIFY(waitForFinish(reply) == Failure);
4309 disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
4310 this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
4312 // verify: error code is QNetworkReply::ContentReSendError
4313 QCOMPARE(reply->error(), QNetworkReply::ContentReSendError);
4317 class SslServer : public QTcpServer {
4320 SslServer() : socket(0) {};
4321 void incomingConnection(qintptr socketDescriptor) {
4322 QSslSocket *serverSocket = new QSslSocket;
4323 serverSocket->setParent(this);
4325 if (serverSocket->setSocketDescriptor(socketDescriptor)) {
4326 QString testDataDir = QFileInfo(QFINDTESTDATA("rfc3252.txt")).absolutePath();
4327 if (testDataDir.isEmpty())
4328 testDataDir = QCoreApplication::applicationDirPath();
4330 connect(serverSocket, SIGNAL(encrypted()), this, SLOT(encryptedSlot()));
4331 connect(serverSocket, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
4332 serverSocket->setProtocol(QSsl::AnyProtocol);
4333 connect(serverSocket, SIGNAL(sslErrors(const QList<QSslError>&)), serverSocket, SLOT(ignoreSslErrors()));
4334 serverSocket->setLocalCertificate(testDataDir + "/certs/server.pem");
4335 serverSocket->setPrivateKey(testDataDir + "/certs/server.key");
4336 serverSocket->startServerEncryption();
4338 delete serverSocket;
4342 void newEncryptedConnection();
4344 void encryptedSlot() {
4345 socket = (QSslSocket*) sender();
4346 emit newEncryptedConnection();
4348 void readyReadSlot() {
4349 // for the incoming sockets, not the server socket
4350 //qDebug() << static_cast<QSslSocket*>(sender())->bytesAvailable() << static_cast<QSslSocket*>(sender())->encryptedBytesAvailable();
4357 // very similar to ioPostToHttpUploadProgress but for SSL
4358 void tst_QNetworkReply::ioPostToHttpsUploadProgress()
4360 //QFile sourceFile(testDataDir + "/bigfile");
4361 //QVERIFY(sourceFile.open(QIODevice::ReadOnly));
4362 qint64 wantedSize = 2*1024*1024; // 2 MB
4363 QByteArray sourceFile;
4364 // And in the case of SSL, the compression can fool us and let the
4365 // server send the data much faster than expected.
4366 // So better provide random data that cannot be compressed.
4367 for (int i = 0; i < wantedSize; ++i)
4368 sourceFile += (char)qrand();
4370 // emulate a minimal https server
4372 server.listen(QHostAddress(QHostAddress::LocalHost), 0);
4374 // create the request
4375 QUrl url = QUrl(QString("https://127.0.0.1:%1/").arg(server.serverPort()));
4376 QNetworkRequest request(url);
4378 request.setRawHeader("Content-Type", "application/octet-stream");
4379 QNetworkReplyPtr reply(manager.post(request, sourceFile));
4381 QSignalSpy spy(reply.data(), SIGNAL(uploadProgress(qint64,qint64)));
4382 connect(&server, SIGNAL(newEncryptedConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
4383 connect(reply, SIGNAL(sslErrors(const QList<QSslError>&)), reply.data(), SLOT(ignoreSslErrors()));
4385 // get the request started and the incoming socket connected
4386 QTestEventLoop::instance().enterLoop(10);
4387 QVERIFY(!QTestEventLoop::instance().timeout());
4388 QTcpSocket *incomingSocket = server.socket;
4389 QVERIFY(incomingSocket);
4390 disconnect(&server, SIGNAL(newEncryptedConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
4393 incomingSocket->setReadBufferSize(1*1024);
4394 QTestEventLoop::instance().enterLoop(2);
4395 // some progress should have been made
4396 QVERIFY(!spy.isEmpty());
4397 QList<QVariant> args = spy.last();
4398 QVERIFY(args.at(0).toLongLong() > 0);
4399 // but not everything!
4400 QVERIFY(args.at(0).toLongLong() != sourceFile.size());
4402 // set the read buffer to unlimited
4403 incomingSocket->setReadBufferSize(0);
4404 QTestEventLoop::instance().enterLoop(10);
4405 // progress should be finished
4406 QVERIFY(!spy.isEmpty());
4407 QList<QVariant> args3 = spy.last();
4408 QCOMPARE(args3.at(0).toLongLong(), args3.at(1).toLongLong());
4409 QCOMPARE(args3.at(0).toLongLong(), qint64(sourceFile.size()));
4411 // after sending this, the QNAM should emit finished()
4412 incomingSocket->write("HTTP/1.0 200 OK\r\n");
4413 incomingSocket->write("Content-Length: 0\r\n");
4414 incomingSocket->write("\r\n");
4416 QVERIFY(waitForFinish(reply) == Success);
4418 incomingSocket->close();
4423 void tst_QNetworkReply::ioGetFromBuiltinHttp_data()
4425 QTest::addColumn<bool>("https");
4426 QTest::addColumn<int>("bufferSize");
4427 QTest::newRow("http+unlimited") << false << 0;
4428 QTest::newRow("http+limited") << false << 4096;
4430 QTest::newRow("https+unlimited") << true << 0;
4431 QTest::newRow("https+limited") << true << 4096;
4435 void tst_QNetworkReply::ioGetFromBuiltinHttp()
4437 QSKIP("Limiting is broken right now, check QTBUG-15065");
4438 QFETCH(bool, https);
4439 QFETCH(int, bufferSize);
4441 QByteArray testData;
4442 // Make the data big enough so that it can fill the kernel buffer
4443 // (which seems to hold 202 KB here)
4444 const int wantedSize = 1200 * 1000;
4445 testData.reserve(wantedSize);
4446 // And in the case of SSL, the compression can fool us and let the
4447 // server send the data much faster than expected.
4448 // So better provide random data that cannot be compressed.
4449 for (int i = 0; i < wantedSize; ++i)
4450 testData += (char)qrand();
4452 QByteArray httpResponse = QByteArray("HTTP/1.0 200 OK\r\nContent-Length: ");
4453 httpResponse += QByteArray::number(testData.size());
4454 httpResponse += "\r\n\r\n";
4455 httpResponse += testData;
4457 qDebug() << "Server will send" << (httpResponse.size()-testData.size()) << "bytes of header and"
4458 << testData.size() << "bytes of data";
4460 const bool fillKernelBuffer = bufferSize > 0;
4461 FastSender server(httpResponse, https, fillKernelBuffer);
4463 QUrl url(QString("%1://127.0.0.1:%2/qtest/rfc3252.txt")
4464 .arg(https?"https":"http")
4465 .arg(server.serverPort()));
4466 QNetworkRequest request(url);
4467 QNetworkReplyPtr reply(manager.get(request));
4468 reply->setReadBufferSize(bufferSize);
4469 reply->ignoreSslErrors();
4470 const int rate = 200; // in kB per sec
4471 RateControlledReader reader(server, reply.data(), rate, bufferSize);
4476 QVERIFY(waitForFinish(reply) == Success);
4478 const int elapsedTime = loopTime.elapsed();
4482 qDebug() << "send rate:" << server.transferRate << "B/s";
4483 qDebug() << "receive rate:" << reader.totalBytesRead * 1000 / elapsedTime
4484 << "(it received" << reader.totalBytesRead << "bytes in" << elapsedTime << "ms)";
4486 QCOMPARE(reply->url(), request.url());
4487 QCOMPARE(reply->error(), QNetworkReply::NoError);
4488 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
4490 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), (qint64)testData.size());
4491 if (reader.data.size() < testData.size()) { // oops?
4492 QCOMPARE(reader.data, testData.mid(0, reader.data.size()));
4493 qDebug() << "The data is incomplete, the last" << testData.size() - reader.data.size() << "bytes are missing";
4494 QEXPECT_FAIL("http+limited", "Limiting is broken right now, check QTBUG-15065", Abort);
4495 QEXPECT_FAIL("https+limited", "Limiting is broken right now, check QTBUG-15065", Abort);
4497 QCOMPARE(reader.data.size(), testData.size());
4498 QCOMPARE(reader.data, testData);
4500 // OK we got the file alright, but did setReadBufferSize work?
4501 QVERIFY(server.transferRate != -1);
4502 if (bufferSize > 0) {
4503 const int allowedDeviation = 16; // TODO find out why the send rate is 13% faster currently
4504 const int minRate = rate * 1024 * (100-allowedDeviation) / 100;
4505 const int maxRate = rate * 1024 * (100+allowedDeviation) / 100;
4506 qDebug() << minRate << "<="<< server.transferRate << "<=" << maxRate << "?";
4507 QEXPECT_FAIL("http+limited", "Limiting is broken right now, check QTBUG-15065", Continue);
4508 QEXPECT_FAIL("https+limited", "Limiting is broken right now, check QTBUG-15065", Continue);
4509 QVERIFY(server.transferRate >= minRate && server.transferRate <= maxRate);
4513 void tst_QNetworkReply::ioPostToHttpUploadProgress()
4515 QFile sourceFile(testDataDir + "/bigfile");
4516 QVERIFY(sourceFile.open(QIODevice::ReadOnly));
4518 // emulate a minimal http server
4520 server.listen(QHostAddress(QHostAddress::LocalHost), 0);
4522 // create the request
4523 QUrl url = QUrl(QString("http://127.0.0.1:%1/").arg(server.serverPort()));
4524 QNetworkRequest request(url);
4525 request.setRawHeader("Content-Type", "application/octet-stream");
4526 QNetworkReplyPtr reply(manager.post(request, &sourceFile));
4527 QSignalSpy spy(reply.data(), SIGNAL(uploadProgress(qint64,qint64)));
4528 connect(&server, SIGNAL(newConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
4530 // get the request started and the incoming socket connected
4531 QTestEventLoop::instance().enterLoop(10);
4532 QVERIFY(!QTestEventLoop::instance().timeout());
4533 QTcpSocket *incomingSocket = server.nextPendingConnection();
4534 QVERIFY(incomingSocket);
4535 disconnect(&server, SIGNAL(newConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
4537 incomingSocket->setReadBufferSize(1*1024);
4538 QTestEventLoop::instance().enterLoop(5);
4539 // some progress should have been made
4540 QList<QVariant> args = spy.last();
4541 QVERIFY(!args.isEmpty());
4542 QVERIFY(args.at(0).toLongLong() > 0);
4543 // but not everything!
4544 QVERIFY(args.at(0).toLongLong() != sourceFile.size());
4546 // set the read buffer to unlimited
4547 incomingSocket->setReadBufferSize(0);
4548 QTestEventLoop::instance().enterLoop(10);
4549 // progress should be finished
4550 QList<QVariant> args3 = spy.last();
4551 QVERIFY(!args3.isEmpty());
4552 // More progress than before
4553 QVERIFY(args3.at(0).toLongLong() > args.at(0).toLongLong());
4554 QCOMPARE(args3.at(0).toLongLong(), args3.at(1).toLongLong());
4555 // And actually finished..
4556 QCOMPARE(args3.at(0).toLongLong(), sourceFile.size());
4558 // after sending this, the QNAM should emit finished()
4559 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
4560 incomingSocket->write("HTTP/1.0 200 OK\r\n");
4561 incomingSocket->write("Content-Length: 0\r\n");
4562 incomingSocket->write("\r\n");
4563 QTestEventLoop::instance().enterLoop(10);
4564 // not timeouted -> finished() was emitted
4565 QVERIFY(!QTestEventLoop::instance().timeout());
4567 incomingSocket->close();
4571 void tst_QNetworkReply::ioPostToHttpEmptyUploadProgress()
4575 QBuffer buffer(&ba,0);
4576 QVERIFY(buffer.open(QIODevice::ReadOnly));
4578 // emulate a minimal http server
4580 server.listen(QHostAddress(QHostAddress::LocalHost), 0);
4582 // create the request
4583 QUrl url = QUrl(QString("http://127.0.0.1:%1/").arg(server.serverPort()));
4584 QNetworkRequest request(url);
4585 request.setRawHeader("Content-Type", "application/octet-stream");
4586 QNetworkReplyPtr reply(manager.post(request, &buffer));
4587 QSignalSpy spy(reply.data(), SIGNAL(uploadProgress(qint64,qint64)));
4588 connect(&server, SIGNAL(newConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
4591 // get the request started and the incoming socket connected
4592 QTestEventLoop::instance().enterLoop(10);
4593 QVERIFY(!QTestEventLoop::instance().timeout());
4594 QTcpSocket *incomingSocket = server.nextPendingConnection();
4595 QVERIFY(incomingSocket);
4597 // after sending this, the QNAM should emit finished()
4598 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
4599 incomingSocket->write("HTTP/1.0 200 OK\r\n");
4600 incomingSocket->write("Content-Length: 0\r\n");
4601 incomingSocket->write("\r\n");
4602 incomingSocket->flush();
4603 QTestEventLoop::instance().enterLoop(10);
4604 // not timeouted -> finished() was emitted
4605 QVERIFY(!QTestEventLoop::instance().timeout());
4607 // final check: only 1 uploadProgress has been emitted
4608 QVERIFY(spy.length() == 1);
4609 QList<QVariant> args = spy.last();
4610 QVERIFY(!args.isEmpty());
4611 QCOMPARE(args.at(0).toLongLong(), buffer.size());
4612 QCOMPARE(args.at(0).toLongLong(), buffer.size());
4614 incomingSocket->close();
4618 void tst_QNetworkReply::lastModifiedHeaderForFile()
4620 QFileInfo fileInfo(testDataDir + "/bigfile");
4621 QVERIFY(fileInfo.exists());
4623 QUrl url = QUrl::fromLocalFile(fileInfo.filePath());
4625 QNetworkRequest request(url);
4626 QNetworkReplyPtr reply(manager.head(request));
4628 QVERIFY(waitForFinish(reply) == Success);
4630 QDateTime header = reply->header(QNetworkRequest::LastModifiedHeader).toDateTime();
4631 QCOMPARE(header, fileInfo.lastModified());
4634 void tst_QNetworkReply::lastModifiedHeaderForHttp()
4636 // Tue, 22 May 2007 12:04:57 GMT according to webserver
4637 QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/fluke.gif";
4639 QNetworkRequest request(url);
4640 QNetworkReplyPtr reply(manager.head(request));
4642 QVERIFY(waitForFinish(reply) == Success);
4644 QDateTime header = reply->header(QNetworkRequest::LastModifiedHeader).toDateTime();
4645 QDateTime realDate = QDateTime::fromString("2007-05-22T12:04:57", Qt::ISODate);
4646 realDate.setTimeSpec(Qt::UTC);
4648 QCOMPARE(header, realDate);
4651 void tst_QNetworkReply::httpCanReadLine()
4653 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
4654 QNetworkReplyPtr reply(manager.get(request));
4656 QVERIFY(waitForFinish(reply) == Success);
4658 QCOMPARE(reply->error(), QNetworkReply::NoError);
4660 QVERIFY(reply->canReadLine());
4661 QVERIFY(!reply->readAll().isEmpty());
4662 QVERIFY(!reply->canReadLine());
4665 void tst_QNetworkReply::rateControl_data()
4667 QTest::addColumn<int>("rate");
4669 QTest::newRow("15") << 15;
4670 QTest::newRow("40") << 40;
4671 QTest::newRow("73") << 73;
4672 QTest::newRow("80") << 80;
4673 QTest::newRow("125") << 125;
4674 QTest::newRow("250") << 250;
4675 QTest::newRow("1024") << 1024;
4678 void tst_QNetworkReply::rateControl()
4680 QSKIP("Test disabled -- only for manual purposes");
4681 // this function tests that we aren't reading from the network
4682 // faster than the data is being consumed.
4685 #if !defined(QT_BUILD_INTERNAL)
4686 QSKIP("backend for testing not available!");
4689 // ask for 20 seconds worth of data
4690 FastSender sender(20 * rate * 1024);
4692 QNetworkRequest request("debugpipe://localhost:" + QString::number(sender.serverPort()));
4693 QNetworkReplyPtr reply(manager.get(request));
4694 reply->setReadBufferSize(32768);
4695 QSignalSpy errorSpy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError)));
4697 RateControlledReader reader(sender, reply.data(), rate, 20);
4699 // this test is designed to run for 25 seconds at most
4703 QVERIFY(waitForFinish(reply) == Success);
4705 int elapsedTime = loopTime.elapsed();
4707 if (!errorSpy.isEmpty()) {
4708 qDebug() << "ERROR!" << errorSpy[0][0] << reply->errorString();
4711 qDebug() << "tst_QNetworkReply::rateControl" << "send rate:" << sender.transferRate;
4712 qDebug() << "tst_QNetworkReply::rateControl" << "receive rate:" << reader.totalBytesRead * 1000 / elapsedTime
4713 << "(it received" << reader.totalBytesRead << "bytes in" << elapsedTime << "ms)";
4717 QCOMPARE(reply->url(), request.url());
4718 QCOMPARE(reply->error(), QNetworkReply::NoError);
4720 QVERIFY(sender.transferRate != -1);
4721 int minRate = rate * 1024 * 9 / 10;
4722 int maxRate = rate * 1024 * 11 / 10;
4723 QVERIFY(sender.transferRate >= minRate);
4724 QVERIFY(sender.transferRate <= maxRate);
4727 void tst_QNetworkReply::downloadProgress_data()
4729 QTest::addColumn<int>("loopCount");
4731 QTest::newRow("empty") << 0;
4732 QTest::newRow("small") << 4;
4733 QTest::newRow("big") << 4096;
4736 void tst_QNetworkReply::downloadProgress()
4738 #if !defined(QT_BUILD_INTERNAL)
4739 QSKIP("backend for testing not available!");
4742 QVERIFY(server.listen());
4744 QNetworkRequest request("debugpipe://127.0.0.1:" + QString::number(server.serverPort()) + "/?bare=1");
4745 QNetworkReplyPtr reply(manager.get(request));
4746 QSignalSpy spy(reply.data(), SIGNAL(downloadProgress(qint64,qint64)));
4747 connect(reply, SIGNAL(downloadProgress(qint64,qint64)),
4748 &QTestEventLoop::instance(), SLOT(exitLoop()));
4749 QVERIFY(spy.isValid());
4750 QVERIFY(!reply->isFinished());
4751 QVERIFY(reply->isRunning());
4753 QCoreApplication::instance()->processEvents();
4754 if (!server.hasPendingConnections())
4755 server.waitForNewConnection(1000);
4756 QVERIFY(server.hasPendingConnections());
4757 QCOMPARE(spy.count(), 0);
4759 QByteArray data(128, 'a');
4760 QTcpSocket *sender = server.nextPendingConnection();
4763 QFETCH(int, loopCount);
4764 for (int i = 1; i <= loopCount; ++i) {
4765 sender->write(data);
4766 QVERIFY2(sender->waitForBytesWritten(2000), "Network timeout");
4769 QTestEventLoop::instance().enterLoop(2);
4770 QVERIFY(!QTestEventLoop::instance().timeout());
4771 QVERIFY(spy.count() > 0);
4772 QVERIFY(!reply->isFinished());
4773 QVERIFY(reply->isRunning());
4775 QList<QVariant> args = spy.last();
4776 QCOMPARE(args.at(0).toInt(), i*data.size());
4777 QCOMPARE(args.at(1).toInt(), -1);
4780 // close the connection:
4784 QTestEventLoop::instance().enterLoop(2);
4785 QCOMPARE(reply->error(), QNetworkReply::NoError);
4786 QVERIFY(!QTestEventLoop::instance().timeout());
4787 QVERIFY(spy.count() > 0);
4788 QVERIFY(!reply->isRunning());
4789 QVERIFY(reply->isFinished());
4791 QList<QVariant> args = spy.last();
4792 QCOMPARE(args.at(0).toInt(), loopCount * data.size());
4793 QCOMPARE(args.at(1).toInt(), loopCount * data.size());
4796 void tst_QNetworkReply::uploadProgress_data()
4801 void tst_QNetworkReply::uploadProgress()
4803 QFETCH(QByteArray, data);
4804 #if !defined(QT_BUILD_INTERNAL)
4805 QSKIP("backend for testing not available!");
4808 QVERIFY(server.listen());
4810 QNetworkRequest request("debugpipe://127.0.0.1:" + QString::number(server.serverPort()) + "/?bare=1");
4811 QNetworkReplyPtr reply(manager.put(request, data));
4812 QSignalSpy spy(reply.data(), SIGNAL(uploadProgress(qint64,qint64)));
4813 QSignalSpy finished(reply.data(), SIGNAL(finished()));
4814 QVERIFY(spy.isValid());
4815 QVERIFY(finished.isValid());
4817 QCoreApplication::instance()->processEvents();
4818 if (!server.hasPendingConnections())
4819 server.waitForNewConnection(1000);
4820 QVERIFY(server.hasPendingConnections());
4822 QTcpSocket *receiver = server.nextPendingConnection();
4823 if (finished.count() == 0) {
4824 // it's not finished yet, so wait for it to be
4825 QVERIFY(waitForFinish(reply) == Success);
4829 QVERIFY(finished.count() > 0);
4830 QVERIFY(spy.count() > 0);
4832 QList<QVariant> args = spy.last();
4833 QCOMPARE(args.at(0).toInt(), data.size());
4834 QCOMPARE(args.at(1).toInt(), data.size());
4837 void tst_QNetworkReply::chaining_data()
4842 void tst_QNetworkReply::chaining()
4844 QTemporaryFile sourceFile(QDir::currentPath() + "/temp-XXXXXX");
4845 sourceFile.setAutoRemove(true);
4846 QVERIFY(sourceFile.open());
4848 QFETCH(QByteArray, data);
4849 QVERIFY(sourceFile.write(data) == data.size());
4851 QCOMPARE(sourceFile.size(), qint64(data.size()));
4853 QNetworkRequest request(QUrl::fromLocalFile(sourceFile.fileName()));
4854 QNetworkReplyPtr getReply(manager.get(request));
4856 QFile targetFile(testFileName);
4857 QUrl url = QUrl::fromLocalFile(targetFile.fileName());
4858 request.setUrl(url);
4859 QNetworkReplyPtr putReply(manager.put(request, getReply.data()));
4861 QVERIFY(waitForFinish(putReply) == Success);
4863 QCOMPARE(getReply->url(), QUrl::fromLocalFile(sourceFile.fileName()));
4864 QCOMPARE(getReply->error(), QNetworkReply::NoError);
4865 QCOMPARE(getReply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), sourceFile.size());
4867 QCOMPARE(putReply->url(), url);
4868 QCOMPARE(putReply->error(), QNetworkReply::NoError);
4869 QCOMPARE(putReply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
4870 QVERIFY(putReply->readAll().isEmpty());
4872 QVERIFY(sourceFile.atEnd());
4873 sourceFile.seek(0); // reset it to the beginning
4875 QVERIFY(targetFile.open(QIODevice::ReadOnly));
4876 QCOMPARE(targetFile.size(), sourceFile.size());
4877 QCOMPARE(targetFile.readAll(), sourceFile.readAll());
4880 void tst_QNetworkReply::receiveCookiesFromHttp_data()
4882 QTest::addColumn<QString>("cookieString");
4883 QTest::addColumn<QList<QNetworkCookie> >("expectedCookiesFromHttp");
4884 QTest::addColumn<QList<QNetworkCookie> >("expectedCookiesInJar");
4886 QTest::newRow("empty") << "" << QList<QNetworkCookie>() << QList<QNetworkCookie>();
4888 QList<QNetworkCookie> header, jar;
4889 QNetworkCookie cookie("a", "b");
4891 cookie.setDomain(QtNetworkSettings::serverName());
4892 cookie.setPath("/qtest/cgi-bin/");
4894 QTest::newRow("simple-cookie") << "a=b" << header << jar;
4896 header << QNetworkCookie("c", "d");
4897 cookie.setName("c");
4898 cookie.setValue("d");
4900 QTest::newRow("two-cookies") << "a=b, c=d" << header << jar;
4901 QTest::newRow("two-cookies-2") << "a=b\nc=d" << header << jar;
4905 cookie = QNetworkCookie("a", "b");
4906 cookie.setPath("/not/part-of-path");
4908 cookie.setDomain(QtNetworkSettings::serverName());
4910 QTest::newRow("invalid-cookie-path") << "a=b; path=/not/part-of-path" << header << jar;
4913 cookie = QNetworkCookie("a", "b");
4914 cookie.setDomain(".example.com");
4917 QTest::newRow("invalid-cookie-domain") << "a=b; domain=.example.com" << header << jar;
4920 void tst_QNetworkReply::receiveCookiesFromHttp()
4922 QFETCH(QString, cookieString);
4924 QByteArray data = cookieString.toLatin1() + '\n';
4925 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/set-cookie.cgi");
4926 QNetworkRequest request(url);
4927 request.setRawHeader("Content-Type", "application/octet-stream");
4928 QNetworkReplyPtr reply;
4929 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PostOperation, request, reply, data));
4931 QCOMPARE(reply->url(), url);
4932 QCOMPARE(reply->error(), QNetworkReply::NoError);
4934 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
4936 QList<QNetworkCookie> setCookies =
4937 qvariant_cast<QList<QNetworkCookie> >(reply->header(QNetworkRequest::SetCookieHeader));
4938 QTEST(setCookies, "expectedCookiesFromHttp");
4939 QTEST(cookieJar->allCookies(), "expectedCookiesInJar");
4942 void tst_QNetworkReply::receiveCookiesFromHttpSynchronous_data()
4944 tst_QNetworkReply::receiveCookiesFromHttp_data();
4947 void tst_QNetworkReply::receiveCookiesFromHttpSynchronous()
4949 QFETCH(QString, cookieString);
4951 QByteArray data = cookieString.toLatin1() + '\n';
4952 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/set-cookie.cgi");
4954 QNetworkRequest request(url);
4955 request.setRawHeader("Content-Type", "application/octet-stream");
4956 request.setAttribute(
4957 QNetworkRequest::SynchronousRequestAttribute,
4960 QNetworkReplyPtr reply;
4961 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PostOperation, request, reply, data));
4963 QCOMPARE(reply->url(), url);
4964 QCOMPARE(reply->error(), QNetworkReply::NoError);
4966 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
4968 QList<QNetworkCookie> setCookies =
4969 qvariant_cast<QList<QNetworkCookie> >(reply->header(QNetworkRequest::SetCookieHeader));
4970 QTEST(setCookies, "expectedCookiesFromHttp");
4971 QTEST(cookieJar->allCookies(), "expectedCookiesInJar");
4974 void tst_QNetworkReply::sendCookies_data()
4976 QTest::addColumn<QList<QNetworkCookie> >("cookiesToSet");
4977 QTest::addColumn<QString>("expectedCookieString");
4979 QList<QNetworkCookie> list;
4980 QTest::newRow("empty") << list << "";
4982 QNetworkCookie cookie("a", "b");
4983 cookie.setPath("/");
4984 cookie.setDomain("example.com");
4986 QTest::newRow("no-match-domain") << list << "";
4988 cookie.setDomain(QtNetworkSettings::serverName());
4989 cookie.setPath("/something/else");
4991 QTest::newRow("no-match-path") << list << "";
4993 cookie.setPath("/");
4995 QTest::newRow("simple-cookie") << list << "a=b";
4997 cookie.setPath("/qtest");
4998 cookie.setValue("longer");
5000 QTest::newRow("two-cookies") << list << "a=longer; a=b";
5003 cookie = QNetworkCookie("a", "b");
5004 cookie.setPath("/");
5005 cookie.setDomain("." + QtNetworkSettings::serverDomainName());
5007 QTest::newRow("domain-match") << list << "a=b";
5009 // but it shouldn't match this:
5010 cookie.setDomain(QtNetworkSettings::serverDomainName());
5012 QTest::newRow("domain-match-2") << list << "a=b";
5015 void tst_QNetworkReply::sendCookies()
5017 QFETCH(QString, expectedCookieString);
5018 QFETCH(QList<QNetworkCookie>, cookiesToSet);
5019 cookieJar->setAllCookies(cookiesToSet);
5021 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/get-cookie.cgi");
5022 QNetworkRequest request(url);
5023 QNetworkReplyPtr reply;
5024 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
5026 QCOMPARE(reply->url(), url);
5027 QCOMPARE(reply->error(), QNetworkReply::NoError);
5029 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
5031 QCOMPARE(QString::fromLatin1(reply->readAll()).trimmed(), expectedCookieString);
5034 void tst_QNetworkReply::sendCookiesSynchronous_data()
5036 tst_QNetworkReply::sendCookies_data();
5039 void tst_QNetworkReply::sendCookiesSynchronous()
5041 QFETCH(QString, expectedCookieString);
5042 QFETCH(QList<QNetworkCookie>, cookiesToSet);
5043 cookieJar->setAllCookies(cookiesToSet);
5045 QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/get-cookie.cgi");
5046 QNetworkRequest request(url);
5048 request.setAttribute(
5049 QNetworkRequest::SynchronousRequestAttribute,
5052 QNetworkReplyPtr reply;
5053 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
5055 QCOMPARE(reply->url(), url);
5056 QCOMPARE(reply->error(), QNetworkReply::NoError);
5058 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
5060 QCOMPARE(QString::fromLatin1(reply->readAll()).trimmed(), expectedCookieString);
5063 void tst_QNetworkReply::nestedEventLoops_slot()
5067 // 16 seconds: fluke times out in 15 seconds, which triggers a QTcpSocket error
5068 QTimer::singleShot(16000, &subloop, SLOT(quit()));
5071 QTestEventLoop::instance().exitLoop();
5074 void tst_QNetworkReply::nestedEventLoops()
5076 // Slightly fragile test, it may not be testing anything
5077 // This is certifying that we're not running into the same issue
5078 // that QHttp had (task 200432): the QTcpSocket connection is
5079 // closed by the remote end because of the kept-alive HTTP
5080 // connection timed out.
5082 // The exact time required for this to happen is not exactly
5083 // defined. Our server (Apache httpd) times out after 15
5084 // seconds. (see above)
5086 qDebug("Takes 16 seconds to run, please wait");
5088 QUrl url("http://" + QtNetworkSettings::serverName());
5089 QNetworkRequest request(url);
5090 QNetworkReplyPtr reply(manager.get(request));
5092 QSignalSpy finishedspy(reply.data(), SIGNAL(finished()));
5093 QSignalSpy errorspy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError)));
5095 connect(reply, SIGNAL(finished()), SLOT(nestedEventLoops_slot()));
5096 QTestEventLoop::instance().enterLoop(20);
5097 QVERIFY2(!QTestEventLoop::instance().timeout(), "Network timeout");
5099 QCOMPARE(finishedspy.count(), 1);
5100 QCOMPARE(errorspy.count(), 0);
5103 void tst_QNetworkReply::httpProxyCommands_data()
5105 QTest::addColumn<QUrl>("url");
5106 QTest::addColumn<QByteArray>("responseToSend");
5107 QTest::addColumn<QString>("expectedCommand");
5109 QTest::newRow("http")
5110 << QUrl("http://0.0.0.0:4443/http-request")
5111 << QByteArray("HTTP/1.0 200 OK\r\nProxy-Connection: close\r\nContent-Length: 1\r\n\r\n1")
5112 << "GET http://0.0.0.0:4443/http-request HTTP/1.";
5114 QTest::newRow("https")
5115 << QUrl("https://0.0.0.0:4443/https-request")
5116 << QByteArray("HTTP/1.0 200 Connection Established\r\n\r\n")
5117 << "CONNECT 0.0.0.0:4443 HTTP/1.";
5121 void tst_QNetworkReply::httpProxyCommands()
5124 QFETCH(QByteArray, responseToSend);
5125 QFETCH(QString, expectedCommand);
5127 MiniHttpServer proxyServer(responseToSend);
5128 QNetworkProxy proxy(QNetworkProxy::HttpProxy, "127.0.0.1", proxyServer.serverPort());
5130 manager.setProxy(proxy);
5131 QNetworkRequest request(url);
5132 request.setRawHeader("User-Agent", "QNetworkReplyAutoTest/1.0");
5133 QNetworkReplyPtr reply(manager.get(request));
5134 //clearing the proxy here causes the test to fail.
5135 //the proxy isn't used until after the bearer has been started
5136 //which is correct in general, because system proxy isn't known until that time.
5137 //removing this line is safe, as the proxy is also reset by the cleanup() function
5138 //manager.setProxy(QNetworkProxy());
5140 // wait for the finished signal
5141 QVERIFY(waitForFinish(reply) != Timeout);
5143 //qDebug() << reply->error() << reply->errorString();
5144 //qDebug() << proxyServer.receivedData;
5146 // we don't really care if the request succeeded
5147 // especially since it won't succeed in the HTTPS case
5148 // so just check that the command was correct
5150 QString receivedHeader = proxyServer.receivedData.left(expectedCommand.length());
5151 QCOMPARE(receivedHeader, expectedCommand);
5153 //QTBUG-17223 - make sure the user agent from the request is sent to proxy server even for CONNECT
5154 int uapos = proxyServer.receivedData.indexOf("User-Agent");
5155 int uaend = proxyServer.receivedData.indexOf("\r\n", uapos);
5156 QByteArray uaheader = proxyServer.receivedData.mid(uapos, uaend - uapos);
5157 QCOMPARE(uaheader, QByteArray("User-Agent: QNetworkReplyAutoTest/1.0"));
5160 class ProxyChangeHelper : public QObject {
5163 ProxyChangeHelper() : QObject(), signalCount(0) {};
5165 void finishedSlot() {
5167 if (signalCount == 2)
5168 QMetaObject::invokeMethod(&QTestEventLoop::instance(), "exitLoop", Qt::QueuedConnection);
5174 void tst_QNetworkReply::httpProxyCommandsSynchronous_data()
5176 httpProxyCommands_data();
5179 struct QThreadCleanup
5181 static inline void cleanup(QThread *thread)
5184 if (thread->wait(3000))
5187 qWarning("thread hung, leaking memory so test can finish");
5191 struct QDeleteLaterCleanup
5193 static inline void cleanup(QObject *o)
5199 void tst_QNetworkReply::httpProxyCommandsSynchronous()
5202 QFETCH(QByteArray, responseToSend);
5203 QFETCH(QString, expectedCommand);
5205 // when using synchronous commands, we need a different event loop for
5206 // the server thread, because the client is never returning to the
5208 QScopedPointer<QThread, QThreadCleanup> serverThread(new QThread);
5209 QScopedPointer<MiniHttpServer, QDeleteLaterCleanup> proxyServer(new MiniHttpServer(responseToSend, false, serverThread.data()));
5210 QNetworkProxy proxy(QNetworkProxy::HttpProxy, "127.0.0.1", proxyServer->serverPort());
5212 manager.setProxy(proxy);
5213 QNetworkRequest request(url);
5215 // send synchronous request
5216 request.setAttribute(
5217 QNetworkRequest::SynchronousRequestAttribute,
5220 QNetworkReplyPtr reply(manager.get(request));
5221 QVERIFY(reply->isFinished()); // synchronous
5222 manager.setProxy(QNetworkProxy());
5224 //qDebug() << reply->error() << reply->errorString();
5226 // we don't really care if the request succeeded
5227 // especially since it won't succeed in the HTTPS case
5228 // so just check that the command was correct
5230 QString receivedHeader = proxyServer->receivedData.left(expectedCommand.length());
5231 QCOMPARE(receivedHeader, expectedCommand);
5234 void tst_QNetworkReply::proxyChange()
5236 ProxyChangeHelper helper;
5237 MiniHttpServer proxyServer(
5238 "HTTP/1.0 200 OK\r\nProxy-Connection: keep-alive\r\n"
5239 "Content-Length: 1\r\n\r\n1");
5240 QNetworkProxy dummyProxy(QNetworkProxy::HttpProxy, "127.0.0.1", proxyServer.serverPort());
5241 QNetworkRequest req(QUrl("http://" + QtNetworkSettings::serverName()));
5242 proxyServer.doClose = false;
5244 manager.setProxy(dummyProxy);
5245 QNetworkReplyPtr reply1(manager.get(req));
5246 connect(reply1, SIGNAL(finished()), &helper, SLOT(finishedSlot()));
5248 manager.setProxy(QNetworkProxy());
5249 QNetworkReplyPtr reply2(manager.get(req));
5250 connect(reply2, SIGNAL(finished()), &helper, SLOT(finishedSlot()));
5252 QTestEventLoop::instance().enterLoop(20);
5253 QVERIFY(!QTestEventLoop::instance().timeout());
5255 // verify that the replies succeeded
5256 QCOMPARE(reply1->error(), QNetworkReply::NoError);
5257 QCOMPARE(reply1->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
5258 QVERIFY(reply1->size() == 1);
5260 QCOMPARE(reply2->error(), QNetworkReply::NoError);
5261 QCOMPARE(reply2->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
5262 QVERIFY(reply2->size() > 1);
5264 // now try again and get an error
5265 // this verifies that we reuse the already-open connection
5267 proxyServer.doClose = true;
5268 proxyServer.dataToTransmit =
5269 "HTTP/1.0 403 Forbidden\r\nProxy-Connection: close\r\n"
5270 "Content-Length: 1\r\n\r\n1";
5272 manager.setProxy(dummyProxy);
5273 QNetworkReplyPtr reply3(manager.get(req));
5275 QVERIFY(waitForFinish(reply3) == Failure);
5277 QVERIFY(int(reply3->error()) > 0);
5280 void tst_QNetworkReply::authorizationError_data()
5283 QTest::addColumn<QString>("url");
5284 QTest::addColumn<int>("errorSignalCount");
5285 QTest::addColumn<int>("finishedSignalCount");
5286 QTest::addColumn<int>("error");
5287 QTest::addColumn<int>("httpStatusCode");
5288 QTest::addColumn<QString>("httpBody");
5290 QTest::newRow("unknown-authorization-method") << "http://" + QtNetworkSettings::serverName() +
5291 "/qtest/cgi-bin/http-unknown-authentication-method.cgi?401-authorization-required" << 1 << 1
5292 << int(QNetworkReply::AuthenticationRequiredError) << 401 << "authorization required";
5293 QTest::newRow("unknown-proxy-authorization-method") << "http://" + QtNetworkSettings::serverName() +
5294 "/qtest/cgi-bin/http-unknown-authentication-method.cgi?407-proxy-authorization-required" << 1 << 1
5295 << int(QNetworkReply::ProxyAuthenticationRequiredError) << 407
5296 << "authorization required";
5299 void tst_QNetworkReply::authorizationError()
5301 QFETCH(QString, url);
5302 QNetworkRequest request(url);
5303 QNetworkReplyPtr reply(manager.get(request));
5305 QCOMPARE(reply->error(), QNetworkReply::NoError);
5307 QSignalSpy errorSpy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError)));
5308 QSignalSpy finishedSpy(reply.data(), SIGNAL(finished()));
5309 // now run the request:
5310 QVERIFY(waitForFinish(reply) == Failure);
5312 QFETCH(int, errorSignalCount);
5313 QCOMPARE(errorSpy.count(), errorSignalCount);
5314 QFETCH(int, finishedSignalCount);
5315 QCOMPARE(finishedSpy.count(), finishedSignalCount);
5317 QCOMPARE(reply->error(), QNetworkReply::NetworkError(error));
5319 QFETCH(int, httpStatusCode);
5320 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), httpStatusCode);
5322 QFETCH(QString, httpBody);
5323 QCOMPARE(qint64(reply->size()), qint64(httpBody.size()));
5324 QCOMPARE(QString(reply->readAll()), httpBody);
5327 void tst_QNetworkReply::httpConnectionCount()
5330 QVERIFY(server.listen());
5331 QCoreApplication::instance()->processEvents();
5333 for (int i = 0; i < 10; i++) {
5334 QNetworkRequest request (QUrl("http://127.0.0.1:" + QString::number(server.serverPort()) + "/" + QString::number(i)));
5335 QNetworkReply* reply = manager.get(request);
5336 reply->setParent(&server);
5339 int pendingConnectionCount = 0;
5343 while(pendingConnectionCount <= 20) {
5344 QTestEventLoop::instance().enterLoop(1);
5345 QTcpSocket *socket = server.nextPendingConnection();
5346 while (socket != 0) {
5347 pendingConnectionCount++;
5348 socket->setParent(&server);
5349 socket = server.nextPendingConnection();
5352 // at max. wait 10 sec
5353 if (time.elapsed() > 10000)
5357 QCOMPARE(pendingConnectionCount, 6);
5360 void tst_QNetworkReply::httpReUsingConnectionSequential_data()
5362 QTest::addColumn<bool>("doDeleteLater");
5363 QTest::newRow("deleteLater") << true;
5364 QTest::newRow("noDeleteLater") << false;
5367 void tst_QNetworkReply::httpReUsingConnectionSequential()
5369 QFETCH(bool, doDeleteLater);
5371 QByteArray response("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
5372 MiniHttpServer server(response);
5373 server.multiple = true;
5374 server.doClose = false;
5377 url.setScheme("http");
5378 url.setPort(server.serverPort());
5379 url.setHost("127.0.0.1");
5381 QNetworkReply* reply1 = manager.get(QNetworkRequest(url));
5382 connect(reply1, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
5383 QTestEventLoop::instance().enterLoop(2);
5384 QVERIFY(!QTestEventLoop::instance().timeout());
5385 QVERIFY(!reply1->error());
5386 int reply1port = server.client->peerPort();
5389 reply1->deleteLater();
5391 // finished received, send the next one
5392 QNetworkReply*reply2 = manager.get(QNetworkRequest(url));
5393 connect(reply2, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
5394 QTestEventLoop::instance().enterLoop(2);
5395 QVERIFY(!QTestEventLoop::instance().timeout());
5396 QVERIFY(!reply2->error());
5397 int reply2port = server.client->peerPort(); // should still be the same object
5399 QVERIFY(reply1port > 0);
5400 QCOMPARE(server.totalConnections, 1);
5401 QCOMPARE(reply2port, reply1port);
5404 reply1->deleteLater(); // only do it if it was not done earlier
5405 reply2->deleteLater();
5408 class HttpReUsingConnectionFromFinishedSlot : public QObject {
5411 QNetworkReply* reply1;
5412 QNetworkReply* reply2;
5414 QNetworkAccessManager manager;
5416 void finishedSlot() {
5417 QVERIFY(!reply1->error());
5419 QFETCH(bool, doDeleteLater);
5420 if (doDeleteLater) {
5421 reply1->deleteLater();
5425 // kick off 2nd request and exit the loop when it is done
5426 reply2 = manager.get(QNetworkRequest(url));
5427 reply2->setParent(this);
5428 connect(reply2, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
5432 void tst_QNetworkReply::httpReUsingConnectionFromFinishedSlot_data()
5434 httpReUsingConnectionSequential_data();
5437 void tst_QNetworkReply::httpReUsingConnectionFromFinishedSlot()
5439 QByteArray response("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
5440 MiniHttpServer server(response);
5441 server.multiple = true;
5442 server.doClose = false;
5444 HttpReUsingConnectionFromFinishedSlot helper;
5447 helper.url.setScheme("http");
5448 helper.url.setPort(server.serverPort());
5449 helper.url.setHost("127.0.0.1");
5452 helper.reply1 = helper.manager.get(QNetworkRequest(helper.url));
5453 helper.reply1->setParent(&helper);
5454 connect(helper.reply1, SIGNAL(finished()), &helper, SLOT(finishedSlot()));
5455 QTestEventLoop::instance().enterLoop(4);
5456 QVERIFY(!QTestEventLoop::instance().timeout());
5458 QVERIFY(helper.reply2);
5459 QVERIFY(!helper.reply2->error());
5461 QCOMPARE(server.totalConnections, 1);
5464 class HttpRecursiveCreationHelper : public QObject {
5468 HttpRecursiveCreationHelper():
5470 requestsStartedCount_finished(0),
5471 requestsStartedCount_readyRead(0),
5472 requestsFinishedCount(0)
5475 QNetworkAccessManager manager;
5476 int requestsStartedCount_finished;
5477 int requestsStartedCount_readyRead;
5478 int requestsFinishedCount;
5480 void finishedSlot() {
5481 requestsFinishedCount++;
5483 QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
5484 QVERIFY(!reply->error());
5485 QVERIFY(reply->bytesAvailable() == 27906);
5487 if (requestsFinishedCount == 60) {
5488 QTestEventLoop::instance().exitLoop();
5492 if (requestsStartedCount_finished < 30) {
5494 requestsStartedCount_finished++;
5497 reply->deleteLater();
5499 void readyReadSlot() {
5500 QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
5501 QVERIFY(!reply->error());
5503 if (requestsStartedCount_readyRead < 30 && reply->bytesAvailable() > 27906/2) {
5505 requestsStartedCount_readyRead++;
5509 QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/fluke.gif";
5510 QNetworkRequest request(url);
5511 QNetworkReply *reply = manager.get(request);
5512 reply->setParent(this);
5513 connect(reply, SIGNAL(finished()), this, SLOT(finishedSlot()));
5514 connect(reply, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
5518 void tst_QNetworkReply::httpRecursiveCreation()
5520 // this test checks if creation of new requests to the same host properly works
5521 // from readyRead() and finished() signals
5522 HttpRecursiveCreationHelper helper;
5524 QTestEventLoop::instance().enterLoop(30);
5525 QVERIFY(!QTestEventLoop::instance().timeout());
5529 void tst_QNetworkReply::ignoreSslErrorsList_data()
5531 QTest::addColumn<QString>("url");
5532 QTest::addColumn<QList<QSslError> >("expectedSslErrors");
5533 QTest::addColumn<QNetworkReply::NetworkError>("expectedNetworkError");
5535 QList<QSslError> expectedSslErrors;
5536 QList<QSslCertificate> certs = QSslCertificate::fromPath(testDataDir + "/certs/qt-test-server-cacert.pem");
5537 QSslError rightError(QSslError::SelfSignedCertificate, certs.at(0));
5538 QSslError wrongError(QSslError::SelfSignedCertificate);
5540 QTest::newRow("SSL-failure-empty-list") << "https://" + QtNetworkSettings::serverName() + "/index.html" << expectedSslErrors << QNetworkReply::SslHandshakeFailedError;
5541 expectedSslErrors.append(wrongError);
5542 QTest::newRow("SSL-failure-wrong-error") << "https://" + QtNetworkSettings::serverName() + "/index.html" << expectedSslErrors << QNetworkReply::SslHandshakeFailedError;
5543 expectedSslErrors.append(rightError);
5544 QTest::newRow("allErrorsInExpectedList1") << "https://" + QtNetworkSettings::serverName() + "/index.html" << expectedSslErrors << QNetworkReply::NoError;
5545 expectedSslErrors.removeAll(wrongError);
5546 QTest::newRow("allErrorsInExpectedList2") << "https://" + QtNetworkSettings::serverName() + "/index.html" << expectedSslErrors << QNetworkReply::NoError;
5547 expectedSslErrors.removeAll(rightError);
5548 QTest::newRow("SSL-failure-empty-list-again") << "https://" + QtNetworkSettings::serverName() + "/index.html" << expectedSslErrors << QNetworkReply::SslHandshakeFailedError;
5551 void tst_QNetworkReply::ignoreSslErrorsList()
5553 QFETCH(QString, url);
5554 QNetworkRequest request(url);
5555 QNetworkReplyPtr reply(manager.get(request));
5557 QFETCH(QList<QSslError>, expectedSslErrors);
5558 reply->ignoreSslErrors(expectedSslErrors);
5560 QVERIFY(waitForFinish(reply) != Timeout);
5562 QFETCH(QNetworkReply::NetworkError, expectedNetworkError);
5563 QCOMPARE(reply->error(), expectedNetworkError);
5566 void tst_QNetworkReply::ignoreSslErrorsListWithSlot_data()
5568 ignoreSslErrorsList_data();
5571 // this is not a test, just a slot called in the test below
5572 void tst_QNetworkReply::ignoreSslErrorListSlot(QNetworkReply *reply, const QList<QSslError> &)
5574 reply->ignoreSslErrors(storedExpectedSslErrors);
5577 // do the same as in ignoreSslErrorsList, but ignore the errors in the slot
5578 void tst_QNetworkReply::ignoreSslErrorsListWithSlot()
5580 QFETCH(QString, url);
5581 QNetworkRequest request(url);
5582 QNetworkReplyPtr reply(manager.get(request));
5584 QFETCH(QList<QSslError>, expectedSslErrors);
5585 // store the errors to ignore them later in the slot connected below
5586 storedExpectedSslErrors = expectedSslErrors;
5587 connect(&manager, SIGNAL(sslErrors(QNetworkReply *, const QList<QSslError> &)),
5588 this, SLOT(ignoreSslErrorListSlot(QNetworkReply *, const QList<QSslError> &)));
5591 QVERIFY(waitForFinish(reply) != Timeout);
5593 QFETCH(QNetworkReply::NetworkError, expectedNetworkError);
5594 QCOMPARE(reply->error(), expectedNetworkError);
5597 void tst_QNetworkReply::sslConfiguration_data()
5599 QTest::addColumn<QSslConfiguration>("configuration");
5600 QTest::addColumn<bool>("works");
5602 QTest::newRow("empty") << QSslConfiguration() << false;
5603 QSslConfiguration conf = QSslConfiguration::defaultConfiguration();
5604 QTest::newRow("default") << conf << false; // does not contain test server cert
5605 QList<QSslCertificate> testServerCert = QSslCertificate::fromPath(testDataDir + "/certs/qt-test-server-cacert.pem");
5606 conf.setCaCertificates(testServerCert);
5607 QTest::newRow("set-root-cert") << conf << true;
5608 conf.setProtocol(QSsl::SecureProtocols);
5609 QTest::newRow("secure") << conf << true;
5612 void tst_QNetworkReply::sslConfiguration()
5614 QNetworkRequest request(QUrl("https://" + QtNetworkSettings::serverName() + "/index.html"));
5615 QFETCH(QSslConfiguration, configuration);
5616 request.setSslConfiguration(configuration);
5617 QNetworkReplyPtr reply(manager.get(request));
5619 QVERIFY(waitForFinish(reply) != Timeout);
5621 QFETCH(bool, works);
5622 QNetworkReply::NetworkError expectedError = works ? QNetworkReply::NoError : QNetworkReply::SslHandshakeFailedError;
5623 QCOMPARE(reply->error(), expectedError);
5628 void tst_QNetworkReply::getAndThenDeleteObject_data()
5630 QTest::addColumn<bool>("replyFirst");
5632 QTest::newRow("delete-reply-first") << true;
5633 QTest::newRow("delete-qnam-first") << false;
5636 void tst_QNetworkReply::getAndThenDeleteObject()
5638 QSKIP("unstable test - reply may be finished too early");
5639 // yes, this will leak if the testcase fails. I don't care. It must not fail then :P
5640 QNetworkAccessManager *manager = new QNetworkAccessManager();
5641 QNetworkRequest request("http://" + QtNetworkSettings::serverName() + "/qtest/bigfile");
5642 QNetworkReply *reply = manager->get(request);
5643 reply->setReadBufferSize(1);
5644 reply->setParent((QObject*)0); // must be 0 because else it is the manager
5649 QCoreApplication::instance()->processEvents();
5650 if (reply->bytesAvailable())
5652 if (stopWatch.elapsed() >= 30000)
5656 QVERIFY(reply->bytesAvailable());
5657 QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
5658 QVERIFY(!reply->isFinished()); // must not be finished
5660 QFETCH(bool, replyFirst);
5671 // see https://bugs.webkit.org/show_bug.cgi?id=38935
5672 void tst_QNetworkReply::symbianOpenCDataUrlCrash()
5674 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==");
5675 QUrl url = QUrl::fromEncoded(requestUrl.toLatin1());
5676 QNetworkRequest req(url);
5677 QNetworkReplyPtr reply;
5679 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, req, reply));
5681 QCOMPARE(reply->url(), url);
5682 QCOMPARE(reply->error(), QNetworkReply::NoError);
5684 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), qint64(598));
5687 void tst_QNetworkReply::getFromHttpIntoBuffer_data()
5689 QTest::addColumn<QUrl>("url");
5691 QTest::newRow("rfc-internal") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt");
5694 // Please note that the whole "zero copy" download buffer API is private right now. Do not use it.
5695 void tst_QNetworkReply::getFromHttpIntoBuffer()
5698 QNetworkRequest request(url);
5699 request.setAttribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute, 1024*128); // 128 kB
5701 QNetworkAccessManager manager;
5702 QNetworkReply *reply = manager.get(request);
5703 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
5704 QTestEventLoop::instance().enterLoop(10);
5705 QVERIFY(!QTestEventLoop::instance().timeout());
5706 QVERIFY(reply->isFinished());
5708 QFile reference(testDataDir + "/rfc3252.txt");
5709 QVERIFY(reference.open(QIODevice::ReadOnly));
5711 QCOMPARE(reference.bytesAvailable(), reply->bytesAvailable());
5712 QCOMPARE(reference.size(), reply->size());
5714 // Compare the memory buffer
5715 QVariant downloadBufferAttribute = reply->attribute(QNetworkRequest::DownloadBufferAttribute);
5716 QVERIFY(downloadBufferAttribute.isValid());
5717 QSharedPointer<char> sharedPointer = downloadBufferAttribute.value<QSharedPointer<char> >();
5718 bool memoryComparison =
5719 (0 == memcmp(static_cast<void*>(reference.readAll().data()),
5720 sharedPointer.data(), reference.size()));
5721 QVERIFY(memoryComparison);
5723 // Make sure the normal reading works
5725 QCOMPARE(reply->read(42), reference.read(42));
5726 QCOMPARE(reply->getChar(0), reference.getChar(0));
5727 QCOMPARE(reply->peek(23), reference.peek(23));
5728 QCOMPARE(reply->readLine(), reference.readLine());
5729 QCOMPARE(reference.bytesAvailable(), reply->bytesAvailable());
5730 QCOMPARE(reply->readAll(), reference.readAll());
5731 QVERIFY(reply->atEnd());
5734 // FIXME we really need to consolidate all those server implementations
5735 class GetFromHttpIntoBuffer2Server : QObject {
5741 bool serverSendsContentLength;
5742 bool chunkedEncoding;
5745 GetFromHttpIntoBuffer2Server (qint64 ds, bool sscl, bool ce) : dataSize(ds), dataSent(0),
5746 client(0), serverSendsContentLength(sscl), chunkedEncoding(ce) {
5748 connect(&server, SIGNAL(newConnection()), this, SLOT(newConnectionSlot()));
5752 return server.serverPort();
5757 void newConnectionSlot() {
5758 client = server.nextPendingConnection();
5759 client->setParent(this);
5760 connect(client, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
5761 connect(client, SIGNAL(bytesWritten(qint64)), this, SLOT(bytesWrittenSlot(qint64)));
5764 void readyReadSlot() {
5766 client->write("HTTP/1.0 200 OK\n");
5767 if (serverSendsContentLength)
5768 client->write(QString("Content-Length: " + QString::number(dataSize) + "\n").toAscii());
5769 if (chunkedEncoding)
5770 client->write(QString("Transfer-Encoding: chunked\n").toAscii());
5771 client->write("Connection: close\n\n");
5774 void bytesWrittenSlot(qint64 amount) {
5776 if (dataSent == dataSize && client) {
5779 // chunked encoding: we have to send a last "empty" chunk
5780 if (chunkedEncoding)
5781 client->write(QString("0\r\n\r\n").toAscii());
5783 client->disconnectFromHost();
5790 if (client && client->bytesToWrite() < 100*1024 && dataSent < dataSize) {
5791 qint64 amount = qMin(qint64(16*1024), dataSize - dataSent);
5792 QByteArray data(amount, '@');
5794 if (chunkedEncoding) {
5795 client->write(QString(QString("%1").arg(amount,0,16).toUpper() + "\r\n").toAscii());
5796 client->write(data.constData(), amount);
5797 client->write(QString("\r\n").toAscii());
5799 client->write(data.constData(), amount);
5807 class GetFromHttpIntoBuffer2Client : QObject {
5810 bool useDownloadBuffer;
5811 QNetworkReply *reply;
5813 QList<qint64> bytesAvailableList;
5815 GetFromHttpIntoBuffer2Client (QNetworkReply *reply, bool useDownloadBuffer, qint64 uploadSize)
5816 : useDownloadBuffer(useDownloadBuffer), reply(reply), uploadSize(uploadSize)
5818 connect(reply, SIGNAL(metaDataChanged()), this, SLOT(metaDataChangedSlot()));
5819 connect(reply, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
5820 connect(reply, SIGNAL(finished()), this, SLOT(finishedSlot()));
5824 void metaDataChangedSlot() {
5825 if (useDownloadBuffer) {
5826 QSharedPointer<char> sharedPointer = qvariant_cast<QSharedPointer<char> >(reply->attribute(QNetworkRequest::DownloadBufferAttribute));
5827 QVERIFY(!sharedPointer.isNull()); // It will be 0 if it failed
5830 // metaDataChanged needs to come before everything else
5831 QVERIFY(bytesAvailableList.isEmpty());
5834 void readyReadSlot() {
5835 QVERIFY(!reply->isFinished());
5837 qint64 bytesAvailable = reply->bytesAvailable();
5839 // bytesAvailable must never be 0
5840 QVERIFY(bytesAvailable != 0);
5842 if (bytesAvailableList.length() < 5) {
5843 // We assume that the first few times the bytes available must be less than the complete size, e.g.
5844 // the bytesAvailable() function works correctly in case of a downloadBuffer.
5845 QVERIFY(bytesAvailable < uploadSize);
5847 if (!bytesAvailableList.isEmpty()) {
5848 // Also check that the same bytesAvailable is not coming twice in a row
5849 QVERIFY(bytesAvailableList.last() != bytesAvailable);
5852 bytesAvailableList.append(bytesAvailable);
5853 // Add bytesAvailable to a list an parse
5856 void finishedSlot() {
5857 // We should have already received all readyRead
5858 QVERIFY(!bytesAvailableList.isEmpty());
5859 QVERIFY(bytesAvailableList.last() == uploadSize);
5863 void tst_QNetworkReply::getFromHttpIntoBuffer2_data()
5865 QTest::addColumn<bool>("useDownloadBuffer");
5867 QTest::newRow("use-download-buffer") << true;
5868 QTest::newRow("do-not-use-download-buffer") << false;
5871 // This test checks mostly that signal emissions are in correct order
5872 // Please note that the whole "zero copy" download buffer API is private right now. Do not use it.
5873 void tst_QNetworkReply::getFromHttpIntoBuffer2()
5875 QFETCH(bool, useDownloadBuffer);
5877 // On my Linux Desktop the results are already visible with 128 kB, however we use this to have good results.
5878 #if defined(Q_OS_WINCE_WM)
5879 // Show some mercy to non-desktop platform/s
5880 enum {UploadSize = 4*1024*1024}; // 4 MB
5882 enum {UploadSize = 32*1024*1024}; // 32 MB
5885 GetFromHttpIntoBuffer2Server server(UploadSize, true, false);
5887 QNetworkRequest request(QUrl("http://127.0.0.1:" + QString::number(server.serverPort()) + "/?bare=1"));
5888 if (useDownloadBuffer)
5889 request.setAttribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute, 1024*1024*128); // 128 MB is max allowed
5891 QNetworkAccessManager manager;
5892 QNetworkReplyPtr reply(manager.get(request));
5894 GetFromHttpIntoBuffer2Client client(reply.data(), useDownloadBuffer, UploadSize);
5896 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
5897 QTestEventLoop::instance().enterLoop(40);
5898 QCOMPARE(reply->error(), QNetworkReply::NoError);
5899 QVERIFY(!QTestEventLoop::instance().timeout());
5903 void tst_QNetworkReply::getFromHttpIntoBufferCanReadLine()
5905 QString header("HTTP/1.0 200 OK\r\nContent-Length: 7\r\n\r\nxxx\nxxx");
5907 MiniHttpServer server(header.toAscii());
5908 server.doClose = true;
5910 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
5911 request.setAttribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute, 1024*1024*128); // 128 MB is max allowed
5912 QNetworkReplyPtr reply(manager.get(request));
5914 QVERIFY(waitForFinish(reply) == Success);
5916 QCOMPARE(reply->error(), QNetworkReply::NoError);
5917 QVERIFY(reply->canReadLine());
5918 QCOMPARE(reply->read(1), QByteArray("x"));
5919 QVERIFY(reply->canReadLine());
5920 QCOMPARE(reply->read(3), QByteArray("xx\n"));
5921 QVERIFY(!reply->canReadLine());
5922 QCOMPARE(reply->readAll(), QByteArray("xxx"));
5923 QVERIFY(!reply->canReadLine());
5928 // Is handled somewhere else too, introduced this special test to have it more accessible
5929 void tst_QNetworkReply::ioGetFromHttpWithoutContentLength()
5931 QByteArray dataToSend("HTTP/1.0 200 OK\r\n\r\nHALLO! 123!");
5932 MiniHttpServer server(dataToSend);
5933 server.doClose = true;
5935 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
5936 QNetworkReplyPtr reply(manager.get(request));
5938 QVERIFY(waitForFinish(reply) == Success);
5940 QCOMPARE(reply->url(), request.url());
5941 QVERIFY(reply->isFinished());
5942 QVERIFY(reply->error() == QNetworkReply::NoError);
5945 // Is handled somewhere else too, introduced this special test to have it more accessible
5946 void tst_QNetworkReply::ioGetFromHttpBrokenChunkedEncoding()
5948 // This is wrong chunked encoding because of the X. What actually has to follow is \r\n
5949 // and then the declaration of the final 0 chunk
5950 QByteArray dataToSend("HTTP/1.0 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n3\r\nABCX");
5951 MiniHttpServer server(dataToSend);
5952 server.doClose = false; // FIXME
5954 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
5955 QNetworkReplyPtr reply(manager.get(request));
5957 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
5958 QTestEventLoop::instance().enterLoop(10);
5960 QEXPECT_FAIL(0, "We should close the socket and not just do nothing", Continue);
5961 QVERIFY(!QTestEventLoop::instance().timeout());
5962 QEXPECT_FAIL(0, "We should close the socket and not just do nothing", Continue);
5963 QVERIFY(reply->isFinished());
5964 QCOMPARE(reply->error(), QNetworkReply::NoError);
5968 // Prepare a gzip that has one chunk that expands to the size mentioned in the bugreport.
5969 // Then have a custom HTTP server that waits after this chunk so the returning gets
5971 void tst_QNetworkReply::qtbug12908compressedHttpReply()
5973 QString header("HTTP/1.0 200 OK\r\nContent-Encoding: gzip\r\nContent-Length: 63\r\n\r\n");
5975 // dd if=/dev/zero of=qtbug-12908 bs=16384 count=1 && gzip qtbug-12908 && base64 -w 0 qtbug-12908.gz
5976 QString encodedFile("H4sICDdDaUwAA3F0YnVnLTEyOTA4AO3BMQEAAADCoPVPbQwfoAAAAAAAAAAAAAAAAAAAAIC3AYbSVKsAQAAA");
5977 QByteArray decodedFile = QByteArray::fromBase64(encodedFile.toAscii());
5978 QCOMPARE(decodedFile.size(), 63);
5980 MiniHttpServer server(header.toAscii() + decodedFile);
5981 server.doClose = true;
5983 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
5984 QNetworkReplyPtr reply(manager.get(request));
5986 QVERIFY(waitForFinish(reply) == Success);
5988 QCOMPARE(reply->error(), QNetworkReply::NoError);
5989 QCOMPARE(reply->size(), qint64(16384));
5990 QCOMPARE(reply->readAll(), QByteArray(16384, '\0'));
5993 void tst_QNetworkReply::compressedHttpReplyBrokenGzip()
5995 QString header("HTTP/1.0 200 OK\r\nContent-Encoding: gzip\r\nContent-Length: 63\r\n\r\n");
5997 // dd if=/dev/zero of=qtbug-12908 bs=16384 count=1 && gzip qtbug-12908 && base64 -w 0 qtbug-12908.gz
5998 // Then change "BMQ" to "BMX"
5999 QString encodedFile("H4sICDdDaUwAA3F0YnVnLTEyOTA4AO3BMXEAAADCoPVPbQwfoAAAAAAAAAAAAAAAAAAAAIC3AYbSVKsAQAAA");
6000 QByteArray decodedFile = QByteArray::fromBase64(encodedFile.toAscii());
6001 QCOMPARE(decodedFile.size(), 63);
6003 MiniHttpServer server(header.toAscii() + decodedFile);
6004 server.doClose = true;
6006 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
6007 QNetworkReplyPtr reply(manager.get(request));
6009 QVERIFY(waitForFinish(reply) == Failure);
6011 QCOMPARE(reply->error(), QNetworkReply::ProtocolFailure);
6014 // TODO add similar test for FTP
6015 void tst_QNetworkReply::getFromUnreachableIp()
6017 QNetworkAccessManager manager;
6019 QNetworkRequest request(QUrl("http://255.255.255.255/42/23/narf/narf/narf"));
6020 QNetworkReplyPtr reply(manager.get(request));
6022 QVERIFY(waitForFinish(reply) == Failure);
6024 QVERIFY(reply->error() != QNetworkReply::NoError);
6027 void tst_QNetworkReply::qtbug4121unknownAuthentication()
6029 MiniHttpServer server(QByteArray("HTTP/1.1 401 bla\r\nWWW-Authenticate: crap\r\nContent-Length: 0\r\n\r\n"));
6030 server.doClose = false;
6032 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
6033 QNetworkAccessManager manager;
6034 QNetworkReplyPtr reply(manager.get(request));
6036 QSignalSpy authSpy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
6037 QSignalSpy finishedSpy(&manager, SIGNAL(finished(QNetworkReply*)));
6038 QSignalSpy errorSpy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError)));
6040 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6041 QTestEventLoop::instance().enterLoop(10);
6042 QVERIFY(!QTestEventLoop::instance().timeout());
6044 QCOMPARE(authSpy.count(), 0);
6045 QCOMPARE(finishedSpy.count(), 1);
6046 QCOMPARE(errorSpy.count(), 1);
6048 QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError);
6051 void tst_QNetworkReply::authenticationCacheAfterCancel_data()
6053 QTest::addColumn<QNetworkProxy>("proxy");
6054 QTest::addColumn<bool>("proxyAuth");
6055 QTest::addColumn<QUrl>("url");
6056 for (int i = 0; i < proxies.count(); ++i) {
6057 QTest::newRow("http" + proxies.at(i).tag) << proxies.at(i).proxy << proxies.at(i).requiresAuthentication << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt");
6059 QTest::newRow("https" + proxies.at(i).tag) << proxies.at(i).proxy << proxies.at(i).requiresAuthentication << QUrl("https://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt");
6064 class AuthenticationCacheHelper : public QObject
6068 AuthenticationCacheHelper()
6071 void proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *auth)
6073 if (!proxyPassword.isNull()) {
6074 auth->setUser(proxyUserName);
6075 auth->setPassword(proxyPassword);
6076 //clear credentials, if they are asked again, they were bad
6077 proxyUserName.clear();
6078 proxyPassword.clear();
6081 void authenticationRequired(QNetworkReply*,QAuthenticator *auth)
6083 if (!httpPassword.isNull()) {
6084 auth->setUser(httpUserName);
6085 auth->setPassword(httpPassword);
6086 //clear credentials, if they are asked again, they were bad
6087 httpUserName.clear();
6088 httpPassword.clear();
6092 QString httpUserName;
6093 QString httpPassword;
6094 QString proxyUserName;
6095 QString proxyPassword;
6098 /* Purpose of this test is to check credentials are cached correctly.
6099 - If user cancels authentication dialog (i.e. nothing is set to the QAuthenticator by the callback) then this is not cached
6100 - if user supplies a wrong password, then this is not cached
6101 - if user supplies a correct user/password combination then this is cached
6103 Test is checking both the proxyAuthenticationRequired and authenticationRequired signals.
6105 void tst_QNetworkReply::authenticationCacheAfterCancel()
6107 QFETCH(QNetworkProxy, proxy);
6108 QFETCH(bool, proxyAuth);
6110 QNetworkAccessManager manager;
6112 connect(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
6113 SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
6115 manager.setProxy(proxy);
6116 QSignalSpy authSpy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
6117 QSignalSpy proxyAuthSpy(&manager, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)));
6119 AuthenticationCacheHelper helper;
6120 connect(&manager, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)), &helper, SLOT(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)));
6121 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), &helper, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
6123 QNetworkRequest request(url);
6124 QNetworkReplyPtr reply;
6126 //should fail due to no credentials
6127 reply.reset(manager.get(request));
6128 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6129 QTestEventLoop::instance().enterLoop(10);
6130 QVERIFY(!QTestEventLoop::instance().timeout());
6132 QCOMPARE(reply->error(), QNetworkReply::ProxyAuthenticationRequiredError);
6133 QCOMPARE(authSpy.count(), 0);
6134 QCOMPARE(proxyAuthSpy.count(), 1);
6135 proxyAuthSpy.clear();
6137 //should fail due to bad credentials
6138 helper.proxyUserName = "qsockstest";
6139 helper.proxyPassword = "badpassword";
6140 reply.reset(manager.get(request));
6141 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6142 QTestEventLoop::instance().enterLoop(10);
6143 QVERIFY(!QTestEventLoop::instance().timeout());
6145 QEXPECT_FAIL("http+socksauth", "QTBUG-23136 - danted accepts bad authentication but blocks the connection", Continue);
6146 QEXPECT_FAIL("https+socksauth", "QTBUG-23136 - danted accepts bad authentication but blocks the connection", Continue);
6148 QCOMPARE(reply->error(), QNetworkReply::ProxyAuthenticationRequiredError);
6149 QCOMPARE(authSpy.count(), 0);
6150 QVERIFY(proxyAuthSpy.count() > 0);
6151 proxyAuthSpy.clear();
6153 //QTBUG-23136 workaround
6154 if (proxy.port() == 1081) {
6155 #ifdef QT_BUILD_INTERNAL
6156 QNetworkAccessManagerPrivate::clearCache(&manager);
6158 return; //XFAIL result above
6162 //next proxy auth should succeed, due to correct credentials
6163 helper.proxyUserName = "qsockstest";
6164 helper.proxyPassword = "password";
6167 //should fail due to no credentials
6168 reply.reset(manager.get(request));
6169 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6170 QTestEventLoop::instance().enterLoop(10);
6171 QVERIFY(!QTestEventLoop::instance().timeout());
6173 QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError);
6174 QVERIFY(authSpy.count() > 0);
6177 QVERIFY(proxyAuthSpy.count() > 0);
6178 proxyAuthSpy.clear();
6181 //should fail due to bad credentials
6182 helper.httpUserName = "baduser";
6183 helper.httpPassword = "badpassword";
6184 reply.reset(manager.get(request));
6185 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6186 QTestEventLoop::instance().enterLoop(10);
6187 QVERIFY(!QTestEventLoop::instance().timeout());
6189 QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError);
6190 QVERIFY(authSpy.count() > 0);
6193 //should be supplied from cache
6194 QCOMPARE(proxyAuthSpy.count(), 0);
6195 proxyAuthSpy.clear();
6198 //next auth should succeed, due to correct credentials
6199 helper.httpUserName = "httptest";
6200 helper.httpPassword = "httptest";
6202 reply.reset(manager.get(request));
6203 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6204 QTestEventLoop::instance().enterLoop(10);
6205 QVERIFY(!QTestEventLoop::instance().timeout());
6207 QCOMPARE(reply->error(), QNetworkReply::NoError);
6208 QVERIFY(authSpy.count() > 0);
6211 //should be supplied from cache
6212 QCOMPARE(proxyAuthSpy.count(), 0);
6213 proxyAuthSpy.clear();
6216 //next auth should use cached credentials
6217 reply.reset(manager.get(request));
6218 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6219 QTestEventLoop::instance().enterLoop(10);
6220 QVERIFY(!QTestEventLoop::instance().timeout());
6222 QCOMPARE(reply->error(), QNetworkReply::NoError);
6223 //should be supplied from cache
6224 QCOMPARE(authSpy.count(), 0);
6227 //should be supplied from cache
6228 QCOMPARE(proxyAuthSpy.count(), 0);
6229 proxyAuthSpy.clear();
6234 void tst_QNetworkReply::authenticationWithDifferentRealm()
6236 AuthenticationCacheHelper helper;
6237 QNetworkAccessManager manager;
6239 connect(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
6240 SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
6242 connect(&manager, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)), &helper, SLOT(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)));
6243 connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), &helper, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
6245 helper.httpUserName = "httptest";
6246 helper.httpPassword = "httptest";
6248 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt"));
6249 QNetworkReply* reply = manager.get(request);
6250 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6251 QTestEventLoop::instance().enterLoop(10);
6252 QVERIFY(!QTestEventLoop::instance().timeout());
6253 QCOMPARE(reply->error(), QNetworkReply::NoError);
6255 helper.httpUserName = "httptest";
6256 helper.httpPassword = "httptest";
6258 request.setUrl(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/auth-digest/"));
6259 reply = manager.get(request);
6260 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6261 QTestEventLoop::instance().enterLoop(10);
6262 QVERIFY(!QTestEventLoop::instance().timeout());
6263 QCOMPARE(reply->error(), QNetworkReply::NoError);
6266 class QtBug13431Helper : public QObject {
6269 QNetworkReply* m_reply;
6272 void replyFinished(QNetworkReply*) {
6273 QTestEventLoop::instance().exitLoop();
6276 void onReadAndReschedule() {
6277 const qint64 bytesReceived = m_reply->bytesAvailable();
6278 if (bytesReceived && m_reply->readBufferSize()) {
6279 QByteArray data = m_reply->read(bytesReceived);
6281 const int millisecDelay = static_cast<int>(bytesReceived * 1000 / m_reply->readBufferSize());
6282 m_dlTimer.start(millisecDelay);
6286 m_dlTimer.start(200);
6291 void tst_QNetworkReply::qtbug13431replyThrottling()
6293 QtBug13431Helper helper;
6295 QNetworkAccessManager nam;
6296 connect(&nam, SIGNAL(finished(QNetworkReply*)), &helper, SLOT(replyFinished(QNetworkReply*)));
6298 // Download a bigger file
6299 QNetworkRequest netRequest(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/bigfile"));
6300 helper.m_reply = nam.get(netRequest);
6302 helper.m_reply->setReadBufferSize(36000);
6304 // Schedule a timer that tries to read
6306 connect(&helper.m_dlTimer, SIGNAL(timeout()), &helper, SLOT(onReadAndReschedule()));
6307 helper.m_dlTimer.setSingleShot(true);
6308 helper.m_dlTimer.start(0);
6310 QTestEventLoop::instance().enterLoop(30);
6311 QVERIFY(!QTestEventLoop::instance().timeout());
6312 QVERIFY(helper.m_reply->isFinished());
6313 QCOMPARE(helper.m_reply->error(), QNetworkReply::NoError);
6316 void tst_QNetworkReply::httpWithNoCredentialUsage()
6318 QNetworkAccessManager manager;
6320 QSignalSpy authSpy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
6321 QSignalSpy finishedSpy(&manager, SIGNAL(finished(QNetworkReply*)));
6323 // Get with credentials, to preload authentication cache
6325 QNetworkRequest request(QUrl("http://httptest:httptest@" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi"));
6326 QNetworkReplyPtr reply(manager.get(request));
6327 QVERIFY(waitForFinish(reply) == Success);
6328 // credentials in URL, so don't expect authentication signal
6329 QCOMPARE(authSpy.count(), 0);
6330 QCOMPARE(finishedSpy.count(), 1);
6331 finishedSpy.clear();
6334 // Get with cached credentials (normal usage)
6336 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi"));
6337 QNetworkReplyPtr reply(manager.get(request));
6338 QVERIFY(waitForFinish(reply) == Success);
6339 // credentials in cache, so don't expect authentication signal
6340 QCOMPARE(authSpy.count(), 0);
6341 QCOMPARE(finishedSpy.count(), 1);
6342 finishedSpy.clear();
6345 // Do not use cached credentials (webkit cross origin usage)
6347 QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi"));
6348 request.setAttribute(QNetworkRequest::AuthenticationReuseAttribute, QNetworkRequest::Manual);
6349 QNetworkReplyPtr reply(manager.get(request));
6351 QSignalSpy errorSpy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError)));
6353 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
6354 QTestEventLoop::instance().enterLoop(10);
6355 QVERIFY(!QTestEventLoop::instance().timeout());
6357 // We check if authenticationRequired was emitted, however we do not anything in it so it should be 401
6358 QCOMPARE(authSpy.count(), 1);
6359 QCOMPARE(finishedSpy.count(), 1);
6360 QCOMPARE(errorSpy.count(), 1);
6362 QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError);
6366 void tst_QNetworkReply::qtbug15311doubleContentLength()
6368 QByteArray response("HTTP/1.0 200 OK\r\nContent-Length: 3\r\nServer: bogus\r\nContent-Length: 3\r\n\r\nABC");
6369 MiniHttpServer server(response);
6370 server.doClose = true;
6372 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
6373 QNetworkReplyPtr reply(manager.get(request));
6375 QVERIFY(waitForFinish(reply) == Success);
6377 QVERIFY(reply->isFinished());
6378 QCOMPARE(reply->error(), QNetworkReply::NoError);
6379 QCOMPARE(reply->size(), qint64(3));
6380 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), qint64(3));
6381 QCOMPARE(reply->rawHeader("Content-length"), QByteArray("3, 3"));
6382 QCOMPARE(reply->readAll(), QByteArray("ABC"));
6385 void tst_QNetworkReply::qtbug18232gzipContentLengthZero()
6387 QByteArray response("HTTP/1.0 200 OK\r\nContent-Encoding: gzip\r\nContent-Length: 0\r\n\r\n");
6388 MiniHttpServer server(response);
6389 server.doClose = true;
6391 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
6392 QNetworkReplyPtr reply(manager.get(request));
6394 QVERIFY(waitForFinish(reply) == Success);
6396 QVERIFY(reply->isFinished());
6397 QCOMPARE(reply->error(), QNetworkReply::NoError);
6398 QCOMPARE(reply->size(), qint64(0));
6399 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), qint64(0));
6400 QCOMPARE(reply->readAll(), QByteArray());
6403 // Reproduced a crash in QHttpNetworkReplyPrivate::gunzipBodyPartiallyEnd
6404 // where zlib inflateEnd was called for uninitialized zlib stream
6405 void tst_QNetworkReply::qtbug22660gzipNoContentLengthEmptyContent()
6407 // Response with no Content-Length in header and empty content
6408 QByteArray response("HTTP/1.0 200 OK\r\nContent-Encoding: gzip\r\n\r\n");
6409 MiniHttpServer server(response);
6410 server.doClose = true;
6412 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
6413 QNetworkReplyPtr reply(manager.get(request));
6415 QVERIFY(waitForFinish(reply) == Success);
6417 QVERIFY(reply->isFinished());
6418 QCOMPARE(reply->error(), QNetworkReply::NoError);
6419 QCOMPARE(reply->size(), qint64(0));
6420 QVERIFY(!reply->header(QNetworkRequest::ContentLengthHeader).isValid());
6421 QCOMPARE(reply->readAll(), QByteArray());
6424 void tst_QNetworkReply::synchronousRequest_data()
6426 QTest::addColumn<QUrl>("url");
6427 QTest::addColumn<QString>("expected");
6428 QTest::addColumn<bool>("checkContentLength");
6429 QTest::addColumn<QString>("mimeType");
6431 // ### cache, auth, proxies
6433 QTest::newRow("http")
6434 << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt")
6435 << QString("file:" + testDataDir + "/rfc3252.txt")
6437 << QString("text/plain");
6439 QTest::newRow("http-gzip")
6440 << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/deflate/rfc3252.txt")
6441 << QString("file:" + testDataDir + "/rfc3252.txt")
6442 << false // don't check content length, because it's gzip encoded
6443 // ### we would need to enflate (un-deflate) the file content and compare the sizes
6444 << QString("text/plain");
6447 QTest::newRow("https")
6448 << QUrl("https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt")
6449 << QString("file:" + testDataDir + "/rfc3252.txt")
6451 << QString("text/plain");
6454 QTest::newRow("data")
6455 << QUrl(QString::fromLatin1("data:text/plain,hello world"))
6456 << QString("data:hello world")
6457 << true // check content length
6458 << QString("text/plain");
6460 QTest::newRow("simple-file")
6461 << QUrl::fromLocalFile(testDataDir + "/rfc3252.txt")
6462 << QString("file:" + testDataDir + "/rfc3252.txt")
6467 // FIXME add testcase for failing network etc
6468 void tst_QNetworkReply::synchronousRequest()
6471 QFETCH(QString, expected);
6472 QFETCH(bool, checkContentLength);
6473 QFETCH(QString, mimeType);
6475 QNetworkRequest request(url);
6478 // workaround for HTTPS requests: add self-signed server cert to list of CA certs,
6479 // since we cannot react to the sslErrors() signal
6480 // to fix this properly we would need to have an ignoreSslErrors() method in the
6481 // QNetworkRequest, see http://bugreports.qt-project.org/browse/QTBUG-14774
6482 if (url.scheme() == "https") {
6483 QSslConfiguration sslConf;
6484 QList<QSslCertificate> certs = QSslCertificate::fromPath(testDataDir + "/certs/qt-test-server-cacert.pem");
6485 sslConf.setCaCertificates(certs);
6486 request.setSslConfiguration(sslConf);
6490 request.setAttribute(
6491 QNetworkRequest::SynchronousRequestAttribute,
6494 QNetworkReplyPtr reply;
6495 QSignalSpy finishedSpy(&manager, SIGNAL(finished(QNetworkReply*)));
6496 QSignalSpy sslErrorsSpy(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)));
6497 RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply, 0));
6498 QVERIFY(reply->isFinished());
6499 QCOMPARE(finishedSpy.count(), 0);
6500 QCOMPARE(sslErrorsSpy.count(), 0);
6502 QCOMPARE(reply->header(QNetworkRequest::ContentTypeHeader).toString(), mimeType);
6504 QByteArray expectedContent;
6506 if (expected.startsWith("file:")) {
6507 QString path = expected.mid(5);
6509 file.open(QIODevice::ReadOnly);
6510 expectedContent = file.readAll();
6511 } else if (expected.startsWith("data:")) {
6512 expectedContent = expected.mid(5).toUtf8();
6515 if (checkContentLength)
6516 QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), qint64(expectedContent.size()));
6517 QCOMPARE(reply->readAll(), expectedContent);
6519 reply->deleteLater();
6523 void tst_QNetworkReply::synchronousRequestSslFailure()
6525 // test that SSL won't be accepted with self-signed certificate,
6526 // and that we do not emit the sslError signal (in the manager that is,
6527 // in the reply we don't care)
6529 QUrl url("https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt");
6530 QNetworkRequest request(url);
6531 request.setAttribute(
6532 QNetworkRequest::SynchronousRequestAttribute,
6534 QNetworkReplyPtr reply;
6535 QSignalSpy sslErrorsSpy(&manager, SIGNAL(sslErrors(QNetworkReply *, const QList<QSslError> &)));
6536 runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply, 0);
6537 QVERIFY(reply->isFinished());
6538 QCOMPARE(reply->error(), QNetworkReply::SslHandshakeFailedError);
6539 QCOMPARE(sslErrorsSpy.count(), 0);
6543 class HttpAbortHelper : public QObject
6547 HttpAbortHelper(QNetworkReply *parent)
6551 connect(parent, SIGNAL(readyRead()), this, SLOT(readyRead()));
6562 QMetaObject::invokeMethod(&QTestEventLoop::instance(), "exitLoop", Qt::QueuedConnection);
6566 QNetworkReply *mReply;
6569 void tst_QNetworkReply::httpAbort()
6571 // FIXME Also implement one where we do a big upload and then abort().
6572 // It must not crash either.
6574 // Abort after the first readyRead()
6575 QNetworkRequest request("http://" + QtNetworkSettings::serverName() + "/qtest/bigfile");
6576 QNetworkReplyPtr reply(manager.get(request));
6577 HttpAbortHelper replyHolder(reply.data());
6578 QTestEventLoop::instance().enterLoop(10);
6579 QVERIFY(!QTestEventLoop::instance().timeout());
6580 QCOMPARE(reply->error(), QNetworkReply::OperationCanceledError);
6581 QVERIFY(reply->isFinished());
6583 // Abort immediately after the get()
6584 QNetworkReplyPtr reply2(manager.get(request));
6585 connect(reply2, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
6587 QCOMPARE(reply2->error(), QNetworkReply::OperationCanceledError);
6588 QVERIFY(reply2->isFinished());
6590 // Abort after the finished()
6591 QNetworkRequest request3("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt");
6592 QNetworkReplyPtr reply3(manager.get(request3));
6594 QVERIFY(waitForFinish(reply3) == Success);
6596 QVERIFY(reply3->isFinished());
6598 QCOMPARE(reply3->error(), QNetworkReply::NoError);
6601 void tst_QNetworkReply::dontInsertPartialContentIntoTheCache()
6603 QByteArray reply206 =
6605 "Connection: keep-alive\r\n"
6606 "Content-Type: text/plain\r\n"
6607 "Cache-control: no-cache\r\n"
6608 "Content-Range: bytes 2-6/8\r\n"
6609 "Content-length: 4\r\n"
6613 MiniHttpServer server(reply206);
6614 server.doClose = false;
6616 MySpyMemoryCache *memoryCache = new MySpyMemoryCache(&manager);
6617 manager.setCache(memoryCache);
6619 QUrl url = "http://localhost:" + QString::number(server.serverPort());
6620 QNetworkRequest request(url);
6621 request.setRawHeader("Range", "bytes=2-6");
6623 QNetworkReplyPtr reply(manager.get(request));
6625 QVERIFY(waitForFinish(reply) == Success);
6627 QVERIFY(server.totalConnections > 0);
6628 QCOMPARE(reply->readAll().constData(), "load");
6629 QCOMPARE(memoryCache->m_insertedUrls.count(), 0);
6632 void tst_QNetworkReply::httpUserAgent()
6634 QByteArray response("HTTP/1.0 200 OK\r\n\r\n");
6635 MiniHttpServer server(response);
6636 server.doClose = true;
6638 QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
6639 request.setHeader(QNetworkRequest::UserAgentHeader, "abcDEFghi");
6640 QNetworkReplyPtr reply(manager.get(request));
6642 QVERIFY(waitForFinish(reply) == Success);
6644 QVERIFY(reply->isFinished());
6645 QCOMPARE(reply->error(), QNetworkReply::NoError);
6646 QVERIFY(server.receivedData.contains("\r\nUser-Agent: abcDEFghi\r\n"));
6649 void tst_QNetworkReply::synchronousAuthenticationCache()
6651 class MiniAuthServer : public MiniHttpServer {
6653 MiniAuthServer(QThread *thread) : MiniHttpServer(QByteArray(), false, thread) {};
6654 virtual void reply() {
6657 "HTTP/1.0 401 Unauthorized\r\n"
6658 "WWW-Authenticate: Basic realm=\"QNetworkAccessManager Test Realm\"\r\n"
6659 "Content-Length: 4\r\n"
6660 "Connection: close\r\n"
6661 "Content-Type: text/plain\r\n"
6664 QRegExp rx("Authorization: Basic ([^\r\n]*)\r\n");
6665 if (rx.indexIn(receivedData) > 0) {
6666 if (QByteArray::fromBase64(rx.cap(1).toLatin1()) == "login:password") {
6668 "HTTP/1.0 200 OK\r\n"
6669 "Content-Type: text/plain\r\n"
6670 "Content-Length: 2\r\n"
6675 receivedData.clear();
6676 MiniHttpServer::reply();
6680 // when using synchronous commands, we need a different event loop for
6681 // the server thread, because the client is never returning to the
6683 QScopedPointer<QThread, QThreadCleanup> serverThread(new QThread);
6684 QScopedPointer<MiniHttpServer, QDeleteLaterCleanup> server(new MiniAuthServer(serverThread.data()));
6685 server->doClose = true;
6687 //1) URL without credentials, we are not authenticated
6689 QUrl url = "http://localhost:" + QString::number(server->serverPort()) + "/path";
6690 QNetworkRequest request(url);
6691 request.setAttribute(QNetworkRequest::SynchronousRequestAttribute, true);
6693 QNetworkReplyPtr reply(manager.get(request));
6694 QVERIFY(reply->isFinished());
6695 QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError);
6698 //2) URL with credentials, we are authenticated
6700 QUrl url = "http://login:password@localhost:" + QString::number(server->serverPort()) + "/path2";
6701 QNetworkRequest request(url);
6702 request.setAttribute(QNetworkRequest::SynchronousRequestAttribute, true);
6704 QNetworkReplyPtr reply(manager.get(request));
6705 QVERIFY(reply->isFinished());
6706 QCOMPARE(reply->error(), QNetworkReply::NoError);
6707 QCOMPARE(reply->readAll().constData(), "OK");
6710 //3) URL without credentials, we are authenticated because they are cached
6712 QUrl url = "http://localhost:" + QString::number(server->serverPort()) + "/path3";
6713 QNetworkRequest request(url);
6714 request.setAttribute(QNetworkRequest::SynchronousRequestAttribute, true);
6716 QNetworkReplyPtr reply(manager.get(request));
6717 QVERIFY(reply->isFinished());
6718 QCOMPARE(reply->error(), QNetworkReply::NoError);
6719 QCOMPARE(reply->readAll().constData(), "OK");
6723 void tst_QNetworkReply::pipelining()
6725 QString urlString("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/echo.cgi?");
6726 QList<QNetworkReplyPtr> replies;
6727 for (int a = 0; a < 20; a++) {
6728 QNetworkRequest request(urlString + QString::number(a));
6729 request.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, QVariant(true));
6730 replies.append(QNetworkReplyPtr(manager.get(request)));
6731 connect(replies.at(a), SIGNAL(finished()), this, SLOT(pipeliningHelperSlot()));
6733 QTestEventLoop::instance().enterLoop(20);
6734 QVERIFY(!QTestEventLoop::instance().timeout());
6737 void tst_QNetworkReply::pipeliningHelperSlot() {
6740 // check that pipelining was used in at least one of the replies
6741 static bool pipeliningWasUsed = false;
6742 QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
6743 bool pipeliningWasUsedInReply = reply->attribute(QNetworkRequest::HttpPipeliningWasUsedAttribute).toBool();
6744 if (pipeliningWasUsedInReply)
6745 pipeliningWasUsed = true;
6747 // check that the contents match (the response to echo.cgi?3 should return 3 etc.)
6748 QString urlQueryString = reply->url().query();
6749 QString content = reply->readAll();
6750 QVERIFY2(urlQueryString == content, "data corruption with pipelining detected");
6754 if (a == 20) { // all replies have finished
6755 QTestEventLoop::instance().exitLoop();
6756 QVERIFY2(pipeliningWasUsed, "pipelining was not used in any of the replies when trying to test pipelining");
6760 void tst_QNetworkReply::closeDuringDownload_data()
6762 QTest::addColumn<QUrl>("url");
6763 QTest::newRow("http") << QUrl("http://" + QtNetworkSettings::serverName() + "/bigfile");
6764 QTest::newRow("ftp") << QUrl("ftp://" + QtNetworkSettings::serverName() + "/qtest/bigfile");
6767 void tst_QNetworkReply::closeDuringDownload()
6770 QNetworkRequest request(url);
6771 QNetworkReply* reply = manager.get(request);
6772 connect(reply, SIGNAL(readyRead()), &QTestEventLoop::instance(), SLOT(exitLoop()));
6773 QTestEventLoop::instance().enterLoop(10);
6774 QVERIFY(!QTestEventLoop::instance().timeout());
6775 connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
6777 reply->deleteLater();
6778 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
6782 void tst_QNetworkReply::ftpAuthentication_data()
6784 QTest::addColumn<QString>("referenceName");
6785 QTest::addColumn<QString>("url");
6786 QTest::addColumn<int>("error");
6788 QTest::newRow("invalidPassword") << (testDataDir + "/rfc3252.txt") << "ftp://ftptest:invalid@" + QtNetworkSettings::serverName() + "/home/qt-test-server/ftp/qtest/rfc3252.txt" << int(QNetworkReply::AuthenticationRequiredError);
6789 QTest::newRow("validPassword") << (testDataDir + "/rfc3252.txt") << "ftp://ftptest:password@" + QtNetworkSettings::serverName() + "/home/qt-test-server/ftp/qtest/rfc3252.txt" << int(QNetworkReply::NoError);
6792 void tst_QNetworkReply::ftpAuthentication()
6794 QFETCH(QString, referenceName);
6795 QFETCH(QString, url);
6798 QFile reference(referenceName);
6799 QVERIFY(reference.open(QIODevice::ReadOnly));
6801 QNetworkRequest request(url);
6802 QNetworkReplyPtr reply;
6803 runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply);
6805 QCOMPARE(reply->url(), request.url());
6806 QCOMPARE(reply->error(), QNetworkReply::NetworkError(error));
6810 // NOTE: This test must be last testcase in tst_qnetworkreply!
6811 void tst_QNetworkReply::parentingRepliesToTheApp()
6813 QNetworkRequest request (QUrl("http://" + QtNetworkSettings::serverName()));
6814 manager.get(request)->setParent(this); // parent to this object
6815 manager.get(request)->setParent(qApp); // parent to the app
6818 QTEST_MAIN(tst_QNetworkReply)
6820 #include "tst_qnetworkreply.moc"