mirror of https://github.com/aria2/aria2
2008-09-25 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
Issue PWD command first and get working directory and use it as a prefix for CWD command. * src/DownloadEngine.cc * src/DownloadEngine.h * src/FtpConnection.cc * src/FtpConnection.h * src/FtpFinishDownloadCommand.cc * src/FtpInitiateConnectionCommand.cc * src/FtpNegotiationCommand.cc * src/FtpNegotiationCommand.h * test/FtpConnectionTest.ccpull/1/head
parent
d717ffb1d0
commit
6bc233f414
14
ChangeLog
14
ChangeLog
|
@ -1,3 +1,17 @@
|
|||
2008-09-25 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
|
||||
|
||||
Issue PWD command first and get working directory and use it as a prefix
|
||||
for CWD command.
|
||||
* src/DownloadEngine.cc
|
||||
* src/DownloadEngine.h
|
||||
* src/FtpConnection.cc
|
||||
* src/FtpConnection.h
|
||||
* src/FtpFinishDownloadCommand.cc
|
||||
* src/FtpInitiateConnectionCommand.cc
|
||||
* src/FtpNegotiationCommand.cc
|
||||
* src/FtpNegotiationCommand.h
|
||||
* test/FtpConnectionTest.cc
|
||||
|
||||
2008-09-25 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
|
||||
|
||||
Removed default user/pass for FTP user/pass, since it should not have
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
#include "DlAbortEx.h"
|
||||
#include "ServerStatMan.h"
|
||||
#include "CookieStorage.h"
|
||||
#include "A2STR.h"
|
||||
#include <signal.h>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
|
@ -891,33 +892,106 @@ SharedHandle<CookieStorage> DownloadEngine::getCookieStorage() const
|
|||
return _cookieStorage;
|
||||
}
|
||||
|
||||
void DownloadEngine::poolSocket(const std::string& ipaddr, uint16_t port,
|
||||
const SharedHandle<SocketCore>& sock,
|
||||
time_t timeout)
|
||||
void DownloadEngine::poolSocket(const std::string& ipaddr,
|
||||
uint16_t port,
|
||||
const SocketPoolEntry& entry)
|
||||
{
|
||||
std::string addr = ipaddr+":"+Util::uitos(port);
|
||||
logger->info("Pool socket for %s", addr.c_str());
|
||||
|
||||
SocketPoolEntry e(sock, timeout);
|
||||
std::multimap<std::string, SocketPoolEntry>::value_type p(addr, e);
|
||||
std::multimap<std::string, SocketPoolEntry>::value_type p(addr, entry);
|
||||
_socketPool.insert(p);
|
||||
|
||||
if(_lastSocketPoolScan.elapsed(60)) {
|
||||
std::multimap<std::string, SocketPoolEntry> newPool;
|
||||
logger->debug("Scaning SocketPool and erasing timed out entry.");
|
||||
_lastSocketPoolScan.reset();
|
||||
for(std::multimap<std::string, SocketPoolEntry>::iterator i =
|
||||
_socketPool.begin(); i != _socketPool.end(); ++i) {
|
||||
if(!(*i).second.isTimeout()) {
|
||||
newPool.insert(*i);
|
||||
}
|
||||
}
|
||||
logger->debug("%zu entries removed.", _socketPool.size()-newPool.size());
|
||||
_socketPool = newPool;
|
||||
}
|
||||
}
|
||||
|
||||
void DownloadEngine::poolSocket
|
||||
(const std::string& ipaddr,
|
||||
uint16_t port,
|
||||
const SharedHandle<SocketCore>& sock,
|
||||
const std::map<std::string, std::string>& options,
|
||||
time_t timeout)
|
||||
{
|
||||
SocketPoolEntry e(sock, options, timeout);
|
||||
poolSocket(ipaddr, port, e);
|
||||
}
|
||||
|
||||
void DownloadEngine::poolSocket
|
||||
(const std::string& ipaddr,
|
||||
uint16_t port,
|
||||
const SharedHandle<SocketCore>& sock,
|
||||
time_t timeout)
|
||||
{
|
||||
SocketPoolEntry e(sock, std::map<std::string, std::string>(), timeout);
|
||||
poolSocket(ipaddr, port, e);
|
||||
}
|
||||
|
||||
std::multimap<std::string, DownloadEngine::SocketPoolEntry>::iterator
|
||||
DownloadEngine::findSocketPoolEntry(const std::string& ipaddr, uint16_t port)
|
||||
{
|
||||
std::string addr = ipaddr+":"+Util::uitos(port);
|
||||
std::pair<std::multimap<std::string, SocketPoolEntry>::iterator,
|
||||
std::multimap<std::string, SocketPoolEntry>::iterator> range =
|
||||
_socketPool.equal_range(addr);
|
||||
for(std::multimap<std::string, SocketPoolEntry>::iterator i = range.first;
|
||||
i != range.second; ++i) {
|
||||
const SocketPoolEntry& e = (*i).second;
|
||||
if(!e.isTimeout()) {
|
||||
logger->info("Found socket for %s", addr.c_str());
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return _socketPool.end();
|
||||
}
|
||||
|
||||
SharedHandle<SocketCore>
|
||||
DownloadEngine::popPooledSocket(const std::string& ipaddr, uint16_t port)
|
||||
{
|
||||
SharedHandle<SocketCore> s;
|
||||
std::string addr = ipaddr+":"+Util::uitos(port);
|
||||
std::multimap<std::string, SocketPoolEntry>::iterator i =
|
||||
findSocketPoolEntry(ipaddr, port);
|
||||
if(i != _socketPool.end()) {
|
||||
s = (*i).second.getSocket();
|
||||
_socketPool.erase(i);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
std::multimap<std::string, SocketPoolEntry>::iterator first = _socketPool.find(addr);
|
||||
|
||||
for(std::multimap<std::string, SocketPoolEntry>::iterator i = first;
|
||||
i != _socketPool.end() && (*i).first == addr; ++i) {
|
||||
const SocketPoolEntry& e = (*i).second;
|
||||
if(!e.isTimeout()) {
|
||||
logger->info("Reuse socket for %s", addr.c_str());
|
||||
s = e.getSocket();
|
||||
_socketPool.erase(first, ++i);
|
||||
SharedHandle<SocketCore>
|
||||
DownloadEngine::popPooledSocket(std::map<std::string, std::string>& options,
|
||||
const std::string& ipaddr, uint16_t port)
|
||||
{
|
||||
SharedHandle<SocketCore> s;
|
||||
std::multimap<std::string, SocketPoolEntry>::iterator i =
|
||||
findSocketPoolEntry(ipaddr, port);
|
||||
if(i != _socketPool.end()) {
|
||||
s = (*i).second.getSocket();
|
||||
options = (*i).second.getOptions();
|
||||
_socketPool.erase(i);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
SharedHandle<SocketCore>
|
||||
DownloadEngine::popPooledSocket
|
||||
(const std::deque<std::string>& ipaddrs, uint16_t port)
|
||||
{
|
||||
SharedHandle<SocketCore> s;
|
||||
for(std::deque<std::string>::const_iterator i = ipaddrs.begin();
|
||||
i != ipaddrs.end(); ++i) {
|
||||
s = popPooledSocket(*i, port);
|
||||
if(!s.isNull()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -926,22 +1000,26 @@ DownloadEngine::popPooledSocket(const std::string& ipaddr, uint16_t port)
|
|||
|
||||
SharedHandle<SocketCore>
|
||||
DownloadEngine::popPooledSocket
|
||||
(const std::deque<std::string>& ipaddrs, uint16_t port)
|
||||
(std::map<std::string, std::string>& options,
|
||||
const std::deque<std::string>& ipaddrs, uint16_t port)
|
||||
{
|
||||
SharedHandle<SocketCore> s;
|
||||
for(std::deque<std::string>::const_iterator i = ipaddrs.begin();
|
||||
i != ipaddrs.end(); ++i) {
|
||||
SharedHandle<SocketCore> s = popPooledSocket(*i, port);
|
||||
s = popPooledSocket(options, *i, port);
|
||||
if(!s.isNull()) {
|
||||
return s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return SharedHandle<SocketCore>();
|
||||
return s;
|
||||
}
|
||||
|
||||
DownloadEngine::SocketPoolEntry::SocketPoolEntry
|
||||
(const SharedHandle<SocketCore>& socket,
|
||||
const std::map<std::string, std::string>& options,
|
||||
time_t timeout):
|
||||
_socket(socket),
|
||||
_options(options),
|
||||
_timeout(timeout) {}
|
||||
|
||||
DownloadEngine::SocketPoolEntry::~SocketPoolEntry() {}
|
||||
|
@ -956,4 +1034,10 @@ SharedHandle<SocketCore> DownloadEngine::SocketPoolEntry::getSocket() const
|
|||
return _socket;
|
||||
}
|
||||
|
||||
const std::map<std::string, std::string>&
|
||||
DownloadEngine::SocketPoolEntry::getOptions() const
|
||||
{
|
||||
return _options;
|
||||
}
|
||||
|
||||
} // namespace aria2
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#ifdef ENABLE_ASYNC_DNS
|
||||
# include "AsyncNameResolver.h"
|
||||
#endif // ENABLE_ASYNC_DNS
|
||||
#include <string>
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#ifdef HAVE_EPOLL
|
||||
|
@ -261,11 +262,14 @@ private:
|
|||
private:
|
||||
SharedHandle<SocketCore> _socket;
|
||||
|
||||
std::map<std::string, std::string> _options;
|
||||
|
||||
time_t _timeout;
|
||||
|
||||
Time _registeredTime;
|
||||
public:
|
||||
SocketPoolEntry(const SharedHandle<SocketCore>& socket,
|
||||
const std::map<std::string, std::string>& option,
|
||||
time_t timeout);
|
||||
|
||||
~SocketPoolEntry();
|
||||
|
@ -273,11 +277,15 @@ private:
|
|||
bool isTimeout() const;
|
||||
|
||||
SharedHandle<SocketCore> getSocket() const;
|
||||
|
||||
const std::map<std::string, std::string>& getOptions() const;
|
||||
};
|
||||
|
||||
// key = IP address:port, value = SocketPoolEntry
|
||||
std::multimap<std::string, SocketPoolEntry> _socketPool;
|
||||
|
||||
Time _lastSocketPoolScan;
|
||||
|
||||
bool _noWait;
|
||||
|
||||
std::deque<Command*> _routineCommands;
|
||||
|
@ -294,6 +302,13 @@ private:
|
|||
void onEndOfRun();
|
||||
|
||||
void afterEachIteration();
|
||||
|
||||
void poolSocket(const std::string& ipaddr,
|
||||
uint16_t port,
|
||||
const SocketPoolEntry& entry);
|
||||
|
||||
std::multimap<std::string, SocketPoolEntry>::iterator
|
||||
findSocketPoolEntry(const std::string& ipaddr, uint16_t port);
|
||||
public:
|
||||
std::deque<Command*> commands;
|
||||
SharedHandle<RequestGroupMan> _requestGroupMan;
|
||||
|
@ -364,15 +379,31 @@ public:
|
|||
void addRoutineCommand(Command* command);
|
||||
|
||||
void poolSocket(const std::string& ipaddr, uint16_t port,
|
||||
const SharedHandle<SocketCore>& sock, time_t timeout = 15);
|
||||
const SharedHandle<SocketCore>& sock,
|
||||
const std::map<std::string, std::string>& options,
|
||||
time_t timeout = 15);
|
||||
|
||||
void poolSocket(const std::string& ipaddr, uint16_t port,
|
||||
const SharedHandle<SocketCore>& sock,
|
||||
time_t timeout = 15);
|
||||
|
||||
SharedHandle<SocketCore> popPooledSocket(const std::string& ipaddr,
|
||||
uint16_t port);
|
||||
|
||||
SharedHandle<SocketCore> popPooledSocket
|
||||
(std::map<std::string, std::string>& options,
|
||||
const std::string& ipaddr,
|
||||
uint16_t port);
|
||||
|
||||
SharedHandle<SocketCore>
|
||||
popPooledSocket(const std::deque<std::string>& ipaddrs, uint16_t port);
|
||||
|
||||
SharedHandle<SocketCore>
|
||||
popPooledSocket
|
||||
(std::map<std::string, std::string>& options,
|
||||
const std::deque<std::string>& ipaddrs,
|
||||
uint16_t port);
|
||||
|
||||
SharedHandle<CookieStorage> getCookieStorage() const;
|
||||
};
|
||||
|
||||
|
|
|
@ -61,7 +61,8 @@ FtpConnection::FtpConnection(int32_t cuid, const SocketHandle& socket,
|
|||
const RequestHandle& req, const Option* op):
|
||||
cuid(cuid), socket(socket), req(req), option(op),
|
||||
logger(LogFactory::getInstance()),
|
||||
_socketBuffer(socket) {}
|
||||
_socketBuffer(socket),
|
||||
_baseWorkingDir("/") {}
|
||||
|
||||
FtpConnection::~FtpConnection() {}
|
||||
|
||||
|
@ -108,10 +109,25 @@ bool FtpConnection::sendType()
|
|||
return _socketBuffer.sendBufferIsEmpty();
|
||||
}
|
||||
|
||||
bool FtpConnection::sendPwd()
|
||||
{
|
||||
if(_socketBuffer.sendBufferIsEmpty()) {
|
||||
std::string request = "PWD\r\n";
|
||||
logger->info(MSG_SENDING_REQUEST, cuid, request.c_str());
|
||||
_socketBuffer.feedSendBuffer(request);
|
||||
}
|
||||
_socketBuffer.send();
|
||||
return _socketBuffer.sendBufferIsEmpty();
|
||||
}
|
||||
|
||||
bool FtpConnection::sendCwd()
|
||||
{
|
||||
if(_socketBuffer.sendBufferIsEmpty()) {
|
||||
std::string request = "CWD "+Util::urldecode(req->getDir())+"\r\n";
|
||||
logger->info("CUID#%d - Using base working directory '%s'",
|
||||
cuid, _baseWorkingDir.c_str());
|
||||
std::string request = "CWD "+
|
||||
(_baseWorkingDir == "/" ? "" : _baseWorkingDir)+
|
||||
Util::urldecode(req->getDir())+"\r\n";
|
||||
logger->info(MSG_SENDING_REQUEST, cuid, request.c_str());
|
||||
_socketBuffer.feedSendBuffer(request);
|
||||
}
|
||||
|
@ -380,4 +396,35 @@ unsigned int FtpConnection::receivePasvResponse(std::pair<std::string, uint16_t>
|
|||
}
|
||||
}
|
||||
|
||||
unsigned int FtpConnection::receivePwdResponse(std::string& pwd)
|
||||
{
|
||||
std::pair<unsigned int, std::string> response;
|
||||
if(bulkReceiveResponse(response)) {
|
||||
if(response.first == 257) {
|
||||
std::string::size_type first;
|
||||
std::string::size_type last;
|
||||
|
||||
if((first = response.second.find("\"")) != std::string::npos &&
|
||||
(last = response.second.find("\"", ++first)) != std::string::npos) {
|
||||
pwd = response.second.substr(first, last-first);
|
||||
} else {
|
||||
throw DlAbortEx(EX_INVALID_RESPONSE);
|
||||
}
|
||||
}
|
||||
return response.first;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void FtpConnection::setBaseWorkingDir(const std::string& baseWorkingDir)
|
||||
{
|
||||
_baseWorkingDir = baseWorkingDir;
|
||||
}
|
||||
|
||||
const std::string& FtpConnection::getBaseWorkingDir() const
|
||||
{
|
||||
return _baseWorkingDir;
|
||||
}
|
||||
|
||||
} // namespace aria2
|
||||
|
|
|
@ -62,6 +62,8 @@ private:
|
|||
|
||||
SocketBuffer _socketBuffer;
|
||||
|
||||
std::string _baseWorkingDir;
|
||||
|
||||
unsigned int getStatus(const std::string& response) const;
|
||||
std::string::size_type findEndOfResponse(unsigned int status,
|
||||
const std::string& buf) const;
|
||||
|
@ -79,6 +81,7 @@ public:
|
|||
bool sendUser();
|
||||
bool sendPass();
|
||||
bool sendType();
|
||||
bool sendPwd();
|
||||
bool sendCwd();
|
||||
bool sendMdtm();
|
||||
bool sendSize();
|
||||
|
@ -98,6 +101,11 @@ public:
|
|||
// If reply is not received yet, returns 0.
|
||||
unsigned int receiveMdtmResponse(Time& time);
|
||||
unsigned int receivePasvResponse(std::pair<std::string, uint16_t>& dest);
|
||||
unsigned int receivePwdResponse(std::string& pwd);
|
||||
|
||||
void setBaseWorkingDir(const std::string& baseWorkingDir);
|
||||
|
||||
const std::string& getBaseWorkingDir() const;
|
||||
};
|
||||
|
||||
} // namespace aria2
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include "SocketCore.h"
|
||||
#include "RequestGroup.h"
|
||||
#include "Logger.h"
|
||||
#include <map>
|
||||
|
||||
namespace aria2 {
|
||||
|
||||
|
@ -85,7 +86,9 @@ bool FtpFinishDownloadCommand::execute()
|
|||
e->option->getAsBool(PREF_FTP_REUSE_CONNECTION)) {
|
||||
std::pair<std::string, uint16_t> peerInfo;
|
||||
socket->getPeerInfo(peerInfo);
|
||||
e->poolSocket(peerInfo.first, peerInfo.second, socket);
|
||||
std::map<std::string, std::string> options;
|
||||
options["baseWorkingDir"] = _ftpConnection->getBaseWorkingDir();
|
||||
e->poolSocket(peerInfo.first, peerInfo.second, socket, options);
|
||||
}
|
||||
} catch(RecoverableException& e) {
|
||||
logger->info(EX_EXCEPTION_CAUGHT, e);
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include "prefs.h"
|
||||
#include "HttpConnection.h"
|
||||
#include "Socket.h"
|
||||
#include <map>
|
||||
|
||||
namespace aria2 {
|
||||
|
||||
|
@ -81,17 +82,20 @@ Command* FtpInitiateConnectionCommand::createNextCommand
|
|||
throw DlAbortEx("ERROR");
|
||||
}
|
||||
} else {
|
||||
std::map<std::string, std::string> options;
|
||||
SharedHandle<SocketCore> pooledSocket =
|
||||
e->popPooledSocket(resolvedAddresses, req->getPort());
|
||||
e->popPooledSocket(options, resolvedAddresses, req->getPort());
|
||||
if(pooledSocket.isNull()) {
|
||||
|
||||
logger->info(MSG_CONNECTING_TO_SERVER, cuid, req->getHost().c_str(),
|
||||
req->getPort());
|
||||
socket.reset(new SocketCore());
|
||||
socket->establishConnection(resolvedAddresses.front(), req->getPort());
|
||||
command = new FtpNegotiationCommand(cuid, req, _requestGroup, e, socket);
|
||||
} else {
|
||||
command = new FtpNegotiationCommand(cuid, req, _requestGroup, e, pooledSocket, FtpNegotiationCommand::SEQ_SEND_CWD);
|
||||
command =
|
||||
new FtpNegotiationCommand(cuid, req, _requestGroup, e, pooledSocket,
|
||||
FtpNegotiationCommand::SEQ_SEND_CWD,
|
||||
options["baseWorkingDir"]);
|
||||
}
|
||||
}
|
||||
return command;
|
||||
|
|
|
@ -59,6 +59,7 @@
|
|||
#include <stdint.h>
|
||||
#include <cassert>
|
||||
#include <utility>
|
||||
#include <map>
|
||||
|
||||
namespace aria2 {
|
||||
|
||||
|
@ -67,10 +68,12 @@ FtpNegotiationCommand::FtpNegotiationCommand(int32_t cuid,
|
|||
RequestGroup* requestGroup,
|
||||
DownloadEngine* e,
|
||||
const SocketHandle& s,
|
||||
Seq seq):
|
||||
Seq seq,
|
||||
const std::string& baseWorkingDir):
|
||||
AbstractCommand(cuid, req, requestGroup, e, s), sequence(seq),
|
||||
ftp(new FtpConnection(cuid, socket, req, e->option))
|
||||
{
|
||||
ftp->setBaseWorkingDir(baseWorkingDir);
|
||||
if(seq == SEQ_RECV_GREETING) {
|
||||
setTimeout(e->option->getAsInt(PREF_CONNECT_TIMEOUT));
|
||||
}
|
||||
|
@ -200,6 +203,33 @@ bool FtpNegotiationCommand::recvType() {
|
|||
if(status != 200) {
|
||||
throw DlAbortEx(StringFormat(EX_BAD_STATUS, status).str());
|
||||
}
|
||||
sequence = SEQ_SEND_PWD;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FtpNegotiationCommand::sendPwd()
|
||||
{
|
||||
if(ftp->sendPwd()) {
|
||||
disableWriteCheckSocket();
|
||||
sequence = SEQ_RECV_PWD;
|
||||
} else {
|
||||
setWriteCheckSocket(socket);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FtpNegotiationCommand::recvPwd()
|
||||
{
|
||||
std::string pwd;
|
||||
unsigned int status = ftp->receivePwdResponse(pwd);
|
||||
if(status == 0) {
|
||||
return false;
|
||||
}
|
||||
if(status != 257) {
|
||||
throw DlAbortEx(StringFormat(EX_BAD_STATUS, status).str());
|
||||
}
|
||||
ftp->setBaseWorkingDir(pwd);
|
||||
logger->info("CUID#%d - base working directory is '%s'", cuid, pwd.c_str());
|
||||
sequence = SEQ_SEND_CWD;
|
||||
return true;
|
||||
}
|
||||
|
@ -536,6 +566,10 @@ bool FtpNegotiationCommand::processSequence(const SegmentHandle& segment) {
|
|||
return sendType();
|
||||
case SEQ_RECV_TYPE:
|
||||
return recvType();
|
||||
case SEQ_SEND_PWD:
|
||||
return sendPwd();
|
||||
case SEQ_RECV_PWD:
|
||||
return recvPwd();
|
||||
case SEQ_SEND_CWD:
|
||||
return sendCwd();
|
||||
case SEQ_RECV_CWD:
|
||||
|
@ -582,7 +616,9 @@ void FtpNegotiationCommand::poolConnection() const
|
|||
e->option->getAsBool(PREF_FTP_REUSE_CONNECTION)) {
|
||||
std::pair<std::string, uint16_t> peerInfo;
|
||||
socket->getPeerInfo(peerInfo);
|
||||
e->poolSocket(peerInfo.first, peerInfo.second, socket);
|
||||
std::map<std::string, std::string> options;
|
||||
options["baseWorkingDir"] = ftp->getBaseWorkingDir();
|
||||
e->poolSocket(peerInfo.first, peerInfo.second, socket, options);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -52,6 +52,8 @@ public:
|
|||
SEQ_RECV_PASS,
|
||||
SEQ_SEND_TYPE,
|
||||
SEQ_RECV_TYPE,
|
||||
SEQ_SEND_PWD,
|
||||
SEQ_RECV_PWD,
|
||||
SEQ_SEND_CWD,
|
||||
SEQ_RECV_CWD,
|
||||
SEQ_SEND_MDTM,
|
||||
|
@ -83,6 +85,8 @@ private:
|
|||
bool recvPass();
|
||||
bool sendType();
|
||||
bool recvType();
|
||||
bool sendPwd();
|
||||
bool recvPwd();
|
||||
bool sendCwd();
|
||||
bool recvCwd();
|
||||
bool sendMdtm();
|
||||
|
@ -120,7 +124,8 @@ public:
|
|||
RequestGroup* requestGroup,
|
||||
DownloadEngine* e,
|
||||
const SharedHandle<SocketCore>& s,
|
||||
Seq seq = SEQ_RECV_GREETING);
|
||||
Seq seq = SEQ_RECV_GREETING,
|
||||
const std::string& baseWorkingDir = "/");
|
||||
virtual ~FtpNegotiationCommand();
|
||||
};
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "Request.h"
|
||||
#include "Option.h"
|
||||
#include "DlRetryEx.h"
|
||||
#include "DlAbortEx.h"
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
|
@ -18,6 +19,12 @@ class FtpConnectionTest:public CppUnit::TestFixture {
|
|||
CPPUNIT_TEST(testReceiveResponse_overflow);
|
||||
CPPUNIT_TEST(testSendMdtm);
|
||||
CPPUNIT_TEST(testReceiveMdtmResponse);
|
||||
CPPUNIT_TEST(testSendPwd);
|
||||
CPPUNIT_TEST(testReceivePwdResponse);
|
||||
CPPUNIT_TEST(testReceivePwdResponse_unquotedResponse);
|
||||
CPPUNIT_TEST(testReceivePwdResponse_badStatus);
|
||||
CPPUNIT_TEST(testSendCwd);
|
||||
CPPUNIT_TEST(testSendCwd_baseWorkingDir);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
private:
|
||||
SharedHandle<SocketCore> _serverSocket;
|
||||
|
@ -54,6 +61,12 @@ public:
|
|||
void testReceiveMdtmResponse();
|
||||
void testReceiveResponse();
|
||||
void testReceiveResponse_overflow();
|
||||
void testSendPwd();
|
||||
void testReceivePwdResponse();
|
||||
void testReceivePwdResponse_unquotedResponse();
|
||||
void testReceivePwdResponse_badStatus();
|
||||
void testSendCwd();
|
||||
void testSendCwd_baseWorkingDir();
|
||||
};
|
||||
|
||||
|
||||
|
@ -159,4 +172,69 @@ void FtpConnectionTest::testReceiveResponse_overflow()
|
|||
}
|
||||
}
|
||||
|
||||
void FtpConnectionTest::testSendPwd()
|
||||
{
|
||||
_ftp->sendPwd();
|
||||
char data[32];
|
||||
size_t len = sizeof(data);
|
||||
_serverSocket->readData(data, len);
|
||||
CPPUNIT_ASSERT_EQUAL((size_t)5, len);
|
||||
data[len] = '\0';
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("PWD\r\n"), std::string(data));
|
||||
}
|
||||
|
||||
void FtpConnectionTest::testReceivePwdResponse()
|
||||
{
|
||||
std::string pwd;
|
||||
_serverSocket->writeData("257 ");
|
||||
CPPUNIT_ASSERT_EQUAL((unsigned int)0, _ftp->receivePwdResponse(pwd));
|
||||
CPPUNIT_ASSERT(pwd.empty());
|
||||
_serverSocket->writeData("\"/dir/to\" is your directory.\r\n");
|
||||
CPPUNIT_ASSERT_EQUAL((unsigned int)257, _ftp->receivePwdResponse(pwd));
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("/dir/to"), pwd);
|
||||
}
|
||||
|
||||
void FtpConnectionTest::testReceivePwdResponse_unquotedResponse()
|
||||
{
|
||||
std::string pwd;
|
||||
_serverSocket->writeData("257 /dir/to\r\n");
|
||||
try {
|
||||
_ftp->receivePwdResponse(pwd);
|
||||
CPPUNIT_FAIL("exception must be thrown.");
|
||||
} catch(DlAbortEx& e) {
|
||||
// success
|
||||
}
|
||||
}
|
||||
|
||||
void FtpConnectionTest::testReceivePwdResponse_badStatus()
|
||||
{
|
||||
std::string pwd;
|
||||
_serverSocket->writeData("500 failed\r\n");
|
||||
CPPUNIT_ASSERT_EQUAL((unsigned int)500, _ftp->receivePwdResponse(pwd));
|
||||
CPPUNIT_ASSERT(pwd.empty());
|
||||
}
|
||||
|
||||
void FtpConnectionTest::testSendCwd()
|
||||
{
|
||||
_ftp->sendCwd();
|
||||
char data[32];
|
||||
size_t len = sizeof(data);
|
||||
_serverSocket->readData(data, len);
|
||||
CPPUNIT_ASSERT_EQUAL((size_t)10, len);
|
||||
data[len] = '\0';
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("CWD /dir\r\n"), std::string(data));
|
||||
}
|
||||
|
||||
void FtpConnectionTest::testSendCwd_baseWorkingDir()
|
||||
{
|
||||
_ftp->setBaseWorkingDir("/base");
|
||||
_ftp->sendCwd();
|
||||
char data[32];
|
||||
size_t len = sizeof(data);
|
||||
_serverSocket->readData(data, len);
|
||||
CPPUNIT_ASSERT_EQUAL((size_t)15, len);
|
||||
data[len] = '\0';
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("CWD /base/dir\r\n"), std::string(data));
|
||||
}
|
||||
|
||||
} // namespace aria2
|
||||
|
|
Loading…
Reference in New Issue