2011-04-27 10:05:43 +00:00
/****************************************************************************
* *
* * Copyright ( C ) 2011 Nokia Corporation and / or its subsidiary ( - ies ) .
* * All rights reserved .
* * Contact : Nokia Corporation ( qt - info @ nokia . com )
* *
* * This file is part of the test suite of the Qt Toolkit .
* *
* * $ QT_BEGIN_LICENSE : LGPL $
* * GNU Lesser General Public License Usage
2011-05-24 09:34:08 +00:00
* * This file may be used under the terms of the GNU Lesser General Public
* * License version 2.1 as published by the Free Software Foundation and
* * appearing in the file LICENSE . LGPL included in the packaging of this
* * file . Please review the following information to ensure the GNU Lesser
* * General Public License version 2.1 requirements will be met :
* * http : //www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
2011-04-27 10:05:43 +00:00
* *
* * In addition , as a special exception , Nokia gives you certain additional
2011-05-24 09:34:08 +00:00
* * rights . These rights are described in the Nokia Qt LGPL Exception
2011-04-27 10:05:43 +00:00
* * version 1.1 , included in the file LGPL_EXCEPTION . txt in this package .
* *
2011-05-24 09:34:08 +00:00
* * GNU General Public License Usage
* * Alternatively , this file may be used under the terms of the GNU General
* * Public License version 3.0 as published by the Free Software Foundation
* * and appearing in the file LICENSE . GPL included in the packaging of this
* * file . Please review the following information to ensure the GNU General
* * Public License version 3.0 requirements will be met :
* * http : //www.gnu.org/copyleft/gpl.html.
* *
* * Other Usage
* * Alternatively , this file may be used in accordance with the terms and
* * conditions contained in a signed written agreement between you and Nokia .
2011-04-27 10:05:43 +00:00
* *
* *
* *
* *
* *
* * $ QT_END_LICENSE $
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <QtTest/QtTest>
# include "private/qhttpnetworkconnection_p.h"
# include "private/qnoncontiguousbytedevice_p.h"
# include <QAuthenticator>
# include "../network-settings.h"
class tst_QHttpNetworkConnection : public QObject
{
Q_OBJECT
public :
tst_QHttpNetworkConnection ( ) ;
public Q_SLOTS :
void finishedReply ( ) ;
void finishedWithError ( QNetworkReply : : NetworkError errorCode , const QString & detail ) ;
void challenge401 ( const QHttpNetworkRequest & request , QAuthenticator * authenticator ) ;
# ifndef QT_NO_OPENSSL
void sslErrors ( const QList < QSslError > & errors ) ;
# endif
private :
bool finishedCalled ;
bool finishedWithErrorCalled ;
QNetworkReply : : NetworkError netErrorCode ;
private Q_SLOTS :
void init ( ) ;
void cleanup ( ) ;
void initTestCase ( ) ;
void cleanupTestCase ( ) ;
void options_data ( ) ;
void options ( ) ;
void get_data ( ) ;
void get ( ) ;
void head_data ( ) ;
void head ( ) ;
void post_data ( ) ;
void post ( ) ;
void put_data ( ) ;
void put ( ) ;
void _delete_data ( ) ;
void _delete ( ) ;
void trace_data ( ) ;
void trace ( ) ;
void _connect_data ( ) ;
void _connect ( ) ;
# ifndef QT_NO_COMPRESS
void compression_data ( ) ;
void compression ( ) ;
# endif
# ifndef QT_NO_OPENSSL
void ignoresslerror_data ( ) ;
void ignoresslerror ( ) ;
# endif
# ifdef QT_NO_OPENSSL
void nossl_data ( ) ;
void nossl ( ) ;
# endif
void get401_data ( ) ;
void get401 ( ) ;
void getMultiple_data ( ) ;
void getMultiple ( ) ;
void getMultipleWithPipeliningAndMultiplePriorities ( ) ;
void getMultipleWithPriorities ( ) ;
void getEmptyWithPipelining ( ) ;
void getAndEverythingShouldBePipelined ( ) ;
void getAndThenDeleteObject ( ) ;
void getAndThenDeleteObject_data ( ) ;
} ;
tst_QHttpNetworkConnection : : tst_QHttpNetworkConnection ( )
{
Q_SET_DEFAULT_IAP
}
void tst_QHttpNetworkConnection : : initTestCase ( )
{
}
void tst_QHttpNetworkConnection : : cleanupTestCase ( )
{
}
void tst_QHttpNetworkConnection : : init ( )
{
}
void tst_QHttpNetworkConnection : : cleanup ( )
{
}
void tst_QHttpNetworkConnection : : options_data ( )
{
// not tested yet
}
void tst_QHttpNetworkConnection : : options ( )
{
QEXPECT_FAIL ( " " , " not tested yet " , Continue ) ;
QVERIFY ( false ) ;
}
void tst_QHttpNetworkConnection : : head_data ( )
{
QTest : : addColumn < QString > ( " protocol " ) ;
QTest : : addColumn < QString > ( " host " ) ;
QTest : : addColumn < QString > ( " path " ) ;
QTest : : addColumn < ushort > ( " port " ) ;
QTest : : addColumn < bool > ( " encrypt " ) ;
QTest : : addColumn < int > ( " statusCode " ) ;
QTest : : addColumn < QString > ( " statusString " ) ;
QTest : : addColumn < int > ( " contentLength " ) ;
QTest : : newRow ( " success-internal " ) < < " http:// " < < QtNetworkSettings : : serverName ( ) < < " /qtest/rfc3252.txt " < < ushort ( 80 ) < < false < < 200 < < " OK " < < 25962 ;
QTest : : newRow ( " success-external " ) < < " http:// " < < " www.ietf.org " < < " /rfc/rfc3252.txt " < < ushort ( 80 ) < < false < < 200 < < " OK " < < 25962 ;
QTest : : newRow ( " failure-path " ) < < " http:// " < < QtNetworkSettings : : serverName ( ) < < " /t " < < ushort ( 80 ) < < false < < 404 < < " Not Found " < < - 1 ;
QTest : : newRow ( " failure-protocol " ) < < " " < < QtNetworkSettings : : serverName ( ) < < " /qtest/rfc3252.txt " < < ushort ( 80 ) < < false < < 400 < < " Bad Request " < < - 1 ;
}
void tst_QHttpNetworkConnection : : head ( )
{
QFETCH ( QString , protocol ) ;
QFETCH ( QString , host ) ;
QFETCH ( QString , path ) ;
QFETCH ( ushort , port ) ;
QFETCH ( bool , encrypt ) ;
QFETCH ( int , statusCode ) ;
QFETCH ( QString , statusString ) ;
QFETCH ( int , contentLength ) ;
QHttpNetworkConnection connection ( host , port , encrypt ) ;
QCOMPARE ( connection . port ( ) , port ) ;
QCOMPARE ( connection . hostName ( ) , host ) ;
QCOMPARE ( connection . isSsl ( ) , encrypt ) ;
QHttpNetworkRequest request ( protocol + host + path , QHttpNetworkRequest : : Head ) ;
QHttpNetworkReply * reply = connection . sendRequest ( request ) ;
QTime stopWatch ;
stopWatch . start ( ) ;
do {
QCoreApplication : : instance ( ) - > processEvents ( ) ;
if ( stopWatch . elapsed ( ) > = 30000 )
break ;
} while ( ! reply - > isFinished ( ) ) ;
QCOMPARE ( reply - > statusCode ( ) , statusCode ) ;
QCOMPARE ( reply - > reasonPhrase ( ) , statusString ) ;
// only check it if it is set and expected
if ( reply - > contentLength ( ) ! = - 1 & & contentLength ! = - 1 )
QCOMPARE ( reply - > contentLength ( ) , qint64 ( contentLength ) ) ;
QVERIFY ( reply - > isFinished ( ) ) ;
delete reply ;
}
void tst_QHttpNetworkConnection : : get_data ( )
{
QTest : : addColumn < QString > ( " protocol " ) ;
QTest : : addColumn < QString > ( " host " ) ;
QTest : : addColumn < QString > ( " path " ) ;
QTest : : addColumn < ushort > ( " port " ) ;
QTest : : addColumn < bool > ( " encrypt " ) ;
QTest : : addColumn < int > ( " statusCode " ) ;
QTest : : addColumn < QString > ( " statusString " ) ;
QTest : : addColumn < int > ( " contentLength " ) ;
QTest : : addColumn < int > ( " downloadSize " ) ;
QTest : : newRow ( " success-internal " ) < < " http:// " < < QtNetworkSettings : : serverName ( ) < < " /qtest/rfc3252.txt " < < ushort ( 80 ) < < false < < 200 < < " OK " < < 25962 < < 25962 ;
QTest : : newRow ( " success-external " ) < < " http:// " < < " www.ietf.org " < < " /rfc/rfc3252.txt " < < ushort ( 80 ) < < false < < 200 < < " OK " < < 25962 < < 25962 ;
QTest : : newRow ( " failure-path " ) < < " http:// " < < QtNetworkSettings : : serverName ( ) < < " /t " < < ushort ( 80 ) < < false < < 404 < < " Not Found " < < - 1 < < - 1 ;
QTest : : newRow ( " failure-protocol " ) < < " " < < QtNetworkSettings : : serverName ( ) < < " /qtest/rfc3252.txt " < < ushort ( 80 ) < < false < < 400 < < " Bad Request " < < - 1 < < - 1 ;
}
void tst_QHttpNetworkConnection : : get ( )
{
QFETCH ( QString , protocol ) ;
QFETCH ( QString , host ) ;
QFETCH ( QString , path ) ;
QFETCH ( ushort , port ) ;
QFETCH ( bool , encrypt ) ;
QFETCH ( int , statusCode ) ;
QFETCH ( QString , statusString ) ;
QFETCH ( int , contentLength ) ;
QFETCH ( int , downloadSize ) ;
QHttpNetworkConnection connection ( host , port , encrypt ) ;
QCOMPARE ( connection . port ( ) , port ) ;
QCOMPARE ( connection . hostName ( ) , host ) ;
QCOMPARE ( connection . isSsl ( ) , encrypt ) ;
QHttpNetworkRequest request ( protocol + host + path ) ;
QHttpNetworkReply * reply = connection . sendRequest ( request ) ;
QTime stopWatch ;
stopWatch . start ( ) ;
forever {
QCoreApplication : : instance ( ) - > processEvents ( ) ;
if ( reply - > bytesAvailable ( ) )
break ;
if ( stopWatch . elapsed ( ) > = 30000 )
break ;
}
QCOMPARE ( reply - > statusCode ( ) , statusCode ) ;
QCOMPARE ( reply - > reasonPhrase ( ) , statusString ) ;
// only check it if it is set and expected
if ( reply - > contentLength ( ) ! = - 1 & & contentLength ! = - 1 )
QCOMPARE ( reply - > contentLength ( ) , qint64 ( contentLength ) ) ;
stopWatch . start ( ) ;
QByteArray ba ;
do {
QCoreApplication : : instance ( ) - > processEvents ( ) ;
while ( reply - > bytesAvailable ( ) )
ba + = reply - > readAny ( ) ;
if ( stopWatch . elapsed ( ) > = 30000 )
break ;
} while ( ! reply - > isFinished ( ) ) ;
QVERIFY ( reply - > isFinished ( ) ) ;
//do not require server generated error pages to be a fixed size
if ( downloadSize ! = - 1 )
QCOMPARE ( ba . size ( ) , downloadSize ) ;
//but check against content length if it was sent
if ( reply - > contentLength ( ) ! = - 1 )
QCOMPARE ( ba . size ( ) , ( int ) reply - > contentLength ( ) ) ;
delete reply ;
}
void tst_QHttpNetworkConnection : : finishedReply ( )
{
finishedCalled = true ;
}
void tst_QHttpNetworkConnection : : finishedWithError ( QNetworkReply : : NetworkError errorCode , const QString & detail )
{
Q_UNUSED ( detail )
finishedWithErrorCalled = true ;
netErrorCode = errorCode ;
}
void tst_QHttpNetworkConnection : : put_data ( )
{
QTest : : addColumn < QString > ( " protocol " ) ;
QTest : : addColumn < QString > ( " host " ) ;
QTest : : addColumn < QString > ( " path " ) ;
QTest : : addColumn < ushort > ( " port " ) ;
QTest : : addColumn < bool > ( " encrypt " ) ;
QTest : : addColumn < QString > ( " data " ) ;
QTest : : addColumn < bool > ( " succeed " ) ;
QTest : : newRow ( " success-internal " ) < < " http:// " < < QtNetworkSettings : : serverName ( ) < < " /dav/file1.txt " < < ushort ( 80 ) < < false < < " Hello World \n End of file \n " < < true ;
QTest : : newRow ( " fail-internal " ) < < " http:// " < < QtNetworkSettings : : serverName ( ) < < " /dav2/file1.txt " < < ushort ( 80 ) < < false < < " Hello World \n End of file \n " < < false ;
QTest : : newRow ( " fail-host " ) < < " http:// " < < " fluke-nosuchhost.troll.no " < < " /dav2/file1.txt " < < ushort ( 80 ) < < false < < " Hello World \n End of file \n " < < false ;
}
void tst_QHttpNetworkConnection : : put ( )
{
QFETCH ( QString , protocol ) ;
QFETCH ( QString , host ) ;
QFETCH ( QString , path ) ;
QFETCH ( ushort , port ) ;
QFETCH ( bool , encrypt ) ;
QFETCH ( QString , data ) ;
QFETCH ( bool , succeed ) ;
QHttpNetworkConnection connection ( host , port , encrypt ) ;
QCOMPARE ( connection . port ( ) , port ) ;
QCOMPARE ( connection . hostName ( ) , host ) ;
QCOMPARE ( connection . isSsl ( ) , encrypt ) ;
QHttpNetworkRequest request ( protocol + host + path , QHttpNetworkRequest : : Put ) ;
QByteArray array = data . toLatin1 ( ) ;
QNonContiguousByteDevice * bd = QNonContiguousByteDeviceFactory : : create ( & array ) ;
bd - > setParent ( this ) ;
request . setUploadByteDevice ( bd ) ;
finishedCalled = false ;
finishedWithErrorCalled = false ;
QHttpNetworkReply * reply = connection . sendRequest ( request ) ;
connect ( reply , SIGNAL ( finished ( ) ) , SLOT ( finishedReply ( ) ) ) ;
connect ( reply , SIGNAL ( finishedWithError ( QNetworkReply : : NetworkError , const QString & ) ) ,
SLOT ( finishedWithError ( QNetworkReply : : NetworkError , const QString & ) ) ) ;
QTime stopWatch ;
stopWatch . start ( ) ;
do {
QCoreApplication : : instance ( ) - > processEvents ( ) ;
if ( stopWatch . elapsed ( ) > = 30000 )
break ;
} while ( ! reply - > isFinished ( ) & & ! finishedCalled & & ! finishedWithErrorCalled ) ;
if ( reply - > isFinished ( ) ) {
QByteArray ba ;
while ( reply - > bytesAvailable ( ) )
ba + = reply - > readAny ( ) ;
} else if ( finishedWithErrorCalled ) {
if ( ! succeed ) {
delete reply ;
return ;
} else {
QFAIL ( " Error in PUT " ) ;
}
} else {
QFAIL ( " PUT timed out " ) ;
}
int status = reply - > statusCode ( ) ;
if ( status ! = 200 & & status ! = 201 & & status ! = 204 ) {
if ( succeed ) {
qDebug ( ) < < " PUT failed, Status Code: " < < status ;
QFAIL ( " Error in PUT " ) ;
}
} else {
if ( ! succeed ) {
qDebug ( ) < < " PUT Should fail, Status Code: " < < status ;
QFAIL ( " Error in PUT " ) ;
}
}
delete reply ;
}
void tst_QHttpNetworkConnection : : post_data ( )
{
QTest : : addColumn < QString > ( " protocol " ) ;
QTest : : addColumn < QString > ( " host " ) ;
QTest : : addColumn < QString > ( " path " ) ;
QTest : : addColumn < ushort > ( " port " ) ;
QTest : : addColumn < bool > ( " encrypt " ) ;
QTest : : addColumn < QString > ( " data " ) ;
QTest : : addColumn < int > ( " statusCode " ) ;
QTest : : addColumn < QString > ( " statusString " ) ;
QTest : : addColumn < int > ( " contentLength " ) ;
QTest : : addColumn < int > ( " downloadSize " ) ;
QTest : : newRow ( " success-internal " ) < < " http:// " < < QtNetworkSettings : : serverName ( ) < < " /qtest/cgi-bin/echo.cgi " < < ushort ( 80 ) < < false < < " 7 bytes " < < 200 < < " OK " < < 7 < < 7 ;
QTest : : newRow ( " failure-internal " ) < < " http:// " < < QtNetworkSettings : : serverName ( ) < < " /t " < < ushort ( 80 ) < < false < < " Hello World " < < 404 < < " Not Found " < < - 1 < < - 1 ;
}
void tst_QHttpNetworkConnection : : post ( )
{
QFETCH ( QString , protocol ) ;
QFETCH ( QString , host ) ;
QFETCH ( QString , path ) ;
QFETCH ( ushort , port ) ;
QFETCH ( bool , encrypt ) ;
QFETCH ( QString , data ) ;
QFETCH ( int , statusCode ) ;
QFETCH ( QString , statusString ) ;
QFETCH ( int , contentLength ) ;
QFETCH ( int , downloadSize ) ;
QHttpNetworkConnection connection ( host , port , encrypt ) ;
QCOMPARE ( connection . port ( ) , port ) ;
QCOMPARE ( connection . hostName ( ) , host ) ;
QCOMPARE ( connection . isSsl ( ) , encrypt ) ;
QHttpNetworkRequest request ( protocol + host + path , QHttpNetworkRequest : : Post ) ;
QByteArray array = data . toLatin1 ( ) ;
QNonContiguousByteDevice * bd = QNonContiguousByteDeviceFactory : : create ( & array ) ;
bd - > setParent ( this ) ;
request . setUploadByteDevice ( bd ) ;
QHttpNetworkReply * reply = connection . sendRequest ( request ) ;
QTime stopWatch ;
stopWatch . start ( ) ;
forever {
QCoreApplication : : instance ( ) - > processEvents ( ) ;
if ( reply - > bytesAvailable ( ) )
break ;
if ( stopWatch . elapsed ( ) > = 30000 )
break ;
}
QCOMPARE ( reply - > statusCode ( ) , statusCode ) ;
QCOMPARE ( reply - > reasonPhrase ( ) , statusString ) ;
qint64 cLen = reply - > contentLength ( ) ;
if ( contentLength ! = - 1 ) {
// only check the content length if test expected it to be set
if ( cLen = = - 1 ) {
// HTTP 1.1 server may respond with chunked encoding and in that
// case contentLength is not present in reply -> verify that it is the case
QByteArray transferEnc = reply - > headerField ( " Transfer-Encoding " ) ;
QCOMPARE ( transferEnc , QByteArray ( " chunked " ) ) ;
} else {
QCOMPARE ( cLen , qint64 ( contentLength ) ) ;
}
}
stopWatch . start ( ) ;
QByteArray ba ;
do {
QCoreApplication : : instance ( ) - > processEvents ( ) ;
while ( reply - > bytesAvailable ( ) )
ba + = reply - > readAny ( ) ;
if ( stopWatch . elapsed ( ) > = 30000 )
break ;
} while ( ! reply - > isFinished ( ) ) ;
QVERIFY ( reply - > isFinished ( ) ) ;
//don't require fixed size for generated error pages
if ( downloadSize ! = - 1 )
QCOMPARE ( ba . size ( ) , downloadSize ) ;
//but do compare with content length if possible
if ( cLen ! = - 1 )
QCOMPARE ( ba . size ( ) , ( int ) cLen ) ;
delete reply ;
}
void tst_QHttpNetworkConnection : : _delete_data ( )
{
// not tested yet
}
void tst_QHttpNetworkConnection : : _delete ( )
{
QEXPECT_FAIL ( " " , " not tested yet " , Continue ) ;
QVERIFY ( false ) ;
}
void tst_QHttpNetworkConnection : : trace_data ( )
{
// not tested yet
}
void tst_QHttpNetworkConnection : : trace ( )
{
QEXPECT_FAIL ( " " , " not tested yet " , Continue ) ;
QVERIFY ( false ) ;
}
void tst_QHttpNetworkConnection : : _connect_data ( )
{
// not tested yet
}
void tst_QHttpNetworkConnection : : _connect ( )
{
QEXPECT_FAIL ( " " , " not tested yet " , Continue ) ;
QVERIFY ( false ) ;
}
void tst_QHttpNetworkConnection : : challenge401 ( const QHttpNetworkRequest & request ,
QAuthenticator * authenticator )
{
Q_UNUSED ( request )
QHttpNetworkReply * reply = qobject_cast < QHttpNetworkReply * > ( sender ( ) ) ;
if ( reply ) {
QHttpNetworkConnection * c = reply - > connection ( ) ;
QVariant val = c - > property ( " setCredentials " ) ;
if ( val . toBool ( ) ) {
QVariant user = c - > property ( " username " ) ;
QVariant password = c - > property ( " password " ) ;
authenticator - > setUser ( user . toString ( ) ) ;
authenticator - > setPassword ( password . toString ( ) ) ;
c - > setProperty ( " setCredentials " , false ) ;
}
}
}
void tst_QHttpNetworkConnection : : get401_data ( )
{
QTest : : addColumn < QString > ( " protocol " ) ;
QTest : : addColumn < QString > ( " host " ) ;
QTest : : addColumn < QString > ( " path " ) ;
QTest : : addColumn < ushort > ( " port " ) ;
QTest : : addColumn < bool > ( " encrypt " ) ;
QTest : : addColumn < bool > ( " setCredentials " ) ;
QTest : : addColumn < QString > ( " username " ) ;
QTest : : addColumn < QString > ( " password " ) ;
QTest : : addColumn < int > ( " statusCode " ) ;
QTest : : newRow ( " no-credentials " ) < < " http:// " < < QtNetworkSettings : : serverName ( ) < < " /qtest/rfcs-auth/index.html " < < ushort ( 80 ) < < false < < false < < " " < < " " < < 401 ;
QTest : : newRow ( " invalid-credentials " ) < < " http:// " < < QtNetworkSettings : : serverName ( ) < < " /qtest/rfcs-auth/index.html " < < ushort ( 80 ) < < false < < true < < " test " < < " test " < < 401 ;
QTest : : newRow ( " valid-credentials " ) < < " http:// " < < QtNetworkSettings : : serverName ( ) < < " /qtest/rfcs-auth/index.html " < < ushort ( 80 ) < < false < < true < < " httptest " < < " httptest " < < 200 ;
QTest : : newRow ( " digest-authentication-invalid " ) < < " http:// " < < QtNetworkSettings : : serverName ( ) < < " /qtest/auth-digest/index.html " < < ushort ( 80 ) < < false < < true < < " wrong " < < " wrong " < < 401 ;
QTest : : newRow ( " digest-authentication-valid " ) < < " http:// " < < QtNetworkSettings : : serverName ( ) < < " /qtest/auth-digest/index.html " < < ushort ( 80 ) < < false < < true < < " httptest " < < " httptest " < < 200 ;
}
void tst_QHttpNetworkConnection : : get401 ( )
{
QFETCH ( QString , protocol ) ;
QFETCH ( QString , host ) ;
QFETCH ( QString , path ) ;
QFETCH ( ushort , port ) ;
QFETCH ( bool , encrypt ) ;
QFETCH ( bool , setCredentials ) ;
QFETCH ( QString , username ) ;
QFETCH ( QString , password ) ;
QFETCH ( int , statusCode ) ;
QHttpNetworkConnection connection ( host , port , encrypt ) ;
QCOMPARE ( connection . port ( ) , port ) ;
QCOMPARE ( connection . hostName ( ) , host ) ;
QCOMPARE ( connection . isSsl ( ) , encrypt ) ;
connection . setProperty ( " setCredentials " , setCredentials ) ;
connection . setProperty ( " username " , username ) ;
connection . setProperty ( " password " , password ) ;
QHttpNetworkRequest request ( protocol + host + path ) ;
QHttpNetworkReply * reply = connection . sendRequest ( request ) ;
connect ( reply , SIGNAL ( authenticationRequired ( const QHttpNetworkRequest & , QAuthenticator * ) ) ,
SLOT ( challenge401 ( const QHttpNetworkRequest & , QAuthenticator * ) ) ) ;
finishedCalled = false ;
finishedWithErrorCalled = false ;
connect ( reply , SIGNAL ( finished ( ) ) , SLOT ( finishedReply ( ) ) ) ;
connect ( reply , SIGNAL ( finishedWithError ( QNetworkReply : : NetworkError , const QString & ) ) ,
SLOT ( finishedWithError ( QNetworkReply : : NetworkError , const QString & ) ) ) ;
QTime stopWatch ;
stopWatch . start ( ) ;
forever {
QCoreApplication : : instance ( ) - > processEvents ( ) ;
if ( finishedCalled )
break ;
if ( finishedWithErrorCalled )
break ;
if ( stopWatch . elapsed ( ) > = 30000 )
break ;
}
QCOMPARE ( reply - > statusCode ( ) , statusCode ) ;
delete reply ;
}
# ifndef QT_NO_COMPRESS
void tst_QHttpNetworkConnection : : compression_data ( )
{
QTest : : addColumn < QString > ( " protocol " ) ;
QTest : : addColumn < QString > ( " host " ) ;
QTest : : addColumn < QString > ( " path " ) ;
QTest : : addColumn < ushort > ( " port " ) ;
QTest : : addColumn < bool > ( " encrypt " ) ;
QTest : : addColumn < int > ( " statusCode " ) ;
QTest : : addColumn < QString > ( " statusString " ) ;
QTest : : addColumn < int > ( " contentLength " ) ;
QTest : : addColumn < int > ( " downloadSize " ) ;
QTest : : addColumn < bool > ( " autoCompress " ) ;
QTest : : addColumn < QString > ( " contentCoding " ) ;
QTest : : newRow ( " success-autogzip-temp " ) < < " http:// " < < QtNetworkSettings : : serverName ( ) < < " /qtest/rfcs/rfc2616.html " < < ushort ( 80 ) < < false < < 200 < < " OK " < < - 1 < < 418321 < < true < < " " ;
QTest : : newRow ( " success-nogzip-temp " ) < < " http:// " < < QtNetworkSettings : : serverName ( ) < < " /qtest/rfcs/rfc2616.html " < < ushort ( 80 ) < < false < < 200 < < " OK " < < 418321 < < 418321 < < false < < " identity " ;
QTest : : newRow ( " success-manualgzip-temp " ) < < " http:// " < < QtNetworkSettings : : serverName ( ) < < " /qtest/deflate/rfc2616.html " < < ushort ( 80 ) < < false < < 200 < < " OK " < < 119124 < < 119124 < < false < < " gzip " ;
}
void tst_QHttpNetworkConnection : : compression ( )
{
QFETCH ( QString , protocol ) ;
QFETCH ( QString , host ) ;
QFETCH ( QString , path ) ;
QFETCH ( ushort , port ) ;
QFETCH ( bool , encrypt ) ;
QFETCH ( int , statusCode ) ;
QFETCH ( QString , statusString ) ;
QFETCH ( int , contentLength ) ;
QFETCH ( int , downloadSize ) ;
QFETCH ( bool , autoCompress ) ;
QFETCH ( QString , contentCoding ) ;
QHttpNetworkConnection connection ( host , port , encrypt ) ;
QCOMPARE ( connection . port ( ) , port ) ;
QCOMPARE ( connection . hostName ( ) , host ) ;
QCOMPARE ( connection . isSsl ( ) , encrypt ) ;
QHttpNetworkRequest request ( protocol + host + path ) ;
if ( ! autoCompress )
request . setHeaderField ( " Accept-Encoding " , contentCoding . toLatin1 ( ) ) ;
QHttpNetworkReply * reply = connection . sendRequest ( request ) ;
QTime stopWatch ;
stopWatch . start ( ) ;
forever {
QCoreApplication : : instance ( ) - > processEvents ( ) ;
if ( reply - > bytesAvailable ( ) )
break ;
if ( stopWatch . elapsed ( ) > = 30000 )
break ;
}
QCOMPARE ( reply - > statusCode ( ) , statusCode ) ;
QCOMPARE ( reply - > reasonPhrase ( ) , statusString ) ;
bool isLengthOk = ( reply - > contentLength ( ) = = qint64 ( contentLength )
| | reply - > contentLength ( ) = = qint64 ( downloadSize )
| | reply - > contentLength ( ) = = - 1 ) ; //apache2 does not send content-length for compressed pages
QVERIFY ( isLengthOk ) ;
stopWatch . start ( ) ;
QByteArray ba ;
do {
QCoreApplication : : instance ( ) - > processEvents ( ) ;
while ( reply - > bytesAvailable ( ) )
ba + = reply - > readAny ( ) ;
if ( stopWatch . elapsed ( ) > = 30000 )
break ;
} while ( ! reply - > isFinished ( ) ) ;
QVERIFY ( reply - > isFinished ( ) ) ;
QCOMPARE ( ba . size ( ) , downloadSize ) ;
delete reply ;
}
# endif
# ifndef QT_NO_OPENSSL
void tst_QHttpNetworkConnection : : sslErrors ( const QList < QSslError > & errors )
{
Q_UNUSED ( errors )
QHttpNetworkReply * reply = qobject_cast < QHttpNetworkReply * > ( sender ( ) ) ;
if ( reply ) {
QHttpNetworkConnection * connection = reply - > connection ( ) ;
QVariant val = connection - > property ( " ignoreFromSignal " ) ;
if ( val . toBool ( ) )
connection - > ignoreSslErrors ( ) ;
finishedWithErrorCalled = true ;
}
}
void tst_QHttpNetworkConnection : : ignoresslerror_data ( )
{
QTest : : addColumn < QString > ( " protocol " ) ;
QTest : : addColumn < QString > ( " host " ) ;
QTest : : addColumn < QString > ( " path " ) ;
QTest : : addColumn < ushort > ( " port " ) ;
QTest : : addColumn < bool > ( " encrypt " ) ;
QTest : : addColumn < bool > ( " ignoreInit " ) ;
QTest : : addColumn < bool > ( " ignoreFromSignal " ) ;
QTest : : addColumn < int > ( " statusCode " ) ;
// This test will work only if the website has ssl errors.
// fluke's certificate is signed by a non-standard authority.
// Since we don't introduce that CA into the SSL verification chain,
// connecting should fail.
QTest : : newRow ( " success-init " ) < < " https:// " < < QtNetworkSettings : : serverName ( ) < < " / " < < ushort ( 443 ) < < true < < true < < false < < 200 ;
QTest : : newRow ( " success-fromSignal " ) < < " https:// " < < QtNetworkSettings : : serverName ( ) < < " / " < < ushort ( 443 ) < < true < < false < < true < < 200 ;
QTest : : newRow ( " failure " ) < < " https:// " < < QtNetworkSettings : : serverName ( ) < < " / " < < ushort ( 443 ) < < true < < false < < false < < 100 ;
}
void tst_QHttpNetworkConnection : : ignoresslerror ( )
{
QFETCH ( QString , protocol ) ;
QFETCH ( QString , host ) ;
QFETCH ( QString , path ) ;
QFETCH ( ushort , port ) ;
QFETCH ( bool , encrypt ) ;
QFETCH ( bool , ignoreInit ) ;
QFETCH ( bool , ignoreFromSignal ) ;
QFETCH ( int , statusCode ) ;
QHttpNetworkConnection connection ( host , port , encrypt ) ;
QCOMPARE ( connection . port ( ) , port ) ;
QCOMPARE ( connection . hostName ( ) , host ) ;
if ( ignoreInit )
connection . ignoreSslErrors ( ) ;
QCOMPARE ( connection . isSsl ( ) , encrypt ) ;
connection . setProperty ( " ignoreFromSignal " , ignoreFromSignal ) ;
QHttpNetworkRequest request ( protocol + host + path ) ;
QHttpNetworkReply * reply = connection . sendRequest ( request ) ;
connect ( reply , SIGNAL ( sslErrors ( const QList < QSslError > & ) ) ,
SLOT ( sslErrors ( const QList < QSslError > & ) ) ) ;
finishedWithErrorCalled = false ;
connect ( reply , SIGNAL ( finished ( ) ) , SLOT ( finishedReply ( ) ) ) ;
QTime stopWatch ;
stopWatch . start ( ) ;
forever {
QCoreApplication : : instance ( ) - > processEvents ( ) ;
if ( reply - > bytesAvailable ( ) )
break ;
if ( statusCode = = 100 & & finishedWithErrorCalled )
break ;
if ( stopWatch . elapsed ( ) > = 30000 )
break ;
}
QCOMPARE ( reply - > statusCode ( ) , statusCode ) ;
delete reply ;
}
# endif
# ifdef QT_NO_OPENSSL
Q_DECLARE_METATYPE ( QNetworkReply : : NetworkError )
void tst_QHttpNetworkConnection : : nossl_data ( )
{
QTest : : addColumn < QString > ( " protocol " ) ;
QTest : : addColumn < QString > ( " host " ) ;
QTest : : addColumn < QString > ( " path " ) ;
QTest : : addColumn < ushort > ( " port " ) ;
QTest : : addColumn < bool > ( " encrypt " ) ;
QTest : : addColumn < QNetworkReply : : NetworkError > ( " networkError " ) ;
QTest : : newRow ( " protocol-error " ) < < " https:// " < < QtNetworkSettings : : serverName ( ) < < " / " < < ushort ( 443 ) < < true < < QNetworkReply : : ProtocolUnknownError ;
}
void tst_QHttpNetworkConnection : : nossl ( )
{
QFETCH ( QString , protocol ) ;
QFETCH ( QString , host ) ;
QFETCH ( QString , path ) ;
QFETCH ( ushort , port ) ;
QFETCH ( bool , encrypt ) ;
QFETCH ( QNetworkReply : : NetworkError , networkError ) ;
QHttpNetworkConnection connection ( host , port , encrypt ) ;
QCOMPARE ( connection . port ( ) , port ) ;
QCOMPARE ( connection . hostName ( ) , host ) ;
QHttpNetworkRequest request ( protocol + host + path ) ;
QHttpNetworkReply * reply = connection . sendRequest ( request ) ;
finishedWithErrorCalled = false ;
netErrorCode = QNetworkReply : : NoError ;
connect ( reply , SIGNAL ( finished ( ) ) , SLOT ( finishedReply ( ) ) ) ;
connect ( reply , SIGNAL ( finishedWithError ( QNetworkReply : : NetworkError , const QString & ) ) ,
SLOT ( finishedWithError ( QNetworkReply : : NetworkError , const QString & ) ) ) ;
QTime stopWatch ;
stopWatch . start ( ) ;
forever {
QCoreApplication : : instance ( ) - > processEvents ( ) ;
if ( finishedWithErrorCalled )
break ;
if ( stopWatch . elapsed ( ) > = 30000 )
break ;
}
QCOMPARE ( netErrorCode , networkError ) ;
delete reply ;
}
# endif
void tst_QHttpNetworkConnection : : getMultiple_data ( )
{
QTest : : addColumn < quint16 > ( " connectionCount " ) ;
QTest : : addColumn < bool > ( " pipeliningAllowed " ) ;
// send 100 requests. apache will usually force-close after 100 requests in a single tcp connection
QTest : : addColumn < int > ( " requestCount " ) ;
QTest : : newRow ( " 6 connections, no pipelining, 100 requests " ) < < quint16 ( 6 ) < < false < < 100 ;
QTest : : newRow ( " 1 connection, no pipelining, 100 requests " ) < < quint16 ( 1 ) < < false < < 100 ;
QTest : : newRow ( " 6 connections, pipelining allowed, 100 requests " ) < < quint16 ( 6 ) < < true < < 100 ;
QTest : : newRow ( " 1 connection, pipelining allowed, 100 requests " ) < < quint16 ( 1 ) < < true < < 100 ;
}
void tst_QHttpNetworkConnection : : getMultiple ( )
{
QFETCH ( quint16 , connectionCount ) ;
QFETCH ( bool , pipeliningAllowed ) ;
QFETCH ( int , requestCount ) ;
QHttpNetworkConnection connection ( connectionCount , QtNetworkSettings : : serverName ( ) ) ;
QList < QHttpNetworkRequest * > requests ;
QList < QHttpNetworkReply * > replies ;
for ( int i = 0 ; i < requestCount ; i + + ) {
// depending on what you use the results will vary.
// for the "real" results, use a URL that has "internet latency" for you. Then (6 connections, pipelining) will win.
// for LAN latency, you will possibly get that (1 connection, no pipelining) is the fastest
QHttpNetworkRequest * request = new QHttpNetworkRequest ( " http:// " + QtNetworkSettings : : serverName ( ) + " /qtest/rfc3252.txt " ) ;
// located in Berlin:
//QHttpNetworkRequest *request = new QHttpNetworkRequest(QUrl("http://klinsmann.nokia.trolltech.de/~berlin/qtcreatorad.gif"));
if ( pipeliningAllowed )
request - > setPipeliningAllowed ( true ) ;
requests . append ( request ) ;
QHttpNetworkReply * reply = connection . sendRequest ( * request ) ;
replies . append ( reply ) ;
}
QTime stopWatch ;
stopWatch . start ( ) ;
int finishedCount = 0 ;
do {
QCoreApplication : : instance ( ) - > processEvents ( ) ;
if ( stopWatch . elapsed ( ) > = 60000 )
break ;
finishedCount = 0 ;
for ( int i = 0 ; i < replies . length ( ) ; i + + )
if ( replies . at ( i ) - > isFinished ( ) )
finishedCount + + ;
} while ( finishedCount ! = replies . length ( ) ) ;
// redundant
for ( int i = 0 ; i < replies . length ( ) ; i + + )
QVERIFY ( replies . at ( i ) - > isFinished ( ) ) ;
qDebug ( ) < < " === " < < stopWatch . elapsed ( ) < < " msec === " ;
qDeleteAll ( requests ) ;
qDeleteAll ( replies ) ;
}
void tst_QHttpNetworkConnection : : getMultipleWithPipeliningAndMultiplePriorities ( )
{
quint16 requestCount = 100 ;
// use 2 connections.
QHttpNetworkConnection connection ( 2 , QtNetworkSettings : : serverName ( ) ) ;
QList < QHttpNetworkRequest * > requests ;
QList < QHttpNetworkReply * > replies ;
for ( int i = 0 ; i < requestCount ; i + + ) {
QHttpNetworkRequest * request = 0 ;
if ( i % 3 )
request = new QHttpNetworkRequest ( " http:// " + QtNetworkSettings : : serverName ( ) + " /qtest/rfc3252.txt " , QHttpNetworkRequest : : Get ) ;
else
request = new QHttpNetworkRequest ( " http:// " + QtNetworkSettings : : serverName ( ) + " /qtest/rfc3252.txt " , QHttpNetworkRequest : : Head ) ;
if ( i % 2 | | i % 3 )
request - > setPipeliningAllowed ( true ) ;
if ( i % 3 )
request - > setPriority ( QHttpNetworkRequest : : HighPriority ) ;
else if ( i % 5 )
request - > setPriority ( QHttpNetworkRequest : : NormalPriority ) ;
else if ( i % 7 )
request - > setPriority ( QHttpNetworkRequest : : LowPriority ) ;
requests . append ( request ) ;
QHttpNetworkReply * reply = connection . sendRequest ( * request ) ;
replies . append ( reply ) ;
}
QTime stopWatch ;
stopWatch . start ( ) ;
int finishedCount = 0 ;
do {
QCoreApplication : : instance ( ) - > processEvents ( ) ;
if ( stopWatch . elapsed ( ) > = 60000 )
break ;
finishedCount = 0 ;
for ( int i = 0 ; i < replies . length ( ) ; i + + )
if ( replies . at ( i ) - > isFinished ( ) )
finishedCount + + ;
} while ( finishedCount ! = replies . length ( ) ) ;
int pipelinedCount = 0 ;
for ( int i = 0 ; i < replies . length ( ) ; i + + ) {
QVERIFY ( replies . at ( i ) - > isFinished ( ) ) ;
QVERIFY ( ! ( replies . at ( i ) - > request ( ) . isPipeliningAllowed ( ) = = false
& & replies . at ( i ) - > isPipeliningUsed ( ) ) ) ;
if ( replies . at ( i ) - > isPipeliningUsed ( ) )
pipelinedCount + + ;
}
// We allow pipelining for every 2nd,3rd,4th,6th,8th,9th,10th etc request.
// Assume that half of the requests had been pipelined.
// (this is a very relaxed condition, when last measured 79 of 100
// requests had been pipelined)
QVERIFY ( pipelinedCount > = requestCount / 2 ) ;
qDebug ( ) < < " === " < < stopWatch . elapsed ( ) < < " msec === " ;
qDeleteAll ( requests ) ;
qDeleteAll ( replies ) ;
}
class GetMultipleWithPrioritiesReceiver : public QObject
{
Q_OBJECT
public :
int highPrioReceived ;
int lowPrioReceived ;
int requestCount ;
GetMultipleWithPrioritiesReceiver ( int rq ) : highPrioReceived ( 0 ) , lowPrioReceived ( 0 ) , requestCount ( rq ) { }
public Q_SLOTS :
void finishedSlot ( ) {
QHttpNetworkReply * reply = ( QHttpNetworkReply * ) sender ( ) ;
if ( reply - > request ( ) . priority ( ) = = QHttpNetworkRequest : : HighPriority )
highPrioReceived + + ;
else if ( reply - > request ( ) . priority ( ) = = QHttpNetworkRequest : : LowPriority )
lowPrioReceived + + ;
else
QFAIL ( " Wrong priority!? " ) ;
QVERIFY ( highPrioReceived + 7 > = lowPrioReceived ) ;
if ( highPrioReceived + lowPrioReceived = = requestCount )
QTestEventLoop : : instance ( ) . exitLoop ( ) ;
}
} ;
void tst_QHttpNetworkConnection : : getMultipleWithPriorities ( )
{
quint16 requestCount = 100 ;
// use 2 connections.
QHttpNetworkConnection connection ( 2 , QtNetworkSettings : : serverName ( ) ) ;
GetMultipleWithPrioritiesReceiver receiver ( requestCount ) ;
QUrl url ( " http:// " + QtNetworkSettings : : serverName ( ) + " /qtest/rfc3252.txt " ) ;
QList < QHttpNetworkRequest * > requests ;
QList < QHttpNetworkReply * > replies ;
for ( int i = 0 ; i < requestCount ; i + + ) {
QHttpNetworkRequest * request = 0 ;
if ( i % 3 )
request = new QHttpNetworkRequest ( url , QHttpNetworkRequest : : Get ) ;
else
request = new QHttpNetworkRequest ( url , QHttpNetworkRequest : : Head ) ;
if ( i % 2 )
request - > setPriority ( QHttpNetworkRequest : : HighPriority ) ;
else
request - > setPriority ( QHttpNetworkRequest : : LowPriority ) ;
requests . append ( request ) ;
QHttpNetworkReply * reply = connection . sendRequest ( * request ) ;
connect ( reply , SIGNAL ( finished ( ) ) , & receiver , SLOT ( finishedSlot ( ) ) ) ;
replies . append ( reply ) ;
}
QTestEventLoop : : instance ( ) . enterLoop ( 40 ) ;
QVERIFY ( ! QTestEventLoop : : instance ( ) . timeout ( ) ) ;
qDeleteAll ( requests ) ;
qDeleteAll ( replies ) ;
}
class GetEmptyWithPipeliningReceiver : public QObject
{
Q_OBJECT
public :
int receivedCount ;
int requestCount ;
GetEmptyWithPipeliningReceiver ( int rq ) : receivedCount ( 0 ) , requestCount ( rq ) { }
public Q_SLOTS :
void finishedSlot ( ) {
QHttpNetworkReply * reply = ( QHttpNetworkReply * ) sender ( ) ;
2011-05-19 14:19:01 +00:00
Q_UNUSED ( reply ) ;
2011-04-27 10:05:43 +00:00
receivedCount + + ;
if ( receivedCount = = requestCount )
QTestEventLoop : : instance ( ) . exitLoop ( ) ;
}
} ;
void tst_QHttpNetworkConnection : : getEmptyWithPipelining ( )
{
quint16 requestCount = 50 ;
// use 2 connections.
QHttpNetworkConnection connection ( 2 , QtNetworkSettings : : serverName ( ) ) ;
GetEmptyWithPipeliningReceiver receiver ( requestCount ) ;
QUrl url ( " http:// " + QtNetworkSettings : : serverName ( ) + " /cgi-bin/echo.cgi " ) ; // a get on this = getting an empty file
QList < QHttpNetworkRequest * > requests ;
QList < QHttpNetworkReply * > replies ;
for ( int i = 0 ; i < requestCount ; i + + ) {
QHttpNetworkRequest * request = 0 ;
request = new QHttpNetworkRequest ( url , QHttpNetworkRequest : : Get ) ;
request - > setPipeliningAllowed ( true ) ;
requests . append ( request ) ;
QHttpNetworkReply * reply = connection . sendRequest ( * request ) ;
connect ( reply , SIGNAL ( finished ( ) ) , & receiver , SLOT ( finishedSlot ( ) ) ) ;
replies . append ( reply ) ;
}
QTestEventLoop : : instance ( ) . enterLoop ( 20 ) ;
QVERIFY ( ! QTestEventLoop : : instance ( ) . timeout ( ) ) ;
qDeleteAll ( requests ) ;
qDeleteAll ( replies ) ;
}
class GetAndEverythingShouldBePipelinedReceiver : public QObject
{
Q_OBJECT
public :
int receivedCount ;
int requestCount ;
GetAndEverythingShouldBePipelinedReceiver ( int rq ) : receivedCount ( 0 ) , requestCount ( rq ) { }
public Q_SLOTS :
void finishedSlot ( ) {
QHttpNetworkReply * reply = ( QHttpNetworkReply * ) sender ( ) ;
2011-05-19 14:19:01 +00:00
Q_UNUSED ( reply ) ;
2011-04-27 10:05:43 +00:00
receivedCount + + ;
if ( receivedCount = = requestCount )
QTestEventLoop : : instance ( ) . exitLoop ( ) ;
}
} ;
void tst_QHttpNetworkConnection : : getAndEverythingShouldBePipelined ( )
{
quint16 requestCount = 100 ;
// use 1 connection.
QHttpNetworkConnection connection ( 1 , QtNetworkSettings : : serverName ( ) ) ;
QUrl url ( " http:// " + QtNetworkSettings : : serverName ( ) + " /qtest/rfc3252.txt " ) ;
QList < QHttpNetworkRequest * > requests ;
QList < QHttpNetworkReply * > replies ;
GetAndEverythingShouldBePipelinedReceiver receiver ( requestCount ) ;
for ( int i = 0 ; i < requestCount ; i + + ) {
QHttpNetworkRequest * request = 0 ;
request = new QHttpNetworkRequest ( url , QHttpNetworkRequest : : Get ) ;
request - > setPipeliningAllowed ( true ) ;
requests . append ( request ) ;
QHttpNetworkReply * reply = connection . sendRequest ( * request ) ;
connect ( reply , SIGNAL ( finished ( ) ) , & receiver , SLOT ( finishedSlot ( ) ) ) ;
replies . append ( reply ) ;
}
QTestEventLoop : : instance ( ) . enterLoop ( 40 ) ;
QVERIFY ( ! QTestEventLoop : : instance ( ) . timeout ( ) ) ;
qDeleteAll ( requests ) ;
qDeleteAll ( replies ) ;
}
void tst_QHttpNetworkConnection : : getAndThenDeleteObject_data ( )
{
QTest : : addColumn < bool > ( " replyFirst " ) ;
QTest : : newRow ( " delete-reply-first " ) < < true ;
QTest : : newRow ( " delete-connection-first " ) < < false ;
}
void tst_QHttpNetworkConnection : : getAndThenDeleteObject ( )
{
// yes, this will leak if the testcase fails. I don't care. It must not fail then :P
QHttpNetworkConnection * connection = new QHttpNetworkConnection ( QtNetworkSettings : : serverName ( ) ) ;
QHttpNetworkRequest request ( " http:// " + QtNetworkSettings : : serverName ( ) + " /qtest/bigfile " ) ;
QHttpNetworkReply * reply = connection - > sendRequest ( request ) ;
reply - > setDownstreamLimited ( true ) ;
QTime stopWatch ;
stopWatch . start ( ) ;
forever {
QCoreApplication : : instance ( ) - > processEvents ( ) ;
if ( reply - > bytesAvailable ( ) )
break ;
if ( stopWatch . elapsed ( ) > = 30000 )
break ;
}
QVERIFY ( reply - > bytesAvailable ( ) ) ;
QCOMPARE ( reply - > statusCode ( ) , 200 ) ;
QVERIFY ( ! reply - > isFinished ( ) ) ; // must not be finished
QFETCH ( bool , replyFirst ) ;
if ( replyFirst ) {
delete reply ;
delete connection ;
} else {
delete connection ;
delete reply ;
}
}
QTEST_MAIN ( tst_QHttpNetworkConnection )
# include "tst_qhttpnetworkconnection.moc"