diff --git a/Net/include/Poco/Net/FTPClientSession.h b/Net/include/Poco/Net/FTPClientSession.h index de3c70a3f..1ae794b34 100644 --- a/Net/include/Poco/Net/FTPClientSession.h +++ b/Net/include/Poco/Net/FTPClientSession.h @@ -77,67 +77,72 @@ public: enum FileType { TYPE_TEXT, // TYPE A (ASCII) - TYPE_BINARY // TYPE I (Image) - }; - - FTPClientSession(); - /// Creates an FTPClientSession. - /// - /// Passive mode will be used for data transfers. + TYPE_BINARY // TYPE I (Image) + }; + + FTPClientSession(); + /// Creates an FTPClientSession. + /// + /// Passive mode will be used for data transfers. - explicit FTPClientSession(const StreamSocket& socket); - /// Creates an FTPClientSession using the given - /// connected socket for the control connection. - /// - /// Passive mode will be used for data transfers. - - FTPClientSession(const std::string& host, - Poco::UInt16 port = FTP_PORT, - const std::string& username = "", - const std::string& password = ""); - /// Creates an FTPClientSession using a socket connected - /// to the given host and port. If username is supplied, - /// login is attempted. - /// - /// Passive mode will be used for data transfers. - + explicit FTPClientSession(const StreamSocket& socket); + /// Creates an FTPClientSession using the given + /// connected socket for the control connection. + /// + /// Passive mode will be used for data transfers. + + FTPClientSession(const std::string& host, + Poco::UInt16 port = FTP_PORT, + const std::string& username = "", + const std::string& password = ""); + /// Creates an FTPClientSession using a socket connected + /// to the given host and port. If username is supplied, + /// login is attempted. + /// + /// Passive mode will be used for data transfers. + virtual ~FTPClientSession(); /// Destroys the FTPClientSession. void setTimeout(const Poco::Timespan& timeout); /// Sets the timeout for socket operations. - Poco::Timespan getTimeout() const; - /// Returns the timeout for socket operations. + Poco::Timespan getTimeout() const; + /// Returns the timeout for socket operations. - void setPassive(bool flag); - /// Enables (default) or disables FTP passive mode for this session. - - bool getPassive() const; - /// Returns true iff passive mode is enabled for this connection. - - void open(const std::string& host, - Poco::UInt16 port, - const std::string& username = "", - const std::string& password = ""); - /// Opens the FTP connection to the given host and port. - /// If username is supplied, login is attempted. + void setPassive(bool flag, bool useRFC1738 = true); + /// Enables (default) or disables FTP passive mode for this session. + /// + /// If useRFC1738 is true (the default), the RFC 1738 + /// EPSV command is used (with a fallback to PASV if EPSV fails) + /// for switching to passive mode. The same applies to + /// EPRT and PORT for active connections. + + bool getPassive() const; + /// Returns true iff passive mode is enabled for this connection. + + void open(const std::string& host, + Poco::UInt16 port, + const std::string& username = "", + const std::string& password = ""); + /// Opens the FTP connection to the given host and port. + /// If username is supplied, login is attempted. - void login(const std::string& username, const std::string& password); - /// Authenticates the user against the FTP server. Must be - /// called before any other commands (except QUIT) can be sent. + void login(const std::string& username, const std::string& password); + /// Authenticates the user against the FTP server. Must be + /// called before any other commands (except QUIT) can be sent. /// /// Sends a USER command followed by a PASS command with the /// respective arguments to the server. /// - /// Throws a FTPException in case of a FTP-specific error, or a - /// NetException in case of a general network communication failure. + /// Throws a FTPException in case of a FTP-specific error, or a + /// NetException in case of a general network communication failure. - void logout(); + void logout(); - void close(); - /// Sends a QUIT command and closes the connection to the server. - /// + void close(); + /// Sends a QUIT command and closes the connection to the server. + /// /// Throws a FTPException in case of a FTP-specific error, or a /// NetException in case of a general network communication failure. @@ -310,18 +315,18 @@ public: /// and waits for a response. int sendCommand(const std::string& command, const std::string& arg, std::string& response); - /// Sends the given command verbatim to the server - /// and waits for a response. + /// Sends the given command verbatim to the server + /// and waits for a response. - bool isOpen() const; - /// Returns true if the connection with FTP server is opened. + bool isOpen() const; + /// Returns true if the connection with FTP server is opened. - bool isLoggedIn() const; - /// Returns true if the session is logged in. + bool isLoggedIn() const; + /// Returns true if the session is logged in. protected: - enum StatusClass - { + enum StatusClass + { FTP_POSITIVE_PRELIMINARY = 1, FTP_POSITIVE_COMPLETION = 2, FTP_POSITIVE_INTERMEDIATE = 3, @@ -350,22 +355,22 @@ protected: void sendPASV(SocketAddress& addr); void parseAddress(const std::string& str, SocketAddress& addr); void parseExtAddress(const std::string& str, SocketAddress& addr); - void endTransfer(); - + void endTransfer(); + private: - FTPClientSession(const FTPClientSession&); - FTPClientSession& operator = (const FTPClientSession&); - - std::string _host; - Poco::UInt16 _port; - DialogSocket* _pControlSocket; - SocketStream* _pDataStream; - bool _passiveMode; - FileType _fileType; - bool _supports1738; - bool _serverReady; - bool _isLoggedIn; - Poco::Timespan _timeout; + FTPClientSession(const FTPClientSession&); + FTPClientSession& operator = (const FTPClientSession&); + + std::string _host; + Poco::UInt16 _port; + DialogSocket* _pControlSocket; + SocketStream* _pDataStream; + bool _passiveMode; + FileType _fileType; + bool _supports1738; + bool _serverReady; + bool _isLoggedIn; + Poco::Timespan _timeout; }; @@ -404,13 +409,13 @@ inline bool FTPClientSession::isPermanentNegative(int status) inline bool FTPClientSession::isOpen() const { - return _pControlSocket != 0; + return _pControlSocket != 0; } inline bool FTPClientSession::isLoggedIn() const { - return _isLoggedIn; + return _isLoggedIn; } diff --git a/Net/src/FTPClientSession.cpp b/Net/src/FTPClientSession.cpp index 9da9455ec..2e3b0fdfc 100644 --- a/Net/src/FTPClientSession.cpp +++ b/Net/src/FTPClientSession.cpp @@ -40,7 +40,7 @@ #include "Poco/Net/ServerSocket.h" #include "Poco/Net/NetException.h" #include "Poco/NumberFormatter.h" -#include +#include "Poco/Ascii.h" using Poco::NumberFormatter; @@ -51,83 +51,84 @@ namespace Net { FTPClientSession::FTPClientSession(): - _port(0), - _pControlSocket(0), - _pDataStream(0), - _passiveMode(true), - _fileType(TYPE_BINARY), - _supports1738(true), - _serverReady(false), - _isLoggedIn(false), - _timeout(DEFAULT_TIMEOUT) + _port(0), + _pControlSocket(0), + _pDataStream(0), + _passiveMode(true), + _fileType(TYPE_BINARY), + _supports1738(true), + _serverReady(false), + _isLoggedIn(false), + _timeout(DEFAULT_TIMEOUT) { } - + FTPClientSession::FTPClientSession(const StreamSocket& socket): - _host(socket.address().host().toString()), - _port(socket.address().port()), - _pControlSocket(new DialogSocket(socket)), - _pDataStream(0), - _passiveMode(true), - _fileType(TYPE_BINARY), - _supports1738(true), - _serverReady(false), - _isLoggedIn(false), - _timeout(DEFAULT_TIMEOUT) + _host(socket.address().host().toString()), + _port(socket.address().port()), + _pControlSocket(new DialogSocket(socket)), + _pDataStream(0), + _passiveMode(true), + _fileType(TYPE_BINARY), + _supports1738(true), + _serverReady(false), + _isLoggedIn(false), + _timeout(DEFAULT_TIMEOUT) { - _pControlSocket->setReceiveTimeout(_timeout); + _pControlSocket->setReceiveTimeout(_timeout); } - + FTPClientSession::FTPClientSession(const std::string& host, - Poco::UInt16 port, - const std::string& username, - const std::string& password): - _host(host), - _port(port), - _pControlSocket(new DialogSocket(SocketAddress(host, port))), - _pDataStream(0), - _passiveMode(true), - _fileType(TYPE_BINARY), - _supports1738(true), - _serverReady(false), - _isLoggedIn(false), - _timeout(DEFAULT_TIMEOUT) -{ - if (!username.empty()) - login(username, password); - else - _pControlSocket->setReceiveTimeout(_timeout); -} + Poco::UInt16 port, + const std::string& username, + const std::string& password): + _host(host), + _port(port), + _pControlSocket(new DialogSocket(SocketAddress(host, port))), + _pDataStream(0), + _passiveMode(true), + _fileType(TYPE_BINARY), + _supports1738(true), + _serverReady(false), + _isLoggedIn(false), + _timeout(DEFAULT_TIMEOUT) + { + if (!username.empty()) + login(username, password); + else + _pControlSocket->setReceiveTimeout(_timeout); + } FTPClientSession::~FTPClientSession() -{ - try { close(); } - catch (...) { } + { + try { close(); } + catch (...) { } } void FTPClientSession::setTimeout(const Poco::Timespan& timeout) { - if (!isOpen()) - throw FTPException("Connection is closed."); + if (!isOpen()) + throw FTPException("Connection is closed."); - _timeout = timeout; - _pControlSocket->setReceiveTimeout(timeout); + _timeout = timeout; + _pControlSocket->setReceiveTimeout(timeout); } - + Poco::Timespan FTPClientSession::getTimeout() const { return _timeout; } -void FTPClientSession::setPassive(bool flag) +void FTPClientSession::setPassive(bool flag, bool useRFC1738) { - _passiveMode = flag; + _passiveMode = flag; + _supports1738 = useRFC1738; } @@ -138,85 +139,85 @@ bool FTPClientSession::getPassive() const void FTPClientSession::open(const std::string& host, - Poco::UInt16 port, - const std::string& username, - const std::string& password) + Poco::UInt16 port, + const std::string& username, + const std::string& password) { - _host = host; - _port = port; - if (!username.empty()) - login(username, password); - else - { - _pControlSocket = new DialogSocket(SocketAddress(_host, _port)); - _pControlSocket->setReceiveTimeout(_timeout); - } + _host = host; + _port = port; + if (!username.empty()) + login(username, password); + else + { + _pControlSocket = new DialogSocket(SocketAddress(_host, _port)); + _pControlSocket->setReceiveTimeout(_timeout); + } } void FTPClientSession::login(const std::string& username, const std::string& password) { - if (_isLoggedIn) logout(); + if (_isLoggedIn) logout(); - int status = FTP_POSITIVE_COMPLETION * 100; - std::string response; - if (!_pControlSocket) - { - _pControlSocket = new DialogSocket(SocketAddress(_host, _port)); - _pControlSocket->setReceiveTimeout(_timeout); - } + int status = FTP_POSITIVE_COMPLETION * 100; + std::string response; + if (!_pControlSocket) + { + _pControlSocket = new DialogSocket(SocketAddress(_host, _port)); + _pControlSocket->setReceiveTimeout(_timeout); + } - if (!_serverReady) - { - status = _pControlSocket->receiveStatusMessage(response); - if (!isPositiveCompletion(status)) - throw FTPException("Cannot login to server", response); + if (!_serverReady) + { + status = _pControlSocket->receiveStatusMessage(response); + if (!isPositiveCompletion(status)) + throw FTPException("Cannot login to server", response, status); - _serverReady = true; - } + _serverReady = true; + } - status = sendCommand("USER", username, response); - if (isPositiveIntermediate(status)) - status = sendCommand("PASS", password, response); - if (!isPositiveCompletion(status)) - throw FTPException("Login denied", response); + status = sendCommand("USER", username, response); + if (isPositiveIntermediate(status)) + status = sendCommand("PASS", password, response); + if (!isPositiveCompletion(status)) + throw FTPException("Login denied", response, status); - setFileType(_fileType); - _isLoggedIn = true; + setFileType(_fileType); + _isLoggedIn = true; } void FTPClientSession::logout() -{ - if (!isOpen()) - throw FTPException("Connection is closed."); + { + if (!isOpen()) + throw FTPException("Connection is closed."); - if (_isLoggedIn) - { - try { endTransfer(); } - catch (...) { } - std::string response; - sendCommand("QUIT", response); - _isLoggedIn = false; - } + if (_isLoggedIn) + { + try { endTransfer(); } + catch (...) { } + std::string response; + sendCommand("QUIT", response); + _isLoggedIn = false; + } } void FTPClientSession::close() { - logout(); - _pControlSocket->close(); - delete _pControlSocket; - _pControlSocket = 0; - _serverReady = false; + logout(); + _pControlSocket->close(); + delete _pControlSocket; + _pControlSocket = 0; + _serverReady = false; } void FTPClientSession::setFileType(FTPClientSession::FileType type) { - std::string response; + std::string response; int status = sendCommand("TYPE", (type == TYPE_TEXT ? "A" : "I"), response); - if (!isPositiveCompletion(status)) throw FTPException("Cannot set file type", response); + if (!isPositiveCompletion(status)) throw FTPException("Cannot set file type", response, status); _fileType = type; } @@ -234,16 +235,16 @@ std::string FTPClientSession::systemType() if (isPositiveCompletion(status)) return response.substr(4); else - throw FTPException("Cannot get remote system type", response); + throw FTPException("Cannot get remote system type", response, status); } void FTPClientSession::setWorkingDirectory(const std::string& path) { - std::string response; - int status = sendCommand("CWD", path, response); - if (!isPositiveCompletion(status)) - throw FTPException("Cannot change directory", response); + std::string response; + int status = sendCommand("CWD", path, response); + if (!isPositiveCompletion(status)) + throw FTPException("Cannot change directory", response, status); } @@ -254,66 +255,66 @@ std::string FTPClientSession::getWorkingDirectory() if (isPositiveCompletion(status)) return extractPath(response); else - throw FTPException("Cannot get current working directory", response); + throw FTPException("Cannot get current working directory", response, status); } void FTPClientSession::cdup() { - std::string response; - int status = sendCommand("CDUP", response); - if (!isPositiveCompletion(status)) - throw FTPException("Cannot change directory", response); + std::string response; + int status = sendCommand("CDUP", response); + if (!isPositiveCompletion(status)) + throw FTPException("Cannot change directory", response, status); } - + void FTPClientSession::rename(const std::string& oldName, const std::string& newName) { - std::string response; - int status = sendCommand("RNFR", oldName, response); - if (!isPositiveIntermediate(status)) - throw FTPException(std::string("Cannot rename ") + oldName, response); - status = sendCommand("RNTO", newName, response); - if (!isPositiveCompletion(status)) - throw FTPException(std::string("Cannot rename to ") + newName, response); + std::string response; + int status = sendCommand("RNFR", oldName, response); + if (!isPositiveIntermediate(status)) + throw FTPException(std::string("Cannot rename ") + oldName, response, status); + status = sendCommand("RNTO", newName, response); + if (!isPositiveCompletion(status)) + throw FTPException(std::string("Cannot rename to ") + newName, response, status); } - + void FTPClientSession::remove(const std::string& path) { - std::string response; - int status = sendCommand("DELE", path, response); - if (!isPositiveCompletion(status)) - throw FTPException(std::string("Cannot remove " + path), response); + std::string response; + int status = sendCommand("DELE", path, response); + if (!isPositiveCompletion(status)) + throw FTPException(std::string("Cannot remove " + path), response, status); } void FTPClientSession::createDirectory(const std::string& path) { - std::string response; - int status = sendCommand("MKD", path, response); - if (!isPositiveCompletion(status)) - throw FTPException(std::string("Cannot create directory ") + path, response); + std::string response; + int status = sendCommand("MKD", path, response); + if (!isPositiveCompletion(status)) + throw FTPException(std::string("Cannot create directory ") + path, response, status); } void FTPClientSession::removeDirectory(const std::string& path) { - std::string response; - int status = sendCommand("RMD", path, response); - if (!isPositiveCompletion(status)) - throw FTPException(std::string("Cannot remove directory ") + path, response); + std::string response; + int status = sendCommand("RMD", path, response); + if (!isPositiveCompletion(status)) + throw FTPException(std::string("Cannot remove directory ") + path, response, status); } std::istream& FTPClientSession::beginDownload(const std::string& path) { - if (!isOpen()) - throw FTPException("Connection is closed."); + if (!isOpen()) + throw FTPException("Connection is closed."); - delete _pDataStream; - _pDataStream = 0; - _pDataStream = new SocketStream(establishDataConnection("RETR", path)); + delete _pDataStream; + _pDataStream = 0; + _pDataStream = new SocketStream(establishDataConnection("RETR", path)); return *_pDataStream; } @@ -323,15 +324,15 @@ void FTPClientSession::endDownload() endTransfer(); } - + std::ostream& FTPClientSession::beginUpload(const std::string& path) { - if (!isOpen()) - throw FTPException("Connection is closed."); + if (!isOpen()) + throw FTPException("Connection is closed."); - delete _pDataStream; - _pDataStream = 0; - _pDataStream = new SocketStream(establishDataConnection("STOR", path)); + delete _pDataStream; + _pDataStream = 0; + _pDataStream = new SocketStream(establishDataConnection("STOR", path)); return *_pDataStream; } @@ -344,12 +345,12 @@ void FTPClientSession::endUpload() std::istream& FTPClientSession::beginList(const std::string& path, bool extended) { - if (!isOpen()) - throw FTPException("Connection is closed."); + if (!isOpen()) + throw FTPException("Connection is closed."); - delete _pDataStream; - _pDataStream = 0; - _pDataStream = new SocketStream(establishDataConnection(extended ? "LIST" : "NLST", path)); + delete _pDataStream; + _pDataStream = 0; + _pDataStream = new SocketStream(establishDataConnection(extended ? "LIST" : "NLST", path)); return *_pDataStream; } @@ -359,39 +360,40 @@ void FTPClientSession::endList() endTransfer(); } - + void FTPClientSession::abort() { - if (!isOpen()) - throw FTPException("Connection is closed."); + if (!isOpen()) + throw FTPException("Connection is closed."); - _pControlSocket->sendByte(DialogSocket::TELNET_IP); - _pControlSocket->synch(); - std::string response; - int status = sendCommand("ABOR", response); - if (status == 426) - status = _pControlSocket->receiveStatusMessage(response); - if (status != 226) throw FTPException("Cannot abort transfer", response); + _pControlSocket->sendByte(DialogSocket::TELNET_IP); + _pControlSocket->synch(); + std::string response; + int status = sendCommand("ABOR", response); + if (status == 426) + status = _pControlSocket->receiveStatusMessage(response); + if (status != 226) + throw FTPException("Cannot abort transfer", response, status); } int FTPClientSession::sendCommand(const std::string& command, std::string& response) { - if (!isOpen()) - throw FTPException("Connection is closed."); + if (!isOpen()) + throw FTPException("Connection is closed."); - _pControlSocket->sendMessage(command); - return _pControlSocket->receiveStatusMessage(response); + _pControlSocket->sendMessage(command); + return _pControlSocket->receiveStatusMessage(response); } int FTPClientSession::sendCommand(const std::string& command, const std::string& arg, std::string& response) { - if (!isOpen()) - throw FTPException("Connection is closed."); + if (!isOpen()) + throw FTPException("Connection is closed."); - _pControlSocket->sendMessage(command, arg); - return _pControlSocket->receiveStatusMessage(response); + _pControlSocket->sendMessage(command, arg); + return _pControlSocket->receiveStatusMessage(response); } @@ -409,7 +411,7 @@ std::string FTPClientSession::extractPath(const std::string& response) if (*it == '"') { ++it; - if (it != end && *it != '"') break; + if (it == end || (it != end && *it != '"')) break; } path += *it++; } @@ -429,14 +431,15 @@ StreamSocket FTPClientSession::establishDataConnection(const std::string& comman StreamSocket FTPClientSession::activeDataConnection(const std::string& command, const std::string& arg) { - if (!isOpen()) - throw FTPException("Connection is closed."); + if (!isOpen()) + throw FTPException("Connection is closed."); - ServerSocket server(SocketAddress(_pControlSocket->address().host(), 0)); - sendPortCommand(server.address()); - std::string response; - int status = sendCommand(command, arg, response); - if (!isPositivePreliminary(status)) throw FTPException(command + " command failed", response); + ServerSocket server(SocketAddress(_pControlSocket->address().host(), 0)); + sendPortCommand(server.address()); + std::string response; + int status = sendCommand(command, arg, response); + if (!isPositivePreliminary(status)) + throw FTPException(command + " command failed", response, status); if (server.poll(_timeout, Socket::SELECT_READ)) return server.acceptConnection(); else @@ -450,7 +453,8 @@ StreamSocket FTPClientSession::passiveDataConnection(const std::string& command, StreamSocket sock(sa); std::string response; int status = sendCommand(command, arg, response); - if (!isPositivePreliminary(status)) throw FTPException(command + " command failed", response); + if (!isPositivePreliminary(status)) + throw FTPException(command + " command failed", response, status); return sock; } @@ -499,7 +503,7 @@ bool FTPClientSession::sendEPRT(const SocketAddress& addr) else if (isPermanentNegative(status)) return false; else - throw FTPException("EPRT command failed", response); + throw FTPException("EPRT command failed", response, status); } @@ -517,7 +521,8 @@ void FTPClientSession::sendPORT(const SocketAddress& addr) arg += NumberFormatter::format(port % 256); std::string response; int status = sendCommand("PORT", arg, response); - if (!isPositiveCompletion(status)) throw FTPException("PORT command failed", response); + if (!isPositiveCompletion(status)) + throw FTPException("PORT command failed", response, status); } @@ -534,7 +539,7 @@ bool FTPClientSession::sendEPSV(SocketAddress& addr) { return false; } - else throw FTPException("EPSV command failed", response); + else throw FTPException("EPSV command failed", response, status); } @@ -542,7 +547,8 @@ void FTPClientSession::sendPASV(SocketAddress& addr) { std::string response; int status = sendCommand("PASV", response); - if (!isPositiveCompletion(status)) throw FTPException("PASV command failed", response); + if (!isPositiveCompletion(status)) + throw FTPException("PASV command failed", response, status); parseAddress(response, addr); } @@ -554,19 +560,19 @@ void FTPClientSession::parseAddress(const std::string& str, SocketAddress& addr) while (it != end && *it != '(') ++it; if (it != end) ++it; std::string host; - while (it != end && std::isdigit(*it)) host += *it++; + while (it != end && Poco::Ascii::isDigit(*it)) host += *it++; if (it != end && *it == ',') { host += '.'; ++it; } - while (it != end && std::isdigit(*it)) host += *it++; + while (it != end && Poco::Ascii::isDigit(*it)) host += *it++; if (it != end && *it == ',') { host += '.'; ++it; } - while (it != end && std::isdigit(*it)) host += *it++; + while (it != end && Poco::Ascii::isDigit(*it)) host += *it++; if (it != end && *it == ',') { host += '.'; ++it; } - while (it != end && std::isdigit(*it)) host += *it++; + while (it != end && Poco::Ascii::isDigit(*it)) host += *it++; if (it != end && *it == ',') ++it; Poco::UInt16 portHi = 0; - while (it != end && std::isdigit(*it)) { portHi *= 10; portHi += *it++ - '0'; } + while (it != end && Poco::Ascii::isDigit(*it)) { portHi *= 10; portHi += *it++ - '0'; } if (it != end && *it == ',') ++it; Poco::UInt16 portLo = 0; - while (it != end && std::isdigit(*it)) { portLo *= 10; portLo += *it++ - '0'; } + while (it != end && Poco::Ascii::isDigit(*it)) { portLo *= 10; portLo += *it++ - '0'; } addr = SocketAddress(host, portHi*256 + portLo); } @@ -582,23 +588,21 @@ void FTPClientSession::parseExtAddress(const std::string& str, SocketAddress& ad if (it != end && *it == delim) ++it; if (it != end && *it == delim) ++it; Poco::UInt16 port = 0; - while (it != end && std::isdigit(*it)) { port *= 10; port += *it++ - '0'; } + while (it != end && Poco::Ascii::isDigit(*it)) { port *= 10; port += *it++ - '0'; } addr = SocketAddress(_pControlSocket->peerAddress().host(), port); } void FTPClientSession::endTransfer() { - if (!isOpen()) - throw FTPException("Connection is closed."); - if (_pDataStream) { delete _pDataStream; _pDataStream = 0; std::string response; int status = _pControlSocket->receiveStatusMessage(response); - if (!isPositiveCompletion(status)) throw FTPException("Data transfer failed", response); + if (!isPositiveCompletion(status)) + throw FTPException("Data transfer failed", response, status); } }