Tokio 0.3 support (#485)

* Tokio 0.3 support

* Tokio 0.3 TLS support

* Tokio 0.3 sendmail transport

* Tokio 0.3 file transport

* Forgotten re-exports

* Tokio 0.3 examples

* fix tokio 0.2 file-transport

* It works
This commit is contained in:
Paolo Barbolini
2020-10-19 10:07:36 +02:00
committed by GitHub
parent 1ea562b15a
commit 697da9f7db
13 changed files with 488 additions and 48 deletions

View File

@@ -44,6 +44,10 @@ jobs:
with:
command: test
args: --features=tokio02
- uses: actions-rs/cargo@v1
with:
command: test
args: --features=tokio03
check:
name: Check

View File

@@ -58,6 +58,9 @@ async-trait = { version = "0.1", optional = true }
tokio02_crate = { package = "tokio", version = "0.2.7", features = ["fs", "process", "tcp", "dns", "io-util"], optional = true }
tokio02_native_tls_crate = { package = "tokio-native-tls", version = "0.1", optional = true }
tokio02_rustls = { package = "tokio-rustls", version = "0.14", optional = true }
tokio03_crate = { package = "tokio", version = "0.3", features = ["fs", "process", "net", "io-util"], optional = true }
tokio03_native_tls_crate = { package = "tokio-native-tls", version = "0.2", optional = true }
tokio03_rustls = { package = "tokio-rustls", version = "0.20", optional = true }
[dev-dependencies]
criterion = "0.3"
@@ -65,6 +68,7 @@ tracing-subscriber = "0.2.10"
glob = "0.3"
walkdir = "2"
tokio02_crate = { package = "tokio", version = "0.2.7", features = ["macros", "rt-threaded"] }
tokio03_crate = { package = "tokio", version = "0.3", features = ["macros", "rt-multi-thread"] }
[[bench]]
harness = false
@@ -87,6 +91,9 @@ async-std1 = ["async-std", "async-trait", "async-attributes"]
tokio02 = ["tokio02_crate", "async-trait", "futures-io", "futures-util"]
tokio02-native-tls = ["tokio02", "native-tls", "tokio02_native_tls_crate"]
tokio02-rustls-tls = ["tokio02", "rustls-tls", "tokio02_rustls"]
tokio03 = ["tokio03_crate", "async-trait", "futures-io", "futures-util"]
tokio03-native-tls = ["tokio03", "native-tls", "tokio03_native_tls_crate"]
tokio03-rustls-tls = ["tokio03", "rustls-tls", "tokio03_rustls"]
[package.metadata.docs.rs]
all-features = true
@@ -115,3 +122,12 @@ required-features = ["smtp-transport", "tokio02", "tokio02-native-tls"]
[[example]]
name = "tokio02_smtp_starttls"
required-features = ["smtp-transport", "tokio02", "tokio02-native-tls"]
[[example]]
name = "tokio03_smtp_tls"
required-features = ["smtp-transport", "tokio03", "tokio03-native-tls"]
[[example]]
name = "tokio03_smtp_starttls"
required-features = ["smtp-transport", "tokio03", "tokio03-native-tls"]

View File

@@ -0,0 +1,36 @@
// This line is only to make it compile from lettre's examples folder,
// since it uses Rust 2018 crate renaming to import tokio.
// Won't be needed in user's code.
use tokio03_crate as tokio;
use lettre::{
transport::smtp::authentication::Credentials, AsyncSmtpTransport, Message, Tokio03Connector,
Tokio03Transport,
};
#[tokio::main]
async fn main() {
tracing_subscriber::fmt::init();
let email = Message::builder()
.from("NoBody <nobody@domain.tld>".parse().unwrap())
.reply_to("Yuin <yuin@domain.tld>".parse().unwrap())
.to("Hei <hei@domain.tld>".parse().unwrap())
.subject("Happy new async year")
.body("Be happy with async!")
.unwrap();
let creds = Credentials::new("smtp_username".to_string(), "smtp_password".to_string());
// Open a remote connection to gmail using STARTTLS
let mailer = AsyncSmtpTransport::<Tokio03Connector>::starttls_relay("smtp.gmail.com")
.unwrap()
.credentials(creds)
.build();
// Send the email
match mailer.send(email).await {
Ok(_) => println!("Email sent successfully!"),
Err(e) => panic!("Could not send email: {:?}", e),
}
}

View File

@@ -0,0 +1,36 @@
// This line is only to make it compile from lettre's examples folder,
// since it uses Rust 2018 crate renaming to import tokio.
// Won't be needed in user's code.
use tokio03_crate as tokio;
use lettre::{
transport::smtp::authentication::Credentials, AsyncSmtpTransport, Message, Tokio03Connector,
Tokio03Transport,
};
#[tokio::main]
async fn main() {
tracing_subscriber::fmt::init();
let email = Message::builder()
.from("NoBody <nobody@domain.tld>".parse().unwrap())
.reply_to("Yuin <yuin@domain.tld>".parse().unwrap())
.to("Hei <hei@domain.tld>".parse().unwrap())
.subject("Happy new async year")
.body("Be happy with async!")
.unwrap();
let creds = Credentials::new("smtp_username".to_string(), "smtp_password".to_string());
// Open a remote connection to gmail
let mailer = AsyncSmtpTransport::<Tokio03Connector>::relay("smtp.gmail.com")
.unwrap()
.credentials(creds)
.build();
// Send the email
match mailer.send(email).await {
Ok(_) => println!("Email sent successfully!"),
Err(e) => panic!("Could not send email: {:?}", e),
}
}

View File

@@ -18,6 +18,9 @@
//! * **tokio02**: Allow to asyncronously send emails using tokio 0.2.x
//! * **tokio02-rustls-tls**: Async TLS support with the `rustls` crate using tokio 0.2
//! * **tokio02-native-tls**: Async TLS support with the `native-tls` crate using tokio 0.2
//! * **tokio03**: Allow to asyncronously send emails using tokio 0.3.x
//! * **tokio03-rustls-tls**: Async TLS support with the `rustls` crate using tokio 0.3
//! * **tokio03-native-tls**: Async TLS support with the `native-tls` crate using tokio 0.3
//! * **async-std1**: Allow to asyncronously send emails using async-std 1.x (SMTP isn't supported yet)
//! * **r2d2**: Connection pool for SMTP transport
//! * **tracing**: Logging using the `tracing` crate
@@ -61,12 +64,19 @@ pub use crate::transport::file::FileTransport;
pub use crate::transport::sendmail::SendmailTransport;
#[cfg(all(feature = "smtp-transport", feature = "connection-pool"))]
pub use crate::transport::smtp::r2d2::SmtpConnectionManager;
#[cfg(all(
feature = "smtp-transport",
any(feature = "tokio02", feature = "tokio03")
))]
pub use crate::transport::smtp::AsyncSmtpTransport;
#[cfg(feature = "smtp-transport")]
pub use crate::transport::smtp::SmtpTransport;
#[cfg(all(feature = "smtp-transport", feature = "tokio02"))]
pub use crate::transport::smtp::{AsyncSmtpTransport, Tokio02Connector};
pub use crate::transport::smtp::Tokio02Connector;
#[cfg(all(feature = "smtp-transport", feature = "tokio03"))]
pub use crate::transport::smtp::Tokio03Connector;
pub use crate::{address::Address, transport::stub::StubTransport};
#[cfg(any(feature = "async-std1", feature = "tokio02"))]
#[cfg(any(feature = "async-std1", feature = "tokio02", feature = "tokio03"))]
use async_trait::async_trait;
#[cfg(feature = "builder")]
use std::convert::TryFrom;
@@ -257,6 +267,29 @@ pub trait Tokio02Transport {
async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error>;
}
/// tokio 0.3.x based Transport method for emails
#[cfg(feature = "tokio03")]
#[cfg_attr(docsrs, doc(cfg(feature = "tokio03")))]
#[async_trait]
pub trait Tokio03Transport {
/// Response produced by the Transport
type Ok;
/// Error produced by the Transport
type Error;
/// Sends the email
#[cfg(feature = "builder")]
#[cfg_attr(docsrs, doc(cfg(feature = "builder")))]
// TODO take &Message
async fn send(&self, message: Message) -> Result<Self::Ok, Self::Error> {
let raw = message.formatted();
let envelope = message.envelope();
self.send_raw(&envelope, &raw).await
}
async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error>;
}
#[cfg(test)]
mod test {
use super::*;

View File

@@ -90,8 +90,10 @@ pub use self::error::Error;
use crate::AsyncStd1Transport;
#[cfg(feature = "tokio02")]
use crate::Tokio02Transport;
#[cfg(feature = "tokio03")]
use crate::Tokio03Transport;
use crate::{Envelope, Transport};
#[cfg(any(feature = "async-std1", feature = "tokio02"))]
#[cfg(any(feature = "async-std1", feature = "tokio02", feature = "tokio03"))]
use async_trait::async_trait;
use std::{
path::{Path, PathBuf},
@@ -199,3 +201,19 @@ impl Tokio02Transport for FileTransport {
Ok(email_id.to_string())
}
}
#[cfg(feature = "tokio03")]
#[async_trait]
impl Tokio03Transport for FileTransport {
type Ok = Id;
type Error = Error;
async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error> {
use tokio03_crate::fs;
let (email_id, file, serialized) = self.send_raw_impl(envelope, email)?;
fs::write(file, serialized).await?;
Ok(email_id.to_string())
}
}

View File

@@ -65,8 +65,10 @@ pub use self::error::Error;
use crate::AsyncStd1Transport;
#[cfg(feature = "tokio02")]
use crate::Tokio02Transport;
#[cfg(feature = "tokio03")]
use crate::Tokio03Transport;
use crate::{Envelope, Transport};
#[cfg(any(feature = "async-std1", feature = "tokio02"))]
#[cfg(any(feature = "async-std1", feature = "tokio02", feature = "tokio03"))]
use async_trait::async_trait;
use std::{
ffi::OsString,
@@ -125,6 +127,21 @@ impl SendmailTransport {
.stdout(Stdio::piped());
c
}
#[cfg(feature = "tokio03")]
fn tokio03_command(&self, envelope: &Envelope) -> tokio03_crate::process::Command {
use tokio03_crate::process::Command;
let mut c = Command::new(&self.command);
c.kill_on_drop(true);
c.arg("-i")
.arg("-f")
.arg(envelope.from().map(|f| f.as_ref()).unwrap_or("\"\""))
.args(envelope.to())
.stdin(Stdio::piped())
.stdout(Stdio::piped());
c
}
}
impl Default for SendmailTransport {
@@ -204,3 +221,28 @@ impl Tokio02Transport for SendmailTransport {
}
}
}
#[cfg(feature = "tokio03")]
#[async_trait]
impl Tokio03Transport for SendmailTransport {
type Ok = ();
type Error = Error;
async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error> {
use tokio03_crate::io::AsyncWriteExt;
let mut command = self.tokio03_command(envelope);
// Spawn the sendmail command
let mut process = command.spawn()?;
process.stdin.as_mut().unwrap().write_all(&email).await?;
let output = process.wait_with_output().await?;
if output.status.success() {
Ok(())
} else {
Err(Error::Client(String::from_utf8(output.stderr)?))
}
}
}

View File

@@ -1,11 +1,15 @@
use async_trait::async_trait;
#[cfg(feature = "tokio02")]
#[cfg(any(feature = "tokio02", feature = "tokio03"))]
use super::Tls;
use super::{
client::AsyncSmtpConnection, ClientId, Credentials, Error, Mechanism, Response, SmtpInfo,
};
use crate::{Envelope, Tokio02Transport};
use crate::Envelope;
#[cfg(feature = "tokio02")]
use crate::Tokio02Transport;
#[cfg(feature = "tokio03")]
use crate::Tokio03Transport;
#[allow(missing_debug_implementations)]
#[derive(Clone)]
@@ -14,6 +18,7 @@ pub struct AsyncSmtpTransport<C> {
inner: AsyncSmtpClient<C>,
}
#[cfg(feature = "tokio02")]
#[async_trait]
impl Tokio02Transport for AsyncSmtpTransport<Tokio02Connector> {
type Ok = Response;
@@ -31,6 +36,24 @@ impl Tokio02Transport for AsyncSmtpTransport<Tokio02Connector> {
}
}
#[cfg(feature = "tokio03")]
#[async_trait]
impl Tokio03Transport for AsyncSmtpTransport<Tokio03Connector> {
type Ok = Response;
type Error = Error;
/// Sends an email
async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error> {
let mut conn = self.inner.connection().await?;
let result = conn.send(envelope, email).await?;
conn.quit().await?;
Ok(result)
}
}
impl<C> AsyncSmtpTransport<C>
where
C: AsyncSmtpConnector,
@@ -41,11 +64,16 @@ where
///
/// Creates an encrypted transport over submissions port, using the provided domain
/// to validate TLS certificates.
#[cfg(any(feature = "tokio02-native-tls", feature = "tokio02-rustls-tls"))]
#[cfg(any(
feature = "tokio02-native-tls",
feature = "tokio02-rustls-tls",
feature = "tokio03-native-tls",
feature = "tokio03-rustls-tls"
))]
pub fn relay(relay: &str) -> Result<AsyncSmtpTransportBuilder, Error> {
use super::{TlsParameters, SUBMISSIONS_PORT};
let tls_parameters = TlsParameters::builder(relay.into()).build_tokio02()?;
let tls_parameters = TlsParameters::new(relay.into())?;
Ok(Self::builder_dangerous(relay)
.port(SUBMISSIONS_PORT)
@@ -63,7 +91,12 @@ where
///
/// An error is returned if the connection can't be upgraded. No credentials
/// or emails will be sent to the server, protecting from downgrade attacks.
#[cfg(any(feature = "tokio02-native-tls", feature = "tokio02-rustls-tls"))]
#[cfg(any(
feature = "tokio02-native-tls",
feature = "tokio02-rustls-tls",
feature = "tokio03-native-tls",
feature = "tokio03-rustls-tls"
))]
pub fn starttls_relay(relay: &str) -> Result<AsyncSmtpTransportBuilder, Error> {
use super::{TlsParameters, SUBMISSION_PORT};
@@ -133,7 +166,12 @@ impl AsyncSmtpTransportBuilder {
}
/// Set the TLS settings to use
#[cfg(any(feature = "tokio02-native-tls", feature = "tokio02-rustls-tls"))]
#[cfg(any(
feature = "tokio02-native-tls",
feature = "tokio02-rustls-tls",
feature = "tokio03-native-tls",
feature = "tokio03-rustls-tls"
))]
pub fn tls(mut self, tls: Tls) -> Self {
self.info.tls = tls;
self
@@ -235,6 +273,48 @@ impl AsyncSmtpConnector for Tokio02Connector {
}
}
#[derive(Debug, Copy, Clone, Default)]
#[cfg(feature = "tokio03")]
#[cfg_attr(docsrs, doc(cfg(feature = "tokio03")))]
pub struct Tokio03Connector;
#[async_trait]
#[cfg(feature = "tokio03")]
impl AsyncSmtpConnector for Tokio03Connector {
async fn connect(
hostname: &str,
port: u16,
hello_name: &ClientId,
tls: &Tls,
) -> Result<AsyncSmtpConnection, Error> {
#[allow(clippy::match_single_binding)]
let tls_parameters = match tls {
#[cfg(any(feature = "tokio03-native-tls", feature = "tokio03-rustls-tls"))]
Tls::Wrapper(ref tls_parameters) => Some(tls_parameters.clone()),
_ => None,
};
#[allow(unused_mut)]
let mut conn =
AsyncSmtpConnection::connect_tokio03(hostname, port, hello_name, tls_parameters)
.await?;
#[cfg(any(feature = "tokio03-native-tls", feature = "tokio03-rustls-tls"))]
match tls {
Tls::Opportunistic(ref tls_parameters) => {
if conn.can_starttls() {
conn.starttls(tls_parameters.clone(), hello_name).await?;
}
}
Tls::Required(ref tls_parameters) => {
conn.starttls(tls_parameters.clone(), hello_name).await?;
}
_ => (),
}
Ok(conn)
}
}
mod private {
use super::*;
@@ -242,4 +322,7 @@ mod private {
#[cfg(feature = "tokio02")]
impl Sealed for Tokio02Connector {}
#[cfg(feature = "tokio03")]
impl Sealed for Tokio03Connector {}
}

View File

@@ -45,11 +45,10 @@ impl AsyncSmtpConnection {
&self.server_info
}
// FIXME add simple connect and rename this one
/// Connects to the configured server
///
/// Sends EHLO and parses server information
#[cfg(feature = "tokio02")]
pub async fn connect_tokio02(
hostname: &str,
port: u16,
@@ -60,6 +59,20 @@ impl AsyncSmtpConnection {
Self::connect_impl(stream, hello_name).await
}
/// Connects to the configured server
///
/// Sends EHLO and parses server information
#[cfg(feature = "tokio03")]
pub async fn connect_tokio03(
hostname: &str,
port: u16,
hello_name: &ClientId,
tls_parameters: Option<TlsParameters>,
) -> Result<AsyncSmtpConnection, Error> {
let stream = AsyncNetworkStream::connect_tokio03(hostname, port, tls_parameters).await?;
Self::connect_impl(stream, hello_name).await
}
async fn connect_impl(
stream: AsyncNetworkStream,
hello_name: &ClientId,

View File

@@ -8,17 +8,30 @@ use std::{
use futures_io::{Error as IoError, ErrorKind, Result as IoResult};
#[cfg(feature = "tokio02")]
use tokio02_crate::io::{AsyncRead, AsyncWrite};
use tokio02_crate::io::{AsyncRead as _, AsyncWrite as _};
#[cfg(feature = "tokio02")]
use tokio02_crate::net::TcpStream;
use tokio02_crate::net::TcpStream as Tokio02TcpStream;
#[cfg(feature = "tokio03")]
use tokio03_crate::io::{AsyncRead as _, AsyncWrite as _, ReadBuf as Tokio03ReadBuf};
#[cfg(feature = "tokio03")]
use tokio03_crate::net::TcpStream as Tokio03TcpStream;
#[cfg(feature = "tokio02-native-tls")]
use tokio02_native_tls_crate::TlsStream;
use tokio02_native_tls_crate::TlsStream as Tokio02TlsStream;
#[cfg(feature = "tokio03-native-tls")]
use tokio03_native_tls_crate::TlsStream as Tokio03TlsStream;
#[cfg(feature = "tokio02-rustls-tls")]
use tokio02_rustls::client::TlsStream as RustlsTlsStream;
use tokio02_rustls::client::TlsStream as Tokio02RustlsTlsStream;
#[cfg(feature = "tokio03-rustls-tls")]
use tokio03_rustls::client::TlsStream as Tokio03RustlsTlsStream;
#[cfg(any(feature = "tokio02-native-tls", feature = "tokio02-rustls-tls"))]
#[cfg(any(
feature = "tokio02-native-tls",
feature = "tokio02-rustls-tls",
feature = "tokio03-native-tls",
feature = "tokio03-rustls-tls"
))]
use super::InnerTlsParameters;
use super::TlsParameters;
use crate::transport::smtp::Error;
@@ -31,15 +44,24 @@ pub struct AsyncNetworkStream {
/// Represents the different types of underlying network streams
#[allow(dead_code)]
enum InnerAsyncNetworkStream {
/// Plain TCP stream
/// Plain Tokio 0.2 TCP stream
#[cfg(feature = "tokio02")]
Tokio02Tcp(TcpStream),
/// Encrypted TCP stream
Tokio02Tcp(Tokio02TcpStream),
/// Encrypted Tokio 0.2 TCP stream
#[cfg(feature = "tokio02-native-tls")]
Tokio02NativeTls(TlsStream<TcpStream>),
/// Encrypted TCP stream
Tokio02NativeTls(Tokio02TlsStream<Tokio02TcpStream>),
/// Encrypted Tokio 0.2 TCP stream
#[cfg(feature = "tokio02-rustls-tls")]
Tokio02RustlsTls(Box<RustlsTlsStream<TcpStream>>),
Tokio02RustlsTls(Box<Tokio02RustlsTlsStream<Tokio02TcpStream>>),
/// Plain Tokio 0.3 TCP stream
#[cfg(feature = "tokio03")]
Tokio03Tcp(Tokio03TcpStream),
/// Encrypted Tokio 0.3 TCP stream
#[cfg(feature = "tokio03-native-tls")]
Tokio03NativeTls(Tokio03TlsStream<Tokio03TcpStream>),
/// Encrypted Tokio 0.3 TCP stream
#[cfg(feature = "tokio03-rustls-tls")]
Tokio03RustlsTls(Box<Tokio03RustlsTlsStream<Tokio03TcpStream>>),
/// Can't be built
None,
}
@@ -47,7 +69,7 @@ enum InnerAsyncNetworkStream {
impl AsyncNetworkStream {
fn new(inner: InnerAsyncNetworkStream) -> Self {
if let InnerAsyncNetworkStream::None = inner {
debug_assert!(false, "InnerAsyncNetworkStream::None should never be built");
debug_assert!(false, "InnerAsyncNetworkStream::None must never be built");
}
AsyncNetworkStream { inner }
@@ -64,11 +86,19 @@ impl AsyncNetworkStream {
}
#[cfg(feature = "tokio02-rustls-tls")]
InnerAsyncNetworkStream::Tokio02RustlsTls(ref s) => s.get_ref().0.peer_addr(),
#[cfg(feature = "tokio03")]
InnerAsyncNetworkStream::Tokio03Tcp(ref s) => s.peer_addr(),
#[cfg(feature = "tokio03-native-tls")]
InnerAsyncNetworkStream::Tokio03NativeTls(ref s) => {
s.get_ref().get_ref().get_ref().peer_addr()
}
#[cfg(feature = "tokio03-rustls-tls")]
InnerAsyncNetworkStream::Tokio03RustlsTls(ref s) => s.get_ref().0.peer_addr(),
InnerAsyncNetworkStream::None => {
debug_assert!(false, "InnerAsyncNetworkStream::None should never be built");
debug_assert!(false, "InnerAsyncNetworkStream::None must never be built");
Err(IoError::new(
ErrorKind::Other,
"InnerAsyncNetworkStream::None should never be built",
"InnerAsyncNetworkStream::None must never be built",
))
}
}
@@ -85,8 +115,16 @@ impl AsyncNetworkStream {
}
#[cfg(feature = "tokio02-rustls-tls")]
InnerAsyncNetworkStream::Tokio02RustlsTls(ref s) => s.get_ref().0.shutdown(how),
#[cfg(feature = "tokio03")]
InnerAsyncNetworkStream::Tokio03Tcp(ref s) => s.shutdown(how),
#[cfg(feature = "tokio03-native-tls")]
InnerAsyncNetworkStream::Tokio03NativeTls(ref s) => {
s.get_ref().get_ref().get_ref().shutdown(how)
}
#[cfg(feature = "tokio03-rustls-tls")]
InnerAsyncNetworkStream::Tokio03RustlsTls(ref s) => s.get_ref().0.shutdown(how),
InnerAsyncNetworkStream::None => {
debug_assert!(false, "InnerAsyncNetworkStream::None should never be built");
debug_assert!(false, "InnerAsyncNetworkStream::None must never be built");
Ok(())
}
}
@@ -98,7 +136,7 @@ impl AsyncNetworkStream {
port: u16,
tls_parameters: Option<TlsParameters>,
) -> Result<AsyncNetworkStream, Error> {
let tcp_stream = TcpStream::connect((hostname, port)).await?;
let tcp_stream = Tokio02TcpStream::connect((hostname, port)).await?;
let mut stream = AsyncNetworkStream::new(InnerAsyncNetworkStream::Tokio02Tcp(tcp_stream));
if let Some(tls_parameters) = tls_parameters {
@@ -107,9 +145,27 @@ impl AsyncNetworkStream {
Ok(stream)
}
#[cfg(feature = "tokio03")]
pub async fn connect_tokio03(
hostname: &str,
port: u16,
tls_parameters: Option<TlsParameters>,
) -> Result<AsyncNetworkStream, Error> {
let tcp_stream = Tokio03TcpStream::connect((hostname, port)).await?;
let mut stream = AsyncNetworkStream::new(InnerAsyncNetworkStream::Tokio03Tcp(tcp_stream));
if let Some(tls_parameters) = tls_parameters {
stream.upgrade_tls(tls_parameters).await?;
}
Ok(stream)
}
pub async fn upgrade_tls(&mut self, tls_parameters: TlsParameters) -> Result<(), Error> {
match &self.inner {
#[cfg(not(any(feature = "tokio02-native-tls", feature = "tokio02-rustls-tls")))]
#[cfg(all(
feature = "tokio02",
not(any(feature = "tokio02-native-tls", feature = "tokio02-rustls-tls"))
))]
InnerAsyncNetworkStream::Tokio02Tcp(_) => {
let _ = tls_parameters;
panic!("Trying to upgrade an AsyncNetworkStream without having enabled either the tokio02-native-tls or the tokio02-rustls-tls feature");
@@ -127,6 +183,27 @@ impl AsyncNetworkStream {
self.inner = Self::upgrade_tokio02_tls(tcp_stream, tls_parameters).await?;
Ok(())
}
#[cfg(all(
feature = "tokio03",
not(any(feature = "tokio03-native-tls", feature = "tokio03-rustls-tls"))
))]
InnerAsyncNetworkStream::Tokio03Tcp(_) => {
let _ = tls_parameters;
panic!("Trying to upgrade an AsyncNetworkStream without having enabled either the tokio03-native-tls or the tokio03-rustls-tls feature");
}
#[cfg(any(feature = "tokio03-native-tls", feature = "tokio03-rustls-tls"))]
InnerAsyncNetworkStream::Tokio03Tcp(_) => {
// get owned TcpStream
let tcp_stream = std::mem::replace(&mut self.inner, InnerAsyncNetworkStream::None);
let tcp_stream = match tcp_stream {
InnerAsyncNetworkStream::Tokio03Tcp(tcp_stream) => tcp_stream,
_ => unreachable!(),
};
self.inner = Self::upgrade_tokio03_tls(tcp_stream, tls_parameters).await?;
Ok(())
}
_ => Ok(()),
}
}
@@ -134,7 +211,7 @@ impl AsyncNetworkStream {
#[allow(unused_variables)]
#[cfg(any(feature = "tokio02-native-tls", feature = "tokio02-rustls-tls"))]
async fn upgrade_tokio02_tls(
tcp_stream: TcpStream,
tcp_stream: Tokio02TcpStream,
mut tls_parameters: TlsParameters,
) -> Result<InnerAsyncNetworkStream, Error> {
let domain = std::mem::take(&mut tls_parameters.domain);
@@ -173,6 +250,48 @@ impl AsyncNetworkStream {
}
}
#[allow(unused_variables)]
#[cfg(any(feature = "tokio03-native-tls", feature = "tokio03-rustls-tls"))]
async fn upgrade_tokio03_tls(
tcp_stream: Tokio03TcpStream,
mut tls_parameters: TlsParameters,
) -> Result<InnerAsyncNetworkStream, Error> {
let domain = std::mem::take(&mut tls_parameters.domain);
match tls_parameters.connector {
#[cfg(feature = "native-tls")]
InnerTlsParameters::NativeTls(connector) => {
#[cfg(not(feature = "tokio03-native-tls"))]
panic!("built without the tokio03-native-tls feature");
#[cfg(feature = "tokio03-native-tls")]
return {
use tokio03_native_tls_crate::TlsConnector;
let connector = TlsConnector::from(connector);
let stream = connector.connect(&domain, tcp_stream).await?;
Ok(InnerAsyncNetworkStream::Tokio03NativeTls(stream))
};
}
#[cfg(feature = "rustls-tls")]
InnerTlsParameters::RustlsTls(config) => {
#[cfg(not(feature = "tokio03-rustls-tls"))]
panic!("built without the tokio03-rustls-tls feature");
#[cfg(feature = "tokio03-rustls-tls")]
return {
use tokio03_rustls::{webpki::DNSNameRef, TlsConnector};
let domain = DNSNameRef::try_from_ascii_str(&domain)?;
let connector = TlsConnector::from(Arc::new(config));
let stream = connector.connect(domain, tcp_stream).await?;
Ok(InnerAsyncNetworkStream::Tokio03RustlsTls(Box::new(stream)))
};
}
}
}
pub fn is_encrypted(&self) -> bool {
match self.inner {
#[cfg(feature = "tokio02")]
@@ -181,6 +300,12 @@ impl AsyncNetworkStream {
InnerAsyncNetworkStream::Tokio02NativeTls(_) => true,
#[cfg(feature = "tokio02-rustls-tls")]
InnerAsyncNetworkStream::Tokio02RustlsTls(_) => true,
#[cfg(feature = "tokio03")]
InnerAsyncNetworkStream::Tokio03Tcp(_) => false,
#[cfg(feature = "tokio03-native-tls")]
InnerAsyncNetworkStream::Tokio03NativeTls(_) => true,
#[cfg(feature = "tokio03-rustls-tls")]
InnerAsyncNetworkStream::Tokio03RustlsTls(_) => true,
InnerAsyncNetworkStream::None => false,
}
}
@@ -199,8 +324,35 @@ impl futures_io::AsyncRead for AsyncNetworkStream {
InnerAsyncNetworkStream::Tokio02NativeTls(ref mut s) => Pin::new(s).poll_read(cx, buf),
#[cfg(feature = "tokio02-rustls-tls")]
InnerAsyncNetworkStream::Tokio02RustlsTls(ref mut s) => Pin::new(s).poll_read(cx, buf),
#[cfg(feature = "tokio03")]
InnerAsyncNetworkStream::Tokio03Tcp(ref mut s) => {
let mut b = Tokio03ReadBuf::new(buf);
match Pin::new(s).poll_read(cx, &mut b) {
Poll::Ready(Ok(())) => Poll::Ready(Ok(b.filled().len())),
Poll::Ready(Err(err)) => Poll::Ready(Err(err)),
Poll::Pending => Poll::Pending,
}
}
#[cfg(feature = "tokio03-native-tls")]
InnerAsyncNetworkStream::Tokio03NativeTls(ref mut s) => {
let mut b = Tokio03ReadBuf::new(buf);
match Pin::new(s).poll_read(cx, &mut b) {
Poll::Ready(Ok(())) => Poll::Ready(Ok(b.filled().len())),
Poll::Ready(Err(err)) => Poll::Ready(Err(err)),
Poll::Pending => Poll::Pending,
}
}
#[cfg(feature = "tokio03-rustls-tls")]
InnerAsyncNetworkStream::Tokio03RustlsTls(ref mut s) => {
let mut b = Tokio03ReadBuf::new(buf);
match Pin::new(s).poll_read(cx, &mut b) {
Poll::Ready(Ok(())) => Poll::Ready(Ok(b.filled().len())),
Poll::Ready(Err(err)) => Poll::Ready(Err(err)),
Poll::Pending => Poll::Pending,
}
}
InnerAsyncNetworkStream::None => {
debug_assert!(false, "InnerAsyncNetworkStream::None should never be built");
debug_assert!(false, "InnerAsyncNetworkStream::None must never be built");
Poll::Ready(Ok(0))
}
}
@@ -220,8 +372,14 @@ impl futures_io::AsyncWrite for AsyncNetworkStream {
InnerAsyncNetworkStream::Tokio02NativeTls(ref mut s) => Pin::new(s).poll_write(cx, buf),
#[cfg(feature = "tokio02-rustls-tls")]
InnerAsyncNetworkStream::Tokio02RustlsTls(ref mut s) => Pin::new(s).poll_write(cx, buf),
#[cfg(feature = "tokio03")]
InnerAsyncNetworkStream::Tokio03Tcp(ref mut s) => Pin::new(s).poll_write(cx, buf),
#[cfg(feature = "tokio03-native-tls")]
InnerAsyncNetworkStream::Tokio03NativeTls(ref mut s) => Pin::new(s).poll_write(cx, buf),
#[cfg(feature = "tokio03-rustls-tls")]
InnerAsyncNetworkStream::Tokio03RustlsTls(ref mut s) => Pin::new(s).poll_write(cx, buf),
InnerAsyncNetworkStream::None => {
debug_assert!(false, "InnerAsyncNetworkStream::None should never be built");
debug_assert!(false, "InnerAsyncNetworkStream::None must never be built");
Poll::Ready(Ok(0))
}
}
@@ -235,8 +393,14 @@ impl futures_io::AsyncWrite for AsyncNetworkStream {
InnerAsyncNetworkStream::Tokio02NativeTls(ref mut s) => Pin::new(s).poll_flush(cx),
#[cfg(feature = "tokio02-rustls-tls")]
InnerAsyncNetworkStream::Tokio02RustlsTls(ref mut s) => Pin::new(s).poll_flush(cx),
#[cfg(feature = "tokio03")]
InnerAsyncNetworkStream::Tokio03Tcp(ref mut s) => Pin::new(s).poll_flush(cx),
#[cfg(feature = "tokio03-native-tls")]
InnerAsyncNetworkStream::Tokio03NativeTls(ref mut s) => Pin::new(s).poll_flush(cx),
#[cfg(feature = "tokio03-rustls-tls")]
InnerAsyncNetworkStream::Tokio03RustlsTls(ref mut s) => Pin::new(s).poll_flush(cx),
InnerAsyncNetworkStream::None => {
debug_assert!(false, "InnerAsyncNetworkStream::None should never be built");
debug_assert!(false, "InnerAsyncNetworkStream::None must never be built");
Poll::Ready(Ok(()))
}
}

View File

@@ -24,9 +24,9 @@
#[cfg(feature = "serde")]
use std::fmt::Debug;
#[cfg(feature = "tokio02")]
#[cfg(any(feature = "tokio02", feature = "tokio03"))]
pub(crate) use self::async_connection::AsyncSmtpConnection;
#[cfg(feature = "tokio02")]
#[cfg(any(feature = "tokio02", feature = "tokio03"))]
pub(crate) use self::async_net::AsyncNetworkStream;
use self::net::NetworkStream;
#[cfg(any(feature = "native-tls", feature = "rustls-tls"))]
@@ -37,9 +37,9 @@ pub use self::{
tls::{Certificate, Tls, TlsParameters, TlsParametersBuilder},
};
#[cfg(feature = "tokio02")]
#[cfg(any(feature = "tokio02", feature = "tokio03"))]
mod async_connection;
#[cfg(feature = "tokio02")]
#[cfg(any(feature = "tokio02", feature = "tokio03"))]
mod async_net;
mod connection;
mod mock;

View File

@@ -126,15 +126,6 @@ impl TlsParametersBuilder {
return self.build_rustls();
}
#[cfg(any(feature = "tokio02-native-tls", feature = "tokio02-rustls-tls"))]
pub(crate) fn build_tokio02(self) -> Result<TlsParameters, Error> {
#[cfg(feature = "tokio02-native-tls")]
return self.build_native();
#[cfg(not(feature = "tokio02-native-tls"))]
return self.build_rustls();
}
/// Creates a new `TlsParameters` using native-tls with the provided configuration
#[cfg(feature = "native-tls")]
#[cfg_attr(docsrs, doc(cfg(feature = "native-tls")))]

View File

@@ -155,8 +155,12 @@
//!
#[cfg(feature = "tokio02")]
pub use self::async_transport::Tokio02Connector;
#[cfg(feature = "tokio03")]
pub use self::async_transport::Tokio03Connector;
#[cfg(any(feature = "tokio02", feature = "tokio03"))]
pub use self::async_transport::{
AsyncSmtpConnector, AsyncSmtpTransport, AsyncSmtpTransportBuilder, Tokio02Connector,
AsyncSmtpConnector, AsyncSmtpTransport, AsyncSmtpTransportBuilder,
};
#[cfg(feature = "r2d2")]
pub use self::pool::PoolConfig;
@@ -176,7 +180,7 @@ use crate::transport::smtp::{
use client::Tls;
use std::time::Duration;
#[cfg(feature = "tokio02")]
#[cfg(any(feature = "tokio02", feature = "tokio03"))]
mod async_transport;
pub mod authentication;
pub mod client;