5555//! clone2.post("http://example.domain/post").body("foo=bar").send().unwrap();
5656//! });
5757//! ```
58+ use std:: borrow:: Cow ;
5859use std:: default:: Default ;
5960use std:: io:: { self , copy, Read } ;
60- use std:: iter:: Extend ;
6161use std:: fmt;
6262
6363use std:: time:: Duration ;
@@ -66,7 +66,7 @@ use url::Url;
6666use url:: ParseError as UrlError ;
6767
6868use header:: { Headers , Header , HeaderFormat } ;
69- use header:: { ContentLength , Location } ;
69+ use header:: { ContentLength , Host , Location } ;
7070use method:: Method ;
7171use net:: { NetworkConnector , NetworkStream } ;
7272use Error ;
@@ -90,6 +90,7 @@ pub struct Client {
9090 redirect_policy : RedirectPolicy ,
9191 read_timeout : Option < Duration > ,
9292 write_timeout : Option < Duration > ,
93+ proxy : Option < ( Cow < ' static , str > , Cow < ' static , str > , u16 ) >
9394}
9495
9596impl fmt:: Debug for Client {
@@ -98,6 +99,7 @@ impl fmt::Debug for Client {
9899 . field ( "redirect_policy" , & self . redirect_policy )
99100 . field ( "read_timeout" , & self . read_timeout )
100101 . field ( "write_timeout" , & self . write_timeout )
102+ . field ( "proxy" , & self . proxy )
101103 . finish ( )
102104 }
103105}
@@ -127,6 +129,7 @@ impl Client {
127129 redirect_policy : Default :: default ( ) ,
128130 read_timeout : None ,
129131 write_timeout : None ,
132+ proxy : None ,
130133 }
131134 }
132135
@@ -145,6 +148,12 @@ impl Client {
145148 self . write_timeout = dur;
146149 }
147150
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+
148157 /// Build a Get request.
149158 pub fn get < U : IntoUrl > ( & self , url : U ) -> RequestBuilder {
150159 self . request ( Method :: Get , url)
@@ -247,7 +256,7 @@ impl<'a> RequestBuilder<'a> {
247256 pub fn send ( self ) -> :: Result < Response > {
248257 let RequestBuilder { client, method, url, headers, body } = self ;
249258 let mut url = try!( url) ;
250- trace ! ( "send {:?} {:?}" , method, url) ;
259+ trace ! ( "send method= {:?}, url= {:?}, client={:?} " , method, url, client ) ;
251260
252261 let can_have_body = match method {
253262 Method :: Get | Method :: Head => false ,
@@ -261,12 +270,25 @@ impl<'a> RequestBuilder<'a> {
261270 } ;
262271
263272 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)
267291 } ;
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 ( ) ) ) ;
270292
271293 try!( req. set_write_timeout ( client. write_timeout ) ) ;
272294 try!( req. set_read_timeout ( client. read_timeout ) ) ;
@@ -456,6 +478,8 @@ fn get_host_and_port(url: &Url) -> ::Result<(&str, u16)> {
456478mod tests {
457479 use std:: io:: Read ;
458480 use header:: Server ;
481+ use http:: h1:: Http11Message ;
482+ use mock:: { MockStream } ;
459483 use super :: { Client , RedirectPolicy } ;
460484 use super :: pool:: Pool ;
461485 use url:: Url ;
@@ -477,6 +501,30 @@ mod tests {
477501 "
478502 } ) ;
479503
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+
480528 #[ test]
481529 fn test_redirect_followall ( ) {
482530 let mut client = Client :: with_connector ( MockRedirectPolicy ) ;
0 commit comments