Skip to content

Commit 2525847

Browse files
committed
Small additions based on PRs to the original fork
- Added function to get server welcome message. - Use the peer address when the server responds with all zeroes like is the case with IPv6. - Added some small tests for types - Make the test results clearer, using ? instead of asserting is_ok()
1 parent 17e31bf commit 2525847

File tree

3 files changed

+63
-21
lines changed

3 files changed

+63
-21
lines changed

src/ftp.rs

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
//! FTP module.
22
use std::borrow::Cow;
33
use std::net::SocketAddr;
4-
use std::str::FromStr;
54
use std::string::String;
65

76
use chrono::offset::TimeZone;
@@ -38,6 +37,7 @@ pub struct FtpStream {
3837
reader: BufReader<DataStream>,
3938
#[cfg(feature = "secure")]
4039
ssl_cfg: Option<(ClientConfig, DNSName)>,
40+
welcome_msg: Option<String>,
4141
}
4242

4343
impl FtpStream {
@@ -51,8 +51,10 @@ impl FtpStream {
5151
reader: BufReader::new(DataStream::Tcp(stream)),
5252
#[cfg(feature = "secure")]
5353
ssl_cfg: None,
54+
welcome_msg: None,
5455
};
55-
ftp_stream.read_response(status::READY).await?;
56+
let result = ftp_stream.read_response(status::READY).await?;
57+
ftp_stream.welcome_msg = Some(result.1);
5658

5759
Ok(ftp_stream)
5860
}
@@ -97,6 +99,7 @@ impl FtpStream {
9799
let mut secured_ftp_tream = FtpStream {
98100
reader: BufReader::new(DataStream::Ssl(stream)),
99101
ssl_cfg: Some((config, domain)),
102+
welcome_msg: None,
100103
};
101104
// Set protection buffer size
102105
secured_ftp_tream.write_str("PBSZ 0\r\n").await?;
@@ -140,6 +143,7 @@ impl FtpStream {
140143
let plain_ftp_stream = FtpStream {
141144
reader: BufReader::new(DataStream::Tcp(self.reader.into_inner().into_tcp_stream())),
142145
ssl_cfg: None,
146+
welcome_msg: None,
143147
};
144148
Ok(plain_ftp_stream)
145149
}
@@ -187,6 +191,11 @@ impl FtpStream {
187191
self.reader.get_ref().get_ref()
188192
}
189193

194+
/// Get welcome message from the server on connect.
195+
pub fn get_welcome_msg(&self) -> Option<&str> {
196+
self.welcome_msg.as_deref()
197+
}
198+
190199
/// Log in to the FTP server.
191200
pub async fn login(&mut self, user: &str, password: &str) -> Result<()> {
192201
self.write_str(format!("USER {}\r\n", user)).await?;
@@ -268,8 +277,18 @@ impl FtpStream {
268277
caps[6].parse::<u8>().unwrap(),
269278
);
270279
let port = ((msb as u16) << 8) + lsb as u16;
271-
let addr = format!("{}.{}.{}.{}:{}", oct1, oct2, oct3, oct4, port);
272-
SocketAddr::from_str(&addr).map_err(FtpError::InvalidAddress)
280+
281+
use std::net::{IpAddr, Ipv4Addr};
282+
283+
let ip = if (oct1, oct2, oct3, oct4) == (0, 0, 0, 0) {
284+
self.get_ref()
285+
.peer_addr()
286+
.map_err(FtpError::ConnectionError)?
287+
.ip()
288+
} else {
289+
IpAddr::V4(Ipv4Addr::new(oct1, oct2, oct3, oct4))
290+
};
291+
Ok(SocketAddr::new(ip, port))
273292
})
274293
}
275294

@@ -292,7 +311,9 @@ impl FtpStream {
292311
pub async fn restart_from(&mut self, offset: u64) -> Result<()> {
293312
let rest_command = format!("REST {}\r\n", offset.to_string());
294313
self.write_str(&rest_command).await?;
295-
self.read_response(status::REQUEST_FILE_PENDING).await.map(|_| ())
314+
self.read_response(status::REQUEST_FILE_PENDING)
315+
.await
316+
.map(|_| ())
296317
}
297318

298319
/// Retrieves the file name specified from the server.
@@ -302,11 +323,8 @@ impl FtpStream {
302323
pub async fn get(&mut self, file_name: &str) -> Result<BufReader<DataStream>> {
303324
let retr_command = format!("RETR {}\r\n", file_name);
304325
let data_stream = BufReader::new(self.data_command(&retr_command).await?);
305-
self.read_response_in(&[
306-
status::ABOUT_TO_SEND,
307-
status::ALREADY_OPEN
308-
])
309-
.await?;
326+
self.read_response_in(&[status::ABOUT_TO_SEND, status::ALREADY_OPEN])
327+
.await?;
310328
Ok(data_stream)
311329
}
312330

@@ -629,7 +647,7 @@ mod tests {
629647
#[tokio::test]
630648
async fn list_command_dos_newlines() {
631649
let data_stream = StreamReader::new(once(Ok::<_, std::io::Error>(
632-
b"Hello\r\nWorld\r\n\r\nBe\r\nHappy\r\n" as &[u8]
650+
b"Hello\r\nWorld\r\n\r\nBe\r\nHappy\r\n" as &[u8],
633651
)));
634652

635653
assert_eq!(
@@ -643,7 +661,9 @@ mod tests {
643661

644662
#[tokio::test]
645663
async fn list_command_unix_newlines() {
646-
let data_stream = StreamReader::new(once(Ok::<_, std::io::Error>(b"Hello\nWorld\n\nBe\nHappy\n" as &[u8])));
664+
let data_stream = StreamReader::new(once(Ok::<_, std::io::Error>(
665+
b"Hello\nWorld\n\nBe\nHappy\n" as &[u8],
666+
)));
647667

648668
assert_eq!(
649669
FtpStream::get_lines_from_stream(data_stream).await.unwrap(),

src/types.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,26 @@ impl Error for FtpError {
9292
}
9393
}
9494
}
95+
96+
#[cfg(test)]
97+
mod tests {
98+
99+
use super::*;
100+
101+
#[test]
102+
fn format_control_str() {
103+
assert_eq!(FormatControl::Default.to_string(), "N");
104+
assert_eq!(FormatControl::NonPrint.to_string(), "N");
105+
assert_eq!(FormatControl::Telnet.to_string(), "T");
106+
assert_eq!(FormatControl::Asa.to_string(), "C");
107+
}
108+
109+
#[test]
110+
fn file_type_str() {
111+
assert_eq!(FileType::Ascii(FormatControl::Default).to_string(), "A N");
112+
assert_eq!(FileType::Ebcdic(FormatControl::Asa).to_string(), "E C");
113+
assert_eq!(FileType::Image.to_string(), "I");
114+
assert_eq!(FileType::Binary.to_string(), "I");
115+
assert_eq!(FileType::Local(6).to_string(), "L 6");
116+
}
117+
}

tests/lib.rs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,22 @@ fn test_ftp() {
1515
// store a file
1616
let file_data = "test data\n";
1717
let mut reader = Cursor::new(file_data.as_bytes());
18-
assert!(ftp_stream.put("test_file.txt", &mut reader).await.is_ok());
18+
ftp_stream.put("test_file.txt", &mut reader).await?;
1919

2020
// retrieve file
21-
assert!(ftp_stream
21+
ftp_stream
2222
.simple_retr("test_file.txt")
2323
.await
24-
.map(|bytes| assert_eq!(bytes.into_inner(), file_data.as_bytes()))
25-
.is_ok());
24+
.map(|bytes| assert_eq!(bytes.into_inner(), file_data.as_bytes()))?;
2625

2726
// remove file
28-
assert!(ftp_stream.rm("test_file.txt").await.is_ok());
27+
ftp_stream.rm("test_file.txt").await?;
2928

3029
// cleanup: go up, remove folder, and quit
31-
assert!(ftp_stream.cdup().await.is_ok());
30+
ftp_stream.cdup().await?;
3231

33-
assert!(ftp_stream.rmdir("test_dir").await.is_ok());
34-
assert!(ftp_stream.quit().await.is_ok());
32+
ftp_stream.rmdir("test_dir").await?;
33+
ftp_stream.quit().await?;
3534

3635
Ok(())
3736
};
@@ -42,5 +41,5 @@ fn test_ftp() {
4241
.unwrap()
4342
.block_on(future);
4443

45-
assert!(result.is_ok());
44+
result.unwrap();
4645
}

0 commit comments

Comments
 (0)