@@ -71,10 +71,12 @@ use method::Method;
71
71
use net:: { NetworkConnector , NetworkStream } ;
72
72
use Error ;
73
73
74
+ use self :: proxy:: tunnel;
74
75
pub use self :: pool:: Pool ;
75
76
pub use self :: request:: Request ;
76
77
pub use self :: response:: Response ;
77
78
79
+ mod proxy;
78
80
pub mod pool;
79
81
pub mod request;
80
82
pub mod response;
@@ -90,7 +92,7 @@ pub struct Client {
90
92
redirect_policy : RedirectPolicy ,
91
93
read_timeout : Option < Duration > ,
92
94
write_timeout : Option < Duration > ,
93
- proxy : Option < ( Cow < ' static , str > , Cow < ' static , str > , u16 ) >
95
+ proxy : Option < ( Cow < ' static , str > , u16 ) >
94
96
}
95
97
96
98
impl fmt:: Debug for Client {
@@ -116,6 +118,15 @@ impl Client {
116
118
Client :: with_connector ( Pool :: new ( config) )
117
119
}
118
120
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
+
119
130
/// Create a new client with a specific connector.
120
131
pub fn with_connector < C , S > ( connector : C ) -> Client
121
132
where C : NetworkConnector < Stream =S > + Send + Sync + ' static , S : NetworkStream + Send {
@@ -148,12 +159,6 @@ impl Client {
148
159
self . write_timeout = dur;
149
160
}
150
161
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
-
157
162
/// Build a Get request.
158
163
pub fn get < U : IntoUrl > ( & self , url : U ) -> RequestBuilder {
159
164
self . request ( Method :: Get , url)
@@ -271,13 +276,12 @@ impl<'a> RequestBuilder<'a> {
271
276
272
277
loop {
273
278
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
+
281
285
let mut headers = match headers {
282
286
Some ( ref headers) => headers. clone ( ) ,
283
287
None => Headers :: new ( ) ,
@@ -286,7 +290,6 @@ impl<'a> RequestBuilder<'a> {
286
290
hostname : host. to_owned ( ) ,
287
291
port : Some ( port) ,
288
292
} ) ;
289
- let message = try!( client. protocol . new_message ( & host, port, scheme) ) ;
290
293
Request :: with_headers_and_message ( method. clone ( ) , url. clone ( ) , headers, message)
291
294
} ;
292
295
@@ -460,6 +463,7 @@ impl Default for RedirectPolicy {
460
463
}
461
464
}
462
465
466
+
463
467
fn get_host_and_port ( url : & Url ) -> :: Result < ( & str , u16 ) > {
464
468
let host = match url. host_str ( ) {
465
469
Some ( host) => host,
@@ -479,8 +483,9 @@ mod tests {
479
483
use std:: io:: Read ;
480
484
use header:: Server ;
481
485
use http:: h1:: Http11Message ;
482
- use mock:: { MockStream } ;
486
+ use mock:: { MockStream , MockSsl } ;
483
487
use super :: { Client , RedirectPolicy } ;
488
+ use super :: proxy:: Proxy ;
484
489
use super :: pool:: Pool ;
485
490
use url:: Url ;
486
491
@@ -505,24 +510,61 @@ mod tests {
505
510
#[ test]
506
511
fn test_proxy ( ) {
507
512
use super :: pool:: PooledStream ;
513
+ type MessageStream = PooledStream < super :: proxy:: Proxied < MockStream , MockStream > > ;
508
514
mock_connector ! ( ProxyConnector {
509
515
b"HTTP/1.1 200 OK\r \n Content-Length: 0\r \n \r \n "
510
516
} ) ;
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 ) ) ;
513
524
let mut dump = vec ! [ ] ;
514
525
client. get ( "http://127.0.0.1/foo/bar" ) . send ( ) . unwrap ( ) . read_to_end ( & mut dump) . unwrap ( ) ;
515
526
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) ;
525
563
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 " ) ) ;
526
568
}
527
569
528
570
#[ test]
0 commit comments