diff --git a/src/ftp.rs b/src/ftp.rs index 38526189..c7724079 100644 --- a/src/ftp.rs +++ b/src/ftp.rs @@ -1,27 +1,27 @@ //! FTP module. -use super::{ - data_stream::DataStream, - status, - types::{FileType, FtpError, Line}, -}; +#[cfg(all(feature = "secure", feature = "native-tls"))] +use native_tls::TlsConnector; use { - chrono::{offset::TimeZone, DateTime, Utc}, + chrono::{DateTime, offset::TimeZone, Utc}, regex::Regex, std::{ borrow::Cow, - io::{copy, BufRead, BufReader, BufWriter, Cursor, Read, Write}, + io::{BufRead, BufReader, BufWriter, copy, Cursor, Read, Write}, net::{SocketAddr, TcpStream, ToSocketAddrs}, str::FromStr, }, }; - -#[cfg(all(feature = "secure", feature = "native-tls"))] -use native_tls::TlsConnector; #[cfg(all(feature = "secure", not(feature = "native-tls")))] use openssl::ssl::{Ssl, SslContext}; +use super::{ + data_stream::DataStream, + status, + types::{FileType, FtpError, Line}, +}; + lazy_static! { // This regex extracts IP and Port details from PASV command response. // The regex looks for the pattern (h1,h2,h3,h4,p1,p2). @@ -68,6 +68,28 @@ impl FtpStream { } }) } + #[cfg(not(feature = "secure"))] + pub fn connect_timeout( + addr: &SocketAddr, + timeout: core::time::Duration, + ) -> crate::Result { + TcpStream::connect_timeout(addr, timeout) + .map_err(FtpError::ConnectionError) + .and_then(|stream| { + let mut ftp_stream = FtpStream { + reader: BufReader::new(DataStream::Tcp(stream)), + welcome_msg: None, + }; + + match ftp_stream.read_response(status::READY) { + Ok(response) => { + ftp_stream.welcome_msg = Some(response.1); + Ok(ftp_stream) + } + Err(err) => Err(err), + } + }) + } /// Creates an FTP Stream and returns the welcome message #[cfg(all(feature = "secure", feature = "native-tls"))] @@ -91,7 +113,28 @@ impl FtpStream { } }) } + #[cfg(all(feature = "secure", feature = "native-tls"))] + pub fn connect_timeout( + addr: &SocketAddr, timeout: core::time::Duration) -> crate::Result { + TcpStream::connect_timeout(addr, timeout) + .map_err(FtpError::ConnectionError) + .and_then(|stream| { + let mut ftp_stream = FtpStream { + reader: BufReader::new(DataStream::Tcp(stream)), + tls_ctx: None, + domain: None, + welcome_msg: None, + }; + match ftp_stream.read_response(status::READY) { + Ok(response) => { + ftp_stream.welcome_msg = Some(response.1); + Ok(ftp_stream) + } + Err(err) => Err(err), + } + }) + } /// Creates an FTP Stream and returns the welcome message #[cfg(all(feature = "secure", not(feature = "native-tls")))] pub fn connect(addr: A) -> crate::Result { @@ -114,6 +157,28 @@ impl FtpStream { }) } + #[cfg(all(feature = "secure", not(feature = "native-tls")))] + pub fn connect_timeout( + addr: &SocketAddr, timeout: core::time::Duration) -> crate::Result { + TcpStream::connect_timeout(addr, timeout) + .map_err(FtpError::ConnectionError) + .and_then(|stream| { + let mut ftp_stream = FtpStream { + reader: BufReader::new(DataStream::Tcp(stream)), + ssl_cfg: None, + welcome_msg: None, + }; + + match ftp_stream.read_response(status::READY) { + Ok(response) => { + ftp_stream.welcome_msg = Some(response.1); + Ok(ftp_stream) + } + Err(err) => Err(err), + } + }) + } + /// Switch to a secure mode if possible, using a provided SSL configuration. /// This method does nothing if the connect is already secured. /// @@ -478,8 +543,8 @@ impl FtpStream { /// # assert!(conn.rm("retr.txt").is_ok()); /// ``` pub fn retr(&mut self, filename: &str, reader: F) -> crate::Result - where - F: Fn(&mut dyn Read) -> crate::Result, + where + F: Fn(&mut dyn Read) -> crate::Result, { let retr_command = format!("RETR {}\r\n", filename); { @@ -487,13 +552,13 @@ impl FtpStream { self.read_response_in(&[status::ABOUT_TO_SEND, status::ALREADY_OPEN]) .and_then(|_| reader(&mut data_stream)) } - .and_then(|res| { - self.read_response_in(&[ - status::CLOSING_DATA_CONNECTION, - status::REQUESTED_FILE_ACTION_OK, - ]) - .map(|_| res) - }) + .and_then(|res| { + self.read_response_in(&[ + status::CLOSING_DATA_CONNECTION, + status::REQUESTED_FILE_ACTION_OK, + ]) + .map(|_| res) + }) } /// Simple way to retr a file from the server. This stores the file in memory. @@ -519,7 +584,7 @@ impl FtpStream { .map(|_| buffer) .map_err(FtpError::ConnectionError) }) - .map(Cursor::new) + .map(Cursor::new) } /// Removes the remote pathname from the server. @@ -559,7 +624,7 @@ impl FtpStream { status::CLOSING_DATA_CONNECTION, status::REQUESTED_FILE_ACTION_OK, ]) - .map(|_| ()) + .map(|_| ()) } /// Execute a command which returns list of strings in a separate stream @@ -593,7 +658,7 @@ impl FtpStream { Err(_) => { return Err(FtpError::InvalidResponse(String::from( "Invalid lines in response", - ))) + ))); } }, None => break Ok(lines),