1//
2// FTPSClientSessionTest.cpp
3//
4// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
5// and Contributors.
6//
7// SPDX-License-Identifier: BSL-1.0
8//
9
10
11#include "FTPSClientSessionTest.h"
12#include "Poco/CppUnit/TestCaller.h"
13#include "Poco/CppUnit/TestSuite.h"
14#include "DialogServer.h"
15#include "Poco/Net/FTPSClientSession.h"
16#include "Poco/Net/DialogSocket.h"
17#include "Poco/Net/SocketAddress.h"
18#include "Poco/Net/NetException.h"
19#include "Poco/Thread.h"
20#include "Poco/ActiveMethod.h"
21#include "Poco/StreamCopier.h"
22#include <sstream>
23#include "Poco/Net/Session.h"
24
25using Poco::Net::FTPSClientSession;
26using Poco::Net::DialogSocket;
27using Poco::Net::SocketAddress;
28using Poco::Net::FTPException;
29using Poco::ActiveMethod;
30using Poco::ActiveResult;
31using Poco::StreamCopier;
32using Poco::Thread;
33using Poco::Net::Session;
34
35namespace
36{
37 class ActiveDownloader
38 {
39 public:
40 ActiveDownloader(FTPSClientSession& session):
41 download(this, &ActiveDownloader::downloadImp),
42 _session(session)
43 {
44 }
45
46 ActiveMethod<std::string, std::string, ActiveDownloader> download;
47
48 protected:
49 std::string downloadImp(const std::string& path)
50 {
51 std::istream& istr = _session.beginDownload(path);
52 std::ostringstream ostr;
53 StreamCopier::copyStream(istr, ostr);
54 _session.endDownload();
55 return ostr.str();
56 }
57
58 private:
59 FTPSClientSession& _session;
60 };
61};
62
63
64FTPSClientSessionTest::FTPSClientSessionTest(const std::string& name): CppUnit::TestCase(name)
65{
66}
67
68
69FTPSClientSessionTest::~FTPSClientSessionTest()
70{
71}
72
73
74void FTPSClientSessionTest::login(DialogServer& server, FTPSClientSession& session)
75{
76 server.addResponse("331 Password required");
77 server.addResponse("230 Welcome");
78 server.addResponse("200 Type set to I");
79 session.login("user", "password");
80 std::string cmd = server.popCommand();
81 assertTrue (cmd == "USER user");
82 cmd = server.popCommand();
83 assertTrue (cmd == "PASS password");
84 cmd = server.popCommand();
85 assertTrue (cmd == "TYPE I");
86
87 assertTrue (session.getFileType() == FTPSClientSession::TYPE_BINARY);
88}
89
90
91void FTPSClientSessionTest::testLogin1()
92{
93 DialogServer server;
94 server.addResponse("220 localhost FTP ready");
95 FTPSClientSession session("127.0.0.1", server.port());
96 assertTrue (session.isOpen());
97 assertTrue (!session.isLoggedIn());
98 login(server, session);
99 assertTrue (session.isOpen());
100 assertTrue (session.isLoggedIn());
101 server.addResponse("221 Good Bye");
102 session.logout();
103 assertTrue (session.isOpen());
104 assertTrue (!session.isLoggedIn());
105
106 server.clearCommands();
107 server.clearResponses();
108
109 session.tryFTPSmode(true);
110 login(server, session);
111 assertTrue (session.isOpen());
112 assertTrue (session.isLoggedIn());
113 server.addResponse("221 Good Bye");
114 session.close();
115 assertTrue (!session.isOpen());
116 assertTrue (!session.isLoggedIn());
117}
118
119
120void FTPSClientSessionTest::testLogin2()
121{
122 DialogServer server;
123 server.addResponse("220 localhost FTP ready");
124
125 server.addResponse("331 Password required");
126 server.addResponse("230 Welcome");
127 server.addResponse("200 Type set to I");
128 Poco::UInt16 serverPort = server.port();
129 FTPSClientSession session("127.0.0.1", serverPort, "user", "password");
130 assertTrue (session.isOpen());
131 assertTrue (session.isLoggedIn());
132 server.addResponse("221 Good Bye");
133 session.close();
134 assertTrue (!session.isOpen());
135 assertTrue (!session.isLoggedIn());
136
137 server.clearCommands();
138 server.clearResponses();
139 server.addResponse("220 localhost FTP ready");
140
141 server.addResponse("331 Password required");
142 server.addResponse("230 Welcome");
143 server.addResponse("200 Type set to I");
144 session.tryFTPSmode(true);
145 session.open("127.0.0.1", serverPort, "user", "password");
146 assertTrue (session.isOpen());
147 assertTrue (session.isLoggedIn());
148 server.addResponse("221 Good Bye");
149 session.close();
150 assertTrue (!session.isOpen());
151 assertTrue (!session.isLoggedIn());
152}
153
154
155void FTPSClientSessionTest::testLogin3()
156{
157 DialogServer server;
158 server.addResponse("220 localhost FTP ready");
159 server.addResponse("331 Password required");
160 server.addResponse("230 Welcome");
161 server.addResponse("200 Type set to I");
162 FTPSClientSession session;
163 assertTrue (!session.isOpen());
164 assertTrue (!session.isLoggedIn());
165 session.open("127.0.0.1", server.port(), "user", "password");
166 server.addResponse("221 Good Bye");
167 session.close();
168 assertTrue (!session.isOpen());
169 assertTrue (!session.isLoggedIn());
170}
171
172
173
174void FTPSClientSessionTest::testLoginFailed1()
175{
176 DialogServer server;
177 server.addResponse("421 localhost FTP not ready");
178 FTPSClientSession session("127.0.0.1", server.port());
179 try
180 {
181 session.login("user", "password");
182 fail("server not ready - must throw");
183 }
184 catch (FTPException&)
185 {
186 }
187 server.addResponse("221 Good Bye");
188 session.close();
189}
190
191
192void FTPSClientSessionTest::testLoginFailed2()
193{
194 DialogServer server;
195 server.addResponse("220 localhost FTP ready");
196 server.addResponse("331 Password required");
197 server.addResponse("530 Login incorrect");
198 FTPSClientSession session("127.0.0.1", server.port());
199 try
200 {
201 session.login("user", "password");
202 fail("login incorrect - must throw");
203 }
204 catch (FTPException&)
205 {
206 }
207 server.addResponse("221 Good Bye");
208 session.close();
209}
210
211
212void FTPSClientSessionTest::testCommands()
213{
214 DialogServer server;
215 server.addResponse("220 localhost FTP ready");
216 server.addResponse("331 Password required");
217 server.addResponse("230 Welcome");
218 server.addResponse("200 Type set to I");
219 FTPSClientSession session("127.0.0.1", server.port());
220 session.login("user", "password");
221 std::string cmd = server.popCommand();
222 assertTrue (cmd == "USER user");
223 cmd = server.popCommand();
224 assertTrue (cmd == "PASS password");
225 cmd = server.popCommand();
226 assertTrue (cmd == "TYPE I");
227
228 // systemType
229 server.clearCommands();
230 server.addResponse("215 UNIX Type: L8 Version: dummyFTP 1.0");
231 std::string type = session.systemType();
232 cmd = server.popCommand();
233 assertTrue (cmd == "SYST");
234 assertTrue (type == "UNIX Type: L8 Version: dummyFTP 1.0");
235
236 // getWorkingDirectory
237 server.addResponse("257 \"/usr/test\" is current directory");
238 std::string cwd = session.getWorkingDirectory();
239 cmd = server.popCommand();
240 assertTrue (cmd == "PWD");
241 assertTrue (cwd == "/usr/test");
242
243 // getWorkingDirectory (quotes in filename)
244 server.addResponse("257 \"\"\"quote\"\"\" is current directory");
245 cwd = session.getWorkingDirectory();
246 cmd = server.popCommand();
247 assertTrue (cmd == "PWD");
248 assertTrue (cwd == "\"quote\"");
249
250 // setWorkingDirectory
251 server.addResponse("250 CWD OK");
252 session.setWorkingDirectory("test");
253 cmd = server.popCommand();
254 assertTrue (cmd == "CWD test");
255
256 server.addResponse("250 CDUP OK");
257 session.cdup();
258 cmd = server.popCommand();
259 assertTrue (cmd == "CDUP");
260
261 // rename
262 server.addResponse("350 File exists, send destination name");
263 server.addResponse("250 Rename OK");
264 session.rename("old.txt", "new.txt");
265 cmd = server.popCommand();
266 assertTrue (cmd == "RNFR old.txt");
267 cmd = server.popCommand();
268 assertTrue (cmd == "RNTO new.txt");
269
270 // rename (failing)
271 server.addResponse("550 not found");
272 try
273 {
274 session.rename("old.txt", "new.txt");
275 fail("not found - must throw");
276 }
277 catch (FTPException&)
278 {
279 }
280 server.clearCommands();
281
282 // remove
283 server.addResponse("250 delete ok");
284 session.remove("test.txt");
285 cmd = server.popCommand();
286 assertTrue (cmd == "DELE test.txt");
287
288 // remove (failing)
289 server.addResponse("550 not found");
290 try
291 {
292 session.remove("test.txt");
293 fail("not found - must throw");
294 }
295 catch (FTPException&)
296 {
297 }
298 server.clearCommands();
299
300 // createDirectory
301 server.addResponse("257 dir created");
302 session.createDirectory("foo");
303 cmd = server.popCommand();
304 assertTrue (cmd == "MKD foo");
305
306 // createDirectory (failing)
307 server.addResponse("550 exists");
308 try
309 {
310 session.createDirectory("foo");
311 fail("not found - must throw");
312 }
313 catch (FTPException&)
314 {
315 }
316 server.clearCommands();
317
318 // removeDirectory
319 server.addResponse("250 RMD OK");
320 session.removeDirectory("foo");
321 cmd = server.popCommand();
322 assertTrue (cmd == "RMD foo");
323
324 // removeDirectory (failing)
325 server.addResponse("550 not found");
326 try
327 {
328 session.removeDirectory("foo");
329 fail("not found - must throw");
330 }
331 catch (FTPException&)
332 {
333 }
334 server.clearCommands();
335
336 server.addResponse("221 Good Bye");
337 session.close();
338}
339
340
341void FTPSClientSessionTest::testDownloadPORT()
342{
343 DialogServer server;
344 server.addResponse("220 localhost FTP ready");
345 server.addResponse("331 Password required");
346 server.addResponse("230 Welcome");
347 server.addResponse("200 Type set to I");
348 FTPSClientSession session("127.0.0.1", server.port());
349 session.setPassive(false);
350 session.login("user", "password");
351 server.clearCommands();
352
353 server.addResponse("500 EPRT not understood");
354 server.addResponse("200 PORT OK");
355 server.addResponse("150 Sending data\r\n226 Transfer complete");
356
357 ActiveDownloader dl(session);
358 ActiveResult<std::string> result = dl.download("test.txt");
359
360 std::string cmd = server.popCommandWait();
361 assertTrue (cmd.substr(0, 4) == "EPRT");
362
363 cmd = server.popCommandWait();
364 assertTrue (cmd.substr(0, 4) == "PORT");
365
366 std::string dummy;
367 int x, lo, hi;
368 for (std::string::iterator it = cmd.begin(); it != cmd.end(); ++it)
369 {
370 if (*it == ',') *it = ' ';
371 }
372 std::istringstream istr(cmd);
373 istr >> dummy >> x >> x >> x >> x >> hi >> lo;
374 int port = hi*256 + lo;
375
376 cmd = server.popCommandWait();
377 assertTrue (cmd == "RETR test.txt");
378
379 SocketAddress sa("127.0.0.1", (Poco::UInt16) port);
380 DialogSocket dataSock;
381 dataSock.connect(sa);
382
383 std::string data("This is some data");
384 dataSock.sendString(data);
385 dataSock.close();
386
387 result.wait();
388 std::string received = result.data();
389 assertTrue (received == data);
390
391 server.addResponse("221 Good Bye");
392 session.close();
393}
394
395
396void FTPSClientSessionTest::testDownloadEPRT()
397{
398 DialogServer server;
399 server.addResponse("220 localhost FTP ready");
400 server.addResponse("331 Password required");
401 server.addResponse("230 Welcome");
402 server.addResponse("200 Type set to I");
403 FTPSClientSession session("127.0.0.1", server.port());
404 session.setPassive(false);
405 session.login("user", "password");
406 server.clearCommands();
407
408 server.addResponse("200 EPRT OK");
409 server.addResponse("150 Sending data\r\n226 Transfer complete");
410
411 ActiveDownloader dl(session);
412 ActiveResult<std::string> result = dl.download("test.txt");
413
414 std::string cmd = server.popCommandWait();
415 assertTrue (cmd.substr(0, 4) == "EPRT");
416
417 std::string dummy;
418 char c;
419 int d;
420 int port;
421 std::istringstream istr(cmd);
422 istr >> dummy >> c >> d >> c >> d >> c >> d >> c >> d >> c >> d >> c >> port >> c;
423
424 cmd = server.popCommandWait();
425 assertTrue (cmd == "RETR test.txt");
426
427 SocketAddress sa("127.0.0.1", (Poco::UInt16) port);
428 DialogSocket dataSock;
429 dataSock.connect(sa);
430
431 std::string data("This is some data");
432 dataSock.sendString(data);
433 dataSock.close();
434
435 result.wait();
436 std::string received = result.data();
437 assertTrue (received == data);
438
439 server.addResponse("221 Good Bye");
440 session.close();
441}
442
443
444void FTPSClientSessionTest::testDownloadPASV()
445{
446 DialogServer server;
447 server.addResponse("220 localhost FTP ready");
448 server.addResponse("331 Password required");
449 server.addResponse("230 Welcome");
450 server.addResponse("200 Type set to I");
451 FTPSClientSession session("127.0.0.1", server.port());
452 session.login("user", "password");
453 server.clearCommands();
454
455 server.addResponse("500 EPSV not understood");
456
457 DialogServer dataServer(false);
458 Poco::UInt16 dataServerPort = dataServer.port();
459 dataServer.addResponse("This is some data");
460 std::ostringstream pasv;
461 pasv << "227 Entering Passive Mode (127,0,0,1," << (dataServerPort/256) << "," << (dataServerPort % 256) << ")";
462 server.addResponse(pasv.str());
463 server.addResponse("150 sending data\r\n226 Transfer complete");
464
465 std::istream& istr = session.beginDownload("test.txt");
466 std::ostringstream dataStr;
467 StreamCopier::copyStream(istr, dataStr);
468 session.endDownload();
469 std::string s(dataStr.str());
470 assertTrue (s == "This is some data\r\n");
471
472 server.addResponse("221 Good Bye");
473 session.close();
474}
475
476
477void FTPSClientSessionTest::testDownloadEPSV()
478{
479 DialogServer server;
480 server.addResponse("220 localhost FTP ready");
481 server.addResponse("331 Password required");
482 server.addResponse("230 Welcome");
483 server.addResponse("200 Type set to I");
484 FTPSClientSession session("127.0.0.1", server.port());
485 session.login("user", "password");
486 server.clearCommands();
487
488 DialogServer dataServer(false);
489 dataServer.addResponse("This is some data");
490 std::ostringstream epsv;
491 epsv << "229 Entering Extended Passive Mode (|||" << dataServer.port() << "|)";
492 server.addResponse(epsv.str());
493 server.addResponse("150 sending data\r\n226 Transfer complete");
494
495 std::istream& istr = session.beginDownload("test.txt");
496 std::ostringstream dataStr;
497 StreamCopier::copyStream(istr, dataStr);
498 session.endDownload();
499 std::string s(dataStr.str());
500 assertTrue (s == "This is some data\r\n");
501
502 std::string cmd = server.popCommand();
503 assertTrue (cmd.substr(0, 4) == "EPSV");
504 cmd = server.popCommand();
505 assertTrue (cmd == "RETR test.txt");
506
507 server.addResponse("221 Good Bye");
508 session.close();
509}
510
511
512void FTPSClientSessionTest::testUpload()
513{
514 DialogServer server;
515 server.addResponse("220 localhost FTP ready");
516 server.addResponse("331 Password required");
517 server.addResponse("230 Welcome");
518 server.addResponse("200 Type set to I");
519 FTPSClientSession session("127.0.0.1", server.port());
520 session.login("user", "password");
521 server.clearCommands();
522
523 DialogServer dataServer;
524 std::ostringstream epsv;
525 epsv << "229 Entering Extended Passive Mode (|||" << dataServer.port() << "|)";
526 server.addResponse(epsv.str());
527 server.addResponse("150 send data\r\n226 Transfer complete");
528
529 std::ostream& ostr = session.beginUpload("test.txt");
530 ostr << "This is some data\r\n";
531 session.endUpload();
532 std::string s(dataServer.popCommandWait());
533 assertTrue (s == "This is some data");
534
535 std::string cmd = server.popCommand();
536 assertTrue (cmd.substr(0, 4) == "EPSV");
537 cmd = server.popCommand();
538 assertTrue (cmd == "STOR test.txt");
539
540 server.addResponse("221 Good Bye");
541 session.close();
542}
543
544void FTPSClientSessionTest::testUploadSSL()
545{
546 DialogServer server(true, true);
547 server.addResponse("220 localhost FTP ready");
548 server.addResponse("331 Password required");
549 server.addResponse("230 Welcome");
550 server.addResponse("200 Type set to I");
551 FTPSClientSession session("127.0.0.1", server.port());
552 session.login("user", "password");
553 server.clearCommands();
554
555 DialogServer dataServer(true, true);
556 Session::Ptr cSessionSSL = server.getSslSession();
557 dataServer.setSslSession(cSessionSSL);
558
559 std::ostringstream epsv;
560 epsv << "229 Entering Extended Passive Mode (|||" << dataServer.port() << "|)";
561 server.addResponse(epsv.str());
562 server.addResponse("150 send data\r\n226 Transfer complete");
563
564 std::ostream& ostr = session.beginUpload("test.txt");
565 ostr << "This is some data\r\n";
566 session.endUpload();
567 std::string s(dataServer.popCommandWait());
568 assertTrue (s == "This is some data");
569
570 std::string cmd = server.popCommand();
571 assertTrue (cmd.substr(0, 4) == "EPSV");
572 cmd = server.popCommand();
573 assertTrue (cmd == "STOR test.txt");
574
575 server.addResponse("221 Good Bye");
576 session.close();
577}
578
579void FTPSClientSessionTest::testList()
580{
581 DialogServer server;
582 server.addResponse("220 localhost FTP ready");
583 server.addResponse("331 Password required");
584 server.addResponse("230 Welcome");
585 server.addResponse("200 Type set to I");
586 FTPSClientSession session("127.0.0.1", server.port());
587 session.login("user", "password");
588 server.clearCommands();
589
590 DialogServer dataServer(false);
591 dataServer.addResponse("file1\r\nfile2");
592 std::ostringstream epsv;
593 epsv << "229 Entering Extended Passive Mode (|||" << dataServer.port() << "|)";
594 server.addResponse(epsv.str());
595 server.addResponse("150 sending data\r\n226 Transfer complete");
596
597 std::istream& istr = session.beginList();
598 std::ostringstream dataStr;
599 StreamCopier::copyStream(istr, dataStr);
600 session.endList();
601 std::string s(dataStr.str());
602 assertTrue (s == "file1\r\nfile2\r\n");
603
604 std::string cmd = server.popCommand();
605 assertTrue (cmd.substr(0, 4) == "EPSV");
606 cmd = server.popCommand();
607 assertTrue (cmd == "NLST");
608
609 server.addResponse("221 Good Bye");
610 session.close();
611}
612
613
614void FTPSClientSessionTest::setUp()
615{
616}
617
618
619void FTPSClientSessionTest::tearDown()
620{
621}
622
623
624CppUnit::Test* FTPSClientSessionTest::suite()
625{
626 CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("FTPSClientSessionTest");
627
628 CppUnit_addTest(pSuite, FTPSClientSessionTest, testLogin1);
629 CppUnit_addTest(pSuite, FTPSClientSessionTest, testLogin2);
630 CppUnit_addTest(pSuite, FTPSClientSessionTest, testLogin3);
631 CppUnit_addTest(pSuite, FTPSClientSessionTest, testLoginFailed1);
632 CppUnit_addTest(pSuite, FTPSClientSessionTest, testLoginFailed2);
633 CppUnit_addTest(pSuite, FTPSClientSessionTest, testCommands);
634 CppUnit_addTest(pSuite, FTPSClientSessionTest, testDownloadPORT);
635 CppUnit_addTest(pSuite, FTPSClientSessionTest, testDownloadEPRT);
636 CppUnit_addTest(pSuite, FTPSClientSessionTest, testDownloadPASV);
637 CppUnit_addTest(pSuite, FTPSClientSessionTest, testDownloadEPSV);
638 CppUnit_addTest(pSuite, FTPSClientSessionTest, testUpload);
639 CppUnit_addTest(pSuite, FTPSClientSessionTest, testList);
640 CppUnit_addTest(pSuite, FTPSClientSessionTest, testUploadSSL);
641
642 return pSuite;
643}
644