@@ -71,10 +71,12 @@ use method::Method;
7171use net:: { NetworkConnector , NetworkStream } ;
7272use Error ;
7373
74+ use self :: proxy:: tunnel;
7475pub use self :: pool:: Pool ;
7576pub use self :: request:: Request ;
7677pub use self :: response:: Response ;
7778
79+ mod proxy;
7880pub mod pool;
7981pub mod request;
8082pub mod response;
@@ -90,7 +92,7 @@ pub struct Client {
9092 redirect_policy : RedirectPolicy ,
9193 read_timeout : Option < Duration > ,
9294 write_timeout : Option < Duration > ,
93- proxy : Option < ( Cow < ' static , str > , Cow < ' static , str > , u16 ) >
95+ proxy : Option < ( Cow < ' static , str > , u16 ) >
9496}
9597
9698impl fmt:: Debug for Client {
@@ -116,6 +118,15 @@ impl Client {
116118 Client :: with_connector ( Pool :: new ( config) )
117119 }
118120
121+ pub fn with_http_proxy < H > ( host : H , port : u16 ) -> Client
122+ where H : Into < Cow < ' static , str > > {
123+ let host = host. into ( ) ;
124+ let proxy = tunnel ( ( host. clone ( ) , port) ) ;
125+ let mut client = Client :: with_connector ( Pool :: with_connector ( Default :: default ( ) , proxy) ) ;
126+ client. proxy = Some ( ( host, port) ) ;
127+ client
128+ }
129+
119130 /// Create a new client with a specific connector.
120131 pub fn with_connector < C , S > ( connector : C ) -> Client
121132 where C : NetworkConnector < Stream =S > + Send + Sync + ' static , S : NetworkStream + Send {
@@ -148,12 +159,6 @@ impl Client {
148159 self . write_timeout = dur;
149160 }
150161
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-
157162 /// Build a Get request.
158163 pub fn get < U : IntoUrl > ( & self , url : U ) -> RequestBuilder {
159164 self . request ( Method :: Get , url)
@@ -271,13 +276,12 @@ impl<'a> RequestBuilder<'a> {
271276
272277 loop {
273278 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- } ;
279+ let ( host, port) = try!( get_host_and_port ( & url) ) ;
280+ let mut message = try!( client. protocol . new_message ( & host, port, url. scheme ( ) ) ) ;
281+ if url. scheme ( ) == "http" && client. proxy . is_some ( ) {
282+ message. set_proxied ( true ) ;
283+ }
284+
281285 let mut headers = match headers {
282286 Some ( ref headers) => headers. clone ( ) ,
283287 None => Headers :: new ( ) ,
@@ -286,7 +290,6 @@ impl<'a> RequestBuilder<'a> {
286290 hostname : host. to_owned ( ) ,
287291 port : Some ( port) ,
288292 } ) ;
289- let message = try!( client. protocol . new_message ( & host, port, scheme) ) ;
290293 Request :: with_headers_and_message ( method. clone ( ) , url. clone ( ) , headers, message)
291294 } ;
292295
@@ -460,6 +463,7 @@ impl Default for RedirectPolicy {
460463 }
461464}
462465
466+
463467fn get_host_and_port ( url : & Url ) -> :: Result < ( & str , u16 ) > {
464468 let host = match url. host_str ( ) {
465469 Some ( host) => host,
@@ -479,8 +483,9 @@ mod tests {
479483 use std:: io:: Read ;
480484 use header:: Server ;
481485 use http:: h1:: Http11Message ;
482- use mock:: { MockStream } ;
486+ use mock:: { MockStream , MockSsl } ;
483487 use super :: { Client , RedirectPolicy } ;
488+ use super :: proxy:: Proxy ;
484489 use super :: pool:: Pool ;
485490 use url:: Url ;
486491
@@ -505,24 +510,61 @@ mod tests {
505510 #[ test]
506511 fn test_proxy ( ) {
507512 use super :: pool:: PooledStream ;
513+ type MessageStream = PooledStream < super :: proxy:: Proxied < MockStream , MockStream > > ;
508514 mock_connector ! ( ProxyConnector {
509515 b"HTTP/1.1 200 OK\r \n Content-Length: 0\r \n \r \n "
510516 } ) ;
511- let mut client = Client :: with_connector ( Pool :: with_connector ( Default :: default ( ) , ProxyConnector ) ) ;
512- client. set_proxy ( "http" , "example.proxy" , 8008 ) ;
517+ let tunnel = Proxy {
518+ connector : ProxyConnector ,
519+ proxy : ( "example.proxy" . into ( ) , 8008 ) ,
520+ ssl : MockSsl ,
521+ } ;
522+ let mut client = Client :: with_connector ( Pool :: with_connector ( Default :: default ( ) , tunnel) ) ;
523+ client. proxy = Some ( ( "example.proxy" . into ( ) , 8008 ) ) ;
513524 let mut dump = vec ! [ ] ;
514525 client. get ( "http://127.0.0.1/foo/bar" ) . send ( ) . unwrap ( ) . read_to_end ( & mut dump) . unwrap ( ) ;
515526
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- }
527+ let box_message = client. protocol . new_message ( "127.0.0.1" , 80 , "http" ) . unwrap ( ) ;
528+ let message = box_message. downcast :: < Http11Message > ( ) . unwrap ( ) ;
529+ let stream = message. into_inner ( ) . downcast :: < MessageStream > ( ) . unwrap ( ) . into_inner ( ) . into_normal ( ) . unwrap ( ) ; ;
530+
531+ let s = :: std:: str:: from_utf8 ( & stream. write ) . unwrap ( ) ;
532+ let request_line = "GET http://127.0.0.1/foo/bar HTTP/1.1\r \n " ;
533+ assert ! ( s. starts_with( request_line) , "{:?} doesn't start with {:?}" , s, request_line) ;
534+ assert ! ( s. contains( "Host: 127.0.0.1\r \n " ) ) ;
535+ }
536+
537+ #[ test]
538+ fn test_proxy_tunnel ( ) {
539+ use super :: pool:: PooledStream ;
540+ type MessageStream = PooledStream < super :: proxy:: Proxied < MockStream , MockStream > > ;
541+
542+ mock_connector ! ( ProxyConnector {
543+ b"HTTP/1.1 200 OK\r \n \r \n " ,
544+ b"HTTP/1.1 200 OK\r \n Content-Length: 0\r \n \r \n "
545+ } ) ;
546+ let tunnel = Proxy {
547+ connector : ProxyConnector ,
548+ proxy : ( "example.proxy" . into ( ) , 8008 ) ,
549+ ssl : MockSsl ,
550+ } ;
551+ let mut client = Client :: with_connector ( Pool :: with_connector ( Default :: default ( ) , tunnel) ) ;
552+ client. proxy = Some ( ( "example.proxy" . into ( ) , 8008 ) ) ;
553+ let mut dump = vec ! [ ] ;
554+ client. get ( "https://127.0.0.1/foo/bar" ) . send ( ) . unwrap ( ) . read_to_end ( & mut dump) . unwrap ( ) ;
555+
556+ let box_message = client. protocol . new_message ( "127.0.0.1" , 443 , "https" ) . unwrap ( ) ;
557+ let message = box_message. downcast :: < Http11Message > ( ) . unwrap ( ) ;
558+ let stream = message. into_inner ( ) . downcast :: < MessageStream > ( ) . unwrap ( ) . into_inner ( ) . into_tunneled ( ) . unwrap ( ) ;
559+
560+ let s = :: std:: str:: from_utf8 ( & stream. write ) . unwrap ( ) ;
561+ let connect_line = "CONNECT 127.0.0.1:443 HTTP/1.1\r \n Host: 127.0.0.1:443\r \n \r \n " ;
562+ assert_eq ! ( & s[ ..connect_line. len( ) ] , connect_line) ;
525563
564+ let s = & s[ connect_line. len ( ) ..] ;
565+ let request_line = "GET /foo/bar HTTP/1.1\r \n " ;
566+ assert_eq ! ( & s[ ..request_line. len( ) ] , request_line) ;
567+ assert ! ( s. contains( "Host: 127.0.0.1\r \n " ) ) ;
526568 }
527569
528570 #[ test]
0 commit comments