Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add connect_timeout method for FtpStream #118

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 87 additions & 22 deletions src/ftp.rs
Original file line number Diff line number Diff line change
@@ -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).
Expand Down Expand Up @@ -68,6 +68,28 @@ impl FtpStream {
}
})
}
#[cfg(not(feature = "secure"))]
pub fn connect_timeout(
addr: &SocketAddr,
timeout: core::time::Duration,
) -> crate::Result<FtpStream> {
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"))]
Expand All @@ -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<FtpStream> {
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<A: ToSocketAddrs>(addr: A) -> crate::Result<FtpStream> {
Expand All @@ -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<FtpStream> {
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.
///
Expand Down Expand Up @@ -478,22 +543,22 @@ impl FtpStream {
/// # assert!(conn.rm("retr.txt").is_ok());
/// ```
pub fn retr<F, T>(&mut self, filename: &str, reader: F) -> crate::Result<T>
where
F: Fn(&mut dyn Read) -> crate::Result<T>,
where
F: Fn(&mut dyn Read) -> crate::Result<T>,
{
let retr_command = format!("RETR {}\r\n", filename);
{
let mut data_stream = BufReader::new(self.data_command(&retr_command)?);
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.
Expand All @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -593,7 +658,7 @@ impl FtpStream {
Err(_) => {
return Err(FtpError::InvalidResponse(String::from(
"Invalid lines in response",
)))
)));
}
},
None => break Ok(lines),
Expand Down