tests/auto/qhttp/tst_qhttp.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 
       
    45 #include <qbuffer.h>
       
    46 #include <qcoreapplication.h>
       
    47 #include <qfile.h>
       
    48 #include <qhostinfo.h>
       
    49 #include <qhttp.h>
       
    50 #include <qlist.h>
       
    51 #include <qpointer.h>
       
    52 #include <qtcpsocket.h>
       
    53 #include <qtcpserver.h>
       
    54 #include <qauthenticator.h>
       
    55 #include <QNetworkProxy>
       
    56 #ifndef QT_NO_OPENSSL
       
    57 # include <qsslsocket.h>
       
    58 #endif
       
    59 
       
    60 #ifndef TEST_QNETWORK_PROXY
       
    61 #define TEST_QNETWORK_PROXY
       
    62 #endif
       
    63 #include "../network-settings.h"
       
    64 
       
    65 //TESTED_CLASS=
       
    66 //TESTED_FILES=
       
    67 
       
    68 #ifdef Q_OS_SYMBIAN
       
    69 // In Symbian OS test data is located in applications private dir
       
    70 // And underlying Open C have application private dir in default search path
       
    71 #define SRCDIR ""
       
    72 #endif
       
    73 
       
    74 Q_DECLARE_METATYPE(QHttpResponseHeader)
       
    75 
       
    76 class tst_QHttp : public QObject
       
    77 {
       
    78     Q_OBJECT
       
    79 
       
    80 public:
       
    81     tst_QHttp();
       
    82     virtual ~tst_QHttp();
       
    83 
       
    84 
       
    85 public slots:
       
    86     void initTestCase_data();
       
    87     void initTestCase();
       
    88     void cleanupTestCase();
       
    89     void init();
       
    90     void cleanup();
       
    91 private slots:
       
    92     void constructing();
       
    93     void invalidRequests();
       
    94     void get_data();
       
    95     void get();
       
    96     void head_data();
       
    97     void head();
       
    98     void post_data();
       
    99     void post();
       
   100     void request_data();
       
   101     void request();
       
   102     void authorization_data();
       
   103     void authorization();
       
   104     void proxy_data();
       
   105     void proxy();
       
   106     void proxy2();
       
   107     void proxy3();
       
   108     void postAuthNtlm();
       
   109     void proxyAndSsl();
       
   110     void cachingProxyAndSsl();
       
   111     void reconnect();
       
   112     void setSocket();
       
   113     void unexpectedRemoteClose();
       
   114     void pctEncodedPath();
       
   115     void caseInsensitiveKeys();
       
   116     void emptyBodyInReply();
       
   117     void abortInReadyRead();
       
   118     void abortInResponseHeaderReceived();
       
   119     void nestedEventLoop();
       
   120 
       
   121 
       
   122     // manual tests
       
   123     void connectionClose();
       
   124 
       
   125 protected slots:
       
   126     void stateChanged( int );
       
   127     void responseHeaderReceived( const QHttpResponseHeader & );
       
   128     void readyRead( const QHttpResponseHeader& );
       
   129     void dataSendProgress( int, int );
       
   130     void dataReadProgress( int , int );
       
   131 
       
   132     void requestStarted( int );
       
   133     void requestFinished( int, bool );
       
   134     void done( bool );
       
   135 
       
   136     void reconnect_state(int state);
       
   137     void proxy2_slot();
       
   138     void nestedEventLoop_slot(int id);
       
   139 
       
   140     void abortSender();
       
   141     void proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *auth);
       
   142 
       
   143 private:
       
   144     QHttp *newHttp(bool withAuth = false);
       
   145     void addRequest( QHttpRequestHeader, int );
       
   146     bool headerAreEqual( const QHttpHeader&, const QHttpHeader& );
       
   147 
       
   148     QHttp *http;
       
   149 
       
   150     struct RequestResult
       
   151     {
       
   152     QHttpRequestHeader req;
       
   153     QHttpResponseHeader resp;
       
   154     int success;
       
   155     };
       
   156     QMap< int, RequestResult > resultMap;
       
   157     typedef QMap<int,RequestResult>::Iterator ResMapIt;
       
   158     QList<int> ids; // helper to make sure that all expected signals are emitted
       
   159 
       
   160     int current_id;
       
   161     int cur_state;
       
   162     int done_success;
       
   163 
       
   164     QByteArray readyRead_ba;
       
   165 
       
   166     int bytesTotalSend;
       
   167     int bytesDoneSend;
       
   168     int bytesTotalRead;
       
   169     int bytesDoneRead;
       
   170 
       
   171     int getId;
       
   172     int headId;
       
   173     int postId;
       
   174 
       
   175     int reconnect_state_connect_count;
       
   176 
       
   177     bool connectionWithAuth;
       
   178     bool proxyAuthCalled;
       
   179 };
       
   180 
       
   181 //#define DUMP_SIGNALS
       
   182 
       
   183 const int bytesTotal_init = -10;
       
   184 const int bytesDone_init = -10;
       
   185 
       
   186 tst_QHttp::tst_QHttp()
       
   187 {
       
   188     Q_SET_DEFAULT_IAP
       
   189 }
       
   190 
       
   191 tst_QHttp::~tst_QHttp()
       
   192 {
       
   193 }
       
   194 
       
   195 void tst_QHttp::initTestCase_data()
       
   196 {
       
   197     QTest::addColumn<bool>("setProxy");
       
   198     QTest::addColumn<int>("proxyType");
       
   199 
       
   200     QTest::newRow("WithoutProxy") << false << 0;
       
   201 #ifdef TEST_QNETWORK_PROXY
       
   202     QTest::newRow("WithSocks5Proxy") << true << int(QNetworkProxy::Socks5Proxy);
       
   203 #endif
       
   204 }
       
   205 
       
   206 void tst_QHttp::initTestCase()
       
   207 {
       
   208 }
       
   209 
       
   210 void tst_QHttp::cleanupTestCase()
       
   211 {
       
   212 }
       
   213 
       
   214 void tst_QHttp::init()
       
   215 {
       
   216     QFETCH_GLOBAL(bool, setProxy);
       
   217     if (setProxy) {
       
   218         QFETCH_GLOBAL(int, proxyType);
       
   219         if (proxyType == QNetworkProxy::Socks5Proxy) {
       
   220             QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080));
       
   221         }
       
   222     }
       
   223 
       
   224     http = 0;
       
   225 
       
   226     resultMap.clear();
       
   227     ids.clear();
       
   228 
       
   229     current_id = 0;
       
   230     cur_state = QHttp::Unconnected;
       
   231     done_success = -1;
       
   232 
       
   233     readyRead_ba = QByteArray();
       
   234 
       
   235     getId = -1;
       
   236     headId = -1;
       
   237     postId = -1;
       
   238 }
       
   239 
       
   240 void tst_QHttp::cleanup()
       
   241 {
       
   242     delete http;
       
   243     http = 0;
       
   244 
       
   245     QCoreApplication::processEvents();
       
   246 
       
   247     QFETCH_GLOBAL(bool, setProxy);
       
   248     if (setProxy) {
       
   249         QNetworkProxy::setApplicationProxy(QNetworkProxy::DefaultProxy);
       
   250     }
       
   251 }
       
   252 
       
   253 void tst_QHttp::constructing()
       
   254 {
       
   255     //QHeader
       
   256     {
       
   257         QHttpRequestHeader header;
       
   258         header.addValue("key1", "val1");
       
   259         header.addValue("key2", "val2");
       
   260         header.addValue("key1", "val3");
       
   261         QCOMPARE(header.values().size(), 3);
       
   262         QCOMPARE(header.allValues("key1").size(), 2);
       
   263         QVERIFY(header.hasKey("key2"));
       
   264         QCOMPARE(header.keys().count(), 2);
       
   265 
       
   266     }
       
   267 
       
   268     {
       
   269         QHttpResponseHeader header(200);
       
   270     }
       
   271 }
       
   272 
       
   273 void tst_QHttp::invalidRequests()
       
   274 {
       
   275     QHttp http;
       
   276     http.setHost("localhost");  // we will not actually connect
       
   277 
       
   278     QTest::ignoreMessage(QtWarningMsg, "QHttp: empty path requested is invalid -- using '/'");
       
   279     http.get(QString());
       
   280 
       
   281     QTest::ignoreMessage(QtWarningMsg, "QHttp: empty path requested is invalid -- using '/'");
       
   282     http.head(QString());
       
   283 
       
   284     QTest::ignoreMessage(QtWarningMsg, "QHttp: empty path requested is invalid -- using '/'");
       
   285     http.post(QString(), QByteArray());
       
   286 
       
   287     QTest::ignoreMessage(QtWarningMsg, "QHttp: empty path requested is invalid -- using '/'");
       
   288     http.request(QHttpRequestHeader("PROPFIND", QString()));
       
   289 }
       
   290 
       
   291 void tst_QHttp::get_data()
       
   292 {
       
   293     QTest::addColumn<QString>("host");
       
   294     QTest::addColumn<uint>("port");
       
   295     QTest::addColumn<QString>("path");
       
   296     QTest::addColumn<int>("success");
       
   297     QTest::addColumn<int>("statusCode");
       
   298     QTest::addColumn<QByteArray>("res");
       
   299     QTest::addColumn<bool>("useIODevice");
       
   300 
       
   301     // ### move this into external testdata
       
   302     QFile file( SRCDIR "rfc3252.txt" );
       
   303     QVERIFY( file.open( QIODevice::ReadOnly ) );
       
   304     QByteArray rfc3252 = file.readAll();
       
   305     file.close();
       
   306 
       
   307     file.setFileName( SRCDIR "trolltech" );
       
   308     QVERIFY( file.open( QIODevice::ReadOnly ) );
       
   309     QByteArray trolltech = file.readAll();
       
   310     file.close();
       
   311 
       
   312     // test the two get() modes in one routine
       
   313     for ( int i=0; i<2; i++ ) {
       
   314 	QTest::newRow(QString("path_01_%1").arg(i).toLatin1()) << QtNetworkSettings::serverName() << 80u
       
   315 	    << QString("/qtest/rfc3252.txt") << 1 << 200 << rfc3252 << (bool)(i==1);
       
   316 	QTest::newRow( QString("path_02_%1").arg(i).toLatin1() ) << QString("www.ietf.org") << 80u
       
   317 	    << QString("/rfc/rfc3252.txt") << 1 << 200 << rfc3252 << (bool)(i==1);
       
   318 
       
   319 	QTest::newRow( QString("uri_01_%1").arg(i).toLatin1() ) << QtNetworkSettings::serverName() << 80u
       
   320 	    << QString("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt") << 1 << 200 << rfc3252 << (bool)(i==1);
       
   321 	QTest::newRow( QString("uri_02_%1").arg(i).toLatin1() ) << "www.ietf.org" << 80u
       
   322 	    << QString("http://www.ietf.org/rfc/rfc3252.txt") << 1 << 200 << rfc3252 << (bool)(i==1);
       
   323 
       
   324 	QTest::newRow( QString("fail_01_%1").arg(i).toLatin1() ) << QString("this-host-will-not-exist.") << 80u
       
   325 	    << QString("/qtest/rfc3252.txt") << 0 << 0 << QByteArray() << (bool)(i==1);
       
   326 
       
   327 	QTest::newRow( QString("failprot_01_%1").arg(i).toLatin1() ) << QtNetworkSettings::serverName() << 80u
       
   328 	    << QString("/t") << 1 << 404 << QByteArray() << (bool)(i==1);
       
   329 	QTest::newRow( QString("failprot_02_%1").arg(i).toLatin1() ) << QtNetworkSettings::serverName() << 80u
       
   330 	    << QString("qtest/rfc3252.txt") << 1 << 400 << QByteArray() << (bool)(i==1);
       
   331 
       
   332   // qt.nokia.com/doc uses transfer-encoding=chunked
       
   333     /* qt.nokia.com/doc no longer seams to be using chuncked encodig.
       
   334     QTest::newRow( QString("chunked_01_%1").arg(i).toLatin1() ) << QString("test.troll.no") << 80u
       
   335 	    << QString("/") << 1 << 200 << trolltech << (bool)(i==1);
       
   336     */
       
   337 	QTest::newRow( QString("chunked_02_%1").arg(i).toLatin1() ) << QtNetworkSettings::serverName() << 80u
       
   338 	    << QString("/qtest/cgi-bin/rfc.cgi") << 1 << 200 << rfc3252 << (bool)(i==1);
       
   339     }
       
   340 }
       
   341 
       
   342 void tst_QHttp::get()
       
   343 {
       
   344     // for the overload that takes a QIODevice
       
   345     QByteArray buf_ba;
       
   346     QBuffer buf( &buf_ba );
       
   347 
       
   348     QFETCH( QString, host );
       
   349     QFETCH( uint, port );
       
   350     QFETCH( QString, path );
       
   351     QFETCH( bool, useIODevice );
       
   352 
       
   353     http = newHttp();
       
   354     QCOMPARE( http->currentId(), 0 );
       
   355     QCOMPARE( (int)http->state(), (int)QHttp::Unconnected );
       
   356 
       
   357     addRequest( QHttpRequestHeader(), http->setHost( host, port ) );
       
   358     if ( useIODevice ) {
       
   359     buf.open( QIODevice::WriteOnly );
       
   360     getId = http->get( path, &buf );
       
   361     } else {
       
   362     getId = http->get( path );
       
   363     }
       
   364     addRequest( QHttpRequestHeader(), getId );
       
   365 
       
   366     QTestEventLoop::instance().enterLoop( 30 );
       
   367 
       
   368     if ( QTestEventLoop::instance().timeout() )
       
   369     QFAIL( "Network operation timed out" );
       
   370 
       
   371     ResMapIt res = resultMap.find( getId );
       
   372     QVERIFY( res != resultMap.end() );
       
   373     if ( res.value().success!=1 && host=="www.ietf.org" ) {
       
   374     // The nightly tests fail from time to time. In order to make them more
       
   375     // stable, add some debug output that might help locate the problem (I
       
   376     // can't reproduce the problem in the non-nightly builds).
       
   377     qDebug( "Error %d: %s", http->error(), http->errorString().toLatin1().constData() );
       
   378     }
       
   379     QTEST( res.value().success, "success" );
       
   380     if ( res.value().success ) {
       
   381     QTEST( res.value().resp.statusCode(), "statusCode" );
       
   382 
       
   383     QFETCH( QByteArray, res );
       
   384     if ( res.count() > 0 ) {
       
   385         if ( useIODevice ) {
       
   386         QCOMPARE(buf_ba, res);
       
   387         if ( bytesDoneRead != bytesDone_init )
       
   388             QVERIFY( (int)buf_ba.size() == bytesDoneRead );
       
   389         } else {
       
   390         QCOMPARE(readyRead_ba, res);
       
   391         if ( bytesDoneRead != bytesDone_init )
       
   392             QVERIFY( (int)readyRead_ba.size() == bytesDoneRead );
       
   393         }
       
   394     }
       
   395     QVERIFY( bytesTotalRead != bytesTotal_init );
       
   396     if ( bytesTotalRead > 0 )
       
   397         QVERIFY( bytesDoneRead == bytesTotalRead );
       
   398     } else {
       
   399     QVERIFY( !res.value().resp.isValid() );
       
   400     }
       
   401 }
       
   402 
       
   403 void tst_QHttp::head_data()
       
   404 {
       
   405     QTest::addColumn<QString>("host");
       
   406     QTest::addColumn<uint>("port");
       
   407     QTest::addColumn<QString>("path");
       
   408     QTest::addColumn<int>("success");
       
   409     QTest::addColumn<int>("statusCode");
       
   410     QTest::addColumn<uint>("contentLength");
       
   411 
       
   412     QTest::newRow( "path_01" ) << QtNetworkSettings::serverName() << 80u
       
   413 	<< QString("/qtest/rfc3252.txt") << 1 << 200 << 25962u;
       
   414 
       
   415     QTest::newRow( "path_02" ) << QString("www.ietf.org") << 80u
       
   416 	<< QString("/rfc/rfc3252.txt") << 1 << 200 << 25962u;
       
   417 
       
   418     QTest::newRow( "uri_01" ) << QtNetworkSettings::serverName() << 80u
       
   419 	<< QString("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt") << 1 << 200 << 25962u;
       
   420 
       
   421     QTest::newRow( "uri_02" ) << QString("www.ietf.org") << 80u
       
   422     << QString("http://www.ietf.org/rfc/rfc3252.txt") << 1 << 200 << 25962u;
       
   423 
       
   424     QTest::newRow( "fail_01" ) << QString("this-host-will-not-exist.") << 80u
       
   425     << QString("/qtest/rfc3252.txt") << 0 << 0 << 0u;
       
   426 
       
   427     QTest::newRow( "failprot_01" ) << QtNetworkSettings::serverName() << 80u
       
   428 	<< QString("/t") << 1 << 404 << 0u;
       
   429 
       
   430     QTest::newRow( "failprot_02" ) << QtNetworkSettings::serverName() << 80u
       
   431 	<< QString("qtest/rfc3252.txt") << 1 << 400 << 0u;
       
   432 
       
   433     /* qt.nokia.com/doc no longer seams to be using chuncked encodig.
       
   434     QTest::newRow( "chunked_01" ) << QString("qt.nokia.com/doc") << 80u
       
   435 	<< QString("/index.html") << 1 << 200 << 0u;
       
   436     */
       
   437     QTest::newRow( "chunked_02" ) << QtNetworkSettings::serverName() << 80u
       
   438 	<< QString("/qtest/cgi-bin/rfc.cgi") << 1 << 200 << 0u;
       
   439 }
       
   440 
       
   441 void tst_QHttp::head()
       
   442 {
       
   443     QFETCH( QString, host );
       
   444     QFETCH( uint, port );
       
   445     QFETCH( QString, path );
       
   446 
       
   447     http = newHttp();
       
   448     QCOMPARE( http->currentId(), 0 );
       
   449     QCOMPARE( (int)http->state(), (int)QHttp::Unconnected );
       
   450 
       
   451     addRequest( QHttpRequestHeader(), http->setHost( host, port ) );
       
   452     headId = http->head( path );
       
   453     addRequest( QHttpRequestHeader(), headId );
       
   454 
       
   455     QTestEventLoop::instance().enterLoop( 30 );
       
   456     if ( QTestEventLoop::instance().timeout() )
       
   457         QFAIL( "Network operation timed out" );
       
   458 
       
   459     ResMapIt res = resultMap.find( headId );
       
   460     QVERIFY( res != resultMap.end() );
       
   461     if ( res.value().success!=1 && host=="www.ietf.org" ) {
       
   462         // The nightly tests fail from time to time. In order to make them more
       
   463         // stable, add some debug output that might help locate the problem (I
       
   464         // can't reproduce the problem in the non-nightly builds).
       
   465         qDebug( "Error %d: %s", http->error(), http->errorString().toLatin1().constData() );
       
   466     }
       
   467     QTEST( res.value().success, "success" );
       
   468     if ( res.value().success ) {
       
   469         QTEST( res.value().resp.statusCode(), "statusCode" );
       
   470         QTEST( res.value().resp.contentLength(), "contentLength" );
       
   471 
       
   472         QCOMPARE( (uint)readyRead_ba.size(), 0u );
       
   473         QVERIFY( bytesTotalRead == bytesTotal_init );
       
   474         QVERIFY( bytesDoneRead == bytesDone_init );
       
   475     } else {
       
   476         QVERIFY( !res.value().resp.isValid() );
       
   477     }
       
   478 }
       
   479 
       
   480 void tst_QHttp::post_data()
       
   481 {
       
   482 	QTest::addColumn<QString>("source");
       
   483     QTest::addColumn<bool>("useIODevice");
       
   484     QTest::addColumn<bool>("useProxy");
       
   485     QTest::addColumn<QString>("host");
       
   486     QTest::addColumn<int>("port");
       
   487     QTest::addColumn<bool>("ssl");
       
   488     QTest::addColumn<QString>("path");
       
   489     QTest::addColumn<QByteArray>("result");
       
   490 
       
   491     QByteArray md5sum;
       
   492     md5sum = "d41d8cd98f00b204e9800998ecf8427e";
       
   493     QTest::newRow("empty-data")
       
   494         << QString() << false << false
       
   495         << QtNetworkSettings::serverName() << 80 << false << "/qtest/cgi-bin/md5sum.cgi" << md5sum;
       
   496     QTest::newRow("empty-device")
       
   497         << QString() << true << false
       
   498         << QtNetworkSettings::serverName() << 80 << false << "/qtest/cgi-bin/md5sum.cgi" << md5sum;
       
   499     QTest::newRow("proxy-empty-data")
       
   500         << QString() << false << true
       
   501         << QtNetworkSettings::serverName() << 80 << false << "/qtest/cgi-bin/md5sum.cgi" << md5sum;
       
   502 
       
   503     md5sum = "b3e32ac459b99d3f59318f3ac31e4bee";
       
   504     QTest::newRow("data") << "rfc3252.txt" << false << false
       
   505                           << QtNetworkSettings::serverName() << 80 << false << "/qtest/cgi-bin/md5sum.cgi"
       
   506                           << md5sum;
       
   507     QTest::newRow("device") << "rfc3252.txt" << true << false
       
   508                           << QtNetworkSettings::serverName() << 80 << false << "/qtest/cgi-bin/md5sum.cgi"
       
   509                           << md5sum;
       
   510     QTest::newRow("proxy-data") << "rfc3252.txt" << false << true
       
   511                                 << QtNetworkSettings::serverName() << 80 << false << "/qtest/cgi-bin/md5sum.cgi"
       
   512                                 << md5sum;
       
   513 
       
   514 #ifndef QT_NO_OPENSSL
       
   515     md5sum = "d41d8cd98f00b204e9800998ecf8427e";
       
   516     QTest::newRow("empty-data-ssl")
       
   517         << QString() << false << false
       
   518         << QtNetworkSettings::serverName() << 443 << true << "/qtest/cgi-bin/md5sum.cgi" << md5sum;
       
   519     QTest::newRow("empty-device-ssl")
       
   520         << QString() << true << false
       
   521         << QtNetworkSettings::serverName() << 443 << true << "/qtest/cgi-bin/md5sum.cgi" << md5sum;
       
   522     QTest::newRow("proxy-empty-data-ssl")
       
   523         << QString() << false << true
       
   524         << QtNetworkSettings::serverName() << 443 << true << "/qtest/cgi-bin/md5sum.cgi" << md5sum;
       
   525     md5sum = "b3e32ac459b99d3f59318f3ac31e4bee";
       
   526     QTest::newRow("data-ssl") << "rfc3252.txt" << false << false
       
   527         << QtNetworkSettings::serverName() << 443 << true << "/qtest/cgi-bin/md5sum.cgi"
       
   528         << md5sum;
       
   529     QTest::newRow("device-ssl") << "rfc3252.txt" << true << false
       
   530         << QtNetworkSettings::serverName() << 443 << true << "/qtest/cgi-bin/md5sum.cgi"
       
   531         << md5sum;
       
   532     QTest::newRow("proxy-data-ssl") << "rfc3252.txt" << false << true
       
   533         << QtNetworkSettings::serverName() << 443 << true << "/qtest/cgi-bin/md5sum.cgi"
       
   534         << md5sum;
       
   535 #endif
       
   536 
       
   537     // the following test won't work. See task 185996
       
   538 /*
       
   539     QTest::newRow("proxy-device") << "rfc3252.txt" << true << true
       
   540                                   << QtNetworkSettings::serverName() << 80 << "/qtest/cgi-bin/md5sum.cgi"
       
   541                                   << md5sum;
       
   542 */
       
   543 }
       
   544 
       
   545 void tst_QHttp::post()
       
   546 {
       
   547 	QFETCH(QString, source);
       
   548     QFETCH(bool, useIODevice);
       
   549     QFETCH(bool, useProxy);
       
   550     QFETCH(QString, host);
       
   551     QFETCH(int, port);
       
   552     QFETCH(bool, ssl);
       
   553     QFETCH(QString, path);
       
   554 
       
   555     http = newHttp(useProxy);
       
   556 #ifndef QT_NO_OPENSSL
       
   557     QObject::connect(http, SIGNAL(sslErrors(const QList<QSslError> &)),
       
   558         http, SLOT(ignoreSslErrors()));
       
   559 #endif
       
   560     QCOMPARE(http->currentId(), 0);
       
   561     QCOMPARE((int)http->state(), (int)QHttp::Unconnected);
       
   562     if (useProxy)
       
   563         addRequest(QHttpRequestHeader(), http->setProxy(QtNetworkSettings::serverName(), 3129));
       
   564     addRequest(QHttpRequestHeader(), http->setHost(host, (ssl ? QHttp::ConnectionModeHttps : QHttp::ConnectionModeHttp), port));
       
   565 
       
   566     // add the POST request
       
   567     QFile file(SRCDIR + source);
       
   568     QBuffer emptyBuffer;
       
   569     QIODevice *dev;
       
   570     if (!source.isEmpty()) {
       
   571         QVERIFY(file.open(QIODevice::ReadOnly));
       
   572         dev = &file;
       
   573     } else {
       
   574         emptyBuffer.open(QIODevice::ReadOnly);
       
   575         dev = &emptyBuffer;
       
   576     }
       
   577 
       
   578     if (useIODevice)
       
   579         postId = http->post(path, dev);
       
   580     else
       
   581         postId = http->post(path, dev->readAll());
       
   582     addRequest(QHttpRequestHeader(), postId);
       
   583 
       
   584     // run request
       
   585     connect(http, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
       
   586             SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
       
   587     QTestEventLoop::instance().enterLoop( 30 );
       
   588 
       
   589     if ( QTestEventLoop::instance().timeout() )
       
   590     QFAIL( "Network operation timed out" );
       
   591 
       
   592     ResMapIt res = resultMap.find(postId);
       
   593     QVERIFY(res != resultMap.end());
       
   594     QVERIFY(res.value().success);
       
   595     QCOMPARE(res.value().resp.statusCode(), 200);
       
   596     QTEST(readyRead_ba.trimmed(), "result");
       
   597 }
       
   598 
       
   599 void tst_QHttp::request_data()
       
   600 {
       
   601     QTest::addColumn<QString>("source");
       
   602     QTest::addColumn<bool>("useIODevice");
       
   603     QTest::addColumn<bool>("useProxy");
       
   604     QTest::addColumn<QString>("host");
       
   605     QTest::addColumn<int>("port");
       
   606     QTest::addColumn<QString>("method");
       
   607     QTest::addColumn<QString>("path");
       
   608     QTest::addColumn<QByteArray>("result");
       
   609 
       
   610     QFile source(SRCDIR "rfc3252.txt");
       
   611     if (!source.open(QIODevice::ReadOnly))
       
   612         return;
       
   613 
       
   614     QByteArray contents = source.readAll();
       
   615     QByteArray md5sum = QCryptographicHash::hash(contents, QCryptographicHash::Md5).toHex() + '\n';
       
   616     QByteArray emptyMd5sum = "d41d8cd98f00b204e9800998ecf8427e\n";
       
   617 
       
   618     QTest::newRow("head") << QString() << false << false << QtNetworkSettings::serverName() << 80
       
   619                           << "HEAD" << "/qtest/rfc3252.txt"
       
   620                           << QByteArray();
       
   621     QTest::newRow("get") << QString() << false << false << QtNetworkSettings::serverName() << 80
       
   622                          << "GET" << "/qtest/rfc3252.txt"
       
   623                          << contents;
       
   624     QTest::newRow("post-empty-data") << QString() << false << false
       
   625                                      << QtNetworkSettings::serverName() << 80 << "POST" << "/qtest/cgi-bin/md5sum.cgi"
       
   626                                      << emptyMd5sum;
       
   627     QTest::newRow("post-empty-device") << QString() << true << false
       
   628                                        << QtNetworkSettings::serverName() << 80 << "POST" << "/qtest/cgi-bin/md5sum.cgi"
       
   629                                        << emptyMd5sum;
       
   630     QTest::newRow("post-data") << "rfc3252.txt" << false << false
       
   631                                << QtNetworkSettings::serverName() << 80 << "POST" << "/qtest/cgi-bin/md5sum.cgi"
       
   632                                << md5sum;
       
   633     QTest::newRow("post-device") << "rfc3252.txt" << true << false
       
   634                                << QtNetworkSettings::serverName() << 80 << "POST" << "/qtest/cgi-bin/md5sum.cgi"
       
   635                                << md5sum;
       
   636 
       
   637     QTest::newRow("proxy-head") << QString() << false << true << QtNetworkSettings::serverName() << 80
       
   638                                 << "HEAD" << "/qtest/rfc3252.txt"
       
   639                                 << QByteArray();
       
   640     QTest::newRow("proxy-get") << QString() << false << true << QtNetworkSettings::serverName() << 80
       
   641                                << "GET" << "/qtest/rfc3252.txt"
       
   642                                << contents;
       
   643     QTest::newRow("proxy-post-empty-data")  << QString() << false << true
       
   644                                             << QtNetworkSettings::serverName() << 80 << "POST" << "/qtest/cgi-bin/md5sum.cgi"
       
   645                                             << emptyMd5sum;
       
   646     QTest::newRow("proxy-post-data") << "rfc3252.txt" << false << true
       
   647                                      << QtNetworkSettings::serverName() << 80 << "POST" << "/qtest/cgi-bin/md5sum.cgi"
       
   648                                      << md5sum;
       
   649     // the following test won't work. See task 185996
       
   650 /*
       
   651     QTest::newRow("proxy-post-device") << "rfc3252.txt" << true << true
       
   652                                        << QtNetworkSettings::serverName() << 80 << "POST" << "/qtest/cgi-bin/md5sum.cgi"
       
   653                                        << md5sum;
       
   654 */
       
   655 }
       
   656 
       
   657 void tst_QHttp::request()
       
   658 {
       
   659     QFETCH(QString, source);
       
   660     QFETCH(bool, useIODevice);
       
   661     QFETCH(bool, useProxy);
       
   662     QFETCH(QString, host);
       
   663     QFETCH(int, port);
       
   664     QFETCH(QString, method);
       
   665     QFETCH(QString, path);
       
   666 
       
   667     http = newHttp(useProxy);
       
   668     QCOMPARE(http->currentId(), 0);
       
   669     QCOMPARE((int)http->state(), (int)QHttp::Unconnected);
       
   670     if (useProxy)
       
   671         addRequest(QHttpRequestHeader(), http->setProxy(QtNetworkSettings::serverName(), 3129));
       
   672     addRequest(QHttpRequestHeader(), http->setHost(host, port));
       
   673 
       
   674     QFile file(SRCDIR + source);
       
   675     QBuffer emptyBuffer;
       
   676     QIODevice *dev;
       
   677     if (!source.isEmpty()) {
       
   678         QVERIFY(file.open(QIODevice::ReadOnly));
       
   679         dev = &file;
       
   680     } else {
       
   681         emptyBuffer.open(QIODevice::ReadOnly);
       
   682         dev = &emptyBuffer;
       
   683     }
       
   684 
       
   685     // prepare the request
       
   686     QHttpRequestHeader request;
       
   687     request.setRequest(method, path, 1,1);
       
   688     request.addValue("Host", host);
       
   689     int *theId;
       
   690 
       
   691     if (method == "POST")
       
   692         theId = &postId;
       
   693     else if (method == "GET")
       
   694         theId = &getId;
       
   695     else if (method == "HEAD")
       
   696         theId = &headId;
       
   697     else
       
   698         QFAIL("You're lazy! Please implement your test!");
       
   699 
       
   700     // now send the request
       
   701     if (useIODevice)
       
   702         *theId = http->request(request, dev);
       
   703     else
       
   704         *theId = http->request(request, dev->readAll());
       
   705     addRequest(QHttpRequestHeader(), *theId);
       
   706 
       
   707     // run request
       
   708     connect(http, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
       
   709             SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
       
   710     QTestEventLoop::instance().enterLoop( 30 );
       
   711 
       
   712     if ( QTestEventLoop::instance().timeout() )
       
   713     QFAIL( "Network operation timed out" );
       
   714 
       
   715     ResMapIt res = resultMap.find(*theId);
       
   716     QVERIFY(res != resultMap.end());
       
   717     QVERIFY(res.value().success);
       
   718     QCOMPARE(res.value().resp.statusCode(), 200);
       
   719     QTEST(readyRead_ba, "result");
       
   720 }
       
   721 
       
   722 void tst_QHttp::authorization_data()
       
   723 {
       
   724     QTest::addColumn<QString>("host");
       
   725     QTest::addColumn<QString>("path");
       
   726     QTest::addColumn<QString>("user");
       
   727     QTest::addColumn<QString>("pass");
       
   728     QTest::addColumn<int>("result");
       
   729 
       
   730     QTest::newRow("correct password") << QtNetworkSettings::serverName()
       
   731                                 << QString::fromLatin1("/qtest/rfcs-auth/index.html")
       
   732                                 << QString::fromLatin1("httptest")
       
   733                                 << QString::fromLatin1("httptest")
       
   734                                 << 200;
       
   735 
       
   736     QTest::newRow("no password") << QtNetworkSettings::serverName()
       
   737                                  << QString::fromLatin1("/qtest/rfcs-auth/index.html")
       
   738                                  << QString::fromLatin1("")
       
   739                                  << QString::fromLatin1("")
       
   740                                  << 401;
       
   741 
       
   742     QTest::newRow("wrong password") << QtNetworkSettings::serverName()
       
   743                                  << QString::fromLatin1("/qtest/rfcs-auth/index.html")
       
   744                                  << QString::fromLatin1("maliciu0s")
       
   745                                  << QString::fromLatin1("h4X0r")
       
   746                                  << 401;
       
   747 }
       
   748 
       
   749 void tst_QHttp::authorization()
       
   750 {
       
   751     QFETCH(QString, host);
       
   752     QFETCH(QString, path);
       
   753     QFETCH(QString, user);
       
   754     QFETCH(QString, pass);
       
   755     QFETCH(int, result);
       
   756 
       
   757     QEventLoop loop;
       
   758 
       
   759     QHttp http;
       
   760     connect(&http, SIGNAL(done(bool)), &loop, SLOT(quit()));
       
   761 
       
   762     if (!user.isEmpty())
       
   763         http.setUser(user, pass);
       
   764     http.setHost(host);
       
   765     int id = http.get(path);
       
   766 
       
   767     QTimer::singleShot(5000, &loop, SLOT(quit()));
       
   768     loop.exec();
       
   769 
       
   770     QCOMPARE(http.lastResponse().statusCode(), result);
       
   771 }
       
   772 
       
   773 void tst_QHttp::proxy_data()
       
   774 {
       
   775     QTest::addColumn<QString>("proxyhost");
       
   776     QTest::addColumn<int>("port");
       
   777     QTest::addColumn<QString>("host");
       
   778     QTest::addColumn<QString>("path");
       
   779     QTest::addColumn<QString>("proxyuser");
       
   780     QTest::addColumn<QString>("proxypass");
       
   781 
       
   782     QTest::newRow("qt-test-server") << QtNetworkSettings::serverName() << 3128
       
   783                                  << QString::fromLatin1("qt.nokia.com") << QString::fromLatin1("/")
       
   784                                  << QString::fromLatin1("") << QString::fromLatin1("");
       
   785     QTest::newRow("qt-test-server pct") << QtNetworkSettings::serverName() << 3128
       
   786                                  << QString::fromLatin1("qt.nokia.com") << QString::fromLatin1("/%64eveloper")
       
   787                                  << QString::fromLatin1("") << QString::fromLatin1("");
       
   788     QTest::newRow("qt-test-server-basic") << QtNetworkSettings::serverName() << 3129
       
   789                                  << QString::fromLatin1("qt.nokia.com") << QString::fromLatin1("/")
       
   790                                  << QString::fromLatin1("qsockstest") << QString::fromLatin1("password");
       
   791 
       
   792 #if 0
       
   793     // NTLM requires sending the same request three times for it to work
       
   794     // the tst_QHttp class is too strict to handle the byte counts sent by dataSendProgress
       
   795     // So don't run this test:
       
   796     QTest::newRow("qt-test-server-ntlm") << QtNetworkSettings::serverName() << 3130
       
   797                                  << QString::fromLatin1("qt.nokia.com") << QString::fromLatin1("/")
       
   798                                  << QString::fromLatin1("qsockstest") << QString::fromLatin1("password");
       
   799 #endif
       
   800 }
       
   801 
       
   802 void tst_QHttp::proxy()
       
   803 {
       
   804     QFETCH(QString, proxyhost);
       
   805     QFETCH(int, port);
       
   806     QFETCH(QString, host);
       
   807     QFETCH(QString, path);
       
   808     QFETCH(QString, proxyuser);
       
   809     QFETCH(QString, proxypass);
       
   810 
       
   811     http = newHttp(!proxyuser.isEmpty());
       
   812 
       
   813     QCOMPARE(http->currentId(), 0);
       
   814     QCOMPARE((int)http->state(), (int)QHttp::Unconnected);
       
   815 
       
   816     addRequest(QHttpRequestHeader(), http->setProxy(proxyhost, port, proxyuser, proxypass));
       
   817     addRequest(QHttpRequestHeader(), http->setHost(host));
       
   818     getId = http->get(path);
       
   819     addRequest(QHttpRequestHeader(), getId);
       
   820 
       
   821     QTestEventLoop::instance().enterLoop(30);
       
   822     if (QTestEventLoop::instance().timeout())
       
   823     QFAIL("Network operation timed out");
       
   824 
       
   825     ResMapIt res = resultMap.find(getId);
       
   826     QVERIFY(res != resultMap.end());
       
   827     QVERIFY(res.value().success);
       
   828     QCOMPARE(res.value().resp.statusCode(), 200);
       
   829 }
       
   830 
       
   831 void tst_QHttp::proxy2()
       
   832 {
       
   833     QFETCH_GLOBAL(bool, setProxy);
       
   834     if (setProxy)
       
   835         return;
       
   836 
       
   837     readyRead_ba.clear();
       
   838 
       
   839     QHttp http;
       
   840     http.setProxy(QtNetworkSettings::serverName(), 3128);
       
   841     http.setHost(QtNetworkSettings::serverName());
       
   842     http.get("/index.html");
       
   843     http.get("/index.html");
       
   844 
       
   845     connect(&http, SIGNAL(requestFinished(int, bool)),
       
   846             this, SLOT(proxy2_slot()));
       
   847     QTestEventLoop::instance().enterLoop(30);
       
   848     QVERIFY(!QTestEventLoop::instance().timeout());
       
   849 
       
   850     QCOMPARE(readyRead_ba.count("Welcome to fluke.troll.no"), 2);
       
   851 
       
   852     readyRead_ba.clear();
       
   853 }
       
   854 
       
   855 void tst_QHttp::proxy2_slot()
       
   856 {
       
   857     QHttp *http = static_cast<QHttp *>(sender());
       
   858     readyRead_ba.append(http->readAll());
       
   859     if (!http->hasPendingRequests())
       
   860         QTestEventLoop::instance().exitLoop();
       
   861 }
       
   862 
       
   863 void tst_QHttp::proxy3()
       
   864 {
       
   865     QFETCH_GLOBAL(bool, setProxy);
       
   866     if (setProxy)
       
   867         return;
       
   868 
       
   869     readyRead_ba.clear();
       
   870 
       
   871     QTcpSocket socket;
       
   872     socket.setProxy(QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3128));
       
   873 
       
   874     QHttp http;
       
   875     http.setSocket(&socket);
       
   876     http.setHost(QtNetworkSettings::serverName());
       
   877     http.get("/index.html");
       
   878     http.get("/index.html");
       
   879 
       
   880     connect(&http, SIGNAL(requestFinished(int, bool)),
       
   881             this, SLOT(proxy2_slot()));
       
   882     QTestEventLoop::instance().enterLoop(30);
       
   883     QVERIFY(!QTestEventLoop::instance().timeout());
       
   884 
       
   885     QCOMPARE(readyRead_ba.count("Welcome to fluke.troll.no"), 2);
       
   886 
       
   887     readyRead_ba.clear();
       
   888 }
       
   889 
       
   890 // test QHttp::currentId() and QHttp::currentRequest()
       
   891 #define CURRENTREQUEST_TEST \
       
   892     { \
       
   893     ResMapIt res = resultMap.find( http->currentId() ); \
       
   894     QVERIFY( res != resultMap.end() ); \
       
   895     if ( http->currentId() == getId ) { \
       
   896         QCOMPARE( http->currentRequest().method(), QString("GET") ); \
       
   897     } else if ( http->currentId() == headId ) { \
       
   898         QCOMPARE( http->currentRequest().method(), QString("HEAD") ); \
       
   899         } else if ( http->currentId() == postId ) { \
       
   900             QCOMPARE( http->currentRequest().method(), QString("POST") ); \
       
   901     } else { \
       
   902         QVERIFY( headerAreEqual( http->currentRequest(), res.value().req ) ); \
       
   903     } \
       
   904     }
       
   905 
       
   906 void tst_QHttp::requestStarted( int id )
       
   907 {
       
   908 #if defined( DUMP_SIGNALS )
       
   909     qDebug( "%d:requestStarted( %d )", http->currentId(), id );
       
   910 #endif
       
   911     // make sure that the requestStarted and requestFinished are nested correctly
       
   912     QVERIFY( current_id == 0 );
       
   913     current_id = id;
       
   914 
       
   915     QVERIFY( !ids.isEmpty() );
       
   916     QVERIFY( ids.first() == id );
       
   917     if ( ids.count() > 1 ) {
       
   918     QVERIFY( http->hasPendingRequests() );
       
   919     } else {
       
   920     QVERIFY( !http->hasPendingRequests() );
       
   921     }
       
   922 
       
   923     QVERIFY( http->currentId() == id );
       
   924     QVERIFY( cur_state == http->state() );
       
   925 
       
   926 
       
   927 
       
   928 
       
   929     CURRENTREQUEST_TEST;
       
   930 
       
   931     QVERIFY( http->error() == QHttp::NoError );
       
   932 }
       
   933 
       
   934 void tst_QHttp::requestFinished( int id, bool error )
       
   935 {
       
   936 #if defined( DUMP_SIGNALS )
       
   937     qDebug( "%d:requestFinished( %d, %d ) -- errorString: '%s'",
       
   938         http->currentId(), id, (int)error, http->errorString().toAscii().data() );
       
   939 #endif
       
   940     // make sure that the requestStarted and requestFinished are nested correctly
       
   941     QVERIFY( current_id == id );
       
   942     current_id = 0;
       
   943 
       
   944     QVERIFY( !ids.isEmpty() );
       
   945     QVERIFY( ids.first() == id );
       
   946     if ( ids.count() > 1 ) {
       
   947     QVERIFY( http->hasPendingRequests() );
       
   948     } else {
       
   949     QVERIFY( !http->hasPendingRequests() );
       
   950     }
       
   951 
       
   952     if ( error ) {
       
   953     QVERIFY( http->error() != QHttp::NoError );
       
   954     ids.clear();
       
   955     } else {
       
   956     QVERIFY( http->error() == QHttp::NoError );
       
   957     ids.pop_front();
       
   958     }
       
   959 
       
   960     QVERIFY( http->currentId() == id );
       
   961     QVERIFY( cur_state == http->state() );
       
   962     CURRENTREQUEST_TEST;
       
   963 
       
   964     ResMapIt res = resultMap.find( http->currentId() );
       
   965     QVERIFY( res != resultMap.end() );
       
   966     QVERIFY( res.value().success == -1 );
       
   967     if ( error )
       
   968     res.value().success = 0;
       
   969     else
       
   970     res.value().success = 1;
       
   971 }
       
   972 
       
   973 void tst_QHttp::done( bool error )
       
   974 {
       
   975 #if defined( DUMP_SIGNALS )
       
   976     qDebug( "%d:done( %d )", http->currentId(), (int)error );
       
   977 #endif
       
   978     QVERIFY( http->currentId() == 0 );
       
   979     QVERIFY( current_id == 0 );
       
   980     QVERIFY( ids.isEmpty() );
       
   981     QVERIFY( cur_state == http->state() );
       
   982     QVERIFY( !http->hasPendingRequests() );
       
   983 
       
   984     QVERIFY( done_success == -1 );
       
   985     if ( error ) {
       
   986     QVERIFY( http->error() != QHttp::NoError );
       
   987     done_success = 0;
       
   988     } else {
       
   989     QVERIFY( http->error() == QHttp::NoError );
       
   990     done_success = 1;
       
   991     }
       
   992     QTestEventLoop::instance().exitLoop();
       
   993 }
       
   994 
       
   995 void tst_QHttp::stateChanged( int state )
       
   996 {
       
   997 #if defined( DUMP_SIGNALS )
       
   998     qDebug( "%d:  stateChanged( %d )", http->currentId(), state );
       
   999 #endif
       
  1000     QCOMPARE( http->currentId(), current_id );
       
  1001     if ( ids.count() > 0 )
       
  1002     CURRENTREQUEST_TEST;
       
  1003 
       
  1004     QVERIFY( state != cur_state );
       
  1005     QVERIFY( state == http->state() );
       
  1006     if ( state != QHttp::Unconnected && !connectionWithAuth ) {
       
  1007     // make sure that the states are always emitted in the right order (for
       
  1008     // this, we assume an ordering on the enum values, which they have at
       
  1009     // the moment)
       
  1010         // connections with authentication will possibly reconnect, so ignore them
       
  1011         QVERIFY( cur_state < state );
       
  1012     }
       
  1013     cur_state = state;
       
  1014 
       
  1015     if (state == QHttp::Connecting) {
       
  1016         bytesTotalSend = bytesTotal_init;
       
  1017         bytesDoneSend = bytesDone_init;
       
  1018         bytesTotalRead = bytesTotal_init;
       
  1019         bytesDoneRead = bytesDone_init;
       
  1020     }
       
  1021 }
       
  1022 
       
  1023 void tst_QHttp::responseHeaderReceived( const QHttpResponseHeader &header )
       
  1024 {
       
  1025 #if defined( DUMP_SIGNALS )
       
  1026     qDebug( "%d:  responseHeaderReceived(\n---{\n%s}---)", http->currentId(), header.toString().toAscii().data() );
       
  1027 #endif
       
  1028     QCOMPARE( http->currentId(), current_id );
       
  1029     if ( ids.count() > 1 ) {
       
  1030     QVERIFY( http->hasPendingRequests() );
       
  1031     } else {
       
  1032     QVERIFY( !http->hasPendingRequests() );
       
  1033     }
       
  1034     CURRENTREQUEST_TEST;
       
  1035 
       
  1036     resultMap[ http->currentId() ].resp = header;
       
  1037 }
       
  1038 
       
  1039 void tst_QHttp::readyRead( const QHttpResponseHeader & )
       
  1040 {
       
  1041 #if defined( DUMP_SIGNALS )
       
  1042     qDebug( "%d:  readyRead()", http->currentId() );
       
  1043 #endif
       
  1044     QCOMPARE( http->currentId(), current_id );
       
  1045     if ( ids.count() > 1 ) {
       
  1046     QVERIFY( http->hasPendingRequests() );
       
  1047     } else {
       
  1048     QVERIFY( !http->hasPendingRequests() );
       
  1049     }
       
  1050     QVERIFY( cur_state == http->state() );
       
  1051     CURRENTREQUEST_TEST;
       
  1052 
       
  1053     if ( QTest::currentTestFunction() != QLatin1String("bytesAvailable") ) {
       
  1054     int oldSize = readyRead_ba.size();
       
  1055     quint64 bytesAvail = http->bytesAvailable();
       
  1056     QByteArray ba = http->readAll();
       
  1057     QVERIFY( (quint64) ba.size() == bytesAvail );
       
  1058     readyRead_ba.resize( oldSize + ba.size() );
       
  1059     memcpy( readyRead_ba.data()+oldSize, ba.data(), ba.size() );
       
  1060 
       
  1061     if ( bytesTotalRead > 0 ) {
       
  1062         QVERIFY( (int)readyRead_ba.size() <= bytesTotalRead );
       
  1063     }
       
  1064     QVERIFY( (int)readyRead_ba.size() == bytesDoneRead );
       
  1065     }
       
  1066 }
       
  1067 
       
  1068 void tst_QHttp::dataSendProgress( int done, int total )
       
  1069 {
       
  1070 #if defined( DUMP_SIGNALS )
       
  1071     qDebug( "%d:  dataSendProgress( %d, %d )", http->currentId(), done, total );
       
  1072 #endif
       
  1073     QCOMPARE( http->currentId(), current_id );
       
  1074     if ( ids.count() > 1 ) {
       
  1075     QVERIFY( http->hasPendingRequests() );
       
  1076     } else {
       
  1077     QVERIFY( !http->hasPendingRequests() );
       
  1078     }
       
  1079     QVERIFY( cur_state == http->state() );
       
  1080     CURRENTREQUEST_TEST;
       
  1081 
       
  1082     if ( bytesTotalSend == bytesTotal_init ) {
       
  1083     bytesTotalSend = total;
       
  1084     } else {
       
  1085     QCOMPARE( bytesTotalSend, total );
       
  1086     }
       
  1087 
       
  1088     QVERIFY( bytesTotalSend != bytesTotal_init );
       
  1089     QVERIFY( bytesDoneSend <= done );
       
  1090     bytesDoneSend = done;
       
  1091     if ( bytesTotalSend > 0 ) {
       
  1092     QVERIFY( bytesDoneSend <= bytesTotalSend );
       
  1093     }
       
  1094 
       
  1095     if ( QTest::currentTestFunction() == QLatin1String("abort") ) {
       
  1096     // ### it would be nice if we could specify in our testdata when to do
       
  1097     // the abort
       
  1098     if ( done >= total/100000 ) {
       
  1099         if ( ids.count() != 1 ) {
       
  1100         // do abort only once
       
  1101         int tmpId = ids.first();
       
  1102         ids.clear();
       
  1103         ids << tmpId;
       
  1104         http->abort();
       
  1105         }
       
  1106     }
       
  1107     }
       
  1108 }
       
  1109 
       
  1110 void tst_QHttp::dataReadProgress( int done, int total )
       
  1111 {
       
  1112 #if defined( DUMP_SIGNALS )
       
  1113     qDebug( "%d:  dataReadProgress( %d, %d )", http->currentId(), done, total );
       
  1114 #endif
       
  1115     QCOMPARE( http->currentId(), current_id );
       
  1116     if ( ids.count() > 1 ) {
       
  1117     QVERIFY( http->hasPendingRequests() );
       
  1118     } else {
       
  1119     QVERIFY( !http->hasPendingRequests() );
       
  1120     }
       
  1121     QVERIFY( cur_state == http->state() );
       
  1122     CURRENTREQUEST_TEST;
       
  1123 
       
  1124     if ( bytesTotalRead == bytesTotal_init )
       
  1125     bytesTotalRead = total;
       
  1126     else {
       
  1127     QVERIFY( bytesTotalRead == total );
       
  1128     }
       
  1129 
       
  1130     QVERIFY( bytesTotalRead != bytesTotal_init );
       
  1131     QVERIFY( bytesDoneRead <= done );
       
  1132     bytesDoneRead = done;
       
  1133     if ( bytesTotalRead > 0 ) {
       
  1134     QVERIFY( bytesDoneRead <= bytesTotalRead );
       
  1135     }
       
  1136 
       
  1137     if ( QTest::currentTestFunction() == QLatin1String("abort") ) {
       
  1138     // ### it would be nice if we could specify in our testdata when to do
       
  1139     // the abort
       
  1140     if ( done >= total/100000 ) {
       
  1141         if ( ids.count() != 1 ) {
       
  1142         // do abort only once
       
  1143         int tmpId = ids.first();
       
  1144         ids.clear();
       
  1145         ids << tmpId;
       
  1146         http->abort();
       
  1147         }
       
  1148     }
       
  1149     }
       
  1150 }
       
  1151 
       
  1152 
       
  1153 QHttp *tst_QHttp::newHttp(bool withAuth)
       
  1154 {
       
  1155     QHttp *nHttp = new QHttp( 0 );
       
  1156     connect( nHttp, SIGNAL(requestStarted(int)),
       
  1157         SLOT(requestStarted(int)) );
       
  1158     connect( nHttp, SIGNAL(requestFinished(int,bool)),
       
  1159         SLOT(requestFinished(int,bool)) );
       
  1160     connect( nHttp, SIGNAL(done(bool)),
       
  1161         SLOT(done(bool)) );
       
  1162     connect( nHttp, SIGNAL(stateChanged(int)),
       
  1163         SLOT(stateChanged(int)) );
       
  1164     connect( nHttp, SIGNAL(responseHeaderReceived(const QHttpResponseHeader&)),
       
  1165         SLOT(responseHeaderReceived(const QHttpResponseHeader&)) );
       
  1166     connect( nHttp, SIGNAL(readyRead(const QHttpResponseHeader&)),
       
  1167         SLOT(readyRead(const QHttpResponseHeader&)) );
       
  1168     connect( nHttp, SIGNAL(dataSendProgress(int,int)),
       
  1169         SLOT(dataSendProgress(int,int)) );
       
  1170     connect( nHttp, SIGNAL(dataReadProgress(int,int)),
       
  1171         SLOT(dataReadProgress(int,int)) );
       
  1172 
       
  1173     connectionWithAuth = withAuth;
       
  1174     return nHttp;
       
  1175 }
       
  1176 
       
  1177 void tst_QHttp::addRequest( QHttpRequestHeader header, int id )
       
  1178 {
       
  1179     ids << id;
       
  1180     RequestResult res;
       
  1181     res.req = header;
       
  1182     res.success = -1;
       
  1183     resultMap[ id ] = res;
       
  1184 }
       
  1185 
       
  1186 bool tst_QHttp::headerAreEqual( const QHttpHeader &h1, const QHttpHeader &h2 )
       
  1187 {
       
  1188     if ( !h1.isValid() )
       
  1189     return !h2.isValid();
       
  1190     if ( !h2.isValid() )
       
  1191     return !h1.isValid();
       
  1192 
       
  1193     return h1.toString() == h2.toString();
       
  1194 }
       
  1195 
       
  1196 
       
  1197 void tst_QHttp::reconnect()
       
  1198 {
       
  1199     reconnect_state_connect_count = 0;
       
  1200 
       
  1201     QHttp http;
       
  1202 
       
  1203     QObject::connect(&http, SIGNAL(stateChanged(int)), this, SLOT(reconnect_state(int)));
       
  1204     http.setHost("trolltech.com", 80);
       
  1205     http.get("/company/index.html");
       
  1206     http.setHost("trolltech.com", 8080);
       
  1207     http.get("/company/index.html");
       
  1208 
       
  1209     QTestEventLoop::instance().enterLoop(60);
       
  1210     if (QTestEventLoop::instance().timeout())
       
  1211     QFAIL("Network operation timed out");
       
  1212 
       
  1213     QCOMPARE(reconnect_state_connect_count, 1);
       
  1214 
       
  1215     QTestEventLoop::instance().enterLoop(60);
       
  1216     if (QTestEventLoop::instance().timeout())
       
  1217     QFAIL("Network operation timed out");
       
  1218 
       
  1219     QCOMPARE(reconnect_state_connect_count, 2);
       
  1220 }
       
  1221 
       
  1222 void tst_QHttp::reconnect_state(int state)
       
  1223 {
       
  1224     if (state == QHttp::Connecting) {
       
  1225         ++reconnect_state_connect_count;
       
  1226         QTestEventLoop::instance().exitLoop();
       
  1227     }
       
  1228 }
       
  1229 
       
  1230 void tst_QHttp::setSocket()
       
  1231 {
       
  1232     QHttp *http = new QHttp;
       
  1233     QPointer<QTcpSocket> replacementSocket = new QTcpSocket;
       
  1234     http->setSocket(replacementSocket);
       
  1235     QCoreApplication::processEvents();
       
  1236     delete http;
       
  1237     QVERIFY(replacementSocket);
       
  1238     delete replacementSocket;
       
  1239 }
       
  1240 
       
  1241 class Server : public QTcpServer
       
  1242 {
       
  1243     Q_OBJECT
       
  1244 public:
       
  1245     Server()
       
  1246     {
       
  1247         connect(this, SIGNAL(newConnection()),
       
  1248                 this, SLOT(serveConnection()));
       
  1249     }
       
  1250 
       
  1251 private slots:
       
  1252     void serveConnection()
       
  1253     {
       
  1254         QTcpSocket *socket = nextPendingConnection();
       
  1255         socket->write("HTTP/1.1 404 Not found\r\n"
       
  1256                       "content-length: 4\r\n\r\nabcd");
       
  1257         socket->disconnectFromHost();
       
  1258     };
       
  1259 };
       
  1260 
       
  1261 void tst_QHttp::unexpectedRemoteClose()
       
  1262 {
       
  1263 	QFETCH_GLOBAL(int, proxyType);
       
  1264     if (proxyType == QNetworkProxy::Socks5Proxy) {
       
  1265         // This test doesn't make sense for SOCKS5
       
  1266         return;
       
  1267     }
       
  1268 
       
  1269     Server server;
       
  1270     server.listen();
       
  1271     QCoreApplication::instance()->processEvents();
       
  1272 
       
  1273     QEventLoop loop;
       
  1274     QTimer::singleShot(3000, &loop, SLOT(quit()));
       
  1275 
       
  1276     QHttp http;
       
  1277     QObject::connect(&http, SIGNAL(done(bool)), &loop, SLOT(quit()));
       
  1278     QSignalSpy finishedSpy(&http, SIGNAL(requestFinished(int, bool)));
       
  1279     QSignalSpy doneSpy(&http, SIGNAL(done(bool)));
       
  1280 
       
  1281     http.setHost("localhost", server.serverPort());
       
  1282     http.get("/");
       
  1283     http.get("/");
       
  1284     http.get("/");
       
  1285 
       
  1286     loop.exec();
       
  1287 
       
  1288     QCOMPARE(finishedSpy.count(), 4);
       
  1289     QVERIFY(!finishedSpy.at(1).at(1).toBool());
       
  1290     QVERIFY(!finishedSpy.at(2).at(1).toBool());
       
  1291     QVERIFY(!finishedSpy.at(3).at(1).toBool());
       
  1292     QCOMPARE(doneSpy.count(), 1);
       
  1293     QVERIFY(!doneSpy.at(0).at(0).toBool());
       
  1294 }
       
  1295 
       
  1296 void tst_QHttp::pctEncodedPath()
       
  1297 {
       
  1298     QHttpRequestHeader header;
       
  1299     header.setRequest("GET", "/index.asp/a=%20&b=%20&c=%20");
       
  1300     QCOMPARE(header.toString(), QString("GET /index.asp/a=%20&b=%20&c=%20 HTTP/1.1\r\n\r\n"));
       
  1301 }
       
  1302 
       
  1303 void tst_QHttp::caseInsensitiveKeys()
       
  1304 {
       
  1305     QHttpResponseHeader header("HTTP/1.1 200 OK\r\nContent-Length: 213\r\nX-Been-There: True\r\nLocation: http://www.TrollTech.com/\r\n\r\n");
       
  1306     QVERIFY(header.hasKey("Content-Length"));
       
  1307     QVERIFY(header.hasKey("X-Been-There"));
       
  1308     QVERIFY(header.hasKey("Location"));
       
  1309     QVERIFY(header.hasKey("content-length"));
       
  1310     QVERIFY(header.hasKey("x-been-there"));
       
  1311     QVERIFY(header.hasKey("location"));
       
  1312     QCOMPARE(header.value("Content-Length"), QString("213"));
       
  1313     QCOMPARE(header.value("X-Been-There"), QString("True"));
       
  1314     QCOMPARE(header.value("Location"), QString("http://www.TrollTech.com/"));
       
  1315     QCOMPARE(header.value("content-length"), QString("213"));
       
  1316     QCOMPARE(header.value("x-been-there"), QString("True"));
       
  1317     QCOMPARE(header.value("location"), QString("http://www.TrollTech.com/"));
       
  1318     QCOMPARE(header.allValues("location"), QStringList("http://www.TrollTech.com/"));
       
  1319 
       
  1320     header.addValue("Content-Length", "213");
       
  1321     header.addValue("Content-Length", "214");
       
  1322     header.addValue("Content-Length", "215");
       
  1323     qDebug() << header.toString();
       
  1324 }
       
  1325 
       
  1326 void tst_QHttp::proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *auth)
       
  1327 {
       
  1328     proxyAuthCalled = true;
       
  1329     auth->setUser("qsockstest");
       
  1330     auth->setPassword("password");
       
  1331 }
       
  1332 
       
  1333 void tst_QHttp::postAuthNtlm()
       
  1334 {
       
  1335 	QSKIP("NTLM not working", SkipAll);
       
  1336 
       
  1337     QHostInfo info = QHostInfo::fromName(QHostInfo::localHostName());
       
  1338     QByteArray postData("Hello World");
       
  1339     QHttp http;
       
  1340 
       
  1341     http.setHost(QtNetworkSettings::serverName());
       
  1342     http.setProxy(QtNetworkSettings::serverName(), 3130);
       
  1343     http.post("/", postData);
       
  1344 
       
  1345     proxyAuthCalled = false;
       
  1346     connect(&http, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
       
  1347             SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
       
  1348 
       
  1349     QObject::connect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  1350     QTestEventLoop::instance().enterLoop(3);
       
  1351     QObject::disconnect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  1352 
       
  1353     QVERIFY(proxyAuthCalled);
       
  1354     QVERIFY(!QTestEventLoop::instance().timeout());
       
  1355 };
       
  1356 
       
  1357 void tst_QHttp::proxyAndSsl()
       
  1358 {
       
  1359 #ifdef QT_NO_OPENSSL
       
  1360     QSKIP("No OpenSSL support in this platform", SkipAll);
       
  1361 #else
       
  1362     QFETCH_GLOBAL(bool, setProxy);
       
  1363     if (setProxy)
       
  1364         return;
       
  1365 
       
  1366     QHttp http;
       
  1367 
       
  1368     http.setHost(QtNetworkSettings::serverName(), QHttp::ConnectionModeHttps);
       
  1369     http.setProxy(QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3129));
       
  1370     http.get("/");
       
  1371 
       
  1372     proxyAuthCalled = false;
       
  1373     connect(&http, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
       
  1374             SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
       
  1375     connect(&http, SIGNAL(sslErrors(QList<QSslError>)),
       
  1376             &http, SLOT(ignoreSslErrors()));
       
  1377 
       
  1378     QObject::connect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  1379     QTestEventLoop::instance().enterLoop(3);
       
  1380     QObject::disconnect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  1381 
       
  1382     QVERIFY(!QTestEventLoop::instance().timeout());
       
  1383     QVERIFY(proxyAuthCalled);
       
  1384 
       
  1385     QHttpResponseHeader header = http.lastResponse();
       
  1386     QVERIFY(header.isValid());
       
  1387     QVERIFY(header.statusCode() < 400); // Should be 200, but as long as it's not an error, we're happy
       
  1388 #endif
       
  1389 }
       
  1390 
       
  1391 void tst_QHttp::cachingProxyAndSsl()
       
  1392 {
       
  1393 #ifdef QT_NO_OPENSSL
       
  1394     QSKIP("No OpenSSL support in this platform", SkipAll);
       
  1395 #else
       
  1396     QFETCH_GLOBAL(bool, setProxy);
       
  1397     if (setProxy)
       
  1398         return;
       
  1399 
       
  1400     QHttp http;
       
  1401 
       
  1402     http.setHost(QtNetworkSettings::serverName(), QHttp::ConnectionModeHttps);
       
  1403     http.setProxy(QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129));
       
  1404     http.get("/");
       
  1405 
       
  1406     proxyAuthCalled = false;
       
  1407     connect(&http, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
       
  1408             SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
       
  1409 
       
  1410     QObject::connect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  1411     QTestEventLoop::instance().enterLoop(3);
       
  1412     QObject::disconnect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  1413 
       
  1414     QVERIFY(!QTestEventLoop::instance().timeout());
       
  1415     QVERIFY(!proxyAuthCalled);  // NOT called! QHttp should get a socket error
       
  1416     QVERIFY(http.state() != QHttp::Connected);
       
  1417 
       
  1418     QHttpResponseHeader header = http.lastResponse();
       
  1419     QVERIFY(!header.isValid());
       
  1420 #endif
       
  1421 }
       
  1422 
       
  1423 void tst_QHttp::emptyBodyInReply()
       
  1424 {
       
  1425     // Note: if this test starts failing, please verify the date on the file
       
  1426     // returned by Apache on http://netiks.troll.no/
       
  1427     // It is right now hard-coded to the date below
       
  1428     QHttp http;
       
  1429     http.setHost(QtNetworkSettings::serverName());
       
  1430 
       
  1431     QHttpRequestHeader headers("GET", "/");
       
  1432     headers.addValue("If-Modified-Since", "Sun, 16 Nov 2008 12:29:51 GMT");
       
  1433     headers.addValue("Host", QtNetworkSettings::serverName());
       
  1434     http.request(headers);
       
  1435 
       
  1436     QObject::connect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  1437     QTestEventLoop::instance().enterLoop(10);
       
  1438     QObject::disconnect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  1439 
       
  1440     QVERIFY(!QTestEventLoop::instance().timeout());
       
  1441 
       
  1442     // check the reply
       
  1443     if (http.lastResponse().statusCode() != 304) {
       
  1444         qWarning() << http.lastResponse().statusCode() << qPrintable(http.lastResponse().reasonPhrase());
       
  1445         qWarning() << "Last-Modified:" << qPrintable(http.lastResponse().value("last-modified"));
       
  1446         QFAIL("Server replied with the wrong status code; see warning output");
       
  1447     }
       
  1448 }
       
  1449 
       
  1450 void tst_QHttp::abortSender()
       
  1451 {
       
  1452     QHttp *http = qobject_cast<QHttp *>(sender());
       
  1453     if (http)
       
  1454         http->abort();
       
  1455 }
       
  1456 
       
  1457 void tst_QHttp::abortInReadyRead()
       
  1458 {
       
  1459     QHttp http;
       
  1460     http.setHost(QtNetworkSettings::serverName());
       
  1461     http.get("/qtest/bigfile");
       
  1462 
       
  1463     qRegisterMetaType<QHttpResponseHeader>();
       
  1464     QSignalSpy spy(&http, SIGNAL(readyRead(QHttpResponseHeader)));
       
  1465 
       
  1466     QObject::connect(&http, SIGNAL(readyRead(QHttpResponseHeader)), this, SLOT(abortSender()));
       
  1467     QObject::connect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  1468     QTestEventLoop::instance().enterLoop(10);
       
  1469     QObject::disconnect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  1470 
       
  1471     QVERIFY2(!QTestEventLoop::instance().timeout(), "Network timeout");
       
  1472     QVERIFY(http.state() != QHttp::Connected);
       
  1473 
       
  1474     QCOMPARE(spy.count(), 1);
       
  1475 }
       
  1476 
       
  1477 void tst_QHttp::abortInResponseHeaderReceived()
       
  1478 {
       
  1479     QHttp http;
       
  1480     http.setHost(QtNetworkSettings::serverName());
       
  1481     http.get("/qtest/bigfile");
       
  1482 
       
  1483     qRegisterMetaType<QHttpResponseHeader>();
       
  1484     QSignalSpy spy(&http, SIGNAL(readyRead(QHttpResponseHeader)));
       
  1485 
       
  1486     QObject::connect(&http, SIGNAL(responseHeaderReceived(QHttpResponseHeader)), this, SLOT(abortSender()));
       
  1487     QObject::connect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  1488     QTestEventLoop::instance().enterLoop(10);
       
  1489     QObject::disconnect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  1490 
       
  1491     QVERIFY2(!QTestEventLoop::instance().timeout(), "Network timeout");
       
  1492     QVERIFY(http.state() != QHttp::Connected);
       
  1493 
       
  1494     QCOMPARE(spy.count(), 0);
       
  1495 }
       
  1496 
       
  1497 void tst_QHttp::connectionClose()
       
  1498 {
       
  1499     // This test tries to connect to a client's server, so it is disabled.
       
  1500     // Every now and then, someone please run it to make sure it's not broken.
       
  1501     // Note: the servers might change too...
       
  1502     //
       
  1503     // This was added in response to bug 176822
       
  1504 #ifndef Q_OS_SYMBIAN
       
  1505     QSKIP("This test is manual - read comments in the source code", SkipAll);
       
  1506 #endif
       
  1507     QFETCH_GLOBAL(bool, setProxy);
       
  1508     if (setProxy)
       
  1509         return;
       
  1510 
       
  1511     QHttp http;
       
  1512     http.setHost("www.fon.com", QHttp::ConnectionModeHttps);
       
  1513     http.get("/login/gateway/processLogin");
       
  1514 
       
  1515     // another possibility:
       
  1516     //http.setHost("nexus.passport.com", QHttp::ConnectionModeHttps, 443);
       
  1517     //http.get("/rdr/pprdr.asp");
       
  1518 
       
  1519     QObject::connect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  1520     QTestEventLoop::instance().enterLoop(900);
       
  1521     QObject::disconnect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
  1522 
       
  1523     QVERIFY(!QTestEventLoop::instance().timeout());
       
  1524 }
       
  1525 
       
  1526 void tst_QHttp::nestedEventLoop_slot(int id)
       
  1527 {
       
  1528     if (!ids.contains(id))
       
  1529         return;
       
  1530     QEventLoop subloop;
       
  1531 
       
  1532     // 16 seconds: fluke times out in 15 seconds, which triggers a QTcpSocket error
       
  1533     QTimer::singleShot(16000, &subloop, SLOT(quit()));
       
  1534     subloop.exec();
       
  1535 
       
  1536     QTestEventLoop::instance().exitLoop();
       
  1537 }
       
  1538 
       
  1539 void tst_QHttp::nestedEventLoop()
       
  1540 {
       
  1541     QFETCH_GLOBAL(bool, setProxy);
       
  1542     if (setProxy)
       
  1543         return;
       
  1544 
       
  1545     http = new QHttp;
       
  1546     http->setHost(QtNetworkSettings::serverName());
       
  1547     int getId = http->get("/");
       
  1548 
       
  1549     ids.clear();
       
  1550     ids << getId;
       
  1551 
       
  1552     QSignalSpy spy(http, SIGNAL(requestStarted(int)));
       
  1553     QSignalSpy spy2(http, SIGNAL(done(bool)));
       
  1554 
       
  1555     connect(http, SIGNAL(requestFinished(int,bool)), SLOT(nestedEventLoop_slot(int)));
       
  1556     QTestEventLoop::instance().enterLoop(20);
       
  1557 
       
  1558     QVERIFY2(!QTestEventLoop::instance().timeout(), "Network timeout");
       
  1559 
       
  1560     // Find out how many signals with the first argument equalling our id were found
       
  1561     int spyCount = 0;
       
  1562     for (int i = 0; i < spy.count(); ++i)
       
  1563         if (spy.at(i).at(0).toInt() == getId)
       
  1564             ++spyCount;
       
  1565 
       
  1566     // each signal spied should have been emitted only once
       
  1567     QCOMPARE(spyCount, 1);
       
  1568     QCOMPARE(spy2.count(), 1);
       
  1569 }
       
  1570 
       
  1571 QTEST_MAIN(tst_QHttp)
       
  1572 #include "tst_qhttp.moc"