diff --git a/src/unversioned/transport/chain.rs b/src/unversioned/transport/chain.rs index 00d6d6fc..6db75c64 100644 --- a/src/unversioned/transport/chain.rs +++ b/src/unversioned/transport/chain.rs @@ -1,59 +1,385 @@ -use std::fmt; -use std::marker::PhantomData; - use super::{Connector, Transport}; -/// Two chained connectors called one after another. +/// Chain of up to 8 connectors /// -/// Created by calling [`Connector::chain`] on the first connector. -pub struct ChainedConnector(First, Second, PhantomData); +/// Can be created manually from a tuple of connectors through `ChainedConnector::new` +#[derive(Debug, Clone)] +pub struct ChainedConnector(Connectors); + +impl ChainedConnector { + /// Create a new chained connector that chains a tuple of connectors + /// + /// ```rust + /// # use ureq::unversioned::transport::{ChainedConnector, TcpConnector, ConnectProxyConnector}; + /// let connector: ChainedConnector<(TcpConnector, ConnectProxyConnector)> = + /// ChainedConnector::new(( + /// TcpConnector::default(), + /// ConnectProxyConnector::default() + /// )); + /// ``` + pub fn new(connectors: Connectors) -> Self { + Self(connectors) + } +} + +// Macro to generate the implementations of ChainedConnectors for various tuple length +// macro_rules! impl_chained_connectors { +// (($first_ty:ident, $first_name: ident) ; $(($ty:ident, $name:ident, $prev_ty:ident)),* ; ($final_ty:ident, $final_name: ident, $pre_final_ty:ident)) => { +// impl Connector for ChainedConnector<($first_ty, $($ty,)* $final_ty)> +// where +// In: Transport, +// $first_ty: Connector, +// $($ty: Connector<$prev_ty::Out>,)* +// $final_ty: Connector<$pre_final_ty::Out>, +// { +// type Out = $final_ty::Out; +// fn connect( +// &self, +// details: &super::ConnectionDetails, +// chained: Option, +// ) -> Result, crate::Error> { +// let ChainedConnector(( +// ref $first_name, +// $(ref $name,)* +// ref $final_name, +// )) = self; -impl Connector for ChainedConnector +// let out = $first_name.connect(details, chained)?; +// $( +// let out = $name.connect(details, out)?; +// )* +// $final_name.connect(details,out) +// } +// } + +// }; +// } + +// Expansion of: +// impl_chained_connectors!( +// (A, a) ; +// (B, b, A), +// (C, c, B), +// (D, d, C), +// (E, e, D), +// (F, f, E), +// (G, g, F), +// (H, h, G), +// (I, i, H); +// (J, j, I) +// ); +impl Connector + for ChainedConnector<(A, B, C, D, E, F, G, H, I, J)> where In: Transport, - First: Connector, - Second: Connector, + A: Connector, + B: Connector, + C: Connector, + D: Connector, + E: Connector, + F: Connector, + G: Connector, + H: Connector, + I: Connector, + J: Connector, { - type Out = Second::Out; + type Out = J::Out; + fn connect( + &self, + details: &super::ConnectionDetails, + chained: Option, + ) -> Result, crate::Error> { + let ChainedConnector(( + ref a, + ref b, + ref c, + ref d, + ref e, + ref f, + ref g, + ref h, + ref i, + ref j, + )) = self; + let out = a.connect(details, chained)?; + let out = b.connect(details, out)?; + let out = c.connect(details, out)?; + let out = d.connect(details, out)?; + let out = e.connect(details, out)?; + let out = f.connect(details, out)?; + let out = g.connect(details, out)?; + let out = h.connect(details, out)?; + let out = i.connect(details, out)?; + j.connect(details, out) + } +} +// Expansion of: +// impl_chained_connectors!( +// (A, a) ; +// (B, b, A), +// (C, c, B), +// (D, d, C), +// (E, e, D), +// (F, f, E), +// (G, g, F), +// (H, h, G); +// (I, i, H) +// ); +impl Connector for ChainedConnector<(A, B, C, D, E, F, G, H, I)> +where + In: Transport, + A: Connector, + B: Connector, + C: Connector, + D: Connector, + E: Connector, + F: Connector, + G: Connector, + H: Connector, + I: Connector, +{ + type Out = I::Out; fn connect( &self, details: &super::ConnectionDetails, chained: Option, ) -> Result, crate::Error> { - let f_out = self.0.connect(details, chained)?; - self.1.connect(details, f_out) + let ChainedConnector((ref a, ref b, ref c, ref d, ref e, ref f, ref g, ref h, ref i)) = + self; + let out = a.connect(details, chained)?; + let out = b.connect(details, out)?; + let out = c.connect(details, out)?; + let out = d.connect(details, out)?; + let out = e.connect(details, out)?; + let out = f.connect(details, out)?; + let out = g.connect(details, out)?; + let out = h.connect(details, out)?; + i.connect(details, out) } } -impl ChainedConnector { - pub(crate) fn new(first: First, second: Second) -> Self { - ChainedConnector(first, second, PhantomData) +// Expansion of: +// impl_chained_connectors!( +// (A, a) ; +// (B, b, A), +// (C, c, B), +// (D, d, C), +// (E, e, D), +// (F, f, E), +// (G, g, F); +// (H, h, G) +// ); +impl Connector for ChainedConnector<(A, B, C, D, E, F, G, H)> +where + In: Transport, + A: Connector, + B: Connector, + C: Connector, + D: Connector, + E: Connector, + F: Connector, + G: Connector, + H: Connector, +{ + type Out = H::Out; + fn connect( + &self, + details: &super::ConnectionDetails, + chained: Option, + ) -> Result, crate::Error> { + let ChainedConnector((ref a, ref b, ref c, ref d, ref e, ref f, ref g, ref h)) = self; + let out = a.connect(details, chained)?; + let out = b.connect(details, out)?; + let out = c.connect(details, out)?; + let out = d.connect(details, out)?; + let out = e.connect(details, out)?; + let out = f.connect(details, out)?; + let out = g.connect(details, out)?; + h.connect(details, out) } } -impl fmt::Debug for ChainedConnector +// Expansion of: +// impl_chained_connectors!( +// (A, a) ; +// (B, b, A), +// (C, c, B), +// (D, d, C), +// (E, e, D), +// (F, f, E); +// (G, g, F) +// ); +impl Connector for ChainedConnector<(A, B, C, D, E, F, G)> where In: Transport, - First: Connector, - Second: Connector, + A: Connector, + B: Connector, + C: Connector, + D: Connector, + E: Connector, + F: Connector, + G: Connector, { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("ChainedConnector") - .field(&self.0) - .field(&self.1) - .finish() + type Out = G::Out; + fn connect( + &self, + details: &super::ConnectionDetails, + chained: Option, + ) -> Result, crate::Error> { + let ChainedConnector((ref a, ref b, ref c, ref d, ref e, ref f, ref g)) = self; + let out = a.connect(details, chained)?; + let out = b.connect(details, out)?; + let out = c.connect(details, out)?; + let out = d.connect(details, out)?; + let out = e.connect(details, out)?; + let out = f.connect(details, out)?; + g.connect(details, out) } } -impl Clone for ChainedConnector +// Expansion of: +// impl_chained_connectors!( +// (A, a) ; +// (B, b, A), +// (C, c, B), +// (D, d, C), +// (E, e, D); +// (F, f, E) +// ); +impl Connector for ChainedConnector<(A, B, C, D, E, F)> where In: Transport, - First: Connector + Clone, - Second: Connector + Clone, + A: Connector, + B: Connector, + C: Connector, + D: Connector, + E: Connector, + F: Connector, { - fn clone(&self) -> Self { - ChainedConnector(self.0.clone(), self.1.clone(), PhantomData) + type Out = F::Out; + fn connect( + &self, + details: &super::ConnectionDetails, + chained: Option, + ) -> Result, crate::Error> { + let ChainedConnector((ref a, ref b, ref c, ref d, ref e, ref f)) = self; + let out = a.connect(details, chained)?; + let out = b.connect(details, out)?; + let out = c.connect(details, out)?; + let out = d.connect(details, out)?; + let out = e.connect(details, out)?; + f.connect(details, out) + } +} + +// Expansion of: +// impl_chained_connectors!( +// (A, a) ; +// (B, b, A), +// (C, c, B), +// (D, d, C); +// (E, e, D) +// ); +impl Connector for ChainedConnector<(A, B, C, D, E)> +where + In: Transport, + A: Connector, + B: Connector, + C: Connector, + D: Connector, + E: Connector, +{ + type Out = E::Out; + fn connect( + &self, + details: &super::ConnectionDetails, + chained: Option, + ) -> Result, crate::Error> { + let ChainedConnector((ref a, ref b, ref c, ref d, ref e)) = self; + let out = a.connect(details, chained)?; + let out = b.connect(details, out)?; + let out = c.connect(details, out)?; + let out = d.connect(details, out)?; + e.connect(details, out) + } +} + +// Expansion of: +// impl_chained_connectors!( +// (A, a) ; +// (B, b, A), +// (C, c, B); +// (D, d, C) +// ); +impl Connector for ChainedConnector<(A, B, C, D)> +where + In: Transport, + A: Connector, + B: Connector, + C: Connector, + D: Connector, +{ + type Out = D::Out; + fn connect( + &self, + details: &super::ConnectionDetails, + chained: Option, + ) -> Result, crate::Error> { + let ChainedConnector((ref a, ref b, ref c, ref d)) = self; + let out = a.connect(details, chained)?; + let out = b.connect(details, out)?; + let out = c.connect(details, out)?; + d.connect(details, out) + } +} + +// Expansion of: +// impl_chained_connectors!( +// (A, a) ; +// (B, b, A); +// (C, c, B) +// ); +impl Connector for ChainedConnector<(A, B, C)> +where + In: Transport, + A: Connector, + B: Connector, + C: Connector, +{ + type Out = C::Out; + fn connect( + &self, + details: &super::ConnectionDetails, + chained: Option, + ) -> Result, crate::Error> { + let ChainedConnector((ref a, ref b, ref c)) = self; + let out = a.connect(details, chained)?; + let out = b.connect(details, out)?; + c.connect(details, out) + } +} + +// Expansion of: +// impl_chained_connectors!( +// (A, a) ;; +// (B, b, A) +// ); +impl Connector for ChainedConnector<(A, B)> +where + In: Transport, + A: Connector, + B: Connector, +{ + type Out = B::Out; + fn connect( + &self, + details: &super::ConnectionDetails, + chained: Option, + ) -> Result, crate::Error> { + let ChainedConnector((ref a, ref b)) = self; + let out = a.connect(details, chained)?; + b.connect(details, out) } } diff --git a/src/unversioned/transport/mod.rs b/src/unversioned/transport/mod.rs index 96930cce..9c039643 100644 --- a/src/unversioned/transport/mod.rs +++ b/src/unversioned/transport/mod.rs @@ -132,11 +132,11 @@ pub trait Connector: Debug + Send + Sync + 'static { /// Chain this connector to another connector. /// /// This connector will be called first, and the output goes into the next connector. - fn chain>(self, next: Next) -> ChainedConnector + fn chain>(self, next: Next) -> ChainedConnector<(Self, Next)> where Self: Sized, { - ChainedConnector::new(self, next) + ChainedConnector::new((self, next)) } } @@ -319,51 +319,39 @@ impl DefaultConnector { impl Default for DefaultConnector { fn default() -> Self { - let inner = (); - - // When enabled, all tests are connected to a dummy server and will not - // make requests to the internet. - #[cfg(feature = "_test")] - let inner = inner.chain(test::TestConnector); - - // If we are using socks-proxy, that takes precedence over TcpConnector. - #[cfg(feature = "socks-proxy")] - let inner = inner.chain(SocksConnector::default()); - - // If the config indicates we ought to use a socks proxy - // and the feature flag isn't enabled, we should warn the user. - #[cfg(not(feature = "socks-proxy"))] - let inner = inner.chain(no_proxy::WarnOnNoSocksConnector); - - // If we didn't get a socks-proxy, open a Tcp connection - let inner = inner.chain(TcpConnector::default()); - - // If rustls is enabled, prefer that - #[cfg(feature = "_rustls")] - let inner = inner.chain(RustlsConnector::default()); - - // Panic if the config calls for rustls, the uri scheme is https and that - // TLS provider is not enabled by feature flags. - #[cfg(feature = "_tls")] - let inner = inner.chain(no_tls::WarnOnMissingTlsProvider( - crate::tls::TlsProvider::Rustls, + let inner = ChainedConnector::new(( + // When enabled, all tests are connected to a dummy server and will not + // make requests to the internet. + #[cfg(feature = "_test")] + test::TestConnector, + // If we are using socks-proxy, that takes precedence over TcpConnector. + #[cfg(feature = "socks-proxy")] + SocksConnector::default(), + // If the config indicates we ought to use a socks proxy + // and the feature flag isn't enabled, we should warn the user. + #[cfg(not(feature = "socks-proxy"))] + no_proxy::WarnOnNoSocksConnector, + // If we didn't get a socks-proxy, open a Tcp connection + TcpConnector::default(), + // If rustls is enabled, prefer that + #[cfg(feature = "_rustls")] + RustlsConnector::default(), + // Panic if the config calls for rustls, the uri scheme is https and that + // TLS provider is not enabled by feature flags. + #[cfg(feature = "_tls")] + no_tls::WarnOnMissingTlsProvider(crate::tls::TlsProvider::Rustls), + // As a fallback if rustls isn't enabled, use native-tls + #[cfg(feature = "native-tls")] + NativeTlsConnector::default(), + // Panic if the config calls for native-tls, the uri scheme is https and that + // TLS provider is not enabled by feature flags. + #[cfg(feature = "_tls")] + no_tls::WarnOnMissingTlsProvider(crate::tls::TlsProvider::NativeTls), + // If this is a CONNECT proxy, we must "prepare" the socket + // by sending the `CONNECT host:port` line. + ConnectProxyConnector::default(), )); - // As a fallback if rustls isn't enabled, use native-tls - #[cfg(feature = "native-tls")] - let inner = inner.chain(NativeTlsConnector::default()); - - // Panic if the config calls for native-tls, the uri scheme is https and that - // TLS provider is not enabled by feature flags. - #[cfg(feature = "_tls")] - let inner = inner.chain(no_tls::WarnOnMissingTlsProvider( - crate::tls::TlsProvider::NativeTls, - )); - - // If this is a CONNECT proxy, we must "prepare" the socket - // by sending the `CONNECT host:port` line. - let inner = inner.chain(ConnectProxyConnector::default()); - DefaultConnector { inner: boxed_connector(inner), }