Skip to content

Commit

Permalink
feat(tls): Add tls handshake timeout support
Browse files Browse the repository at this point in the history
  • Loading branch information
honsunrise committed Nov 28, 2024
1 parent a7030a7 commit f66b551
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 4 deletions.
17 changes: 13 additions & 4 deletions tonic/src/transport/channel/service/tls.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use std::fmt;
use std::sync::Arc;
use std::{sync::Arc, time::Duration};

use hyper_util::rt::TokioIo;
use tokio::io::{AsyncRead, AsyncWrite};
use tokio::time;
use tokio_rustls::{
rustls::{
crypto,
Expand All @@ -23,6 +24,7 @@ pub(crate) struct TlsConnector {
config: Arc<ClientConfig>,
domain: Arc<ServerName<'static>>,
assume_http2: bool,
timeout: Option<Duration>,
}

impl TlsConnector {
Expand All @@ -34,6 +36,7 @@ impl TlsConnector {
assume_http2: bool,
#[cfg(feature = "tls-native-roots")] with_native_roots: bool,
#[cfg(feature = "tls-webpki-roots")] with_webpki_roots: bool,
timeout: Option<Duration>,
) -> Result<Self, crate::BoxError> {
fn with_provider(
provider: Arc<crypto::CryptoProvider>,
Expand Down Expand Up @@ -92,16 +95,22 @@ impl TlsConnector {
config: Arc::new(config),
domain: Arc::new(ServerName::try_from(domain)?.to_owned()),
assume_http2,
timeout,
})
}

pub(crate) async fn connect<I>(&self, io: I) -> Result<BoxedIo, crate::BoxError>
where
I: AsyncRead + AsyncWrite + Send + Unpin + 'static,
{
let io = RustlsConnector::from(self.config.clone())
.connect(self.domain.as_ref().to_owned(), io)
.await?;
let conn_fut =
RustlsConnector::from(self.config.clone()).connect(self.domain.as_ref().to_owned(), io);
let io = match self.timeout {
Some(timeout) => time::timeout(timeout, conn_fut)
.await
.map_err(|_| TlsError::HandshakeTimeout)??,
None => conn_fut.await?,
};

// Generally we require ALPN to be negotiated, but if the user has
// explicitly set `assume_http2` to true, we'll allow it to be missing.
Expand Down
11 changes: 11 additions & 0 deletions tonic/src/transport/channel/tls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::transport::{
Error,
};
use http::Uri;
use std::time::Duration;
use tokio_rustls::rustls::pki_types::TrustAnchor;

/// Configures TLS settings for endpoints.
Expand All @@ -18,6 +19,7 @@ pub struct ClientTlsConfig {
with_native_roots: bool,
#[cfg(feature = "tls-webpki-roots")]
with_webpki_roots: bool,
timeout: Option<Duration>,
}

impl ClientTlsConfig {
Expand Down Expand Up @@ -112,6 +114,14 @@ impl ClientTlsConfig {
config
}

/// Sets the timeout for the TLS handshake.
pub fn timeout(self, timeout: Duration) -> Self {
ClientTlsConfig {
timeout: Some(timeout),
..self
}
}

pub(crate) fn into_tls_connector(self, uri: &Uri) -> Result<TlsConnector, crate::BoxError> {
let domain = match &self.domain {
Some(domain) => domain,
Expand All @@ -127,6 +137,7 @@ impl ClientTlsConfig {
self.with_native_roots,
#[cfg(feature = "tls-webpki-roots")]
self.with_webpki_roots,
self.timeout,
)
}
}
2 changes: 2 additions & 0 deletions tonic/src/transport/service/tls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub(crate) enum TlsError {
NativeCertsNotFound,
CertificateParseError,
PrivateKeyParseError,
HandshakeTimeout,

Check failure on line 18 in tonic/src/transport/service/tls.rs

View workflow job for this annotation

GitHub Actions / check (ubuntu-latest)

variant `HandshakeTimeout` is never constructed

Check failure on line 18 in tonic/src/transport/service/tls.rs

View workflow job for this annotation

GitHub Actions / check (macOS-latest)

variant `HandshakeTimeout` is never constructed
}

impl fmt::Display for TlsError {
Expand All @@ -29,6 +30,7 @@ impl fmt::Display for TlsError {
f,
"Error parsing TLS private key - no RSA or PKCS8-encoded keys found."
),
TlsError::HandshakeTimeout => write!(f, "TLS handshake timeout."),
}
}
}
Expand Down

0 comments on commit f66b551

Please sign in to comment.