blob: 850d1554d6ca9ca8f595a7978f880f1678e46451 [file]
// Copyright 2026 The BoringSSL Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Hyper support
use crate::TlsConnector;
use std::{
error::Error,
fmt::Debug,
future::Future,
pin::Pin,
sync::Arc,
task::{
Context,
Poll, //
}, //
};
use hyper::http;
use tower::Service;
/// A connector for `hyper` using `bssl-tls`.
#[derive(Clone)]
pub struct HyperBsslConnector<Inner> {
inner: Inner,
connector: Arc<TlsConnector>,
}
impl<Inner: Debug> std::fmt::Debug for HyperBsslConnector<Inner> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("HyperBsslConnector")
.field("inner", &self.inner)
.finish()
}
}
impl<Inner> HyperBsslConnector<Inner> {
/// Construct a new `HyperBsslConnector`.
pub fn new(inner: Inner, connector: TlsConnector) -> Self {
Self {
inner,
connector: Arc::new(connector),
}
}
}
impl<Inner> Service<http::Uri> for HyperBsslConnector<Inner>
where
Inner: Service<http::Uri>,
Inner::Response: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin + Send + Sync + 'static,
Inner::Future: Send + 'static,
Inner::Error: Into<Box<dyn Error + Send + Sync>>,
{
type Response = crate::TlsStream<bssl_tls::connection::Client, Inner::Response>;
type Error = Box<dyn Error + Send + Sync>;
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.inner.poll_ready(cx).map_err(Into::into)
}
fn call(&mut self, uri: http::Uri) -> Self::Future {
let domain = uri
.host()
.unwrap_or("")
.trim_start_matches('[')
.trim_end_matches(']')
.to_string();
if domain.is_empty() {
return Box::pin(std::future::ready(Err("empty domain".into())));
}
let fut = self.inner.call(uri);
let connector = self.connector.clone();
Box::pin(async move {
let stream = fut.await.map_err(Into::into)?;
Ok(connector.connect(&domain, stream).await?)
})
}
}