1- #[ allow( clippy:: module_inception) ]
2- mod conn;
31mod connector;
42mod http;
53mod proxy;
4+ mod tcp;
65mod tls_info;
76#[ cfg( unix) ]
87mod uds;
98mod verbose;
109
1110use std:: {
1211 fmt:: { self , Debug , Formatter } ,
12+ io,
13+ io:: IoSlice ,
14+ pin:: Pin ,
1315 sync:: {
1416 Arc ,
1517 atomic:: { AtomicBool , Ordering } ,
1618 } ,
19+ task:: { Context , Poll } ,
1720} ;
1821
1922use :: http:: { Extensions , HeaderMap , HeaderValue } ;
20- use tokio:: io:: { AsyncRead , AsyncWrite } ;
23+ use pin_project_lite:: pin_project;
24+ use tokio:: io:: { AsyncRead , AsyncWrite , ReadBuf } ;
25+ use tokio_btls:: SslStream ;
2126use tower:: {
2227 BoxError ,
2328 util:: { BoxCloneSyncService , BoxCloneSyncServiceLayer } ,
@@ -26,16 +31,16 @@ use tower::{
2631#[ cfg( feature = "socks" ) ]
2732pub ( super ) use self :: proxy:: socks;
2833pub ( super ) use self :: {
29- conn:: Conn ,
3034 connector:: Connector ,
31- http:: { HttpInfo , TcpConnectOptions } ,
35+ http:: { HttpInfo , HttpTransport } ,
3236 proxy:: tunnel,
37+ tcp:: { SocketBindOptions , tokio:: TokioTcpConnector } ,
3338 tls_info:: TlsInfoFactory ,
3439} ;
35- use crate :: { client:: ConnectRequest , dns:: DynResolver , proxy:: matcher:: Intercept } ;
40+ use crate :: { client:: ConnectRequest , dns:: DynResolver , proxy:: matcher:: Intercept , tls :: TlsInfo } ;
3641
3742/// HTTP connector with dynamic DNS resolver.
38- pub type HttpConnector = self :: http:: HttpConnector < DynResolver > ;
43+ pub type HttpConnector = self :: http:: HttpConnector < DynResolver , TokioTcpConnector > ;
3944
4045/// Boxed connector service for establishing connections.
4146pub type BoxedConnectorService = BoxCloneSyncService < Unnameable , Conn , BoxError > ;
@@ -69,6 +74,31 @@ impl<T> AsyncConn for T where T: AsyncRead + AsyncWrite + Connection + Send + Sy
6974
7075impl < T > AsyncConnWithInfo for T where T : AsyncConn + TlsInfoFactory { }
7176
77+ pin_project ! {
78+ /// Note: the `is_proxy` member means *is plain text HTTP proxy*.
79+ /// This tells core whether the URI should be written in
80+ /// * origin-form (`GET /just/a/path HTTP/1.1`), when `is_proxy == false`, or
81+ /// * absolute-form (`GET http://foo.bar/and/a/path HTTP/1.1`), otherwise.
82+ pub struct Conn {
83+ tls_info: bool ,
84+ proxy: Option <Intercept >,
85+ #[ pin]
86+ stream: Box <dyn AsyncConnWithInfo >,
87+ }
88+ }
89+
90+ pin_project ! {
91+ /// A wrapper around `SslStream` that adapts it for use as a generic async connection.
92+ ///
93+ /// This type enables unified handling of plain TCP and TLS-encrypted streams by providing
94+ /// implementations of `Connection`, `Read`, `Write`, and `TlsInfoFactory`.
95+ /// It is mainly used internally to abstract over different connection types.
96+ pub struct TlsConn <T > {
97+ #[ pin]
98+ stream: SslStream <T >,
99+ }
100+ }
101+
72102/// Describes a type returned by a connector.
73103pub trait Connection {
74104 /// Return metadata describing the connection.
@@ -129,6 +159,145 @@ pub struct Connected {
129159 poisoned : PoisonPill ,
130160}
131161
162+ // ==== impl Conn ====
163+
164+ impl Connection for Conn {
165+ fn connected ( & self ) -> Connected {
166+ let mut connected = self . stream . connected ( ) ;
167+
168+ if let Some ( proxy) = & self . proxy {
169+ connected = connected. proxy ( proxy. clone ( ) ) ;
170+ }
171+
172+ if self . tls_info {
173+ if let Some ( tls_info) = self . stream . tls_info ( ) {
174+ connected. extra ( tls_info)
175+ } else {
176+ connected
177+ }
178+ } else {
179+ connected
180+ }
181+ }
182+ }
183+
184+ impl AsyncRead for Conn {
185+ #[ inline]
186+ fn poll_read (
187+ self : Pin < & mut Self > ,
188+ cx : & mut Context ,
189+ buf : & mut ReadBuf < ' _ > ,
190+ ) -> Poll < io:: Result < ( ) > > {
191+ AsyncRead :: poll_read ( self . project ( ) . stream , cx, buf)
192+ }
193+ }
194+
195+ impl AsyncWrite for Conn {
196+ #[ inline]
197+ fn poll_write (
198+ self : Pin < & mut Self > ,
199+ cx : & mut Context ,
200+ buf : & [ u8 ] ,
201+ ) -> Poll < Result < usize , io:: Error > > {
202+ AsyncWrite :: poll_write ( self . project ( ) . stream , cx, buf)
203+ }
204+
205+ #[ inline]
206+ fn poll_write_vectored (
207+ self : Pin < & mut Self > ,
208+ cx : & mut Context < ' _ > ,
209+ bufs : & [ IoSlice < ' _ > ] ,
210+ ) -> Poll < Result < usize , io:: Error > > {
211+ AsyncWrite :: poll_write_vectored ( self . project ( ) . stream , cx, bufs)
212+ }
213+
214+ #[ inline]
215+ fn is_write_vectored ( & self ) -> bool {
216+ self . stream . is_write_vectored ( )
217+ }
218+
219+ #[ inline]
220+ fn poll_flush ( self : Pin < & mut Self > , cx : & mut Context ) -> Poll < Result < ( ) , io:: Error > > {
221+ AsyncWrite :: poll_flush ( self . project ( ) . stream , cx)
222+ }
223+
224+ #[ inline]
225+ fn poll_shutdown ( self : Pin < & mut Self > , cx : & mut Context ) -> Poll < Result < ( ) , io:: Error > > {
226+ AsyncWrite :: poll_shutdown ( self . project ( ) . stream , cx)
227+ }
228+ }
229+
230+ // ===== impl TlsConn =====
231+
232+ impl < T > Connection for TlsConn < T >
233+ where
234+ T : Connection ,
235+ {
236+ fn connected ( & self ) -> Connected {
237+ let connected = self . stream . get_ref ( ) . connected ( ) ;
238+ if self . stream . ssl ( ) . selected_alpn_protocol ( ) == Some ( b"h2" ) {
239+ connected. negotiated_h2 ( )
240+ } else {
241+ connected
242+ }
243+ }
244+ }
245+
246+ impl < T : AsyncRead + AsyncWrite + Unpin > AsyncRead for TlsConn < T > {
247+ #[ inline]
248+ fn poll_read (
249+ self : Pin < & mut Self > ,
250+ cx : & mut Context ,
251+ buf : & mut ReadBuf < ' _ > ,
252+ ) -> Poll < tokio:: io:: Result < ( ) > > {
253+ AsyncRead :: poll_read ( self . project ( ) . stream , cx, buf)
254+ }
255+ }
256+
257+ impl < T : AsyncRead + AsyncWrite + Unpin > AsyncWrite for TlsConn < T > {
258+ #[ inline]
259+ fn poll_write (
260+ self : Pin < & mut Self > ,
261+ cx : & mut Context ,
262+ buf : & [ u8 ] ,
263+ ) -> Poll < Result < usize , tokio:: io:: Error > > {
264+ AsyncWrite :: poll_write ( self . project ( ) . stream , cx, buf)
265+ }
266+
267+ #[ inline]
268+ fn poll_write_vectored (
269+ self : Pin < & mut Self > ,
270+ cx : & mut Context < ' _ > ,
271+ bufs : & [ IoSlice < ' _ > ] ,
272+ ) -> Poll < Result < usize , io:: Error > > {
273+ AsyncWrite :: poll_write_vectored ( self . project ( ) . stream , cx, bufs)
274+ }
275+
276+ #[ inline]
277+ fn is_write_vectored ( & self ) -> bool {
278+ self . stream . is_write_vectored ( )
279+ }
280+
281+ #[ inline]
282+ fn poll_flush ( self : Pin < & mut Self > , cx : & mut Context ) -> Poll < Result < ( ) , tokio:: io:: Error > > {
283+ AsyncWrite :: poll_flush ( self . project ( ) . stream , cx)
284+ }
285+
286+ #[ inline]
287+ fn poll_shutdown ( self : Pin < & mut Self > , cx : & mut Context ) -> Poll < Result < ( ) , tokio:: io:: Error > > {
288+ AsyncWrite :: poll_shutdown ( self . project ( ) . stream , cx)
289+ }
290+ }
291+
292+ impl < T > TlsInfoFactory for TlsConn < T >
293+ where
294+ SslStream < T > : TlsInfoFactory ,
295+ {
296+ fn tls_info ( & self ) -> Option < TlsInfo > {
297+ self . stream . tls_info ( )
298+ }
299+ }
300+
132301// ===== impl PoisonPill =====
133302
134303impl fmt:: Debug for PoisonPill {
0 commit comments