11//! http-client implementation for async-h1, with connecton pooling ("Keep-Alive").
22
3+ #[ cfg( feature = "unstable-config" ) ]
4+ use std:: convert:: { Infallible , TryFrom } ;
5+
36use std:: fmt:: Debug ;
47use std:: net:: SocketAddr ;
8+ use std:: sync:: Arc ;
59
610use async_h1:: client;
711use async_std:: net:: TcpStream ;
@@ -17,6 +21,8 @@ cfg_if::cfg_if! {
1721 }
1822}
1923
24+ use crate :: Config ;
25+
2026use super :: { async_trait, Error , HttpClient , Request , Response } ;
2127
2228mod tcp;
@@ -40,6 +46,7 @@ pub struct H1Client {
4046 #[ cfg( any( feature = "native-tls" , feature = "rustls" ) ) ]
4147 https_pools : HttpsPool ,
4248 max_concurrent_connections : usize ,
49+ config : Arc < Config > ,
4350}
4451
4552impl Debug for H1Client {
@@ -79,6 +86,7 @@ impl Debug for H1Client {
7986 "max_concurrent_connections" ,
8087 & self . max_concurrent_connections ,
8188 )
89+ . field ( "config" , & self . config )
8290 . finish ( )
8391 }
8492}
@@ -97,6 +105,7 @@ impl H1Client {
97105 #[ cfg( any( feature = "native-tls" , feature = "rustls" ) ) ]
98106 https_pools : DashMap :: new ( ) ,
99107 max_concurrent_connections : DEFAULT_MAX_CONCURRENT_CONNECTIONS ,
108+ config : Arc :: new ( Config :: default ( ) ) ,
100109 }
101110 }
102111
@@ -107,6 +116,7 @@ impl H1Client {
107116 #[ cfg( any( feature = "native-tls" , feature = "rustls" ) ) ]
108117 https_pools : DashMap :: new ( ) ,
109118 max_concurrent_connections : max,
119+ config : Arc :: new ( Config :: default ( ) ) ,
110120 }
111121 }
112122}
@@ -147,12 +157,43 @@ impl HttpClient for H1Client {
147157 for ( idx, addr) in addrs. into_iter ( ) . enumerate ( ) {
148158 let has_another_addr = idx != max_addrs_idx;
149159
160+ #[ cfg( feature = "unstable-config" ) ]
161+ if !self . config . http_keep_alive {
162+ match scheme {
163+ "http" => {
164+ let stream = async_std:: net:: TcpStream :: connect ( addr) . await ?;
165+ req. set_peer_addr ( stream. peer_addr ( ) . ok ( ) ) ;
166+ req. set_local_addr ( stream. local_addr ( ) . ok ( ) ) ;
167+ let tcp_conn = client:: connect ( stream, req) ;
168+ return if let Some ( timeout) = self . config . timeout {
169+ async_std:: future:: timeout ( timeout, tcp_conn) . await ?
170+ } else {
171+ tcp_conn. await
172+ } ;
173+ }
174+ #[ cfg( any( feature = "native-tls" , feature = "rustls" ) ) ]
175+ "https" => {
176+ let raw_stream = async_std:: net:: TcpStream :: connect ( addr) . await ?;
177+ req. set_peer_addr ( raw_stream. peer_addr ( ) . ok ( ) ) ;
178+ req. set_local_addr ( raw_stream. local_addr ( ) . ok ( ) ) ;
179+ let tls_stream = tls:: add_tls ( & host, raw_stream, & self . config ) . await ?;
180+ let tsl_conn = client:: connect ( tls_stream, req) ;
181+ return if let Some ( timeout) = self . config . timeout {
182+ async_std:: future:: timeout ( timeout, tsl_conn) . await ?
183+ } else {
184+ tsl_conn. await
185+ } ;
186+ }
187+ _ => unreachable ! ( ) ,
188+ }
189+ }
190+
150191 match scheme {
151192 "http" => {
152193 let pool_ref = if let Some ( pool_ref) = self . http_pools . get ( & addr) {
153194 pool_ref
154195 } else {
155- let manager = TcpConnection :: new ( addr) ;
196+ let manager = TcpConnection :: new ( addr, self . config . clone ( ) ) ;
156197 let pool = Pool :: < TcpStream , std:: io:: Error > :: new (
157198 manager,
158199 self . max_concurrent_connections ,
@@ -168,19 +209,28 @@ impl HttpClient for H1Client {
168209 let stream = match pool. get ( ) . await {
169210 Ok ( s) => s,
170211 Err ( _) if has_another_addr => continue ,
171- Err ( e) => return Err ( Error :: from_str ( 400 , e. to_string ( ) ) ) ? ,
212+ Err ( e) => return Err ( Error :: from_str ( 400 , e. to_string ( ) ) ) ,
172213 } ;
173214
174215 req. set_peer_addr ( stream. peer_addr ( ) . ok ( ) ) ;
175216 req. set_local_addr ( stream. local_addr ( ) . ok ( ) ) ;
176- return client:: connect ( TcpConnWrapper :: new ( stream) , req) . await ;
217+
218+ let tcp_conn = client:: connect ( TcpConnWrapper :: new ( stream) , req) ;
219+ #[ cfg( feature = "unstable-config" ) ]
220+ return if let Some ( timeout) = self . config . timeout {
221+ async_std:: future:: timeout ( timeout, tcp_conn) . await ?
222+ } else {
223+ tcp_conn. await
224+ } ;
225+ #[ cfg( not( feature = "unstable-config" ) ) ]
226+ return tcp_conn. await ;
177227 }
178228 #[ cfg( any( feature = "native-tls" , feature = "rustls" ) ) ]
179229 "https" => {
180230 let pool_ref = if let Some ( pool_ref) = self . https_pools . get ( & addr) {
181231 pool_ref
182232 } else {
183- let manager = TlsConnection :: new ( host. clone ( ) , addr) ;
233+ let manager = TlsConnection :: new ( host. clone ( ) , addr, self . config . clone ( ) ) ;
184234 let pool = Pool :: < TlsStream < TcpStream > , Error > :: new (
185235 manager,
186236 self . max_concurrent_connections ,
@@ -196,13 +246,21 @@ impl HttpClient for H1Client {
196246 let stream = match pool. get ( ) . await {
197247 Ok ( s) => s,
198248 Err ( _) if has_another_addr => continue ,
199- Err ( e) => return Err ( Error :: from_str ( 400 , e. to_string ( ) ) ) ? ,
249+ Err ( e) => return Err ( Error :: from_str ( 400 , e. to_string ( ) ) ) ,
200250 } ;
201251
202252 req. set_peer_addr ( stream. get_ref ( ) . peer_addr ( ) . ok ( ) ) ;
203253 req. set_local_addr ( stream. get_ref ( ) . local_addr ( ) . ok ( ) ) ;
204254
205- return client:: connect ( TlsConnWrapper :: new ( stream) , req) . await ;
255+ let tls_conn = client:: connect ( TlsConnWrapper :: new ( stream) , req) ;
256+ #[ cfg( feature = "unstable-config" ) ]
257+ return if let Some ( timeout) = self . config . timeout {
258+ async_std:: future:: timeout ( timeout, tls_conn) . await ?
259+ } else {
260+ tls_conn. await
261+ } ;
262+ #[ cfg( not( feature = "unstable-config" ) ) ]
263+ return tls_conn. await ;
206264 }
207265 _ => unreachable ! ( ) ,
208266 }
@@ -213,6 +271,37 @@ impl HttpClient for H1Client {
213271 "missing valid address" ,
214272 ) )
215273 }
274+
275+ #[ cfg( feature = "unstable-config" ) ]
276+ /// Override the existing configuration with new configuration.
277+ ///
278+ /// Config options may not impact existing connections.
279+ fn set_config ( & mut self , config : Config ) -> http_types:: Result < ( ) > {
280+ self . config = Arc :: new ( config) ;
281+
282+ Ok ( ( ) )
283+ }
284+
285+ #[ cfg( feature = "unstable-config" ) ]
286+ /// Get the current configuration.
287+ fn config ( & self ) -> & Config {
288+ & * self . config
289+ }
290+ }
291+
292+ #[ cfg( feature = "unstable-config" ) ]
293+ impl TryFrom < Config > for H1Client {
294+ type Error = Infallible ;
295+
296+ fn try_from ( config : Config ) -> Result < Self , Self :: Error > {
297+ Ok ( Self {
298+ http_pools : DashMap :: new ( ) ,
299+ #[ cfg( any( feature = "native-tls" , feature = "rustls" ) ) ]
300+ https_pools : DashMap :: new ( ) ,
301+ max_concurrent_connections : DEFAULT_MAX_CONCURRENT_CONNECTIONS ,
302+ config : Arc :: new ( config) ,
303+ } )
304+ }
216305}
217306
218307#[ cfg( test) ]
0 commit comments