55
55
//! clone2.post("http://example.domain/post").body("foo=bar").send().unwrap();
56
56
//! });
57
57
//! ```
58
+ use std:: borrow:: Cow ;
58
59
use std:: default:: Default ;
59
60
use std:: io:: { self , copy, Read } ;
60
- use std:: iter:: Extend ;
61
61
use std:: fmt;
62
62
63
63
use std:: time:: Duration ;
@@ -66,7 +66,7 @@ use url::Url;
66
66
use url:: ParseError as UrlError ;
67
67
68
68
use header:: { Headers , Header , HeaderFormat } ;
69
- use header:: { ContentLength , Location } ;
69
+ use header:: { ContentLength , Host , Location } ;
70
70
use method:: Method ;
71
71
use net:: { NetworkConnector , NetworkStream } ;
72
72
use Error ;
@@ -90,6 +90,7 @@ pub struct Client {
90
90
redirect_policy : RedirectPolicy ,
91
91
read_timeout : Option < Duration > ,
92
92
write_timeout : Option < Duration > ,
93
+ proxy : Option < ( Cow < ' static , str > , Cow < ' static , str > , u16 ) >
93
94
}
94
95
95
96
impl fmt:: Debug for Client {
@@ -98,6 +99,7 @@ impl fmt::Debug for Client {
98
99
. field ( "redirect_policy" , & self . redirect_policy )
99
100
. field ( "read_timeout" , & self . read_timeout )
100
101
. field ( "write_timeout" , & self . write_timeout )
102
+ . field ( "proxy" , & self . proxy )
101
103
. finish ( )
102
104
}
103
105
}
@@ -127,6 +129,7 @@ impl Client {
127
129
redirect_policy : Default :: default ( ) ,
128
130
read_timeout : None ,
129
131
write_timeout : None ,
132
+ proxy : None ,
130
133
}
131
134
}
132
135
@@ -145,6 +148,12 @@ impl Client {
145
148
self . write_timeout = dur;
146
149
}
147
150
151
+ /// Set a proxy for requests of this Client.
152
+ pub fn set_proxy < S , H > ( & mut self , scheme : S , host : H , port : u16 )
153
+ where S : Into < Cow < ' static , str > > , H : Into < Cow < ' static , str > > {
154
+ self . proxy = Some ( ( scheme. into ( ) , host. into ( ) , port) ) ;
155
+ }
156
+
148
157
/// Build a Get request.
149
158
pub fn get < U : IntoUrl > ( & self , url : U ) -> RequestBuilder {
150
159
self . request ( Method :: Get , url)
@@ -247,7 +256,7 @@ impl<'a> RequestBuilder<'a> {
247
256
pub fn send ( self ) -> :: Result < Response > {
248
257
let RequestBuilder { client, method, url, headers, body } = self ;
249
258
let mut url = try!( url) ;
250
- trace ! ( "send {:?} {:?}" , method, url) ;
259
+ trace ! ( "send method= {:?}, url= {:?}, client={:?} " , method, url, client ) ;
251
260
252
261
let can_have_body = match method {
253
262
Method :: Get | Method :: Head => false ,
@@ -261,12 +270,25 @@ impl<'a> RequestBuilder<'a> {
261
270
} ;
262
271
263
272
loop {
264
- let message = {
265
- let ( host, port) = try!( get_host_and_port ( & url) ) ;
266
- try!( client. protocol . new_message ( & host, port, url. scheme ( ) ) )
273
+ let mut req = {
274
+ let ( scheme, host, port) = match client. proxy {
275
+ Some ( ref proxy) => ( proxy. 0 . as_ref ( ) , proxy. 1 . as_ref ( ) , proxy. 2 ) ,
276
+ None => {
277
+ let hp = try!( get_host_and_port ( & url) ) ;
278
+ ( url. scheme ( ) , hp. 0 , hp. 1 )
279
+ }
280
+ } ;
281
+ let mut headers = match headers {
282
+ Some ( ref headers) => headers. clone ( ) ,
283
+ None => Headers :: new ( ) ,
284
+ } ;
285
+ headers. set ( Host {
286
+ hostname : host. to_owned ( ) ,
287
+ port : Some ( port) ,
288
+ } ) ;
289
+ let message = try!( client. protocol . new_message ( & host, port, scheme) ) ;
290
+ Request :: with_headers_and_message ( method. clone ( ) , url. clone ( ) , headers, message)
267
291
} ;
268
- let mut req = try!( Request :: with_message ( method. clone ( ) , url. clone ( ) , message) ) ;
269
- headers. as_ref ( ) . map ( |headers| req. headers_mut ( ) . extend ( headers. iter ( ) ) ) ;
270
292
271
293
try!( req. set_write_timeout ( client. write_timeout ) ) ;
272
294
try!( req. set_read_timeout ( client. read_timeout ) ) ;
@@ -456,6 +478,8 @@ fn get_host_and_port(url: &Url) -> ::Result<(&str, u16)> {
456
478
mod tests {
457
479
use std:: io:: Read ;
458
480
use header:: Server ;
481
+ use http:: h1:: Http11Message ;
482
+ use mock:: { MockStream } ;
459
483
use super :: { Client , RedirectPolicy } ;
460
484
use super :: pool:: Pool ;
461
485
use url:: Url ;
@@ -477,6 +501,30 @@ mod tests {
477
501
"
478
502
} ) ;
479
503
504
+
505
+ #[ test]
506
+ fn test_proxy ( ) {
507
+ use super :: pool:: PooledStream ;
508
+ mock_connector ! ( ProxyConnector {
509
+ b"HTTP/1.1 200 OK\r \n Content-Length: 0\r \n \r \n "
510
+ } ) ;
511
+ let mut client = Client :: with_connector ( Pool :: with_connector ( Default :: default ( ) , ProxyConnector ) ) ;
512
+ client. set_proxy ( "http" , "example.proxy" , 8008 ) ;
513
+ let mut dump = vec ! [ ] ;
514
+ client. get ( "http://127.0.0.1/foo/bar" ) . send ( ) . unwrap ( ) . read_to_end ( & mut dump) . unwrap ( ) ;
515
+
516
+ {
517
+ let box_message = client. protocol . new_message ( "example.proxy" , 8008 , "http" ) . unwrap ( ) ;
518
+ let message = box_message. downcast :: < Http11Message > ( ) . unwrap ( ) ;
519
+ let stream = message. into_inner ( ) . downcast :: < PooledStream < MockStream > > ( ) . unwrap ( ) . into_inner ( ) ;
520
+ let s = :: std:: str:: from_utf8 ( & stream. write ) . unwrap ( ) ;
521
+ let request_line = "GET http://127.0.0.1/foo/bar HTTP/1.1\r \n " ;
522
+ assert_eq ! ( & s[ ..request_line. len( ) ] , request_line) ;
523
+ assert ! ( s. contains( "Host: example.proxy:8008\r \n " ) ) ;
524
+ }
525
+
526
+ }
527
+
480
528
#[ test]
481
529
fn test_redirect_followall ( ) {
482
530
let mut client = Client :: with_connector ( MockRedirectPolicy ) ;
0 commit comments