1use std::fmt;
7
8use crate::{
9 Context, Service,
10 error::{BoxError, ErrorContext, OpaqueError},
11 http::{Request, Response, dep::http_body},
12 net::client::EstablishedClientConnection,
13 service::BoxService,
14 telemetry::tracing,
15};
16
17#[doc(inline)]
18pub use ::rama_http_backend::client::*;
19
20pub mod builder;
21#[doc(inline)]
22pub use builder::EasyHttpWebClientBuilder;
23
24#[cfg(feature = "socks5")]
25mod proxy_connector;
26#[cfg(feature = "socks5")]
27#[doc(inline)]
28pub use proxy_connector::{MaybeProxiedConnection, ProxyConnector, ProxyConnectorLayer};
29
30pub struct EasyHttpWebClient<BodyIn, ConnResponse> {
42 connector: BoxService<Request<BodyIn>, ConnResponse, BoxError>,
43}
44
45impl<BodyIn, ConnResponse> fmt::Debug for EasyHttpWebClient<BodyIn, ConnResponse> {
46 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47 f.debug_struct("EasyHttpWebClient").finish()
48 }
49}
50
51impl<BodyIn, ConnResponse> Clone for EasyHttpWebClient<BodyIn, ConnResponse> {
52 fn clone(&self) -> Self {
53 Self {
54 connector: self.connector.clone(),
55 }
56 }
57}
58
59impl EasyHttpWebClient<(), ()> {
60 #[must_use]
62 pub fn builder() -> EasyHttpWebClientBuilder {
63 EasyHttpWebClientBuilder::new()
64 }
65}
66
67impl<Body> Default
68 for EasyHttpWebClient<Body, EstablishedClientConnection<HttpClientService<Body>, Request<Body>>>
69where
70 Body: http_body::Body<Data: Send + 'static, Error: Into<BoxError>> + Unpin + Send + 'static,
71{
72 #[cfg(feature = "boring")]
73 fn default() -> Self {
74 let tls_config =
75 rama_tls_boring::client::TlsConnectorDataBuilder::new_http_auto().into_shared_builder();
76
77 EasyHttpWebClientBuilder::new()
78 .with_default_transport_connector()
79 .with_tls_proxy_support_using_boringssl()
80 .with_proxy_support()
81 .with_tls_support_using_boringssl(Some(tls_config))
82 .build()
83 }
84
85 #[cfg(all(feature = "rustls", not(feature = "boring")))]
86 fn default() -> Self {
87 let tls_config = rama_tls_rustls::client::TlsConnectorData::new_http_auto()
88 .expect("connector data with http auto");
89
90 EasyHttpWebClientBuilder::new()
91 .with_default_transport_connector()
92 .with_tls_proxy_support_using_rustls()
93 .with_proxy_support()
94 .with_tls_support_using_rustls(Some(tls_config))
95 .build()
96 }
97
98 #[cfg(not(any(feature = "rustls", feature = "boring")))]
99 fn default() -> Self {
100 EasyHttpWebClientBuilder::new()
101 .with_default_transport_connector()
102 .without_tls_proxy_support()
103 .with_proxy_support()
104 .without_tls_support()
105 .build()
106 }
107}
108
109impl<BodyIn, ConnResponse> EasyHttpWebClient<BodyIn, ConnResponse> {
110 #[must_use]
112 pub fn new(connector: BoxService<Request<BodyIn>, ConnResponse, BoxError>) -> Self {
113 Self { connector }
114 }
115
116 #[must_use]
118 pub fn with_connector<BodyInNew, ConnResponseNew>(
119 self,
120 connector: BoxService<Request<BodyInNew>, ConnResponseNew, BoxError>,
121 ) -> EasyHttpWebClient<BodyInNew, ConnResponseNew> {
122 EasyHttpWebClient { connector }
123 }
124}
125
126impl<Body, ModifiedBody, ConnResponse> Service<Request<Body>>
127 for EasyHttpWebClient<Body, EstablishedClientConnection<ConnResponse, Request<ModifiedBody>>>
128where
129 Body: http_body::Body<Data: Send + 'static, Error: Into<BoxError>> + Unpin + Send + 'static,
130 ModifiedBody:
131 http_body::Body<Data: Send + 'static, Error: Into<BoxError>> + Unpin + Send + 'static,
132 ConnResponse: Service<Request<ModifiedBody>, Response = Response, Error = BoxError>,
133{
134 type Response = Response;
135
136 type Error = OpaqueError;
137
138 async fn serve(&self, ctx: Context, req: Request<Body>) -> Result<Self::Response, Self::Error> {
139 let uri = req.uri().clone();
140
141 let EstablishedClientConnection { ctx, req, conn } = self.connector.serve(ctx, req).await?;
142 tracing::trace!(url.full = %uri, "send http req to connector stack");
144
145 let result = conn.serve(ctx, req).await;
146
147 let resp = result
148 .map_err(OpaqueError::from_boxed)
149 .with_context(|| format!("http request failure for uri: {uri}"))?;
150
151 tracing::trace!(url.full = %uri, "response received from connector stack");
152
153 Ok(resp)
154 }
155}