@@ -21,16 +21,17 @@ use hyper::{
21
21
ext:: HeaderCaseMap ,
22
22
Body , Client , Uri ,
23
23
} ;
24
- use hyper_openssl:: HttpsConnector ;
24
+ use hyper_openssl:: { HttpsConnector , MaybeHttpsStream } ;
25
+ use hyper_proxy:: { Intercept , Proxy , ProxyConnector as HttpProxyConnector , ProxyStream } ;
25
26
use hyper_socks2:: SocksConnector ;
26
27
use ipnet:: IpNet ;
27
- use openssl:: ssl:: { SslConnector , SslMethod , SslVerifyMode } ;
28
+ use openssl:: ssl:: { SslConnector , SslConnectorBuilder , SslMethod , SslVerifyMode } ;
28
29
use serde:: Serialize ;
29
30
use thiserror:: Error ;
30
31
use tokio:: { net:: TcpStream , sync:: Mutex } ;
31
32
use tower:: Service ;
32
33
33
- use crate :: cfg:: ProxyConfig ;
34
+ use crate :: cfg:: { ProxyAddr , ProxyConfig } ;
34
35
35
36
pub type CaseSensitiveHeaderMap = HashMap < String , HeaderValue > ;
36
37
@@ -55,7 +56,7 @@ pub enum Error {
55
56
56
57
#[ derive( Clone ) ]
57
58
pub struct WebhookClient {
58
- client : Client < HttpsConnector < SvixHttpConnector > , Body > ,
59
+ client : Client < SvixHttpsConnector , Body > ,
59
60
whitelist_nets : Arc < Vec < IpNet > > ,
60
61
}
61
62
@@ -64,7 +65,7 @@ impl WebhookClient {
64
65
whitelist_nets : Option < Arc < Vec < IpNet > > > ,
65
66
whitelist_names : Option < Arc < Vec < String > > > ,
66
67
dangerous_disable_tls_verification : bool ,
67
- proxy_config : Option < ProxyConfig > ,
68
+ proxy_config : Option < & ProxyConfig > ,
68
69
) -> Self {
69
70
let whitelist_nets = whitelist_nets. unwrap_or_else ( || Arc :: new ( Vec :: new ( ) ) ) ;
70
71
let whitelist_names = whitelist_names. unwrap_or_else ( || Arc :: new ( Vec :: new ( ) ) ) ;
@@ -81,8 +82,8 @@ impl WebhookClient {
81
82
ssl. set_verify ( SslVerifyMode :: NONE ) ;
82
83
}
83
84
84
- let http = SvixHttpConnector :: new ( http, proxy_config) ;
85
- let https = HttpsConnector :: with_connector ( http , ssl ) . expect ( "HttpsConnector build failed" ) ;
85
+ let https = SvixHttpsConnector :: new ( http, proxy_config, ssl )
86
+ . expect ( "SvixHttpsConnector build failed" ) ;
86
87
87
88
let client: Client < _ , hyper:: Body > = Client :: builder ( )
88
89
. http1_ignore_invalid_headers_in_responses ( true )
@@ -428,54 +429,87 @@ impl RequestBuilder {
428
429
}
429
430
}
430
431
431
- /// Plain-HTTP connector that blocks outgoing requests to private IPs with
432
- /// support for optionally proxying via SOCKS5.
433
- #[ derive( Clone , Debug ) ]
434
- enum SvixHttpConnector {
435
- Regular ( NonLocalHttpConnector ) ,
436
- Proxied ( SocksConnector < NonLocalHttpConnector > ) ,
432
+ /// HTTP connector that blocks outgoing requests to private IPs with support
433
+ /// for HTTPS and optionally proxying via SOCKS5 or HTTP(S).
434
+ #[ derive( Clone ) ]
435
+ enum SvixHttpsConnector {
436
+ Regular ( HttpsConnector < NonLocalHttpConnector > ) ,
437
+ Socks5Proxy ( HttpsConnector < SocksConnector < NonLocalHttpConnector > > ) ,
438
+ HttpProxy ( HttpProxyConnector < HttpConnector < NonLocalDnsResolver > > ) ,
437
439
}
438
440
439
- impl SvixHttpConnector {
440
- fn new ( inner : NonLocalHttpConnector , proxy_cfg : Option < ProxyConfig > ) -> Self {
441
+ impl SvixHttpsConnector {
442
+ fn new (
443
+ inner : NonLocalHttpConnector ,
444
+ proxy_cfg : Option < & ProxyConfig > ,
445
+ ssl : SslConnectorBuilder ,
446
+ ) -> Result < Self , Box < dyn std:: error:: Error > > {
441
447
match proxy_cfg {
442
- Some ( proxy_cfg) => Self :: Proxied ( SocksConnector {
443
- proxy_addr : proxy_cfg. addr . into ( ) ,
444
- auth : None ,
445
- connector : inner,
446
- } ) ,
447
- None => Self :: Regular ( inner) ,
448
+ Some ( proxy_cfg) => match proxy_cfg. addr . clone ( ) {
449
+ // In the SOCKS5 case, TLS is handled inside of the proxy
450
+ // TcpStream, by the same code that would do it without a proxy
451
+ ProxyAddr :: Socks5 ( proxy_addr) => {
452
+ let socks = SocksConnector {
453
+ proxy_addr,
454
+ auth : None ,
455
+ connector : inner,
456
+ } ;
457
+ let socks_https = HttpsConnector :: with_connector ( socks, ssl) ?;
458
+ Ok ( Self :: Socks5Proxy ( socks_https) )
459
+ }
460
+ // In the HTTP proxy case, TLS is handled by the proxy connector
461
+ ProxyAddr :: Http ( proxy_addr) => {
462
+ let proxy = Proxy :: new ( Intercept :: All , proxy_addr) ;
463
+ Ok ( Self :: HttpProxy ( HttpProxyConnector :: from_proxy (
464
+ inner, proxy,
465
+ ) ?) )
466
+ }
467
+ } ,
468
+ None => {
469
+ let https = HttpsConnector :: with_connector ( inner, ssl) ?;
470
+ Ok ( Self :: Regular ( https) )
471
+ }
448
472
}
449
473
}
450
474
}
451
475
452
- impl Service < Uri > for SvixHttpConnector {
453
- type Response = TcpStream ;
454
- type Error = hyper_socks2 :: Error ;
476
+ impl Service < Uri > for SvixHttpsConnector {
477
+ type Response = ProxyStream < TcpStream > ;
478
+ type Error = Box < dyn std :: error :: Error + Send + Sync > ;
455
479
type Future = Pin < Box < dyn Future < Output = Result < Self :: Response , Self :: Error > > + Send > > ;
456
480
457
481
fn poll_ready (
458
482
& mut self ,
459
483
cx : & mut std:: task:: Context < ' _ > ,
460
484
) -> std:: task:: Poll < Result < ( ) , Self :: Error > > {
461
485
match self {
462
- Self :: Regular ( inner) => inner
463
- . poll_ready ( cx)
464
- . map_err ( |e| hyper_socks2:: Error :: Connector ( e. into ( ) ) ) ,
465
- Self :: Proxied ( inner) => inner. poll_ready ( cx) ,
486
+ Self :: Regular ( inner) => inner. poll_ready ( cx) ,
487
+ Self :: Socks5Proxy ( inner) => inner. poll_ready ( cx) ,
488
+ Self :: HttpProxy ( inner) => inner. poll_ready ( cx) . map_err ( Into :: into) ,
466
489
}
467
490
}
468
491
469
492
fn call ( & mut self , req : Uri ) -> Self :: Future {
493
+ fn convert_stream ( maybe_https : MaybeHttpsStream < TcpStream > ) -> ProxyStream < TcpStream > {
494
+ match maybe_https {
495
+ MaybeHttpsStream :: Http ( stream) => ProxyStream :: NoProxy ( stream) ,
496
+ MaybeHttpsStream :: Https ( stream) => ProxyStream :: Secured ( stream) ,
497
+ }
498
+ }
499
+
470
500
match self {
471
501
Self :: Regular ( inner) => {
472
502
let fut = inner. call ( req) ;
473
- Box :: pin ( async move {
474
- fut. await
475
- . map_err ( |e| hyper_socks2:: Error :: Connector ( e. into ( ) ) )
476
- } )
503
+ Box :: pin ( async move { Ok ( convert_stream ( fut. await ?) ) } )
504
+ }
505
+ Self :: Socks5Proxy ( inner) => {
506
+ let fut = inner. call ( req) ;
507
+ Box :: pin ( async move { Ok ( convert_stream ( fut. await ?) ) } )
508
+ }
509
+ Self :: HttpProxy ( inner) => {
510
+ let fut = inner. call ( req) ;
511
+ Box :: pin ( async move { fut. await . map_err ( Into :: into) } )
477
512
}
478
- Self :: Proxied ( inner) => Box :: pin ( inner. call ( req) ) ,
479
513
}
480
514
}
481
515
}
0 commit comments