Merge pull request #107 from amousset/stream-timeout

feat(transport-smtp): Add timeout suppor to SMTP transport
This commit is contained in:
Alexis Mousset
2016-11-06 22:20:49 +01:00
committed by GitHub
3 changed files with 54 additions and 2 deletions

View File

@@ -7,9 +7,10 @@ use std::io;
use std::io::{BufRead, Read, Write}; use std::io::{BufRead, Read, Write};
use std::net::ToSocketAddrs; use std::net::ToSocketAddrs;
use std::string::String; use std::string::String;
use std::time::Duration;
use transport::smtp::{CRLF, MESSAGE_ENDING}; use transport::smtp::{CRLF, MESSAGE_ENDING};
use transport::smtp::authentication::Mechanism; use transport::smtp::authentication::Mechanism;
use transport::smtp::client::net::{Connector, NetworkStream}; use transport::smtp::client::net::{Connector, NetworkStream, Timeout};
use transport::smtp::error::{Error, SmtpResult}; use transport::smtp::error::{Error, SmtpResult};
use transport::smtp::response::ResponseParser; use transport::smtp::response::ResponseParser;
@@ -64,7 +65,7 @@ impl<S: Write + Read> Client<S> {
} }
} }
impl<S: Connector + Write + Read + Debug> Client<S> { impl<S: Connector + Timeout + Write + Read + Debug> Client<S> {
/// Closes the SMTP transaction if possible /// Closes the SMTP transaction if possible
pub fn close(&mut self) { pub fn close(&mut self) {
let _ = self.quit(); let _ = self.quit();
@@ -92,6 +93,18 @@ impl<S: Connector + Write + Read + Debug> Client<S> {
} }
} }
/// Set timeout
pub fn set_timeout(&mut self, duration: Option<Duration>) -> io::Result<()> {
match self.stream {
Some(ref mut stream) => {
try!(stream.get_mut().set_read_timeout(duration));
try!(stream.get_mut().set_read_timeout(duration));
Ok(())
}
None => Ok(()),
}
}
/// Connects to the configured server /// Connects to the configured server
pub fn connect<A: ToSocketAddrs>(&mut self, pub fn connect<A: ToSocketAddrs>(&mut self,
addr: &A, addr: &A,

View File

@@ -6,6 +6,7 @@ use std::fmt::{Debug, Formatter};
use std::io; use std::io;
use std::io::{ErrorKind, Read, Write}; use std::io::{ErrorKind, Read, Write};
use std::net::{SocketAddr, TcpStream}; use std::net::{SocketAddr, TcpStream};
use std::time::Duration;
/// A trait for the concept of opening a stream /// A trait for the concept of opening a stream
pub trait Connector: Sized { pub trait Connector: Sized {
@@ -97,3 +98,28 @@ impl Write for NetworkStream {
} }
} }
} }
/// A trait for read and write timeout support
pub trait Timeout: Sized {
/// Set read timeout for IO calls
fn set_read_timeout(&mut self, duration: Option<Duration>) -> io::Result<()>;
/// Set write timeout for IO calls
fn set_write_timeout(&mut self, duration: Option<Duration>) -> io::Result<()>;
}
impl Timeout for NetworkStream {
fn set_read_timeout(&mut self, duration: Option<Duration>) -> io::Result<()> {
match *self {
NetworkStream::Plain(ref mut stream) => stream.set_read_timeout(duration),
NetworkStream::Ssl(ref mut stream) => stream.get_mut().set_read_timeout(duration),
}
}
/// Set write tiemout for IO calls
fn set_write_timeout(&mut self, duration: Option<Duration>) -> io::Result<()> {
match *self {
NetworkStream::Plain(ref mut stream) => stream.set_write_timeout(duration),
NetworkStream::Ssl(ref mut stream) => stream.get_mut().set_write_timeout(duration),
}
}
}

View File

@@ -4,6 +4,7 @@ use email::SendableEmail;
use openssl::ssl::{SslContext, SslMethod}; use openssl::ssl::{SslContext, SslMethod};
use std::net::{SocketAddr, ToSocketAddrs}; use std::net::{SocketAddr, ToSocketAddrs};
use std::string::String; use std::string::String;
use std::time::Duration;
use transport::EmailTransport; use transport::EmailTransport;
use transport::smtp::authentication::Mechanism; use transport::smtp::authentication::Mechanism;
use transport::smtp::client::Client; use transport::smtp::client::Client;
@@ -85,6 +86,9 @@ pub struct SmtpTransportBuilder {
smtp_utf8: bool, smtp_utf8: bool,
/// Optional enforced authentication mechanism /// Optional enforced authentication mechanism
authentication_mechanism: Option<Mechanism>, authentication_mechanism: Option<Mechanism>,
/// Define network timeout
/// It can be changed later for specific needs (like a different timeout for each SMTP command)
timeout: Option<Duration>,
} }
/// Builder for the SMTP `SmtpTransport` /// Builder for the SMTP `SmtpTransport`
@@ -105,6 +109,7 @@ impl SmtpTransportBuilder {
connection_reuse: false, connection_reuse: false,
hello_name: "localhost".to_string(), hello_name: "localhost".to_string(),
authentication_mechanism: None, authentication_mechanism: None,
timeout: Some(Duration::new(60, 0)),
}) })
} }
None => Err(From::from("Could nor resolve hostname")), None => Err(From::from("Could nor resolve hostname")),
@@ -183,6 +188,12 @@ impl SmtpTransportBuilder {
self self
} }
/// Set the timeout duration
pub fn timeout(mut self, timeout: Option<Duration>) -> SmtpTransportBuilder {
self.timeout = timeout;
self
}
/// Build the SMTP client /// Build the SMTP client
/// ///
/// It does not connect to the server, but only creates the `SmtpTransport` /// It does not connect to the server, but only creates the `SmtpTransport`
@@ -297,6 +308,8 @@ impl EmailTransport<SmtpResult> for SmtpTransport {
_ => None, _ => None,
})); }));
try!(self.client.set_timeout(self.client_info.timeout));
// Log the connection // Log the connection
info!("connection established to {}", self.client_info.server_addr); info!("connection established to {}", self.client_info.server_addr);