6
6
//! establishes connections over TCP.
7
7
//! - The [`Connect`](Connect) trait and related types to build custom connectors.
8
8
use std:: error:: Error as StdError ;
9
- use std:: mem;
9
+ use std:: { fmt , mem} ;
10
10
11
11
use bytes:: { BufMut , Bytes , BytesMut } ;
12
12
use futures:: Future ;
13
- use http:: { uri, Uri } ;
13
+ use http:: { uri, Response , Uri } ;
14
14
use tokio_io:: { AsyncRead , AsyncWrite } ;
15
15
16
16
#[ cfg( feature = "runtime" ) ] mod dns;
17
17
#[ cfg( feature = "runtime" ) ] mod http;
18
- #[ cfg( feature = "runtime" ) ] pub use self :: http:: HttpConnector ;
18
+ #[ cfg( feature = "runtime" ) ] pub use self :: http:: { HttpConnector , HttpInfo } ;
19
19
20
20
/// Connect to a destination, returning an IO transport.
21
21
///
@@ -48,8 +48,11 @@ pub struct Destination {
48
48
pub struct Connected {
49
49
//alpn: Alpn,
50
50
pub ( super ) is_proxied : bool ,
51
+ pub ( super ) extra : Option < Extra > ,
51
52
}
52
53
54
+ pub ( super ) struct Extra ( Box < ExtraInner > ) ;
55
+
53
56
/*TODO: when HTTP1 Upgrades to H2 are added, this will be needed
54
57
#[derive(Debug)]
55
58
pub(super) enum Alpn {
@@ -245,6 +248,7 @@ impl Connected {
245
248
Connected {
246
249
//alpn: Alpn::Http1,
247
250
is_proxied : false ,
251
+ extra : None ,
248
252
}
249
253
}
250
254
@@ -260,6 +264,12 @@ impl Connected {
260
264
self
261
265
}
262
266
267
+ /// Set extra connection information to be set in the extensions of every `Response`.
268
+ pub fn extra < T : Clone + Send + Sync + ' static > ( mut self , extra : T ) -> Connected {
269
+ self . extra = Some ( Extra ( Box :: new ( ExtraEnvelope ( extra) ) ) ) ;
270
+ self
271
+ }
272
+
263
273
/*
264
274
/// Set that the connected transport negotiated HTTP/2 as it's
265
275
/// next protocol.
@@ -268,6 +278,61 @@ impl Connected {
268
278
self
269
279
}
270
280
*/
281
+
282
+ // Don't public expose that `Connected` is `Clone`, unsure if we want to
283
+ // keep that contract...
284
+ pub ( super ) fn clone ( & self ) -> Connected {
285
+ Connected {
286
+ is_proxied : self . is_proxied ,
287
+ extra : self . extra . clone ( ) ,
288
+ }
289
+ }
290
+ }
291
+
292
+ // ===== impl Extra =====
293
+
294
+ impl Extra {
295
+ pub ( super ) fn set ( & self , res : & mut Response < :: Body > ) {
296
+ self . 0 . set ( res) ;
297
+ }
298
+ }
299
+
300
+ impl Clone for Extra {
301
+ fn clone ( & self ) -> Extra {
302
+ Extra ( self . 0 . clone_box ( ) )
303
+ }
304
+ }
305
+
306
+ impl fmt:: Debug for Extra {
307
+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
308
+ f. debug_struct ( "Extra" )
309
+ . finish ( )
310
+ }
311
+ }
312
+
313
+ // This indirection allows the `Connected` to have a type-erased "extra" value,
314
+ // while that type still knows its inner extra type. This allows the correct
315
+ // TypeId to be used when inserting into `res.extensions_mut()`.
316
+ #[ derive( Clone ) ]
317
+ struct ExtraEnvelope < T > ( T ) ;
318
+
319
+ trait ExtraInner : Send + Sync {
320
+ fn clone_box ( & self ) -> Box < ExtraInner > ;
321
+ fn set ( & self , res : & mut Response < :: Body > ) ;
322
+ }
323
+
324
+ impl < T > ExtraInner for ExtraEnvelope < T >
325
+ where
326
+ T : Clone + Send + Sync + ' static
327
+ {
328
+ fn clone_box ( & self ) -> Box < ExtraInner > {
329
+ Box :: new ( self . clone ( ) )
330
+ }
331
+
332
+ fn set ( & self , res : & mut Response < :: Body > ) {
333
+ let extra = self . 0 . clone ( ) ;
334
+ res. extensions_mut ( ) . insert ( extra) ;
335
+ }
271
336
}
272
337
273
338
#[ cfg( test) ]
0 commit comments