1
1
//! http-client implementation for async-h1, with connecton pooling ("Keep-Alive").
2
2
3
+ #[ cfg( feature = "unstable-config" ) ]
4
+ use std:: convert:: { Infallible , TryFrom } ;
5
+
3
6
use std:: fmt:: Debug ;
4
7
use std:: net:: SocketAddr ;
8
+ use std:: sync:: Arc ;
5
9
6
10
use async_h1:: client;
7
11
use async_std:: net:: TcpStream ;
@@ -17,6 +21,8 @@ cfg_if::cfg_if! {
17
21
}
18
22
}
19
23
24
+ use crate :: Config ;
25
+
20
26
use super :: { async_trait, Error , HttpClient , Request , Response } ;
21
27
22
28
mod tcp;
@@ -40,6 +46,7 @@ pub struct H1Client {
40
46
#[ cfg( any( feature = "native-tls" , feature = "rustls" ) ) ]
41
47
https_pools : HttpsPool ,
42
48
max_concurrent_connections : usize ,
49
+ config : Arc < Config > ,
43
50
}
44
51
45
52
impl Debug for H1Client {
@@ -79,6 +86,7 @@ impl Debug for H1Client {
79
86
"max_concurrent_connections" ,
80
87
& self . max_concurrent_connections ,
81
88
)
89
+ . field ( "config" , & self . config )
82
90
. finish ( )
83
91
}
84
92
}
@@ -97,6 +105,7 @@ impl H1Client {
97
105
#[ cfg( any( feature = "native-tls" , feature = "rustls" ) ) ]
98
106
https_pools : DashMap :: new ( ) ,
99
107
max_concurrent_connections : DEFAULT_MAX_CONCURRENT_CONNECTIONS ,
108
+ config : Arc :: new ( Config :: default ( ) ) ,
100
109
}
101
110
}
102
111
@@ -107,6 +116,7 @@ impl H1Client {
107
116
#[ cfg( any( feature = "native-tls" , feature = "rustls" ) ) ]
108
117
https_pools : DashMap :: new ( ) ,
109
118
max_concurrent_connections : max,
119
+ config : Arc :: new ( Config :: default ( ) ) ,
110
120
}
111
121
}
112
122
}
@@ -147,12 +157,43 @@ impl HttpClient for H1Client {
147
157
for ( idx, addr) in addrs. into_iter ( ) . enumerate ( ) {
148
158
let has_another_addr = idx != max_addrs_idx;
149
159
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
+
150
191
match scheme {
151
192
"http" => {
152
193
let pool_ref = if let Some ( pool_ref) = self . http_pools . get ( & addr) {
153
194
pool_ref
154
195
} else {
155
- let manager = TcpConnection :: new ( addr) ;
196
+ let manager = TcpConnection :: new ( addr, self . config . clone ( ) ) ;
156
197
let pool = Pool :: < TcpStream , std:: io:: Error > :: new (
157
198
manager,
158
199
self . max_concurrent_connections ,
@@ -168,19 +209,28 @@ impl HttpClient for H1Client {
168
209
let stream = match pool. get ( ) . await {
169
210
Ok ( s) => s,
170
211
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 ( ) ) ) ,
172
213
} ;
173
214
174
215
req. set_peer_addr ( stream. peer_addr ( ) . ok ( ) ) ;
175
216
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 ;
177
227
}
178
228
#[ cfg( any( feature = "native-tls" , feature = "rustls" ) ) ]
179
229
"https" => {
180
230
let pool_ref = if let Some ( pool_ref) = self . https_pools . get ( & addr) {
181
231
pool_ref
182
232
} else {
183
- let manager = TlsConnection :: new ( host. clone ( ) , addr) ;
233
+ let manager = TlsConnection :: new ( host. clone ( ) , addr, self . config . clone ( ) ) ;
184
234
let pool = Pool :: < TlsStream < TcpStream > , Error > :: new (
185
235
manager,
186
236
self . max_concurrent_connections ,
@@ -196,13 +246,21 @@ impl HttpClient for H1Client {
196
246
let stream = match pool. get ( ) . await {
197
247
Ok ( s) => s,
198
248
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 ( ) ) ) ,
200
250
} ;
201
251
202
252
req. set_peer_addr ( stream. get_ref ( ) . peer_addr ( ) . ok ( ) ) ;
203
253
req. set_local_addr ( stream. get_ref ( ) . local_addr ( ) . ok ( ) ) ;
204
254
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 ;
206
264
}
207
265
_ => unreachable ! ( ) ,
208
266
}
@@ -213,6 +271,37 @@ impl HttpClient for H1Client {
213
271
"missing valid address" ,
214
272
) )
215
273
}
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
+ }
216
305
}
217
306
218
307
#[ cfg( test) ]
0 commit comments