summaryrefslogtreecommitdiff
path: root/vendor/hyper-rustls/src
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/hyper-rustls/src')
-rw-r--r--vendor/hyper-rustls/src/config.rs136
-rw-r--r--vendor/hyper-rustls/src/connector.rs296
-rw-r--r--vendor/hyper-rustls/src/connector/builder.rs500
-rw-r--r--vendor/hyper-rustls/src/lib.rs76
-rw-r--r--vendor/hyper-rustls/src/stream.rs121
5 files changed, 1129 insertions, 0 deletions
diff --git a/vendor/hyper-rustls/src/config.rs b/vendor/hyper-rustls/src/config.rs
new file mode 100644
index 00000000..38382617
--- /dev/null
+++ b/vendor/hyper-rustls/src/config.rs
@@ -0,0 +1,136 @@
+#[cfg(feature = "rustls-native-certs")]
+use std::io;
+
+#[cfg(any(
+ feature = "rustls-platform-verifier",
+ feature = "rustls-native-certs",
+ feature = "webpki-roots"
+))]
+use rustls::client::WantsClientCert;
+use rustls::{ClientConfig, ConfigBuilder, WantsVerifier};
+#[cfg(feature = "rustls-native-certs")]
+use rustls_native_certs::CertificateResult;
+#[cfg(feature = "rustls-platform-verifier")]
+use rustls_platform_verifier::BuilderVerifierExt;
+
+/// Methods for configuring roots
+///
+/// This adds methods (gated by crate features) for easily configuring
+/// TLS server roots a rustls ClientConfig will trust.
+pub trait ConfigBuilderExt: sealed::Sealed {
+ /// Use the platform's native verifier to verify server certificates.
+ ///
+ /// See the documentation for [rustls-platform-verifier] for more details.
+ ///
+ /// # Panics
+ ///
+ /// Since 0.27.7, this method will panic if the platform verifier cannot be initialized.
+ /// Use `try_with_platform_verifier()` instead to handle errors gracefully.
+ ///
+ /// [rustls-platform-verifier]: https://docs.rs/rustls-platform-verifier
+ #[deprecated(since = "0.27.7", note = "use `try_with_platform_verifier` instead")]
+ #[cfg(feature = "rustls-platform-verifier")]
+ fn with_platform_verifier(self) -> ConfigBuilder<ClientConfig, WantsClientCert>;
+
+ /// Use the platform's native verifier to verify server certificates.
+ ///
+ /// See the documentation for [rustls-platform-verifier] for more details.
+ ///
+ /// [rustls-platform-verifier]: https://docs.rs/rustls-platform-verifier
+ #[cfg(feature = "rustls-platform-verifier")]
+ fn try_with_platform_verifier(
+ self,
+ ) -> Result<ConfigBuilder<ClientConfig, WantsClientCert>, rustls::Error>;
+
+ /// This configures the platform's trusted certs, as implemented by
+ /// rustls-native-certs
+ ///
+ /// This will return an error if no valid certs were found. In that case,
+ /// it's recommended to use `with_webpki_roots`.
+ #[cfg(feature = "rustls-native-certs")]
+ fn with_native_roots(self) -> Result<ConfigBuilder<ClientConfig, WantsClientCert>, io::Error>;
+
+ /// This configures the webpki roots, which are Mozilla's set of
+ /// trusted roots as packaged by webpki-roots.
+ #[cfg(feature = "webpki-roots")]
+ fn with_webpki_roots(self) -> ConfigBuilder<ClientConfig, WantsClientCert>;
+}
+
+impl ConfigBuilderExt for ConfigBuilder<ClientConfig, WantsVerifier> {
+ #[cfg(feature = "rustls-platform-verifier")]
+ fn with_platform_verifier(self) -> ConfigBuilder<ClientConfig, WantsClientCert> {
+ self.try_with_platform_verifier()
+ .expect("failure to initialize platform verifier")
+ }
+
+ #[cfg(feature = "rustls-platform-verifier")]
+ fn try_with_platform_verifier(
+ self,
+ ) -> Result<ConfigBuilder<ClientConfig, WantsClientCert>, rustls::Error> {
+ BuilderVerifierExt::with_platform_verifier(self)
+ }
+
+ #[cfg(feature = "rustls-native-certs")]
+ #[cfg_attr(not(feature = "logging"), allow(unused_variables))]
+ fn with_native_roots(self) -> Result<ConfigBuilder<ClientConfig, WantsClientCert>, io::Error> {
+ let mut roots = rustls::RootCertStore::empty();
+ let mut valid_count = 0;
+ let mut invalid_count = 0;
+
+ let CertificateResult { certs, errors, .. } = rustls_native_certs::load_native_certs();
+ if !errors.is_empty() {
+ crate::log::warn!("native root CA certificate loading errors: {errors:?}");
+ }
+
+ if certs.is_empty() {
+ return Err(io::Error::new(
+ io::ErrorKind::NotFound,
+ format!("no native root CA certificates found (errors: {errors:?})"),
+ ));
+ }
+
+ for cert in certs {
+ match roots.add(cert) {
+ Ok(_) => valid_count += 1,
+ Err(err) => {
+ crate::log::debug!("certificate parsing failed: {:?}", err);
+ invalid_count += 1
+ }
+ }
+ }
+
+ crate::log::debug!(
+ "with_native_roots processed {} valid and {} invalid certs",
+ valid_count,
+ invalid_count
+ );
+ if roots.is_empty() {
+ crate::log::debug!("no valid native root CA certificates found");
+ Err(io::Error::new(
+ io::ErrorKind::NotFound,
+ format!("no valid native root CA certificates found ({invalid_count} invalid)"),
+ ))?
+ }
+
+ Ok(self.with_root_certificates(roots))
+ }
+
+ #[cfg(feature = "webpki-roots")]
+ fn with_webpki_roots(self) -> ConfigBuilder<ClientConfig, WantsClientCert> {
+ let mut roots = rustls::RootCertStore::empty();
+ roots.extend(
+ webpki_roots::TLS_SERVER_ROOTS
+ .iter()
+ .cloned(),
+ );
+ self.with_root_certificates(roots)
+ }
+}
+
+mod sealed {
+ use super::*;
+
+ pub trait Sealed {}
+
+ impl Sealed for ConfigBuilder<ClientConfig, WantsVerifier> {}
+}
diff --git a/vendor/hyper-rustls/src/connector.rs b/vendor/hyper-rustls/src/connector.rs
new file mode 100644
index 00000000..f8abe457
--- /dev/null
+++ b/vendor/hyper-rustls/src/connector.rs
@@ -0,0 +1,296 @@
+use std::future::Future;
+use std::pin::Pin;
+use std::sync::Arc;
+use std::task::{Context, Poll};
+use std::{fmt, io};
+
+use http::Uri;
+use hyper::rt;
+use hyper_util::client::legacy::connect::Connection;
+use hyper_util::rt::TokioIo;
+use pki_types::ServerName;
+use tokio_rustls::TlsConnector;
+use tower_service::Service;
+
+use crate::stream::MaybeHttpsStream;
+
+pub(crate) mod builder;
+
+type BoxError = Box<dyn std::error::Error + Send + Sync>;
+
+/// A Connector for the `https` scheme.
+#[derive(Clone)]
+pub struct HttpsConnector<T> {
+ force_https: bool,
+ http: T,
+ tls_config: Arc<rustls::ClientConfig>,
+ server_name_resolver: Arc<dyn ResolveServerName + Sync + Send>,
+}
+
+impl<T> HttpsConnector<T> {
+ /// Creates a [`crate::HttpsConnectorBuilder`] to configure a `HttpsConnector`.
+ ///
+ /// This is the same as [`crate::HttpsConnectorBuilder::new()`].
+ pub fn builder() -> builder::ConnectorBuilder<builder::WantsTlsConfig> {
+ builder::ConnectorBuilder::new()
+ }
+
+ /// Force the use of HTTPS when connecting.
+ ///
+ /// If a URL is not `https` when connecting, an error is returned.
+ pub fn enforce_https(&mut self) {
+ self.force_https = true;
+ }
+}
+
+impl<T> Service<Uri> for HttpsConnector<T>
+where
+ T: Service<Uri>,
+ T::Response: Connection + rt::Read + rt::Write + Send + Unpin + 'static,
+ T::Future: Send + 'static,
+ T::Error: Into<BoxError>,
+{
+ type Response = MaybeHttpsStream<T::Response>;
+ type Error = BoxError;
+
+ #[allow(clippy::type_complexity)]
+ type Future =
+ Pin<Box<dyn Future<Output = Result<MaybeHttpsStream<T::Response>, BoxError>> + Send>>;
+
+ fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
+ match self.http.poll_ready(cx) {
+ Poll::Ready(Ok(())) => Poll::Ready(Ok(())),
+ Poll::Ready(Err(e)) => Poll::Ready(Err(e.into())),
+ Poll::Pending => Poll::Pending,
+ }
+ }
+
+ fn call(&mut self, dst: Uri) -> Self::Future {
+ // dst.scheme() would need to derive Eq to be matchable;
+ // use an if cascade instead
+ match dst.scheme() {
+ Some(scheme) if scheme == &http::uri::Scheme::HTTP && !self.force_https => {
+ let future = self.http.call(dst);
+ return Box::pin(async move {
+ Ok(MaybeHttpsStream::Http(future.await.map_err(Into::into)?))
+ });
+ }
+ Some(scheme) if scheme != &http::uri::Scheme::HTTPS => {
+ let message = format!("unsupported scheme {scheme}");
+ return Box::pin(async move {
+ Err(io::Error::new(io::ErrorKind::Other, message).into())
+ });
+ }
+ Some(_) => {}
+ None => {
+ return Box::pin(async move {
+ Err(io::Error::new(io::ErrorKind::Other, "missing scheme").into())
+ })
+ }
+ };
+
+ let cfg = self.tls_config.clone();
+ let hostname = match self.server_name_resolver.resolve(&dst) {
+ Ok(hostname) => hostname,
+ Err(e) => {
+ return Box::pin(async move { Err(e) });
+ }
+ };
+
+ let connecting_future = self.http.call(dst);
+ Box::pin(async move {
+ let tcp = connecting_future
+ .await
+ .map_err(Into::into)?;
+ Ok(MaybeHttpsStream::Https(TokioIo::new(
+ TlsConnector::from(cfg)
+ .connect(hostname, TokioIo::new(tcp))
+ .await
+ .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?,
+ )))
+ })
+ }
+}
+
+impl<H, C> From<(H, C)> for HttpsConnector<H>
+where
+ C: Into<Arc<rustls::ClientConfig>>,
+{
+ fn from((http, cfg): (H, C)) -> Self {
+ Self {
+ force_https: false,
+ http,
+ tls_config: cfg.into(),
+ server_name_resolver: Arc::new(DefaultServerNameResolver::default()),
+ }
+ }
+}
+
+impl<T> fmt::Debug for HttpsConnector<T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("HttpsConnector")
+ .field("force_https", &self.force_https)
+ .finish()
+ }
+}
+
+/// The default server name resolver, which uses the hostname in the URI.
+#[derive(Default)]
+pub struct DefaultServerNameResolver(());
+
+impl ResolveServerName for DefaultServerNameResolver {
+ fn resolve(
+ &self,
+ uri: &Uri,
+ ) -> Result<ServerName<'static>, Box<dyn std::error::Error + Sync + Send>> {
+ let mut hostname = uri.host().unwrap_or_default();
+
+ // Remove square brackets around IPv6 address.
+ if let Some(trimmed) = hostname
+ .strip_prefix('[')
+ .and_then(|h| h.strip_suffix(']'))
+ {
+ hostname = trimmed;
+ }
+
+ ServerName::try_from(hostname.to_string()).map_err(|e| Box::new(e) as _)
+ }
+}
+
+/// A server name resolver which always returns the same fixed name.
+pub struct FixedServerNameResolver {
+ name: ServerName<'static>,
+}
+
+impl FixedServerNameResolver {
+ /// Creates a new resolver returning the specified name.
+ pub fn new(name: ServerName<'static>) -> Self {
+ Self { name }
+ }
+}
+
+impl ResolveServerName for FixedServerNameResolver {
+ fn resolve(
+ &self,
+ _: &Uri,
+ ) -> Result<ServerName<'static>, Box<dyn std::error::Error + Sync + Send>> {
+ Ok(self.name.clone())
+ }
+}
+
+impl<F, E> ResolveServerName for F
+where
+ F: Fn(&Uri) -> Result<ServerName<'static>, E>,
+ E: Into<Box<dyn std::error::Error + Sync + Send>>,
+{
+ fn resolve(
+ &self,
+ uri: &Uri,
+ ) -> Result<ServerName<'static>, Box<dyn std::error::Error + Sync + Send>> {
+ self(uri).map_err(Into::into)
+ }
+}
+
+/// A trait implemented by types that can resolve a [`ServerName`] for a request.
+pub trait ResolveServerName {
+ /// Maps a [`Uri`] into a [`ServerName`].
+ fn resolve(
+ &self,
+ uri: &Uri,
+ ) -> Result<ServerName<'static>, Box<dyn std::error::Error + Sync + Send>>;
+}
+
+#[cfg(all(
+ test,
+ any(feature = "ring", feature = "aws-lc-rs"),
+ any(
+ feature = "rustls-native-certs",
+ feature = "webpki-roots",
+ feature = "rustls-platform-verifier",
+ )
+))]
+mod tests {
+ use std::future::poll_fn;
+
+ use http::Uri;
+ use hyper_util::rt::TokioIo;
+ use tokio::net::TcpStream;
+ use tower_service::Service;
+
+ use super::*;
+ use crate::{ConfigBuilderExt, HttpsConnectorBuilder, MaybeHttpsStream};
+
+ #[tokio::test]
+ async fn connects_https() {
+ connect(Allow::Any, Scheme::Https)
+ .await
+ .unwrap();
+ }
+
+ #[tokio::test]
+ async fn connects_http() {
+ connect(Allow::Any, Scheme::Http)
+ .await
+ .unwrap();
+ }
+
+ #[tokio::test]
+ async fn connects_https_only() {
+ connect(Allow::Https, Scheme::Https)
+ .await
+ .unwrap();
+ }
+
+ #[tokio::test]
+ async fn enforces_https_only() {
+ let message = connect(Allow::Https, Scheme::Http)
+ .await
+ .unwrap_err()
+ .to_string();
+
+ assert_eq!(message, "unsupported scheme http");
+ }
+
+ async fn connect(
+ allow: Allow,
+ scheme: Scheme,
+ ) -> Result<MaybeHttpsStream<TokioIo<TcpStream>>, BoxError> {
+ let config_builder = rustls::ClientConfig::builder();
+ cfg_if::cfg_if! {
+ if #[cfg(feature = "rustls-platform-verifier")] {
+ let config_builder = config_builder.try_with_platform_verifier()?;
+ } else if #[cfg(feature = "rustls-native-certs")] {
+ let config_builder = config_builder.with_native_roots().unwrap();
+ } else if #[cfg(feature = "webpki-roots")] {
+ let config_builder = config_builder.with_webpki_roots();
+ }
+ }
+ let config = config_builder.with_no_client_auth();
+
+ let builder = HttpsConnectorBuilder::new().with_tls_config(config);
+ let mut service = match allow {
+ Allow::Https => builder.https_only(),
+ Allow::Any => builder.https_or_http(),
+ }
+ .enable_http1()
+ .build();
+
+ poll_fn(|cx| service.poll_ready(cx)).await?;
+ service
+ .call(Uri::from_static(match scheme {
+ Scheme::Https => "https://google.com",
+ Scheme::Http => "http://google.com",
+ }))
+ .await
+ }
+
+ enum Allow {
+ Https,
+ Any,
+ }
+
+ enum Scheme {
+ Https,
+ Http,
+ }
+}
diff --git a/vendor/hyper-rustls/src/connector/builder.rs b/vendor/hyper-rustls/src/connector/builder.rs
new file mode 100644
index 00000000..417d1303
--- /dev/null
+++ b/vendor/hyper-rustls/src/connector/builder.rs
@@ -0,0 +1,500 @@
+use std::sync::Arc;
+
+use hyper_util::client::legacy::connect::HttpConnector;
+#[cfg(any(
+ feature = "rustls-native-certs",
+ feature = "rustls-platform-verifier",
+ feature = "webpki-roots"
+))]
+use rustls::crypto::CryptoProvider;
+use rustls::ClientConfig;
+
+use super::{DefaultServerNameResolver, HttpsConnector, ResolveServerName};
+#[cfg(any(
+ feature = "rustls-native-certs",
+ feature = "webpki-roots",
+ feature = "rustls-platform-verifier"
+))]
+use crate::config::ConfigBuilderExt;
+use pki_types::ServerName;
+
+/// A builder for an [`HttpsConnector`]
+///
+/// This makes configuration flexible and explicit and ensures connector
+/// features match crate features
+///
+/// # Examples
+///
+/// ```
+/// use hyper_rustls::HttpsConnectorBuilder;
+///
+/// # #[cfg(all(feature = "webpki-roots", feature = "http1", feature="aws-lc-rs"))]
+/// # {
+/// # let _ = rustls::crypto::aws_lc_rs::default_provider().install_default();
+/// let https = HttpsConnectorBuilder::new()
+/// .with_webpki_roots()
+/// .https_only()
+/// .enable_http1()
+/// .build();
+/// # }
+/// ```
+pub struct ConnectorBuilder<State>(State);
+
+/// State of a builder that needs a TLS client config next
+pub struct WantsTlsConfig(());
+
+impl ConnectorBuilder<WantsTlsConfig> {
+ /// Creates a new [`ConnectorBuilder`]
+ pub fn new() -> Self {
+ Self(WantsTlsConfig(()))
+ }
+
+ /// Passes a rustls [`ClientConfig`] to configure the TLS connection
+ ///
+ /// The [`alpn_protocols`](ClientConfig::alpn_protocols) field is
+ /// required to be empty (or the function will panic) and will be
+ /// rewritten to match the enabled schemes (see
+ /// [`enable_http1`](ConnectorBuilder::enable_http1),
+ /// [`enable_http2`](ConnectorBuilder::enable_http2)) before the
+ /// connector is built.
+ pub fn with_tls_config(self, config: ClientConfig) -> ConnectorBuilder<WantsSchemes> {
+ assert!(
+ config.alpn_protocols.is_empty(),
+ "ALPN protocols should not be pre-defined"
+ );
+ ConnectorBuilder(WantsSchemes { tls_config: config })
+ }
+
+ /// Shorthand for using rustls' default crypto provider and other defaults, and
+ /// the platform verifier.
+ ///
+ /// See [`ConfigBuilderExt::with_platform_verifier()`].
+ #[cfg(all(
+ any(feature = "ring", feature = "aws-lc-rs"),
+ feature = "rustls-platform-verifier"
+ ))]
+ pub fn with_platform_verifier(self) -> ConnectorBuilder<WantsSchemes> {
+ self.try_with_platform_verifier()
+ .expect("failure to initialize platform verifier")
+ }
+
+ /// Shorthand for using rustls' default crypto provider and other defaults, and
+ /// the platform verifier.
+ ///
+ /// See [`ConfigBuilderExt::with_platform_verifier()`].
+ #[cfg(all(
+ any(feature = "ring", feature = "aws-lc-rs"),
+ feature = "rustls-platform-verifier"
+ ))]
+ pub fn try_with_platform_verifier(
+ self,
+ ) -> Result<ConnectorBuilder<WantsSchemes>, rustls::Error> {
+ Ok(self.with_tls_config(
+ ClientConfig::builder()
+ .try_with_platform_verifier()?
+ .with_no_client_auth(),
+ ))
+ }
+
+ /// Shorthand for using a custom [`CryptoProvider`] and the platform verifier.
+ ///
+ /// See [`ConfigBuilderExt::with_platform_verifier()`].
+ #[cfg(feature = "rustls-platform-verifier")]
+ pub fn with_provider_and_platform_verifier(
+ self,
+ provider: impl Into<Arc<CryptoProvider>>,
+ ) -> std::io::Result<ConnectorBuilder<WantsSchemes>> {
+ Ok(self.with_tls_config(
+ ClientConfig::builder_with_provider(provider.into())
+ .with_safe_default_protocol_versions()
+ .and_then(|builder| builder.try_with_platform_verifier())
+ .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?
+ .with_no_client_auth(),
+ ))
+ }
+
+ /// Shorthand for using rustls' default crypto provider and safe defaults, with
+ /// native roots.
+ ///
+ /// See [`ConfigBuilderExt::with_native_roots`]
+ #[cfg(all(
+ any(feature = "ring", feature = "aws-lc-rs"),
+ feature = "rustls-native-certs"
+ ))]
+ pub fn with_native_roots(self) -> std::io::Result<ConnectorBuilder<WantsSchemes>> {
+ Ok(self.with_tls_config(
+ ClientConfig::builder()
+ .with_native_roots()?
+ .with_no_client_auth(),
+ ))
+ }
+
+ /// Shorthand for using a custom [`CryptoProvider`] and native roots
+ ///
+ /// See [`ConfigBuilderExt::with_native_roots`]
+ #[cfg(feature = "rustls-native-certs")]
+ pub fn with_provider_and_native_roots(
+ self,
+ provider: impl Into<Arc<CryptoProvider>>,
+ ) -> std::io::Result<ConnectorBuilder<WantsSchemes>> {
+ Ok(self.with_tls_config(
+ ClientConfig::builder_with_provider(provider.into())
+ .with_safe_default_protocol_versions()
+ .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?
+ .with_native_roots()?
+ .with_no_client_auth(),
+ ))
+ }
+
+ /// Shorthand for using rustls' default crypto provider and its
+ /// safe defaults.
+ ///
+ /// See [`ConfigBuilderExt::with_webpki_roots`]
+ #[cfg(all(any(feature = "ring", feature = "aws-lc-rs"), feature = "webpki-roots"))]
+ pub fn with_webpki_roots(self) -> ConnectorBuilder<WantsSchemes> {
+ self.with_tls_config(
+ ClientConfig::builder()
+ .with_webpki_roots()
+ .with_no_client_auth(),
+ )
+ }
+
+ /// Shorthand for using a custom [`CryptoProvider`], Rustls' safe default
+ /// protocol versions and Mozilla roots
+ ///
+ /// See [`ConfigBuilderExt::with_webpki_roots`]
+ #[cfg(feature = "webpki-roots")]
+ pub fn with_provider_and_webpki_roots(
+ self,
+ provider: impl Into<Arc<CryptoProvider>>,
+ ) -> Result<ConnectorBuilder<WantsSchemes>, rustls::Error> {
+ Ok(self.with_tls_config(
+ ClientConfig::builder_with_provider(provider.into())
+ .with_safe_default_protocol_versions()?
+ .with_webpki_roots()
+ .with_no_client_auth(),
+ ))
+ }
+}
+
+impl Default for ConnectorBuilder<WantsTlsConfig> {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+/// State of a builder that needs schemes (https:// and http://) to be
+/// configured next
+pub struct WantsSchemes {
+ tls_config: ClientConfig,
+}
+
+impl ConnectorBuilder<WantsSchemes> {
+ /// Enforce the use of HTTPS when connecting
+ ///
+ /// Only URLs using the HTTPS scheme will be connectable.
+ pub fn https_only(self) -> ConnectorBuilder<WantsProtocols1> {
+ ConnectorBuilder(WantsProtocols1 {
+ tls_config: self.0.tls_config,
+ https_only: true,
+ server_name_resolver: None,
+ })
+ }
+
+ /// Allow both HTTPS and HTTP when connecting
+ ///
+ /// HTTPS URLs will be handled through rustls,
+ /// HTTP URLs will be handled by the lower-level connector.
+ pub fn https_or_http(self) -> ConnectorBuilder<WantsProtocols1> {
+ ConnectorBuilder(WantsProtocols1 {
+ tls_config: self.0.tls_config,
+ https_only: false,
+ server_name_resolver: None,
+ })
+ }
+}
+
+/// State of a builder that needs to have some protocols (HTTP1 or later)
+/// enabled next
+///
+/// No protocol has been enabled at this point.
+pub struct WantsProtocols1 {
+ tls_config: ClientConfig,
+ https_only: bool,
+ server_name_resolver: Option<Arc<dyn ResolveServerName + Sync + Send>>,
+}
+
+impl WantsProtocols1 {
+ fn wrap_connector<H>(self, conn: H) -> HttpsConnector<H> {
+ HttpsConnector {
+ force_https: self.https_only,
+ http: conn,
+ tls_config: std::sync::Arc::new(self.tls_config),
+ server_name_resolver: self
+ .server_name_resolver
+ .unwrap_or_else(|| Arc::new(DefaultServerNameResolver::default())),
+ }
+ }
+
+ fn build(self) -> HttpsConnector<HttpConnector> {
+ let mut http = HttpConnector::new();
+ // HttpConnector won't enforce scheme, but HttpsConnector will
+ http.enforce_http(false);
+ self.wrap_connector(http)
+ }
+}
+
+impl ConnectorBuilder<WantsProtocols1> {
+ /// Enable HTTP1
+ ///
+ /// This needs to be called explicitly, no protocol is enabled by default
+ #[cfg(feature = "http1")]
+ pub fn enable_http1(self) -> ConnectorBuilder<WantsProtocols2> {
+ ConnectorBuilder(WantsProtocols2 { inner: self.0 })
+ }
+
+ /// Enable HTTP2
+ ///
+ /// This needs to be called explicitly, no protocol is enabled by default
+ #[cfg(feature = "http2")]
+ pub fn enable_http2(mut self) -> ConnectorBuilder<WantsProtocols3> {
+ self.0.tls_config.alpn_protocols = vec![b"h2".to_vec()];
+ ConnectorBuilder(WantsProtocols3 {
+ inner: self.0,
+ enable_http1: false,
+ })
+ }
+
+ /// Enable all HTTP versions built into this library (enabled with Cargo features)
+ ///
+ /// For now, this could enable both HTTP 1 and 2, depending on active features.
+ /// In the future, other supported versions will be enabled as well.
+ #[cfg(feature = "http2")]
+ pub fn enable_all_versions(mut self) -> ConnectorBuilder<WantsProtocols3> {
+ #[cfg(feature = "http1")]
+ let alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
+ #[cfg(not(feature = "http1"))]
+ let alpn_protocols = vec![b"h2".to_vec()];
+
+ self.0.tls_config.alpn_protocols = alpn_protocols;
+ ConnectorBuilder(WantsProtocols3 {
+ inner: self.0,
+ enable_http1: cfg!(feature = "http1"),
+ })
+ }
+
+ /// Override server name for the TLS stack
+ ///
+ /// By default, for each connection hyper-rustls will extract host portion
+ /// of the destination URL and verify that server certificate contains
+ /// this value.
+ ///
+ /// If this method is called, hyper-rustls will instead use this resolver
+ /// to compute the value used to verify the server certificate.
+ pub fn with_server_name_resolver(
+ mut self,
+ resolver: impl ResolveServerName + 'static + Sync + Send,
+ ) -> Self {
+ self.0.server_name_resolver = Some(Arc::new(resolver));
+ self
+ }
+
+ /// Override server name for the TLS stack
+ ///
+ /// By default, for each connection hyper-rustls will extract host portion
+ /// of the destination URL and verify that server certificate contains
+ /// this value.
+ ///
+ /// If this method is called, hyper-rustls will instead verify that server
+ /// certificate contains `override_server_name`. Domain name included in
+ /// the URL will not affect certificate validation.
+ #[deprecated(
+ since = "0.27.1",
+ note = "use Self::with_server_name_resolver with FixedServerNameResolver instead"
+ )]
+ pub fn with_server_name(self, mut override_server_name: String) -> Self {
+ // remove square brackets around IPv6 address.
+ if let Some(trimmed) = override_server_name
+ .strip_prefix('[')
+ .and_then(|s| s.strip_suffix(']'))
+ {
+ override_server_name = trimmed.to_string();
+ }
+
+ self.with_server_name_resolver(move |_: &_| {
+ ServerName::try_from(override_server_name.clone())
+ })
+ }
+}
+
+/// State of a builder with HTTP1 enabled, that may have some other
+/// protocols (HTTP2 or later) enabled next
+///
+/// At this point a connector can be built, see
+/// [`build`](ConnectorBuilder<WantsProtocols2>::build) and
+/// [`wrap_connector`](ConnectorBuilder<WantsProtocols2>::wrap_connector).
+pub struct WantsProtocols2 {
+ inner: WantsProtocols1,
+}
+
+impl ConnectorBuilder<WantsProtocols2> {
+ /// Enable HTTP2
+ ///
+ /// This needs to be called explicitly, no protocol is enabled by default
+ #[cfg(feature = "http2")]
+ pub fn enable_http2(mut self) -> ConnectorBuilder<WantsProtocols3> {
+ self.0.inner.tls_config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
+ ConnectorBuilder(WantsProtocols3 {
+ inner: self.0.inner,
+ enable_http1: true,
+ })
+ }
+
+ /// This builds an [`HttpsConnector`] built on hyper's default [`HttpConnector`]
+ pub fn build(self) -> HttpsConnector<HttpConnector> {
+ self.0.inner.build()
+ }
+
+ /// This wraps an arbitrary low-level connector into an [`HttpsConnector`]
+ pub fn wrap_connector<H>(self, conn: H) -> HttpsConnector<H> {
+ // HTTP1-only, alpn_protocols stays empty
+ // HttpConnector doesn't have a way to say http1-only;
+ // its connection pool may still support HTTP2
+ // though it won't be used
+ self.0.inner.wrap_connector(conn)
+ }
+}
+
+/// State of a builder with HTTP2 (and possibly HTTP1) enabled
+///
+/// At this point a connector can be built, see
+/// [`build`](ConnectorBuilder<WantsProtocols3>::build) and
+/// [`wrap_connector`](ConnectorBuilder<WantsProtocols3>::wrap_connector).
+#[cfg(feature = "http2")]
+pub struct WantsProtocols3 {
+ inner: WantsProtocols1,
+ // ALPN is built piecemeal without the need to read back this field
+ #[allow(dead_code)]
+ enable_http1: bool,
+}
+
+#[cfg(feature = "http2")]
+impl ConnectorBuilder<WantsProtocols3> {
+ /// This builds an [`HttpsConnector`] built on hyper's default [`HttpConnector`]
+ pub fn build(self) -> HttpsConnector<HttpConnector> {
+ self.0.inner.build()
+ }
+
+ /// This wraps an arbitrary low-level connector into an [`HttpsConnector`]
+ pub fn wrap_connector<H>(self, conn: H) -> HttpsConnector<H> {
+ // If HTTP1 is disabled, we can set http2_only
+ // on the Client (a higher-level object that uses the connector)
+ // client.http2_only(!self.0.enable_http1);
+ self.0.inner.wrap_connector(conn)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ // Typical usage
+ #[test]
+ #[cfg(all(feature = "webpki-roots", feature = "http1"))]
+ fn test_builder() {
+ ensure_global_state();
+ let _connector = super::ConnectorBuilder::new()
+ .with_webpki_roots()
+ .https_only()
+ .enable_http1()
+ .build();
+ }
+
+ #[test]
+ #[cfg(feature = "http1")]
+ #[should_panic(expected = "ALPN protocols should not be pre-defined")]
+ fn test_reject_predefined_alpn() {
+ ensure_global_state();
+ let roots = rustls::RootCertStore::empty();
+ let mut config_with_alpn = rustls::ClientConfig::builder()
+ .with_root_certificates(roots)
+ .with_no_client_auth();
+ config_with_alpn.alpn_protocols = vec![b"fancyprotocol".to_vec()];
+ let _connector = super::ConnectorBuilder::new()
+ .with_tls_config(config_with_alpn)
+ .https_only()
+ .enable_http1()
+ .build();
+ }
+
+ #[test]
+ #[cfg(all(feature = "http1", feature = "http2"))]
+ fn test_alpn() {
+ ensure_global_state();
+ let roots = rustls::RootCertStore::empty();
+ let tls_config = rustls::ClientConfig::builder()
+ .with_root_certificates(roots)
+ .with_no_client_auth();
+ let connector = super::ConnectorBuilder::new()
+ .with_tls_config(tls_config.clone())
+ .https_only()
+ .enable_http1()
+ .build();
+ assert!(connector
+ .tls_config
+ .alpn_protocols
+ .is_empty());
+ let connector = super::ConnectorBuilder::new()
+ .with_tls_config(tls_config.clone())
+ .https_only()
+ .enable_http2()
+ .build();
+ assert_eq!(&connector.tls_config.alpn_protocols, &[b"h2".to_vec()]);
+ let connector = super::ConnectorBuilder::new()
+ .with_tls_config(tls_config.clone())
+ .https_only()
+ .enable_http1()
+ .enable_http2()
+ .build();
+ assert_eq!(
+ &connector.tls_config.alpn_protocols,
+ &[b"h2".to_vec(), b"http/1.1".to_vec()]
+ );
+ let connector = super::ConnectorBuilder::new()
+ .with_tls_config(tls_config)
+ .https_only()
+ .enable_all_versions()
+ .build();
+ assert_eq!(
+ &connector.tls_config.alpn_protocols,
+ &[b"h2".to_vec(), b"http/1.1".to_vec()]
+ );
+ }
+
+ #[test]
+ #[cfg(all(not(feature = "http1"), feature = "http2"))]
+ fn test_alpn_http2() {
+ let roots = rustls::RootCertStore::empty();
+ let tls_config = rustls::ClientConfig::builder()
+ .with_safe_defaults()
+ .with_root_certificates(roots)
+ .with_no_client_auth();
+ let connector = super::ConnectorBuilder::new()
+ .with_tls_config(tls_config.clone())
+ .https_only()
+ .enable_http2()
+ .build();
+ assert_eq!(&connector.tls_config.alpn_protocols, &[b"h2".to_vec()]);
+ let connector = super::ConnectorBuilder::new()
+ .with_tls_config(tls_config)
+ .https_only()
+ .enable_all_versions()
+ .build();
+ assert_eq!(&connector.tls_config.alpn_protocols, &[b"h2".to_vec()]);
+ }
+
+ fn ensure_global_state() {
+ #[cfg(feature = "ring")]
+ let _ = rustls::crypto::ring::default_provider().install_default();
+ #[cfg(feature = "aws-lc-rs")]
+ let _ = rustls::crypto::aws_lc_rs::default_provider().install_default();
+ }
+}
diff --git a/vendor/hyper-rustls/src/lib.rs b/vendor/hyper-rustls/src/lib.rs
new file mode 100644
index 00000000..89e355ae
--- /dev/null
+++ b/vendor/hyper-rustls/src/lib.rs
@@ -0,0 +1,76 @@
+//! # hyper-rustls
+//!
+//! A pure-Rust HTTPS connector for [hyper](https://hyper.rs), based on
+//! [Rustls](https://github.com/rustls/rustls).
+//!
+//! ## Example client
+//!
+//! ```no_run
+//! # #[cfg(all(feature = "rustls-native-certs", feature = "http1"))]
+//! # fn main() {
+//! use http::StatusCode;
+//! use http_body_util::Empty;
+//! use hyper::body::Bytes;
+//! use hyper_util::client::legacy::Client;
+//! use hyper_util::rt::TokioExecutor;
+//!
+//! let mut rt = tokio::runtime::Runtime::new().unwrap();
+//! let url = ("https://hyper.rs").parse().unwrap();
+//! let https = hyper_rustls::HttpsConnectorBuilder::new()
+//! .with_native_roots()
+//! .expect("no native root CA certificates found")
+//! .https_only()
+//! .enable_http1()
+//! .build();
+//!
+//! let client: Client<_, Empty<Bytes>> = Client::builder(TokioExecutor::new()).build(https);
+//!
+//! let res = rt.block_on(client.get(url)).unwrap();
+//! assert_eq!(res.status(), StatusCode::OK);
+//! # }
+//! # #[cfg(not(all(feature = "rustls-native-certs", feature = "http1")))]
+//! # fn main() {}
+//! ```
+
+#![warn(missing_docs, unreachable_pub, clippy::use_self)]
+#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
+
+mod config;
+mod connector;
+mod stream;
+
+#[cfg(feature = "logging")]
+mod log {
+ #[cfg(any(feature = "rustls-native-certs", feature = "webpki-roots"))]
+ pub(crate) use log::debug;
+ #[cfg(feature = "rustls-native-certs")]
+ pub(crate) use log::warn;
+}
+
+#[cfg(not(feature = "logging"))]
+mod log {
+ #[cfg(any(feature = "rustls-native-certs", feature = "webpki-roots"))]
+ macro_rules! debug ( ($($tt:tt)*) => {{}} );
+ #[cfg(any(feature = "rustls-native-certs", feature = "webpki-roots"))]
+ pub(crate) use debug;
+ #[cfg(feature = "rustls-native-certs")]
+ macro_rules! warn_ ( ($($tt:tt)*) => {{}} );
+ #[cfg(feature = "rustls-native-certs")]
+ pub(crate) use warn_ as warn;
+}
+
+pub use crate::config::ConfigBuilderExt;
+pub use crate::connector::builder::ConnectorBuilder as HttpsConnectorBuilder;
+pub use crate::connector::{
+ DefaultServerNameResolver, FixedServerNameResolver, HttpsConnector, ResolveServerName,
+};
+pub use crate::stream::MaybeHttpsStream;
+
+/// The various states of the [`HttpsConnectorBuilder`]
+pub mod builderstates {
+ #[cfg(feature = "http2")]
+ pub use crate::connector::builder::WantsProtocols3;
+ pub use crate::connector::builder::{
+ WantsProtocols1, WantsProtocols2, WantsSchemes, WantsTlsConfig,
+ };
+}
diff --git a/vendor/hyper-rustls/src/stream.rs b/vendor/hyper-rustls/src/stream.rs
new file mode 100644
index 00000000..f08e7b1b
--- /dev/null
+++ b/vendor/hyper-rustls/src/stream.rs
@@ -0,0 +1,121 @@
+// Copied from hyperium/hyper-tls#62e3376/src/stream.rs
+use std::fmt;
+use std::io;
+use std::pin::Pin;
+use std::task::{Context, Poll};
+
+use hyper::rt;
+use hyper_util::client::legacy::connect::{Connected, Connection};
+
+use hyper_util::rt::TokioIo;
+use tokio_rustls::client::TlsStream;
+
+/// A stream that might be protected with TLS.
+#[allow(clippy::large_enum_variant)]
+pub enum MaybeHttpsStream<T> {
+ /// A stream over plain text.
+ Http(T),
+ /// A stream protected with TLS.
+ Https(TokioIo<TlsStream<TokioIo<T>>>),
+}
+
+impl<T: rt::Read + rt::Write + Connection + Unpin> Connection for MaybeHttpsStream<T> {
+ fn connected(&self) -> Connected {
+ match self {
+ Self::Http(s) => s.connected(),
+ Self::Https(s) => {
+ let (tcp, tls) = s.inner().get_ref();
+ if tls.alpn_protocol() == Some(b"h2") {
+ tcp.inner().connected().negotiated_h2()
+ } else {
+ tcp.inner().connected()
+ }
+ }
+ }
+ }
+}
+
+impl<T: fmt::Debug> fmt::Debug for MaybeHttpsStream<T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ Self::Http(..) => f.pad("Http(..)"),
+ Self::Https(..) => f.pad("Https(..)"),
+ }
+ }
+}
+
+impl<T> From<T> for MaybeHttpsStream<T> {
+ fn from(inner: T) -> Self {
+ Self::Http(inner)
+ }
+}
+
+impl<T> From<TlsStream<TokioIo<T>>> for MaybeHttpsStream<T> {
+ fn from(inner: TlsStream<TokioIo<T>>) -> Self {
+ Self::Https(TokioIo::new(inner))
+ }
+}
+
+impl<T: rt::Read + rt::Write + Unpin> rt::Read for MaybeHttpsStream<T> {
+ #[inline]
+ fn poll_read(
+ self: Pin<&mut Self>,
+ cx: &mut Context,
+ buf: rt::ReadBufCursor<'_>,
+ ) -> Poll<Result<(), io::Error>> {
+ match Pin::get_mut(self) {
+ Self::Http(s) => Pin::new(s).poll_read(cx, buf),
+ Self::Https(s) => Pin::new(s).poll_read(cx, buf),
+ }
+ }
+}
+
+impl<T: rt::Write + rt::Read + Unpin> rt::Write for MaybeHttpsStream<T> {
+ #[inline]
+ fn poll_write(
+ self: Pin<&mut Self>,
+ cx: &mut Context<'_>,
+ buf: &[u8],
+ ) -> Poll<Result<usize, io::Error>> {
+ match Pin::get_mut(self) {
+ Self::Http(s) => Pin::new(s).poll_write(cx, buf),
+ Self::Https(s) => Pin::new(s).poll_write(cx, buf),
+ }
+ }
+
+ #[inline]
+ fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
+ match Pin::get_mut(self) {
+ Self::Http(s) => Pin::new(s).poll_flush(cx),
+ Self::Https(s) => Pin::new(s).poll_flush(cx),
+ }
+ }
+
+ #[inline]
+ fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
+ match Pin::get_mut(self) {
+ Self::Http(s) => Pin::new(s).poll_shutdown(cx),
+ Self::Https(s) => Pin::new(s).poll_shutdown(cx),
+ }
+ }
+
+ #[inline]
+ fn is_write_vectored(&self) -> bool {
+ match self {
+ Self::Http(s) => s.is_write_vectored(),
+ Self::Https(s) => s.is_write_vectored(),
+ }
+ }
+
+ #[inline]
+ fn poll_write_vectored(
+ self: Pin<&mut Self>,
+ cx: &mut Context<'_>,
+ bufs: &[io::IoSlice<'_>],
+ ) -> Poll<Result<usize, io::Error>> {
+ match Pin::get_mut(self) {
+ Self::Http(s) => Pin::new(s).poll_write_vectored(cx, bufs),
+ Self::Https(s) => Pin::new(s).poll_write_vectored(cx, bufs),
+ }
+ }
+}