diff options
author | Sean McArthur <sean@seanmonstar.com> | 2024-07-24 13:20:06 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-07-24 20:20:06 +0000 |
commit | c7f468d33b5d0814b56036639eb2a8226d4bfbbf (patch) | |
tree | 7464522c9574c57d2c3e9c4902278864631d83f1 /ext/fetch/proxy.rs | |
parent | b305ba3e1c155a33139ec0d764f547ffde4d4de4 (diff) |
fix(ext/fetch): use correct ALPN to proxies (#24696)
Sending ALPN to a proxy, and then when tunneling, requires better
juggling of TLS configs. This improves the choice of TLS config in the
proxy connector, based on what reqwest does. It also includes some
`ext/fetch/tests.rs` that check the different combinations.
Fixes #24632
Fixes #24691
Diffstat (limited to 'ext/fetch/proxy.rs')
-rw-r--r-- | ext/fetch/proxy.rs | 61 |
1 files changed, 31 insertions, 30 deletions
diff --git a/ext/fetch/proxy.rs b/ext/fetch/proxy.rs index db187c3f6..c8e54d5ec 100644 --- a/ext/fetch/proxy.rs +++ b/ext/fetch/proxy.rs @@ -17,6 +17,8 @@ use deno_tls::rustls::ClientConfig as TlsConfig; use http::header::HeaderValue; use http::uri::Scheme; use http::Uri; +use hyper_rustls::HttpsConnector; +use hyper_rustls::MaybeHttpsStream; use hyper_util::client::legacy::connect::Connected; use hyper_util::client::legacy::connect::Connection; use hyper_util::rt::TokioIo; @@ -29,10 +31,14 @@ use tower_service::Service; #[derive(Debug, Clone)] pub(crate) struct ProxyConnector<C> { - connector: C, - proxies: Arc<Proxies>, - tls: Arc<TlsConfig>, - user_agent: Option<HeaderValue>, + pub(crate) http: C, + pub(crate) proxies: Arc<Proxies>, + /// TLS config when destination is not a proxy + pub(crate) tls: Arc<TlsConfig>, + /// TLS config when destination is a proxy + /// Notably, does not include ALPN + pub(crate) tls_proxy: Arc<TlsConfig>, + pub(crate) user_agent: Option<HeaderValue>, } #[derive(Debug)] @@ -361,23 +367,6 @@ impl DomainMatcher { } impl<C> ProxyConnector<C> { - pub(crate) fn new( - proxies: Arc<Proxies>, - connector: C, - tls: Arc<TlsConfig>, - ) -> Self { - ProxyConnector { - connector, - proxies, - tls, - user_agent: None, - } - } - - pub(crate) fn user_agent(&mut self, val: HeaderValue) { - self.user_agent = Some(val); - } - fn intercept(&self, dst: &Uri) -> Option<&Intercept> { self.proxies.intercept(dst) } @@ -438,12 +427,13 @@ pub enum Proxied<T> { impl<C> Service<Uri> for ProxyConnector<C> where - C: Service<Uri>, - C::Response: hyper::rt::Read + hyper::rt::Write + Unpin + Send + 'static, + C: Service<Uri> + Clone, + C::Response: + hyper::rt::Read + hyper::rt::Write + Connection + Unpin + Send + 'static, C::Future: Send + 'static, C::Error: Into<BoxError> + 'static, { - type Response = Proxied<C::Response>; + type Response = Proxied<MaybeHttpsStream<C::Response>>; type Error = BoxError; type Future = BoxFuture<Result<Self::Response, Self::Error>>; @@ -451,7 +441,7 @@ where &mut self, cx: &mut Context<'_>, ) -> Poll<Result<(), Self::Error>> { - self.connector.poll_ready(cx).map_err(Into::into) + self.http.poll_ready(cx).map_err(Into::into) } fn call(&mut self, orig_dst: Uri) -> Self::Future { @@ -467,10 +457,12 @@ where dst: proxy_dst, auth, } => { - let connecting = self.connector.call(proxy_dst); + let mut connector = + HttpsConnector::from((self.http.clone(), self.tls_proxy.clone())); + let connecting = connector.call(proxy_dst); let tls = TlsConnector::from(self.tls.clone()); Box::pin(async move { - let mut io = connecting.await.map_err(Into::into)?; + let mut io = connecting.await.map_err(Into::<BoxError>::into)?; if is_https { tunnel(&mut io, &orig_dst, user_agent, auth).await?; @@ -529,9 +521,11 @@ where } }; } + + let mut connector = + HttpsConnector::from((self.http.clone(), self.tls.clone())); Box::pin( - self - .connector + connector .call(orig_dst) .map_ok(Proxied::PassThrough) .map_err(Into::into), @@ -721,7 +715,14 @@ where match self { Proxied::PassThrough(ref p) => p.connected(), Proxied::HttpForward(ref p) => p.connected().proxy(true), - Proxied::HttpTunneled(ref p) => p.inner().get_ref().0.connected(), + Proxied::HttpTunneled(ref p) => { + let tunneled_tls = p.inner().get_ref(); + if tunneled_tls.1.alpn_protocol() == Some(b"h2") { + tunneled_tls.0.connected().negotiated_h2() + } else { + tunneled_tls.0.connected() + } + } Proxied::Socks(ref p) => p.connected(), Proxied::SocksTls(ref p) => p.inner().get_ref().0.connected(), } |