@@ -3,6 +3,7 @@ use std::error::Error as StdError;
3
3
use std:: io;
4
4
use std:: mem;
5
5
use std:: net:: { IpAddr , SocketAddr } ;
6
+ use std:: sync:: Arc ;
6
7
use std:: time:: Duration ;
7
8
8
9
use http:: uri:: { Scheme , Uri } ;
@@ -13,7 +14,7 @@ use tokio_net::tcp::TcpStream;
13
14
use tokio_timer:: { Delay , Timeout } ;
14
15
15
16
use crate :: common:: { Future , Pin , Poll , task} ;
16
- use super :: { Connect , Connected , Destination } ;
17
+ use super :: { Connected , Destination } ;
17
18
use super :: dns:: { self , GaiResolver , Resolve } ;
18
19
#[ cfg( feature = "runtime" ) ] use super :: dns:: TokioThreadpoolGaiResolver ;
19
20
@@ -30,17 +31,8 @@ type ConnectFuture = Pin<Box<dyn Future<Output = io::Result<TcpStream>> + Send>>
30
31
/// transport information such as the remote socket address used.
31
32
#[ derive( Clone ) ]
32
33
pub struct HttpConnector < R = GaiResolver > {
33
- enforce_http : bool ,
34
- handle : Option < Handle > ,
35
- connect_timeout : Option < Duration > ,
36
- happy_eyeballs_timeout : Option < Duration > ,
37
- keep_alive_timeout : Option < Duration > ,
38
- local_address : Option < IpAddr > ,
39
- nodelay : bool ,
34
+ config : Arc < Config > ,
40
35
resolver : R ,
41
- reuse_address : bool ,
42
- send_buffer_size : Option < usize > ,
43
- recv_buffer_size : Option < usize > ,
44
36
}
45
37
46
38
/// Extra information about the transport when an HttpConnector is used.
@@ -76,6 +68,22 @@ pub struct HttpInfo {
76
68
remote_addr : SocketAddr ,
77
69
}
78
70
71
+ #[ derive( Clone ) ]
72
+ struct Config {
73
+ connect_timeout : Option < Duration > ,
74
+ enforce_http : bool ,
75
+ handle : Option < Handle > ,
76
+ happy_eyeballs_timeout : Option < Duration > ,
77
+ keep_alive_timeout : Option < Duration > ,
78
+ local_address : Option < IpAddr > ,
79
+ nodelay : bool ,
80
+ reuse_address : bool ,
81
+ send_buffer_size : Option < usize > ,
82
+ recv_buffer_size : Option < usize > ,
83
+ }
84
+
85
+ // ===== impl HttpConnector =====
86
+
79
87
impl HttpConnector {
80
88
/// Construct a new HttpConnector.
81
89
pub fn new ( ) -> HttpConnector {
@@ -100,17 +108,19 @@ impl<R> HttpConnector<R> {
100
108
/// Takes a `Resolve` to handle DNS lookups.
101
109
pub fn new_with_resolver ( resolver : R ) -> HttpConnector < R > {
102
110
HttpConnector {
103
- enforce_http : true ,
104
- handle : None ,
105
- connect_timeout : None ,
106
- happy_eyeballs_timeout : Some ( Duration :: from_millis ( 300 ) ) ,
107
- keep_alive_timeout : None ,
108
- local_address : None ,
109
- nodelay : false ,
111
+ config : Arc :: new ( Config {
112
+ connect_timeout : None ,
113
+ enforce_http : true ,
114
+ handle : None ,
115
+ happy_eyeballs_timeout : Some ( Duration :: from_millis ( 300 ) ) ,
116
+ keep_alive_timeout : None ,
117
+ local_address : None ,
118
+ nodelay : false ,
119
+ reuse_address : false ,
120
+ send_buffer_size : None ,
121
+ recv_buffer_size : None ,
122
+ } ) ,
110
123
resolver,
111
- reuse_address : false ,
112
- send_buffer_size : None ,
113
- recv_buffer_size : None ,
114
124
}
115
125
}
116
126
@@ -119,15 +129,15 @@ impl<R> HttpConnector<R> {
119
129
/// Enabled by default.
120
130
#[ inline]
121
131
pub fn enforce_http ( & mut self , is_enforced : bool ) {
122
- self . enforce_http = is_enforced;
132
+ self . config_mut ( ) . enforce_http = is_enforced;
123
133
}
124
134
125
135
/// Set a handle to a `Reactor` to register connections to.
126
136
///
127
137
/// If `None`, the implicit default reactor will be used.
128
138
#[ inline]
129
139
pub fn set_reactor ( & mut self , handle : Option < Handle > ) {
130
- self . handle = handle;
140
+ self . config_mut ( ) . handle = handle;
131
141
}
132
142
133
143
/// Set that all sockets have `SO_KEEPALIVE` set with the supplied duration.
@@ -137,27 +147,27 @@ impl<R> HttpConnector<R> {
137
147
/// Default is `None`.
138
148
#[ inline]
139
149
pub fn set_keepalive ( & mut self , dur : Option < Duration > ) {
140
- self . keep_alive_timeout = dur;
150
+ self . config_mut ( ) . keep_alive_timeout = dur;
141
151
}
142
152
143
153
/// Set that all sockets have `SO_NODELAY` set to the supplied value `nodelay`.
144
154
///
145
155
/// Default is `false`.
146
156
#[ inline]
147
157
pub fn set_nodelay ( & mut self , nodelay : bool ) {
148
- self . nodelay = nodelay;
158
+ self . config_mut ( ) . nodelay = nodelay;
149
159
}
150
160
151
161
/// Sets the value of the SO_SNDBUF option on the socket.
152
162
#[ inline]
153
163
pub fn set_send_buffer_size ( & mut self , size : Option < usize > ) {
154
- self . send_buffer_size = size;
164
+ self . config_mut ( ) . send_buffer_size = size;
155
165
}
156
166
157
167
/// Sets the value of the SO_RCVBUF option on the socket.
158
168
#[ inline]
159
169
pub fn set_recv_buffer_size ( & mut self , size : Option < usize > ) {
160
- self . recv_buffer_size = size;
170
+ self . config_mut ( ) . recv_buffer_size = size;
161
171
}
162
172
163
173
/// Set that all sockets are bound to the configured address before connection.
@@ -167,7 +177,7 @@ impl<R> HttpConnector<R> {
167
177
/// Default is `None`.
168
178
#[ inline]
169
179
pub fn set_local_address ( & mut self , addr : Option < IpAddr > ) {
170
- self . local_address = addr;
180
+ self . config_mut ( ) . local_address = addr;
171
181
}
172
182
173
183
/// Set the connect timeout.
@@ -178,7 +188,7 @@ impl<R> HttpConnector<R> {
178
188
/// Default is `None`.
179
189
#[ inline]
180
190
pub fn set_connect_timeout ( & mut self , dur : Option < Duration > ) {
181
- self . connect_timeout = dur;
191
+ self . config_mut ( ) . connect_timeout = dur;
182
192
}
183
193
184
194
/// Set timeout for [RFC 6555 (Happy Eyeballs)][RFC 6555] algorithm.
@@ -195,17 +205,26 @@ impl<R> HttpConnector<R> {
195
205
/// [RFC 6555]: https://tools.ietf.org/html/rfc6555
196
206
#[ inline]
197
207
pub fn set_happy_eyeballs_timeout ( & mut self , dur : Option < Duration > ) {
198
- self . happy_eyeballs_timeout = dur;
208
+ self . config_mut ( ) . happy_eyeballs_timeout = dur;
199
209
}
200
210
201
211
/// Set that all socket have `SO_REUSEADDR` set to the supplied value `reuse_address`.
202
212
///
203
213
/// Default is `false`.
204
214
#[ inline]
205
215
pub fn set_reuse_address ( & mut self , reuse_address : bool ) -> & mut Self {
206
- self . reuse_address = reuse_address;
216
+ self . config_mut ( ) . reuse_address = reuse_address;
207
217
self
208
218
}
219
+
220
+ // private
221
+
222
+ fn config_mut ( & mut self ) -> & mut Config {
223
+ // If the are HttpConnector clones, this will clone the inner
224
+ // config. So mutating the config won't ever affect previous
225
+ // clones.
226
+ Arc :: make_mut ( & mut self . config )
227
+ }
209
228
}
210
229
211
230
// R: Debug required for now to allow adding it to debug output later...
@@ -216,51 +235,59 @@ impl<R: fmt::Debug> fmt::Debug for HttpConnector<R> {
216
235
}
217
236
}
218
237
219
- impl < R > Connect for HttpConnector < R >
238
+ impl < R > tower_service :: Service < Destination > for HttpConnector < R >
220
239
where
221
240
R : Resolve + Clone + Send + Sync ,
222
241
R :: Future : Send ,
223
242
{
224
- type Transport = TcpStream ;
243
+ type Response = ( TcpStream , Connected ) ;
225
244
type Error = io:: Error ;
226
245
type Future = HttpConnecting < R > ;
227
246
228
- fn connect ( & self , dst : Destination ) -> Self :: Future {
247
+ fn poll_ready ( & mut self , cx : & mut task:: Context < ' _ > ) -> Poll < Result < ( ) , Self :: Error > > {
248
+ // For now, always ready.
249
+ // TODO: When `Resolve` becomes an alias for `Service`, check
250
+ // the resolver's readiness.
251
+ drop ( cx) ;
252
+ Poll :: Ready ( Ok ( ( ) ) )
253
+ }
254
+
255
+ fn call ( & mut self , dst : Destination ) -> Self :: Future {
229
256
trace ! (
230
257
"Http::connect; scheme={}, host={}, port={:?}" ,
231
258
dst. scheme( ) ,
232
259
dst. host( ) ,
233
260
dst. port( ) ,
234
261
) ;
235
262
236
- if self . enforce_http {
263
+ if self . config . enforce_http {
237
264
if dst. uri . scheme_part ( ) != Some ( & Scheme :: HTTP ) {
238
- return invalid_url ( InvalidUrl :: NotHttp , & self . handle ) ;
265
+ return invalid_url ( InvalidUrl :: NotHttp , & self . config . handle ) ;
239
266
}
240
267
} else if dst. uri . scheme_part ( ) . is_none ( ) {
241
- return invalid_url ( InvalidUrl :: MissingScheme , & self . handle ) ;
268
+ return invalid_url ( InvalidUrl :: MissingScheme , & self . config . handle ) ;
242
269
}
243
270
244
271
let host = match dst. uri . host ( ) {
245
272
Some ( s) => s,
246
- None => return invalid_url ( InvalidUrl :: MissingAuthority , & self . handle ) ,
273
+ None => return invalid_url ( InvalidUrl :: MissingAuthority , & self . config . handle ) ,
247
274
} ;
248
275
let port = match dst. uri . port_part ( ) {
249
276
Some ( port) => port. as_u16 ( ) ,
250
277
None => if dst. uri . scheme_part ( ) == Some ( & Scheme :: HTTPS ) { 443 } else { 80 } ,
251
278
} ;
252
279
253
280
HttpConnecting {
254
- state : State :: Lazy ( self . resolver . clone ( ) , host. into ( ) , self . local_address ) ,
255
- handle : self . handle . clone ( ) ,
256
- connect_timeout : self . connect_timeout ,
257
- happy_eyeballs_timeout : self . happy_eyeballs_timeout ,
258
- keep_alive_timeout : self . keep_alive_timeout ,
259
- nodelay : self . nodelay ,
281
+ state : State :: Lazy ( self . resolver . clone ( ) , host. into ( ) , self . config . local_address ) ,
282
+ handle : self . config . handle . clone ( ) ,
283
+ connect_timeout : self . config . connect_timeout ,
284
+ happy_eyeballs_timeout : self . config . happy_eyeballs_timeout ,
285
+ keep_alive_timeout : self . config . keep_alive_timeout ,
286
+ nodelay : self . config . nodelay ,
260
287
port,
261
- reuse_address : self . reuse_address ,
262
- send_buffer_size : self . send_buffer_size ,
263
- recv_buffer_size : self . recv_buffer_size ,
288
+ reuse_address : self . config . reuse_address ,
289
+ send_buffer_size : self . config . send_buffer_size ,
290
+ recv_buffer_size : self . config . recv_buffer_size ,
264
291
}
265
292
}
266
293
}
@@ -289,34 +316,34 @@ where
289
316
dst. port( ) ,
290
317
) ;
291
318
292
- if self . enforce_http {
319
+ if self . config . enforce_http {
293
320
if dst. uri . scheme_part ( ) != Some ( & Scheme :: HTTP ) {
294
- return invalid_url :: < R > ( InvalidUrl :: NotHttp , & self . handle ) . map_ok ( |( s, _) | s) . boxed ( ) ;
321
+ return invalid_url :: < R > ( InvalidUrl :: NotHttp , & self . config . handle ) . map_ok ( |( s, _) | s) . boxed ( ) ;
295
322
}
296
323
} else if dst. uri . scheme_part ( ) . is_none ( ) {
297
- return invalid_url :: < R > ( InvalidUrl :: MissingScheme , & self . handle ) . map_ok ( |( s, _) | s) . boxed ( ) ;
324
+ return invalid_url :: < R > ( InvalidUrl :: MissingScheme , & self . config . handle ) . map_ok ( |( s, _) | s) . boxed ( ) ;
298
325
}
299
326
300
327
let host = match dst. uri . host ( ) {
301
328
Some ( s) => s,
302
- None => return invalid_url :: < R > ( InvalidUrl :: MissingAuthority , & self . handle ) . map_ok ( |( s, _) | s) . boxed ( ) ,
329
+ None => return invalid_url :: < R > ( InvalidUrl :: MissingAuthority , & self . config . handle ) . map_ok ( |( s, _) | s) . boxed ( ) ,
303
330
} ;
304
331
let port = match dst. uri . port_part ( ) {
305
332
Some ( port) => port. as_u16 ( ) ,
306
333
None => if dst. uri . scheme_part ( ) == Some ( & Scheme :: HTTPS ) { 443 } else { 80 } ,
307
334
} ;
308
335
309
336
let fut = HttpConnecting {
310
- state : State :: Lazy ( self . resolver . clone ( ) , host. into ( ) , self . local_address ) ,
311
- handle : self . handle . clone ( ) ,
312
- connect_timeout : self . connect_timeout ,
313
- happy_eyeballs_timeout : self . happy_eyeballs_timeout ,
314
- keep_alive_timeout : self . keep_alive_timeout ,
315
- nodelay : self . nodelay ,
337
+ state : State :: Lazy ( self . resolver . clone ( ) , host. into ( ) , self . config . local_address ) ,
338
+ handle : self . config . handle . clone ( ) ,
339
+ connect_timeout : self . config . connect_timeout ,
340
+ happy_eyeballs_timeout : self . config . happy_eyeballs_timeout ,
341
+ keep_alive_timeout : self . config . keep_alive_timeout ,
342
+ nodelay : self . config . nodelay ,
316
343
port,
317
- reuse_address : self . reuse_address ,
318
- send_buffer_size : self . send_buffer_size ,
319
- recv_buffer_size : self . recv_buffer_size ,
344
+ reuse_address : self . config . reuse_address ,
345
+ send_buffer_size : self . config . send_buffer_size ,
346
+ recv_buffer_size : self . config . recv_buffer_size ,
320
347
} ;
321
348
322
349
fut. map_ok ( |( s, _) | s) . boxed ( )
@@ -671,7 +698,15 @@ mod tests {
671
698
use tokio:: runtime:: current_thread:: Runtime ;
672
699
use tokio_net:: driver:: Handle ;
673
700
674
- use super :: { Connect , Destination , HttpConnector } ;
701
+ use super :: { Connected , Destination , HttpConnector } ;
702
+ use super :: super :: sealed:: Connect ;
703
+
704
+ async fn connect < C > ( connector : C , dst : Destination ) -> Result < ( C :: Transport , Connected ) , C :: Error >
705
+ where
706
+ C : Connect ,
707
+ {
708
+ connector. connect ( super :: super :: sealed:: Internal , dst) . await
709
+ }
675
710
676
711
#[ test]
677
712
fn test_errors_missing_authority ( ) {
@@ -684,7 +719,7 @@ mod tests {
684
719
685
720
rt. block_on ( async {
686
721
assert_eq ! (
687
- connector . connect( dst) . await . unwrap_err( ) . kind( ) ,
722
+ connect( connector , dst) . await . unwrap_err( ) . kind( ) ,
688
723
io:: ErrorKind :: InvalidInput ,
689
724
) ;
690
725
} )
@@ -701,7 +736,7 @@ mod tests {
701
736
702
737
rt. block_on ( async {
703
738
assert_eq ! (
704
- connector . connect( dst) . await . unwrap_err( ) . kind( ) ,
739
+ connect( connector , dst) . await . unwrap_err( ) . kind( ) ,
705
740
io:: ErrorKind :: InvalidInput ,
706
741
) ;
707
742
} )
@@ -718,7 +753,7 @@ mod tests {
718
753
719
754
rt. block_on ( async {
720
755
assert_eq ! (
721
- connector . connect( dst) . await . unwrap_err( ) . kind( ) ,
756
+ connect( connector , dst) . await . unwrap_err( ) . kind( ) ,
722
757
io:: ErrorKind :: InvalidInput ,
723
758
) ;
724
759
} ) ;
0 commit comments