From d61a55f1ef480dad9f299012c23e199c47d99df5 Mon Sep 17 00:00:00 2001 From: Shikhar Bhushan Date: Tue, 22 Oct 2024 15:37:05 -0400 Subject: [PATCH] feat: make pub `Channel` fns that allow creating it from a custom connector (#2015) * feat: make pub `Channel` fns that allow creating it from a custom connector The connector is required to be a `Service` that accepts a `http::Uri` and returns a connection implementing hyper's IO traits, which is a very reasonable requirement that can be fulfilled by advanced users that need to customize any mechanics that don't fit into the paved path for HTTP and HTTPS with tonic. One such requirement is customizing `rustls::ClientConfig`, which has come up for a number of users. They have been pointed in the direction of a custom connector, but the APIs on `Endpoint` are not always suitable: `Enedpoint::connect_(lazy_)with_connector` always wraps the provided connector with `transport::channel::service::Connector`. This wrapper validates if the scheme is HTTPS, the TLS feature is enabled, and TLS was not configured on the endpoint, and raises an error `HttpsUriWithoutTlsSupport` in this situation. This is a good safety feature in general, but not if the wrapped connector is taking care of TLS. As a side bonus, `tonic::transport::channel::service::io::BoxedIo` can be avoided. * chore: remove redundant bound on connections --- tonic/src/transport/channel/mod.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tonic/src/transport/channel/mod.rs b/tonic/src/transport/channel/mod.rs index 2fe8a2753..c1bee0140 100644 --- a/tonic/src/transport/channel/mod.rs +++ b/tonic/src/transport/channel/mod.rs @@ -16,7 +16,6 @@ use http::{ uri::{InvalidUri, Uri}, Request, Response, }; -use hyper_util::client::legacy::connect::Connection as HyperConnection; use std::{ fmt, future::Future, @@ -144,12 +143,15 @@ impl Channel { (Self::balance(list, DEFAULT_BUFFER_SIZE, executor), tx) } - pub(crate) fn new(connector: C, endpoint: Endpoint) -> Self + /// Create a new [`Channel`] using a custom connector to the provided [Endpoint]. + /// + /// This is a lower level API, prefer to use [`Endpoint::connect_lazy`] if you are not using a custom connector. + pub fn new(connector: C, endpoint: Endpoint) -> Self where C: Service + Send + 'static, C::Error: Into + Send, C::Future: Send, - C::Response: rt::Read + rt::Write + HyperConnection + Unpin + Send + 'static, + C::Response: rt::Read + rt::Write + Unpin + Send + 'static, { let buffer_size = endpoint.buffer_size.unwrap_or(DEFAULT_BUFFER_SIZE); let executor = endpoint.executor.clone(); @@ -162,12 +164,15 @@ impl Channel { Channel { svc } } - pub(crate) async fn connect(connector: C, endpoint: Endpoint) -> Result + /// Connect to the provided [`Endpoint`] using the provided connector, and return a new [`Channel`]. + /// + /// This is a lower level API, prefer to use [`Endpoint::connect`] if you are not using a custom connector. + pub async fn connect(connector: C, endpoint: Endpoint) -> Result where C: Service + Send + 'static, C::Error: Into + Send, C::Future: Unpin + Send, - C::Response: rt::Read + rt::Write + HyperConnection + Unpin + Send + 'static, + C::Response: rt::Read + rt::Write + Unpin + Send + 'static, { let buffer_size = endpoint.buffer_size.unwrap_or(DEFAULT_BUFFER_SIZE); let executor = endpoint.executor.clone();