1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-11-20 12:02:22 +03:00

Gate some crates behind features in mas-http

This commit is contained in:
Quentin Gliech
2022-08-17 12:20:09 +02:00
parent 9fe541f7b6
commit 185ff622f9
9 changed files with 199 additions and 159 deletions

View File

@@ -24,30 +24,14 @@
#![warn(clippy::pedantic)]
#![allow(clippy::module_name_repetitions)]
use std::sync::Arc;
use bytes::Bytes;
use futures_util::{FutureExt, TryFutureExt};
use http::{Request, Response};
use http_body::{combinators::BoxBody, Body};
use hyper::{
client::{connect::dns::GaiResolver, HttpConnector},
Client,
};
use hyper_rustls::{ConfigBuilderExt, HttpsConnector, HttpsConnectorBuilder};
use thiserror::Error;
use tokio::{sync::OnceCell, task::JoinError};
use tower::{util::BoxCloneService, ServiceBuilder, ServiceExt};
use self::layers::{
client::ClientResponse,
otel::{TraceDns, TraceLayer},
};
#[cfg(feature = "client")]
mod client;
mod ext;
mod future_service;
mod layers;
#[cfg(feature = "client")]
pub use self::client::client;
pub use self::{
ext::{
set_propagator, CorsLayerExt, ServiceBuilderExt as HttpServiceBuilderExt,
@@ -67,97 +51,3 @@ pub use self::{
};
pub(crate) type BoxError = Box<dyn std::error::Error + Send + Sync>;
/// A wrapper over a boxed error that implements ``std::error::Error``.
/// This is helps converting to ``anyhow::Error`` with the `?` operator
#[derive(Error, Debug)]
pub enum ClientError {
#[error("failed to initialize HTTPS client")]
Init(#[from] ClientInitError),
#[error(transparent)]
Call(#[from] BoxError),
}
#[derive(Error, Debug, Clone)]
pub enum ClientInitError {
#[error("failed to load system certificates")]
CertificateLoad {
#[from]
inner: Arc<JoinError>, // That error is in an Arc to have the error implement Clone
},
}
static TLS_CONFIG: OnceCell<rustls::ClientConfig> = OnceCell::const_new();
async fn make_base_client<B, E>(
) -> Result<hyper::Client<HttpsConnector<HttpConnector<TraceDns<GaiResolver>>>, B>, ClientInitError>
where
B: http_body::Body<Data = Bytes, Error = E> + Send + 'static,
E: Into<BoxError>,
{
// Trace DNS requests
let resolver = ServiceBuilder::new()
.layer(TraceLayer::dns())
.service(GaiResolver::new());
let mut http = HttpConnector::new_with_resolver(resolver);
http.enforce_http(false);
let tls_config = TLS_CONFIG
.get_or_try_init(|| async move {
// Load the TLS config once in a blocking task because loading the system
// certificates can take a long time (~200ms) on macOS
let span = tracing::info_span!("load_certificates");
tokio::task::spawn_blocking(|| {
let _span = span.entered();
rustls::ClientConfig::builder()
.with_safe_defaults()
.with_native_roots()
.with_no_client_auth()
})
.await
})
.await
.map_err(|e| ClientInitError::from(Arc::new(e)))?;
let https = HttpsConnectorBuilder::new()
.with_tls_config(tls_config.clone())
.https_or_http()
.enable_http1()
.enable_http2()
.wrap_connector(http);
// TODO: we should get the remote address here
let client = Client::builder().build(https);
Ok::<_, ClientInitError>(client)
}
#[must_use]
pub fn client<B, E>(
operation: &'static str,
) -> BoxCloneService<Request<B>, Response<BoxBody<bytes::Bytes, ClientError>>, ClientError>
where
B: http_body::Body<Data = Bytes, Error = E> + Default + Send + 'static,
E: Into<BoxError> + 'static,
{
let fut = make_base_client()
// Map the error to a ClientError
.map_ok(|s| s.map_err(|e| ClientError::from(BoxError::from(e))))
// Wrap it in an Shared (Arc) to be able to Clone it
.shared();
let client: FutureService<_, _> = FutureService::new(fut);
let client = ServiceBuilder::new()
// Convert the errors to ClientError to help dealing with them
.map_err(ClientError::from)
.map_response(|r: ClientResponse<hyper::Body>| {
r.map(|body| body.map_err(ClientError::from).boxed())
})
.layer(ClientLayer::new(operation))
.service(client);
client.boxed_clone()
}