|
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" |