@@ -125,10 +125,11 @@ impl Connected {
125
125
mod http {
126
126
use super :: * ;
127
127
128
+ use std:: borrow:: Cow ;
128
129
use std:: fmt;
129
130
use std:: io;
130
131
use std:: mem;
131
- use std:: net:: SocketAddr ;
132
+ use std:: net:: { IpAddr , SocketAddr } ;
132
133
use std:: sync:: Arc ;
133
134
use std:: time:: Duration ;
134
135
@@ -146,30 +147,35 @@ mod http {
146
147
use self :: http_connector:: HttpConnectorBlockingTask ;
147
148
148
149
149
- fn connect ( addr : & SocketAddr , handle : & Option < Handle > ) -> io:: Result < ConnectFuture > {
150
- if let Some ( ref handle) = * handle {
151
- let builder = match addr {
152
- & SocketAddr :: V4 ( _) => TcpBuilder :: new_v4 ( ) ?,
153
- & SocketAddr :: V6 ( _) => TcpBuilder :: new_v6 ( ) ?,
150
+ fn connect ( addr : & SocketAddr , local_addr : & Option < IpAddr > , handle : & Option < Handle > ) -> io:: Result < ConnectFuture > {
151
+ let builder = match addr {
152
+ & SocketAddr :: V4 ( _) => TcpBuilder :: new_v4 ( ) ?,
153
+ & SocketAddr :: V6 ( _) => TcpBuilder :: new_v6 ( ) ?,
154
+ } ;
155
+
156
+ if let Some ( ref local_addr) = * local_addr {
157
+ // Caller has requested this socket be bound before calling connect
158
+ builder. bind ( SocketAddr :: new ( local_addr. clone ( ) , 0 ) ) ?;
159
+ }
160
+ else if cfg ! ( windows) {
161
+ // Windows requires a socket be bound before calling connect
162
+ let any: SocketAddr = match addr {
163
+ & SocketAddr :: V4 ( _) => {
164
+ ( [ 0 , 0 , 0 , 0 ] , 0 ) . into ( )
165
+ } ,
166
+ & SocketAddr :: V6 ( _) => {
167
+ ( [ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] , 0 ) . into ( )
168
+ }
154
169
} ;
170
+ builder. bind ( any) ?;
171
+ }
155
172
156
- if cfg ! ( windows) {
157
- // Windows requires a socket be bound before calling connect
158
- let any: SocketAddr = match addr {
159
- & SocketAddr :: V4 ( _) => {
160
- ( [ 0 , 0 , 0 , 0 ] , 0 ) . into ( )
161
- } ,
162
- & SocketAddr :: V6 ( _) => {
163
- ( [ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] , 0 ) . into ( )
164
- }
165
- } ;
166
- builder. bind ( any) ?;
167
- }
173
+ let handle = match * handle {
174
+ Some ( ref handle) => Cow :: Borrowed ( handle) ,
175
+ None => Cow :: Owned ( Handle :: current ( ) ) ,
176
+ } ;
168
177
169
- Ok ( TcpStream :: connect_std ( builder. to_tcp_stream ( ) ?, addr, handle) )
170
- } else {
171
- Ok ( TcpStream :: connect ( addr) )
172
- }
178
+ Ok ( TcpStream :: connect_std ( builder. to_tcp_stream ( ) ?, addr, & handle) )
173
179
}
174
180
175
181
/// A connector for the `http` scheme.
@@ -182,6 +188,7 @@ mod http {
182
188
handle : Option < Handle > ,
183
189
keep_alive_timeout : Option < Duration > ,
184
190
nodelay : bool ,
191
+ local_address : Option < IpAddr > ,
185
192
}
186
193
187
194
impl HttpConnector {
@@ -218,6 +225,7 @@ mod http {
218
225
handle,
219
226
keep_alive_timeout : None ,
220
227
nodelay : false ,
228
+ local_address : None ,
221
229
}
222
230
}
223
231
@@ -246,6 +254,16 @@ mod http {
246
254
pub fn set_nodelay ( & mut self , nodelay : bool ) {
247
255
self . nodelay = nodelay;
248
256
}
257
+
258
+ /// Set that all sockets are bound to the configured address before connection.
259
+ ///
260
+ /// If `None`, the sockets will not be bound.
261
+ ///
262
+ /// Default is `None`.
263
+ #[ inline]
264
+ pub fn set_local_address ( & mut self , addr : Option < IpAddr > ) {
265
+ self . local_address = addr;
266
+ }
249
267
}
250
268
251
269
impl fmt:: Debug for HttpConnector {
@@ -287,7 +305,7 @@ mod http {
287
305
} ;
288
306
289
307
HttpConnecting {
290
- state : State :: Lazy ( self . executor . clone ( ) , host. into ( ) , port) ,
308
+ state : State :: Lazy ( self . executor . clone ( ) , host. into ( ) , port, self . local_address ) ,
291
309
handle : self . handle . clone ( ) ,
292
310
keep_alive_timeout : self . keep_alive_timeout ,
293
311
nodelay : self . nodelay ,
@@ -337,8 +355,8 @@ mod http {
337
355
}
338
356
339
357
enum State {
340
- Lazy ( HttpConnectExecutor , String , u16 ) ,
341
- Resolving ( oneshot:: SpawnHandle < dns:: IpAddrs , io:: Error > ) ,
358
+ Lazy ( HttpConnectExecutor , String , u16 , Option < IpAddr > ) ,
359
+ Resolving ( oneshot:: SpawnHandle < dns:: IpAddrs , io:: Error > , Option < IpAddr > ) ,
342
360
Connecting ( ConnectingTcp ) ,
343
361
Error ( Option < io:: Error > ) ,
344
362
}
@@ -351,26 +369,28 @@ mod http {
351
369
loop {
352
370
let state;
353
371
match self . state {
354
- State :: Lazy ( ref executor, ref mut host, port) => {
372
+ State :: Lazy ( ref executor, ref mut host, port, local_addr ) => {
355
373
// If the host is already an IP addr (v4 or v6),
356
374
// skip resolving the dns and start connecting right away.
357
375
if let Some ( addrs) = dns:: IpAddrs :: try_parse ( host, port) {
358
376
state = State :: Connecting ( ConnectingTcp {
359
377
addrs : addrs,
378
+ local_addr : local_addr,
360
379
current : None
361
380
} )
362
381
} else {
363
382
let host = mem:: replace ( host, String :: new ( ) ) ;
364
383
let work = dns:: Work :: new ( host, port) ;
365
- state = State :: Resolving ( oneshot:: spawn ( work, executor) ) ;
384
+ state = State :: Resolving ( oneshot:: spawn ( work, executor) , local_addr ) ;
366
385
}
367
386
} ,
368
- State :: Resolving ( ref mut future) => {
387
+ State :: Resolving ( ref mut future, local_addr ) => {
369
388
match try!( future. poll ( ) ) {
370
389
Async :: NotReady => return Ok ( Async :: NotReady ) ,
371
390
Async :: Ready ( addrs) => {
372
391
state = State :: Connecting ( ConnectingTcp {
373
392
addrs : addrs,
393
+ local_addr : local_addr,
374
394
current : None ,
375
395
} )
376
396
}
@@ -402,6 +422,7 @@ mod http {
402
422
403
423
struct ConnectingTcp {
404
424
addrs : dns:: IpAddrs ,
425
+ local_addr : Option < IpAddr > ,
405
426
current : Option < ConnectFuture > ,
406
427
}
407
428
@@ -418,14 +439,14 @@ mod http {
418
439
err = Some ( e) ;
419
440
if let Some ( addr) = self . addrs . next ( ) {
420
441
debug ! ( "connecting to {}" , addr) ;
421
- * current = connect ( & addr, handle) ?;
442
+ * current = connect ( & addr, & self . local_addr , handle) ?;
422
443
continue ;
423
444
}
424
445
}
425
446
}
426
447
} else if let Some ( addr) = self . addrs . next ( ) {
427
448
debug ! ( "connecting to {}" , addr) ;
428
- self . current = Some ( connect ( & addr, handle) ?) ;
449
+ self . current = Some ( connect ( & addr, & self . local_addr , handle) ?) ;
429
450
continue ;
430
451
}
431
452
0 commit comments