tests/auto/qnetworkreply/tst_qnetworkreply.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the test suite of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 
       
    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/QTemporaryFile>
       
    51 #include <QtNetwork/QTcpServer>
       
    52 #include <QtNetwork/QTcpSocket>
       
    53 #include <QtNetwork/QLocalSocket>
       
    54 #include <QtNetwork/QLocalServer>
       
    55 #include <QtNetwork/QHostInfo>
       
    56 #include <QtNetwork/QFtp>
       
    57 #include <QtNetwork/qauthenticator.h>
       
    58 #include <QtNetwork/qnetworkaccessmanager.h>
       
    59 #include <QtNetwork/qnetworkrequest.h>
       
    60 #include <QtNetwork/qnetworkreply.h>
       
    61 #include <QtNetwork/qnetworkcookie.h>
       
    62 #ifndef QT_NO_OPENSSL
       
    63 #include <QtNetwork/qsslerror.h>
       
    64 #include <QtNetwork/qsslconfiguration.h>
       
    65 #endif
       
    66 
       
    67 #include <time.h>
       
    68 
       
    69 #include "private/qnetworkaccessmanager_p.h"
       
    70 
       
    71 #ifdef Q_OS_SYMBIAN
       
    72 #define SRCDIR "."
       
    73 #endif
       
    74 
       
    75 #include "../network-settings.h"
       
    76 
       
    77 
       
    78 Q_DECLARE_METATYPE(QNetworkReply*)
       
    79 Q_DECLARE_METATYPE(QAuthenticator*)
       
    80 Q_DECLARE_METATYPE(QNetworkProxy)
       
    81 Q_DECLARE_METATYPE(QNetworkProxyQuery)
       
    82 Q_DECLARE_METATYPE(QList<QNetworkProxy>)
       
    83 Q_DECLARE_METATYPE(QNetworkReply::NetworkError)
       
    84 
       
    85 class QNetworkReplyPtr: public QSharedPointer<QNetworkReply>
       
    86 {
       
    87 public:
       
    88     inline QNetworkReplyPtr(QNetworkReply *ptr = 0)
       
    89         : QSharedPointer<QNetworkReply>(ptr)
       
    90     { }
       
    91 
       
    92     inline operator QNetworkReply *() const { return data(); }
       
    93 };
       
    94 
       
    95 class MyCookieJar;
       
    96 class tst_QNetworkReply: public QObject
       
    97 {
       
    98     Q_OBJECT
       
    99 
       
   100     struct ProxyData {
       
   101         ProxyData(const QNetworkProxy &p, const QByteArray &t, bool auth)
       
   102             : tag(t), proxy(p), requiresAuthentication(auth)
       
   103         { }
       
   104         QByteArray tag;
       
   105         QNetworkProxy proxy;
       
   106         bool requiresAuthentication;
       
   107     };
       
   108 
       
   109     QEventLoop *loop;
       
   110     enum RunSimpleRequestReturn { Timeout = 0, Success, Failure };
       
   111     int returnCode;
       
   112     QString testFileName;
       
   113 #if !defined Q_OS_WIN
       
   114     QString wronlyFileName;
       
   115 #endif
       
   116     QString uniqueExtension;
       
   117     QList<ProxyData> proxies;
       
   118     QNetworkAccessManager manager;
       
   119     MyCookieJar *cookieJar;
       
   120 #ifndef QT_NO_OPENSSL
       
   121     QSslConfiguration storedSslConfiguration;
       
   122     QList<QSslError> storedExpectedSslErrors;
       
   123 #endif
       
   124 
       
   125 public:
       
   126     tst_QNetworkReply();
       
   127     ~tst_QNetworkReply();
       
   128     QString runSimpleRequest(QNetworkAccessManager::Operation op, const QNetworkRequest &request,
       
   129                              QNetworkReplyPtr &reply, const QByteArray &data = QByteArray());
       
   130 
       
   131 public Q_SLOTS:
       
   132     void finished();
       
   133     void gotError();
       
   134     void authenticationRequired(QNetworkReply*,QAuthenticator*);
       
   135     void proxyAuthenticationRequired(const QNetworkProxy &,QAuthenticator*);
       
   136 
       
   137 #ifndef QT_NO_OPENSSL
       
   138     void sslErrors(QNetworkReply*,const QList<QSslError> &);
       
   139     void storeSslConfiguration();
       
   140     void ignoreSslErrorListSlot(QNetworkReply *reply, const QList<QSslError> &);
       
   141 #endif
       
   142 
       
   143 protected Q_SLOTS:
       
   144     void nestedEventLoops_slot();
       
   145 
       
   146 private Q_SLOTS:
       
   147     void init();
       
   148     void cleanup();
       
   149     void initTestCase();
       
   150     void cleanupTestCase();
       
   151 
       
   152     void stateChecking();
       
   153     void invalidProtocol();
       
   154     void getFromData_data();
       
   155     void getFromData();
       
   156     void getFromFile();
       
   157     void getFromFileSpecial_data();
       
   158     void getFromFileSpecial();
       
   159     void getFromFtp_data();
       
   160     void getFromFtp();
       
   161     void getFromHttp_data();
       
   162     void getFromHttp();
       
   163     void getErrors_data();
       
   164     void getErrors();
       
   165     void putToFile_data();
       
   166     void putToFile();
       
   167     void putToFtp_data();
       
   168     void putToFtp();
       
   169     void putToHttp_data();
       
   170     void putToHttp();
       
   171     void postToHttp_data();
       
   172     void postToHttp();
       
   173     void deleteFromHttp_data();
       
   174     void deleteFromHttp();
       
   175     void putGetDeleteGetFromHttp_data();
       
   176     void putGetDeleteGetFromHttp();
       
   177 
       
   178     void ioGetFromData_data();
       
   179     void ioGetFromData();
       
   180     void ioGetFromFileSpecial_data();
       
   181     void ioGetFromFileSpecial();
       
   182     void ioGetFromFile_data();
       
   183     void ioGetFromFile();
       
   184     void ioGetFromFtp_data();
       
   185     void ioGetFromFtp();
       
   186     void ioGetFromFtpWithReuse();
       
   187     void ioGetFromHttp();
       
   188 
       
   189     void ioGetFromHttpWithReuseParallel();
       
   190     void ioGetFromHttpWithReuseSequential();
       
   191     void ioGetFromHttpWithAuth();
       
   192     void ioGetFromHttpWithProxyAuth();
       
   193     void ioGetFromHttpWithSocksProxy();
       
   194 #ifndef QT_NO_OPENSSL
       
   195     void ioGetFromHttpsWithSslErrors();
       
   196     void ioGetFromHttpsWithIgnoreSslErrors();
       
   197     void ioGetFromHttpsWithSslHandshakeError();
       
   198 #endif
       
   199     void ioGetFromHttpBrokenServer_data();
       
   200     void ioGetFromHttpBrokenServer();
       
   201 
       
   202     void ioGetWithManyProxies_data();
       
   203     void ioGetWithManyProxies();
       
   204 
       
   205     void ioPutToFileFromFile_data();
       
   206     void ioPutToFileFromFile();
       
   207     void ioPutToFileFromSocket_data();
       
   208     void ioPutToFileFromSocket();
       
   209     void ioPutToFileFromLocalSocket_data();
       
   210     void ioPutToFileFromLocalSocket();
       
   211     void ioPutToFileFromProcess_data();
       
   212     void ioPutToFileFromProcess();
       
   213     void ioPutToFtpFromFile_data();
       
   214     void ioPutToFtpFromFile();
       
   215     void ioPutToHttpFromFile_data();
       
   216     void ioPutToHttpFromFile();
       
   217     void ioPostToHttpFromFile_data();
       
   218     void ioPostToHttpFromFile();
       
   219     void ioPostToHttpFromSocket_data();
       
   220     void ioPostToHttpFromSocket();
       
   221     void ioPostToHttpFromMiddleOfFileToEnd();
       
   222     void ioPostToHttpFromMiddleOfFileFiveBytes();
       
   223     void ioPostToHttpFromMiddleOfQBufferFiveBytes();
       
   224     void ioPostToHttpNoBufferFlag();
       
   225     void ioPostToHttpUploadProgress();
       
   226     void ioPostToHttpEmtpyUploadProgress();
       
   227 
       
   228     void rateControl_data();
       
   229     void rateControl();
       
   230     void downloadPerformance();
       
   231     void uploadPerformance();
       
   232     void performanceControlRate();
       
   233     void httpUploadPerformance();
       
   234     void httpDownloadPerformance_data();
       
   235     void httpDownloadPerformance();
       
   236 
       
   237     void downloadProgress_data();
       
   238     void downloadProgress();
       
   239     void uploadProgress_data();
       
   240     void uploadProgress();
       
   241 
       
   242     void chaining_data();
       
   243     void chaining();
       
   244 
       
   245     void receiveCookiesFromHttp_data();
       
   246     void receiveCookiesFromHttp();
       
   247     void sendCookies_data();
       
   248     void sendCookies();
       
   249 
       
   250     void nestedEventLoops();
       
   251 
       
   252     void httpProxyCommands_data();
       
   253     void httpProxyCommands();
       
   254     void proxyChange();
       
   255     void authorizationError_data();
       
   256     void authorizationError();
       
   257 
       
   258     void httpConnectionCount();
       
   259 
       
   260 #ifndef QT_NO_OPENSSL
       
   261     void ioPostToHttpsUploadProgress();
       
   262     void ignoreSslErrorsList_data();
       
   263     void ignoreSslErrorsList();
       
   264     void ignoreSslErrorsListWithSlot_data();
       
   265     void ignoreSslErrorsListWithSlot();
       
   266 #endif
       
   267 };
       
   268 
       
   269 QT_BEGIN_NAMESPACE
       
   270 
       
   271 namespace QTest {
       
   272     template<>
       
   273     char *toString(const QNetworkReply::NetworkError& code)
       
   274     {
       
   275         const QMetaObject *mo = &QNetworkReply::staticMetaObject;
       
   276         int index = mo->indexOfEnumerator("NetworkError");
       
   277         if (index == -1)
       
   278             return qstrdup("");
       
   279 
       
   280         QMetaEnum qme = mo->enumerator(index);
       
   281         return qstrdup(qme.valueToKey(code));
       
   282     }
       
   283 
       
   284     template<>
       
   285     char *toString(const QNetworkCookie &cookie)
       
   286     {
       
   287         return qstrdup(cookie.toRawForm());
       
   288     }
       
   289 
       
   290     template<>
       
   291     char *toString(const QList<QNetworkCookie> &list)
       
   292     {
       
   293         QString result = "QList(";
       
   294         bool first = true;
       
   295         foreach (QNetworkCookie cookie, list) {
       
   296             if (!first)
       
   297                 result += ", ";
       
   298             first = false;
       
   299             result += QString::fromLatin1("QNetworkCookie(%1)").arg(QLatin1String(cookie.toRawForm()));
       
   300         }
       
   301 
       
   302         return qstrdup(result.append(')').toLocal8Bit());
       
   303     }
       
   304 }
       
   305 
       
   306 QT_END_NAMESPACE
       
   307 
       
   308 #define RUN_REQUEST(call)                       \
       
   309     do {                                        \
       
   310         QString errorMsg = call;                \
       
   311         if (!errorMsg.isEmpty())                \
       
   312             QFAIL(qPrintable(errorMsg));        \
       
   313     } while (0);
       
   314 
       
   315 class MiniHttpServer: public QTcpServer
       
   316 {
       
   317     Q_OBJECT
       
   318     QTcpSocket *client;
       
   319 
       
   320 public:
       
   321     QByteArray dataToTransmit;
       
   322     QByteArray receivedData;
       
   323     bool doClose;
       
   324 
       
   325     MiniHttpServer(const QByteArray &data) : client(0), dataToTransmit(data), doClose(true)
       
   326     {
       
   327         listen();
       
   328         connect(this, SIGNAL(newConnection()), this, SLOT(doAccept()));
       
   329     }
       
   330 
       
   331 public slots:
       
   332     void doAccept()
       
   333     {
       
   334         client = nextPendingConnection();
       
   335         connect(client, SIGNAL(readyRead()), this, SLOT(sendData()));
       
   336     }
       
   337 
       
   338     void sendData()
       
   339     {
       
   340         receivedData += client->readAll();
       
   341         if (receivedData.contains("\r\n\r\n") ||
       
   342             receivedData.contains("\n\n")) {
       
   343             client->write(dataToTransmit);
       
   344             if (doClose) {
       
   345                 client->disconnectFromHost();
       
   346                 disconnect(client, 0, this, 0);
       
   347                 client = 0;
       
   348             }
       
   349         }
       
   350     }
       
   351 };
       
   352 
       
   353 class MyCookieJar: public QNetworkCookieJar
       
   354 {
       
   355 public:
       
   356     inline QList<QNetworkCookie> allCookies() const
       
   357         { return QNetworkCookieJar::allCookies(); }
       
   358     inline void setAllCookies(const QList<QNetworkCookie> &cookieList)
       
   359         { QNetworkCookieJar::setAllCookies(cookieList); }
       
   360 };
       
   361 
       
   362 class MyProxyFactory: public QNetworkProxyFactory
       
   363 {
       
   364 public:
       
   365     int callCount;
       
   366     QList<QNetworkProxy> toReturn;
       
   367     QNetworkProxyQuery lastQuery;
       
   368     inline MyProxyFactory() { clear(); }
       
   369 
       
   370     inline void clear()
       
   371     {
       
   372         callCount = 0;
       
   373         toReturn = QList<QNetworkProxy>() << QNetworkProxy::DefaultProxy;
       
   374         lastQuery = QNetworkProxyQuery();
       
   375     }
       
   376 
       
   377     virtual QList<QNetworkProxy> queryProxy(const QNetworkProxyQuery &query)
       
   378     {
       
   379         lastQuery = query;
       
   380         ++callCount;
       
   381         return toReturn;
       
   382     }
       
   383 };
       
   384 
       
   385 class DataReader: public QObject
       
   386 {
       
   387     Q_OBJECT
       
   388 public:
       
   389     qint64 totalBytes;
       
   390     QByteArray data;
       
   391     QIODevice *device;
       
   392     bool accumulate;
       
   393     DataReader(QIODevice *dev, bool acc = true) : totalBytes(0), device(dev), accumulate(acc)
       
   394     {
       
   395         connect(device, SIGNAL(readyRead()), SLOT(doRead()));
       
   396     }
       
   397 
       
   398 public slots:
       
   399     void doRead()
       
   400     {
       
   401         QByteArray buffer;
       
   402         buffer.resize(device->bytesAvailable());
       
   403         qint64 bytesRead = device->read(buffer.data(), device->bytesAvailable());
       
   404         if (bytesRead == -1) {
       
   405             QTestEventLoop::instance().exitLoop();
       
   406             return;
       
   407         }
       
   408         buffer.truncate(bytesRead);
       
   409         totalBytes += bytesRead;
       
   410 
       
   411         if (accumulate)
       
   412             data += buffer;
       
   413     }
       
   414 };
       
   415 
       
   416 class FixedSizeDataGenerator : public QIODevice
       
   417 {
       
   418     Q_OBJECT
       
   419     enum { Idle, Started, Stopped } state;
       
   420 public:
       
   421     FixedSizeDataGenerator(qint64 size) : state(Idle)
       
   422     { open(ReadOnly | Unbuffered);
       
   423       toBeGeneratedTotalCount = toBeGeneratedCount = size;
       
   424     }
       
   425 
       
   426     virtual qint64 bytesAvailable() const
       
   427     {
       
   428         return state == Started ? toBeGeneratedCount + QIODevice::bytesAvailable() : 0;
       
   429     }
       
   430 
       
   431     virtual bool isSequential() const{
       
   432         return false;
       
   433     }
       
   434 
       
   435     virtual bool reset() const{
       
   436         return false;
       
   437     }
       
   438 
       
   439     qint64 size() const {
       
   440         return toBeGeneratedTotalCount;
       
   441     }
       
   442 
       
   443 public slots:
       
   444     void start() { state = Started; emit readyRead(); }
       
   445 
       
   446 protected:
       
   447     virtual qint64 readData(char *data, qint64 maxlen)
       
   448     {
       
   449         memset(data, '@', maxlen);
       
   450 
       
   451         if (toBeGeneratedCount <= 0) {
       
   452             return -1;
       
   453         }
       
   454 
       
   455         qint64 n = qMin(maxlen, toBeGeneratedCount);
       
   456         toBeGeneratedCount -= n;
       
   457 
       
   458         if (toBeGeneratedCount <= 0) {
       
   459             // make sure this is a queued connection!
       
   460             emit readChannelFinished();
       
   461         }
       
   462 
       
   463         return n;
       
   464     }
       
   465     virtual qint64 writeData(const char *, qint64)
       
   466     { return -1; }
       
   467 
       
   468     qint64 toBeGeneratedCount;
       
   469     qint64 toBeGeneratedTotalCount;
       
   470 };
       
   471 
       
   472 
       
   473 class DataGenerator: public QIODevice
       
   474 {
       
   475     Q_OBJECT
       
   476     enum { Idle, Started, Stopped } state;
       
   477 public:
       
   478     DataGenerator() : state(Idle)
       
   479     { open(ReadOnly); }
       
   480 
       
   481     virtual bool isSequential() const { return true; }
       
   482     virtual qint64 bytesAvailable() const { return state == Started ? 1024*1024 : 0; }
       
   483 
       
   484 public slots:
       
   485     void start() { state = Started; emit readyRead(); }
       
   486     void stop() { state = Stopped; emit readyRead(); }
       
   487 
       
   488 protected:
       
   489     virtual qint64 readData(char *data, qint64 maxlen)
       
   490     {
       
   491         if (state == Stopped)
       
   492             return -1;          // EOF
       
   493 
       
   494         // return as many bytes as are wanted
       
   495         memset(data, '@', maxlen);
       
   496         return maxlen;
       
   497     }
       
   498     virtual qint64 writeData(const char *, qint64)
       
   499     { return -1; }
       
   500 };
       
   501 
       
   502 
       
   503 
       
   504 class SocketPair: public QObject
       
   505 {
       
   506     Q_OBJECT
       
   507 public:
       
   508     QIODevice *endPoints[2];
       
   509 
       
   510     SocketPair(QObject *parent = 0)
       
   511         : QObject(parent)
       
   512     {
       
   513         endPoints[0] = endPoints[1] = 0;
       
   514     }
       
   515 
       
   516     bool create()
       
   517     {
       
   518         QTcpServer server;
       
   519         server.listen();
       
   520 
       
   521         QTcpSocket *active = new QTcpSocket(this);
       
   522         active->connectToHost("127.0.0.1", server.serverPort());
       
   523 #ifndef Q_OS_SYMBIAN
       
   524         // need more time as working with embedded
       
   525 		// device and testing from emualtor
       
   526 		// things tend to get slower
       
   527         if (!active->waitForConnected(1000))
       
   528             return false;
       
   529 
       
   530         if (!server.waitForNewConnection(1000))
       
   531             return false;
       
   532 #else
       
   533         if (!active->waitForConnected(100))
       
   534             return false;
       
   535 
       
   536         if (!server.waitForNewConnection(100))
       
   537             return false;
       
   538 #endif
       
   539         QTcpSocket *passive = server.nextPendingConnection();
       
   540         passive->setParent(this);
       
   541 
       
   542         endPoints[0] = active;
       
   543         endPoints[1] = passive;
       
   544         return true;
       
   545     }
       
   546 };
       
   547 
       
   548 class FastSender: public QThread
       
   549 {
       
   550     Q_OBJECT
       
   551     QSemaphore ready;
       
   552     qint64 wantedSize;
       
   553     int port;
       
   554 public:
       
   555     int transferRate;
       
   556     QWaitCondition cond;
       
   557     FastSender(qint64 size)
       
   558         : wantedSize(size), port(-1), transferRate(-1)
       
   559     {
       
   560         start();
       
   561         ready.acquire();
       
   562     }
       
   563 
       
   564     inline int serverPort() const { return port; }
       
   565 
       
   566 protected:
       
   567     void run()
       
   568     {
       
   569         QTcpServer server;
       
   570         server.listen();
       
   571         port = server.serverPort();
       
   572         ready.release();
       
   573 
       
   574         server.waitForNewConnection(-1);
       
   575         QTcpSocket *client = server.nextPendingConnection();
       
   576 
       
   577         // get the "request" packet
       
   578         if (!client->waitForReadyRead(2000)) {
       
   579             qDebug() << client->error() << "waiting for \"request\" packet";
       
   580             return;
       
   581         }
       
   582         client->readAll();      // we're not interested in the actual contents
       
   583 
       
   584         enum { BlockSize = 256 };
       
   585         QByteArray data;
       
   586         {
       
   587             QDataStream stream(&data, QIODevice::WriteOnly);
       
   588             stream << QVariantMap() << QByteArray(BlockSize, 'a');
       
   589         }
       
   590         qint32 size = data.size();
       
   591 
       
   592         // write a bunch of bytes to fill up the buffers
       
   593         do {
       
   594             client->write((char*)&size, sizeof size);
       
   595             client->write(data);
       
   596             while (client->bytesToWrite() > 0)
       
   597                 if (!client->waitForBytesWritten(0))
       
   598                     break;
       
   599         } while (client->bytesToWrite() == 0);
       
   600 
       
   601         // the kernel buffer is full
       
   602         // clean up QAbstractSocket's residue:
       
   603         while (client->bytesToWrite() > 0)
       
   604             if (!client->waitForBytesWritten(2000)) {
       
   605                 qDebug() << client->error() << "cleaning up residue";
       
   606                 return;
       
   607             }
       
   608 
       
   609         // now write in "blocking mode"
       
   610         QTime timer;
       
   611         timer.start();
       
   612         qint64 totalBytes = 0;
       
   613         while (totalBytes < wantedSize) {
       
   614             int bytesToWrite = wantedSize - totalBytes;
       
   615             Q_ASSERT(bytesToWrite);
       
   616             if (bytesToWrite > BlockSize) {
       
   617                 bytesToWrite = BlockSize;
       
   618             } else {
       
   619                 QDataStream stream(&data, QIODevice::WriteOnly);
       
   620                 stream << QVariantMap() << QByteArray(bytesToWrite, 'b');
       
   621             }
       
   622             size = data.size();
       
   623             client->write((char*)&size, sizeof size);
       
   624             client->write(data);
       
   625             totalBytes += bytesToWrite;
       
   626 
       
   627             while (client->bytesToWrite() > 0)
       
   628                 if (!client->waitForBytesWritten(2000)) {
       
   629                     qDebug() << client->error() << "blocking write";
       
   630                     return;
       
   631                 }
       
   632 //            qDebug() << bytesToWrite << "bytes written now;"
       
   633 //                     << totalBytes << "total ("
       
   634 //                     << totalBytes*100/wantedSize << "% complete);"
       
   635 //                     << timer.elapsed() << "ms elapsed";
       
   636         }
       
   637 
       
   638         transferRate = totalBytes * 1000 / timer.elapsed();
       
   639         qDebug() << "flushed" << totalBytes << "bytes in" << timer.elapsed() << "ms: rate =" << transferRate;
       
   640 
       
   641         // write a "close connection" packet
       
   642         {
       
   643             QDataStream stream(&data, QIODevice::WriteOnly);
       
   644             stream << QVariantMap() << QByteArray();
       
   645         }
       
   646         size = data.size();
       
   647         client->write((char*)&size, sizeof size);
       
   648         client->write(data);
       
   649     }
       
   650 };
       
   651 
       
   652 class RateControlledReader: public QObject
       
   653 {
       
   654     Q_OBJECT
       
   655     QIODevice *device;
       
   656     int bytesToRead;
       
   657     int interval;
       
   658 public:
       
   659     qint64 totalBytesRead;
       
   660     RateControlledReader(QIODevice *dev, int kbPerSec)
       
   661         : device(dev), totalBytesRead(0)
       
   662     {
       
   663         // determine how often we have to wake up
       
   664         bytesToRead = kbPerSec * 1024 / 20;
       
   665         interval = 50;
       
   666 
       
   667         qDebug() << "RateControlledReader: going to read" << bytesToRead
       
   668                  << "bytes every" << interval << "ms";
       
   669         qDebug() << "actual rate will be"
       
   670                  << (bytesToRead * 1000 / interval) << "bytes/sec (wanted"
       
   671                  << kbPerSec * 1024 << "bytes/sec)";
       
   672         startTimer(interval);
       
   673     }
       
   674 
       
   675 protected:
       
   676     void timerEvent(QTimerEvent *)
       
   677     {
       
   678         qint64 bytesRead = 0;
       
   679         QTime stopWatch;
       
   680         stopWatch.start();
       
   681         do {
       
   682             if (device->bytesAvailable() == 0)
       
   683                 if (stopWatch.elapsed() > 10 || !device->waitForReadyRead(5))
       
   684                     break;
       
   685             QByteArray data = device->read(bytesToRead - bytesRead);
       
   686             bytesRead += data.size();
       
   687         } while (bytesRead < bytesToRead);// && stopWatch.elapsed() < interval/4);
       
   688         totalBytesRead += bytesRead;
       
   689 
       
   690         if (bytesRead < bytesToRead)
       
   691             qWarning() << bytesToRead - bytesRead << "bytes not read";
       
   692     }
       
   693 };
       
   694 
       
   695 class TimedSender: public QThread
       
   696 {
       
   697     Q_OBJECT
       
   698     qint64 totalBytes;
       
   699     QSemaphore ready;
       
   700     QByteArray dataToSend;
       
   701     QTcpSocket *client;
       
   702     int timeout;
       
   703     int port;
       
   704 public:
       
   705     int transferRate;
       
   706     TimedSender(int ms)
       
   707         : totalBytes(0), timeout(ms), port(-1), transferRate(-1)
       
   708     {
       
   709         dataToSend = QByteArray(16*1024, '@');
       
   710         start();
       
   711         ready.acquire();
       
   712     }
       
   713 
       
   714     inline int serverPort() const { return port; }
       
   715 
       
   716 private slots:
       
   717     void writeMore()
       
   718     {
       
   719         while (client->bytesToWrite() < 128 * 1024) {
       
   720             writePacket(dataToSend);
       
   721         }
       
   722     }
       
   723 
       
   724 protected:
       
   725     void run()
       
   726     {
       
   727         QTcpServer server;
       
   728         server.listen();
       
   729         port = server.serverPort();
       
   730         ready.release();
       
   731 
       
   732         server.waitForNewConnection(-1);
       
   733         client = server.nextPendingConnection();
       
   734 
       
   735         writeMore();
       
   736         connect(client, SIGNAL(bytesWritten(qint64)), SLOT(writeMore()), Qt::DirectConnection);
       
   737 
       
   738         QEventLoop eventLoop;
       
   739         QTimer::singleShot(timeout, &eventLoop, SLOT(quit()));
       
   740 
       
   741         QTime timer;
       
   742         timer.start();
       
   743         eventLoop.exec();
       
   744         disconnect(client, SIGNAL(bytesWritten(qint64)), this, 0);
       
   745 
       
   746         // wait for the connection to shut down
       
   747         client->disconnectFromHost();
       
   748         if (!client->waitForDisconnected(10000))
       
   749             return;
       
   750 
       
   751         transferRate = totalBytes * 1000 / timer.elapsed();
       
   752         qDebug() << "TimedSender::run" << "receive rate:" << (transferRate / 1024) << "kB/s in"
       
   753                  << timer.elapsed() << "ms";
       
   754     }
       
   755 
       
   756     void writePacket(const QByteArray &array)
       
   757     {
       
   758         client->write(array);
       
   759         totalBytes += array.size();
       
   760     }
       
   761 };
       
   762 
       
   763 class ThreadedDataReader: public QThread
       
   764 {
       
   765     Q_OBJECT
       
   766     // used to make the constructor only return after the tcp server started listening
       
   767     QSemaphore ready;
       
   768     QTcpSocket *client;
       
   769     int timeout;
       
   770     int port;
       
   771 public:
       
   772     qint64 transferRate;
       
   773     ThreadedDataReader()
       
   774         : port(-1), transferRate(-1)
       
   775     {
       
   776         start();
       
   777         ready.acquire();
       
   778     }
       
   779 
       
   780     inline int serverPort() const { return port; }
       
   781 
       
   782 protected:
       
   783     void run()
       
   784     {
       
   785         QTcpServer server;
       
   786         server.listen();
       
   787         port = server.serverPort();
       
   788         ready.release();
       
   789 
       
   790         server.waitForNewConnection(-1);
       
   791         client = server.nextPendingConnection();
       
   792 
       
   793         QEventLoop eventLoop;
       
   794         DataReader reader(client, false);
       
   795         QObject::connect(client, SIGNAL(disconnected()), &eventLoop, SLOT(quit()));
       
   796 
       
   797         QTime timer;
       
   798         timer.start();
       
   799         eventLoop.exec();
       
   800         qint64 elapsed = timer.elapsed();
       
   801 
       
   802         transferRate = reader.totalBytes * 1000 / elapsed;
       
   803         qDebug() << "ThreadedDataReader::run" << "send rate:" << (transferRate / 1024) << "kB/s in" << elapsed << "msec";
       
   804     }
       
   805 };
       
   806 
       
   807 class ThreadedDataReaderHttpServer: public QThread
       
   808 {
       
   809     Q_OBJECT
       
   810     // used to make the constructor only return after the tcp server started listening
       
   811     QSemaphore ready;
       
   812     QTcpSocket *client;
       
   813     int timeout;
       
   814     int port;
       
   815 public:
       
   816     qint64 transferRate;
       
   817     ThreadedDataReaderHttpServer()
       
   818         : port(-1), transferRate(-1)
       
   819     {
       
   820         start();
       
   821         ready.acquire();
       
   822     }
       
   823 
       
   824     inline int serverPort() const { return port; }
       
   825 
       
   826 protected:
       
   827     void run()
       
   828     {
       
   829         QTcpServer server;
       
   830         server.listen();
       
   831         port = server.serverPort();
       
   832         ready.release();
       
   833 
       
   834         server.waitForNewConnection(-1);
       
   835         client = server.nextPendingConnection();
       
   836         client->write("HTTP/1.0 200 OK\r\n");
       
   837         client->write("Content-length: 0\r\n");
       
   838         client->write("\r\n");
       
   839         client->flush();
       
   840 
       
   841         QCoreApplication::processEvents();
       
   842 
       
   843         QEventLoop eventLoop;
       
   844         DataReader reader(client, false);
       
   845         QObject::connect(client, SIGNAL(disconnected()), &eventLoop, SLOT(quit()));
       
   846 
       
   847         QTime timer;
       
   848         timer.start();
       
   849         eventLoop.exec();
       
   850         qint64 elapsed = timer.elapsed();
       
   851 
       
   852         transferRate = reader.totalBytes * 1000 / elapsed;
       
   853         qDebug() << "ThreadedDataReaderHttpServer::run" << "send rate:" << (transferRate / 1024) << "kB/s in" << elapsed << "msec";
       
   854     }
       
   855 };
       
   856 
       
   857 class HttpDownloadPerformanceClient : QObject {
       
   858     Q_OBJECT;
       
   859     QIODevice *device;
       
   860     public:
       
   861     HttpDownloadPerformanceClient (QIODevice *dev) : device(dev){
       
   862         connect(dev, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
       
   863     }
       
   864 
       
   865     public slots:
       
   866     void readyReadSlot() {
       
   867         device->readAll();
       
   868     }
       
   869 
       
   870 };
       
   871 
       
   872 class HttpDownloadPerformanceServer : QObject {
       
   873     Q_OBJECT;
       
   874     qint64 dataSize;
       
   875     qint64 dataSent;
       
   876     QTcpServer server;
       
   877     QTcpSocket *client;
       
   878     bool serverSendsContentLength;
       
   879     bool chunkedEncoding;
       
   880 
       
   881 public:
       
   882     HttpDownloadPerformanceServer (qint64 ds, bool sscl, bool ce) : dataSize(ds), dataSent(0),
       
   883     client(0), serverSendsContentLength(sscl), chunkedEncoding(ce) {
       
   884         server.listen();
       
   885         connect(&server, SIGNAL(newConnection()), this, SLOT(newConnectionSlot()));
       
   886     }
       
   887 
       
   888     int serverPort() {
       
   889         return server.serverPort();
       
   890     }
       
   891 
       
   892 public slots:
       
   893 
       
   894     void newConnectionSlot() {
       
   895         client = server.nextPendingConnection();
       
   896         client->setParent(this);
       
   897         connect(client, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
       
   898         connect(client, SIGNAL(bytesWritten(qint64)), this, SLOT(bytesWrittenSlot(qint64)));
       
   899     }
       
   900 
       
   901     void readyReadSlot() {
       
   902         client->readAll();
       
   903         client->write("HTTP/1.0 200 OK\n");
       
   904         if (serverSendsContentLength)
       
   905             client->write(QString("Content-Length: " + QString::number(dataSize) + "\n").toAscii());
       
   906         if (chunkedEncoding)
       
   907             client->write(QString("Transfer-Encoding: chunked\n").toAscii());
       
   908         client->write("Connection: close\n\n");
       
   909     }
       
   910 
       
   911     void bytesWrittenSlot(qint64 amount) {
       
   912         Q_UNUSED(amount);
       
   913         if (dataSent == dataSize && client) {
       
   914             // close eventually
       
   915 
       
   916             // chunked encoding: we have to send a last "empty" chunk
       
   917             if (chunkedEncoding)
       
   918                 client->write(QString("0\r\n\r\n").toAscii());
       
   919 
       
   920             client->disconnectFromHost();
       
   921             server.close();
       
   922             client = 0;
       
   923             return;
       
   924         }
       
   925 
       
   926         // send data
       
   927         if (client && client->bytesToWrite() < 100*1024 && dataSent < dataSize) {
       
   928             qint64 amount = qMin(qint64(16*1024), dataSize - dataSent);
       
   929             QByteArray data(amount, '@');
       
   930 
       
   931             if (chunkedEncoding) {
       
   932                 client->write(QString(QString("%1").arg(amount,0,16).toUpper() + "\r\n").toAscii());
       
   933                 client->write(data.constData(), amount);
       
   934                 client->write(QString("\r\n").toAscii());
       
   935             } else {
       
   936                 client->write(data.constData(), amount);
       
   937             }
       
   938 
       
   939             dataSent += amount;
       
   940         }
       
   941     }
       
   942 };
       
   943 
       
   944 
       
   945 tst_QNetworkReply::tst_QNetworkReply()
       
   946 {
       
   947     Q_SET_DEFAULT_IAP
       
   948 
       
   949     testFileName = QDir::currentPath() + "/testfile";
       
   950 #ifndef Q_OS_WINCE
       
   951     uniqueExtension = QString("%1%2%3").arg((qulonglong)this).arg(rand()).arg((qulonglong)time(0));
       
   952 #else
       
   953     uniqueExtension = QString("%1%2").arg((qulonglong)this).arg(rand());
       
   954 #endif
       
   955     cookieJar = new MyCookieJar;
       
   956     manager.setCookieJar(cookieJar);
       
   957 
       
   958     QHostInfo hostInfo = QHostInfo::fromName(QtNetworkSettings::serverName());
       
   959 
       
   960     proxies << ProxyData(QNetworkProxy::NoProxy, "", false);
       
   961 
       
   962     if (hostInfo.error() == QHostInfo::NoError && !hostInfo.addresses().isEmpty()) {
       
   963         QString proxyserver = hostInfo.addresses().first().toString();
       
   964         proxies << ProxyData(QNetworkProxy(QNetworkProxy::HttpProxy, proxyserver, 3128), "+proxy", false)
       
   965                 << ProxyData(QNetworkProxy(QNetworkProxy::HttpProxy, proxyserver, 3129), "+proxyauth", true)
       
   966                 // currently unsupported
       
   967                 // << ProxyData(QNetworkProxy(QNetworkProxy::HttpProxy, proxyserver, 3130), "+proxyauth-ntlm", true);
       
   968                 << ProxyData(QNetworkProxy(QNetworkProxy::Socks5Proxy, proxyserver, 1080), "+socks", false)
       
   969                 << ProxyData(QNetworkProxy(QNetworkProxy::Socks5Proxy, proxyserver, 1081), "+socksauth", true);
       
   970     } else {
       
   971         printf("==================================================================\n");
       
   972         printf("Proxy could not be looked up. No proxy will be used while testing!\n");
       
   973         printf("==================================================================\n");
       
   974     }
       
   975 }
       
   976 
       
   977 tst_QNetworkReply::~tst_QNetworkReply()
       
   978 {
       
   979 }
       
   980 
       
   981 
       
   982 void tst_QNetworkReply::authenticationRequired(QNetworkReply*, QAuthenticator* auth)
       
   983 {
       
   984     auth->setUser("httptest");
       
   985     auth->setPassword("httptest");
       
   986 }
       
   987 
       
   988 void tst_QNetworkReply::proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator* auth)
       
   989 {
       
   990     auth->setUser("qsockstest");
       
   991     auth->setPassword("password");
       
   992 }
       
   993 
       
   994 #ifndef QT_NO_OPENSSL
       
   995 void tst_QNetworkReply::sslErrors(QNetworkReply *reply, const QList<QSslError> &errors)
       
   996 {
       
   997     reply->ignoreSslErrors();
       
   998     QVERIFY(!errors.isEmpty());
       
   999     QVERIFY(!reply->sslConfiguration().isNull());
       
  1000 }
       
  1001 
       
  1002 void tst_QNetworkReply::storeSslConfiguration()
       
  1003 {
       
  1004     storedSslConfiguration = QSslConfiguration();
       
  1005     QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
       
  1006     if (reply)
       
  1007         storedSslConfiguration = reply->sslConfiguration();
       
  1008 }
       
  1009 #endif
       
  1010 
       
  1011 QString tst_QNetworkReply::runSimpleRequest(QNetworkAccessManager::Operation op,
       
  1012                                             const QNetworkRequest &request,
       
  1013                                             QNetworkReplyPtr &reply,
       
  1014                                             const QByteArray &data)
       
  1015 {
       
  1016     switch (op) {
       
  1017     case QNetworkAccessManager::HeadOperation:
       
  1018         reply = manager.head(request);
       
  1019         break;
       
  1020 
       
  1021     case QNetworkAccessManager::GetOperation:
       
  1022         reply = manager.get(request);
       
  1023         break;
       
  1024 
       
  1025     case QNetworkAccessManager::PutOperation:
       
  1026         reply = manager.put(request, data);
       
  1027         break;
       
  1028 
       
  1029     case QNetworkAccessManager::PostOperation:
       
  1030         reply = manager.post(request, data);
       
  1031         break;
       
  1032 
       
  1033     case QNetworkAccessManager::DeleteOperation:
       
  1034         reply = manager.deleteResource(request);
       
  1035         break;
       
  1036 
       
  1037     default:
       
  1038         Q_ASSERT_X(false, "tst_QNetworkReply", "Invalid/unknown operation requested");
       
  1039     }
       
  1040     reply->setParent(this);
       
  1041     connect(reply, SIGNAL(finished()), SLOT(finished()));
       
  1042     connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(gotError()));
       
  1043 
       
  1044     returnCode = Timeout;
       
  1045     loop = new QEventLoop;
       
  1046     QTimer::singleShot(20000, loop, SLOT(quit()));
       
  1047     int code = returnCode == Timeout ? loop->exec() : returnCode;
       
  1048     delete loop;
       
  1049     loop = 0;
       
  1050 
       
  1051     switch (code) {
       
  1052     case Failure:
       
  1053         return "Request failed: " + reply->errorString();
       
  1054     case Timeout:
       
  1055         return "Network timeout";
       
  1056     }
       
  1057     return QString();
       
  1058 }
       
  1059 
       
  1060 void tst_QNetworkReply::finished()
       
  1061 {
       
  1062     loop->exit(returnCode = Success);
       
  1063 }
       
  1064 
       
  1065 void tst_QNetworkReply::gotError()
       
  1066 {
       
  1067     loop->exit(returnCode = Failure);
       
  1068     disconnect(QObject::sender(), SIGNAL(finished()), this, 0);
       
  1069 }
       
  1070 
       
  1071 void tst_QNetworkReply::initTestCase()
       
  1072 {
       
  1073 #if !defined Q_OS_WIN
       
  1074     wronlyFileName = QDir::currentPath() + "/write-only";
       
  1075     QFile wr(wronlyFileName);
       
  1076     QVERIFY(wr.open(QIODevice::WriteOnly | QIODevice::Truncate));
       
  1077     wr.setPermissions(QFile::WriteOwner | QFile::WriteUser);
       
  1078     wr.close();
       
  1079 #endif
       
  1080 
       
  1081     QDir::setSearchPaths("srcdir", QStringList() << SRCDIR);
       
  1082 }
       
  1083 
       
  1084 void tst_QNetworkReply::cleanupTestCase()
       
  1085 {
       
  1086 #if !defined Q_OS_WIN
       
  1087     QFile::remove(wronlyFileName);
       
  1088 #endif
       
  1089 }
       
  1090 
       
  1091 void tst_QNetworkReply::init()
       
  1092 {
       
  1093     cleanup();
       
  1094 }
       
  1095 
       
  1096 void tst_QNetworkReply::cleanup()
       
  1097 {
       
  1098     QFile file(testFileName);
       
  1099     QVERIFY(!file.exists() || file.remove());
       
  1100 
       
  1101     // clear the internal cache
       
  1102     QNetworkAccessManagerPrivate::clearCache(&manager);
       
  1103     manager.setProxy(QNetworkProxy());
       
  1104 
       
  1105     // clear cookies
       
  1106     cookieJar->setAllCookies(QList<QNetworkCookie>());
       
  1107 }
       
  1108 
       
  1109 void tst_QNetworkReply::stateChecking()
       
  1110 {
       
  1111     QUrl url = QUrl("file:///");
       
  1112     QNetworkRequest req(url);   // you can't open this file, I know
       
  1113     QNetworkReplyPtr reply = manager.get(req);
       
  1114 
       
  1115     QVERIFY(reply.data());
       
  1116     QVERIFY(reply->isOpen());
       
  1117     QVERIFY(reply->isReadable());
       
  1118     QVERIFY(!reply->isWritable());
       
  1119     QCOMPARE(reply->errorString(), QString("Unknown error"));
       
  1120 
       
  1121     QCOMPARE(reply->manager(), &manager);
       
  1122     QCOMPARE(reply->request(), req);
       
  1123     QCOMPARE(int(reply->operation()), int(QNetworkAccessManager::GetOperation));
       
  1124     QCOMPARE(reply->error(), QNetworkReply::NoError);
       
  1125     QCOMPARE(reply->isFinished(), false);
       
  1126     QCOMPARE(reply->url(), url);
       
  1127 
       
  1128     reply->abort();
       
  1129 }
       
  1130 
       
  1131 void tst_QNetworkReply::invalidProtocol()
       
  1132 {
       
  1133     QUrl url = QUrl::fromEncoded("not-a-known-protocol://foo/bar");
       
  1134     QNetworkRequest req(url);
       
  1135     QNetworkReplyPtr reply;
       
  1136 
       
  1137     QString errorMsg = "Request failed: Protocol \"not-a-known-protocol\" is unknown";
       
  1138     QString result = runSimpleRequest(QNetworkAccessManager::GetOperation, req, reply);
       
  1139     QCOMPARE(result, errorMsg);
       
  1140 
       
  1141     QCOMPARE(reply->url(), url);
       
  1142     QCOMPARE(reply->error(), QNetworkReply::ProtocolUnknownError);
       
  1143 }
       
  1144 
       
  1145 void tst_QNetworkReply::getFromData_data()
       
  1146 {
       
  1147 	QTest::addColumn<QString>("request");
       
  1148     QTest::addColumn<QByteArray>("expected");
       
  1149     QTest::addColumn<QString>("mimeType");
       
  1150 
       
  1151     const QString defaultMimeType("text/plain;charset=US-ASCII");
       
  1152 
       
  1153     //QTest::newRow("empty") << "data:" << QByteArray() << defaultMimeType;
       
  1154     QTest::newRow("empty2") << "data:," << QByteArray() << defaultMimeType;
       
  1155     QTest::newRow("just-charset_1") << "data:charset=iso-8859-1,"
       
  1156                                     << QByteArray() << "text/plain;charset=iso-8859-1";
       
  1157     QTest::newRow("just-charset_2") << "data:charset = iso-8859-1 ,"
       
  1158                                     << QByteArray() << "text/plain;charset = iso-8859-1";
       
  1159     //QTest::newRow("just-media") << "data:text/xml" << QByteArray() << "text/xml";
       
  1160     QTest::newRow("just-media2") << "data:text/xml," << QByteArray() << "text/xml";
       
  1161 
       
  1162     QTest::newRow("plain_1") << "data:,foo" << QByteArray("foo") << defaultMimeType;
       
  1163     QTest::newRow("plain_2") << "data:text/html,Hello World" << QByteArray("Hello World")
       
  1164                              << "text/html";
       
  1165     QTest::newRow("plain_3") << "data:text/html;charset=utf-8,Hello World"
       
  1166                              << QByteArray("Hello World") << "text/html;charset=utf-8";
       
  1167 
       
  1168     QTest::newRow("pct_1") << "data:,%3Cbody%20contentEditable%3Dtrue%3E%0D%0A"
       
  1169                            << QByteArray("<body contentEditable=true>\r\n") << defaultMimeType;
       
  1170     QTest::newRow("pct_2") << "data:text/html;charset=utf-8,%3Cbody%20contentEditable%3Dtrue%3E%0D%0A"
       
  1171                            << QByteArray("<body contentEditable=true>\r\n")
       
  1172                            << "text/html;charset=utf-8";
       
  1173 
       
  1174     QTest::newRow("base64-empty_1") << "data:;base64," << QByteArray() << defaultMimeType;
       
  1175     QTest::newRow("base64-empty_2") << "data:charset=utf-8;base64," << QByteArray()
       
  1176                                     << "text/plain;charset=utf-8";
       
  1177     QTest::newRow("base64-empty_3") << "data:text/html;charset=utf-8;base64,"
       
  1178                                     << QByteArray() << "text/html;charset=utf-8";
       
  1179 
       
  1180     QTest::newRow("base64_1") << "data:;base64,UXQgaXMgZ3JlYXQh" << QByteArray("Qt is great!")
       
  1181                               << defaultMimeType;
       
  1182     QTest::newRow("base64_2") << "data:charset=utf-8;base64,UXQgaXMgZ3JlYXQh"
       
  1183                               << QByteArray("Qt is great!") << "text/plain;charset=utf-8";
       
  1184     QTest::newRow("base64_3") << "data:text/html;charset=utf-8;base64,UXQgaXMgZ3JlYXQh"
       
  1185                               << QByteArray("Qt is great!") << "text/html;charset=utf-8";
       
  1186 
       
  1187     QTest::newRow("pct-nul") << "data:,a%00g" << QByteArray("a\0g", 3) << defaultMimeType;
       
  1188     QTest::newRow("base64-nul") << "data:;base64,YQBn" << QByteArray("a\0g", 3) << defaultMimeType;
       
  1189     QTest::newRow("pct-nonutf8") << "data:,a%E1g" << QByteArray("a\xE1g", 3) << defaultMimeType;
       
  1190 
       
  1191     QTest::newRow("base64")
       
  1192         << QString::fromLatin1("data:application/xml;base64,PGUvPg==")
       
  1193         << QByteArray("<e/>")
       
  1194         << "application/xml";
       
  1195 
       
  1196     QTest::newRow("base64, no media type")
       
  1197         << QString::fromLatin1("data:;base64,PGUvPg==")
       
  1198         << QByteArray("<e/>")
       
  1199         << defaultMimeType;
       
  1200 
       
  1201     QTest::newRow("Percent encoding")
       
  1202         << QString::fromLatin1("data:application/xml,%3Ce%2F%3E")
       
  1203         << QByteArray("<e/>")
       
  1204         << "application/xml";
       
  1205 
       
  1206     QTest::newRow("Percent encoding, no media type")
       
  1207         << QString::fromLatin1("data:,%3Ce%2F%3E")
       
  1208         << QByteArray("<e/>")
       
  1209         << defaultMimeType;
       
  1210 
       
  1211     QTest::newRow("querychars")
       
  1212         << QString::fromLatin1("data:,foo?x=0&y=0")
       
  1213         << QByteArray("foo?x=0&y=0")
       
  1214         << defaultMimeType;
       
  1215 
       
  1216     QTest::newRow("css") << "data:text/css,div%20{%20border-right:%20solid;%20}"
       
  1217                          << QByteArray("div { border-right: solid; }")
       
  1218                          << "text/css";
       
  1219 }
       
  1220 
       
  1221 void tst_QNetworkReply::getFromData()
       
  1222 {
       
  1223     QFETCH(QString, request);
       
  1224     QFETCH(QByteArray, expected);
       
  1225     QFETCH(QString, mimeType);
       
  1226 
       
  1227     QUrl url = QUrl::fromEncoded(request.toLatin1());
       
  1228     QNetworkRequest req(url);
       
  1229     QNetworkReplyPtr reply;
       
  1230 
       
  1231     RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, req, reply));
       
  1232 
       
  1233     QCOMPARE(reply->url(), url);
       
  1234     QCOMPARE(reply->error(), QNetworkReply::NoError);
       
  1235 
       
  1236     QCOMPARE(reply->header(QNetworkRequest::ContentTypeHeader).toString(), mimeType);
       
  1237     QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), qint64(expected.size()));
       
  1238     QCOMPARE(reply->readAll(), expected);
       
  1239 }
       
  1240 
       
  1241 void tst_QNetworkReply::getFromFile()
       
  1242 {
       
  1243 	// create the file:
       
  1244     QTemporaryFile file(QDir::currentPath() + "/temp-XXXXXX");
       
  1245     file.setAutoRemove(true);
       
  1246     QVERIFY(file.open());
       
  1247 
       
  1248     QNetworkRequest request(QUrl::fromLocalFile(file.fileName()));
       
  1249     QNetworkReplyPtr reply;
       
  1250 
       
  1251     static const char fileData[] = "This is some data that is in the file.\r\n";
       
  1252     QByteArray data = QByteArray::fromRawData(fileData, sizeof fileData - 1);
       
  1253     QVERIFY(file.write(data) == data.size());
       
  1254     file.flush();
       
  1255     QCOMPARE(file.size(), qint64(data.size()));
       
  1256 
       
  1257     RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
       
  1258 
       
  1259     QCOMPARE(reply->url(), request.url());
       
  1260     QCOMPARE(reply->error(), QNetworkReply::NoError);
       
  1261 
       
  1262     QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), file.size());
       
  1263     QCOMPARE(reply->readAll(), data);
       
  1264 
       
  1265     // make the file bigger
       
  1266     file.resize(0);
       
  1267     const int multiply = (128 * 1024) / (sizeof fileData - 1);
       
  1268     for (int i = 0; i < multiply; ++i)
       
  1269         file.write(fileData, sizeof fileData - 1);
       
  1270     file.flush();
       
  1271 
       
  1272     // run again
       
  1273     reply = 0;
       
  1274 
       
  1275     RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
       
  1276     QCOMPARE(reply->url(), request.url());
       
  1277     QCOMPARE(reply->error(), QNetworkReply::NoError);
       
  1278 
       
  1279     QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), file.size());
       
  1280     QCOMPARE(qint64(reply->readAll().size()), file.size());
       
  1281 }
       
  1282 
       
  1283 void tst_QNetworkReply::getFromFileSpecial_data()
       
  1284 {
       
  1285     QTest::addColumn<QString>("fileName");
       
  1286     QTest::addColumn<QString>("url");
       
  1287 
       
  1288     QTest::newRow("resource") << ":/resource" <<  "qrc:/resource";
       
  1289     QTest::newRow("search-path") << "srcdir:/rfc3252.txt" << "srcdir:/rfc3252.txt";
       
  1290     QTest::newRow("bigfile-path") << "srcdir:/bigfile" << "srcdir:/bigfile";
       
  1291 }
       
  1292 
       
  1293 void tst_QNetworkReply::getFromFileSpecial()
       
  1294 {
       
  1295 	QFETCH(QString, fileName);
       
  1296     QFETCH(QString, url);
       
  1297 
       
  1298     // open the resource so we can find out its size
       
  1299     QFile resource(fileName);
       
  1300     QVERIFY(resource.open(QIODevice::ReadOnly));
       
  1301 
       
  1302     QNetworkRequest request;
       
  1303     QNetworkReplyPtr reply;
       
  1304     request.setUrl(url);
       
  1305     RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
       
  1306 
       
  1307     QCOMPARE(reply->url(), request.url());
       
  1308     QCOMPARE(reply->error(), QNetworkReply::NoError);
       
  1309 
       
  1310     QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), resource.size());
       
  1311     QCOMPARE(reply->readAll(), resource.readAll());
       
  1312 }
       
  1313 
       
  1314 void tst_QNetworkReply::getFromFtp_data()
       
  1315 {
       
  1316     QTest::addColumn<QString>("referenceName");
       
  1317     QTest::addColumn<QString>("url");
       
  1318 
       
  1319     QTest::newRow("rfc3252.txt") << SRCDIR "/rfc3252.txt" << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt";
       
  1320     QTest::newRow("bigfile") << SRCDIR "/bigfile" << "ftp://" + QtNetworkSettings::serverName() + "/qtest/bigfile";
       
  1321 }
       
  1322 
       
  1323 void tst_QNetworkReply::getFromFtp()
       
  1324 {
       
  1325 	QFETCH(QString, referenceName);
       
  1326     QFETCH(QString, url);
       
  1327 
       
  1328     QFile reference(referenceName);
       
  1329     QVERIFY(reference.open(QIODevice::ReadOnly));
       
  1330 
       
  1331     QNetworkRequest request(url);
       
  1332     QNetworkReplyPtr reply;
       
  1333     RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
       
  1334 
       
  1335     QCOMPARE(reply->url(), request.url());
       
  1336     QCOMPARE(reply->error(), QNetworkReply::NoError);
       
  1337 
       
  1338     QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
       
  1339     QCOMPARE(reply->readAll(), reference.readAll());
       
  1340 }
       
  1341 
       
  1342 void tst_QNetworkReply::getFromHttp_data()
       
  1343 {
       
  1344     QTest::addColumn<QString>("referenceName");
       
  1345     QTest::addColumn<QString>("url");
       
  1346 
       
  1347     QTest::newRow("success-internal") << SRCDIR "/rfc3252.txt" << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt";
       
  1348     QTest::newRow("success-external") << SRCDIR "/rfc3252.txt" << "http://www.ietf.org/rfc/rfc3252.txt";
       
  1349     QTest::newRow("bigfile-internal") << SRCDIR "/bigfile" << "http://" + QtNetworkSettings::serverName() + "/qtest/bigfile";
       
  1350 }
       
  1351 
       
  1352 void tst_QNetworkReply::getFromHttp()
       
  1353 {
       
  1354 	QFETCH(QString, referenceName);
       
  1355     QFETCH(QString, url);
       
  1356 
       
  1357     QFile reference(referenceName);
       
  1358     QVERIFY(reference.open(QIODevice::ReadOnly));
       
  1359 
       
  1360     QNetworkRequest request(url);
       
  1361     QNetworkReplyPtr reply;
       
  1362     RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
       
  1363 
       
  1364     QCOMPARE(reply->url(), request.url());
       
  1365     QCOMPARE(reply->error(), QNetworkReply::NoError);
       
  1366     QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
       
  1367     QCOMPARE(reply->size(), reference.size());
       
  1368     // only compare when the header is set.
       
  1369     if (reply->header(QNetworkRequest::ContentLengthHeader).isValid())
       
  1370         QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
       
  1371     QCOMPARE(reply->readAll(), reference.readAll());
       
  1372 }
       
  1373 
       
  1374 void tst_QNetworkReply::getErrors_data()
       
  1375 {
       
  1376     QTest::addColumn<QString>("url");
       
  1377     QTest::addColumn<int>("error");
       
  1378     QTest::addColumn<int>("httpStatusCode");
       
  1379     QTest::addColumn<bool>("dataIsEmpty");
       
  1380 
       
  1381     // file: errors
       
  1382     QTest::newRow("file-host") << "file://this-host-doesnt-exist.troll.no/foo.txt"
       
  1383 #if !defined Q_OS_WIN
       
  1384                                << int(QNetworkReply::ProtocolInvalidOperationError) << 0 << true;
       
  1385 #else
       
  1386                                << int(QNetworkReply::ContentNotFoundError) << 0 << true;
       
  1387 #endif
       
  1388     QTest::newRow("file-no-path") << "file://localhost"
       
  1389                                   << int(QNetworkReply::ContentOperationNotPermittedError) << 0 << true;
       
  1390     QTest::newRow("file-is-dir") << QUrl::fromLocalFile(QDir::currentPath()).toString()
       
  1391                                  << int(QNetworkReply::ContentOperationNotPermittedError) << 0 << true;
       
  1392     QTest::newRow("file-exist") << QUrl::fromLocalFile(QDir::currentPath() + "/this-file-doesnt-exist.txt").toString()
       
  1393                                 << int(QNetworkReply::ContentNotFoundError) << 0 << true;
       
  1394 #if !defined Q_OS_WIN && !defined(Q_OS_SYMBIAN)
       
  1395     QTest::newRow("file-is-wronly") << QUrl::fromLocalFile(wronlyFileName).toString()
       
  1396                                     << int(QNetworkReply::ContentAccessDenied) << 0 << true;
       
  1397 #endif
       
  1398     if (QFile::exists("/etc/shadow"))
       
  1399         QTest::newRow("file-permissions") << "file:/etc/shadow"
       
  1400                                           << int(QNetworkReply::ContentAccessDenied) << 0 << true;
       
  1401 
       
  1402     // ftp: errors
       
  1403     QTest::newRow("ftp-host") << "ftp://this-host-doesnt-exist.troll.no/foo.txt"
       
  1404                               << int(QNetworkReply::HostNotFoundError) << 0 << true;
       
  1405     QTest::newRow("ftp-no-path") << "ftp://" + QtNetworkSettings::serverName()
       
  1406                                  << int(QNetworkReply::ContentOperationNotPermittedError) << 0 << true;
       
  1407     QTest::newRow("ftp-is-dir") << "ftp://" + QtNetworkSettings::serverName() + "/qtest"
       
  1408                                 << int(QNetworkReply::ContentOperationNotPermittedError) << 0 << true;
       
  1409     QTest::newRow("ftp-dir-not-readable") << "ftp://" + QtNetworkSettings::serverName() + "/pub/dir-not-readable/foo.txt"
       
  1410                                           << int(QNetworkReply::ContentAccessDenied) << 0 << true;
       
  1411     QTest::newRow("ftp-file-not-readable") << "ftp://" + QtNetworkSettings::serverName() + "/pub/file-not-readable.txt"
       
  1412                                            << int(QNetworkReply::ContentAccessDenied) << 0 << true;
       
  1413     QTest::newRow("ftp-exist") << "ftp://" + QtNetworkSettings::serverName() + "/pub/this-file-doesnt-exist.txt"
       
  1414                                << int(QNetworkReply::ContentNotFoundError) << 0 << true;
       
  1415 
       
  1416     // http: errors
       
  1417     QTest::newRow("http-host") << "http://this-host-will-never-exist.troll.no/"
       
  1418                                << int(QNetworkReply::HostNotFoundError) << 0 << true;
       
  1419     QTest::newRow("http-exist") << "http://" + QtNetworkSettings::serverName() + "/this-file-doesnt-exist.txt"
       
  1420                                 << int(QNetworkReply::ContentNotFoundError) << 404 << false;
       
  1421     QTest::newRow("http-authentication") << "http://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth"
       
  1422                                          << int(QNetworkReply::AuthenticationRequiredError) << 401 << false;
       
  1423 }
       
  1424 
       
  1425 void tst_QNetworkReply::getErrors()
       
  1426 {
       
  1427     QFETCH(QString, url);
       
  1428     QNetworkRequest request(url);
       
  1429     QNetworkReplyPtr reply = manager.get(request);
       
  1430     reply->setParent(this);     // we have expect-fails
       
  1431 
       
  1432     QCOMPARE(reply->error(), QNetworkReply::NoError);
       
  1433 
       
  1434     // now run the request:
       
  1435     connect(reply, SIGNAL(finished()),
       
  1436             &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  1437     QTestEventLoop::instance().enterLoop(10);
       
  1438     QVERIFY(!QTestEventLoop::instance().timeout());
       
  1439     //qDebug() << reply->errorString();
       
  1440 
       
  1441     QFETCH(int, error);
       
  1442     QEXPECT_FAIL("ftp-is-dir", "QFtp cannot provide enough detail", Abort);
       
  1443     // the line below is not necessary
       
  1444     QEXPECT_FAIL("ftp-dir-not-readable", "QFtp cannot provide enough detail", Abort);
       
  1445     QCOMPARE(reply->error(), QNetworkReply::NetworkError(error));
       
  1446 
       
  1447     QTEST(reply->readAll().isEmpty(), "dataIsEmpty");
       
  1448 
       
  1449     QVERIFY(reply->isFinished());
       
  1450     QVERIFY(!reply->isRunning());
       
  1451 
       
  1452     QFETCH(int, httpStatusCode);
       
  1453     if (httpStatusCode != 0) {
       
  1454         QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), httpStatusCode);
       
  1455     }
       
  1456 }
       
  1457 
       
  1458 static inline QByteArray md5sum(const QByteArray &data)
       
  1459 {
       
  1460     return QCryptographicHash::hash(data, QCryptographicHash::Md5);
       
  1461 }
       
  1462 
       
  1463 void tst_QNetworkReply::putToFile_data()
       
  1464 {
       
  1465     QTest::addColumn<QByteArray>("data");
       
  1466     QTest::addColumn<QByteArray>("md5sum");
       
  1467 
       
  1468     QByteArray data;
       
  1469     data = "";
       
  1470     QTest::newRow("empty") << data << md5sum(data);
       
  1471 
       
  1472     data = "This is a normal message.";
       
  1473     QTest::newRow("generic") << data << md5sum(data);
       
  1474 
       
  1475     data = "This is a message to show that Qt rocks!\r\n\n";
       
  1476     QTest::newRow("small") << data << md5sum(data);
       
  1477 
       
  1478     data = QByteArray("abcd\0\1\2\abcd",12);
       
  1479     QTest::newRow("with-nul") << data << md5sum(data);
       
  1480 
       
  1481     data = QByteArray(4097, '\4');
       
  1482     QTest::newRow("4k+1") << data << md5sum(data);
       
  1483 
       
  1484     data = QByteArray(128*1024+1, '\177');
       
  1485     QTest::newRow("128k+1") << data << md5sum(data);
       
  1486 }
       
  1487 
       
  1488 void tst_QNetworkReply::putToFile()
       
  1489 {
       
  1490     QFile file(testFileName);
       
  1491 
       
  1492     QUrl url = QUrl::fromLocalFile(file.fileName());
       
  1493     QNetworkRequest request(url);
       
  1494     QNetworkReplyPtr reply;
       
  1495 
       
  1496     QFETCH(QByteArray, data);
       
  1497 
       
  1498     RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PutOperation, request, reply, data));
       
  1499 
       
  1500     QCOMPARE(reply->url(), url);
       
  1501     QCOMPARE(reply->error(), QNetworkReply::NoError);
       
  1502     QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
       
  1503     QVERIFY(reply->readAll().isEmpty());
       
  1504 
       
  1505     QVERIFY(file.open(QIODevice::ReadOnly));
       
  1506     QCOMPARE(file.size(), qint64(data.size()));
       
  1507     QByteArray contents = file.readAll();
       
  1508     QCOMPARE(contents, data);
       
  1509 }
       
  1510 
       
  1511 void tst_QNetworkReply::putToFtp_data()
       
  1512 {
       
  1513     putToFile_data();
       
  1514 }
       
  1515 
       
  1516 void tst_QNetworkReply::putToFtp()
       
  1517 {
       
  1518     QUrl url("ftp://" + QtNetworkSettings::serverName());
       
  1519     url.setPath(QString("/qtest/upload/qnetworkaccess-putToFtp-%1-%2")
       
  1520                 .arg(QTest::currentDataTag())
       
  1521                 .arg(uniqueExtension));
       
  1522 
       
  1523     QNetworkRequest request(url);
       
  1524     QNetworkReplyPtr reply;
       
  1525 
       
  1526     QFETCH(QByteArray, data);
       
  1527 
       
  1528     RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PutOperation, request, reply, data));
       
  1529 
       
  1530     QCOMPARE(reply->url(), url);
       
  1531     QCOMPARE(reply->error(), QNetworkReply::NoError);
       
  1532     QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
       
  1533     QVERIFY(reply->readAll().isEmpty());
       
  1534 
       
  1535     // download the file again from FTP to make sure it was uploaded
       
  1536     // correctly
       
  1537     QFtp ftp;
       
  1538     ftp.connectToHost(url.host());
       
  1539     ftp.login();
       
  1540     ftp.get(url.path());
       
  1541 
       
  1542     QObject::connect(&ftp, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  1543     QTestEventLoop::instance().enterLoop(10);
       
  1544     QObject::disconnect(&ftp, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  1545 
       
  1546     QByteArray uploaded = ftp.readAll();
       
  1547     QCOMPARE(uploaded.size(), data.size());
       
  1548     QCOMPARE(uploaded, data);
       
  1549 
       
  1550     ftp.close();
       
  1551     QObject::connect(&ftp, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  1552     QTestEventLoop::instance().enterLoop(10);
       
  1553     QObject::disconnect(&ftp, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  1554 }
       
  1555 
       
  1556 void tst_QNetworkReply::putToHttp_data()
       
  1557 {
       
  1558     putToFile_data();
       
  1559 }
       
  1560 
       
  1561 void tst_QNetworkReply::putToHttp()
       
  1562 {
       
  1563     QUrl url("http://" + QtNetworkSettings::serverName());
       
  1564     url.setPath(QString("/dav/qnetworkaccess-putToHttp-%1-%2")
       
  1565                 .arg(QTest::currentDataTag())
       
  1566                 .arg(uniqueExtension));
       
  1567 
       
  1568     QNetworkRequest request(url);
       
  1569     QNetworkReplyPtr reply;
       
  1570 
       
  1571     QFETCH(QByteArray, data);
       
  1572 
       
  1573     RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PutOperation, request, reply, data));
       
  1574 
       
  1575     QCOMPARE(reply->url(), url);
       
  1576     QCOMPARE(reply->error(), QNetworkReply::NoError);
       
  1577 
       
  1578     QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 201); // 201 Created
       
  1579 
       
  1580     // download the file again from HTTP to make sure it was uploaded
       
  1581     // correctly. HTTP/0.9 is enough
       
  1582     QTcpSocket socket;
       
  1583     socket.connectToHost(QtNetworkSettings::serverName(), 80);
       
  1584     socket.write("GET " + url.toEncoded(QUrl::RemoveScheme | QUrl::RemoveAuthority) + "\r\n");
       
  1585     if (!socket.waitForDisconnected(10000))
       
  1586         QFAIL("Network timeout");
       
  1587 
       
  1588     QByteArray uploadedData = socket.readAll();
       
  1589     QCOMPARE(uploadedData, data);
       
  1590 }
       
  1591 
       
  1592 void tst_QNetworkReply::postToHttp_data()
       
  1593 {
       
  1594     putToFile_data();
       
  1595 }
       
  1596 
       
  1597 void tst_QNetworkReply::postToHttp()
       
  1598 {
       
  1599     QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi");
       
  1600 
       
  1601     QNetworkRequest request(url);
       
  1602     QNetworkReplyPtr reply;
       
  1603 
       
  1604     QFETCH(QByteArray, data);
       
  1605 
       
  1606     RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PostOperation, request, reply, data));
       
  1607 
       
  1608     QCOMPARE(reply->url(), url);
       
  1609     QCOMPARE(reply->error(), QNetworkReply::NoError);
       
  1610 
       
  1611     QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
       
  1612 
       
  1613     QFETCH(QByteArray, md5sum);
       
  1614     QByteArray uploadedData = reply->readAll().trimmed();
       
  1615     QCOMPARE(uploadedData, md5sum.toHex());
       
  1616 }
       
  1617 
       
  1618 void tst_QNetworkReply::deleteFromHttp_data()
       
  1619 {
       
  1620     QTest::addColumn<QUrl>("url");
       
  1621     QTest::addColumn<int>("resultCode");
       
  1622     QTest::addColumn<QNetworkReply::NetworkError>("error");
       
  1623 
       
  1624     // for status codes to expect, see http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
       
  1625 
       
  1626     QTest::newRow("405-method-not-allowed") << QUrl("http://" + QtNetworkSettings::serverName() + "/index.html") << 405 << QNetworkReply::ContentOperationNotPermittedError;
       
  1627     QTest::newRow("200-ok") << QUrl("http://" + QtNetworkSettings::serverName() + "/cgi-bin/http-delete.cgi?200-ok") << 200 << QNetworkReply::NoError;
       
  1628     QTest::newRow("202-accepted") << QUrl("http://" + QtNetworkSettings::serverName() + "/cgi-bin/http-delete.cgi?202-accepted") << 202 << QNetworkReply::NoError;
       
  1629     QTest::newRow("204-no-content") << QUrl("http://" + QtNetworkSettings::serverName() + "/cgi-bin/http-delete.cgi?204-no-content") << 204 << QNetworkReply::NoError;
       
  1630     QTest::newRow("404-not-found") << QUrl("http://" + QtNetworkSettings::serverName() + "/cgi-bin/http-delete.cgi?404-not-found") << 404 << QNetworkReply::ContentNotFoundError;
       
  1631 }
       
  1632 
       
  1633 void tst_QNetworkReply::deleteFromHttp()
       
  1634 {
       
  1635     QFETCH(QUrl, url);
       
  1636     QFETCH(int, resultCode);
       
  1637     QFETCH(QNetworkReply::NetworkError, error);
       
  1638     QNetworkRequest request(url);
       
  1639     QNetworkReplyPtr reply;
       
  1640     runSimpleRequest(QNetworkAccessManager::DeleteOperation, request, reply, 0);
       
  1641     QCOMPARE(reply->url(), url);
       
  1642     QCOMPARE(reply->error(), error);
       
  1643     QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), resultCode);
       
  1644 }
       
  1645 
       
  1646 void tst_QNetworkReply::putGetDeleteGetFromHttp_data()
       
  1647 {
       
  1648     QTest::addColumn<QUrl>("putUrl");
       
  1649     QTest::addColumn<int>("putResultCode");
       
  1650     QTest::addColumn<QNetworkReply::NetworkError>("putError");
       
  1651     QTest::addColumn<QUrl>("deleteUrl");
       
  1652     QTest::addColumn<int>("deleteResultCode");
       
  1653     QTest::addColumn<QNetworkReply::NetworkError>("deleteError");
       
  1654     QTest::addColumn<QUrl>("get2Url");
       
  1655     QTest::addColumn<int>("get2ResultCode");
       
  1656     QTest::addColumn<QNetworkReply::NetworkError>("get2Error");
       
  1657 
       
  1658     QUrl url("http://" + QtNetworkSettings::serverName());
       
  1659     url.setPath(QString("/dav/qnetworkaccess-putToHttp-%1-%2")
       
  1660                 .arg(QTest::currentDataTag())
       
  1661                 .arg(uniqueExtension));
       
  1662 
       
  1663     // first use case: put, get (to check it is there), delete, get (to check it is not there anymore)
       
  1664     QTest::newRow("success") << url << 201 << QNetworkReply::NoError << url << 204 << QNetworkReply::NoError << url << 404 << QNetworkReply::ContentNotFoundError;
       
  1665 
       
  1666     QUrl wrongUrl("http://" + QtNetworkSettings::serverName());
       
  1667     wrongUrl.setPath(QString("/dav/qnetworkaccess-thisURLisNotAvailable"));
       
  1668 
       
  1669     // second use case: put, get (to check it is there), delete wrong URL, get (to check it is still there)
       
  1670     QTest::newRow("delete-error") << url << 201 << QNetworkReply::NoError << wrongUrl << 404 << QNetworkReply::ContentNotFoundError << url << 200 << QNetworkReply::NoError;
       
  1671 
       
  1672 }
       
  1673 
       
  1674 void tst_QNetworkReply::putGetDeleteGetFromHttp()
       
  1675 {
       
  1676     QFETCH(QUrl, putUrl);
       
  1677     QFETCH(int, putResultCode);
       
  1678     QFETCH(QNetworkReply::NetworkError, putError);
       
  1679     QFETCH(QUrl, deleteUrl);
       
  1680     QFETCH(int, deleteResultCode);
       
  1681     QFETCH(QNetworkReply::NetworkError, deleteError);
       
  1682     QFETCH(QUrl, get2Url);
       
  1683     QFETCH(int, get2ResultCode);
       
  1684     QFETCH(QNetworkReply::NetworkError, get2Error);
       
  1685 
       
  1686     QNetworkRequest putRequest(putUrl);
       
  1687     QNetworkRequest deleteRequest(deleteUrl);
       
  1688     QNetworkRequest get2Request(get2Url);
       
  1689     QNetworkReplyPtr reply;
       
  1690 
       
  1691     RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PutOperation, putRequest, reply, 0));
       
  1692     QCOMPARE(reply->error(), putError);
       
  1693     QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), putResultCode);
       
  1694 
       
  1695     runSimpleRequest(QNetworkAccessManager::GetOperation, putRequest, reply, 0);
       
  1696     QCOMPARE(reply->error(), QNetworkReply::NoError);
       
  1697     QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
       
  1698 
       
  1699     runSimpleRequest(QNetworkAccessManager::DeleteOperation, deleteRequest, reply, 0);
       
  1700     QCOMPARE(reply->error(), deleteError);
       
  1701     QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), deleteResultCode);
       
  1702 
       
  1703     runSimpleRequest(QNetworkAccessManager::GetOperation, get2Request, reply, 0);
       
  1704     QCOMPARE(reply->error(), get2Error);
       
  1705     QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), get2ResultCode);
       
  1706 
       
  1707 }
       
  1708 
       
  1709 void tst_QNetworkReply::ioGetFromData_data()
       
  1710 {
       
  1711     QTest::addColumn<QString>("urlStr");
       
  1712     QTest::addColumn<QByteArray>("data");
       
  1713 
       
  1714     QTest::newRow("data-empty") << "data:," << QByteArray();
       
  1715     QTest::newRow("data-literal") << "data:,foo" << QByteArray("foo");
       
  1716     QTest::newRow("data-pct") << "data:,%3Cbody%20contentEditable%3Dtrue%3E%0D%0A"
       
  1717                            << QByteArray("<body contentEditable=true>\r\n");
       
  1718     QTest::newRow("data-base64") << "data:;base64,UXQgaXMgZ3JlYXQh" << QByteArray("Qt is great!");
       
  1719 }
       
  1720 
       
  1721 void tst_QNetworkReply::ioGetFromData()
       
  1722 {
       
  1723     QFETCH(QString, urlStr);
       
  1724 
       
  1725     QUrl url = QUrl::fromEncoded(urlStr.toLatin1());
       
  1726     QNetworkRequest request(url);
       
  1727 
       
  1728     QNetworkReplyPtr reply = manager.get(request);
       
  1729     DataReader reader(reply);
       
  1730 
       
  1731     connect(reply, SIGNAL(finished()),
       
  1732             &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  1733     QTestEventLoop::instance().enterLoop(10);
       
  1734     QVERIFY(!QTestEventLoop::instance().timeout());
       
  1735 
       
  1736     QCOMPARE(reply->url(), request.url());
       
  1737     QCOMPARE(reply->error(), QNetworkReply::NoError);
       
  1738 
       
  1739     QFETCH(QByteArray, data);
       
  1740     QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toInt(), data.size());
       
  1741     QCOMPARE(reader.data.size(), data.size());
       
  1742     QCOMPARE(reader.data, data);
       
  1743 }
       
  1744 
       
  1745 void tst_QNetworkReply::ioGetFromFileSpecial_data()
       
  1746 {
       
  1747     getFromFileSpecial_data();
       
  1748 }
       
  1749 
       
  1750 void tst_QNetworkReply::ioGetFromFileSpecial()
       
  1751 {
       
  1752     QFETCH(QString, fileName);
       
  1753     QFETCH(QString, url);
       
  1754 
       
  1755     QFile resource(fileName);
       
  1756     QVERIFY(resource.open(QIODevice::ReadOnly));
       
  1757 
       
  1758     QNetworkRequest request;
       
  1759     request.setUrl(url);
       
  1760     QNetworkReplyPtr reply = manager.get(request);
       
  1761     DataReader reader(reply);
       
  1762 
       
  1763     connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  1764     QTestEventLoop::instance().enterLoop(10);
       
  1765     QVERIFY(!QTestEventLoop::instance().timeout());
       
  1766 
       
  1767     QCOMPARE(reply->url(), request.url());
       
  1768     QCOMPARE(reply->error(), QNetworkReply::NoError);
       
  1769 
       
  1770     QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), resource.size());
       
  1771     QCOMPARE(qint64(reader.data.size()), resource.size());
       
  1772     QCOMPARE(reader.data, resource.readAll());
       
  1773 }
       
  1774 
       
  1775 void tst_QNetworkReply::ioGetFromFile_data()
       
  1776 {
       
  1777     putToFile_data();
       
  1778 }
       
  1779 
       
  1780 void tst_QNetworkReply::ioGetFromFile()
       
  1781 {
       
  1782     QTemporaryFile file(QDir::currentPath() + "/temp-XXXXXX");
       
  1783     file.setAutoRemove(true);
       
  1784     QVERIFY(file.open());
       
  1785 
       
  1786     QFETCH(QByteArray, data);
       
  1787     QVERIFY(file.write(data) == data.size());
       
  1788     file.flush();
       
  1789     QCOMPARE(file.size(), qint64(data.size()));
       
  1790 
       
  1791     QNetworkRequest request(QUrl::fromLocalFile(file.fileName()));
       
  1792     QNetworkReplyPtr reply = manager.get(request);
       
  1793     DataReader reader(reply);
       
  1794 
       
  1795     connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  1796     QTestEventLoop::instance().enterLoop(10);
       
  1797     QVERIFY(!QTestEventLoop::instance().timeout());
       
  1798 
       
  1799     QCOMPARE(reply->url(), request.url());
       
  1800     QCOMPARE(reply->error(), QNetworkReply::NoError);
       
  1801 
       
  1802     QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), file.size());
       
  1803     QCOMPARE(qint64(reader.data.size()), file.size());
       
  1804     QCOMPARE(reader.data, data);
       
  1805 }
       
  1806 
       
  1807 void tst_QNetworkReply::ioGetFromFtp_data()
       
  1808 {
       
  1809     QTest::addColumn<QString>("fileName");
       
  1810     QTest::addColumn<qint64>("expectedSize");
       
  1811 
       
  1812     QTest::newRow("bigfile") << "bigfile" << Q_INT64_C(519240);
       
  1813 
       
  1814     QFile file(SRCDIR "/rfc3252.txt");
       
  1815     QTest::newRow("rfc3252.txt") << "rfc3252.txt" << file.size();
       
  1816 }
       
  1817 
       
  1818 void tst_QNetworkReply::ioGetFromFtp()
       
  1819 {
       
  1820     QFETCH(QString, fileName);
       
  1821     QFile reference(fileName);
       
  1822     reference.open(QIODevice::ReadOnly); // will fail for bigfile
       
  1823 
       
  1824     QNetworkRequest request("ftp://" + QtNetworkSettings::serverName() + "/qtest/" + fileName);
       
  1825     QNetworkReplyPtr reply = manager.get(request);
       
  1826     DataReader reader(reply);
       
  1827 
       
  1828     connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  1829     QTestEventLoop::instance().enterLoop(10);
       
  1830     QVERIFY(!QTestEventLoop::instance().timeout());
       
  1831 
       
  1832     QCOMPARE(reply->url(), request.url());
       
  1833     QCOMPARE(reply->error(), QNetworkReply::NoError);
       
  1834 
       
  1835     QFETCH(qint64, expectedSize);
       
  1836     QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), expectedSize);
       
  1837     QCOMPARE(qint64(reader.data.size()), expectedSize);
       
  1838 
       
  1839     if (reference.isOpen())
       
  1840         QCOMPARE(reader.data, reference.readAll());
       
  1841 }
       
  1842 
       
  1843 void tst_QNetworkReply::ioGetFromFtpWithReuse()
       
  1844 {
       
  1845     QString fileName = SRCDIR "/rfc3252.txt";
       
  1846     QFile reference(fileName);
       
  1847     reference.open(QIODevice::ReadOnly);
       
  1848 
       
  1849     QNetworkRequest request(QUrl("ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
       
  1850 
       
  1851     // two concurrent (actually, consecutive) gets:
       
  1852     QNetworkReplyPtr reply1 = manager.get(request);
       
  1853     DataReader reader1(reply1);
       
  1854     QNetworkReplyPtr reply2 = manager.get(request);
       
  1855     DataReader reader2(reply2);
       
  1856     QSignalSpy spy(reply1, SIGNAL(finished()));
       
  1857 
       
  1858     connect(reply2, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  1859     QTestEventLoop::instance().enterLoop(10);
       
  1860     QVERIFY(!QTestEventLoop::instance().timeout());
       
  1861     if (spy.count() == 0) {
       
  1862         connect(reply1, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  1863         QTestEventLoop::instance().enterLoop(10);
       
  1864         QVERIFY(!QTestEventLoop::instance().timeout());
       
  1865     }
       
  1866 
       
  1867     QCOMPARE(reply1->url(), request.url());
       
  1868     QCOMPARE(reply2->url(), request.url());
       
  1869     QCOMPARE(reply1->error(), QNetworkReply::NoError);
       
  1870     QCOMPARE(reply2->error(), QNetworkReply::NoError);
       
  1871 
       
  1872     QCOMPARE(qint64(reader1.data.size()), reference.size());
       
  1873     QCOMPARE(qint64(reader2.data.size()), reference.size());
       
  1874     QCOMPARE(reply1->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
       
  1875     QCOMPARE(reply2->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
       
  1876 
       
  1877     QByteArray referenceData = reference.readAll();
       
  1878     QCOMPARE(reader1.data, referenceData);
       
  1879     QCOMPARE(reader2.data, referenceData);
       
  1880 }
       
  1881 
       
  1882 void tst_QNetworkReply::ioGetFromHttp()
       
  1883 {
       
  1884     QFile reference(SRCDIR "/rfc3252.txt");
       
  1885     QVERIFY(reference.open(QIODevice::ReadOnly));
       
  1886 
       
  1887     QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
       
  1888     QNetworkReplyPtr reply = manager.get(request);
       
  1889     DataReader reader(reply);
       
  1890 
       
  1891     connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  1892     QTestEventLoop::instance().enterLoop(10);
       
  1893     QVERIFY(!QTestEventLoop::instance().timeout());
       
  1894 
       
  1895     QCOMPARE(reply->url(), request.url());
       
  1896     QCOMPARE(reply->error(), QNetworkReply::NoError);
       
  1897     QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
       
  1898 
       
  1899     QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
       
  1900     QCOMPARE(qint64(reader.data.size()), reference.size());
       
  1901 
       
  1902     QCOMPARE(reader.data, reference.readAll());
       
  1903 }
       
  1904 
       
  1905 void tst_QNetworkReply::ioGetFromHttpWithReuseParallel()
       
  1906 {
       
  1907     QFile reference(SRCDIR "/rfc3252.txt");
       
  1908     QVERIFY(reference.open(QIODevice::ReadOnly));
       
  1909 
       
  1910     QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
       
  1911     QNetworkReplyPtr reply1 = manager.get(request);
       
  1912     QNetworkReplyPtr reply2 = manager.get(request);
       
  1913     DataReader reader1(reply1);
       
  1914     DataReader reader2(reply2);
       
  1915     QSignalSpy spy(reply1, SIGNAL(finished()));
       
  1916 
       
  1917     connect(reply2, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  1918     QTestEventLoop::instance().enterLoop(10);
       
  1919     QVERIFY(!QTestEventLoop::instance().timeout());
       
  1920     if (spy.count() == 0) {
       
  1921         connect(reply1, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  1922         QTestEventLoop::instance().enterLoop(10);
       
  1923         QVERIFY(!QTestEventLoop::instance().timeout());
       
  1924     }
       
  1925 
       
  1926     QCOMPARE(reply1->url(), request.url());
       
  1927     QCOMPARE(reply2->url(), request.url());
       
  1928     QCOMPARE(reply1->error(), QNetworkReply::NoError);
       
  1929     QCOMPARE(reply2->error(), QNetworkReply::NoError);
       
  1930     QCOMPARE(reply1->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
       
  1931     QCOMPARE(reply2->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
       
  1932 
       
  1933     QCOMPARE(reply1->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
       
  1934     QCOMPARE(reply2->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
       
  1935     QCOMPARE(qint64(reader1.data.size()), reference.size());
       
  1936     QCOMPARE(qint64(reader2.data.size()), reference.size());
       
  1937 
       
  1938     QByteArray referenceData = reference.readAll();
       
  1939     QCOMPARE(reader1.data, referenceData);
       
  1940     QCOMPARE(reader2.data, referenceData);
       
  1941 }
       
  1942 
       
  1943 void tst_QNetworkReply::ioGetFromHttpWithReuseSequential()
       
  1944 {
       
  1945     QFile reference(SRCDIR "/rfc3252.txt");
       
  1946     QVERIFY(reference.open(QIODevice::ReadOnly));
       
  1947 
       
  1948     QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
       
  1949     {
       
  1950         QNetworkReplyPtr reply = manager.get(request);
       
  1951         DataReader reader(reply);
       
  1952 
       
  1953         connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  1954         QTestEventLoop::instance().enterLoop(10);
       
  1955         QVERIFY(!QTestEventLoop::instance().timeout());
       
  1956 
       
  1957         QCOMPARE(reply->url(), request.url());
       
  1958         QCOMPARE(reply->error(), QNetworkReply::NoError);
       
  1959         QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
       
  1960 
       
  1961         QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
       
  1962         QCOMPARE(qint64(reader.data.size()), reference.size());
       
  1963 
       
  1964         QCOMPARE(reader.data, reference.readAll());
       
  1965     }
       
  1966 
       
  1967     reference.seek(0);
       
  1968     // rinse and repeat:
       
  1969     {
       
  1970         QNetworkReplyPtr reply = manager.get(request);
       
  1971         DataReader reader(reply);
       
  1972 
       
  1973         connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  1974         QTestEventLoop::instance().enterLoop(10);
       
  1975         QVERIFY(!QTestEventLoop::instance().timeout());
       
  1976 
       
  1977         QCOMPARE(reply->url(), request.url());
       
  1978         QCOMPARE(reply->error(), QNetworkReply::NoError);
       
  1979         QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
       
  1980 
       
  1981         QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
       
  1982         QCOMPARE(qint64(reader.data.size()), reference.size());
       
  1983 
       
  1984         QCOMPARE(reader.data, reference.readAll());
       
  1985     }
       
  1986 }
       
  1987 
       
  1988 void tst_QNetworkReply::ioGetFromHttpWithAuth()
       
  1989 {
       
  1990     qRegisterMetaType<QNetworkReply *>(); // for QSignalSpy
       
  1991     qRegisterMetaType<QAuthenticator *>();
       
  1992 
       
  1993     // This test sends three requests
       
  1994     // The first two in parallel
       
  1995     // The third after the first two finished
       
  1996     QFile reference(SRCDIR "/rfc3252.txt");
       
  1997     QVERIFY(reference.open(QIODevice::ReadOnly));
       
  1998 
       
  1999     QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt"));
       
  2000     {
       
  2001         QNetworkReplyPtr reply1 = manager.get(request);
       
  2002         QNetworkReplyPtr reply2 = manager.get(request);
       
  2003         DataReader reader1(reply1);
       
  2004         DataReader reader2(reply2);
       
  2005         QSignalSpy finishedspy(reply1, SIGNAL(finished()));
       
  2006 
       
  2007         QSignalSpy authspy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
       
  2008         connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
       
  2009                 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
       
  2010 
       
  2011         connect(reply2, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  2012         QTestEventLoop::instance().enterLoop(10);
       
  2013         QVERIFY(!QTestEventLoop::instance().timeout());
       
  2014         if (finishedspy.count() == 0) {
       
  2015             connect(reply1, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  2016             QTestEventLoop::instance().enterLoop(10);
       
  2017             QVERIFY(!QTestEventLoop::instance().timeout());
       
  2018         }
       
  2019         manager.disconnect(SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
       
  2020                            this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
       
  2021 
       
  2022         QCOMPARE(reply1->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
       
  2023         QCOMPARE(reply2->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
       
  2024         QByteArray referenceData = reference.readAll();
       
  2025         QCOMPARE(reader1.data, referenceData);
       
  2026         QCOMPARE(reader2.data, referenceData);
       
  2027 
       
  2028         QCOMPARE(authspy.count(), 1);
       
  2029     }
       
  2030 
       
  2031     reference.seek(0);
       
  2032     // rinse and repeat:
       
  2033     {
       
  2034         QNetworkReplyPtr reply = manager.get(request);
       
  2035         DataReader reader(reply);
       
  2036 
       
  2037         QSignalSpy authspy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
       
  2038         connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
       
  2039                 SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
       
  2040         connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  2041         QTestEventLoop::instance().enterLoop(10);
       
  2042         QVERIFY(!QTestEventLoop::instance().timeout());
       
  2043         manager.disconnect(SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
       
  2044                            this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
       
  2045 
       
  2046         QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
       
  2047         QCOMPARE(reader.data, reference.readAll());
       
  2048 
       
  2049         QCOMPARE(authspy.count(), 0);
       
  2050     }
       
  2051 }
       
  2052 
       
  2053 void tst_QNetworkReply::ioGetFromHttpWithProxyAuth()
       
  2054 {
       
  2055     qRegisterMetaType<QNetworkProxy>(); // for QSignalSpy
       
  2056     qRegisterMetaType<QAuthenticator *>();
       
  2057 
       
  2058     // This test sends three requests
       
  2059     // The first two in parallel
       
  2060     // The third after the first two finished
       
  2061     QFile reference(SRCDIR "/rfc3252.txt");
       
  2062     QVERIFY(reference.open(QIODevice::ReadOnly));
       
  2063 
       
  2064     QNetworkProxy proxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129);
       
  2065     QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
       
  2066     {
       
  2067         manager.setProxy(proxy);
       
  2068         QNetworkReplyPtr reply1 = manager.get(request);
       
  2069         QNetworkReplyPtr reply2 = manager.get(request);
       
  2070         manager.setProxy(QNetworkProxy());
       
  2071 
       
  2072         DataReader reader1(reply1);
       
  2073         DataReader reader2(reply2);
       
  2074         QSignalSpy finishedspy(reply1, SIGNAL(finished()));
       
  2075 
       
  2076         QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
       
  2077         connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
       
  2078                 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
       
  2079 
       
  2080         connect(reply2, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  2081         QTestEventLoop::instance().enterLoop(10);
       
  2082         QVERIFY(!QTestEventLoop::instance().timeout());
       
  2083         if (finishedspy.count() == 0) {
       
  2084             connect(reply1, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  2085             QTestEventLoop::instance().enterLoop(10);
       
  2086             QVERIFY(!QTestEventLoop::instance().timeout());
       
  2087         }
       
  2088         manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
       
  2089                            this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
       
  2090 
       
  2091         QCOMPARE(reply1->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
       
  2092         QCOMPARE(reply2->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
       
  2093         QByteArray referenceData = reference.readAll();
       
  2094         QCOMPARE(reader1.data, referenceData);
       
  2095         QCOMPARE(reader2.data, referenceData);
       
  2096 
       
  2097         QCOMPARE(authspy.count(), 1);
       
  2098     }
       
  2099 
       
  2100     reference.seek(0);
       
  2101     // rinse and repeat:
       
  2102     {
       
  2103         manager.setProxy(proxy);
       
  2104         QNetworkReplyPtr reply = manager.get(request);
       
  2105         DataReader reader(reply);
       
  2106         manager.setProxy(QNetworkProxy());
       
  2107 
       
  2108         QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
       
  2109         connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
       
  2110                 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
       
  2111         connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  2112         QTestEventLoop::instance().enterLoop(10);
       
  2113         QVERIFY(!QTestEventLoop::instance().timeout());
       
  2114         manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
       
  2115                            this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
       
  2116 
       
  2117         QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
       
  2118         QCOMPARE(reader.data, reference.readAll());
       
  2119 
       
  2120         QCOMPARE(authspy.count(), 0);
       
  2121     }
       
  2122 }
       
  2123 
       
  2124 void tst_QNetworkReply::ioGetFromHttpWithSocksProxy()
       
  2125 {
       
  2126     // HTTP caching proxies are tested by the above function
       
  2127     // test SOCKSv5 proxies too
       
  2128 
       
  2129     qRegisterMetaType<QNetworkProxy>(); // for QSignalSpy
       
  2130     qRegisterMetaType<QAuthenticator *>();
       
  2131 
       
  2132     QFile reference(SRCDIR "/rfc3252.txt");
       
  2133     QVERIFY(reference.open(QIODevice::ReadOnly));
       
  2134 
       
  2135     QNetworkProxy proxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080);
       
  2136     QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
       
  2137     {
       
  2138         manager.setProxy(proxy);
       
  2139         QNetworkReplyPtr reply = manager.get(request);
       
  2140         DataReader reader(reply);
       
  2141         manager.setProxy(QNetworkProxy());
       
  2142 
       
  2143         QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
       
  2144         connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
       
  2145                 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
       
  2146         connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  2147         QTestEventLoop::instance().enterLoop(10);
       
  2148         QVERIFY(!QTestEventLoop::instance().timeout());
       
  2149         manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
       
  2150                            this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
       
  2151 
       
  2152         QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
       
  2153         QCOMPARE(reader.data, reference.readAll());
       
  2154 
       
  2155         QCOMPARE(authspy.count(), 0);
       
  2156     }
       
  2157 
       
  2158     // set an invalid proxy just to make sure that we can't load
       
  2159     proxy = QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1079);
       
  2160     {
       
  2161         manager.setProxy(proxy);
       
  2162         QNetworkReplyPtr reply = manager.get(request);
       
  2163         DataReader reader(reply);
       
  2164         manager.setProxy(QNetworkProxy());
       
  2165 
       
  2166         QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
       
  2167         connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
       
  2168                 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
       
  2169         connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  2170         QTestEventLoop::instance().enterLoop(10);
       
  2171         QVERIFY(!QTestEventLoop::instance().timeout());
       
  2172         manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
       
  2173                            this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
       
  2174 
       
  2175         QVERIFY(!reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).isValid());
       
  2176         QVERIFY(reader.data.isEmpty());
       
  2177 
       
  2178         QVERIFY(int(reply->error()) > 0);
       
  2179         QEXPECT_FAIL("", "QTcpSocket doesn't return enough information yet", Continue);
       
  2180         QCOMPARE(int(reply->error()), int(QNetworkReply::ProxyConnectionRefusedError));
       
  2181 
       
  2182         QCOMPARE(authspy.count(), 0);
       
  2183     }
       
  2184 }
       
  2185 
       
  2186 #ifndef QT_NO_OPENSSL
       
  2187 void tst_QNetworkReply::ioGetFromHttpsWithSslErrors()
       
  2188 {
       
  2189     qRegisterMetaType<QNetworkReply*>(); // for QSignalSpy
       
  2190     qRegisterMetaType<QList<QSslError> >();
       
  2191 
       
  2192     QFile reference(SRCDIR "/rfc3252.txt");
       
  2193     QVERIFY(reference.open(QIODevice::ReadOnly));
       
  2194 
       
  2195     QNetworkRequest request(QUrl("https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
       
  2196     QNetworkReplyPtr reply = manager.get(request);
       
  2197     DataReader reader(reply);
       
  2198 
       
  2199     QSignalSpy sslspy(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)));
       
  2200     connect(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
       
  2201             SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
       
  2202     connect(reply, SIGNAL(metaDataChanged()), SLOT(storeSslConfiguration()));
       
  2203 
       
  2204     connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  2205     QTestEventLoop::instance().enterLoop(10);
       
  2206     QVERIFY(!QTestEventLoop::instance().timeout());
       
  2207     manager.disconnect(SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
       
  2208                        this, SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
       
  2209 
       
  2210     QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
       
  2211     QCOMPARE(reader.data, reference.readAll());
       
  2212 
       
  2213     QCOMPARE(sslspy.count(), 1);
       
  2214 
       
  2215     QVERIFY(!storedSslConfiguration.isNull());
       
  2216     QVERIFY(!reply->sslConfiguration().isNull());
       
  2217 }
       
  2218 
       
  2219 void tst_QNetworkReply::ioGetFromHttpsWithIgnoreSslErrors()
       
  2220 {
       
  2221     // same as above, except that we call ignoreSslErrors and don't connect
       
  2222     // to the sslErrors() signal (which is *still* emitted)
       
  2223 
       
  2224     qRegisterMetaType<QNetworkReply*>(); // for QSignalSpy
       
  2225     qRegisterMetaType<QList<QSslError> >();
       
  2226 
       
  2227     QFile reference(SRCDIR "/rfc3252.txt");
       
  2228     QVERIFY(reference.open(QIODevice::ReadOnly));
       
  2229 
       
  2230     QNetworkRequest request(QUrl("https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"));
       
  2231 
       
  2232     QNetworkReplyPtr reply = manager.get(request);
       
  2233     reply->ignoreSslErrors();
       
  2234     DataReader reader(reply);
       
  2235 
       
  2236     QSignalSpy sslspy(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)));
       
  2237     connect(reply, SIGNAL(metaDataChanged()), SLOT(storeSslConfiguration()));
       
  2238     connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  2239     QTestEventLoop::instance().enterLoop(10);
       
  2240     QVERIFY(!QTestEventLoop::instance().timeout());
       
  2241 
       
  2242     QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
       
  2243     QCOMPARE(reader.data, reference.readAll());
       
  2244 
       
  2245     QCOMPARE(sslspy.count(), 1);
       
  2246 
       
  2247     QVERIFY(!storedSslConfiguration.isNull());
       
  2248     QVERIFY(!reply->sslConfiguration().isNull());
       
  2249 }
       
  2250 
       
  2251 void tst_QNetworkReply::ioGetFromHttpsWithSslHandshakeError()
       
  2252 {
       
  2253     qRegisterMetaType<QNetworkReply*>(); // for QSignalSpy
       
  2254     qRegisterMetaType<QList<QSslError> >();
       
  2255 
       
  2256     QFile reference(SRCDIR "/rfc3252.txt");
       
  2257     QVERIFY(reference.open(QIODevice::ReadOnly));
       
  2258 
       
  2259     QNetworkRequest request(QUrl("https://" + QtNetworkSettings::serverName() + ":80"));
       
  2260 
       
  2261     QNetworkReplyPtr reply = manager.get(request);
       
  2262     reply->ignoreSslErrors();
       
  2263     DataReader reader(reply);
       
  2264 
       
  2265     QSignalSpy sslspy(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)));
       
  2266     connect(reply, SIGNAL(metaDataChanged()), SLOT(storeSslConfiguration()));
       
  2267     connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  2268     QTestEventLoop::instance().enterLoop(10);
       
  2269     QVERIFY(!QTestEventLoop::instance().timeout());
       
  2270 
       
  2271     QCOMPARE(reply->error(), QNetworkReply::SslHandshakeFailedError);
       
  2272     QCOMPARE(sslspy.count(), 0);
       
  2273 }
       
  2274 #endif
       
  2275 
       
  2276 void tst_QNetworkReply::ioGetFromHttpBrokenServer_data()
       
  2277 {
       
  2278     QTest::addColumn<QByteArray>("dataToSend");
       
  2279     QTest::addColumn<bool>("doDisconnect");
       
  2280 
       
  2281     QTest::newRow("no-newline") << QByteArray("Hello World") << false;
       
  2282 
       
  2283     // these are OK now, we just eat the lonely newlines
       
  2284     //QTest::newRow("just-newline") << QByteArray("\r\n") << false;
       
  2285     //QTest::newRow("just-2newline") << QByteArray("\r\n\r\n") << false;
       
  2286 
       
  2287     QTest::newRow("with-newlines") << QByteArray("Long first line\r\nLong second line") << false;
       
  2288     QTest::newRow("with-newlines2") << QByteArray("\r\nSecond line") << false;
       
  2289     QTest::newRow("with-newlines3") << QByteArray("ICY\r\nSecond line") << false;
       
  2290     QTest::newRow("invalid-version") << QByteArray("HTTP/123 200 \r\n") << false;
       
  2291     QTest::newRow("invalid-version2") << QByteArray("HTTP/a.\033 200 \r\n") << false;
       
  2292     QTest::newRow("invalid-reply-code") << QByteArray("HTTP/1.0 fuu \r\n") << false;
       
  2293 
       
  2294     QTest::newRow("empty+disconnect") << QByteArray() << true;
       
  2295 
       
  2296     QTest::newRow("no-newline+disconnect") << QByteArray("Hello World") << true;
       
  2297     QTest::newRow("just-newline+disconnect") << QByteArray("\r\n") << true;
       
  2298     QTest::newRow("just-2newline+disconnect") << QByteArray("\r\n\r\n") << true;
       
  2299     QTest::newRow("with-newlines+disconnect") << QByteArray("Long first line\r\nLong second line") << true;
       
  2300     QTest::newRow("with-newlines2+disconnect") << QByteArray("\r\nSecond line") << true;
       
  2301     QTest::newRow("with-newlines3+disconnect") << QByteArray("ICY\r\nSecond line") << true;
       
  2302 
       
  2303     QTest::newRow("invalid-version+disconnect") << QByteArray("HTTP/123 200 ") << true;
       
  2304     QTest::newRow("invalid-version2+disconnect") << QByteArray("HTTP/a.\033 200 ") << true;
       
  2305     QTest::newRow("invalid-reply-code+disconnect") << QByteArray("HTTP/1.0 fuu ") << true;
       
  2306 }
       
  2307 
       
  2308 void tst_QNetworkReply::ioGetFromHttpBrokenServer()
       
  2309 {
       
  2310     QFETCH(QByteArray, dataToSend);
       
  2311     QFETCH(bool, doDisconnect);
       
  2312     MiniHttpServer server(dataToSend);
       
  2313     server.doClose = doDisconnect;
       
  2314 
       
  2315     QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
       
  2316     QNetworkReplyPtr reply = manager.get(request);
       
  2317 
       
  2318     connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  2319     QTestEventLoop::instance().enterLoop(10);
       
  2320     QVERIFY(!QTestEventLoop::instance().timeout());
       
  2321 
       
  2322     QCOMPARE(reply->url(), request.url());
       
  2323     QVERIFY(reply->error() != QNetworkReply::NoError);
       
  2324 }
       
  2325 
       
  2326 void tst_QNetworkReply::ioGetWithManyProxies_data()
       
  2327 {
       
  2328     QTest::addColumn<QList<QNetworkProxy> >("proxyList");
       
  2329     QTest::addColumn<QNetworkProxy>("proxyUsed");
       
  2330     QTest::addColumn<QString>("url");
       
  2331     QTest::addColumn<QNetworkReply::NetworkError>("expectedError");
       
  2332 
       
  2333     QList<QNetworkProxy> proxyList;
       
  2334 
       
  2335     // All of the other functions test DefaultProxy
       
  2336     // So let's test something else
       
  2337 
       
  2338     // Simple tests that work:
       
  2339 
       
  2340     // HTTP request with HTTP caching proxy
       
  2341     proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129);
       
  2342     QTest::newRow("http-on-http")
       
  2343         << proxyList << proxyList.at(0)
       
  2344         << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
       
  2345         << QNetworkReply::NoError;
       
  2346 
       
  2347     // HTTP request with HTTP transparent proxy
       
  2348     proxyList.clear();
       
  2349     proxyList << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3129);
       
  2350     QTest::newRow("http-on-http2")
       
  2351         << proxyList << proxyList.at(0)
       
  2352         << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
       
  2353         << QNetworkReply::NoError;
       
  2354 
       
  2355     // HTTP request with SOCKS transparent proxy
       
  2356     proxyList.clear();
       
  2357     proxyList << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081);
       
  2358     QTest::newRow("http-on-socks")
       
  2359         << proxyList << proxyList.at(0)
       
  2360         << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
       
  2361         << QNetworkReply::NoError;
       
  2362 
       
  2363     // FTP request with FTP caching proxy
       
  2364     proxyList.clear();
       
  2365     proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121);
       
  2366     QTest::newRow("ftp-on-ftp")
       
  2367         << proxyList << proxyList.at(0)
       
  2368         << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
       
  2369         << QNetworkReply::NoError;
       
  2370 
       
  2371     // The following test doesn't work because QFtp is too limited
       
  2372     // It can only talk to its own kind of proxies
       
  2373 
       
  2374     // FTP request with SOCKSv5 transparent proxy
       
  2375     proxyList.clear();
       
  2376     proxyList << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081);
       
  2377     QTest::newRow("ftp-on-socks")
       
  2378         << proxyList << proxyList.at(0)
       
  2379         << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
       
  2380         << QNetworkReply::NoError;
       
  2381 
       
  2382 #ifndef QT_NO_OPENSSL
       
  2383     // HTTPS with HTTP transparent proxy
       
  2384     proxyList.clear();
       
  2385     proxyList << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3129);
       
  2386     QTest::newRow("https-on-http")
       
  2387         << proxyList << proxyList.at(0)
       
  2388         << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
       
  2389         << QNetworkReply::NoError;
       
  2390 
       
  2391     // HTTPS request with SOCKS transparent proxy
       
  2392     proxyList.clear();
       
  2393     proxyList << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081);
       
  2394     QTest::newRow("https-on-socks")
       
  2395         << proxyList << proxyList.at(0)
       
  2396         << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
       
  2397         << QNetworkReply::NoError;
       
  2398 #endif
       
  2399 
       
  2400     // Tests that fail:
       
  2401 
       
  2402     // HTTP request with FTP caching proxy
       
  2403     proxyList.clear();
       
  2404     proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121);
       
  2405     QTest::newRow("http-on-ftp")
       
  2406         << proxyList << QNetworkProxy()
       
  2407         << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
       
  2408         << QNetworkReply::ProxyNotFoundError;
       
  2409 
       
  2410     // FTP request with HTTP caching proxy
       
  2411     proxyList.clear();
       
  2412     proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129);
       
  2413     QTest::newRow("ftp-on-http")
       
  2414         << proxyList << QNetworkProxy()
       
  2415         << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
       
  2416         << QNetworkReply::ProxyNotFoundError;
       
  2417 
       
  2418     // FTP request with HTTP caching proxies
       
  2419     proxyList.clear();
       
  2420     proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
       
  2421               << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3130);
       
  2422     QTest::newRow("ftp-on-multiple-http")
       
  2423         << proxyList << QNetworkProxy()
       
  2424         << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
       
  2425         << QNetworkReply::ProxyNotFoundError;
       
  2426 
       
  2427 #ifndef QT_NO_OPENSSL
       
  2428     // HTTPS with HTTP caching proxy
       
  2429     proxyList.clear();
       
  2430     proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129);
       
  2431     QTest::newRow("https-on-httptransparent")
       
  2432         << proxyList << QNetworkProxy()
       
  2433         << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
       
  2434         << QNetworkReply::ProxyNotFoundError;
       
  2435 
       
  2436     // HTTPS with FTP caching proxy
       
  2437     proxyList.clear();
       
  2438     proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121);
       
  2439     QTest::newRow("https-on-ftp")
       
  2440         << proxyList << QNetworkProxy()
       
  2441         << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
       
  2442         << QNetworkReply::ProxyNotFoundError;
       
  2443 #endif
       
  2444 
       
  2445     // Complex requests:
       
  2446 
       
  2447     // HTTP request with more than one HTTP proxy
       
  2448     proxyList.clear();
       
  2449     proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
       
  2450               << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3130);
       
  2451     QTest::newRow("http-on-multiple-http")
       
  2452         << proxyList << proxyList.at(0)
       
  2453         << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
       
  2454         << QNetworkReply::NoError;
       
  2455 
       
  2456     // HTTP request with HTTP + SOCKS
       
  2457     proxyList.clear();
       
  2458     proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
       
  2459               << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081);
       
  2460     QTest::newRow("http-on-http+socks")
       
  2461         << proxyList << proxyList.at(0)
       
  2462         << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
       
  2463         << QNetworkReply::NoError;
       
  2464 
       
  2465     // HTTP request with FTP + HTTP + SOCKS
       
  2466     proxyList.clear();
       
  2467     proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121)
       
  2468               << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
       
  2469               << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081);
       
  2470     QTest::newRow("http-on-ftp+http+socks")
       
  2471         << proxyList << proxyList.at(1) // second proxy should be used
       
  2472         << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
       
  2473         << QNetworkReply::NoError;
       
  2474 
       
  2475     // HTTP request with NoProxy + HTTP
       
  2476     proxyList.clear();
       
  2477     proxyList << QNetworkProxy(QNetworkProxy::NoProxy)
       
  2478               << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129);
       
  2479     QTest::newRow("http-on-noproxy+http")
       
  2480         << proxyList << proxyList.at(0)
       
  2481         << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
       
  2482         << QNetworkReply::NoError;
       
  2483 
       
  2484     // HTTP request with FTP + NoProxy
       
  2485     proxyList.clear();
       
  2486     proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121)
       
  2487               << QNetworkProxy(QNetworkProxy::NoProxy);
       
  2488     QTest::newRow("http-on-ftp+noproxy")
       
  2489         << proxyList << proxyList.at(1) // second proxy should be used
       
  2490         << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
       
  2491         << QNetworkReply::NoError;
       
  2492 
       
  2493     // FTP request with HTTP Caching + FTP
       
  2494     proxyList.clear();
       
  2495     proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
       
  2496               << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121);
       
  2497     QTest::newRow("ftp-on-http+ftp")
       
  2498         << proxyList << proxyList.at(1) // second proxy should be used
       
  2499         << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
       
  2500         << QNetworkReply::NoError;
       
  2501 
       
  2502 #ifndef QT_NO_OPENSSL
       
  2503     // HTTPS request with HTTP Caching + HTTP transparent
       
  2504     proxyList.clear();
       
  2505     proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
       
  2506               << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3129);
       
  2507     QTest::newRow("https-on-httpcaching+http")
       
  2508         << proxyList << proxyList.at(1) // second proxy should be used
       
  2509         << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
       
  2510         << QNetworkReply::NoError;
       
  2511 
       
  2512     // HTTPS request with FTP + HTTP C + HTTP T
       
  2513     proxyList.clear();
       
  2514     proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121)
       
  2515               << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
       
  2516               << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3129);
       
  2517     QTest::newRow("https-on-ftp+httpcaching+http")
       
  2518         << proxyList << proxyList.at(2) // skip the first two
       
  2519         << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"
       
  2520         << QNetworkReply::NoError;
       
  2521 #endif
       
  2522 }
       
  2523 
       
  2524 void tst_QNetworkReply::ioGetWithManyProxies()
       
  2525 {
       
  2526     // Test proxy factories
       
  2527 
       
  2528     qRegisterMetaType<QNetworkProxy>(); // for QSignalSpy
       
  2529     qRegisterMetaType<QAuthenticator *>();
       
  2530 
       
  2531     QFile reference(SRCDIR "/rfc3252.txt");
       
  2532     QVERIFY(reference.open(QIODevice::ReadOnly));
       
  2533 
       
  2534     // set the proxy factory:
       
  2535     QFETCH(QList<QNetworkProxy>, proxyList);
       
  2536     MyProxyFactory *proxyFactory = new MyProxyFactory;
       
  2537     proxyFactory->toReturn = proxyList;
       
  2538     manager.setProxyFactory(proxyFactory);
       
  2539 
       
  2540     QFETCH(QString, url);
       
  2541     QUrl theUrl(url);
       
  2542     QNetworkRequest request(theUrl);
       
  2543     QNetworkReplyPtr reply = manager.get(request);
       
  2544     DataReader reader(reply);
       
  2545 
       
  2546     QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
       
  2547     connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
       
  2548             SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
       
  2549     connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  2550 #ifndef QT_NO_OPENSSL
       
  2551     connect(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
       
  2552             SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
       
  2553 #endif
       
  2554     QTestEventLoop::instance().enterLoop(10);
       
  2555     QVERIFY(!QTestEventLoop::instance().timeout());
       
  2556 
       
  2557     manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
       
  2558                        this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
       
  2559 #ifndef QT_NO_OPENSSL
       
  2560     manager.disconnect(SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
       
  2561                        this, SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
       
  2562 #endif
       
  2563 
       
  2564     QFETCH(QNetworkReply::NetworkError, expectedError);
       
  2565     QEXPECT_FAIL("ftp-on-socks", "QFtp is too limited and won't accept non-FTP proxies", Abort);
       
  2566     QCOMPARE(reply->error(), expectedError);
       
  2567 
       
  2568     // Verify that the factory was called properly
       
  2569     QCOMPARE(proxyFactory->callCount, 1);
       
  2570     QCOMPARE(proxyFactory->lastQuery, QNetworkProxyQuery(theUrl));
       
  2571 
       
  2572     if (expectedError == QNetworkReply::NoError) {
       
  2573         // request succeeded
       
  2574         QCOMPARE(reader.data, reference.readAll());
       
  2575 
       
  2576         // now verify that the proxies worked:
       
  2577         QFETCH(QNetworkProxy, proxyUsed);
       
  2578         if (proxyUsed.type() == QNetworkProxy::NoProxy) {
       
  2579             QCOMPARE(authspy.count(), 0);
       
  2580         } else {
       
  2581             if (QByteArray(QTest::currentDataTag()).startsWith("ftp-"))
       
  2582                 return;         // No authentication with current FTP or with FTP proxies
       
  2583             QCOMPARE(authspy.count(), 1);
       
  2584             QCOMPARE(qvariant_cast<QNetworkProxy>(authspy.at(0).at(0)), proxyUsed);
       
  2585         }
       
  2586     } else {
       
  2587         // request failed
       
  2588         QCOMPARE(authspy.count(), 0);
       
  2589     }
       
  2590 }
       
  2591 
       
  2592 void tst_QNetworkReply::ioPutToFileFromFile_data()
       
  2593 {
       
  2594     QTest::addColumn<QString>("fileName");
       
  2595 
       
  2596     QTest::newRow("empty") << SRCDIR "/empty";
       
  2597     QTest::newRow("real-file") << SRCDIR "/rfc3252.txt";
       
  2598     QTest::newRow("resource") << ":/resource";
       
  2599     QTest::newRow("search-path") << "srcdir:/rfc3252.txt";
       
  2600 }
       
  2601 
       
  2602 void tst_QNetworkReply::ioPutToFileFromFile()
       
  2603 {
       
  2604     QFETCH(QString, fileName);
       
  2605     QFile sourceFile(fileName);
       
  2606     QFile targetFile(testFileName);
       
  2607 
       
  2608     QVERIFY(sourceFile.open(QIODevice::ReadOnly));
       
  2609 
       
  2610     QUrl url = QUrl::fromLocalFile(targetFile.fileName());
       
  2611     QNetworkRequest request(url);
       
  2612     QNetworkReplyPtr reply = manager.put(request, &sourceFile);
       
  2613 
       
  2614     connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  2615     QTestEventLoop::instance().enterLoop(10);
       
  2616     QVERIFY(!QTestEventLoop::instance().timeout());
       
  2617 
       
  2618     QCOMPARE(reply->url(), url);
       
  2619     QCOMPARE(reply->error(), QNetworkReply::NoError);
       
  2620     QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
       
  2621     QVERIFY(reply->readAll().isEmpty());
       
  2622 
       
  2623     QVERIFY(sourceFile.atEnd());
       
  2624     sourceFile.seek(0);         // reset it to the beginning
       
  2625 
       
  2626     QVERIFY(targetFile.open(QIODevice::ReadOnly));
       
  2627     QCOMPARE(targetFile.size(), sourceFile.size());
       
  2628     QCOMPARE(targetFile.readAll(), sourceFile.readAll());
       
  2629 }
       
  2630 
       
  2631 void tst_QNetworkReply::ioPutToFileFromSocket_data()
       
  2632 {
       
  2633     putToFile_data();
       
  2634 }
       
  2635 
       
  2636 void tst_QNetworkReply::ioPutToFileFromSocket()
       
  2637 {
       
  2638     QFile file(testFileName);
       
  2639 
       
  2640     QUrl url = QUrl::fromLocalFile(file.fileName());
       
  2641     QNetworkRequest request(url);
       
  2642 
       
  2643     QFETCH(QByteArray, data);
       
  2644     SocketPair socketpair;
       
  2645     socketpair.create();
       
  2646     QVERIFY(socketpair.endPoints[0] && socketpair.endPoints[1]);
       
  2647 
       
  2648     socketpair.endPoints[0]->write(data);
       
  2649     QNetworkReplyPtr reply = manager.put(QNetworkRequest(url), socketpair.endPoints[1]);
       
  2650     socketpair.endPoints[0]->close();
       
  2651 
       
  2652     connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  2653     QTestEventLoop::instance().enterLoop(10);
       
  2654     QCOMPARE(reply->error(), QNetworkReply::NoError);
       
  2655     QVERIFY(!QTestEventLoop::instance().timeout());
       
  2656 
       
  2657     QCOMPARE(reply->url(), url);
       
  2658     QCOMPARE(reply->error(), QNetworkReply::NoError);
       
  2659     QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
       
  2660     QVERIFY(reply->readAll().isEmpty());
       
  2661 
       
  2662     QVERIFY(file.open(QIODevice::ReadOnly));
       
  2663     QCOMPARE(file.size(), qint64(data.size()));
       
  2664     QByteArray contents = file.readAll();
       
  2665     QCOMPARE(contents, data);
       
  2666 }
       
  2667 
       
  2668 void tst_QNetworkReply::ioPutToFileFromLocalSocket_data()
       
  2669 {
       
  2670     putToFile_data();
       
  2671 }
       
  2672 
       
  2673 void tst_QNetworkReply::ioPutToFileFromLocalSocket()
       
  2674 {
       
  2675     QString socketname = "networkreplytest";
       
  2676     QLocalServer server;
       
  2677     if (!server.listen(socketname)) {
       
  2678         if (QFile::exists(server.fullServerName()))
       
  2679             QFile::remove(server.fullServerName());
       
  2680         QVERIFY(server.listen(socketname));
       
  2681     }
       
  2682     QLocalSocket active;
       
  2683     active.connectToServer(socketname);
       
  2684     QVERIFY2(server.waitForNewConnection(10), server.errorString().toLatin1().constData());
       
  2685     QVERIFY2(active.waitForConnected(10), active.errorString().toLatin1().constData());
       
  2686     QVERIFY2(server.hasPendingConnections(), server.errorString().toLatin1().constData());
       
  2687     QLocalSocket *passive = server.nextPendingConnection();
       
  2688 
       
  2689     QFile file(testFileName);
       
  2690     QUrl url = QUrl::fromLocalFile(file.fileName());
       
  2691     QNetworkRequest request(url);
       
  2692 
       
  2693     QFETCH(QByteArray, data);
       
  2694     active.write(data);
       
  2695     active.close();
       
  2696     QNetworkReplyPtr reply = manager.put(QNetworkRequest(url), passive);
       
  2697     passive->setParent(reply);
       
  2698 
       
  2699     connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  2700     QTestEventLoop::instance().enterLoop(10);
       
  2701     QCOMPARE(reply->error(), QNetworkReply::NoError);
       
  2702     QVERIFY(!QTestEventLoop::instance().timeout());
       
  2703 
       
  2704     QCOMPARE(reply->url(), url);
       
  2705     QCOMPARE(reply->error(), QNetworkReply::NoError);
       
  2706     QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
       
  2707     QVERIFY(reply->readAll().isEmpty());
       
  2708 
       
  2709     QVERIFY(file.open(QIODevice::ReadOnly));
       
  2710     QCOMPARE(file.size(), qint64(data.size()));
       
  2711     QByteArray contents = file.readAll();
       
  2712     QCOMPARE(contents, data);
       
  2713 }
       
  2714 
       
  2715 void tst_QNetworkReply::ioPutToFileFromProcess_data()
       
  2716 {
       
  2717     putToFile_data();
       
  2718 }
       
  2719 
       
  2720 void tst_QNetworkReply::ioPutToFileFromProcess()
       
  2721 {
       
  2722 #if defined(Q_OS_WINCE) || defined (Q_OS_SYMBIAN)
       
  2723     QSKIP("Currently no stdin/out supported for Windows CE / Symbian OS", SkipAll);
       
  2724 #endif
       
  2725 
       
  2726 #ifdef Q_OS_WIN
       
  2727     if (qstrcmp(QTest::currentDataTag(), "small") == 0)
       
  2728         QSKIP("When passing a CR-LF-LF sequence through Windows stdio, it gets converted, "
       
  2729               "so this test fails. Disabled on Windows", SkipSingle);
       
  2730 #endif
       
  2731 
       
  2732 #if defined(QT_NO_PROCESS)
       
  2733     QSKIP("Qt was compiled with QT_NO_PROCESS", SkipAll);
       
  2734 #else
       
  2735     QFile file(testFileName);
       
  2736 
       
  2737     QUrl url = QUrl::fromLocalFile(file.fileName());
       
  2738     QNetworkRequest request(url);
       
  2739 
       
  2740     QFETCH(QByteArray, data);
       
  2741     QProcess process;
       
  2742     process.start("echo/echo all");
       
  2743     process.write(data);
       
  2744     process.closeWriteChannel();
       
  2745 
       
  2746     QNetworkReplyPtr reply = manager.put(QNetworkRequest(url), &process);
       
  2747 
       
  2748     connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  2749     QTestEventLoop::instance().enterLoop(10);
       
  2750     QVERIFY(!QTestEventLoop::instance().timeout());
       
  2751 
       
  2752     QCOMPARE(reply->url(), url);
       
  2753     QCOMPARE(reply->error(), QNetworkReply::NoError);
       
  2754     QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
       
  2755     QVERIFY(reply->readAll().isEmpty());
       
  2756 
       
  2757     QVERIFY(file.open(QIODevice::ReadOnly));
       
  2758     QCOMPARE(file.size(), qint64(data.size()));
       
  2759     QByteArray contents = file.readAll();
       
  2760     QCOMPARE(contents, data);
       
  2761 #endif
       
  2762 }
       
  2763 
       
  2764 void tst_QNetworkReply::ioPutToFtpFromFile_data()
       
  2765 {
       
  2766     ioPutToFileFromFile_data();
       
  2767 }
       
  2768 
       
  2769 void tst_QNetworkReply::ioPutToFtpFromFile()
       
  2770 {
       
  2771     QFETCH(QString, fileName);
       
  2772     QFile sourceFile(fileName);
       
  2773     QVERIFY(sourceFile.open(QIODevice::ReadOnly));
       
  2774 
       
  2775     QUrl url("ftp://" + QtNetworkSettings::serverName());
       
  2776     url.setPath(QString("/qtest/upload/qnetworkaccess-ioPutToFtpFromFile-%1-%2")
       
  2777                 .arg(QTest::currentDataTag())
       
  2778                 .arg(uniqueExtension));
       
  2779 
       
  2780     QNetworkRequest request(url);
       
  2781     QNetworkReplyPtr reply = manager.put(request, &sourceFile);
       
  2782 
       
  2783     connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  2784     QTestEventLoop::instance().enterLoop(10);
       
  2785     QVERIFY(!QTestEventLoop::instance().timeout());
       
  2786 
       
  2787     QCOMPARE(reply->url(), url);
       
  2788     QCOMPARE(reply->error(), QNetworkReply::NoError);
       
  2789     QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
       
  2790     QVERIFY(reply->readAll().isEmpty());
       
  2791 
       
  2792     QVERIFY(sourceFile.atEnd());
       
  2793     sourceFile.seek(0);         // reset it to the beginning
       
  2794 
       
  2795     // download the file again from FTP to make sure it was uploaded
       
  2796     // correctly
       
  2797     QFtp ftp;
       
  2798     ftp.connectToHost(url.host());
       
  2799     ftp.login();
       
  2800     ftp.get(url.path());
       
  2801 
       
  2802     QObject::connect(&ftp, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  2803     QTestEventLoop::instance().enterLoop(3);
       
  2804     QObject::disconnect(&ftp, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  2805 
       
  2806     QByteArray uploaded = ftp.readAll();
       
  2807     QCOMPARE(qint64(uploaded.size()), sourceFile.size());
       
  2808     QCOMPARE(uploaded, sourceFile.readAll());
       
  2809 
       
  2810     ftp.close();
       
  2811     QObject::connect(&ftp, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  2812     QTestEventLoop::instance().enterLoop(10);
       
  2813     QObject::disconnect(&ftp, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  2814 }
       
  2815 
       
  2816 void tst_QNetworkReply::ioPutToHttpFromFile_data()
       
  2817 {
       
  2818     ioPutToFileFromFile_data();
       
  2819 }
       
  2820 
       
  2821 void tst_QNetworkReply::ioPutToHttpFromFile()
       
  2822 {
       
  2823     QFETCH(QString, fileName);
       
  2824     QFile sourceFile(fileName);
       
  2825     QVERIFY(sourceFile.open(QIODevice::ReadOnly));
       
  2826 
       
  2827     QUrl url("http://" + QtNetworkSettings::serverName());
       
  2828     url.setPath(QString("/dav/qnetworkaccess-ioPutToHttpFromFile-%1-%2")
       
  2829                 .arg(QTest::currentDataTag())
       
  2830                 .arg(uniqueExtension));
       
  2831 
       
  2832     QNetworkRequest request(url);
       
  2833     QNetworkReplyPtr reply = manager.put(request, &sourceFile);
       
  2834 
       
  2835     connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  2836     QTestEventLoop::instance().enterLoop(10);
       
  2837     QVERIFY(!QTestEventLoop::instance().timeout());
       
  2838 
       
  2839     QCOMPARE(reply->url(), url);
       
  2840     QCOMPARE(reply->error(), QNetworkReply::NoError);
       
  2841 
       
  2842     // verify that the HTTP status code is 201 Created
       
  2843     QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 201);
       
  2844 
       
  2845     QVERIFY(sourceFile.atEnd());
       
  2846     sourceFile.seek(0);         // reset it to the beginning
       
  2847 
       
  2848     // download the file again from HTTP to make sure it was uploaded
       
  2849     // correctly
       
  2850     reply = manager.get(request);
       
  2851     connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  2852     QTestEventLoop::instance().enterLoop(10);
       
  2853     QVERIFY(!QTestEventLoop::instance().timeout());
       
  2854 
       
  2855     QCOMPARE(reply->url(), url);
       
  2856     QCOMPARE(reply->error(), QNetworkReply::NoError);
       
  2857     QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
       
  2858 
       
  2859     QCOMPARE(reply->readAll(), sourceFile.readAll());
       
  2860 }
       
  2861 
       
  2862 void tst_QNetworkReply::ioPostToHttpFromFile_data()
       
  2863 {
       
  2864     ioPutToFileFromFile_data();
       
  2865 }
       
  2866 
       
  2867 void tst_QNetworkReply::ioPostToHttpFromFile()
       
  2868 {
       
  2869     QFETCH(QString, fileName);
       
  2870     QFile sourceFile(fileName);
       
  2871     QVERIFY(sourceFile.open(QIODevice::ReadOnly));
       
  2872 
       
  2873     QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi");
       
  2874     QNetworkRequest request(url);
       
  2875     QNetworkReplyPtr reply = manager.post(request, &sourceFile);
       
  2876 
       
  2877     connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  2878     QTestEventLoop::instance().enterLoop(10);
       
  2879     QVERIFY(!QTestEventLoop::instance().timeout());
       
  2880 
       
  2881     QCOMPARE(reply->url(), url);
       
  2882     QCOMPARE(reply->error(), QNetworkReply::NoError);
       
  2883 
       
  2884     // verify that the HTTP status code is 200 Ok
       
  2885     QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
       
  2886 
       
  2887     QVERIFY(sourceFile.atEnd());
       
  2888     sourceFile.seek(0);         // reset it to the beginning
       
  2889 
       
  2890     QCOMPARE(reply->readAll().trimmed(), md5sum(sourceFile.readAll()).toHex());
       
  2891 }
       
  2892 
       
  2893 void tst_QNetworkReply::ioPostToHttpFromSocket_data()
       
  2894 {
       
  2895     QTest::addColumn<QByteArray>("data");
       
  2896     QTest::addColumn<QByteArray>("md5sum");
       
  2897     QTest::addColumn<QUrl>("url");
       
  2898     QTest::addColumn<QNetworkProxy>("proxy");
       
  2899     QTest::addColumn<int>("authenticationRequiredCount");
       
  2900     QTest::addColumn<int>("proxyAuthenticationRequiredCount");
       
  2901 
       
  2902     for (int i = 0; i < proxies.count(); ++i)
       
  2903         for (int auth = 0; auth < 2; ++auth) {
       
  2904             QUrl url;
       
  2905             if (auth)
       
  2906                 url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi";
       
  2907             else
       
  2908                 url = "http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi";
       
  2909 
       
  2910             QNetworkProxy proxy = proxies.at(i).proxy;
       
  2911             QByteArray testsuffix = QByteArray(auth ? "+auth" : "") + proxies.at(i).tag;
       
  2912             int proxyauthcount = proxies.at(i).requiresAuthentication;
       
  2913 
       
  2914             QByteArray data;
       
  2915             data = "";
       
  2916             QTest::newRow("empty" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount;
       
  2917 
       
  2918             data = "This is a normal message.";
       
  2919             QTest::newRow("generic" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount;
       
  2920 
       
  2921             data = "This is a message to show that Qt rocks!\r\n\n";
       
  2922             QTest::newRow("small" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount;
       
  2923 
       
  2924             data = QByteArray("abcd\0\1\2\abcd",12);
       
  2925             QTest::newRow("with-nul" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount;
       
  2926 
       
  2927             data = QByteArray(4097, '\4');
       
  2928             QTest::newRow("4k+1" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount;
       
  2929 
       
  2930             data = QByteArray(128*1024+1, '\177');
       
  2931             QTest::newRow("128k+1" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount;
       
  2932         }
       
  2933 }
       
  2934 
       
  2935 void tst_QNetworkReply::ioPostToHttpFromSocket()
       
  2936 {
       
  2937     qRegisterMetaType<QNetworkProxy>(); // for QSignalSpy
       
  2938     qRegisterMetaType<QAuthenticator *>();
       
  2939     qRegisterMetaType<QNetworkReply *>();
       
  2940 
       
  2941     QFETCH(QByteArray, data);
       
  2942     QFETCH(QUrl, url);
       
  2943     QFETCH(QNetworkProxy, proxy);
       
  2944     SocketPair socketpair;
       
  2945     socketpair.create();
       
  2946     QVERIFY(socketpair.endPoints[0] && socketpair.endPoints[1]);
       
  2947 
       
  2948     socketpair.endPoints[0]->write(data);
       
  2949 
       
  2950     QNetworkRequest request(url);
       
  2951     manager.setProxy(proxy);
       
  2952     QNetworkReplyPtr reply = manager.post(QNetworkRequest(url), socketpair.endPoints[1]);
       
  2953     socketpair.endPoints[0]->close();
       
  2954 
       
  2955     connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  2956     connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
       
  2957             SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
       
  2958     connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
       
  2959             SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
       
  2960 
       
  2961     QSignalSpy authenticationRequiredSpy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
       
  2962     QSignalSpy proxyAuthenticationRequiredSpy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
       
  2963 
       
  2964 #ifdef Q_OS_SYMBIAN
       
  2965     QTestEventLoop::instance().enterLoop(6);
       
  2966 #else
       
  2967     QTestEventLoop::instance().enterLoop(3);
       
  2968 #endif
       
  2969 
       
  2970     disconnect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
       
  2971                this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
       
  2972     disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
       
  2973                this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
       
  2974     QCOMPARE(reply->error(), QNetworkReply::NoError);
       
  2975     QVERIFY(!QTestEventLoop::instance().timeout());
       
  2976 
       
  2977     QCOMPARE(reply->url(), url);
       
  2978     QCOMPARE(reply->error(), QNetworkReply::NoError);
       
  2979     // verify that the HTTP status code is 200 Ok
       
  2980     QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
       
  2981 
       
  2982     QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex());
       
  2983 
       
  2984     QTEST(authenticationRequiredSpy.count(), "authenticationRequiredCount");
       
  2985     QTEST(proxyAuthenticationRequiredSpy.count(), "proxyAuthenticationRequiredCount");
       
  2986  }
       
  2987 
       
  2988 // this tests checks if rewinding the POST-data to some place in the middle
       
  2989 // worked.
       
  2990 void tst_QNetworkReply::ioPostToHttpFromMiddleOfFileToEnd()
       
  2991 {
       
  2992     QFile sourceFile(SRCDIR "/rfc3252.txt");
       
  2993     QVERIFY(sourceFile.open(QIODevice::ReadOnly));
       
  2994     // seeking to the middle
       
  2995     sourceFile.seek(sourceFile.size() / 2);
       
  2996 
       
  2997     QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi";
       
  2998     QNetworkRequest request(url);
       
  2999     QNetworkReplyPtr reply = manager.post(QNetworkRequest(url), &sourceFile);
       
  3000 
       
  3001     connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  3002     connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
       
  3003             SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
       
  3004 
       
  3005     QTestEventLoop::instance().enterLoop(2);
       
  3006     disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
       
  3007                this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
       
  3008     QVERIFY(!QTestEventLoop::instance().timeout());
       
  3009 
       
  3010     // compare half data
       
  3011     sourceFile.seek(sourceFile.size() / 2);
       
  3012     QByteArray data = sourceFile.readAll();
       
  3013     QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex());
       
  3014 }
       
  3015 
       
  3016 void tst_QNetworkReply::ioPostToHttpFromMiddleOfFileFiveBytes()
       
  3017 {
       
  3018     QFile sourceFile(SRCDIR "/rfc3252.txt");
       
  3019     QVERIFY(sourceFile.open(QIODevice::ReadOnly));
       
  3020     // seeking to the middle
       
  3021     sourceFile.seek(sourceFile.size() / 2);
       
  3022 
       
  3023     QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi";
       
  3024     QNetworkRequest request(url);
       
  3025     // only send 5 bytes
       
  3026     request.setHeader(QNetworkRequest::ContentLengthHeader, 5);
       
  3027     QVERIFY(request.header(QNetworkRequest::ContentLengthHeader).isValid());
       
  3028     QNetworkReplyPtr reply = manager.post(request, &sourceFile);
       
  3029 
       
  3030     connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  3031     connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
       
  3032             SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
       
  3033 
       
  3034     QTestEventLoop::instance().enterLoop(2);
       
  3035     disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
       
  3036                this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
       
  3037     QVERIFY(!QTestEventLoop::instance().timeout());
       
  3038 
       
  3039     // compare half data
       
  3040     sourceFile.seek(sourceFile.size() / 2);
       
  3041     QByteArray data = sourceFile.read(5);
       
  3042     QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex());
       
  3043 }
       
  3044 
       
  3045 void tst_QNetworkReply::ioPostToHttpFromMiddleOfQBufferFiveBytes()
       
  3046 {
       
  3047     // test needed since a QBuffer goes with a different codepath than the QFile
       
  3048     // tested in ioPostToHttpFromMiddleOfFileFiveBytes
       
  3049     QBuffer uploadBuffer;
       
  3050     uploadBuffer.open(QIODevice::ReadWrite);
       
  3051     uploadBuffer.write("1234567890");
       
  3052     uploadBuffer.seek(5);
       
  3053 
       
  3054     QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi";
       
  3055     QNetworkRequest request(url);
       
  3056     QNetworkReplyPtr reply = manager.post(request, &uploadBuffer);
       
  3057 
       
  3058     connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  3059     connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
       
  3060             SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
       
  3061 
       
  3062     QTestEventLoop::instance().enterLoop(2);
       
  3063     disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
       
  3064                this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
       
  3065     QVERIFY(!QTestEventLoop::instance().timeout());
       
  3066 
       
  3067     // compare half data
       
  3068     uploadBuffer.seek(5);
       
  3069     QByteArray data = uploadBuffer.read(5);
       
  3070     QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex());
       
  3071 }
       
  3072 
       
  3073 
       
  3074 void tst_QNetworkReply::ioPostToHttpNoBufferFlag()
       
  3075 {
       
  3076     QByteArray data = QByteArray("daaaaaaataaaaaaa");
       
  3077     // create a sequential QIODevice by feeding the data into a local TCP server
       
  3078     SocketPair socketpair;
       
  3079     socketpair.create();
       
  3080     QVERIFY(socketpair.endPoints[0] && socketpair.endPoints[1]);
       
  3081     socketpair.endPoints[0]->write(data);
       
  3082 
       
  3083     QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi";
       
  3084     QNetworkRequest request(url);
       
  3085     // disallow buffering
       
  3086     request.setAttribute(QNetworkRequest::DoNotBufferUploadDataAttribute, true);
       
  3087     request.setHeader(QNetworkRequest::ContentLengthHeader, data.size());
       
  3088     QNetworkReplyPtr reply = manager.post(request, socketpair.endPoints[1]);
       
  3089     socketpair.endPoints[0]->close();
       
  3090 
       
  3091     connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  3092     connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
       
  3093             SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
       
  3094 
       
  3095     QTestEventLoop::instance().enterLoop(2);
       
  3096     disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
       
  3097                this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
       
  3098 
       
  3099     // verify: error code is QNetworkReply::ContentReSendError
       
  3100     QCOMPARE(reply->error(), QNetworkReply::ContentReSendError);
       
  3101 }
       
  3102 
       
  3103 #ifndef QT_NO_OPENSSL
       
  3104 class SslServer : public QTcpServer {
       
  3105     Q_OBJECT
       
  3106 public:
       
  3107     SslServer() : socket(0) {};
       
  3108     void incomingConnection(int socketDescriptor) {
       
  3109         QSslSocket *serverSocket = new QSslSocket;
       
  3110         serverSocket->setParent(this);
       
  3111 
       
  3112         if (serverSocket->setSocketDescriptor(socketDescriptor)) {
       
  3113             connect(serverSocket, SIGNAL(encrypted()), this, SLOT(encryptedSlot()));
       
  3114             serverSocket->setProtocol(QSsl::AnyProtocol);
       
  3115             connect(serverSocket, SIGNAL(sslErrors(const QList<QSslError>&)), serverSocket, SLOT(ignoreSslErrors()));
       
  3116             serverSocket->setLocalCertificate (SRCDIR "/certs/server.pem");
       
  3117             serverSocket->setPrivateKey (SRCDIR  "/certs/server.key");
       
  3118             serverSocket->startServerEncryption();
       
  3119         } else {
       
  3120             delete serverSocket;
       
  3121         }
       
  3122     }
       
  3123 signals:
       
  3124     void newEncryptedConnection();
       
  3125 public slots:
       
  3126     void encryptedSlot() {
       
  3127         socket = (QSslSocket*) sender();
       
  3128         emit newEncryptedConnection();
       
  3129     }
       
  3130 public:
       
  3131     QSslSocket *socket;
       
  3132 };
       
  3133 
       
  3134 // very similar to ioPostToHttpUploadProgress but for SSL
       
  3135 void tst_QNetworkReply::ioPostToHttpsUploadProgress()
       
  3136 {
       
  3137     QFile sourceFile(SRCDIR "/bigfile");
       
  3138     QVERIFY(sourceFile.open(QIODevice::ReadOnly));
       
  3139 
       
  3140     // emulate a minimal https server
       
  3141     SslServer server;
       
  3142     server.listen(QHostAddress(QHostAddress::LocalHost), 0);
       
  3143 
       
  3144     // create the request
       
  3145     QUrl url = QUrl(QString("https://127.0.0.1:%1/").arg(server.serverPort()));
       
  3146     QNetworkRequest request(url);
       
  3147     QNetworkReplyPtr reply = manager.post(request, &sourceFile);
       
  3148     QSignalSpy spy(reply, SIGNAL(uploadProgress(qint64,qint64)));
       
  3149     connect(&server, SIGNAL(newEncryptedConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  3150     connect(reply, SIGNAL(sslErrors(const QList<QSslError>&)), reply, SLOT(ignoreSslErrors()));
       
  3151 
       
  3152     // get the request started and the incoming socket connected
       
  3153     QTestEventLoop::instance().enterLoop(10);
       
  3154     QVERIFY(!QTestEventLoop::instance().timeout());
       
  3155     QTcpSocket *incomingSocket = server.socket;
       
  3156     QVERIFY(incomingSocket);
       
  3157     disconnect(&server, SIGNAL(newEncryptedConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  3158 
       
  3159 
       
  3160     incomingSocket->setReadBufferSize(1*1024);
       
  3161     QTestEventLoop::instance().enterLoop(2);
       
  3162     // some progress should have been made
       
  3163     QList<QVariant> args = spy.last();
       
  3164     qDebug() << "tst_QNetworkReply::ioPostToHttpsUploadProgress"
       
  3165             << args.at(0).toLongLong()
       
  3166             << sourceFile.size()
       
  3167             << spy.size();
       
  3168     QVERIFY(!args.isEmpty());
       
  3169     QVERIFY(args.at(0).toLongLong() > 0);
       
  3170     // FIXME this is where it messes up
       
  3171 
       
  3172     QEXPECT_FAIL("", "Either the readBufferSize of QSslSocket is broken or we do upload too much. Hm.", Abort);
       
  3173     QVERIFY(args.at(0).toLongLong() != sourceFile.size());
       
  3174 
       
  3175     incomingSocket->setReadBufferSize(32*1024);
       
  3176     incomingSocket->read(16*1024);
       
  3177     QTestEventLoop::instance().enterLoop(2);
       
  3178     // some more progress than before
       
  3179     QList<QVariant> args2 = spy.last();
       
  3180     QVERIFY(!args2.isEmpty());
       
  3181     QVERIFY(args2.at(0).toLongLong() > args.at(0).toLongLong());
       
  3182 
       
  3183     // set the read buffer to unlimited
       
  3184     incomingSocket->setReadBufferSize(0);
       
  3185     QTestEventLoop::instance().enterLoop(10);
       
  3186     // progress should be finished
       
  3187     QList<QVariant> args3 = spy.last();
       
  3188     QVERIFY(!args3.isEmpty());
       
  3189     QVERIFY(args3.at(0).toLongLong() > args2.at(0).toLongLong());
       
  3190     QCOMPARE(args3.at(0).toLongLong(), args3.at(1).toLongLong());
       
  3191     QCOMPARE(args3.at(0).toLongLong(), sourceFile.size());
       
  3192 
       
  3193     // after sending this, the QNAM should emit finished()
       
  3194     connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  3195     incomingSocket->write("HTTP/1.0 200 OK\r\n");
       
  3196     incomingSocket->write("Content-Length: 0\r\n");
       
  3197     incomingSocket->write("\r\n");
       
  3198     QTestEventLoop::instance().enterLoop(10);
       
  3199     // not timeouted -> finished() was emitted
       
  3200     QVERIFY(!QTestEventLoop::instance().timeout());
       
  3201 
       
  3202     incomingSocket->close();
       
  3203     server.close();
       
  3204 }
       
  3205 #endif
       
  3206 
       
  3207 void tst_QNetworkReply::ioPostToHttpUploadProgress()
       
  3208 {
       
  3209     QFile sourceFile(SRCDIR "/bigfile");
       
  3210     QVERIFY(sourceFile.open(QIODevice::ReadOnly));
       
  3211 
       
  3212     // emulate a minimal http server
       
  3213     QTcpServer server;
       
  3214     server.listen(QHostAddress(QHostAddress::LocalHost), 0);
       
  3215 
       
  3216     // create the request
       
  3217     QUrl url = QUrl(QString("http://127.0.0.1:%1/").arg(server.serverPort()));
       
  3218     QNetworkRequest request(url);
       
  3219     QNetworkReplyPtr reply = manager.post(request, &sourceFile);
       
  3220     QSignalSpy spy(reply, SIGNAL(uploadProgress(qint64,qint64)));
       
  3221     connect(&server, SIGNAL(newConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  3222 
       
  3223     // get the request started and the incoming socket connected
       
  3224     QTestEventLoop::instance().enterLoop(10);
       
  3225     QVERIFY(!QTestEventLoop::instance().timeout());
       
  3226     QTcpSocket *incomingSocket = server.nextPendingConnection();
       
  3227     QVERIFY(incomingSocket);
       
  3228     disconnect(&server, SIGNAL(newConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  3229 
       
  3230     incomingSocket->setReadBufferSize(1*1024);
       
  3231     QTestEventLoop::instance().enterLoop(2);
       
  3232     // some progress should have been made
       
  3233     QList<QVariant> args = spy.last();
       
  3234     QVERIFY(!args.isEmpty());
       
  3235     QVERIFY(args.at(0).toLongLong() > 0);
       
  3236 
       
  3237     incomingSocket->setReadBufferSize(32*1024);
       
  3238     incomingSocket->read(16*1024);
       
  3239     QTestEventLoop::instance().enterLoop(2);
       
  3240     // some more progress than before
       
  3241     QList<QVariant> args2 = spy.last();
       
  3242     QVERIFY(!args2.isEmpty());
       
  3243     QVERIFY(args2.at(0).toLongLong() > args.at(0).toLongLong());
       
  3244 
       
  3245     // set the read buffer to unlimited
       
  3246     incomingSocket->setReadBufferSize(0);
       
  3247     QTestEventLoop::instance().enterLoop(10);
       
  3248     // progress should be finished
       
  3249     QList<QVariant> args3 = spy.last();
       
  3250     QVERIFY(!args3.isEmpty());
       
  3251     QVERIFY(args3.at(0).toLongLong() > args2.at(0).toLongLong());
       
  3252     QCOMPARE(args3.at(0).toLongLong(), args3.at(1).toLongLong());
       
  3253     QCOMPARE(args3.at(0).toLongLong(), sourceFile.size());
       
  3254 
       
  3255     // after sending this, the QNAM should emit finished()
       
  3256     connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  3257     incomingSocket->write("HTTP/1.0 200 OK\r\n");
       
  3258     incomingSocket->write("Content-Length: 0\r\n");
       
  3259     incomingSocket->write("\r\n");
       
  3260     QTestEventLoop::instance().enterLoop(10);
       
  3261     // not timeouted -> finished() was emitted
       
  3262     QVERIFY(!QTestEventLoop::instance().timeout());
       
  3263 
       
  3264     incomingSocket->close();
       
  3265     server.close();
       
  3266 }
       
  3267 
       
  3268 void tst_QNetworkReply::ioPostToHttpEmtpyUploadProgress()
       
  3269 {
       
  3270     QByteArray ba;
       
  3271     ba.resize(0);
       
  3272     QBuffer buffer(&ba,0);
       
  3273     QVERIFY(buffer.open(QIODevice::ReadOnly));
       
  3274 
       
  3275     // emulate a minimal http server
       
  3276     QTcpServer server;
       
  3277     server.listen(QHostAddress(QHostAddress::LocalHost), 0);
       
  3278 
       
  3279     // create the request
       
  3280     QUrl url = QUrl(QString("http://127.0.0.1:%1/").arg(server.serverPort()));
       
  3281     QNetworkRequest request(url);
       
  3282     QNetworkReplyPtr reply = manager.post(request, &buffer);
       
  3283     QSignalSpy spy(reply, SIGNAL(uploadProgress(qint64,qint64)));
       
  3284     connect(&server, SIGNAL(newConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  3285 
       
  3286 
       
  3287     // get the request started and the incoming socket connected
       
  3288     QTestEventLoop::instance().enterLoop(10);
       
  3289     QVERIFY(!QTestEventLoop::instance().timeout());
       
  3290     QTcpSocket *incomingSocket = server.nextPendingConnection();
       
  3291     QVERIFY(incomingSocket);
       
  3292 
       
  3293     // after sending this, the QNAM should emit finished()
       
  3294     connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  3295     incomingSocket->write("HTTP/1.0 200 OK\r\n");
       
  3296     incomingSocket->write("Content-Length: 0\r\n");
       
  3297     incomingSocket->write("\r\n");
       
  3298     incomingSocket->flush();
       
  3299     QTestEventLoop::instance().enterLoop(10);
       
  3300     // not timeouted -> finished() was emitted
       
  3301     QVERIFY(!QTestEventLoop::instance().timeout());
       
  3302 
       
  3303     // final check: only 1 uploadProgress has been emitted
       
  3304     QVERIFY(spy.length() == 1);
       
  3305     QList<QVariant> args = spy.last();
       
  3306     QVERIFY(!args.isEmpty());
       
  3307     QCOMPARE(args.at(0).toLongLong(), buffer.size());
       
  3308     QCOMPARE(args.at(0).toLongLong(), buffer.size());
       
  3309 
       
  3310     incomingSocket->close();
       
  3311     server.close();
       
  3312 }
       
  3313 
       
  3314 
       
  3315 void tst_QNetworkReply::rateControl_data()
       
  3316 {
       
  3317     QTest::addColumn<int>("rate");
       
  3318 
       
  3319     QTest::newRow("15") << 15;
       
  3320     QTest::newRow("40") << 40;
       
  3321     QTest::newRow("73") << 73;
       
  3322     QTest::newRow("80") << 80;
       
  3323     QTest::newRow("125") << 125;
       
  3324     QTest::newRow("250") << 250;
       
  3325     QTest::newRow("1024") << 1024;
       
  3326 }
       
  3327 
       
  3328 void tst_QNetworkReply::rateControl()
       
  3329 {
       
  3330     QSKIP("Test disabled -- only for manual purposes", SkipAll);
       
  3331     // this function tests that we aren't reading from the network
       
  3332     // faster than the data is being consumed.
       
  3333     QFETCH(int, rate);
       
  3334 
       
  3335     // ask for 20 seconds worth of data
       
  3336     FastSender sender(20 * rate * 1024);
       
  3337 
       
  3338     QNetworkRequest request("debugpipe://localhost:" + QString::number(sender.serverPort()));
       
  3339     QNetworkReplyPtr reply = manager.get(request);
       
  3340     reply->setReadBufferSize(32768);
       
  3341     connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  3342 
       
  3343     RateControlledReader reader(reply, rate);
       
  3344 
       
  3345     // this test is designed to run for 25 seconds at most
       
  3346     QTime loopTime;
       
  3347     loopTime.start();
       
  3348     QTestEventLoop::instance().enterLoop(40);
       
  3349     int elapsedTime = loopTime.elapsed();
       
  3350 
       
  3351     qDebug() << "tst_QNetworkReply::rateControl" << "send rate:" << sender.transferRate;
       
  3352     qDebug() << "tst_QNetworkReply::rateControl" << "receive rate:" << reader.totalBytesRead * 1000 / elapsedTime
       
  3353              << "(it received" << reader.totalBytesRead << "bytes in" << elapsedTime << "ms)";
       
  3354 
       
  3355     sender.wait();
       
  3356     QVERIFY(!QTestEventLoop::instance().timeout());
       
  3357 
       
  3358     QCOMPARE(reply->url(), request.url());
       
  3359     QCOMPARE(reply->error(), QNetworkReply::NoError);
       
  3360 
       
  3361     QVERIFY(sender.transferRate != -1);
       
  3362     int minRate = rate * 1024 * 9 / 10;
       
  3363     int maxRate = rate * 1024 * 11 / 10;
       
  3364     QVERIFY(sender.transferRate >= minRate);
       
  3365     QVERIFY(sender.transferRate <= maxRate);
       
  3366 }
       
  3367 
       
  3368 void tst_QNetworkReply::downloadPerformance()
       
  3369 {
       
  3370     // unlike the above function, this one tries to send as fast as possible
       
  3371     // and measures how fast it was.
       
  3372     TimedSender sender(5000);
       
  3373     QNetworkRequest request("debugpipe://127.0.0.1:" + QString::number(sender.serverPort()) + "/?bare=1");
       
  3374     QNetworkReplyPtr reply = manager.get(request);
       
  3375     DataReader reader(reply, false);
       
  3376 
       
  3377     QTime loopTime;
       
  3378     connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  3379     loopTime.start();
       
  3380     QTestEventLoop::instance().enterLoop(40);
       
  3381     int elapsedTime = loopTime.elapsed();
       
  3382     sender.wait();
       
  3383 
       
  3384     qint64 receivedBytes = reader.totalBytes;
       
  3385     qDebug() << "tst_QNetworkReply::downloadPerformance" << "receive rate:" << (receivedBytes * 1000 / elapsedTime / 1024) << "kB/s and"
       
  3386              << elapsedTime << "ms";
       
  3387 }
       
  3388 
       
  3389 void tst_QNetworkReply::uploadPerformance()
       
  3390 {
       
  3391       ThreadedDataReader reader;
       
  3392       DataGenerator generator;
       
  3393 
       
  3394 
       
  3395       QNetworkRequest request("debugpipe://127.0.0.1:" + QString::number(reader.serverPort()) + "/?bare=1");
       
  3396       QNetworkReplyPtr reply = manager.put(request, &generator);
       
  3397       generator.start();
       
  3398       connect(&reader, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  3399       QTimer::singleShot(5000, &generator, SLOT(stop()));
       
  3400 
       
  3401       QTestEventLoop::instance().enterLoop(30);
       
  3402       QCOMPARE(reply->error(), QNetworkReply::NoError);
       
  3403       QVERIFY(!QTestEventLoop::instance().timeout());
       
  3404 }
       
  3405 
       
  3406 void tst_QNetworkReply::httpUploadPerformance()
       
  3407 {
       
  3408 #ifdef Q_OS_SYMBIAN
       
  3409       // SHow some mercy for non-desktop platform/s
       
  3410       enum {UploadSize = 4*1024*1024}; // 4 MB
       
  3411 #else
       
  3412       enum {UploadSize = 128*1024*1024}; // 128 MB
       
  3413 #endif
       
  3414       ThreadedDataReaderHttpServer reader;
       
  3415       FixedSizeDataGenerator generator(UploadSize);
       
  3416 
       
  3417       QNetworkRequest request(QUrl("http://127.0.0.1:" + QString::number(reader.serverPort()) + "/?bare=1"));
       
  3418       request.setHeader(QNetworkRequest::ContentLengthHeader,UploadSize);
       
  3419 
       
  3420       QNetworkReplyPtr reply = manager.put(request, &generator);
       
  3421 
       
  3422       connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  3423 
       
  3424       QTime time;
       
  3425       generator.start();
       
  3426       time.start();
       
  3427       QTestEventLoop::instance().enterLoop(40);
       
  3428       QCOMPARE(reply->error(), QNetworkReply::NoError);
       
  3429       QVERIFY(!QTestEventLoop::instance().timeout());
       
  3430 
       
  3431       qint64 elapsed = time.elapsed();
       
  3432       qDebug() << "tst_QNetworkReply::httpUploadPerformance" << elapsed << "msec, "
       
  3433               << ((UploadSize/1024.0)/(elapsed/1000.0)) << " kB/sec";
       
  3434 
       
  3435       reader.exit();
       
  3436       reader.wait();
       
  3437 }
       
  3438 
       
  3439 
       
  3440 void tst_QNetworkReply::performanceControlRate()
       
  3441 {
       
  3442     // this is a control comparison for the other two above
       
  3443     // it does the same thing, but instead bypasses the QNetworkAccess system
       
  3444     qDebug() << "The following are the maximum transfer rates that we can get in this system"
       
  3445         " (bypassing QNetworkAccess)";
       
  3446 
       
  3447     TimedSender sender(5000);
       
  3448     QTcpSocket sink;
       
  3449     sink.connectToHost("127.0.0.1", sender.serverPort());
       
  3450     DataReader reader(&sink, false);
       
  3451 
       
  3452     QTime loopTime;
       
  3453     connect(&sink, SIGNAL(disconnected()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  3454     loopTime.start();
       
  3455     QTestEventLoop::instance().enterLoop(40);
       
  3456     int elapsedTime = loopTime.elapsed();
       
  3457     sender.wait();
       
  3458 
       
  3459     qint64 receivedBytes = reader.totalBytes;
       
  3460     qDebug() << "tst_QNetworkReply::performanceControlRate" << "receive rate:" << (receivedBytes * 1000 / elapsedTime / 1024) << "kB/s and"
       
  3461              << elapsedTime << "ms";
       
  3462 }
       
  3463 
       
  3464 void tst_QNetworkReply::httpDownloadPerformance_data()
       
  3465 {
       
  3466     QTest::addColumn<bool>("serverSendsContentLength");
       
  3467     QTest::addColumn<bool>("chunkedEncoding");
       
  3468 
       
  3469     QTest::newRow("Server sends no Content-Length") << false << false;
       
  3470     QTest::newRow("Server sends Content-Length")     << true << false;
       
  3471     QTest::newRow("Server uses chunked encoding")     << false << true;
       
  3472 
       
  3473 }
       
  3474 
       
  3475 void tst_QNetworkReply::httpDownloadPerformance()
       
  3476 {
       
  3477     QFETCH(bool, serverSendsContentLength);
       
  3478     QFETCH(bool, chunkedEncoding);
       
  3479 #ifdef Q_OS_SYMBIAN
       
  3480     // Show some mercy to non-desktop platform/s
       
  3481     enum {UploadSize = 4*1024*1024}; // 4 MB
       
  3482 #else
       
  3483     enum {UploadSize = 128*1024*1024}; // 128 MB
       
  3484 #endif
       
  3485     HttpDownloadPerformanceServer server(UploadSize, serverSendsContentLength, chunkedEncoding);
       
  3486 
       
  3487     QNetworkRequest request(QUrl("http://127.0.0.1:" + QString::number(server.serverPort()) + "/?bare=1"));
       
  3488     QNetworkReplyPtr reply = manager.get(request);
       
  3489 
       
  3490     connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
       
  3491     HttpDownloadPerformanceClient client(reply);
       
  3492 
       
  3493     QTime time;
       
  3494     time.start();
       
  3495     QTestEventLoop::instance().enterLoop(40);
       
  3496     QCOMPARE(reply->error(), QNetworkReply::NoError);
       
  3497     QVERIFY(!QTestEventLoop::instance().timeout());
       
  3498 
       
  3499     qint64 elapsed = time.elapsed();
       
  3500     qDebug() << "tst_QNetworkReply::httpDownloadPerformance" << elapsed << "msec, "
       
  3501             << ((UploadSize/1024.0)/(elapsed/1000.0)) << " kB/sec";
       
  3502 }
       
  3503 
       
  3504 void tst_QNetworkReply::downloadProgress_data()
       
  3505 {
       
  3506     QTest::addColumn<int>("loopCount");
       
  3507 
       
  3508     QTest::newRow("empty") << 0;
       
  3509     QTest::newRow("small") << 4;
       
  3510 #ifndef Q_OS_SYMBIAN
       
  3511     QTest::newRow("big") << 4096;
       
  3512 #else
       
  3513     // it can run even with 4096
       
  3514 	// but it takes lot time
       
  3515 	//especially on emulator
       
  3516     QTest::newRow("big") << 1024;
       
  3517 #endif
       
  3518 }
       
  3519 
       
  3520 void tst_QNetworkReply::downloadProgress()
       
  3521 {
       
  3522     QTcpServer server;
       
  3523     QVERIFY(server.listen());
       
  3524 
       
  3525     QNetworkRequest request("debugpipe://127.0.0.1:" + QString::number(server.serverPort()) + "/?bare=1");
       
  3526     QNetworkReplyPtr reply = manager.get(request);
       
  3527     QSignalSpy spy(reply, SIGNAL(downloadProgress(qint64,qint64)));
       
  3528     connect(reply, SIGNAL(downloadProgress(qint64,qint64)),
       
  3529             &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  3530     QVERIFY(spy.isValid());
       
  3531     QVERIFY(!reply->isFinished());
       
  3532     QVERIFY(reply->isRunning());
       
  3533 
       
  3534     QCoreApplication::instance()->processEvents();
       
  3535     if (!server.hasPendingConnections())
       
  3536         server.waitForNewConnection(1000);
       
  3537     QVERIFY(server.hasPendingConnections());
       
  3538     QCOMPARE(spy.count(), 0);
       
  3539 
       
  3540     QByteArray data(128, 'a');
       
  3541     QTcpSocket *sender = server.nextPendingConnection();
       
  3542     QVERIFY(sender);
       
  3543 
       
  3544     QFETCH(int, loopCount);
       
  3545     for (int i = 1; i <= loopCount; ++i) {
       
  3546         sender->write(data);
       
  3547         QVERIFY2(sender->waitForBytesWritten(2000), "Network timeout");
       
  3548 
       
  3549         spy.clear();
       
  3550         QTestEventLoop::instance().enterLoop(2);
       
  3551         QVERIFY(!QTestEventLoop::instance().timeout());
       
  3552         QVERIFY(spy.count() > 0);
       
  3553         QVERIFY(!reply->isFinished());
       
  3554         QVERIFY(reply->isRunning());
       
  3555 
       
  3556         QList<QVariant> args = spy.last();
       
  3557         QCOMPARE(args.at(0).toInt(), i*data.size());
       
  3558         QCOMPARE(args.at(1).toInt(), -1);
       
  3559     }
       
  3560 
       
  3561     // close the connection:
       
  3562     delete sender;
       
  3563 
       
  3564     spy.clear();
       
  3565     QTestEventLoop::instance().enterLoop(2);
       
  3566     QCOMPARE(reply->error(), QNetworkReply::NoError);
       
  3567     QVERIFY(!QTestEventLoop::instance().timeout());
       
  3568     QVERIFY(spy.count() > 0);
       
  3569     QVERIFY(!reply->isRunning());
       
  3570     QVERIFY(reply->isFinished());
       
  3571 
       
  3572     QList<QVariant> args = spy.last();
       
  3573     QCOMPARE(args.at(0).toInt(), loopCount * data.size());
       
  3574     QCOMPARE(args.at(1).toInt(), loopCount * data.size());
       
  3575 }
       
  3576 
       
  3577 void tst_QNetworkReply::uploadProgress_data()
       
  3578 {
       
  3579     putToFile_data();
       
  3580 }
       
  3581 
       
  3582 void tst_QNetworkReply::uploadProgress()
       
  3583 {
       
  3584     QFETCH(QByteArray, data);
       
  3585     QTcpServer server;
       
  3586     QVERIFY(server.listen());
       
  3587 
       
  3588     QNetworkRequest request("debugpipe://127.0.0.1:" + QString::number(server.serverPort()) + "/?bare=1");
       
  3589     QNetworkReplyPtr reply = manager.put(request, data);
       
  3590     QSignalSpy spy(reply, SIGNAL(uploadProgress(qint64,qint64)));
       
  3591     QSignalSpy finished(reply, SIGNAL(finished()));
       
  3592     QVERIFY(spy.isValid());
       
  3593     QVERIFY(finished.isValid());
       
  3594 
       
  3595     QCoreApplication::instance()->processEvents();
       
  3596     if (!server.hasPendingConnections())
       
  3597         server.waitForNewConnection(1000);
       
  3598     QVERIFY(server.hasPendingConnections());
       
  3599 
       
  3600     QTcpSocket *receiver = server.nextPendingConnection();
       
  3601     if (finished.count() == 0) {
       
  3602         // it's not finished yet, so wait for it to be
       
  3603         connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  3604         QTestEventLoop::instance().enterLoop(2);
       
  3605         QVERIFY(!QTestEventLoop::instance().timeout());
       
  3606     }
       
  3607     delete receiver;
       
  3608 
       
  3609     QVERIFY(finished.count() > 0);
       
  3610     QVERIFY(spy.count() > 0);
       
  3611 
       
  3612     QList<QVariant> args = spy.last();
       
  3613     QCOMPARE(args.at(0).toInt(), data.size());
       
  3614     QCOMPARE(args.at(1).toInt(), data.size());
       
  3615 }
       
  3616 
       
  3617 void tst_QNetworkReply::chaining_data()
       
  3618 {
       
  3619     putToFile_data();
       
  3620 }
       
  3621 
       
  3622 void tst_QNetworkReply::chaining()
       
  3623 {
       
  3624     QTemporaryFile sourceFile(QDir::currentPath() + "/temp-XXXXXX");
       
  3625     sourceFile.setAutoRemove(true);
       
  3626     QVERIFY(sourceFile.open());
       
  3627 
       
  3628     QFETCH(QByteArray, data);
       
  3629     QVERIFY(sourceFile.write(data) == data.size());
       
  3630     sourceFile.flush();
       
  3631     QCOMPARE(sourceFile.size(), qint64(data.size()));
       
  3632 
       
  3633     QNetworkRequest request(QUrl::fromLocalFile(sourceFile.fileName()));
       
  3634     QNetworkReplyPtr getReply = manager.get(request);
       
  3635 
       
  3636     QFile targetFile(testFileName);
       
  3637     QUrl url = QUrl::fromLocalFile(targetFile.fileName());
       
  3638     request.setUrl(url);
       
  3639     QNetworkReplyPtr putReply = manager.put(request, getReply);
       
  3640 
       
  3641     connect(putReply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  3642     QTestEventLoop::instance().enterLoop(10);
       
  3643     QVERIFY(!QTestEventLoop::instance().timeout());
       
  3644 
       
  3645     QCOMPARE(getReply->url(), QUrl::fromLocalFile(sourceFile.fileName()));
       
  3646     QCOMPARE(getReply->error(), QNetworkReply::NoError);
       
  3647     QCOMPARE(getReply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), sourceFile.size());
       
  3648 
       
  3649     QCOMPARE(putReply->url(), url);
       
  3650     QCOMPARE(putReply->error(), QNetworkReply::NoError);
       
  3651     QCOMPARE(putReply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0));
       
  3652     QVERIFY(putReply->readAll().isEmpty());
       
  3653 
       
  3654     QVERIFY(sourceFile.atEnd());
       
  3655     sourceFile.seek(0);         // reset it to the beginning
       
  3656 
       
  3657     QVERIFY(targetFile.open(QIODevice::ReadOnly));
       
  3658     QCOMPARE(targetFile.size(), sourceFile.size());
       
  3659     QCOMPARE(targetFile.readAll(), sourceFile.readAll());
       
  3660 }
       
  3661 
       
  3662 void tst_QNetworkReply::receiveCookiesFromHttp_data()
       
  3663 {
       
  3664     QTest::addColumn<QString>("cookieString");
       
  3665     QTest::addColumn<QList<QNetworkCookie> >("expectedCookiesFromHttp");
       
  3666     QTest::addColumn<QList<QNetworkCookie> >("expectedCookiesInJar");
       
  3667 
       
  3668     QTest::newRow("empty") << "" << QList<QNetworkCookie>() << QList<QNetworkCookie>();
       
  3669 
       
  3670     QList<QNetworkCookie> header, jar;
       
  3671     QNetworkCookie cookie("a", "b");
       
  3672     header << cookie;
       
  3673     cookie.setDomain(QtNetworkSettings::serverName());
       
  3674     cookie.setPath("/qtest/cgi-bin/");
       
  3675     jar << cookie;
       
  3676     QTest::newRow("simple-cookie") << "a=b" << header << jar;
       
  3677 
       
  3678     header << QNetworkCookie("c", "d");
       
  3679     cookie.setName("c");
       
  3680     cookie.setValue("d");
       
  3681     jar << cookie;
       
  3682     QTest::newRow("two-cookies") << "a=b, c=d" << header << jar;
       
  3683     QTest::newRow("two-cookies-2") << "a=b\nc=d" << header << jar;
       
  3684 
       
  3685     header.clear();
       
  3686     jar.clear();
       
  3687     cookie = QNetworkCookie("a", "b");
       
  3688     cookie.setPath("/not/part-of-path");
       
  3689     header << cookie;
       
  3690     QTest::newRow("invalid-cookie-path") << "a=b; path=/not/part-of-path" << header << jar;
       
  3691 
       
  3692     cookie = QNetworkCookie("a", "b");
       
  3693     cookie.setDomain(".example.com");
       
  3694     header.clear();
       
  3695     header << cookie;
       
  3696     QTest::newRow("invalid-cookie-domain") << "a=b; domain=.example.com" << header << jar;
       
  3697 }
       
  3698 
       
  3699 void tst_QNetworkReply::receiveCookiesFromHttp()
       
  3700 {
       
  3701 	QFETCH(QString, cookieString);
       
  3702 
       
  3703     QByteArray data = cookieString.toLatin1() + '\n';
       
  3704     QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/set-cookie.cgi");
       
  3705     QNetworkRequest request(url);
       
  3706     QNetworkReplyPtr reply;
       
  3707     RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PostOperation, request, reply, data));
       
  3708 
       
  3709     QCOMPARE(reply->url(), url);
       
  3710     QCOMPARE(reply->error(), QNetworkReply::NoError);
       
  3711 
       
  3712     QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
       
  3713 
       
  3714     QList<QNetworkCookie> setCookies =
       
  3715         qvariant_cast<QList<QNetworkCookie> >(reply->header(QNetworkRequest::SetCookieHeader));
       
  3716     QTEST(setCookies, "expectedCookiesFromHttp");
       
  3717     QTEST(cookieJar->allCookies(), "expectedCookiesInJar");
       
  3718 }
       
  3719 
       
  3720 void tst_QNetworkReply::sendCookies_data()
       
  3721 {
       
  3722     QTest::addColumn<QList<QNetworkCookie> >("cookiesToSet");
       
  3723     QTest::addColumn<QString>("expectedCookieString");
       
  3724 
       
  3725     QList<QNetworkCookie> list;
       
  3726     QTest::newRow("empty") << list << "";
       
  3727 
       
  3728     QNetworkCookie cookie("a", "b");
       
  3729     cookie.setPath("/");
       
  3730     cookie.setDomain("example.com");
       
  3731     list << cookie;
       
  3732     QTest::newRow("no-match-domain") << list << "";
       
  3733 
       
  3734     cookie.setDomain(QtNetworkSettings::serverName());
       
  3735     cookie.setPath("/something/else");
       
  3736     list << cookie;
       
  3737     QTest::newRow("no-match-path") << list << "";
       
  3738 
       
  3739     cookie.setPath("/");
       
  3740     list << cookie;
       
  3741     QTest::newRow("simple-cookie") << list << "a=b";
       
  3742 
       
  3743     cookie.setPath("/qtest");
       
  3744     cookie.setValue("longer");
       
  3745     list << cookie;
       
  3746     QTest::newRow("two-cookies") << list << "a=longer; a=b";
       
  3747 
       
  3748     list.clear();
       
  3749     cookie = QNetworkCookie("a", "b");
       
  3750     cookie.setPath("/");
       
  3751     cookie.setDomain("." + QtNetworkSettings::serverDomainName());
       
  3752     list << cookie;
       
  3753     QTest::newRow("domain-match") << list << "a=b";
       
  3754 
       
  3755     // but it shouldn't match this:
       
  3756     cookie.setDomain(QtNetworkSettings::serverDomainName());
       
  3757     list << cookie;
       
  3758     QTest::newRow("domain-match-2") << list << "a=b";
       
  3759 }
       
  3760 
       
  3761 void tst_QNetworkReply::sendCookies()
       
  3762 {
       
  3763     QFETCH(QString, expectedCookieString);
       
  3764     QFETCH(QList<QNetworkCookie>, cookiesToSet);
       
  3765     cookieJar->setAllCookies(cookiesToSet);
       
  3766 
       
  3767     QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/get-cookie.cgi");
       
  3768     QNetworkRequest request(url);
       
  3769     QNetworkReplyPtr reply;
       
  3770     RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
       
  3771 
       
  3772     QCOMPARE(reply->url(), url);
       
  3773     QCOMPARE(reply->error(), QNetworkReply::NoError);
       
  3774 
       
  3775     QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok
       
  3776 
       
  3777     QCOMPARE(QString::fromLatin1(reply->readAll()).trimmed(), expectedCookieString);
       
  3778 }
       
  3779 
       
  3780 void tst_QNetworkReply::nestedEventLoops_slot()
       
  3781 {
       
  3782     QEventLoop subloop;
       
  3783 
       
  3784     // 16 seconds: fluke times out in 15 seconds, which triggers a QTcpSocket error
       
  3785     QTimer::singleShot(16000, &subloop, SLOT(quit()));
       
  3786     subloop.exec();
       
  3787 
       
  3788     QTestEventLoop::instance().exitLoop();
       
  3789 }
       
  3790 
       
  3791 void tst_QNetworkReply::nestedEventLoops()
       
  3792 {
       
  3793     // Slightly fragile test, it may not be testing anything
       
  3794     // This is certifying that we're not running into the same issue
       
  3795     // that QHttp had (task 200432): the QTcpSocket connection is
       
  3796     // closed by the remote end because of the kept-alive HTTP
       
  3797     // connection timed out.
       
  3798     //
       
  3799     // The exact time required for this to happen is not exactly
       
  3800     // defined. Our server (Apache httpd) times out after 15
       
  3801     // seconds. (see above)
       
  3802 
       
  3803     qDebug("Takes 16 seconds to run, please wait");
       
  3804     qRegisterMetaType<QNetworkReply::NetworkError>();
       
  3805 
       
  3806     QUrl url("http://" + QtNetworkSettings::serverName());
       
  3807     QNetworkRequest request(url);
       
  3808     QNetworkReplyPtr reply = manager.get(request);
       
  3809 
       
  3810     QSignalSpy finishedspy(reply, SIGNAL(finished()));
       
  3811     QSignalSpy errorspy(reply, SIGNAL(error(QNetworkReply::NetworkError)));
       
  3812 
       
  3813     connect(reply, SIGNAL(finished()), SLOT(nestedEventLoops_slot()));
       
  3814     QTestEventLoop::instance().enterLoop(20);
       
  3815     QVERIFY2(!QTestEventLoop::instance().timeout(), "Network timeout");
       
  3816 
       
  3817     QCOMPARE(finishedspy.count(), 1);
       
  3818     QCOMPARE(errorspy.count(), 0);
       
  3819 }
       
  3820 
       
  3821 void tst_QNetworkReply::httpProxyCommands_data()
       
  3822 {
       
  3823     QTest::addColumn<QUrl>("url");
       
  3824     QTest::addColumn<QByteArray>("responseToSend");
       
  3825     QTest::addColumn<QString>("expectedCommand");
       
  3826 
       
  3827     QTest::newRow("http")
       
  3828         << QUrl("http://0.0.0.0:4443/http-request")
       
  3829         << QByteArray("HTTP/1.0 200 OK\r\nProxy-Connection: close\r\nContent-Length: 1\r\n\r\n1")
       
  3830         << "GET http://0.0.0.0:4443/http-request HTTP/1.";
       
  3831 #ifndef QT_NO_OPENSSL
       
  3832     QTest::newRow("https")
       
  3833         << QUrl("https://0.0.0.0:4443/https-request")
       
  3834         << QByteArray("HTTP/1.0 200 Connection Established\r\n\r\n")
       
  3835         << "CONNECT 0.0.0.0:4443 HTTP/1.";
       
  3836 #endif
       
  3837 }
       
  3838 
       
  3839 void tst_QNetworkReply::httpProxyCommands()
       
  3840 {
       
  3841     QFETCH(QUrl, url);
       
  3842     QFETCH(QByteArray, responseToSend);
       
  3843     QFETCH(QString, expectedCommand);
       
  3844 
       
  3845     MiniHttpServer proxyServer(responseToSend);
       
  3846     QNetworkProxy proxy(QNetworkProxy::HttpProxy, "127.0.0.1", proxyServer.serverPort());
       
  3847 
       
  3848     manager.setProxy(proxy);
       
  3849     QNetworkReplyPtr reply = manager.get(QNetworkRequest(url));
       
  3850     manager.setProxy(QNetworkProxy());
       
  3851 
       
  3852     // wait for the finished signal
       
  3853     connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  3854 
       
  3855     QTestEventLoop::instance().enterLoop(1);
       
  3856 
       
  3857     QVERIFY(!QTestEventLoop::instance().timeout());
       
  3858 
       
  3859     //qDebug() << reply->error() << reply->errorString();
       
  3860 
       
  3861     // we don't really care if the request succeeded
       
  3862     // especially since it won't succeed in the HTTPS case
       
  3863     // so just check that the command was correct
       
  3864 
       
  3865     QString receivedHeader = proxyServer.receivedData.left(expectedCommand.length());
       
  3866     QCOMPARE(receivedHeader, expectedCommand);
       
  3867 }
       
  3868 
       
  3869 void tst_QNetworkReply::proxyChange()
       
  3870 {
       
  3871     MiniHttpServer proxyServer(
       
  3872         "HTTP/1.0 200 OK\r\nProxy-Connection: keep-alive\r\n"
       
  3873         "Content-Length: 1\r\n\r\n1");
       
  3874     QNetworkProxy dummyProxy(QNetworkProxy::HttpProxy, "127.0.0.1", proxyServer.serverPort());
       
  3875     QNetworkRequest req(QUrl("http://" + QtNetworkSettings::serverName()));
       
  3876     proxyServer.doClose = false;
       
  3877 
       
  3878     manager.setProxy(dummyProxy);
       
  3879     QNetworkReplyPtr reply1 = manager.get(req);
       
  3880     QSignalSpy finishedspy(reply1, SIGNAL(finished()));
       
  3881 
       
  3882     manager.setProxy(QNetworkProxy());
       
  3883     QNetworkReplyPtr reply2 = manager.get(req);
       
  3884 
       
  3885     connect(reply2, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  3886 #ifdef Q_OS_SYMBIAN
       
  3887     // we need more time as:
       
  3888     // 1. running from the emulator
       
  3889     // 2. not perfect POSIX implementation
       
  3890     // 3. embedded device
       
  3891     QTestEventLoop::instance().enterLoop(20);
       
  3892 #else
       
  3893     QTestEventLoop::instance().enterLoop(10);
       
  3894 #endif
       
  3895     QVERIFY(!QTestEventLoop::instance().timeout());
       
  3896 
       
  3897     if (finishedspy.count() == 0) {
       
  3898         // wait for the second reply as well
       
  3899         connect(reply1, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  3900         QTestEventLoop::instance().enterLoop(1);
       
  3901         QVERIFY(!QTestEventLoop::instance().timeout());
       
  3902     }
       
  3903 
       
  3904     // verify that the replies succeeded
       
  3905     QCOMPARE(reply1->error(), QNetworkReply::NoError);
       
  3906     QCOMPARE(reply1->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
       
  3907     QVERIFY(reply1->size() == 1);
       
  3908 
       
  3909     QCOMPARE(reply2->error(), QNetworkReply::NoError);
       
  3910     QCOMPARE(reply2->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
       
  3911     QVERIFY(reply2->size() > 1);
       
  3912 
       
  3913     // now try again and get an error
       
  3914     // this verifies that we reuse the already-open connection
       
  3915 
       
  3916     proxyServer.doClose = true;
       
  3917     proxyServer.dataToTransmit =
       
  3918         "HTTP/1.0 403 Forbidden\r\nProxy-Connection: close\r\n"
       
  3919         "Content-Length: 1\r\n\r\n1";
       
  3920 
       
  3921     manager.setProxy(dummyProxy);
       
  3922     QNetworkReplyPtr reply3 = manager.get(req);
       
  3923     connect(reply3, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  3924     QTestEventLoop::instance().enterLoop(1);
       
  3925     QVERIFY(!QTestEventLoop::instance().timeout());
       
  3926 
       
  3927     QVERIFY(int(reply3->error()) > 0);
       
  3928 }
       
  3929 
       
  3930 void tst_QNetworkReply::authorizationError_data()
       
  3931 {
       
  3932 
       
  3933     QTest::addColumn<QString>("url");
       
  3934     QTest::addColumn<int>("errorSignalCount");
       
  3935     QTest::addColumn<int>("finishedSignalCount");
       
  3936     QTest::addColumn<int>("error");
       
  3937     QTest::addColumn<int>("httpStatusCode");
       
  3938     QTest::addColumn<QString>("httpBody");
       
  3939 
       
  3940     QTest::newRow("unknown-authorization-method") << "http://" + QtNetworkSettings::serverName() +
       
  3941                                                      "/cgi-bin/http-unknown-authentication-method.cgi?401-authorization-required" << 1 << 1
       
  3942                                                   << int(QNetworkReply::AuthenticationRequiredError) << 401 << "authorization required";
       
  3943     QTest::newRow("unknown-proxy-authorization-method") << "http://" + QtNetworkSettings::serverName() +
       
  3944                                                            "/cgi-bin/http-unknown-authentication-method.cgi?407-proxy-authorization-required" << 1 << 1
       
  3945                                                         << int(QNetworkReply::ProxyAuthenticationRequiredError) << 407
       
  3946                                                         << "authorization required";
       
  3947 }
       
  3948 
       
  3949 void tst_QNetworkReply::authorizationError()
       
  3950 {
       
  3951     QFETCH(QString, url);
       
  3952     QNetworkRequest request(url);
       
  3953     QNetworkReplyPtr reply = manager.get(request);
       
  3954 
       
  3955     QCOMPARE(reply->error(), QNetworkReply::NoError);
       
  3956 
       
  3957     qRegisterMetaType<QNetworkReply::NetworkError>("QNetworkReply::NetworkError");
       
  3958     QSignalSpy errorSpy(reply, SIGNAL(error(QNetworkReply::NetworkError)));
       
  3959     QSignalSpy finishedSpy(reply, SIGNAL(finished()));
       
  3960     // now run the request:
       
  3961     connect(reply, SIGNAL(finished()),
       
  3962             &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  3963     QTestEventLoop::instance().enterLoop(10);
       
  3964     QVERIFY(!QTestEventLoop::instance().timeout());
       
  3965 
       
  3966     QFETCH(int, errorSignalCount);
       
  3967     QCOMPARE(errorSpy.count(), errorSignalCount);
       
  3968     QFETCH(int, finishedSignalCount);
       
  3969     QCOMPARE(finishedSpy.count(), finishedSignalCount);
       
  3970     QFETCH(int, error);
       
  3971     QCOMPARE(reply->error(), QNetworkReply::NetworkError(error));
       
  3972 
       
  3973     QFETCH(int, httpStatusCode);
       
  3974     QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), httpStatusCode);
       
  3975 
       
  3976     QFETCH(QString, httpBody);
       
  3977     QCOMPARE(QString(reply->readAll()), httpBody);
       
  3978 }
       
  3979 
       
  3980 void tst_QNetworkReply::httpConnectionCount()
       
  3981 {
       
  3982     QTcpServer server;
       
  3983     QVERIFY(server.listen());
       
  3984     QCoreApplication::instance()->processEvents();
       
  3985 
       
  3986     for (int i = 0; i < 10; i++) {
       
  3987         QNetworkRequest request (QUrl("http://127.0.0.1:" + QString::number(server.serverPort()) + "/" +  QString::number(i)));
       
  3988         QNetworkReply* reply = manager.get(request);
       
  3989         reply->setParent(this);
       
  3990     }
       
  3991 
       
  3992     int pendingConnectionCount = 0;
       
  3993     QTime time;
       
  3994     time.start();
       
  3995 
       
  3996     while(pendingConnectionCount <= 20) {
       
  3997         QTestEventLoop::instance().enterLoop(1);
       
  3998         QTcpSocket *socket = server.nextPendingConnection();
       
  3999         while (socket != 0) {
       
  4000             pendingConnectionCount++;
       
  4001             socket->setParent(&server);
       
  4002             socket = server.nextPendingConnection();
       
  4003         }
       
  4004 
       
  4005         // at max. wait 10 sec
       
  4006         if (time.elapsed() > 10000)
       
  4007             break;
       
  4008     }
       
  4009 
       
  4010 #ifdef Q_OS_SYMBIAN
       
  4011     // see in qhttpnetworkconnection.cpp
       
  4012     // hardcoded defaultChannelCount = 3
       
  4013     QCOMPARE(pendingConnectionCount, 3);
       
  4014 #else
       
  4015     QCOMPARE(pendingConnectionCount, 6);
       
  4016 #endif
       
  4017 }
       
  4018 
       
  4019 #ifndef QT_NO_OPENSSL
       
  4020 void tst_QNetworkReply::ignoreSslErrorsList_data()
       
  4021 {
       
  4022     QTest::addColumn<QString>("url");
       
  4023     QTest::addColumn<QList<QSslError> >("expectedSslErrors");
       
  4024     QTest::addColumn<QNetworkReply::NetworkError>("expectedNetworkError");
       
  4025 
       
  4026     QList<QSslError> expectedSslErrors;
       
  4027     // apparently, because of some weird behaviour of SRCDIR, the file name below needs to start with a slash
       
  4028     QList<QSslCertificate> certs = QSslCertificate::fromPath(QLatin1String(SRCDIR "/certs/qt-test-server-cacert.pem"));
       
  4029     QSslError rightError(QSslError::SelfSignedCertificate, certs.at(0));
       
  4030     QSslError wrongError(QSslError::SelfSignedCertificate);
       
  4031 
       
  4032     QTest::newRow("SSL-failure-empty-list") << "https://" + QtNetworkSettings::serverName() + "/index.html" << expectedSslErrors << QNetworkReply::SslHandshakeFailedError;
       
  4033     expectedSslErrors.append(wrongError);
       
  4034     QTest::newRow("SSL-failure-wrong-error") << "https://" + QtNetworkSettings::serverName() + "/index.html" << expectedSslErrors << QNetworkReply::SslHandshakeFailedError;
       
  4035     expectedSslErrors.append(rightError);
       
  4036     QTest::newRow("allErrorsInExpectedList1") << "https://" + QtNetworkSettings::serverName() + "/index.html" << expectedSslErrors << QNetworkReply::NoError;
       
  4037     expectedSslErrors.removeAll(wrongError);
       
  4038     QTest::newRow("allErrorsInExpectedList2") << "https://" + QtNetworkSettings::serverName() + "/index.html" << expectedSslErrors << QNetworkReply::NoError;
       
  4039     expectedSslErrors.removeAll(rightError);
       
  4040     QTest::newRow("SSL-failure-empty-list-again") << "https://" + QtNetworkSettings::serverName() + "/index.html" << expectedSslErrors << QNetworkReply::SslHandshakeFailedError;
       
  4041 }
       
  4042 
       
  4043 void tst_QNetworkReply::ignoreSslErrorsList()
       
  4044 {
       
  4045     QFETCH(QString, url);
       
  4046     QNetworkRequest request(url);
       
  4047     QNetworkReplyPtr reply = manager.get(request);
       
  4048 
       
  4049     QFETCH(QList<QSslError>, expectedSslErrors);
       
  4050     reply->ignoreSslErrors(expectedSslErrors);
       
  4051 
       
  4052     connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  4053     QTestEventLoop::instance().enterLoop(10);
       
  4054     QVERIFY(!QTestEventLoop::instance().timeout());
       
  4055 
       
  4056     QFETCH(QNetworkReply::NetworkError, expectedNetworkError);
       
  4057     QCOMPARE(reply->error(), expectedNetworkError);
       
  4058 }
       
  4059 
       
  4060 void tst_QNetworkReply::ignoreSslErrorsListWithSlot_data()
       
  4061 {
       
  4062     ignoreSslErrorsList_data();
       
  4063 }
       
  4064 
       
  4065 // this is not a test, just a slot called in the test below
       
  4066 void tst_QNetworkReply::ignoreSslErrorListSlot(QNetworkReply *reply, const QList<QSslError> &)
       
  4067 {
       
  4068     reply->ignoreSslErrors(storedExpectedSslErrors);
       
  4069 }
       
  4070 
       
  4071 // do the same as in ignoreSslErrorsList, but ignore the errors in the slot
       
  4072 void tst_QNetworkReply::ignoreSslErrorsListWithSlot()
       
  4073 {
       
  4074     QFETCH(QString, url);
       
  4075     QNetworkRequest request(url);
       
  4076     QNetworkReplyPtr reply = manager.get(request);
       
  4077 
       
  4078     QFETCH(QList<QSslError>, expectedSslErrors);
       
  4079     // store the errors to ignore them later in the slot connected below
       
  4080     storedExpectedSslErrors = expectedSslErrors;
       
  4081     connect(&manager, SIGNAL(sslErrors(QNetworkReply *, const QList<QSslError> &)),
       
  4082             this, SLOT(ignoreSslErrorListSlot(QNetworkReply *, const QList<QSslError> &)));
       
  4083 
       
  4084 
       
  4085     connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  4086     QTestEventLoop::instance().enterLoop(10);
       
  4087     QVERIFY(!QTestEventLoop::instance().timeout());
       
  4088 
       
  4089     QFETCH(QNetworkReply::NetworkError, expectedNetworkError);
       
  4090     QCOMPARE(reply->error(), expectedNetworkError);
       
  4091 }
       
  4092 
       
  4093 #endif // QT_NO_OPENSSL
       
  4094 
       
  4095 QTEST_MAIN(tst_QNetworkReply)
       
  4096 #include "tst_qnetworkreply.moc"