1use rama_core::rt::Executor;
2
3use super::HttpConnector;
4use crate::{
5 Layer, Service,
6 dns::DnsResolver,
7 error::{BoxError, OpaqueError},
8 extensions::ExtensionsMut,
9 http::{
10 Request, StreamingBody, client::proxy::layer::HttpProxyConnector,
11 layer::version_adapter::RequestVersionAdapter,
12 },
13 net::client::{
14 EstablishedClientConnection,
15 pool::{
16 LruDropPool, PooledConnector,
17 http::{BasicHttpConId, BasicHttpConnIdentifier, HttpPooledConnectorConfig},
18 },
19 },
20 tcp::client::service::TcpConnector,
21};
22use std::{marker::PhantomData, time::Duration};
23
24#[cfg(feature = "boring")]
25use crate::tls::boring::client as boring_client;
26
27#[cfg(feature = "rustls")]
28use crate::tls::rustls::client as rustls_client;
29
30#[cfg(feature = "socks5")]
31use crate::{http::client::proxy_connector::ProxyConnector, proxy::socks5::Socks5ProxyConnector};
32
33#[derive(Default)]
35pub struct EasyHttpConnectorBuilder<C = (), S = ()> {
36 connector: C,
37 _phantom: PhantomData<S>,
38}
39
40#[non_exhaustive]
41#[derive(Debug)]
42pub struct TransportStage;
43#[non_exhaustive]
44#[derive(Debug)]
45pub struct ProxyTunnelStage;
46#[non_exhaustive]
47#[derive(Debug)]
48pub struct ProxyStage;
49#[non_exhaustive]
50#[derive(Debug)]
51pub struct TlsStage;
52#[non_exhaustive]
53#[derive(Debug)]
54pub struct HttpStage;
55#[non_exhaustive]
56#[derive(Debug)]
57pub struct PoolStage;
58
59impl EasyHttpConnectorBuilder {
60 #[must_use]
61 pub fn new() -> Self {
62 Self::default()
63 }
64
65 #[must_use]
66 pub fn with_default_transport_connector(
67 self,
68 ) -> EasyHttpConnectorBuilder<TcpConnector, TransportStage> {
69 let connector = TcpConnector::default();
70 EasyHttpConnectorBuilder {
71 connector,
72 _phantom: PhantomData,
73 }
74 }
75
76 pub fn with_custom_transport_connector<C>(
78 self,
79 connector: C,
80 ) -> EasyHttpConnectorBuilder<C, TransportStage> {
81 EasyHttpConnectorBuilder {
82 connector,
83 _phantom: PhantomData,
84 }
85 }
86}
87
88impl<T, Stage> EasyHttpConnectorBuilder<T, Stage> {
89 pub fn with_custom_connector<L>(
94 self,
95 connector_layer: L,
96 ) -> EasyHttpConnectorBuilder<L::Service, Stage>
97 where
98 L: Layer<T>,
99 {
100 self.map_connector(|c| connector_layer.into_layer(c))
101 }
102
103 pub fn map_connector<T2>(
108 self,
109 map_fn: impl FnOnce(T) -> T2,
110 ) -> EasyHttpConnectorBuilder<T2, Stage> {
111 let connector = map_fn(self.connector);
112 EasyHttpConnectorBuilder {
113 connector,
114 _phantom: PhantomData,
115 }
116 }
117}
118
119impl EasyHttpConnectorBuilder<TcpConnector, TransportStage> {
120 pub fn with_dns_resolver<T: DnsResolver + Clone>(
122 self,
123 resolver: T,
124 ) -> EasyHttpConnectorBuilder<TcpConnector<T>, TransportStage> {
125 let connector = self.connector.with_dns(resolver);
126 EasyHttpConnectorBuilder {
127 connector,
128 _phantom: PhantomData,
129 }
130 }
131}
132
133impl<T> EasyHttpConnectorBuilder<T, TransportStage> {
134 #[cfg(any(feature = "rustls", feature = "boring"))]
135 pub fn with_custom_tls_proxy_connector<L>(
137 self,
138 connector_layer: L,
139 ) -> EasyHttpConnectorBuilder<L::Service, ProxyTunnelStage>
140 where
141 L: Layer<T>,
142 {
143 let connector = connector_layer.into_layer(self.connector);
144 EasyHttpConnectorBuilder {
145 connector,
146 _phantom: PhantomData,
147 }
148 }
149
150 #[cfg(feature = "boring")]
151 #[cfg_attr(docsrs, doc(cfg(feature = "boring")))]
152 pub fn with_tls_proxy_support_using_boringssl(
158 self,
159 ) -> EasyHttpConnectorBuilder<
160 boring_client::TlsConnector<T, boring_client::ConnectorKindTunnel>,
161 ProxyTunnelStage,
162 > {
163 let connector = boring_client::TlsConnector::tunnel(self.connector, None);
164 EasyHttpConnectorBuilder {
165 connector,
166 _phantom: PhantomData,
167 }
168 }
169
170 #[cfg(feature = "boring")]
171 #[cfg_attr(docsrs, doc(cfg(feature = "boring")))]
172 pub fn with_tls_proxy_support_using_boringssl_config(
178 self,
179 config: std::sync::Arc<boring_client::TlsConnectorDataBuilder>,
180 ) -> EasyHttpConnectorBuilder<
181 boring_client::TlsConnector<T, boring_client::ConnectorKindTunnel>,
182 ProxyTunnelStage,
183 > {
184 let connector =
185 boring_client::TlsConnector::tunnel(self.connector, None).with_connector_data(config);
186 EasyHttpConnectorBuilder {
187 connector,
188 _phantom: PhantomData,
189 }
190 }
191
192 #[cfg(feature = "rustls")]
193 #[cfg_attr(docsrs, doc(cfg(feature = "rustls")))]
194 pub fn with_tls_proxy_support_using_rustls(
200 self,
201 ) -> EasyHttpConnectorBuilder<
202 rustls_client::TlsConnector<T, rustls_client::ConnectorKindTunnel>,
203 ProxyTunnelStage,
204 > {
205 let connector = rustls_client::TlsConnector::tunnel(self.connector, None);
206
207 EasyHttpConnectorBuilder {
208 connector,
209 _phantom: PhantomData,
210 }
211 }
212
213 #[cfg(feature = "rustls")]
214 #[cfg_attr(docsrs, doc(cfg(feature = "rustls")))]
215 pub fn with_tls_proxy_support_using_rustls_config(
221 self,
222 config: rustls_client::TlsConnectorData,
223 ) -> EasyHttpConnectorBuilder<
224 rustls_client::TlsConnector<T, rustls_client::ConnectorKindTunnel>,
225 ProxyTunnelStage,
226 > {
227 let connector =
228 rustls_client::TlsConnector::tunnel(self.connector, None).with_connector_data(config);
229
230 EasyHttpConnectorBuilder {
231 connector,
232 _phantom: PhantomData,
233 }
234 }
235
236 pub fn without_tls_proxy_support(self) -> EasyHttpConnectorBuilder<T, ProxyTunnelStage> {
242 EasyHttpConnectorBuilder {
243 connector: self.connector,
244 _phantom: PhantomData,
245 }
246 }
247}
248
249impl<T> EasyHttpConnectorBuilder<T, ProxyTunnelStage> {
250 pub fn with_custom_proxy_connector<L>(
252 self,
253 connector_layer: L,
254 ) -> EasyHttpConnectorBuilder<L::Service, ProxyStage>
255 where
256 L: Layer<T>,
257 {
258 let connector = connector_layer.into_layer(self.connector);
259 EasyHttpConnectorBuilder {
260 connector,
261 _phantom: PhantomData,
262 }
263 }
264
265 #[cfg(not(feature = "socks5"))]
266 pub fn with_proxy_support(self) -> EasyHttpConnectorBuilder<HttpProxyConnector<T>, ProxyStage> {
276 self.with_http_proxy_support()
277 }
278
279 pub fn with_http_proxy_support(
287 self,
288 ) -> EasyHttpConnectorBuilder<HttpProxyConnector<T>, ProxyStage> {
289 let connector = HttpProxyConnector::optional(self.connector);
290
291 EasyHttpConnectorBuilder {
292 connector,
293 _phantom: PhantomData,
294 }
295 }
296
297 #[cfg(feature = "socks5")]
298 #[cfg_attr(docsrs, doc(cfg(feature = "socks5")))]
299 pub fn with_socks5_proxy_support(
303 self,
304 ) -> EasyHttpConnectorBuilder<Socks5ProxyConnector<T>, ProxyStage> {
305 let connector = Socks5ProxyConnector::optional(self.connector);
306
307 EasyHttpConnectorBuilder {
308 connector,
309 _phantom: PhantomData,
310 }
311 }
312
313 pub fn without_proxy_support(self) -> EasyHttpConnectorBuilder<T, ProxyStage> {
315 EasyHttpConnectorBuilder {
316 connector: self.connector,
317 _phantom: PhantomData,
318 }
319 }
320}
321
322impl<T: Clone> EasyHttpConnectorBuilder<T, ProxyTunnelStage> {
323 #[cfg(feature = "socks5")]
324 #[cfg_attr(docsrs, doc(cfg(feature = "socks5")))]
325 pub fn with_proxy_support(self) -> EasyHttpConnectorBuilder<ProxyConnector<T>, ProxyStage> {
333 use rama_http_backend::client::proxy::layer::HttpProxyConnectorLayer;
334 use rama_socks5::Socks5ProxyConnectorLayer;
335
336 let connector = ProxyConnector::optional(
337 self.connector,
338 Socks5ProxyConnectorLayer::required(),
339 HttpProxyConnectorLayer::required(),
340 );
341
342 EasyHttpConnectorBuilder {
343 connector,
344 _phantom: PhantomData,
345 }
346 }
347}
348
349impl<T> EasyHttpConnectorBuilder<T, ProxyStage> {
350 #[cfg(any(feature = "rustls", feature = "boring"))]
351 pub fn with_custom_tls_connector<L>(
358 self,
359 connector_layer: L,
360 ) -> EasyHttpConnectorBuilder<L::Service, TlsStage>
361 where
362 L: Layer<T>,
363 {
364 let connector = connector_layer.into_layer(self.connector);
365
366 EasyHttpConnectorBuilder {
367 connector,
368 _phantom: PhantomData,
369 }
370 }
371
372 #[cfg(feature = "boring")]
373 #[cfg_attr(docsrs, doc(cfg(feature = "boring")))]
374 pub fn with_tls_support_using_boringssl(
380 self,
381 config: Option<std::sync::Arc<boring_client::TlsConnectorDataBuilder>>,
382 ) -> EasyHttpConnectorBuilder<RequestVersionAdapter<boring_client::TlsConnector<T>>, TlsStage>
383 {
384 let connector =
385 boring_client::TlsConnector::auto(self.connector).maybe_with_connector_data(config);
386 let connector = RequestVersionAdapter::new(connector);
387
388 EasyHttpConnectorBuilder {
389 connector,
390 _phantom: PhantomData,
391 }
392 }
393
394 #[cfg(feature = "boring")]
395 #[cfg_attr(docsrs, doc(cfg(feature = "boring")))]
396 pub fn with_tls_support_using_boringssl_and_default_http_version(
405 self,
406 config: Option<std::sync::Arc<boring_client::TlsConnectorDataBuilder>>,
407 default_http_version: rama_http::Version,
408 ) -> EasyHttpConnectorBuilder<RequestVersionAdapter<boring_client::TlsConnector<T>>, TlsStage>
409 {
410 let connector =
411 boring_client::TlsConnector::auto(self.connector).maybe_with_connector_data(config);
412 let connector =
413 RequestVersionAdapter::new(connector).with_default_version(default_http_version);
414
415 EasyHttpConnectorBuilder {
416 connector,
417 _phantom: PhantomData,
418 }
419 }
420
421 #[cfg(feature = "rustls")]
422 #[cfg_attr(docsrs, doc(cfg(feature = "rustls")))]
423 pub fn with_tls_support_using_rustls(
429 self,
430 config: Option<rustls_client::TlsConnectorData>,
431 ) -> EasyHttpConnectorBuilder<RequestVersionAdapter<rustls_client::TlsConnector<T>>, TlsStage>
432 {
433 let connector =
434 rustls_client::TlsConnector::auto(self.connector).maybe_with_connector_data(config);
435 let connector = RequestVersionAdapter::new(connector);
436
437 EasyHttpConnectorBuilder {
438 connector,
439 _phantom: PhantomData,
440 }
441 }
442
443 #[cfg(feature = "rustls")]
444 #[cfg_attr(docsrs, doc(cfg(feature = "rustls")))]
445 pub fn with_tls_support_using_rustls_and_default_http_version(
454 self,
455 config: Option<rustls_client::TlsConnectorData>,
456 default_http_version: rama_http::Version,
457 ) -> EasyHttpConnectorBuilder<RequestVersionAdapter<rustls_client::TlsConnector<T>>, TlsStage>
458 {
459 let connector =
460 rustls_client::TlsConnector::auto(self.connector).maybe_with_connector_data(config);
461 let connector =
462 RequestVersionAdapter::new(connector).with_default_version(default_http_version);
463
464 EasyHttpConnectorBuilder {
465 connector,
466 _phantom: PhantomData,
467 }
468 }
469
470 pub fn without_tls_support(self) -> EasyHttpConnectorBuilder<T, TlsStage> {
472 EasyHttpConnectorBuilder {
473 connector: self.connector,
474 _phantom: PhantomData,
475 }
476 }
477}
478
479impl<T> EasyHttpConnectorBuilder<T, TlsStage> {
480 pub fn with_default_http_connector<Body>(
482 self,
483 exec: Executor,
484 ) -> EasyHttpConnectorBuilder<HttpConnector<T, Body>, HttpStage> {
485 let connector = HttpConnector::new(self.connector, exec);
486
487 EasyHttpConnectorBuilder {
488 connector,
489 _phantom: PhantomData,
490 }
491 }
492
493 pub fn with_custom_http_connector<L>(
495 self,
496 connector_layer: L,
497 ) -> EasyHttpConnectorBuilder<L::Service, HttpStage>
498 where
499 L: Layer<T>,
500 {
501 let connector = connector_layer.into_layer(self.connector);
502
503 EasyHttpConnectorBuilder {
504 connector,
505 _phantom: PhantomData,
506 }
507 }
508}
509
510type DefaultConnectionPoolBuilder<T, C> = EasyHttpConnectorBuilder<
511 RequestVersionAdapter<
512 PooledConnector<T, LruDropPool<C, BasicHttpConId>, BasicHttpConnIdentifier>,
513 >,
514 PoolStage,
515>;
516
517impl<T> EasyHttpConnectorBuilder<T, HttpStage> {
518 pub fn try_with_connection_pool<C: ExtensionsMut>(
534 self,
535 config: HttpPooledConnectorConfig,
536 ) -> Result<DefaultConnectionPoolBuilder<T, C>, OpaqueError> {
537 let connector = config.build_connector(self.connector)?;
538 let connector = RequestVersionAdapter::new(connector);
539
540 Ok(EasyHttpConnectorBuilder {
541 connector,
542 _phantom: PhantomData,
543 })
544 }
545
546 #[inline(always)]
547 pub fn try_with_default_connection_pool<C: ExtensionsMut>(
549 self,
550 ) -> Result<DefaultConnectionPoolBuilder<T, C>, OpaqueError> {
551 self.try_with_connection_pool(Default::default())
552 }
553
554 pub fn with_custom_connection_pool<P, R>(
565 self,
566 pool: P,
567 req_to_conn_id: R,
568 wait_for_pool_timeout: Option<Duration>,
569 ) -> EasyHttpConnectorBuilder<PooledConnector<T, P, R>, PoolStage> {
570 let connector = PooledConnector::new(self.connector, pool, req_to_conn_id)
571 .maybe_with_wait_for_pool_timeout(wait_for_pool_timeout);
572
573 EasyHttpConnectorBuilder {
574 connector,
575 _phantom: PhantomData,
576 }
577 }
578}
579
580impl<T, S> EasyHttpConnectorBuilder<T, S> {
581 pub fn build_client<Body, ModifiedBody, ConnResponse>(
583 self,
584 ) -> super::EasyHttpWebClient<Body, T::Output, ()>
585 where
586 Body: StreamingBody<Data: Send + 'static, Error: Into<BoxError>> + Unpin + Send + 'static,
587 ModifiedBody:
588 StreamingBody<Data: Send + 'static, Error: Into<BoxError>> + Unpin + Send + 'static,
589 T: Service<
590 Request<Body>,
591 Output = EstablishedClientConnection<ConnResponse, Request<ModifiedBody>>,
592 Error = BoxError,
593 >,
594 ConnResponse: ExtensionsMut,
595 {
596 super::EasyHttpWebClient::new(self.connector.boxed())
597 }
598
599 pub fn build_connector(self) -> T {
601 self.connector
602 }
603}