1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29
30#include <QtTest/QtTest>
31
32#include <qcoreapplication.h>
33#include <qfile.h>
34#include <qbuffer.h>
35#include "private/qftp_p.h"
36#include <qmap.h>
37#include <time.h>
38#include <stdlib.h>
39#include <QNetworkProxy>
40#include <QNetworkConfiguration>
41#include <qnetworkconfigmanager.h>
42#include <QNetworkSession>
43#include <QtNetwork/private/qnetworksession_p.h>
44#include <QTcpServer>
45#include <QHostInfo>
46#include <QElapsedTimer>
47#include <QTcpSocket>
48
49#include "../../../network-settings.h"
50
51template <class T1, class T2>
52static QByteArray msgComparison(T1 lhs, const char *op, T2 rhs)
53{
54 QString result;
55 QTextStream(&result) << lhs << ' ' << op << ' ' << rhs;
56 return result.toLatin1();
57}
58
59class tst_QFtp : public QObject
60{
61 Q_OBJECT
62
63public:
64 tst_QFtp();
65
66private slots:
67 void initTestCase_data();
68 void initTestCase();
69 void cleanupTestCase();
70 void init();
71 void cleanup();
72 void connectToHost_data();
73 void connectToHost();
74 void connectToUnresponsiveHost();
75 void login_data();
76 void login();
77 void close_data();
78 void close();
79
80 void list_data();
81 void list();
82 void cd_data();
83 void cd();
84 void get_data();
85 void get();
86 void put_data();
87 void put();
88 void mkdir_data();
89 void mkdir();
90 void mkdir2();
91 void rename_data();
92 void rename();
93
94 void commandSequence_data();
95 void commandSequence();
96
97 void abort_data();
98 void abort();
99
100 void bytesAvailable_data();
101 void bytesAvailable();
102
103 void activeMode();
104
105 void proxy_data();
106 void proxy();
107
108 void binaryAscii();
109
110 void doneSignal();
111 void queueMoreCommandsInDoneSlot();
112
113 void qtbug7359Crash();
114
115 void loginURL_data();
116 void loginURL();
117
118protected slots:
119 void stateChanged( int );
120 void listInfo( const QUrlInfo & );
121 void readyRead();
122 void dataTransferProgress(qint64, qint64);
123
124 void commandStarted( int );
125 void commandFinished( int, bool );
126 void done( bool );
127 void activeModeDone( bool );
128 void mkdir2Slot(int id, bool error);
129 void cdUpSlot(bool);
130
131private:
132 QFtp *newFtp();
133 void addCommand( QFtp::Command, int );
134 bool fileExists( const QString &host, quint16 port, const QString &user, const QString &password, const QString &file, const QString &cdDir = QString() );
135 bool dirExists( const QString &host, quint16 port, const QString &user, const QString &password, const QString &cdDir, const QString &dirToCreate );
136
137 void renameInit( const QString &host, const QString &user, const QString &password, const QString &createFile );
138 void renameCleanup( const QString &host, const QString &user, const QString &password, const QString &fileToDelete );
139
140 QFtp *ftp;
141#ifndef QT_NO_BEARERMANAGEMENT
142 QSharedPointer<QNetworkSession> networkSessionExplicit;
143 QSharedPointer<QNetworkSession> networkSessionImplicit;
144#endif
145
146 QList<int> ids; // helper to make sure that all expected signals are emitted
147 int current_id;
148
149 int connectToHost_state;
150 int close_state;
151 int login_state;
152 int cur_state;
153 struct CommandResult
154 {
155 int id;
156 int success;
157 };
158 QMap< QFtp::Command, CommandResult > resultMap;
159 typedef QMap<QFtp::Command,CommandResult>::Iterator ResMapIt;
160
161 int done_success;
162 int commandSequence_success;
163
164 qlonglong bytesAvailable_finishedGet;
165 qlonglong bytesAvailable_finished;
166 qlonglong bytesAvailable_done;
167
168 QList<QUrlInfo> listInfo_i;
169 QByteArray newData_ba;
170 qlonglong bytesTotal;
171 qlonglong bytesDone;
172
173 bool inFileDirExistsFunction;
174
175 QString uniqueExtension;
176 QString rfc3252File;
177};
178
179//#define DUMP_SIGNALS
180
181const int bytesTotal_init = -10;
182const int bytesDone_init = -10;
183
184tst_QFtp::tst_QFtp() :
185 ftp(0)
186{
187}
188
189void tst_QFtp::initTestCase_data()
190{
191 QTest::addColumn<bool>(name: "setProxy");
192 QTest::addColumn<int>(name: "proxyType");
193 QTest::addColumn<bool>(name: "setSession");
194
195 QTest::newRow(dataTag: "WithoutProxy") << false << 0 << false;
196#if QT_CONFIG(socks5)
197 QTest::newRow(dataTag: "WithSocks5Proxy") << true << int(QNetworkProxy::Socks5Proxy) << false;
198#endif
199 //### doesn't work well yet.
200 //QTest::newRow("WithHttpProxy") << true << int(QNetworkProxy::HttpProxy);
201
202#ifndef QT_NO_BEARERMANAGEMENT
203 QTest::newRow(dataTag: "WithoutProxyWithSession") << false << 0 << true;
204#if QT_CONFIG(socks5)
205 QTest::newRow(dataTag: "WithSocks5ProxyAndSession") << true << int(QNetworkProxy::Socks5Proxy) << true;
206#endif
207#endif
208}
209
210void tst_QFtp::initTestCase()
211{
212#if defined(QT_TEST_SERVER)
213 QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::ftpServerName(), 21));
214 QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::ftpProxyServerName(), 2121));
215 QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::socksProxyServerName(), 1080));
216 QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpProxyServerName(), 3128));
217#else
218 if (!QtNetworkSettings::verifyTestNetworkSettings())
219 QSKIP("No network test server available");
220#endif
221#ifndef QT_NO_BEARERMANAGEMENT
222 QNetworkConfigurationManager manager;
223 networkSessionImplicit = QSharedPointer<QNetworkSession>::create(arguments: manager.defaultConfiguration());
224 networkSessionImplicit->open();
225 QVERIFY(networkSessionImplicit->waitForOpened(60000)); //there may be user prompt on 1st connect
226#endif
227 rfc3252File = QFINDTESTDATA("rfc3252.txt");
228 QVERIFY(!rfc3252File.isEmpty());
229}
230
231void tst_QFtp::cleanupTestCase()
232{
233#ifndef QT_NO_BEARERMANAGEMENT
234 networkSessionExplicit.clear();
235 networkSessionImplicit.clear();
236#endif
237}
238
239void tst_QFtp::init()
240{
241 QFETCH_GLOBAL(bool, setProxy);
242 QFETCH_GLOBAL(int, proxyType);
243 QFETCH_GLOBAL(bool, setSession);
244 if (setProxy) {
245#ifndef QT_NO_NETWORKPROXY
246 if (proxyType == QNetworkProxy::Socks5Proxy) {
247 QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1080));
248 } else if (proxyType == QNetworkProxy::HttpProxy) {
249 QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::httpProxyServerName(), 3128));
250 }
251#else // !QT_NO_NETWORKPROXY
252 Q_UNUSED(proxyType);
253 QSKIP("No proxy support");
254#endif // QT_NO_NETWORKPROXY
255 }
256#ifndef QT_NO_BEARERMANAGEMENT
257 if (setSession) {
258 networkSessionExplicit = networkSessionImplicit;
259 if (!networkSessionExplicit->isOpen()) {
260 networkSessionExplicit->open();
261 QVERIFY(networkSessionExplicit->waitForOpened(30000));
262 }
263 } else {
264 networkSessionExplicit.clear();
265 }
266#else
267 Q_UNUSED(setSession);
268#endif
269
270 delete ftp;
271 ftp = 0;
272
273 ids.clear();
274 current_id = 0;
275
276 resultMap.clear();
277 connectToHost_state = -1;
278 close_state = -1;
279 login_state = -1;
280 cur_state = QFtp::Unconnected;
281
282 listInfo_i.clear();
283 newData_ba = QByteArray();
284 bytesTotal = bytesTotal_init;
285 bytesDone = bytesDone_init;
286
287 done_success = -1;
288 commandSequence_success = -1;
289
290 bytesAvailable_finishedGet = 1234567890;
291 bytesAvailable_finished = 1234567890;
292 bytesAvailable_done = 1234567890;
293
294 inFileDirExistsFunction = false;
295
296 uniqueExtension = QString::number((quintptr)this) + QString::number(QRandomGenerator::global()->generate())
297 + QString::number((qulonglong)time(timer: 0));
298}
299
300void tst_QFtp::cleanup()
301{
302 if (ftp) {
303 delete ftp;
304 ftp = 0;
305 }
306 QFETCH_GLOBAL(bool, setProxy);
307 if (setProxy) {
308#ifndef QT_NO_NETWORKPROXY
309 QNetworkProxy::setApplicationProxy(QNetworkProxy::DefaultProxy);
310#else
311 QSKIP("No proxy support");
312#endif
313 }
314
315 delete ftp;
316 ftp = 0;
317#ifndef QT_NO_BEARERMANAGEMENT
318 networkSessionExplicit.clear();
319#endif
320}
321
322void tst_QFtp::connectToHost_data()
323{
324 QTest::addColumn<QString>(name: "host");
325 QTest::addColumn<uint>(name: "port");
326 QTest::addColumn<int>(name: "state");
327
328 QTest::newRow( dataTag: "ok01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << (int)QFtp::Connected;
329 QTest::newRow( dataTag: "error01" ) << QtNetworkSettings::ftpServerName() << (uint)2222 << (int)QFtp::Unconnected;
330 QTest::newRow( dataTag: "error02" ) << QString("foo.bar") << (uint)21 << (int)QFtp::Unconnected;
331}
332
333static QByteArray msgTimedOut(const QString &host, quint16 port = 0)
334{
335 QByteArray result = "Network operation timed out on " + host.toLatin1();
336 if (port) {
337 result += ':';
338 result += QByteArray::number(port);
339 }
340 return result;
341}
342
343void tst_QFtp::connectToHost()
344{
345 QFETCH( QString, host );
346 QFETCH( uint, port );
347
348 ftp = newFtp();
349 addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
350
351 QTestEventLoop::instance().enterLoop( secs: 61 );
352 delete ftp;
353 ftp = 0;
354 if ( QTestEventLoop::instance().timeout() )
355 QFAIL( msgTimedOut(host, port) );
356
357 QTEST( connectToHost_state, "state" );
358
359 ResMapIt it = resultMap.find( akey: QFtp::ConnectToHost );
360 QVERIFY( it != resultMap.end() );
361 QFETCH( int, state );
362 if ( state == QFtp::Connected ) {
363 QCOMPARE( it.value().success, 1 );
364 } else {
365 QCOMPARE( it.value().success , 0 );
366 }
367}
368
369void tst_QFtp::connectToUnresponsiveHost()
370{
371 QFETCH_GLOBAL(bool, setProxy);
372 if (setProxy)
373 QSKIP( "This test takes too long if we test with proxies too");
374
375 QString host = "192.0.2.42"; // IP out of TEST-NET, should be unreachable
376 uint port = 21;
377
378 ftp = newFtp();
379 addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
380
381 qDebug( msg: "About to connect to host that won't reply (this test takes 60 seconds)" );
382 QTestEventLoop::instance().enterLoop( secs: 61 );
383#ifdef Q_OS_WIN
384 /* On Windows, we do not get a timeout, because Winsock is behaving in a strange way:
385 We issue two "WSAConnect()" calls, after the first, as a result we get WSAEWOULDBLOCK,
386 after the second, we get WSAEISCONN, which means that the socket is connected, which cannot be.
387 However, after some seconds we get a socket error saying that the remote host closed the connection,
388 which can neither be. For this test, that would actually enable us to finish before timout, but handling that case
389 (in void QFtpPI::error(QAbstractSocket::SocketError e)) breaks
390 a lot of other stuff in QFtp, so we just expect this test to fail on Windows.
391 */
392 QEXPECT_FAIL("", "timeout not working due to strange Windows socket behaviour (see source file of this test for explanation)", Abort);
393
394#endif
395 QVERIFY2(! QTestEventLoop::instance().timeout(), "Network timeout longer than expected (should have been 60 seconds)");
396
397 QCOMPARE( ftp->state(), QFtp::Unconnected);
398 ResMapIt it = resultMap.find( akey: QFtp::ConnectToHost );
399 QVERIFY( it != resultMap.end() );
400 QCOMPARE( it.value().success, 0 );
401
402 delete ftp;
403 ftp = 0;
404}
405
406void tst_QFtp::login_data()
407{
408 QTest::addColumn<QString>(name: "host");
409 QTest::addColumn<uint>(name: "port");
410 QTest::addColumn<QString>(name: "user");
411 QTest::addColumn<QString>(name: "password");
412 QTest::addColumn<int>(name: "success");
413
414 QTest::newRow( dataTag: "ok01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << 1;
415 QTest::newRow( dataTag: "ok02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftp") << QString("") << 1;
416 QTest::newRow( dataTag: "ok03" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftp") << QString("foo") << 1;
417 QTest::newRow( dataTag: "ok04" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << 1;
418
419 QTest::newRow( dataTag: "error01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("foo") << QString("") << 0;
420 QTest::newRow( dataTag: "error02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("foo") << QString("bar") << 0;
421}
422
423void tst_QFtp::login()
424{
425 QFETCH( QString, host );
426 QFETCH( uint, port );
427 QFETCH( QString, user );
428 QFETCH( QString, password );
429
430 ftp = newFtp();
431 addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
432 addCommand( QFtp::Login, ftp->login( user, password ) );
433
434 QTestEventLoop::instance().enterLoop( secs: 30 );
435 delete ftp;
436 ftp = 0;
437 if ( QTestEventLoop::instance().timeout() )
438 QFAIL( msgTimedOut(host, port) );
439
440 ResMapIt it = resultMap.find( akey: QFtp::Login );
441 QVERIFY( it != resultMap.end() );
442 QTEST( it.value().success, "success" );
443
444 const QFtp::State loginState = static_cast<QFtp::State>(login_state);
445 if ( it.value().success ) {
446 QCOMPARE( loginState, QFtp::LoggedIn );
447 } else {
448 QVERIFY2( loginState != QFtp::LoggedIn, msgComparison(loginState, "!=", QFtp::LoggedIn));
449 }
450}
451
452void tst_QFtp::close_data()
453{
454 QTest::addColumn<QString>(name: "host");
455 QTest::addColumn<uint>(name: "port");
456 QTest::addColumn<QString>(name: "user");
457 QTest::addColumn<QString>(name: "password");
458 QTest::addColumn<bool>(name: "login");
459
460 QTest::newRow( dataTag: "login01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << true;
461 QTest::newRow( dataTag: "login02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftp") << QString() << true;
462 QTest::newRow( dataTag: "login03" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftp") << QString("foo") << true;
463 QTest::newRow( dataTag: "login04" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << true;
464
465 QTest::newRow( dataTag: "no-login01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("") << QString("") << false;
466}
467
468void tst_QFtp::close()
469{
470 QFETCH( QString, host );
471 QFETCH( uint, port );
472 QFETCH( QString, user );
473 QFETCH( QString, password );
474 QFETCH( bool, login );
475
476 ftp = newFtp();
477 addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
478 if ( login )
479 addCommand( QFtp::Login, ftp->login( user, password ) );
480 addCommand( QFtp::Close, ftp->close() );
481
482 QTestEventLoop::instance().enterLoop( secs: 30 );
483 delete ftp;
484 ftp = 0;
485 if ( QTestEventLoop::instance().timeout() )
486 QFAIL( msgTimedOut(host, port) );
487
488 QCOMPARE( close_state, (int)QFtp::Unconnected );
489
490 ResMapIt it = resultMap.find( akey: QFtp::Close );
491 QVERIFY( it != resultMap.end() );
492 QCOMPARE( it.value().success, 1 );
493}
494
495void tst_QFtp::list_data()
496{
497 QTest::addColumn<QString>(name: "host");
498 QTest::addColumn<uint>(name: "port");
499 QTest::addColumn<QString>(name: "user");
500 QTest::addColumn<QString>(name: "password");
501 QTest::addColumn<QString>(name: "dir");
502 QTest::addColumn<int>(name: "success");
503 QTest::addColumn<QStringList>(name: "entryNames"); // ### we should rather use a QList<QUrlInfo> here
504
505 QStringList flukeRoot;
506 flukeRoot << "pub";
507 flukeRoot << "qtest";
508 QStringList flukeQtest;
509 flukeQtest << "bigfile";
510 flukeQtest << "nonASCII";
511 flukeQtest << "rfc3252";
512 flukeQtest << "rfc3252.txt";
513 flukeQtest << "upload";
514
515 QTest::newRow( dataTag: "workDir01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString() << 1 << flukeRoot;
516 QTest::newRow( dataTag: "workDir02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << QString() << 1 << flukeRoot;
517
518 QTest::newRow( dataTag: "relPath01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("qtest") << 1 << flukeQtest;
519 QTest::newRow( dataTag: "relPath02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << QString("qtest") << 1 << flukeQtest;
520
521 QTest::newRow( dataTag: "absPath01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("/qtest") << 1 << flukeQtest;
522 QTest::newRow( dataTag: "absPath02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << QString("/var/ftp/qtest") << 1 << flukeQtest;
523
524 QTest::newRow( dataTag: "nonExist01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("foo") << 1 << QStringList();
525 QTest::newRow( dataTag: "nonExist02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("/foo") << 1 << QStringList();
526 // ### The microsoft server does not seem to work properly at the moment --
527 // I am also not able to open a data connection with other, non-Qt FTP
528 // clients to it.
529 // QTest::newRow( "nonExist03" ) << "ftp.microsoft.com" << (uint)21 << QString() << QString() << QString("/foo") << 0 << QStringList();
530
531 QStringList susePub;
532 susePub << "README.mirror-policy" << "axp" << "i386" << "ia64" << "install" << "noarch" << "pubring.gpg-build.suse.de" << "update" << "x86_64";
533 QTest::newRow( dataTag: "epsvNotSupported" ) << QString("ftp.funet.fi") << (uint)21 << QString::fromLatin1(str: "ftp") << QString::fromLatin1(str: "root@") << QString("/pub/Linux/suse/suse") << 1 << susePub;
534}
535
536void tst_QFtp::list()
537{
538 QFETCH( QString, host );
539 QFETCH( uint, port );
540 QFETCH( QString, user );
541 QFETCH( QString, password );
542 QFETCH( QString, dir );
543
544 ftp = newFtp();
545 addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
546 addCommand( QFtp::Login, ftp->login( user, password ) );
547 addCommand( QFtp::List, ftp->list( dir ) );
548 addCommand( QFtp::Close, ftp->close() );
549
550 QTestEventLoop::instance().enterLoop( secs: 30 );
551 delete ftp;
552 ftp = 0;
553 if ( QTestEventLoop::instance().timeout() )
554 QFAIL( msgTimedOut(host, port) );
555
556 ResMapIt it = resultMap.find( akey: QFtp::List );
557 QVERIFY( it != resultMap.end() );
558 QTEST( it.value().success, "success" );
559 QFETCH( QStringList, entryNames );
560 QCOMPARE( listInfo_i.count(), entryNames.count() );
561 for ( uint i=0; i < (uint) entryNames.count(); i++ ) {
562 QCOMPARE( listInfo_i[i].name(), entryNames[i] );
563 }
564}
565
566void tst_QFtp::cd_data()
567{
568 QTest::addColumn<QString>(name: "host");
569 QTest::addColumn<uint>(name: "port");
570 QTest::addColumn<QString>(name: "user");
571 QTest::addColumn<QString>(name: "password");
572 QTest::addColumn<QString>(name: "dir");
573 QTest::addColumn<int>(name: "success");
574 QTest::addColumn<QStringList>(name: "entryNames"); // ### we should rather use a QList<QUrlInfo> here
575
576 QStringList flukeRoot;
577 flukeRoot << "qtest";
578 QStringList flukeQtest;
579 flukeQtest << "bigfile";
580 flukeQtest << "nonASCII";
581 flukeQtest << "rfc3252";
582 flukeQtest << "rfc3252.txt";
583 flukeQtest << "upload";
584
585 QTest::newRow( dataTag: "relPath01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("qtest") << 1 << flukeQtest;
586 QTest::newRow( dataTag: "relPath02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << QString("qtest") << 1 << flukeQtest;
587
588 QTest::newRow( dataTag: "absPath01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("/qtest") << 1 << flukeQtest;
589 QTest::newRow( dataTag: "absPath02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << QString("/var/ftp/qtest") << 1 << flukeQtest;
590
591 QTest::newRow( dataTag: "nonExist01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("foo") << 0 << QStringList();
592 QTest::newRow( dataTag: "nonExist03" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("/foo") << 0 << QStringList();
593}
594
595void tst_QFtp::cd()
596{
597 QFETCH( QString, host );
598 QFETCH( uint, port );
599 QFETCH( QString, user );
600 QFETCH( QString, password );
601 QFETCH( QString, dir );
602
603 ftp = newFtp();
604 addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
605 addCommand( QFtp::Login, ftp->login( user, password ) );
606 addCommand( QFtp::Cd, ftp->cd( dir ) );
607 addCommand( QFtp::List, ftp->list() );
608 addCommand( QFtp::Close, ftp->close() );
609
610 QTestEventLoop::instance().enterLoop( secs: 30 );
611
612 delete ftp;
613 ftp = 0;
614 if ( QTestEventLoop::instance().timeout() ) {
615 QFAIL( msgTimedOut(host, port) );
616 }
617
618 ResMapIt it = resultMap.find( akey: QFtp::Cd );
619 QVERIFY( it != resultMap.end() );
620 QTEST( it.value().success, "success" );
621 QFETCH( QStringList, entryNames );
622 QCOMPARE( listInfo_i.count(), entryNames.count() );
623 for ( uint i=0; i < (uint) entryNames.count(); i++ ) {
624 QCOMPARE( listInfo_i[i].name(), entryNames[i] );
625 }
626}
627
628void tst_QFtp::get_data()
629{
630 QTest::addColumn<QString>(name: "host");
631 QTest::addColumn<uint>(name: "port");
632 QTest::addColumn<QString>(name: "user");
633 QTest::addColumn<QString>(name: "password");
634 QTest::addColumn<QString>(name: "file");
635 QTest::addColumn<int>(name: "success");
636 QTest::addColumn<QByteArray>(name: "res");
637 QTest::addColumn<bool>(name: "useIODevice");
638
639 // ### move this into external testdata
640 QFile file(rfc3252File);
641 QVERIFY2( file.open( QIODevice::ReadOnly ), qPrintable(file.errorString()) );
642 QByteArray rfc3252 = file.readAll();
643
644 // test the two get() overloads in one routine
645 for ( int i=0; i<2; i++ ) {
646 const QByteArray iB = QByteArray::number(i);
647 QTest::newRow(dataTag: ("relPath01_" + iB).constData()) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString()
648 << "qtest/rfc3252" << 1 << rfc3252 << (bool)(i==1);
649 QTest::newRow(dataTag: ("relPath02_" + iB).constData()) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password")
650 << "qtest/rfc3252" << 1 << rfc3252 << (bool)(i==1);
651
652 QTest::newRow(dataTag: ("absPath01_" + iB).constData()) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString()
653 << "/qtest/rfc3252" << 1 << rfc3252 << (bool)(i==1);
654 QTest::newRow(dataTag: ("absPath02_" + iB).constData()) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password")
655 << "/var/ftp/qtest/rfc3252" << 1 << rfc3252 << (bool)(i==1);
656
657 QTest::newRow(dataTag: ("nonExist01_" + iB).constData()) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString()
658 << QString("foo") << 0 << QByteArray() << (bool)(i==1);
659 QTest::newRow(dataTag: ("nonExist02_" + iB).constData()) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString()
660 << QString("/foo") << 0 << QByteArray() << (bool)(i==1);
661 }
662}
663
664void tst_QFtp::get()
665{
666 // for the overload that takes a QIODevice
667 QByteArray buf_ba;
668 QBuffer buf( &buf_ba );
669
670 QFETCH( QString, host );
671 QFETCH( uint, port );
672 QFETCH( QString, user );
673 QFETCH( QString, password );
674 QFETCH( QString, file );
675 QFETCH( bool, useIODevice );
676
677 ftp = newFtp();
678 addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
679 addCommand( QFtp::Login, ftp->login( user, password ) );
680 if ( useIODevice ) {
681 buf.open( openMode: QIODevice::WriteOnly );
682 addCommand( QFtp::Get, ftp->get( file, dev: &buf ) );
683 } else {
684 addCommand( QFtp::Get, ftp->get( file ) );
685 }
686 addCommand( QFtp::Close, ftp->close() );
687
688 QTestEventLoop::instance().enterLoop( secs: 50 );
689 delete ftp;
690 ftp = 0;
691 if ( QTestEventLoop::instance().timeout() )
692 QFAIL( msgTimedOut(host, port) );
693
694 ResMapIt it = resultMap.find( akey: QFtp::Get );
695 QVERIFY( it != resultMap.end() );
696 QTEST( it.value().success, "success" );
697 if ( useIODevice ) {
698 QTEST( buf_ba, "res" );
699 } else {
700 QTEST( newData_ba, "res" );
701 }
702 QVERIFY2( bytesTotal != bytesTotal_init, msgComparison(bytesTotal, "!=", bytesTotal_init) );
703 if ( bytesTotal != -1 ) {
704 QCOMPARE( bytesDone, bytesTotal );
705 }
706 if ( useIODevice ) {
707 if ( bytesDone != bytesDone_init ) {
708 QCOMPARE( qlonglong(buf_ba.size()), bytesDone );
709 }
710 } else {
711 if ( bytesDone != bytesDone_init ) {
712 QCOMPARE( qlonglong(newData_ba.size()), bytesDone );
713 }
714 }
715}
716
717void tst_QFtp::put_data()
718{
719 QTest::addColumn<QString>(name: "host");
720 QTest::addColumn<uint>(name: "port");
721 QTest::addColumn<QString>(name: "user");
722 QTest::addColumn<QString>(name: "password");
723 QTest::addColumn<QString>(name: "file");
724 QTest::addColumn<QByteArray>(name: "fileData");
725 QTest::addColumn<bool>(name: "useIODevice");
726 QTest::addColumn<int>(name: "success");
727
728 // ### move this into external testdata
729 QFile file(rfc3252File);
730 QVERIFY2( file.open( QIODevice::ReadOnly ), qPrintable(file.errorString()) );
731 QByteArray rfc3252 = file.readAll();
732
733 QByteArray bigData( 10*1024*1024, 0 );
734 bigData.fill( c: 'A' );
735
736 // test the two put() overloads in one routine with a file name containing
737 // U+0x00FC (latin small letter u with diaeresis) for QTBUG-52303, testing UTF-8
738 for ( int i=0; i<2; i++ ) {
739 QTest::newRow(dataTag: ("relPath01_" + QByteArray::number(i)).constData()) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString()
740 << (QLatin1String("qtest/upload/rel01_") + QChar(0xfc) + QLatin1String("%1")) << rfc3252
741 << (bool)(i==1) << 1;
742 /*
743 QTest::newRow( QString("relPath02_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password")
744 << QString("qtest/upload/rel02_%1") << rfc3252
745 << (bool)(i==1) << 1;
746 QTest::newRow( QString("relPath03_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password")
747 << QString("qtest/upload/rel03_%1") << QByteArray()
748 << (bool)(i==1) << 1;
749 QTest::newRow( QString("relPath04_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password")
750 << QString("qtest/upload/rel04_%1") << bigData
751 << (bool)(i==1) << 1;
752
753 QTest::newRow( QString("absPath01_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString()
754 << QString("/qtest/upload/abs01_%1") << rfc3252
755 << (bool)(i==1) << 1;
756 QTest::newRow( QString("absPath02_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password")
757 << QString("/srv/ftp/qtest/upload/abs02_%1") << rfc3252
758 << (bool)(i==1) << 1;
759
760 QTest::newRow( QString("nonExist01_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString()
761 << QString("foo") << QByteArray()
762 << (bool)(i==1) << 0;
763 QTest::newRow( QString("nonExist02_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString()
764 << QString("/foo") << QByteArray()
765 << (bool)(i==1) << 0;
766*/
767 }
768}
769
770void tst_QFtp::put()
771{
772 QFETCH( QString, host );
773 QFETCH( uint, port );
774 QFETCH( QString, user );
775 QFETCH( QString, password );
776 QFETCH( QString, file );
777 QFETCH( QByteArray, fileData );
778 QFETCH( bool, useIODevice );
779
780#if defined(Q_OS_WIN) && !defined(QT_NO_NETWORKPROXY)
781 QFETCH_GLOBAL(bool, setProxy);
782 if (setProxy) {
783 QFETCH_GLOBAL(int, proxyType);
784 if (proxyType == QNetworkProxy::Socks5Proxy)
785 QSKIP("With socks5 the put() test takes too long time on Windows.");
786 }
787#endif // OS_WIN && !QT_NO_NETWORKPROXY
788
789 const int timestep = 50;
790
791 if(file.contains(c: '%'))
792 file = file.arg(a: uniqueExtension);
793
794 // for the overload that takes a QIODevice
795 QBuffer buf_fileData( &fileData );
796 buf_fileData.open( openMode: QIODevice::ReadOnly );
797
798 ResMapIt it;
799 //////////////////////////////////////////////////////////////////
800 // upload the file
801 init();
802 ftp = newFtp();
803 addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
804 addCommand( QFtp::Login, ftp->login( user, password ) );
805 if ( useIODevice )
806 addCommand( QFtp::Put, ftp->put( dev: &buf_fileData, file ) );
807 else
808 addCommand( QFtp::Put, ftp->put( data: fileData, file ) );
809 addCommand( QFtp::Close, ftp->close() );
810
811 for(int time = 0; time <= fileData.length() / 20000; time += timestep) {
812 QTestEventLoop::instance().enterLoop( secs: timestep );
813 if(ftp->currentCommand() == QFtp::None)
814 break;
815 }
816 delete ftp;
817 ftp = 0;
818 if ( QTestEventLoop::instance().timeout() )
819 QFAIL( msgTimedOut(host, port) );
820
821 it = resultMap.find( akey: QFtp::Put );
822 QVERIFY( it != resultMap.end() );
823 QTEST( it.value().success, "success" );
824 if ( !it.value().success ) {
825 QVERIFY( !fileExists( host, port, user, password, file ) );
826 return; // the following tests are only meaningful if the file could be put
827 }
828 QCOMPARE( bytesTotal, qlonglong(fileData.size()) );
829 QCOMPARE( bytesDone, bytesTotal );
830
831 QVERIFY( fileExists( host, port, user, password, file ) );
832
833 //////////////////////////////////////////////////////////////////
834 // fetch file to make sure that it is equal to the uploaded file
835 init();
836 ftp = newFtp();
837 QBuffer buf;
838 buf.open( openMode: QIODevice::WriteOnly );
839 addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
840 addCommand( QFtp::Login, ftp->login( user, password ) );
841 addCommand( QFtp::Get, ftp->get( file, dev: &buf ) );
842 addCommand( QFtp::Close, ftp->close() );
843
844 for(int time = 0; time <= fileData.length() / 20000; time += timestep) {
845 QTestEventLoop::instance().enterLoop( secs: timestep );
846 if(ftp->currentCommand() == QFtp::None)
847 break;
848 }
849 delete ftp;
850 ftp = 0;
851 if ( QTestEventLoop::instance().timeout() )
852 QFAIL( msgTimedOut(host, port) );
853
854 QCOMPARE( done_success, 1 );
855 QTEST( buf.buffer(), "fileData" );
856
857 //////////////////////////////////////////////////////////////////
858 // cleanup (i.e. remove the file) -- this also tests the remove command
859 init();
860 ftp = newFtp();
861 addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
862 addCommand( QFtp::Login, ftp->login( user, password ) );
863 addCommand( QFtp::Remove, ftp->remove( file ) );
864 addCommand( QFtp::Close, ftp->close() );
865
866 QTestEventLoop::instance().enterLoop( secs: timestep );
867 delete ftp;
868 ftp = 0;
869 if ( QTestEventLoop::instance().timeout() )
870 QFAIL( msgTimedOut(host, port) );
871
872 it = resultMap.find( akey: QFtp::Remove );
873 QVERIFY( it != resultMap.end() );
874 QCOMPARE( it.value().success, 1 );
875
876 QVERIFY( !fileExists( host, port, user, password, file ) );
877}
878
879void tst_QFtp::mkdir_data()
880{
881 QTest::addColumn<QString>(name: "host");
882 QTest::addColumn<uint>(name: "port");
883 QTest::addColumn<QString>(name: "user");
884 QTest::addColumn<QString>(name: "password");
885 QTest::addColumn<QString>(name: "cdDir");
886 QTest::addColumn<QString>(name: "dirToCreate");
887 QTest::addColumn<int>(name: "success");
888
889 QTest::newRow( dataTag: "relPath01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString()
890 << "qtest/upload" << QString("rel01_%1") << 1;
891 QTest::newRow( dataTag: "relPath02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password")
892 << "qtest/upload" << QString("rel02_%1") << 1;
893 QTest::newRow( dataTag: "relPath03" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password")
894 << "qtest/upload" << QString("rel03_%1") << 1;
895
896 QTest::newRow( dataTag: "absPath01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString()
897 << "." << QString("/qtest/upload/abs01_%1") << 1;
898 QTest::newRow( dataTag: "absPath02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password")
899 << "." << QString("/var/ftp/qtest/upload/abs02_%1") << 1;
900
901 // QTest::newRow( "nonExist01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("foo") << 0;
902 QTest::newRow( dataTag: "nonExist01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString()
903 << "." << QString("foo") << 0;
904 QTest::newRow( dataTag: "nonExist02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString()
905 << "." << QString("/foo") << 0;
906}
907
908void tst_QFtp::mkdir()
909{
910 QFETCH( QString, host );
911 QFETCH( uint, port );
912 QFETCH( QString, user );
913 QFETCH( QString, password );
914 QFETCH( QString, cdDir );
915 QFETCH( QString, dirToCreate );
916
917 if(dirToCreate.contains(c: '%'))
918 dirToCreate = dirToCreate.arg(a: uniqueExtension);
919
920 //////////////////////////////////////////////////////////////////
921 // create the directory
922 init();
923 ftp = newFtp();
924 addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
925 addCommand( QFtp::Login, ftp->login( user, password ) );
926 addCommand( QFtp::Cd, ftp->cd( dir: cdDir ) );
927 addCommand( QFtp::Mkdir, ftp->mkdir( dir: dirToCreate ) );
928 addCommand( QFtp::Close, ftp->close() );
929
930 QTestEventLoop::instance().enterLoop( secs: 30 );
931 delete ftp;
932 ftp = 0;
933 if ( QTestEventLoop::instance().timeout() )
934 QFAIL( msgTimedOut(host, port) );
935
936 ResMapIt it = resultMap.find( akey: QFtp::Mkdir );
937 QVERIFY( it != resultMap.end() );
938 QTEST( it.value().success, "success" );
939 if ( !it.value().success ) {
940 QVERIFY( !dirExists( host, port, user, password, cdDir, dirToCreate ) );
941 return; // the following tests are only meaningful if the dir could be created
942 }
943 QVERIFY( dirExists( host, port, user, password, cdDir, dirToCreate ) );
944
945 //////////////////////////////////////////////////////////////////
946 // create the directory again (should always fail!)
947 init();
948 ftp = newFtp();
949 addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
950 addCommand( QFtp::Login, ftp->login( user, password ) );
951 addCommand( QFtp::Cd, ftp->cd( dir: cdDir ) );
952 addCommand( QFtp::Mkdir, ftp->mkdir( dir: dirToCreate ) );
953 addCommand( QFtp::Close, ftp->close() );
954
955 QTestEventLoop::instance().enterLoop( secs: 30 );
956 delete ftp;
957 ftp = 0;
958 if ( QTestEventLoop::instance().timeout() )
959 QFAIL( msgTimedOut(host, port) );
960
961 it = resultMap.find( akey: QFtp::Mkdir );
962 QVERIFY( it != resultMap.end() );
963 QCOMPARE( it.value().success, 0 );
964
965 //////////////////////////////////////////////////////////////////
966 // remove the directory
967 init();
968 ftp = newFtp();
969 addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
970 addCommand( QFtp::Login, ftp->login( user, password ) );
971 addCommand( QFtp::Cd, ftp->cd( dir: cdDir ) );
972 addCommand( QFtp::Rmdir, ftp->rmdir( dir: dirToCreate ) );
973 addCommand( QFtp::Close, ftp->close() );
974
975 QTestEventLoop::instance().enterLoop( secs: 30 );
976 delete ftp;
977 ftp = 0;
978 if ( QTestEventLoop::instance().timeout() )
979 QFAIL( msgTimedOut(host, port) );
980
981 it = resultMap.find( akey: QFtp::Rmdir );
982 QVERIFY( it != resultMap.end() );
983 QCOMPARE( it.value().success, 1 );
984
985 QVERIFY( !dirExists( host, port, user, password, cdDir, dirToCreate ) );
986}
987
988void tst_QFtp::mkdir2()
989{
990 ftp = new QFtp;
991 ftp->connectToHost(host: QtNetworkSettings::ftpServerName());
992 ftp->login();
993 current_id = ftp->cd(dir: "kake/test");
994
995 QEventLoop loop;
996 connect(sender: ftp, SIGNAL(done(bool)), receiver: &loop, SLOT(quit()));
997 connect(sender: ftp, SIGNAL(commandFinished(int,bool)), receiver: this, SLOT(mkdir2Slot(int,bool)));
998 QTimer::singleShot(msec: 5000, receiver: &loop, SLOT(quit()));
999
1000 QSignalSpy commandStartedSpy(ftp, SIGNAL(commandStarted(int)));
1001 QSignalSpy commandFinishedSpy(ftp, SIGNAL(commandFinished(int,bool)));
1002
1003 loop.exec();
1004
1005 QCOMPARE(commandStartedSpy.count(), 4); // connect, login, cd, mkdir
1006 QCOMPARE(commandFinishedSpy.count(), 4);
1007
1008 for (int i = 0; i < 4; ++i)
1009 QCOMPARE(commandFinishedSpy.at(i).at(0), commandStartedSpy.at(i).at(0));
1010
1011 QVERIFY(!commandFinishedSpy.at(0).at(1).toBool());
1012 QVERIFY(!commandFinishedSpy.at(1).at(1).toBool());
1013 QVERIFY(commandFinishedSpy.at(2).at(1).toBool());
1014 QVERIFY(commandFinishedSpy.at(3).at(1).toBool());
1015
1016 delete ftp;
1017 ftp = 0;
1018}
1019
1020void tst_QFtp::mkdir2Slot(int id, bool)
1021{
1022 if (id == current_id)
1023 ftp->mkdir(dir: "kake/test");
1024}
1025
1026void tst_QFtp::rename_data()
1027{
1028 QTest::addColumn<QString>(name: "host");
1029 QTest::addColumn<QString>(name: "user");
1030 QTest::addColumn<QString>(name: "password");
1031 QTest::addColumn<QString>(name: "cdDir");
1032 QTest::addColumn<QString>(name: "oldfile");
1033 QTest::addColumn<QString>(name: "newfile");
1034 QTest::addColumn<QString>(name: "createFile");
1035 QTest::addColumn<QString>(name: "renamedFile");
1036 QTest::addColumn<int>(name: "success");
1037
1038 QTest::newRow(dataTag: "relPath01") << QtNetworkSettings::ftpServerName() << QString() << QString()
1039 << "qtest/upload"
1040 << QString("rel_old01_%1") << QString("rel_new01_%1")
1041 << QString("qtest/upload/rel_old01_%1") << QString("qtest/upload/rel_new01_%1")
1042 << 1;
1043 QTest::newRow(dataTag: "relPath02") << QtNetworkSettings::ftpServerName() << QString("ftptest") << "password"
1044 << "qtest/upload"
1045 << QString("rel_old02_%1") << QString("rel_new02_%1")
1046 << QString("qtest/upload/rel_old02_%1") << QString("qtest/upload/rel_new02_%1")
1047 << 1;
1048 QTest::newRow(dataTag: "relPath03") << QtNetworkSettings::ftpServerName() << QString("ftptest") << "password"
1049 << "qtest/upload"
1050 << QString("rel_old03_%1")<< QString("rel_new03_%1")
1051 << QString("qtest/upload/rel_old03_%1") << QString("qtest/upload/rel_new03_%1")
1052 << 1;
1053
1054 QTest::newRow(dataTag: "absPath01") << QtNetworkSettings::ftpServerName() << QString() << QString()
1055 << QString()
1056 << QString("/qtest/upload/abs_old01_%1") << QString("/qtest/upload/abs_new01_%1")
1057 << QString("/qtest/upload/abs_old01_%1") << QString("/qtest/upload/abs_new01_%1")
1058 << 1;
1059 QTest::newRow(dataTag: "absPath02") << QtNetworkSettings::ftpServerName() << QString("ftptest") << "password"
1060 << QString()
1061 << QString("/var/ftp/qtest/upload/abs_old02_%1") << QString("/var/ftp/qtest/upload/abs_new02_%1")
1062 << QString("/var/ftp/qtest/upload/abs_old02_%1") << QString("/var/ftp/qtest/upload/abs_new02_%1")
1063 << 1;
1064
1065 QTest::newRow(dataTag: "nonExist01") << QtNetworkSettings::ftpServerName() << QString() << QString()
1066 << QString()
1067 << QString("foo") << "new_foo"
1068 << QString() << QString()
1069 << 0;
1070 QTest::newRow(dataTag: "nonExist02") << QtNetworkSettings::ftpServerName() << QString() << QString()
1071 << QString()
1072 << QString("/foo") << QString("/new_foo")
1073 << QString() << QString()
1074 << 0;
1075}
1076
1077void tst_QFtp::renameInit( const QString &host, const QString &user, const QString &password, const QString &createFile )
1078{
1079 if ( !createFile.isNull() ) {
1080 // upload the file
1081 init();
1082 ftp = newFtp();
1083 addCommand( QFtp::ConnectToHost, ftp->connectToHost( host ) );
1084 addCommand( QFtp::Login, ftp->login( user, password ) );
1085 addCommand( QFtp::Put, ftp->put( data: QByteArray(), file: createFile ) );
1086 addCommand( QFtp::Close, ftp->close() );
1087
1088 QTestEventLoop::instance().enterLoop( secs: 50 );
1089 delete ftp;
1090 ftp = 0;
1091 if ( QTestEventLoop::instance().timeout() )
1092 QFAIL( msgTimedOut(host) );
1093
1094 ResMapIt it = resultMap.find( akey: QFtp::Put );
1095 QVERIFY( it != resultMap.end() );
1096 QCOMPARE( it.value().success, 1 );
1097
1098 QVERIFY( fileExists( host, 21, user, password, createFile ) );
1099 }
1100}
1101
1102void tst_QFtp::renameCleanup( const QString &host, const QString &user, const QString &password, const QString &fileToDelete )
1103{
1104 if ( !fileToDelete.isNull() ) {
1105 // cleanup (i.e. remove the file)
1106 init();
1107 ftp = newFtp();
1108 addCommand( QFtp::ConnectToHost, ftp->connectToHost( host ) );
1109 addCommand( QFtp::Login, ftp->login( user, password ) );
1110 addCommand( QFtp::Remove, ftp->remove( file: fileToDelete ) );
1111 addCommand( QFtp::Close, ftp->close() );
1112
1113 QTestEventLoop::instance().enterLoop( secs: 30 );
1114 delete ftp;
1115 ftp = 0;
1116 if ( QTestEventLoop::instance().timeout() )
1117 QFAIL( msgTimedOut(host) );
1118
1119 ResMapIt it = resultMap.find( akey: QFtp::Remove );
1120 QVERIFY( it != resultMap.end() );
1121 QCOMPARE( it.value().success, 1 );
1122
1123 QVERIFY( !fileExists( host, 21, user, password, fileToDelete ) );
1124 }
1125}
1126
1127void tst_QFtp::rename()
1128{
1129 QFETCH( QString, host );
1130 QFETCH( QString, user );
1131 QFETCH( QString, password );
1132 QFETCH( QString, cdDir );
1133 QFETCH( QString, oldfile );
1134 QFETCH( QString, newfile );
1135 QFETCH( QString, createFile );
1136 QFETCH( QString, renamedFile );
1137
1138 if(oldfile.contains(c: '%'))
1139 oldfile = oldfile.arg(a: uniqueExtension);
1140 if(newfile.contains(c: '%'))
1141 newfile = newfile.arg(a: uniqueExtension);
1142 if(createFile.contains(c: '%'))
1143 createFile = createFile.arg(a: uniqueExtension);
1144 if(renamedFile.contains(c: '%'))
1145 renamedFile = renamedFile.arg(a: uniqueExtension);
1146
1147 renameInit( host, user, password, createFile );
1148
1149 init();
1150 ftp = newFtp();
1151 addCommand( QFtp::ConnectToHost, ftp->connectToHost( host ) );
1152 addCommand( QFtp::Login, ftp->login( user, password ) );
1153 if ( !cdDir.isNull() )
1154 addCommand( QFtp::Cd, ftp->cd( dir: cdDir ) );
1155 addCommand( QFtp::Rename, ftp->rename( oldname: oldfile, newname: newfile ) );
1156 addCommand( QFtp::Close, ftp->close() );
1157
1158 QTestEventLoop::instance().enterLoop( secs: 30 );
1159 delete ftp;
1160 ftp = 0;
1161 if ( QTestEventLoop::instance().timeout() )
1162 QFAIL( msgTimedOut(host) );
1163
1164 ResMapIt it = resultMap.find( akey: QFtp::Rename );
1165 QVERIFY( it != resultMap.end() );
1166 QTEST( it.value().success, "success" );
1167
1168 if ( it.value().success ) {
1169 QVERIFY( !fileExists( host, 21, user, password, oldfile, cdDir ) );
1170 QVERIFY( fileExists( host, 21, user, password, newfile, cdDir ) );
1171 QVERIFY( fileExists( host, 21, user, password, renamedFile ) );
1172 } else {
1173 QVERIFY( !fileExists( host, 21, user, password, newfile, cdDir ) );
1174 QVERIFY( !fileExists( host, 21, user, password, renamedFile ) );
1175 }
1176
1177 renameCleanup( host, user, password, fileToDelete: renamedFile );
1178}
1179
1180/*
1181 The commandSequence() test does not test any particular function. It rather
1182 tests a sequence of arbitrary commands specified in the test data.
1183*/
1184class FtpCommand
1185{
1186public:
1187 FtpCommand() :
1188 cmd(QFtp::None)
1189 { }
1190
1191 FtpCommand( QFtp::Command command ) :
1192 cmd(command)
1193 { }
1194
1195 FtpCommand( QFtp::Command command, const QStringList &arguments ) :
1196 cmd(command), args(arguments)
1197 { }
1198
1199 FtpCommand( const FtpCommand &c )
1200 { *this = c; }
1201
1202 FtpCommand &operator=( const FtpCommand &c )
1203 {
1204 this->cmd = c.cmd;
1205 this->args = c.args;
1206 return *this;
1207 }
1208
1209 QFtp::Command cmd;
1210 QStringList args;
1211};
1212QDataStream &operator<<( QDataStream &s, const FtpCommand &command )
1213{
1214 s << (int)command.cmd;
1215 s << command.args;
1216 return s;
1217}
1218QDataStream &operator>>( QDataStream &s, FtpCommand &command )
1219{
1220 int tmp;
1221 s >> tmp;
1222 command.cmd = (QFtp::Command)tmp;
1223 s >> command.args;
1224 return s;
1225}
1226Q_DECLARE_METATYPE(QList<FtpCommand>)
1227
1228void tst_QFtp::commandSequence_data()
1229{
1230 // some "constants"
1231 QStringList argConnectToHost01;
1232 argConnectToHost01 << QtNetworkSettings::ftpServerName() << "21";
1233
1234 QStringList argLogin01, argLogin02, argLogin03, argLogin04;
1235 argLogin01 << QString() << QString();
1236 argLogin02 << "ftp" << QString();
1237 argLogin03 << "ftp" << "foo";
1238 argLogin04 << QString("ftptest") << "password";
1239
1240 FtpCommand connectToHost01( QFtp::ConnectToHost, argConnectToHost01 );
1241 FtpCommand login01( QFtp::Login, argLogin01 );
1242 FtpCommand login02( QFtp::Login, argLogin01 );
1243 FtpCommand login03( QFtp::Login, argLogin01 );
1244 FtpCommand login04( QFtp::Login, argLogin01 );
1245 FtpCommand close01( QFtp::Close );
1246
1247 QTest::addColumn<QList<FtpCommand> >(name: "cmds");
1248 QTest::addColumn<int>(name: "success");
1249
1250 // success data
1251 {
1252 QList<FtpCommand> cmds;
1253 cmds << connectToHost01;
1254 QTest::newRow( dataTag: "simple_ok01" ) << cmds << 1;
1255 }
1256 {
1257 QList<FtpCommand> cmds;
1258 cmds << connectToHost01;
1259 cmds << login01;
1260 QTest::newRow( dataTag: "simple_ok02" ) << cmds << 1;
1261 }
1262 {
1263 QList<FtpCommand> cmds;
1264 cmds << connectToHost01;
1265 cmds << login01;
1266 cmds << close01;
1267 QTest::newRow( dataTag: "simple_ok03" ) << cmds << 1;
1268 }
1269 {
1270 QList<FtpCommand> cmds;
1271 cmds << connectToHost01;
1272 cmds << close01;
1273 QTest::newRow( dataTag: "simple_ok04" ) << cmds << 1;
1274 }
1275 {
1276 QList<FtpCommand> cmds;
1277 cmds << connectToHost01;
1278 cmds << login01;
1279 cmds << close01;
1280 cmds << connectToHost01;
1281 cmds << login02;
1282 cmds << close01;
1283 QTest::newRow( dataTag: "connect_twice" ) << cmds << 1;
1284 }
1285
1286 // error data
1287 {
1288 QList<FtpCommand> cmds;
1289 cmds << close01;
1290 QTest::newRow( dataTag: "error01" ) << cmds << 0;
1291 }
1292 {
1293 QList<FtpCommand> cmds;
1294 cmds << login01;
1295 QTest::newRow( dataTag: "error02" ) << cmds << 0;
1296 }
1297 {
1298 QList<FtpCommand> cmds;
1299 cmds << login01;
1300 cmds << close01;
1301 QTest::newRow( dataTag: "error03" ) << cmds << 0;
1302 }
1303 {
1304 QList<FtpCommand> cmds;
1305 cmds << connectToHost01;
1306 cmds << login01;
1307 cmds << close01;
1308 cmds << login01;
1309 QTest::newRow( dataTag: "error04" ) << cmds << 0;
1310 }
1311}
1312
1313void tst_QFtp::commandSequence()
1314{
1315 QFETCH( QList<FtpCommand>, cmds );
1316
1317 ftp = newFtp();
1318 QString host;
1319 quint16 port = 0;
1320 QList<FtpCommand>::iterator it;
1321 for ( it = cmds.begin(); it != cmds.end(); ++it ) {
1322 switch ( (*it).cmd ) {
1323 case QFtp::ConnectToHost:
1324 {
1325 QCOMPARE( (*it).args.count(), 2 );
1326 bool portOk;
1327 port = (*it).args[1].toUShort( ok: &portOk );
1328 QVERIFY( portOk );
1329 host = (*it).args[0];
1330 ids << ftp->connectToHost( host, port );
1331 }
1332 break;
1333 case QFtp::Login:
1334 QCOMPARE( (*it).args.count(), 2 );
1335 ids << ftp->login( user: (*it).args[0], password: (*it).args[1] );
1336 break;
1337 case QFtp::Close:
1338 QCOMPARE( (*it).args.count(), 0 );
1339 ids << ftp->close();
1340 break;
1341 default:
1342 QFAIL( "Error in test: unexpected enum value" );
1343 break;
1344 }
1345 }
1346
1347 QTestEventLoop::instance().enterLoop( secs: 30 );
1348 delete ftp;
1349 ftp = 0;
1350 if ( QTestEventLoop::instance().timeout() )
1351 QFAIL( msgTimedOut(host) );
1352
1353 QTEST( commandSequence_success, "success" );
1354}
1355
1356void tst_QFtp::abort_data()
1357{
1358 QTest::addColumn<QString>(name: "host");
1359 QTest::addColumn<uint>(name: "port");
1360 QTest::addColumn<QString>(name: "file");
1361 QTest::addColumn<QByteArray>(name: "uploadData");
1362
1363 QTest::newRow( dataTag: "get_fluke01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("qtest/bigfile") << QByteArray();
1364 QTest::newRow( dataTag: "get_fluke02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("qtest/rfc3252") << QByteArray();
1365
1366 // Qt/CE test environment has too little memory for this test
1367 QByteArray bigData( 10*1024*1024, 0 );
1368 bigData.fill( c: 'B' );
1369 QTest::newRow( dataTag: "put_fluke01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("qtest/upload/abort_put") << bigData;
1370}
1371
1372void tst_QFtp::abort()
1373{
1374 QSKIP("This test takes too long.");
1375 // In case you wonder where the abort() actually happens, look into
1376 // tst_QFtp::dataTransferProgress
1377 //
1378 QFETCH( QString, host );
1379 QFETCH( uint, port );
1380 QFETCH( QString, file );
1381 QFETCH( QByteArray, uploadData );
1382
1383 QFtp::Command cmd;
1384 if ( uploadData.size() == 0 )
1385 cmd = QFtp::Get;
1386 else
1387 cmd = QFtp::Put;
1388
1389 ftp = newFtp();
1390 addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
1391 addCommand( QFtp::Login, ftp->login() );
1392 if ( cmd == QFtp::Get )
1393 addCommand( cmd, ftp->get( file ) );
1394 else
1395 addCommand( cmd, ftp->put( data: uploadData, file ) );
1396 addCommand( QFtp::Close, ftp->close() );
1397
1398 for(int time = 0; time <= uploadData.length() / 30000; time += 30) {
1399 QTestEventLoop::instance().enterLoop( secs: 50 );
1400 if(ftp->currentCommand() == QFtp::None)
1401 break;
1402 }
1403 delete ftp;
1404 ftp = 0;
1405 if ( QTestEventLoop::instance().timeout() )
1406 QFAIL( msgTimedOut(host, port) );
1407
1408 ResMapIt it = resultMap.find( akey: cmd );
1409 QVERIFY( it != resultMap.end() );
1410 // ### how to test the abort?
1411 if ( it.value().success ) {
1412 // The FTP server on fluke is sadly returning a success, even when
1413 // the operation was aborted. So we have to use some heuristics.
1414 if ( host == QtNetworkSettings::ftpServerName() ) {
1415 if ( cmd == QFtp::Get ) {
1416 QVERIFY2(bytesDone <= bytesTotal, msgComparison(bytesDone, "<=", bytesTotal));
1417 } else {
1418 // put commands should always be aborted, since we use really
1419 // big data
1420 QVERIFY2( bytesDone != bytesTotal, msgComparison(bytesDone, "!=", bytesTotal) );
1421 }
1422 } else {
1423 // this could be tested by verifying that no more progress signals are emitted
1424 QVERIFY2(bytesDone <= bytesTotal, msgComparison(bytesDone, "<=", bytesTotal));
1425 }
1426 } else {
1427 QVERIFY2( bytesDone != bytesTotal, msgComparison(bytesDone, "!=", bytesTotal) );
1428 }
1429
1430 if ( cmd == QFtp::Put ) {
1431 //////////////////////////////////////
1432 // cleanup (i.e. remove the file)
1433 init();
1434 ftp = newFtp();
1435 addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
1436 addCommand( QFtp::Login, ftp->login() );
1437 addCommand( QFtp::Remove, ftp->remove( file ) );
1438 addCommand( QFtp::Close, ftp->close() );
1439
1440 QTestEventLoop::instance().enterLoop( secs: 30 );
1441 delete ftp;
1442 ftp = 0;
1443 if ( QTestEventLoop::instance().timeout() )
1444 QFAIL( msgTimedOut(host, port) );
1445
1446 it = resultMap.find( akey: QFtp::Remove );
1447 QVERIFY( it != resultMap.end() );
1448 QCOMPARE( it.value().success, 1 );
1449 }
1450}
1451
1452void tst_QFtp::bytesAvailable_data()
1453{
1454 QTest::addColumn<QString>(name: "host");
1455 QTest::addColumn<QString>(name: "file");
1456 QTest::addColumn<int>(name: "type");
1457 QTest::addColumn<qlonglong>(name: "bytesAvailFinishedGet");
1458 QTest::addColumn<qlonglong>(name: "bytesAvailFinished");
1459 QTest::addColumn<qlonglong>(name: "bytesAvailDone");
1460
1461 QTest::newRow( dataTag: "fluke01" ) << QtNetworkSettings::ftpServerName() << QString("qtest/bigfile") << 0 << (qlonglong)519240 << (qlonglong)519240 << (qlonglong)519240;
1462 QTest::newRow( dataTag: "fluke02" ) << QtNetworkSettings::ftpServerName() << QString("qtest/rfc3252") << 0 << (qlonglong)25962 << (qlonglong)25962 << (qlonglong)25962;
1463
1464 QTest::newRow( dataTag: "fluke03" ) << QtNetworkSettings::ftpServerName() << QString("qtest/bigfile") << 1 << (qlonglong)519240 << (qlonglong)0 << (qlonglong)0;
1465 QTest::newRow( dataTag: "fluke04" ) << QtNetworkSettings::ftpServerName() << QString("qtest/rfc3252") << 1 << (qlonglong)25962 << (qlonglong)0 << (qlonglong)0;
1466}
1467
1468void tst_QFtp::bytesAvailable()
1469{
1470 QFETCH( QString, host );
1471 QFETCH( QString, file );
1472 QFETCH( int, type );
1473
1474 ftp = newFtp();
1475 addCommand( QFtp::ConnectToHost, ftp->connectToHost( host ) );
1476 addCommand( QFtp::Login, ftp->login() );
1477 addCommand( QFtp::Get, ftp->get( file ) );
1478 if ( type != 0 )
1479 addCommand( QFtp::Close, ftp->close() );
1480
1481 QTestEventLoop::instance().enterLoop( secs: 40 );
1482 if ( QTestEventLoop::instance().timeout() )
1483 QFAIL( msgTimedOut(host) );
1484
1485 ResMapIt it = resultMap.find( akey: QFtp::Get );
1486 QVERIFY( it != resultMap.end() );
1487 QVERIFY( it.value().success );
1488
1489 QFETCH(qlonglong, bytesAvailFinishedGet);
1490 QCOMPARE(bytesAvailable_finishedGet, bytesAvailFinishedGet);
1491
1492 QFETCH(qlonglong, bytesAvailFinished);
1493 QCOMPARE(bytesAvailable_finished, bytesAvailFinished);
1494
1495 QFETCH(qlonglong, bytesAvailDone);
1496 QCOMPARE(bytesAvailable_done, bytesAvailDone);
1497
1498 ftp->readAll();
1499 QCOMPARE( ftp->bytesAvailable(), 0 );
1500 delete ftp;
1501 ftp = 0;
1502}
1503
1504void tst_QFtp::activeMode()
1505{
1506 QFile file("tst_QFtp_activeMode_inittab");
1507 file.open(flags: QIODevice::ReadWrite);
1508 QFtp ftp;
1509 ftp.setTransferMode(QFtp::Active);
1510 ftp.connectToHost(host: QtNetworkSettings::ftpServerName(), port: 21);
1511 ftp.login();
1512 ftp.list();
1513 ftp.get(file: "/qtest/rfc3252.txt", dev: &file);
1514 connect(asender: &ftp, SIGNAL(done(bool)), SLOT(activeModeDone(bool)));
1515 QTestEventLoop::instance().enterLoop(secs: 900);
1516 QFile::remove(fileName: "tst_QFtp_activeMode_inittab");
1517 QCOMPARE(done_success, 1);
1518
1519}
1520
1521void tst_QFtp::activeModeDone(bool error)
1522{
1523 done_success = error ? -1 : 1;
1524 QTestEventLoop::instance().exitLoop();
1525}
1526
1527void tst_QFtp::proxy_data()
1528{
1529 QTest::addColumn<QString>(name: "host");
1530 QTest::addColumn<uint>(name: "port");
1531 QTest::addColumn<QString>(name: "user");
1532 QTest::addColumn<QString>(name: "password");
1533 QTest::addColumn<QString>(name: "dir");
1534 QTest::addColumn<int>(name: "success");
1535 QTest::addColumn<QStringList>(name: "entryNames"); // ### we should rather use a QList<QUrlInfo> here
1536
1537 QStringList flukeRoot;
1538 flukeRoot << "qtest";
1539 QStringList flukeQtest;
1540 flukeQtest << "bigfile";
1541 flukeQtest << "nonASCII";
1542 flukeQtest << "rfc3252";
1543 flukeQtest << "rfc3252.txt";
1544 flukeQtest << "upload";
1545
1546 QTest::newRow( dataTag: "proxy_relPath01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("qtest") << 1 << flukeQtest;
1547 QTest::newRow( dataTag: "proxy_relPath02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << QString("qtest") << 1 << flukeQtest;
1548
1549 QTest::newRow( dataTag: "proxy_absPath01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("/qtest") << 1 << flukeQtest;
1550 QTest::newRow( dataTag: "proxy_absPath02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << QString("/var/ftp/qtest") << 1 << flukeQtest;
1551
1552 QTest::newRow( dataTag: "proxy_nonExist01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("foo") << 0 << QStringList();
1553 QTest::newRow( dataTag: "proxy_nonExist03" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("/foo") << 0 << QStringList();
1554}
1555
1556void tst_QFtp::proxy()
1557{
1558 QFETCH( QString, host );
1559 QFETCH( uint, port );
1560 QFETCH( QString, user );
1561 QFETCH( QString, password );
1562 QFETCH( QString, dir );
1563
1564 ftp = newFtp();
1565 addCommand( QFtp::SetProxy, ftp->setProxy( host: QtNetworkSettings::ftpProxyServerName(), port: 2121 ) );
1566 addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
1567 addCommand( QFtp::Login, ftp->login( user, password ) );
1568 addCommand( QFtp::Cd, ftp->cd( dir ) );
1569 addCommand( QFtp::List, ftp->list() );
1570
1571 QTestEventLoop::instance().enterLoop( secs: 50 );
1572
1573 delete ftp;
1574 ftp = 0;
1575 if ( QTestEventLoop::instance().timeout() ) {
1576 QFAIL( msgTimedOut(host, port) );
1577 }
1578
1579 ResMapIt it = resultMap.find( akey: QFtp::Cd );
1580 QVERIFY( it != resultMap.end() );
1581 QFETCH( int, success );
1582 QCOMPARE( it.value().success, success );
1583 QFETCH( QStringList, entryNames );
1584 QCOMPARE( listInfo_i.count(), entryNames.count() );
1585 for ( uint i=0; i < (uint) entryNames.count(); i++ ) {
1586 QCOMPARE( listInfo_i[i].name(), entryNames[i] );
1587 }
1588}
1589
1590void tst_QFtp::binaryAscii()
1591{
1592 QString file = "asciifile%1.txt";
1593
1594 if(file.contains(c: '%'))
1595 file = file.arg(a: uniqueExtension);
1596
1597 QByteArray putData = "a line of text\r\n";
1598
1599 init();
1600 ftp = newFtp();
1601 addCommand(QFtp::ConnectToHost, ftp->connectToHost(host: QtNetworkSettings::ftpServerName(), port: 21));
1602 addCommand(QFtp::Login, ftp->login(user: "ftptest", password: "password"));
1603 addCommand(QFtp::Cd, ftp->cd(dir: "qtest/upload"));
1604 addCommand(QFtp::Put, ftp->put(data: putData, file, type: QFtp::Ascii));
1605 addCommand(QFtp::Close, ftp->close());
1606
1607 QTestEventLoop::instance().enterLoop( secs: 30 );
1608 delete ftp;
1609 ftp = 0;
1610 if ( QTestEventLoop::instance().timeout() )
1611 QFAIL( msgTimedOut(QtNetworkSettings::ftpServerName()) );
1612
1613 ResMapIt it = resultMap.find(akey: QFtp::Put);
1614 QVERIFY(it != resultMap.end());
1615 QVERIFY(it.value().success);
1616
1617 QByteArray getData;
1618 QBuffer getBuf(&getData);
1619 getBuf.open(openMode: QBuffer::WriteOnly);
1620
1621 init();
1622 ftp = newFtp();
1623 addCommand(QFtp::ConnectToHost, ftp->connectToHost(host: QtNetworkSettings::ftpServerName(), port: 21));
1624 addCommand(QFtp::Login, ftp->login(user: "ftptest", password: "password"));
1625 addCommand(QFtp::Cd, ftp->cd(dir: "qtest/upload"));
1626 addCommand(QFtp::Get, ftp->get(file, dev: &getBuf, type: QFtp::Binary));
1627 addCommand(QFtp::Close, ftp->close());
1628
1629 QTestEventLoop::instance().enterLoop( secs: 30 );
1630 delete ftp;
1631 ftp = 0;
1632 if ( QTestEventLoop::instance().timeout() )
1633 QFAIL( msgTimedOut(QtNetworkSettings::ftpServerName()) );
1634
1635 ResMapIt it2 = resultMap.find(akey: QFtp::Get);
1636 QVERIFY(it2 != resultMap.end());
1637 QVERIFY(it2.value().success);
1638 // most modern ftp servers leave the file as it is by default
1639 // (and do not remove the windows line ending), the -1 below could be
1640 // deleted in the future
1641 QCOMPARE(getData.size(), putData.size() - 1);
1642 //////////////////////////////////////////////////////////////////
1643 // cleanup (i.e. remove the file) -- this also tests the remove command
1644 init();
1645 ftp = newFtp();
1646 addCommand(QFtp::ConnectToHost, ftp->connectToHost(host: QtNetworkSettings::ftpServerName(), port: 21));
1647 addCommand(QFtp::Login, ftp->login(user: "ftptest", password: "password"));
1648 addCommand(QFtp::Cd, ftp->cd(dir: "qtest/upload"));
1649 addCommand(QFtp::Remove, ftp->remove(file));
1650 addCommand(QFtp::Close, ftp->close());
1651
1652 QTestEventLoop::instance().enterLoop( secs: 30 );
1653 delete ftp;
1654 ftp = 0;
1655 if ( QTestEventLoop::instance().timeout() )
1656 QFAIL( msgTimedOut(QtNetworkSettings::ftpServerName()) );
1657
1658 it = resultMap.find( akey: QFtp::Remove );
1659 QVERIFY( it != resultMap.end() );
1660 QCOMPARE( it.value().success, 1 );
1661
1662 QVERIFY(!fileExists(QtNetworkSettings::ftpServerName(), 21, "ftptest", "password", file));
1663}
1664
1665
1666// test QFtp::currentId() and QFtp::currentCommand()
1667#define CURRENTCOMMAND_TEST \
1668{ \
1669 ResMapIt it; \
1670 for ( it = resultMap.begin(); it != resultMap.end(); ++it ) { \
1671 if ( it.value().id == ftp->currentId() ) { \
1672 QVERIFY( it.key() == ftp->currentCommand() ); \
1673 } \
1674} \
1675}
1676
1677void tst_QFtp::commandStarted( int id )
1678{
1679#if defined( DUMP_SIGNALS )
1680 qDebug( "%d:commandStarted( %d )", ftp->currentId(), id );
1681#endif
1682 // make sure that the commandStarted and commandFinished are nested correctly
1683 QCOMPARE( current_id, 0 );
1684 current_id = id;
1685
1686 QVERIFY( !ids.isEmpty() );
1687 QCOMPARE( ids.first(), id );
1688 if ( ids.count() > 1 ) {
1689 QVERIFY( ftp->hasPendingCommands() );
1690 } else {
1691 QVERIFY( !ftp->hasPendingCommands() );
1692 }
1693
1694 QVERIFY( ftp->currentId() == id );
1695 QCOMPARE( cur_state, int(ftp->state()) );
1696 CURRENTCOMMAND_TEST;
1697
1698 QCOMPARE( ftp->error(), QFtp::NoError );
1699}
1700
1701void tst_QFtp::commandFinished( int id, bool error )
1702{
1703#if defined( DUMP_SIGNALS )
1704 qDebug( "%d:commandFinished( %d, %d ) -- errorString: '%s'",
1705 ftp->currentId(), id, (int)error, ftp->errorString().toLatin1().constData() );
1706#endif
1707 if ( ftp->currentCommand() == QFtp::Get ) {
1708 bytesAvailable_finishedGet = ftp->bytesAvailable();
1709 }
1710 bytesAvailable_finished = ftp->bytesAvailable();
1711
1712 // make sure that the commandStarted and commandFinished are nested correctly
1713 QCOMPARE( current_id, id );
1714 current_id = 0;
1715
1716 QVERIFY( !ids.isEmpty() );
1717 QCOMPARE( ids.first(), id );
1718 if ( !error && ids.count() > 1) {
1719 QVERIFY( ftp->hasPendingCommands() );
1720 } else {
1721 QVERIFY( !ftp->hasPendingCommands() );
1722 }
1723 if ( error ) {
1724 QVERIFY2( ftp->error() != QFtp::NoError, msgComparison(ftp->error(), "!=", QFtp::NoError) );
1725 ids.clear();
1726 } else {
1727 QCOMPARE( ftp->error(), QFtp::NoError );
1728 ids.pop_front();
1729 }
1730
1731 QCOMPARE( ftp->currentId(), id );
1732 QCOMPARE( cur_state, int(ftp->state()) );
1733 CURRENTCOMMAND_TEST;
1734
1735 if ( QTest::currentTestFunction() != QLatin1String("commandSequence") ) {
1736 ResMapIt it = resultMap.find( akey: ftp->currentCommand() );
1737 QVERIFY( it != resultMap.end() );
1738 QCOMPARE( it.value().success, -1 );
1739 if ( error )
1740 it.value().success = 0;
1741 else
1742 it.value().success = 1;
1743 }
1744}
1745
1746void tst_QFtp::done( bool error )
1747{
1748#if defined( DUMP_SIGNALS )
1749 qDebug( "%d:done( %d )", ftp->currentId(), (int)error );
1750#endif
1751 bytesAvailable_done = ftp->bytesAvailable();
1752
1753 QCOMPARE( ftp->currentId(), 0 );
1754 QVERIFY( current_id == 0 );
1755 QVERIFY( ids.isEmpty() );
1756 QVERIFY( cur_state == ftp->state() );
1757 QVERIFY( !ftp->hasPendingCommands() );
1758
1759 if ( QTest::currentTestFunction() == QLatin1String("commandSequence") ) {
1760 QCOMPARE( commandSequence_success, -1 );
1761 if ( error )
1762 commandSequence_success = 0;
1763 else
1764 commandSequence_success = 1;
1765 }
1766 QCOMPARE( done_success, -1 );
1767 if ( error ) {
1768 QVERIFY2( ftp->error() != QFtp::NoError, msgComparison(ftp->error(), "!=", QFtp::NoError) );
1769 done_success = 0;
1770 } else {
1771 QCOMPARE( ftp->error(), QFtp::NoError );
1772 done_success = 1;
1773 }
1774 QTestEventLoop::instance().exitLoop();
1775}
1776
1777void tst_QFtp::stateChanged( int state )
1778{
1779#if defined( DUMP_SIGNALS )
1780 qDebug( "%d: stateChanged( %d )", ftp->currentId(), state );
1781#endif
1782 QCOMPARE( ftp->currentId(), current_id );
1783 CURRENTCOMMAND_TEST;
1784
1785 QVERIFY2( state != cur_state, msgComparison(state, "!=", cur_state) );
1786 QCOMPARE( state, (int)ftp->state() );
1787 if ( state != QFtp::Unconnected ) {
1788 // make sure that the states are always emitted in the right order (for
1789 // this, we assume an ordering on the enum values, which they have at
1790 // the moment)
1791 QVERIFY2( cur_state < state, msgComparison(cur_state, "<", state) );
1792
1793 // make sure that state changes are only emitted in response to certain
1794 // commands
1795 switch ( state ) {
1796 case QFtp::HostLookup:
1797 case QFtp::Connecting:
1798 case QFtp::Connected:
1799 QCOMPARE( (int)ftp->currentCommand(), (int)QFtp::ConnectToHost );
1800 break;
1801 case QFtp::LoggedIn:
1802 QCOMPARE( (int)ftp->currentCommand(), (int)QFtp::Login );
1803 break;
1804 case QFtp::Closing:
1805 QCOMPARE( (int)ftp->currentCommand(), (int)QFtp::Close );
1806 break;
1807 default:
1808 QWARN( QString("Unexpected state '%1'").arg(state).toLatin1().constData() );
1809 break;
1810 }
1811 }
1812 cur_state = state;
1813
1814 if ( QTest::currentTestFunction() == QLatin1String("connectToHost") ) {
1815 switch ( state ) {
1816 case QFtp::HostLookup:
1817 case QFtp::Connecting:
1818 case QFtp::LoggedIn:
1819 case QFtp::Closing:
1820 // ignore
1821 break;
1822 case QFtp::Connected:
1823 case QFtp::Unconnected:
1824 QVERIFY( connectToHost_state == -1 );
1825 connectToHost_state = state;
1826 break;
1827 default:
1828 QWARN( QString("Unknown state '%1'").arg(state).toLatin1().constData() );
1829 break;
1830 }
1831 } else if ( QTest::currentTestFunction() == QLatin1String("close") ) {
1832 ResMapIt it = resultMap.find( akey: QFtp::Close );
1833 if ( it!=resultMap.end() && ftp->currentId()==it.value().id ) {
1834 if ( state == QFtp::Closing ) {
1835 QCOMPARE( close_state, -1 );
1836 close_state = state;
1837 } else if ( state == QFtp::Unconnected ) {
1838 QCOMPARE(close_state, int(QFtp::Closing) );
1839 close_state = state;
1840 }
1841 }
1842 } else if ( QTest::currentTestFunction() == QLatin1String("login") ) {
1843 ResMapIt it = resultMap.find( akey: QFtp::Login );
1844 if ( it!=resultMap.end() && ftp->currentId()==it.value().id ) {
1845 if ( state == QFtp::LoggedIn ) {
1846 QCOMPARE( login_state, -1 );
1847 login_state = state;
1848 }
1849 }
1850 }
1851}
1852
1853void tst_QFtp::listInfo( const QUrlInfo &i )
1854{
1855#if defined( DUMP_SIGNALS )
1856 qDebug( "%d: listInfo( %s )", ftp->currentId(), i.name().toLatin1().constData() );
1857#endif
1858 QCOMPARE( ftp->currentId(), current_id );
1859 if ( ids.count() > 1 ) {
1860 QVERIFY( ftp->hasPendingCommands() );
1861 } else {
1862 QVERIFY( !ftp->hasPendingCommands() );
1863 }
1864 QCOMPARE( cur_state, int(ftp->state()) );
1865 CURRENTCOMMAND_TEST;
1866
1867 if ( QTest::currentTestFunction()==QLatin1String("list") || QTest::currentTestFunction()==QLatin1String("cd") || QTest::currentTestFunction()==QLatin1String("proxy") || inFileDirExistsFunction ) {
1868 ResMapIt it = resultMap.find( akey: QFtp::List );
1869 QVERIFY( it != resultMap.end() );
1870 QCOMPARE( ftp->currentId(), it.value().id );
1871 listInfo_i << i;
1872 }
1873}
1874
1875void tst_QFtp::readyRead()
1876{
1877#if defined( DUMP_SIGNALS )
1878 qDebug( "%d: readyRead(), bytesAvailable == %lu", ftp->currentId(), ftp->bytesAvailable() );
1879#endif
1880 QCOMPARE( ftp->currentId(), current_id );
1881 if ( ids.count() > 1 ) {
1882 QVERIFY( ftp->hasPendingCommands() );
1883 } else {
1884 QVERIFY( !ftp->hasPendingCommands() );
1885 }
1886 QVERIFY( cur_state == ftp->state() );
1887 CURRENTCOMMAND_TEST;
1888
1889 if ( QTest::currentTestFunction() != QLatin1String("bytesAvailable") ) {
1890 int oldSize = newData_ba.size();
1891 qlonglong bytesAvail = ftp->bytesAvailable();
1892 QByteArray ba = ftp->readAll();
1893 QCOMPARE( ba.size(), (int) bytesAvail );
1894 newData_ba.resize( size: oldSize + ba.size() );
1895 memcpy( dest: newData_ba.data()+oldSize, src: ba.data(), n: ba.size() );
1896
1897 if ( bytesTotal != -1 ) {
1898 QVERIFY2( (int)newData_ba.size() <= bytesTotal, msgComparison(newData_ba.size(), "<=", bytesTotal) );
1899 }
1900 QCOMPARE( qlonglong(newData_ba.size()), bytesDone );
1901 }
1902}
1903
1904void tst_QFtp::dataTransferProgress( qint64 done, qint64 total )
1905{
1906#if defined( DUMP_SIGNALS )
1907 qDebug( "%d: dataTransferProgress( %lli, %lli )", ftp->currentId(), done, total );
1908#endif
1909 QCOMPARE( ftp->currentId(), current_id );
1910 if ( ids.count() > 1 ) {
1911 QVERIFY( ftp->hasPendingCommands() );
1912 } else {
1913 QVERIFY( !ftp->hasPendingCommands() );
1914 }
1915 QCOMPARE( cur_state, int(ftp->state()) );
1916 CURRENTCOMMAND_TEST;
1917
1918 if ( bytesTotal == bytesTotal_init ) {
1919 bytesTotal = total;
1920 } else {
1921 QCOMPARE( bytesTotal, total );
1922 }
1923
1924 QVERIFY2( bytesTotal != bytesTotal_init, msgComparison(bytesTotal, "!=", bytesTotal_init) );
1925 QVERIFY2( bytesDone <= done, msgComparison(bytesDone, "<=", done) );
1926 bytesDone = done;
1927 if ( bytesTotal != -1 ) {
1928 QVERIFY2( bytesDone <= bytesTotal, msgComparison(bytesDone, "<=", bytesTotal) );
1929 }
1930
1931 if ( QTest::currentTestFunction() == QLatin1String("abort") ) {
1932 // ### it would be nice if we could specify in our testdata when to do
1933 // the abort
1934 if ( done >= total/100000 ) {
1935 if ( ids.count() != 1 ) {
1936 // do abort only once
1937 int tmpId = ids.first();
1938 ids.clear();
1939 ids << tmpId;
1940 ftp->abort();
1941 }
1942 }
1943 }
1944}
1945
1946
1947QFtp *tst_QFtp::newFtp()
1948{
1949 QFtp *nFtp = new QFtp( this );
1950#ifndef QT_NO_BEARERMANAGEMENT
1951 if (networkSessionExplicit) {
1952 nFtp->setProperty(name: "_q_networksession", value: QVariant::fromValue(value: networkSessionExplicit));
1953 }
1954#endif
1955 connect( asender: nFtp, SIGNAL(commandStarted(int)),
1956 SLOT(commandStarted(int)) );
1957 connect( asender: nFtp, SIGNAL(commandFinished(int,bool)),
1958 SLOT(commandFinished(int,bool)) );
1959 connect( asender: nFtp, SIGNAL(done(bool)),
1960 SLOT(done(bool)) );
1961 connect( asender: nFtp, SIGNAL(stateChanged(int)),
1962 SLOT(stateChanged(int)) );
1963 connect( asender: nFtp, SIGNAL(listInfo(QUrlInfo)),
1964 SLOT(listInfo(QUrlInfo)) );
1965 connect( asender: nFtp, SIGNAL(readyRead()),
1966 SLOT(readyRead()) );
1967 connect( asender: nFtp, SIGNAL(dataTransferProgress(qint64,qint64)),
1968 SLOT(dataTransferProgress(qint64,qint64)) );
1969
1970 return nFtp;
1971}
1972
1973void tst_QFtp::addCommand( QFtp::Command cmd, int id )
1974{
1975 ids << id;
1976 CommandResult res;
1977 res.id = id;
1978 res.success = -1;
1979 resultMap[ cmd ] = res;
1980}
1981
1982bool tst_QFtp::fileExists( const QString &host, quint16 port, const QString &user, const QString &password, const QString &file, const QString &cdDir )
1983{
1984 init();
1985 ftp = newFtp();
1986 // ### make these tests work
1987 if (ftp->currentId() != 0) {
1988 qWarning(msg: "ftp->currentId() != 0");
1989 return false;
1990 }
1991
1992 if (ftp->state() != QFtp::Unconnected) {
1993 qWarning(msg: "ftp->state() != QFtp::Unconnected");
1994 return false;
1995 }
1996
1997 addCommand( cmd: QFtp::ConnectToHost, id: ftp->connectToHost( host, port ) );
1998 addCommand( cmd: QFtp::Login, id: ftp->login( user, password ) );
1999 if ( !cdDir.isNull() )
2000 addCommand( cmd: QFtp::Cd, id: ftp->cd( dir: cdDir ) );
2001 addCommand( cmd: QFtp::List, id: ftp->list( dir: file ) );
2002 addCommand( cmd: QFtp::Close, id: ftp->close() );
2003
2004 inFileDirExistsFunction = true;
2005 QTestEventLoop::instance().enterLoop( secs: 30 );
2006 delete ftp;
2007 ftp = 0;
2008 if ( QTestEventLoop::instance().timeout() ) {
2009 // ### make this test work
2010 qWarning(msg: "tst_QFtp::fileExists: Network operation timed out");
2011 return false;
2012 }
2013 inFileDirExistsFunction = false;
2014
2015 ResMapIt it = resultMap.find( akey: QFtp::ConnectToHost );
2016 // ### make these tests work
2017 if (it == resultMap.end()) {
2018 qWarning(msg: "it != resultMap.end()");
2019 return false;
2020 }
2021
2022 if (it.value().success == -1) {
2023 qWarning(msg: "it.value().success != -1");
2024 return false;
2025 }
2026
2027 if ( it.value().success == 1 ) {
2028 for ( uint i=0; i < (uint) listInfo_i.count(); i++ ) {
2029 if ( QFileInfo(listInfo_i[i].name()).fileName() == QFileInfo(file).fileName() )
2030 return true;
2031 }
2032 }
2033
2034 //this is not a good warning considering sometime this function is used to test that a file does not exist
2035 //qWarning("file doesn't exist");
2036 return false;
2037}
2038
2039bool tst_QFtp::dirExists( const QString &host, quint16 port, const QString &user, const QString &password, const QString &cdDir, const QString &dirToCreate )
2040{
2041 init();
2042 ftp = newFtp();
2043 // ### make these tests work
2044 // QCOMPARE( ftp->currentId(), 0 );
2045 // QCOMPARE( (int)ftp->state(), (int)QFtp::Unconnected );
2046
2047 addCommand( cmd: QFtp::ConnectToHost, id: ftp->connectToHost( host, port ) );
2048 addCommand( cmd: QFtp::Login, id: ftp->login( user, password ) );
2049 if ( dirToCreate.startsWith( c: QLatin1Char('/') ) )
2050 addCommand( cmd: QFtp::Cd, id: ftp->cd( dir: dirToCreate ) );
2051 else
2052 addCommand( cmd: QFtp::Cd, id: ftp->cd( dir: cdDir + QLatin1Char('/') + dirToCreate ) );
2053 addCommand( cmd: QFtp::Close, id: ftp->close() );
2054
2055 inFileDirExistsFunction = true;
2056 QTestEventLoop::instance().enterLoop( secs: 30 );
2057 delete ftp;
2058 ftp = 0;
2059 if ( QTestEventLoop::instance().timeout() ) {
2060 // ### make this test work
2061 // QFAIL( msgTimedOut(host, port) );
2062 qWarning(msg: "tst_QFtp::dirExists: Network operation timed out");
2063 return false;
2064 }
2065 inFileDirExistsFunction = false;
2066
2067 ResMapIt it = resultMap.find( akey: QFtp::Cd );
2068 // ### make these tests work
2069 // QVERIFY( it != resultMap.end() );
2070 // QVERIFY( it.value().success != -1 );
2071 return it.value().success == 1;
2072}
2073
2074void tst_QFtp::doneSignal()
2075{
2076 QFtp ftp;
2077 QSignalSpy spy(&ftp, SIGNAL(done(bool)));
2078
2079 ftp.connectToHost(host: QtNetworkSettings::ftpServerName());
2080 ftp.login(user: "anonymous");
2081 ftp.list();
2082 ftp.close();
2083
2084 done_success = 0;
2085 connect(sender: &ftp, SIGNAL(done(bool)), receiver: &(QTestEventLoop::instance()), SLOT(exitLoop()));
2086 QTestEventLoop::instance().enterLoop(secs: 61);
2087 if (QTestEventLoop::instance().timeout())
2088 QFAIL("Network operation timed out");
2089
2090 QCOMPARE(spy.count(), 1);
2091 QCOMPARE(spy.first().first().toBool(), false);
2092}
2093
2094void tst_QFtp::queueMoreCommandsInDoneSlot()
2095{
2096 QSKIP("Task 127050 && 113966");
2097
2098 QFtp ftp;
2099 QSignalSpy doneSpy(&ftp, SIGNAL(done(bool)));
2100 QSignalSpy commandFinishedSpy(&ftp, SIGNAL(commandFinished(int,bool)));
2101
2102 this->ftp = &ftp;
2103 connect(sender: &ftp, SIGNAL(done(bool)), receiver: this, SLOT(cdUpSlot(bool)));
2104
2105 ftp.connectToHost(host: "ftp.qt-project.org");
2106 ftp.login();
2107 ftp.cd(dir: "qt");
2108 ftp.rmdir(dir: "qtest-removedir-noexist");
2109
2110 while ( ftp.hasPendingCommands() || ftp.currentCommand() != QFtp::None ) {
2111 QCoreApplication::instance()->processEvents(flags: QEventLoop::AllEvents
2112 | QEventLoop::WaitForMoreEvents);
2113 }
2114
2115 QCOMPARE(doneSpy.count(), 2);
2116 QCOMPARE(doneSpy.first().first().toBool(), true);
2117 QCOMPARE(doneSpy.last().first().toBool(), false);
2118
2119 QCOMPARE(commandFinishedSpy.count(), 6);
2120 int firstId = commandFinishedSpy.at(i: 0).at(i: 0).toInt();
2121 QCOMPARE(commandFinishedSpy.at(0).at(1).toBool(), false);
2122 QCOMPARE(commandFinishedSpy.at(1).at(0).toInt(), firstId + 1);
2123 QCOMPARE(commandFinishedSpy.at(1).at(1).toBool(), false);
2124 QCOMPARE(commandFinishedSpy.at(2).at(0).toInt(), firstId + 2);
2125 QCOMPARE(commandFinishedSpy.at(2).at(1).toBool(), false);
2126 QCOMPARE(commandFinishedSpy.at(3).at(0).toInt(), firstId + 3);
2127 QCOMPARE(commandFinishedSpy.at(3).at(1).toBool(), true);
2128 QCOMPARE(commandFinishedSpy.at(4).at(0).toInt(), firstId + 4);
2129 QCOMPARE(commandFinishedSpy.at(4).at(1).toBool(), false);
2130 QCOMPARE(commandFinishedSpy.at(5).at(0).toInt(), firstId + 5);
2131 QCOMPARE(commandFinishedSpy.at(5).at(1).toBool(), false);
2132
2133 this->ftp = 0;
2134}
2135
2136void tst_QFtp::cdUpSlot(bool error)
2137{
2138 if (error) {
2139 ftp->cd(dir: "..");
2140 ftp->cd(dir: "qt");
2141 }
2142}
2143
2144void tst_QFtp::qtbug7359Crash()
2145{
2146 QFtp ftp;
2147 ftp.connectToHost(host: "127.0.0.1");
2148
2149 QElapsedTimer t;
2150 int elapsed;
2151
2152 t.start();
2153 while ((elapsed = t.elapsed()) < 200)
2154 QCoreApplication::processEvents(flags: QEventLoop::AllEvents, maxtime: 200 - elapsed);
2155
2156 ftp.close();
2157 t.restart();
2158 while ((elapsed = t.elapsed()) < 1000)
2159 QCoreApplication::processEvents(flags: QEventLoop::AllEvents, maxtime: 1000 - elapsed);
2160
2161 ftp.connectToHost(host: "127.0.0.1");
2162
2163 t.restart();
2164 while ((elapsed = t.elapsed()) < 2000)
2165 QCoreApplication::processEvents(flags: QEventLoop::AllEvents, maxtime: 2000 - elapsed);
2166}
2167
2168class FtpLocalServer : public QTcpServer
2169{
2170 Q_OBJECT
2171
2172public:
2173 explicit FtpLocalServer(QObject *parent = 0) : QTcpServer(parent) {}
2174 virtual ~FtpLocalServer() { delete mSocket; }
2175 void startServer(qint16 port = 0);
2176 void stopServer();
2177
2178 enum class ReplyCodes {
2179 ServiceReady = 220,
2180 ServiceClose = 221,
2181 NeedPassword = 331,
2182 LoginFailed = 530,
2183 RequestDeny = 550
2184 };
2185
2186 void sendResponse(ReplyCodes code);
2187
2188 inline QString getRawUser() { return rawUser; }
2189 inline QString getRawPassword() { return rawPass; }
2190
2191signals:
2192 void onStarted();
2193 void onStopped();
2194
2195public slots:
2196 void socketReadyRead();
2197 void socketDisconnected();
2198
2199protected:
2200 virtual void incomingConnection(qintptr handle);
2201
2202private:
2203 QTcpSocket *mSocket = nullptr;
2204 QString rawUser;
2205 QString rawPass;
2206};
2207
2208void FtpLocalServer::startServer(qint16 port)
2209{
2210 if (listen(address: QHostAddress::Any, port))
2211 emit onStarted(); // Notify connected objects
2212 else
2213 qDebug(msg: "Could not start FTP server");
2214}
2215
2216void FtpLocalServer::stopServer()
2217{
2218 close();
2219 emit onStopped(); // Notify connected objects
2220}
2221
2222void FtpLocalServer::sendResponse(ReplyCodes code)
2223{
2224 if (mSocket)
2225 {
2226 QString response;
2227 switch (code) {
2228 case ReplyCodes::ServiceReady:
2229 response = QString("220 Service ready for new user.\r\n");
2230 break;
2231 case ReplyCodes::ServiceClose:
2232 response = QString("221 Service closing control connection.\r\n");
2233 break;
2234 case ReplyCodes::NeedPassword:
2235 response = QString("331 User name okay, need password.\r\n");
2236 break;
2237 case ReplyCodes::LoginFailed:
2238 response = QString("530 Not logged in.\r\n");
2239 break;
2240 case ReplyCodes::RequestDeny:
2241 response = QString("550 Requested action not taken.\r\n");
2242 break;
2243 default:
2244 qDebug(msg: "Unimplemented response code: %u", static_cast<uint>(code));
2245 break;
2246 }
2247
2248 if (!response.isEmpty())
2249 mSocket->write(data: response.toLatin1());
2250 }
2251}
2252
2253void FtpLocalServer::incomingConnection(qintptr handle)
2254{
2255 mSocket = new QTcpSocket(this);
2256 if (mSocket == nullptr || !mSocket->setSocketDescriptor(socketDescriptor: handle))
2257 {
2258 delete mSocket;
2259 mSocket = nullptr;
2260 qDebug() << handle << " Error binding socket";
2261 return;
2262 }
2263
2264 connect(sender: mSocket, SIGNAL(readyRead()), receiver: this, SLOT(socketReadyRead()));
2265 connect(sender: mSocket, SIGNAL(disconnected()), receiver: this, SLOT(socketDisconnected()));
2266
2267 // Accept client connection
2268 sendResponse(code: ReplyCodes::ServiceReady);
2269}
2270
2271void FtpLocalServer::socketReadyRead()
2272{
2273 QString data;
2274 if (mSocket)
2275 data.append(s: mSocket->readAll());
2276
2277 // RFC959 Upper and lower case alphabetic characters are to be treated identically.
2278 if (data.startsWith(s: "USER", cs: Qt::CaseInsensitive)) {
2279 rawUser = data;
2280 sendResponse(code: ReplyCodes::NeedPassword);
2281 } else if (data.startsWith(s: "PASS", cs: Qt::CaseInsensitive)) {
2282 rawPass = data;
2283 sendResponse(code: ReplyCodes::LoginFailed);
2284 } else {
2285 sendResponse(code: ReplyCodes::RequestDeny);
2286 }
2287}
2288
2289void FtpLocalServer::socketDisconnected()
2290{
2291 // Cleanup
2292 if (mSocket)
2293 mSocket->deleteLater();
2294 deleteLater();
2295}
2296
2297void tst_QFtp::loginURL_data()
2298{
2299 QTest::addColumn<QString>(name: "user");
2300 QTest::addColumn<QString>(name: "password");
2301 QTest::addColumn<QString>(name: "rawUser");
2302 QTest::addColumn<QString>(name: "rawPass");
2303
2304 QTest::newRow(dataTag: "no username, no password")
2305 << QString() << QString()
2306 << QString("USER anonymous\r\n") << QString("PASS anonymous@\r\n");
2307
2308 QTest::newRow(dataTag: "username, no password")
2309 << QString("someone") << QString()
2310 << QString("USER someone\r\n") << QString();
2311
2312 QTest::newRow(dataTag: "username, empty password")
2313 << QString("someone") << QString("")
2314 << QString("USER someone\r\n") << QString("PASS \r\n");
2315
2316 QTest::newRow(dataTag: "username, password")
2317 << QString("someone") << QString("nonsense")
2318 << QString("USER someone\r\n") << QString("PASS nonsense\r\n");
2319
2320 QTest::newRow(dataTag: "anonymous, no password")
2321 << QString("anonymous") << QString()
2322 << QString("USER anonymous\r\n") << QString("PASS anonymous@\r\n");
2323
2324 QTest::newRow(dataTag: "Anonymous, no password")
2325 << QString("Anonymous") << QString()
2326 << QString("USER Anonymous\r\n") << QString("PASS anonymous@\r\n");
2327
2328 QTest::newRow(dataTag: "anonymous, empty password")
2329 << QString("anonymous") << QString("")
2330 << QString("USER anonymous\r\n") << QString("PASS \r\n");
2331
2332 QTest::newRow(dataTag: "ANONYMOUS, password")
2333 << QString("ANONYMOUS") << QString("nonsense")
2334 << QString("USER ANONYMOUS\r\n") << QString("PASS nonsense\r\n");
2335}
2336
2337void tst_QFtp::loginURL()
2338{
2339 QFETCH_GLOBAL(bool, setProxy);
2340 if (setProxy)
2341 QSKIP("This test should be verified on the local machine without proxies");
2342
2343 QFETCH(QString, user);
2344 QFETCH(QString, password);
2345 QFETCH(QString, rawUser);
2346 QFETCH(QString, rawPass);
2347
2348 FtpLocalServer server;
2349 server.startServer();
2350 uint port = server.serverPort();
2351
2352 ftp = newFtp();
2353 addCommand(cmd: QFtp::ConnectToHost,
2354 id: ftp->connectToHost(host: "127.0.0.1", port));
2355 addCommand(cmd: QFtp::Login, id: ftp->login(user, password));
2356
2357 QTestEventLoop::instance().enterLoop(secs: 5);
2358 delete ftp;
2359 ftp = nullptr;
2360 server.stopServer();
2361 if (QTestEventLoop::instance().timeout())
2362 QFAIL(msgTimedOut("127.0.0.1", port));
2363
2364 QCOMPARE(server.getRawUser(), rawUser);
2365 QCOMPARE(server.getRawPassword(), rawPass);
2366}
2367
2368QTEST_MAIN(tst_QFtp)
2369
2370#include "tst_qftp.moc"
2371

source code of qtbase/tests/auto/network/access/qftp/tst_qftp.cpp