FtpConnectionTest.cc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. #include "FtpConnection.h"
  2. #include <iostream>
  3. #include <cstring>
  4. #include <cppunit/extensions/HelperMacros.h>
  5. #include "Exception.h"
  6. #include "util.h"
  7. #include "SocketCore.h"
  8. #include "Request.h"
  9. #include "Option.h"
  10. #include "DlRetryEx.h"
  11. #include "DlAbortEx.h"
  12. #include "AuthConfigFactory.h"
  13. #include "AuthConfig.h"
  14. namespace aria2 {
  15. class FtpConnectionTest:public CppUnit::TestFixture {
  16. CPPUNIT_TEST_SUITE(FtpConnectionTest);
  17. CPPUNIT_TEST(testReceiveResponse);
  18. CPPUNIT_TEST(testReceiveResponse_overflow);
  19. CPPUNIT_TEST(testSendMdtm);
  20. CPPUNIT_TEST(testReceiveMdtmResponse);
  21. CPPUNIT_TEST(testSendPwd);
  22. CPPUNIT_TEST(testReceivePwdResponse);
  23. CPPUNIT_TEST(testReceivePwdResponse_unquotedResponse);
  24. CPPUNIT_TEST(testReceivePwdResponse_badStatus);
  25. CPPUNIT_TEST(testSendCwd);
  26. CPPUNIT_TEST(testSendSize);
  27. CPPUNIT_TEST(testReceiveSizeResponse);
  28. CPPUNIT_TEST(testSendRetr);
  29. CPPUNIT_TEST(testReceiveEpsvResponse);
  30. CPPUNIT_TEST_SUITE_END();
  31. private:
  32. SharedHandle<SocketCore> serverSocket_;
  33. uint16_t listenPort_;
  34. SharedHandle<SocketCore> clientSocket_;
  35. SharedHandle<FtpConnection> ftp_;
  36. SharedHandle<Option> option_;
  37. SharedHandle<AuthConfigFactory> authConfigFactory_;
  38. SharedHandle<Request> req_;
  39. public:
  40. void setUp()
  41. {
  42. option_.reset(new Option());
  43. authConfigFactory_.reset(new AuthConfigFactory());
  44. //_ftpServerSocket.reset(new SocketCore());
  45. SharedHandle<SocketCore> listenSocket(new SocketCore());
  46. listenSocket->bind(0);
  47. listenSocket->beginListen();
  48. std::pair<std::string, uint16_t> addrinfo;
  49. listenSocket->getAddrInfo(addrinfo);
  50. listenPort_ = addrinfo.second;
  51. req_.reset(new Request());
  52. req_->setUri("ftp://localhost/dir%20sp/hello%20world.img");
  53. clientSocket_.reset(new SocketCore());
  54. clientSocket_->establishConnection("localhost", listenPort_);
  55. while(!clientSocket_->isWritable(0));
  56. clientSocket_->setBlockingMode();
  57. serverSocket_.reset(listenSocket->acceptConnection());
  58. ftp_.reset(new FtpConnection(1, clientSocket_, req_,
  59. authConfigFactory_->createAuthConfig
  60. (req_, option_.get()),
  61. option_.get()));
  62. }
  63. void tearDown() {}
  64. void testSendMdtm();
  65. void testReceiveMdtmResponse();
  66. void testReceiveResponse();
  67. void testReceiveResponse_overflow();
  68. void testSendPwd();
  69. void testReceivePwdResponse();
  70. void testReceivePwdResponse_unquotedResponse();
  71. void testReceivePwdResponse_badStatus();
  72. void testSendCwd();
  73. void testSendSize();
  74. void testReceiveSizeResponse();
  75. void testSendRetr();
  76. void testReceiveEpsvResponse();
  77. };
  78. CPPUNIT_TEST_SUITE_REGISTRATION(FtpConnectionTest);
  79. namespace {
  80. void waitRead(const SharedHandle<SocketCore>& socket)
  81. {
  82. while(!socket->isReadable(0));
  83. }
  84. } // namespace
  85. void FtpConnectionTest::testReceiveResponse()
  86. {
  87. serverSocket_->writeData("100");
  88. waitRead(clientSocket_);
  89. CPPUNIT_ASSERT_EQUAL((unsigned int)0, ftp_->receiveResponse());
  90. serverSocket_->writeData(" single line response");
  91. waitRead(clientSocket_);
  92. CPPUNIT_ASSERT_EQUAL((unsigned int)0, ftp_->receiveResponse());
  93. serverSocket_->writeData("\r\n");
  94. waitRead(clientSocket_);
  95. CPPUNIT_ASSERT_EQUAL((unsigned int)100, ftp_->receiveResponse());
  96. // 2 responses in the buffer
  97. serverSocket_->writeData("101 single1\r\n"
  98. "102 single2\r\n");
  99. waitRead(clientSocket_);
  100. CPPUNIT_ASSERT_EQUAL((unsigned int)101, ftp_->receiveResponse());
  101. CPPUNIT_ASSERT_EQUAL((unsigned int)102, ftp_->receiveResponse());
  102. serverSocket_->writeData("103-multi line response\r\n");
  103. waitRead(clientSocket_);
  104. CPPUNIT_ASSERT_EQUAL((unsigned int)0, ftp_->receiveResponse());
  105. serverSocket_->writeData("103-line2\r\n");
  106. waitRead(clientSocket_);
  107. CPPUNIT_ASSERT_EQUAL((unsigned int)0, ftp_->receiveResponse());
  108. serverSocket_->writeData("103");
  109. waitRead(clientSocket_);
  110. CPPUNIT_ASSERT_EQUAL((unsigned int)0, ftp_->receiveResponse());
  111. serverSocket_->writeData(" ");
  112. waitRead(clientSocket_);
  113. CPPUNIT_ASSERT_EQUAL((unsigned int)0, ftp_->receiveResponse());
  114. serverSocket_->writeData("last\r\n");
  115. waitRead(clientSocket_);
  116. CPPUNIT_ASSERT_EQUAL((unsigned int)103, ftp_->receiveResponse());
  117. serverSocket_->writeData("104-multi\r\n"
  118. "104 \r\n"
  119. "105-multi\r\n"
  120. "105 \r\n");
  121. waitRead(clientSocket_);
  122. CPPUNIT_ASSERT_EQUAL((unsigned int)104, ftp_->receiveResponse());
  123. CPPUNIT_ASSERT_EQUAL((unsigned int)105, ftp_->receiveResponse());
  124. }
  125. void FtpConnectionTest::testSendMdtm()
  126. {
  127. ftp_->sendMdtm();
  128. char data[32];
  129. size_t len = sizeof(data);
  130. serverSocket_->readData(data, len);
  131. data[len] = '\0';
  132. CPPUNIT_ASSERT_EQUAL(std::string("MDTM hello world.img\r\n"),
  133. std::string(data));
  134. }
  135. void FtpConnectionTest::testReceiveMdtmResponse()
  136. {
  137. {
  138. Time t;
  139. serverSocket_->writeData("213 20080908124312");
  140. waitRead(clientSocket_);
  141. CPPUNIT_ASSERT_EQUAL((unsigned int)0, ftp_->receiveMdtmResponse(t));
  142. serverSocket_->writeData("\r\n");
  143. waitRead(clientSocket_);
  144. CPPUNIT_ASSERT_EQUAL((unsigned int)213, ftp_->receiveMdtmResponse(t));
  145. CPPUNIT_ASSERT_EQUAL((time_t)1220877792, t.getTime());
  146. }
  147. {
  148. // see milli second part is ignored
  149. Time t;
  150. serverSocket_->writeData("213 20080908124312.014\r\n");
  151. waitRead(clientSocket_);
  152. CPPUNIT_ASSERT_EQUAL((unsigned int)213, ftp_->receiveMdtmResponse(t));
  153. CPPUNIT_ASSERT_EQUAL((time_t)1220877792, t.getTime());
  154. }
  155. {
  156. // hhmmss part is missing
  157. Time t;
  158. serverSocket_->writeData("213 20080908\r\n");
  159. waitRead(clientSocket_);
  160. CPPUNIT_ASSERT_EQUAL((unsigned int)213, ftp_->receiveMdtmResponse(t));
  161. CPPUNIT_ASSERT(t.bad());
  162. }
  163. {
  164. // invalid month: 19, we don't care about invalid month..
  165. Time t;
  166. serverSocket_->writeData("213 20081908124312\r\n");
  167. waitRead(clientSocket_);
  168. CPPUNIT_ASSERT_EQUAL((unsigned int)213, ftp_->receiveMdtmResponse(t));
  169. // Wed Jul 8 12:43:12 2009
  170. CPPUNIT_ASSERT_EQUAL((time_t)1247056992, t.getTime());
  171. }
  172. {
  173. Time t;
  174. serverSocket_->writeData("550 File Not Found\r\n");
  175. waitRead(clientSocket_);
  176. CPPUNIT_ASSERT_EQUAL((unsigned int)550, ftp_->receiveMdtmResponse(t));
  177. }
  178. }
  179. void FtpConnectionTest::testReceiveResponse_overflow()
  180. {
  181. char data[1024];
  182. memset(data, 0, sizeof(data));
  183. memcpy(data, "213 ", 4);
  184. for(int i = 0; i < 64; ++i) {
  185. serverSocket_->writeData(data, sizeof(data));
  186. waitRead(clientSocket_);
  187. CPPUNIT_ASSERT_EQUAL((unsigned int)0, ftp_->receiveResponse());
  188. }
  189. serverSocket_->writeData(data, sizeof(data));
  190. waitRead(clientSocket_);
  191. try {
  192. ftp_->receiveResponse();
  193. CPPUNIT_FAIL("exception must be thrown.");
  194. } catch(DlRetryEx& e) {
  195. // success
  196. }
  197. }
  198. void FtpConnectionTest::testSendPwd()
  199. {
  200. ftp_->sendPwd();
  201. char data[32];
  202. size_t len = sizeof(data);
  203. serverSocket_->readData(data, len);
  204. CPPUNIT_ASSERT_EQUAL((size_t)5, len);
  205. data[len] = '\0';
  206. CPPUNIT_ASSERT_EQUAL(std::string("PWD\r\n"), std::string(data));
  207. }
  208. void FtpConnectionTest::testReceivePwdResponse()
  209. {
  210. std::string pwd;
  211. serverSocket_->writeData("257 ");
  212. waitRead(clientSocket_);
  213. CPPUNIT_ASSERT_EQUAL((unsigned int)0, ftp_->receivePwdResponse(pwd));
  214. CPPUNIT_ASSERT(pwd.empty());
  215. serverSocket_->writeData("\"/dir/to\" is your directory.\r\n");
  216. waitRead(clientSocket_);
  217. CPPUNIT_ASSERT_EQUAL((unsigned int)257, ftp_->receivePwdResponse(pwd));
  218. CPPUNIT_ASSERT_EQUAL(std::string("/dir/to"), pwd);
  219. }
  220. void FtpConnectionTest::testReceivePwdResponse_unquotedResponse()
  221. {
  222. std::string pwd;
  223. serverSocket_->writeData("257 /dir/to\r\n");
  224. waitRead(clientSocket_);
  225. try {
  226. ftp_->receivePwdResponse(pwd);
  227. CPPUNIT_FAIL("exception must be thrown.");
  228. } catch(DlAbortEx& e) {
  229. // success
  230. }
  231. }
  232. void FtpConnectionTest::testReceivePwdResponse_badStatus()
  233. {
  234. std::string pwd;
  235. serverSocket_->writeData("500 failed\r\n");
  236. waitRead(clientSocket_);
  237. CPPUNIT_ASSERT_EQUAL((unsigned int)500, ftp_->receivePwdResponse(pwd));
  238. CPPUNIT_ASSERT(pwd.empty());
  239. }
  240. void FtpConnectionTest::testSendCwd()
  241. {
  242. ftp_->sendCwd("%2Fdir%20sp");
  243. char data[32];
  244. size_t len = sizeof(data);
  245. serverSocket_->readData(data, len);
  246. data[len] = '\0';
  247. CPPUNIT_ASSERT_EQUAL(std::string("CWD /dir sp\r\n"), std::string(data));
  248. }
  249. void FtpConnectionTest::testSendSize()
  250. {
  251. ftp_->sendSize();
  252. char data[32];
  253. size_t len = sizeof(data);
  254. serverSocket_->readData(data, len);
  255. CPPUNIT_ASSERT_EQUAL(std::string("SIZE hello world.img\r\n"),
  256. std::string(&data[0], &data[len]));
  257. }
  258. void FtpConnectionTest::testReceiveSizeResponse()
  259. {
  260. serverSocket_->writeData("213 4294967296\r\n");
  261. waitRead(clientSocket_);
  262. uint64_t size;
  263. CPPUNIT_ASSERT_EQUAL((unsigned int)213, ftp_->receiveSizeResponse(size));
  264. CPPUNIT_ASSERT_EQUAL((uint64_t)4294967296LL, size);
  265. }
  266. void FtpConnectionTest::testSendRetr()
  267. {
  268. ftp_->sendRetr();
  269. char data[32];
  270. size_t len = sizeof(data);
  271. serverSocket_->readData(data, len);
  272. CPPUNIT_ASSERT_EQUAL(std::string("RETR hello world.img\r\n"),
  273. std::string(&data[0], &data[len]));
  274. }
  275. void FtpConnectionTest::testReceiveEpsvResponse()
  276. {
  277. serverSocket_->writeData("229 Success (|||12000|)\r\n");
  278. waitRead(clientSocket_);
  279. uint16_t port = 0;
  280. CPPUNIT_ASSERT_EQUAL((unsigned int)229, ftp_->receiveEpsvResponse(port));
  281. CPPUNIT_ASSERT_EQUAL((uint16_t)12000, port);
  282. serverSocket_->writeData("229 Success |||12000|)\r\n");
  283. waitRead(clientSocket_);
  284. CPPUNIT_ASSERT_EQUAL((unsigned int)229, ftp_->receiveEpsvResponse(port));
  285. CPPUNIT_ASSERT_EQUAL((uint16_t)0, port);
  286. serverSocket_->writeData("229 Success (|||12000|\r\n");
  287. waitRead(clientSocket_);
  288. CPPUNIT_ASSERT_EQUAL((unsigned int)229, ftp_->receiveEpsvResponse(port));
  289. CPPUNIT_ASSERT_EQUAL((uint16_t)0, port);
  290. serverSocket_->writeData("229 Success ()|||12000|\r\n");
  291. waitRead(clientSocket_);
  292. CPPUNIT_ASSERT_EQUAL((unsigned int)229, ftp_->receiveEpsvResponse(port));
  293. CPPUNIT_ASSERT_EQUAL((uint16_t)0, port);
  294. serverSocket_->writeData("229 Success )(|||12000|)\r\n");
  295. waitRead(clientSocket_);
  296. CPPUNIT_ASSERT_EQUAL((unsigned int)229, ftp_->receiveEpsvResponse(port));
  297. CPPUNIT_ASSERT_EQUAL((uint16_t)0, port);
  298. serverSocket_->writeData("229 Success )(||12000|)\r\n");
  299. waitRead(clientSocket_);
  300. CPPUNIT_ASSERT_EQUAL((unsigned int)229, ftp_->receiveEpsvResponse(port));
  301. CPPUNIT_ASSERT_EQUAL((uint16_t)0, port);
  302. }
  303. } // namespace aria2