mirror of
https://github.com/chatmail/core.git
synced 2026-05-20 23:36:30 +03:00
refactor: replace {IMAP,SMTP,HTTP}_TIMEOUT with a single constant
This change also increases HTTP timeout from 30 seconds to 60 seconds.
This commit is contained in:
@@ -1,7 +1,4 @@
|
|||||||
use std::{
|
use std::ops::{Deref, DerefMut};
|
||||||
ops::{Deref, DerefMut},
|
|
||||||
time::Duration,
|
|
||||||
};
|
|
||||||
|
|
||||||
use anyhow::{Context as _, Result};
|
use anyhow::{Context as _, Result};
|
||||||
use async_imap::Client as ImapClient;
|
use async_imap::Client as ImapClient;
|
||||||
@@ -17,9 +14,6 @@ use crate::net::{connect_starttls_imap, connect_tcp, connect_tls};
|
|||||||
use crate::socks::Socks5Config;
|
use crate::socks::Socks5Config;
|
||||||
use fast_socks5::client::Socks5Stream;
|
use fast_socks5::client::Socks5Stream;
|
||||||
|
|
||||||
/// IMAP connection, write and read timeout.
|
|
||||||
pub(crate) const IMAP_TIMEOUT: Duration = Duration::from_secs(60);
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct Client {
|
pub(crate) struct Client {
|
||||||
inner: ImapClient<Box<dyn SessionStream>>,
|
inner: ImapClient<Box<dyn SessionStream>>,
|
||||||
@@ -104,8 +98,7 @@ impl Client {
|
|||||||
port: u16,
|
port: u16,
|
||||||
strict_tls: bool,
|
strict_tls: bool,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
let tls_stream =
|
let tls_stream = connect_tls(context, hostname, port, strict_tls, "imap").await?;
|
||||||
connect_tls(context, hostname, port, IMAP_TIMEOUT, strict_tls, "imap").await?;
|
|
||||||
let buffered_stream = BufWriter::new(tls_stream);
|
let buffered_stream = BufWriter::new(tls_stream);
|
||||||
let session_stream: Box<dyn SessionStream> = Box::new(buffered_stream);
|
let session_stream: Box<dyn SessionStream> = Box::new(buffered_stream);
|
||||||
let mut client = Client::new(session_stream);
|
let mut client = Client::new(session_stream);
|
||||||
@@ -117,7 +110,7 @@ impl Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn connect_insecure(context: &Context, hostname: &str, port: u16) -> Result<Self> {
|
pub async fn connect_insecure(context: &Context, hostname: &str, port: u16) -> Result<Self> {
|
||||||
let tcp_stream = connect_tcp(context, hostname, port, IMAP_TIMEOUT, false).await?;
|
let tcp_stream = connect_tcp(context, hostname, port, false).await?;
|
||||||
let buffered_stream = BufWriter::new(tcp_stream);
|
let buffered_stream = BufWriter::new(tcp_stream);
|
||||||
let session_stream: Box<dyn SessionStream> = Box::new(buffered_stream);
|
let session_stream: Box<dyn SessionStream> = Box::new(buffered_stream);
|
||||||
let mut client = Client::new(session_stream);
|
let mut client = Client::new(session_stream);
|
||||||
@@ -134,8 +127,7 @@ impl Client {
|
|||||||
port: u16,
|
port: u16,
|
||||||
strict_tls: bool,
|
strict_tls: bool,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
let tls_stream =
|
let tls_stream = connect_starttls_imap(context, hostname, port, strict_tls).await?;
|
||||||
connect_starttls_imap(context, hostname, port, IMAP_TIMEOUT, strict_tls).await?;
|
|
||||||
|
|
||||||
let buffered_stream = BufWriter::new(tls_stream);
|
let buffered_stream = BufWriter::new(tls_stream);
|
||||||
let session_stream: Box<dyn SessionStream> = Box::new(buffered_stream);
|
let session_stream: Box<dyn SessionStream> = Box::new(buffered_stream);
|
||||||
@@ -151,7 +143,7 @@ impl Client {
|
|||||||
socks5_config: Socks5Config,
|
socks5_config: Socks5Config,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
let socks5_stream = socks5_config
|
let socks5_stream = socks5_config
|
||||||
.connect(context, domain, port, IMAP_TIMEOUT, strict_tls)
|
.connect(context, domain, port, strict_tls)
|
||||||
.await?;
|
.await?;
|
||||||
let tls_stream = wrap_tls(strict_tls, domain, "imap", socks5_stream).await?;
|
let tls_stream = wrap_tls(strict_tls, domain, "imap", socks5_stream).await?;
|
||||||
let buffered_stream = BufWriter::new(tls_stream);
|
let buffered_stream = BufWriter::new(tls_stream);
|
||||||
@@ -170,9 +162,7 @@ impl Client {
|
|||||||
port: u16,
|
port: u16,
|
||||||
socks5_config: Socks5Config,
|
socks5_config: Socks5Config,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
let socks5_stream = socks5_config
|
let socks5_stream = socks5_config.connect(context, domain, port, false).await?;
|
||||||
.connect(context, domain, port, IMAP_TIMEOUT, false)
|
|
||||||
.await?;
|
|
||||||
let buffered_stream = BufWriter::new(socks5_stream);
|
let buffered_stream = BufWriter::new(socks5_stream);
|
||||||
let session_stream: Box<dyn SessionStream> = Box::new(buffered_stream);
|
let session_stream: Box<dyn SessionStream> = Box::new(buffered_stream);
|
||||||
let mut client = Client::new(session_stream);
|
let mut client = Client::new(session_stream);
|
||||||
@@ -191,7 +181,7 @@ impl Client {
|
|||||||
strict_tls: bool,
|
strict_tls: bool,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
let socks5_stream = socks5_config
|
let socks5_stream = socks5_config
|
||||||
.connect(context, hostname, port, IMAP_TIMEOUT, strict_tls)
|
.connect(context, hostname, port, strict_tls)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// Run STARTTLS command and convert the client back into a stream.
|
// Run STARTTLS command and convert the client back into a stream.
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ use tokio::time::timeout;
|
|||||||
use super::session::Session;
|
use super::session::Session;
|
||||||
use super::Imap;
|
use super::Imap;
|
||||||
use crate::context::Context;
|
use crate::context::Context;
|
||||||
use crate::imap::{client::IMAP_TIMEOUT, FolderMeaning};
|
use crate::imap::FolderMeaning;
|
||||||
|
use crate::net::TIMEOUT;
|
||||||
use crate::tools::{self, time_elapsed};
|
use crate::tools::{self, time_elapsed};
|
||||||
|
|
||||||
/// Timeout after which IDLE is finished
|
/// Timeout after which IDLE is finished
|
||||||
@@ -51,7 +52,7 @@ impl Session {
|
|||||||
|
|
||||||
// At this point IDLE command was sent and we received a "+ idling" response. We will now
|
// At this point IDLE command was sent and we received a "+ idling" response. We will now
|
||||||
// read from the stream without getting any data for up to `IDLE_TIMEOUT`. If we don't
|
// read from the stream without getting any data for up to `IDLE_TIMEOUT`. If we don't
|
||||||
// disable read timeout, we would get a timeout after `IMAP_TIMEOUT`, which is a lot
|
// disable read timeout, we would get a timeout after `crate::net::TIMEOUT`, which is a lot
|
||||||
// shorter than `IDLE_TIMEOUT`.
|
// shorter than `IDLE_TIMEOUT`.
|
||||||
handle.as_mut().set_read_timeout(None);
|
handle.as_mut().set_read_timeout(None);
|
||||||
let (idle_wait, interrupt) = handle.wait_with_timeout(IDLE_TIMEOUT);
|
let (idle_wait, interrupt) = handle.wait_with_timeout(IDLE_TIMEOUT);
|
||||||
@@ -93,7 +94,7 @@ impl Session {
|
|||||||
.await
|
.await
|
||||||
.with_context(|| format!("{folder}: IMAP IDLE protocol timed out"))?
|
.with_context(|| format!("{folder}: IMAP IDLE protocol timed out"))?
|
||||||
.with_context(|| format!("{folder}: IMAP IDLE failed"))?;
|
.with_context(|| format!("{folder}: IMAP IDLE failed"))?;
|
||||||
session.as_mut().set_read_timeout(Some(IMAP_TIMEOUT));
|
session.as_mut().set_read_timeout(Some(TIMEOUT));
|
||||||
self.inner = session;
|
self.inner = session;
|
||||||
|
|
||||||
// Fetch mail once we exit IDLE.
|
// Fetch mail once we exit IDLE.
|
||||||
|
|||||||
53
src/net.rs
53
src/net.rs
@@ -22,16 +22,18 @@ use dns::lookup_host_with_cache;
|
|||||||
pub use http::{read_url, read_url_blob, Response as HttpResponse};
|
pub use http::{read_url, read_url_blob, Response as HttpResponse};
|
||||||
use tls::wrap_tls;
|
use tls::wrap_tls;
|
||||||
|
|
||||||
|
/// Connection, write and read timeout.
|
||||||
|
///
|
||||||
|
/// This constant should be more than the largest expected RTT.
|
||||||
|
pub(crate) const TIMEOUT: Duration = Duration::from_secs(60);
|
||||||
|
|
||||||
/// Returns a TCP connection stream with read/write timeouts set
|
/// Returns a TCP connection stream with read/write timeouts set
|
||||||
/// and Nagle's algorithm disabled with `TCP_NODELAY`.
|
/// and Nagle's algorithm disabled with `TCP_NODELAY`.
|
||||||
///
|
///
|
||||||
/// `TCP_NODELAY` ensures writing to the stream always results in immediate sending of the packet
|
/// `TCP_NODELAY` ensures writing to the stream always results in immediate sending of the packet
|
||||||
/// to the network, which is important to reduce the latency of interactive protocols such as IMAP.
|
/// to the network, which is important to reduce the latency of interactive protocols such as IMAP.
|
||||||
async fn connect_tcp_inner(
|
async fn connect_tcp_inner(addr: SocketAddr) -> Result<Pin<Box<TimeoutStream<TcpStream>>>> {
|
||||||
addr: SocketAddr,
|
let tcp_stream = timeout(TIMEOUT, TcpStream::connect(addr))
|
||||||
timeout_val: Duration,
|
|
||||||
) -> Result<Pin<Box<TimeoutStream<TcpStream>>>> {
|
|
||||||
let tcp_stream = timeout(timeout_val, TcpStream::connect(addr))
|
|
||||||
.await
|
.await
|
||||||
.context("connection timeout")?
|
.context("connection timeout")?
|
||||||
.context("connection failure")?;
|
.context("connection failure")?;
|
||||||
@@ -40,8 +42,8 @@ async fn connect_tcp_inner(
|
|||||||
tcp_stream.set_nodelay(true)?;
|
tcp_stream.set_nodelay(true)?;
|
||||||
|
|
||||||
let mut timeout_stream = TimeoutStream::new(tcp_stream);
|
let mut timeout_stream = TimeoutStream::new(tcp_stream);
|
||||||
timeout_stream.set_write_timeout(Some(timeout_val));
|
timeout_stream.set_write_timeout(Some(TIMEOUT));
|
||||||
timeout_stream.set_read_timeout(Some(timeout_val));
|
timeout_stream.set_read_timeout(Some(TIMEOUT));
|
||||||
|
|
||||||
Ok(Box::pin(timeout_stream))
|
Ok(Box::pin(timeout_stream))
|
||||||
}
|
}
|
||||||
@@ -50,12 +52,11 @@ async fn connect_tcp_inner(
|
|||||||
/// given the result of the hostname to address resolution.
|
/// given the result of the hostname to address resolution.
|
||||||
async fn connect_tls_inner(
|
async fn connect_tls_inner(
|
||||||
addr: SocketAddr,
|
addr: SocketAddr,
|
||||||
timeout_val: Duration,
|
|
||||||
host: &str,
|
host: &str,
|
||||||
strict_tls: bool,
|
strict_tls: bool,
|
||||||
alpn: &str,
|
alpn: &str,
|
||||||
) -> Result<TlsStream<Pin<Box<TimeoutStream<TcpStream>>>>> {
|
) -> Result<TlsStream<Pin<Box<TimeoutStream<TcpStream>>>>> {
|
||||||
let tcp_stream = connect_tcp_inner(addr, timeout_val).await?;
|
let tcp_stream = connect_tcp_inner(addr).await?;
|
||||||
let tls_stream = wrap_tls(strict_tls, host, alpn, tcp_stream).await?;
|
let tls_stream = wrap_tls(strict_tls, host, alpn, tcp_stream).await?;
|
||||||
Ok(tls_stream)
|
Ok(tls_stream)
|
||||||
}
|
}
|
||||||
@@ -70,15 +71,12 @@ pub(crate) async fn connect_tcp(
|
|||||||
context: &Context,
|
context: &Context,
|
||||||
host: &str,
|
host: &str,
|
||||||
port: u16,
|
port: u16,
|
||||||
timeout_val: Duration,
|
|
||||||
load_cache: bool,
|
load_cache: bool,
|
||||||
) -> Result<Pin<Box<TimeoutStream<TcpStream>>>> {
|
) -> Result<Pin<Box<TimeoutStream<TcpStream>>>> {
|
||||||
let mut first_error = None;
|
let mut first_error = None;
|
||||||
|
|
||||||
for resolved_addr in
|
for resolved_addr in lookup_host_with_cache(context, host, port, load_cache).await? {
|
||||||
lookup_host_with_cache(context, host, port, timeout_val, load_cache).await?
|
match connect_tcp_inner(resolved_addr).await {
|
||||||
{
|
|
||||||
match connect_tcp_inner(resolved_addr, timeout_val).await {
|
|
||||||
Ok(stream) => {
|
Ok(stream) => {
|
||||||
return Ok(stream);
|
return Ok(stream);
|
||||||
}
|
}
|
||||||
@@ -99,16 +97,13 @@ pub(crate) async fn connect_tls(
|
|||||||
context: &Context,
|
context: &Context,
|
||||||
host: &str,
|
host: &str,
|
||||||
port: u16,
|
port: u16,
|
||||||
timeout_val: Duration,
|
|
||||||
strict_tls: bool,
|
strict_tls: bool,
|
||||||
alpn: &str,
|
alpn: &str,
|
||||||
) -> Result<TlsStream<Pin<Box<TimeoutStream<TcpStream>>>>> {
|
) -> Result<TlsStream<Pin<Box<TimeoutStream<TcpStream>>>>> {
|
||||||
let mut first_error = None;
|
let mut first_error = None;
|
||||||
|
|
||||||
for resolved_addr in
|
for resolved_addr in lookup_host_with_cache(context, host, port, strict_tls).await? {
|
||||||
lookup_host_with_cache(context, host, port, timeout_val, strict_tls).await?
|
match connect_tls_inner(resolved_addr, host, strict_tls, alpn).await {
|
||||||
{
|
|
||||||
match connect_tls_inner(resolved_addr, timeout_val, host, strict_tls, alpn).await {
|
|
||||||
Ok(tls_stream) => {
|
Ok(tls_stream) => {
|
||||||
if strict_tls {
|
if strict_tls {
|
||||||
dns::update_connect_timestamp(context, host, &resolved_addr.ip().to_string())
|
dns::update_connect_timestamp(context, host, &resolved_addr.ip().to_string())
|
||||||
@@ -129,10 +124,9 @@ pub(crate) async fn connect_tls(
|
|||||||
async fn connect_starttls_imap_inner(
|
async fn connect_starttls_imap_inner(
|
||||||
addr: SocketAddr,
|
addr: SocketAddr,
|
||||||
host: &str,
|
host: &str,
|
||||||
timeout_val: Duration,
|
|
||||||
strict_tls: bool,
|
strict_tls: bool,
|
||||||
) -> Result<TlsStream<Pin<Box<TimeoutStream<TcpStream>>>>> {
|
) -> Result<TlsStream<Pin<Box<TimeoutStream<TcpStream>>>>> {
|
||||||
let tcp_stream = connect_tcp_inner(addr, timeout_val).await?;
|
let tcp_stream = connect_tcp_inner(addr).await?;
|
||||||
|
|
||||||
// Run STARTTLS command and convert the client back into a stream.
|
// Run STARTTLS command and convert the client back into a stream.
|
||||||
let buffered_tcp_stream = BufWriter::new(tcp_stream);
|
let buffered_tcp_stream = BufWriter::new(tcp_stream);
|
||||||
@@ -159,15 +153,12 @@ pub(crate) async fn connect_starttls_imap(
|
|||||||
context: &Context,
|
context: &Context,
|
||||||
host: &str,
|
host: &str,
|
||||||
port: u16,
|
port: u16,
|
||||||
timeout_val: Duration,
|
|
||||||
strict_tls: bool,
|
strict_tls: bool,
|
||||||
) -> Result<TlsStream<Pin<Box<TimeoutStream<TcpStream>>>>> {
|
) -> Result<TlsStream<Pin<Box<TimeoutStream<TcpStream>>>>> {
|
||||||
let mut first_error = None;
|
let mut first_error = None;
|
||||||
|
|
||||||
for resolved_addr in
|
for resolved_addr in lookup_host_with_cache(context, host, port, strict_tls).await? {
|
||||||
lookup_host_with_cache(context, host, port, timeout_val, strict_tls).await?
|
match connect_starttls_imap_inner(resolved_addr, host, strict_tls).await {
|
||||||
{
|
|
||||||
match connect_starttls_imap_inner(resolved_addr, host, timeout_val, strict_tls).await {
|
|
||||||
Ok(tls_stream) => {
|
Ok(tls_stream) => {
|
||||||
if strict_tls {
|
if strict_tls {
|
||||||
dns::update_connect_timestamp(context, host, &resolved_addr.ip().to_string())
|
dns::update_connect_timestamp(context, host, &resolved_addr.ip().to_string())
|
||||||
@@ -188,10 +179,9 @@ pub(crate) async fn connect_starttls_imap(
|
|||||||
async fn connect_starttls_smtp_inner(
|
async fn connect_starttls_smtp_inner(
|
||||||
addr: SocketAddr,
|
addr: SocketAddr,
|
||||||
host: &str,
|
host: &str,
|
||||||
timeout_val: Duration,
|
|
||||||
strict_tls: bool,
|
strict_tls: bool,
|
||||||
) -> Result<TlsStream<Pin<Box<TimeoutStream<TcpStream>>>>> {
|
) -> Result<TlsStream<Pin<Box<TimeoutStream<TcpStream>>>>> {
|
||||||
let tcp_stream = connect_tcp_inner(addr, timeout_val).await?;
|
let tcp_stream = connect_tcp_inner(addr).await?;
|
||||||
|
|
||||||
// Run STARTTLS command and convert the client back into a stream.
|
// Run STARTTLS command and convert the client back into a stream.
|
||||||
let client = async_smtp::SmtpClient::new().smtp_utf8(true);
|
let client = async_smtp::SmtpClient::new().smtp_utf8(true);
|
||||||
@@ -207,15 +197,12 @@ pub(crate) async fn connect_starttls_smtp(
|
|||||||
context: &Context,
|
context: &Context,
|
||||||
host: &str,
|
host: &str,
|
||||||
port: u16,
|
port: u16,
|
||||||
timeout_val: Duration,
|
|
||||||
strict_tls: bool,
|
strict_tls: bool,
|
||||||
) -> Result<TlsStream<Pin<Box<TimeoutStream<TcpStream>>>>> {
|
) -> Result<TlsStream<Pin<Box<TimeoutStream<TcpStream>>>>> {
|
||||||
let mut first_error = None;
|
let mut first_error = None;
|
||||||
|
|
||||||
for resolved_addr in
|
for resolved_addr in lookup_host_with_cache(context, host, port, strict_tls).await? {
|
||||||
lookup_host_with_cache(context, host, port, timeout_val, strict_tls).await?
|
match connect_starttls_smtp_inner(resolved_addr, host, strict_tls).await {
|
||||||
{
|
|
||||||
match connect_starttls_smtp_inner(resolved_addr, host, timeout_val, strict_tls).await {
|
|
||||||
Ok(tls_stream) => {
|
Ok(tls_stream) => {
|
||||||
if strict_tls {
|
if strict_tls {
|
||||||
dns::update_connect_timestamp(context, host, &resolved_addr.ip().to_string())
|
dns::update_connect_timestamp(context, host, &resolved_addr.ip().to_string())
|
||||||
|
|||||||
@@ -3,19 +3,14 @@
|
|||||||
use anyhow::{Context as _, Result};
|
use anyhow::{Context as _, Result};
|
||||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
|
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::time::Duration;
|
|
||||||
use tokio::net::lookup_host;
|
use tokio::net::lookup_host;
|
||||||
use tokio::time::timeout;
|
use tokio::time::timeout;
|
||||||
|
|
||||||
use crate::context::Context;
|
use crate::context::Context;
|
||||||
use crate::tools::time;
|
use crate::tools::time;
|
||||||
|
|
||||||
async fn lookup_host_with_timeout(
|
async fn lookup_host_with_timeout(hostname: &str, port: u16) -> Result<Vec<SocketAddr>> {
|
||||||
hostname: &str,
|
let res = timeout(super::TIMEOUT, lookup_host((hostname, port)))
|
||||||
port: u16,
|
|
||||||
timeout_val: Duration,
|
|
||||||
) -> Result<Vec<SocketAddr>> {
|
|
||||||
let res = timeout(timeout_val, lookup_host((hostname, port)))
|
|
||||||
.await
|
.await
|
||||||
.context("DNS lookup timeout")?
|
.context("DNS lookup timeout")?
|
||||||
.context("DNS lookup failure")?;
|
.context("DNS lookup failure")?;
|
||||||
@@ -66,11 +61,10 @@ pub(crate) async fn lookup_host_with_cache(
|
|||||||
context: &Context,
|
context: &Context,
|
||||||
hostname: &str,
|
hostname: &str,
|
||||||
port: u16,
|
port: u16,
|
||||||
timeout_val: Duration,
|
|
||||||
load_cache: bool,
|
load_cache: bool,
|
||||||
) -> Result<Vec<SocketAddr>> {
|
) -> Result<Vec<SocketAddr>> {
|
||||||
let now = time();
|
let now = time();
|
||||||
let mut resolved_addrs = match lookup_host_with_timeout(hostname, port, timeout_val).await {
|
let mut resolved_addrs = match lookup_host_with_timeout(hostname, port).await {
|
||||||
Ok(res) => res,
|
Ok(res) => res,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
warn!(
|
warn!(
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
//! # HTTP module.
|
//! # HTTP module.
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use mime::Mime;
|
use mime::Mime;
|
||||||
@@ -11,8 +10,6 @@ use crate::context::Context;
|
|||||||
use crate::net::lookup_host_with_cache;
|
use crate::net::lookup_host_with_cache;
|
||||||
use crate::socks::Socks5Config;
|
use crate::socks::Socks5Config;
|
||||||
|
|
||||||
const HTTP_TIMEOUT: Duration = Duration::from_secs(30);
|
|
||||||
|
|
||||||
static LETSENCRYPT_ROOT: Lazy<reqwest::tls::Certificate> = Lazy::new(|| {
|
static LETSENCRYPT_ROOT: Lazy<reqwest::tls::Certificate> = Lazy::new(|| {
|
||||||
reqwest::tls::Certificate::from_der(include_bytes!(
|
reqwest::tls::Certificate::from_der(include_bytes!(
|
||||||
"../../assets/root-certificates/letsencrypt/isrgrootx1.der"
|
"../../assets/root-certificates/letsencrypt/isrgrootx1.der"
|
||||||
@@ -122,8 +119,7 @@ impl reqwest::dns::Resolve for CustomResolver {
|
|||||||
let port = 443; // Actual port does not matter.
|
let port = 443; // Actual port does not matter.
|
||||||
|
|
||||||
let socket_addrs =
|
let socket_addrs =
|
||||||
lookup_host_with_cache(&context, hostname.as_str(), port, HTTP_TIMEOUT, load_cache)
|
lookup_host_with_cache(&context, hostname.as_str(), port, load_cache).await;
|
||||||
.await;
|
|
||||||
match socket_addrs {
|
match socket_addrs {
|
||||||
Ok(socket_addrs) => {
|
Ok(socket_addrs) => {
|
||||||
let addrs: reqwest::dns::Addrs = Box::new(socket_addrs.into_iter());
|
let addrs: reqwest::dns::Addrs = Box::new(socket_addrs.into_iter());
|
||||||
@@ -141,7 +137,7 @@ pub(crate) async fn get_client(context: &Context, load_cache: bool) -> Result<re
|
|||||||
let resolver = Arc::new(CustomResolver::new(context.clone(), load_cache));
|
let resolver = Arc::new(CustomResolver::new(context.clone(), load_cache));
|
||||||
|
|
||||||
let builder = reqwest::ClientBuilder::new()
|
let builder = reqwest::ClientBuilder::new()
|
||||||
.timeout(HTTP_TIMEOUT)
|
.timeout(super::TIMEOUT)
|
||||||
.add_root_certificate(LETSENCRYPT_ROOT.clone())
|
.add_root_certificate(LETSENCRYPT_ROOT.clone())
|
||||||
.dns_resolver(resolver);
|
.dns_resolver(resolver);
|
||||||
|
|
||||||
|
|||||||
19
src/smtp.rs
19
src/smtp.rs
@@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
pub mod send;
|
pub mod send;
|
||||||
|
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
use anyhow::{bail, format_err, Context as _, Error, Result};
|
use anyhow::{bail, format_err, Context as _, Error, Result};
|
||||||
use async_smtp::response::{Category, Code, Detail};
|
use async_smtp::response::{Category, Code, Detail};
|
||||||
use async_smtp::{self as smtp, EmailAddress, SmtpTransport};
|
use async_smtp::{self as smtp, EmailAddress, SmtpTransport};
|
||||||
@@ -30,9 +28,6 @@ use crate::sql;
|
|||||||
use crate::stock_str::unencrypted_email;
|
use crate::stock_str::unencrypted_email;
|
||||||
use crate::tools::{self, time_elapsed};
|
use crate::tools::{self, time_elapsed};
|
||||||
|
|
||||||
/// SMTP connection, write and read timeout.
|
|
||||||
const SMTP_TIMEOUT: Duration = Duration::from_secs(60);
|
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub(crate) struct Smtp {
|
pub(crate) struct Smtp {
|
||||||
/// SMTP connection.
|
/// SMTP connection.
|
||||||
@@ -118,7 +113,7 @@ impl Smtp {
|
|||||||
socks5_config: Socks5Config,
|
socks5_config: Socks5Config,
|
||||||
) -> Result<SmtpTransport<Box<dyn SessionBufStream>>> {
|
) -> Result<SmtpTransport<Box<dyn SessionBufStream>>> {
|
||||||
let socks5_stream = socks5_config
|
let socks5_stream = socks5_config
|
||||||
.connect(context, hostname, port, SMTP_TIMEOUT, strict_tls)
|
.connect(context, hostname, port, strict_tls)
|
||||||
.await?;
|
.await?;
|
||||||
let tls_stream = wrap_tls(strict_tls, hostname, "smtp", socks5_stream).await?;
|
let tls_stream = wrap_tls(strict_tls, hostname, "smtp", socks5_stream).await?;
|
||||||
let buffered_stream = BufStream::new(tls_stream);
|
let buffered_stream = BufStream::new(tls_stream);
|
||||||
@@ -137,7 +132,7 @@ impl Smtp {
|
|||||||
socks5_config: Socks5Config,
|
socks5_config: Socks5Config,
|
||||||
) -> Result<SmtpTransport<Box<dyn SessionBufStream>>> {
|
) -> Result<SmtpTransport<Box<dyn SessionBufStream>>> {
|
||||||
let socks5_stream = socks5_config
|
let socks5_stream = socks5_config
|
||||||
.connect(context, hostname, port, SMTP_TIMEOUT, strict_tls)
|
.connect(context, hostname, port, strict_tls)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// Run STARTTLS command and convert the client back into a stream.
|
// Run STARTTLS command and convert the client back into a stream.
|
||||||
@@ -162,7 +157,7 @@ impl Smtp {
|
|||||||
socks5_config: Socks5Config,
|
socks5_config: Socks5Config,
|
||||||
) -> Result<SmtpTransport<Box<dyn SessionBufStream>>> {
|
) -> Result<SmtpTransport<Box<dyn SessionBufStream>>> {
|
||||||
let socks5_stream = socks5_config
|
let socks5_stream = socks5_config
|
||||||
.connect(context, hostname, port, SMTP_TIMEOUT, false)
|
.connect(context, hostname, port, false)
|
||||||
.await?;
|
.await?;
|
||||||
let buffered_stream = BufStream::new(socks5_stream);
|
let buffered_stream = BufStream::new(socks5_stream);
|
||||||
let session_stream: Box<dyn SessionBufStream> = Box::new(buffered_stream);
|
let session_stream: Box<dyn SessionBufStream> = Box::new(buffered_stream);
|
||||||
@@ -178,8 +173,7 @@ impl Smtp {
|
|||||||
port: u16,
|
port: u16,
|
||||||
strict_tls: bool,
|
strict_tls: bool,
|
||||||
) -> Result<SmtpTransport<Box<dyn SessionBufStream>>> {
|
) -> Result<SmtpTransport<Box<dyn SessionBufStream>>> {
|
||||||
let tls_stream =
|
let tls_stream = connect_tls(context, hostname, port, strict_tls, "smtp").await?;
|
||||||
connect_tls(context, hostname, port, SMTP_TIMEOUT, strict_tls, "smtp").await?;
|
|
||||||
let buffered_stream = BufStream::new(tls_stream);
|
let buffered_stream = BufStream::new(tls_stream);
|
||||||
let session_stream: Box<dyn SessionBufStream> = Box::new(buffered_stream);
|
let session_stream: Box<dyn SessionBufStream> = Box::new(buffered_stream);
|
||||||
let client = smtp::SmtpClient::new().smtp_utf8(true);
|
let client = smtp::SmtpClient::new().smtp_utf8(true);
|
||||||
@@ -194,8 +188,7 @@ impl Smtp {
|
|||||||
port: u16,
|
port: u16,
|
||||||
strict_tls: bool,
|
strict_tls: bool,
|
||||||
) -> Result<SmtpTransport<Box<dyn SessionBufStream>>> {
|
) -> Result<SmtpTransport<Box<dyn SessionBufStream>>> {
|
||||||
let tls_stream =
|
let tls_stream = connect_starttls_smtp(context, hostname, port, strict_tls).await?;
|
||||||
connect_starttls_smtp(context, hostname, port, SMTP_TIMEOUT, strict_tls).await?;
|
|
||||||
|
|
||||||
let buffered_stream = BufStream::new(tls_stream);
|
let buffered_stream = BufStream::new(tls_stream);
|
||||||
let session_stream: Box<dyn SessionBufStream> = Box::new(buffered_stream);
|
let session_stream: Box<dyn SessionBufStream> = Box::new(buffered_stream);
|
||||||
@@ -210,7 +203,7 @@ impl Smtp {
|
|||||||
hostname: &str,
|
hostname: &str,
|
||||||
port: u16,
|
port: u16,
|
||||||
) -> Result<SmtpTransport<Box<dyn SessionBufStream>>> {
|
) -> Result<SmtpTransport<Box<dyn SessionBufStream>>> {
|
||||||
let tcp_stream = connect_tcp(context, hostname, port, SMTP_TIMEOUT, false).await?;
|
let tcp_stream = connect_tcp(context, hostname, port, false).await?;
|
||||||
let buffered_stream = BufStream::new(tcp_stream);
|
let buffered_stream = BufStream::new(tcp_stream);
|
||||||
let session_stream: Box<dyn SessionBufStream> = Box::new(buffered_stream);
|
let session_stream: Box<dyn SessionBufStream> = Box::new(buffered_stream);
|
||||||
let client = smtp::SmtpClient::new().smtp_utf8(true);
|
let client = smtp::SmtpClient::new().smtp_utf8(true);
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use fast_socks5::client::{Config, Socks5Stream};
|
use fast_socks5::client::{Config, Socks5Stream};
|
||||||
@@ -76,11 +75,9 @@ impl Socks5Config {
|
|||||||
context: &Context,
|
context: &Context,
|
||||||
target_host: &str,
|
target_host: &str,
|
||||||
target_port: u16,
|
target_port: u16,
|
||||||
timeout_val: Duration,
|
|
||||||
load_dns_cache: bool,
|
load_dns_cache: bool,
|
||||||
) -> Result<Socks5Stream<Pin<Box<TimeoutStream<TcpStream>>>>> {
|
) -> Result<Socks5Stream<Pin<Box<TimeoutStream<TcpStream>>>>> {
|
||||||
let tcp_stream =
|
let tcp_stream = connect_tcp(context, &self.host, self.port, load_dns_cache).await?;
|
||||||
connect_tcp(context, &self.host, self.port, timeout_val, load_dns_cache).await?;
|
|
||||||
|
|
||||||
let authentication_method = if let Some((username, password)) = self.user_password.as_ref()
|
let authentication_method = if let Some((username, password)) = self.user_password.as_ref()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user