@@ -32,8 +32,8 @@ use crate::{
3232 error:: { BoxError , TimedOut , map_timeout_to_connector_error} ,
3333 proxy:: { Intercepted , Matcher as ProxyMatcher } ,
3434 tls:: {
35- CertStore , HttpsConnector , Identity , KeyLogPolicy , MaybeHttpsStream , TlsConfig ,
36- TlsConnector , TlsConnectorBuilder , TlsInfo , TlsVersion ,
35+ CertStore , EstablishedConn , HttpsConnector , Identity , KeyLogPolicy , MaybeHttpsStream ,
36+ TlsConfig , TlsConnector , TlsConnectorBuilder , TlsInfo , TlsVersion ,
3737 } ,
3838} ;
3939
@@ -305,7 +305,6 @@ impl Connector {
305305 #[ cfg( feature = "socks" ) ]
306306 resolver : resolver. clone ( ) ,
307307 http : {
308- // Create a new HttpConnector with the provided resolver
309308 let mut http = HttpConnector :: new_with_resolver ( resolver) ;
310309 http. enforce_http ( false ) ;
311310 http
@@ -314,8 +313,6 @@ impl Connector {
314313 verbose : verbose:: OFF ,
315314 timeout : None ,
316315 tcp_nodelay : false ,
317-
318- // TLS connector and its configuration
319316 tls_info : false ,
320317 tls_builder : TlsConnector :: builder ( ) ,
321318 }
@@ -367,7 +364,25 @@ pub(crate) struct ConnectorService {
367364}
368365
369366impl ConnectorService {
370- async fn connect ( self , mut req : ConnRequest , is_proxy : bool ) -> Result < Conn , BoxError > {
367+ /// Constructs an HTTPS connector by wrapping an `HttpConnector`
368+ /// with the appropriate TLS configuration.
369+ fn build_tls_connector (
370+ & self ,
371+ mut http : HttpConnector ,
372+ req : & mut ConnRequest ,
373+ ) -> Result < HttpsConnector < HttpConnector > , BoxError > {
374+ let ex_data = req. ex_data ( ) ;
375+ http. set_tcp_connect_options ( ex_data. tcp_connect_options ( ) . cloned ( ) ) ;
376+ let tls = match ex_data. tls_config ( ) {
377+ Some ( cfg) => self . tls_builder . build ( cfg. clone ( ) ) ?,
378+ None => self . tls . clone ( ) ,
379+ } ;
380+ Ok ( HttpsConnector :: with_connector ( http, tls) )
381+ }
382+
383+ /// Establishes a direct connection to the target URI without using a proxy.
384+ /// May perform a plain TCP or a TLS handshake depending on the URI scheme.
385+ async fn connect_direct ( self , mut req : ConnRequest , is_proxy : bool ) -> Result < Conn , BoxError > {
371386 trace ! ( "connect with maybe proxy: {:?}" , is_proxy) ;
372387
373388 let uri = req. uri ( ) . clone ( ) ;
@@ -380,8 +395,8 @@ impl ConnectorService {
380395 http. set_nodelay ( true ) ;
381396 }
382397
383- let mut connector = self . create_https_connector ( http, & mut req) ?;
384- let io = connector. call ( uri ) . await ?;
398+ let mut connector = self . build_tls_connector ( http, & mut req) ?;
399+ let io = connector. call ( req ) . await ?;
385400
386401 // If the connection is HTTPS, wrap the TLS stream in a TlsConn for unified handling.
387402 // For plain HTTP, use the stream directly without additional wrapping.
@@ -403,7 +418,9 @@ impl ConnectorService {
403418 } )
404419 }
405420
406- async fn connect_via_proxy (
421+ /// Establishes a connection through a specified proxy.
422+ /// Supports both SOCKS and HTTP tunneling proxies.
423+ async fn connect_with_proxy (
407424 self ,
408425 mut req : ConnRequest ,
409426 proxy : Intercepted ,
@@ -437,8 +454,9 @@ impl ConnectorService {
437454
438455 return if uri. scheme ( ) == Some ( & Scheme :: HTTPS ) {
439456 trace ! ( "socks HTTPS over proxy" ) ;
440- let mut connector = self . create_https_connector ( self . http . clone ( ) , & mut req) ?;
441- let io = connector. call ( ( uri, conn) ) . await ?;
457+ let mut connector = self . build_tls_connector ( self . http . clone ( ) , & mut req) ?;
458+ let established_conn = EstablishedConn :: new ( req, conn) ;
459+ let io = connector. call ( established_conn) . await ?;
442460
443461 Ok ( Conn {
444462 inner : self . verbose . wrap ( TlsConn {
@@ -460,7 +478,7 @@ impl ConnectorService {
460478 // Handle HTTPS proxy tunneling connection
461479 if uri. scheme ( ) == Some ( & Scheme :: HTTPS ) {
462480 trace ! ( "tunneling HTTPS over HTTP proxy: {:?}" , proxy_uri) ;
463- let mut connector = self . create_https_connector ( self . http . clone ( ) , & mut req) ?;
481+ let mut connector = self . build_tls_connector ( self . http . clone ( ) , & mut req) ?;
464482
465483 let mut tunnel = proxy:: Tunnel :: new ( proxy_uri, connector. clone ( ) ) ;
466484 if let Some ( auth) = proxy. basic_auth ( ) {
@@ -473,10 +491,11 @@ impl ConnectorService {
473491
474492 // We don't wrap this again in an HttpsConnector since that uses Maybe,
475493 // and we know this is definitely HTTPS.
476- let tunneled = tunnel. call ( uri. clone ( ) ) . await ?;
494+ let tunneled = tunnel. call ( uri) . await ?;
477495 let tunneled = TokioIo :: new ( tunneled) ;
478496 let tunneled = TokioIo :: new ( tunneled) ;
479- let io = connector. call ( ( uri, tunneled) ) . await ?;
497+ let established_conn = EstablishedConn :: new ( req, tunneled) ;
498+ let io = connector. call ( established_conn) . await ?;
480499
481500 return Ok ( Conn {
482501 inner : self . verbose . wrap ( TlsConn {
@@ -487,44 +506,42 @@ impl ConnectorService {
487506 } ) ;
488507 }
489508
490- // Update the connect URI to the proxy URI
491509 * req. uri_mut ( ) = proxy_uri;
492-
493- self . connect ( req, true ) . await
510+ self . connect_direct ( req, true ) . await
494511 }
495512
496- fn create_https_connector (
497- & self ,
498- http : HttpConnector ,
499- conn_req : & mut ConnRequest ,
500- ) -> Result < HttpsConnector < HttpConnector > , BoxError > {
501- let ( tcp_opts, tls_cfg, alpn_protocol) = conn_req. take_config_bundle ( ) ;
502-
503- let tls = tls_cfg
504- . map ( |cfg| self . tls_builder . build ( cfg) )
505- . transpose ( ) ?
506- . unwrap_or_else ( || self . tls . clone ( ) ) ;
513+ /// Automatically selects between a direct or proxied connection
514+ /// based on the request and configured proxy matchers.
515+ /// Applies a timeout if configured.
516+ async fn connect_auto ( self , req : ConnRequest ) -> Result < Conn , BoxError > {
517+ debug ! ( "starting new connection: {:?}" , req. uri( ) ) ;
507518
508- let mut connector = HttpsConnector :: with_connector ( http, tls) ;
509- connector. set_alpn_protocol ( alpn_protocol) ;
510- connector. set_tcp_connect_options ( tcp_opts) ;
519+ let intercepted = req
520+ . ex_data ( )
521+ . proxy_matcher ( )
522+ . and_then ( |scheme| scheme. intercept ( req. uri ( ) ) )
523+ . or_else ( || {
524+ self . proxies
525+ . iter ( )
526+ . find_map ( |prox| prox. intercept ( req. uri ( ) ) )
527+ } ) ;
511528
512- Ok ( connector)
513- }
514- }
529+ let timeout = self . timeout ;
530+ let fut = async {
531+ if let Some ( intercepted) = intercepted {
532+ self . connect_with_proxy ( req, intercepted) . await
533+ } else {
534+ self . connect_direct ( req, false ) . await
535+ }
536+ } ;
515537
516- async fn with_timeout < T , F > ( f : F , timeout : Option < Duration > ) -> Result < T , BoxError >
517- where
518- F : Future < Output = Result < T , BoxError > > ,
519- {
520- if let Some ( to) = timeout {
521- match tokio:: time:: timeout ( to, f) . await {
522- Err ( _elapsed) => Err ( Box :: new ( TimedOut ) as BoxError ) ,
523- Ok ( Ok ( try_res) ) => Ok ( try_res) ,
524- Ok ( Err ( e) ) => Err ( e) ,
538+ if let Some ( to) = timeout {
539+ tokio:: time:: timeout ( to, fut)
540+ . await
541+ . map_err ( |_| BoxError :: from ( TimedOut ) ) ?
542+ } else {
543+ fut. await
525544 }
526- } else {
527- f. await
528545 }
529546}
530547
@@ -538,26 +555,9 @@ impl Service<ConnRequest> for ConnectorService {
538555 Poll :: Ready ( Ok ( ( ) ) )
539556 }
540557
541- fn call ( & mut self , mut req : ConnRequest ) -> Self :: Future {
542- debug ! ( "starting new connection: {:?}" , req. uri( ) ) ;
543-
544- let intercepted = req
545- . take_proxy_matcher ( )
546- . and_then ( |scheme| scheme. intercept ( req. uri ( ) ) )
547- . or_else ( || {
548- self . proxies
549- . iter ( )
550- . find_map ( |prox| prox. intercept ( req. uri ( ) ) )
551- } ) ;
552-
553- if let Some ( intercepted) = intercepted {
554- return Box :: pin ( with_timeout (
555- self . clone ( ) . connect_via_proxy ( req, intercepted) ,
556- self . timeout ,
557- ) ) ;
558- }
559-
560- Box :: pin ( with_timeout ( self . clone ( ) . connect ( req, false ) , self . timeout ) )
558+ #[ inline( always) ]
559+ fn call ( & mut self , req : ConnRequest ) -> Self :: Future {
560+ Box :: pin ( self . clone ( ) . connect_auto ( req) )
561561 }
562562}
563563
@@ -627,7 +627,7 @@ mod conn {
627627
628628 pin_project ! {
629629 /// Note: the `is_proxy` member means *is plain text HTTP proxy*.
630- /// This tells hyper whether the URI should be written in
630+ /// This tells core whether the URI should be written in
631631 /// * origin-form (`GET /just/a/path HTTP/1.1`), when `is_proxy == false`, or
632632 /// * absolute-form (`GET http://foo.bar/and/a/path HTTP/1.1`), otherwise.
633633 pub struct Conn {
0 commit comments