1use rama_core::rt::Executor;
2
3use super::HttpConnector;
4use crate::{
5 Layer, Service,
6 dns::client::resolver::DnsAddressResolver,
7 error::BoxError,
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_address_resolver<T: DnsAddressResolver + Clone>(
123 self,
124 resolver: T,
125 ) -> EasyHttpConnectorBuilder<TcpConnector<T>, TransportStage> {
126 let connector = self.connector.with_dns(resolver);
127 EasyHttpConnectorBuilder {
128 connector,
129 _phantom: PhantomData,
130 }
131 }
132}
133
134impl<T> EasyHttpConnectorBuilder<T, TransportStage> {
135 #[cfg(any(feature = "rustls", feature = "boring"))]
136 pub fn with_custom_tls_proxy_connector<L>(
138 self,
139 connector_layer: L,
140 ) -> EasyHttpConnectorBuilder<L::Service, ProxyTunnelStage>
141 where
142 L: Layer<T>,
143 {
144 let connector = connector_layer.into_layer(self.connector);
145 EasyHttpConnectorBuilder {
146 connector,
147 _phantom: PhantomData,
148 }
149 }
150
151 #[cfg(feature = "boring")]
152 #[cfg_attr(docsrs, doc(cfg(feature = "boring")))]
153 pub fn with_tls_proxy_support_using_boringssl(
159 self,
160 ) -> EasyHttpConnectorBuilder<
161 boring_client::TlsConnector<T, boring_client::ConnectorKindTunnel>,
162 ProxyTunnelStage,
163 > {
164 let connector = boring_client::TlsConnector::tunnel(self.connector, None);
165 EasyHttpConnectorBuilder {
166 connector,
167 _phantom: PhantomData,
168 }
169 }
170
171 #[cfg(feature = "boring")]
172 #[cfg_attr(docsrs, doc(cfg(feature = "boring")))]
173 pub fn with_tls_proxy_support_using_boringssl_config(
179 self,
180 config: std::sync::Arc<boring_client::TlsConnectorDataBuilder>,
181 ) -> EasyHttpConnectorBuilder<
182 boring_client::TlsConnector<T, boring_client::ConnectorKindTunnel>,
183 ProxyTunnelStage,
184 > {
185 let connector =
186 boring_client::TlsConnector::tunnel(self.connector, None).with_connector_data(config);
187 EasyHttpConnectorBuilder {
188 connector,
189 _phantom: PhantomData,
190 }
191 }
192
193 #[cfg(feature = "rustls")]
194 #[cfg_attr(docsrs, doc(cfg(feature = "rustls")))]
195 pub fn with_tls_proxy_support_using_rustls(
201 self,
202 ) -> EasyHttpConnectorBuilder<
203 rustls_client::TlsConnector<T, rustls_client::ConnectorKindTunnel>,
204 ProxyTunnelStage,
205 > {
206 let connector = rustls_client::TlsConnector::tunnel(self.connector, None);
207
208 EasyHttpConnectorBuilder {
209 connector,
210 _phantom: PhantomData,
211 }
212 }
213
214 #[cfg(feature = "rustls")]
215 #[cfg_attr(docsrs, doc(cfg(feature = "rustls")))]
216 pub fn with_tls_proxy_support_using_rustls_config(
222 self,
223 config: rustls_client::TlsConnectorData,
224 ) -> EasyHttpConnectorBuilder<
225 rustls_client::TlsConnector<T, rustls_client::ConnectorKindTunnel>,
226 ProxyTunnelStage,
227 > {
228 let connector =
229 rustls_client::TlsConnector::tunnel(self.connector, None).with_connector_data(config);
230
231 EasyHttpConnectorBuilder {
232 connector,
233 _phantom: PhantomData,
234 }
235 }
236
237 pub fn without_tls_proxy_support(self) -> EasyHttpConnectorBuilder<T, ProxyTunnelStage> {
243 EasyHttpConnectorBuilder {
244 connector: self.connector,
245 _phantom: PhantomData,
246 }
247 }
248}
249
250impl<T> EasyHttpConnectorBuilder<T, ProxyTunnelStage> {
251 pub fn with_custom_proxy_connector<L>(
253 self,
254 connector_layer: L,
255 ) -> EasyHttpConnectorBuilder<L::Service, ProxyStage>
256 where
257 L: Layer<T>,
258 {
259 let connector = connector_layer.into_layer(self.connector);
260 EasyHttpConnectorBuilder {
261 connector,
262 _phantom: PhantomData,
263 }
264 }
265
266 #[cfg(not(feature = "socks5"))]
267 pub fn with_proxy_support(self) -> EasyHttpConnectorBuilder<HttpProxyConnector<T>, ProxyStage> {
277 self.with_http_proxy_support()
278 }
279
280 pub fn with_http_proxy_support(
288 self,
289 ) -> EasyHttpConnectorBuilder<HttpProxyConnector<T>, ProxyStage> {
290 let connector = HttpProxyConnector::optional(self.connector);
291
292 EasyHttpConnectorBuilder {
293 connector,
294 _phantom: PhantomData,
295 }
296 }
297
298 #[cfg(feature = "socks5")]
299 #[cfg_attr(docsrs, doc(cfg(feature = "socks5")))]
300 pub fn with_socks5_proxy_support(
304 self,
305 ) -> EasyHttpConnectorBuilder<Socks5ProxyConnector<T>, ProxyStage> {
306 let connector = Socks5ProxyConnector::optional(self.connector);
307
308 EasyHttpConnectorBuilder {
309 connector,
310 _phantom: PhantomData,
311 }
312 }
313
314 pub fn without_proxy_support(self) -> EasyHttpConnectorBuilder<T, ProxyStage> {
316 EasyHttpConnectorBuilder {
317 connector: self.connector,
318 _phantom: PhantomData,
319 }
320 }
321}
322
323impl<T: Clone> EasyHttpConnectorBuilder<T, ProxyTunnelStage> {
324 #[cfg(feature = "socks5")]
325 #[cfg_attr(docsrs, doc(cfg(feature = "socks5")))]
326 pub fn with_proxy_support(self) -> EasyHttpConnectorBuilder<ProxyConnector<T>, ProxyStage> {
334 use rama_http_backend::client::proxy::layer::HttpProxyConnectorLayer;
335 use rama_socks5::Socks5ProxyConnectorLayer;
336
337 let connector = ProxyConnector::optional(
338 self.connector,
339 Socks5ProxyConnectorLayer::required(),
340 HttpProxyConnectorLayer::required(),
341 );
342
343 EasyHttpConnectorBuilder {
344 connector,
345 _phantom: PhantomData,
346 }
347 }
348}
349
350impl<T> EasyHttpConnectorBuilder<T, ProxyStage> {
351 #[cfg(any(feature = "rustls", feature = "boring"))]
352 pub fn with_custom_tls_connector<L>(
359 self,
360 connector_layer: L,
361 ) -> EasyHttpConnectorBuilder<L::Service, TlsStage>
362 where
363 L: Layer<T>,
364 {
365 let connector = connector_layer.into_layer(self.connector);
366
367 EasyHttpConnectorBuilder {
368 connector,
369 _phantom: PhantomData,
370 }
371 }
372
373 #[cfg(feature = "boring")]
374 #[cfg_attr(docsrs, doc(cfg(feature = "boring")))]
375 pub fn with_tls_support_using_boringssl(
381 self,
382 config: Option<std::sync::Arc<boring_client::TlsConnectorDataBuilder>>,
383 ) -> EasyHttpConnectorBuilder<RequestVersionAdapter<boring_client::TlsConnector<T>>, TlsStage>
384 {
385 let connector =
386 boring_client::TlsConnector::auto(self.connector).maybe_with_connector_data(config);
387 let connector = RequestVersionAdapter::new(connector);
388
389 EasyHttpConnectorBuilder {
390 connector,
391 _phantom: PhantomData,
392 }
393 }
394
395 #[cfg(feature = "boring")]
396 #[cfg_attr(docsrs, doc(cfg(feature = "boring")))]
397 pub fn with_tls_support_using_boringssl_and_default_http_version(
406 self,
407 config: Option<std::sync::Arc<boring_client::TlsConnectorDataBuilder>>,
408 default_http_version: rama_http::Version,
409 ) -> EasyHttpConnectorBuilder<RequestVersionAdapter<boring_client::TlsConnector<T>>, TlsStage>
410 {
411 let connector =
412 boring_client::TlsConnector::auto(self.connector).maybe_with_connector_data(config);
413 let connector =
414 RequestVersionAdapter::new(connector).with_default_version(default_http_version);
415
416 EasyHttpConnectorBuilder {
417 connector,
418 _phantom: PhantomData,
419 }
420 }
421
422 #[cfg(feature = "rustls")]
423 #[cfg_attr(docsrs, doc(cfg(feature = "rustls")))]
424 pub fn with_tls_support_using_rustls(
430 self,
431 config: Option<rustls_client::TlsConnectorData>,
432 ) -> EasyHttpConnectorBuilder<RequestVersionAdapter<rustls_client::TlsConnector<T>>, TlsStage>
433 {
434 let connector =
435 rustls_client::TlsConnector::auto(self.connector).maybe_with_connector_data(config);
436 let connector = RequestVersionAdapter::new(connector);
437
438 EasyHttpConnectorBuilder {
439 connector,
440 _phantom: PhantomData,
441 }
442 }
443
444 #[cfg(feature = "rustls")]
445 #[cfg_attr(docsrs, doc(cfg(feature = "rustls")))]
446 pub fn with_tls_support_using_rustls_and_default_http_version(
455 self,
456 config: Option<rustls_client::TlsConnectorData>,
457 default_http_version: rama_http::Version,
458 ) -> EasyHttpConnectorBuilder<RequestVersionAdapter<rustls_client::TlsConnector<T>>, TlsStage>
459 {
460 let connector =
461 rustls_client::TlsConnector::auto(self.connector).maybe_with_connector_data(config);
462 let connector =
463 RequestVersionAdapter::new(connector).with_default_version(default_http_version);
464
465 EasyHttpConnectorBuilder {
466 connector,
467 _phantom: PhantomData,
468 }
469 }
470
471 pub fn without_tls_support(self) -> EasyHttpConnectorBuilder<T, TlsStage> {
473 EasyHttpConnectorBuilder {
474 connector: self.connector,
475 _phantom: PhantomData,
476 }
477 }
478}
479
480impl<T> EasyHttpConnectorBuilder<T, TlsStage> {
481 pub fn with_default_http_connector<Body>(
483 self,
484 exec: Executor,
485 ) -> EasyHttpConnectorBuilder<HttpConnector<T, Body>, HttpStage> {
486 let connector = HttpConnector::new(self.connector, exec);
487
488 EasyHttpConnectorBuilder {
489 connector,
490 _phantom: PhantomData,
491 }
492 }
493
494 pub fn with_custom_http_connector<L>(
496 self,
497 connector_layer: L,
498 ) -> EasyHttpConnectorBuilder<L::Service, HttpStage>
499 where
500 L: Layer<T>,
501 {
502 let connector = connector_layer.into_layer(self.connector);
503
504 EasyHttpConnectorBuilder {
505 connector,
506 _phantom: PhantomData,
507 }
508 }
509}
510
511type DefaultConnectionPoolBuilder<T, C> = EasyHttpConnectorBuilder<
512 RequestVersionAdapter<
513 PooledConnector<T, LruDropPool<C, BasicHttpConId>, BasicHttpConnIdentifier>,
514 >,
515 PoolStage,
516>;
517
518impl<T> EasyHttpConnectorBuilder<T, HttpStage> {
519 pub fn try_with_connection_pool<C: ExtensionsMut>(
535 self,
536 config: HttpPooledConnectorConfig,
537 ) -> Result<DefaultConnectionPoolBuilder<T, C>, BoxError> {
538 let connector = config.build_connector(self.connector)?;
539 let connector = RequestVersionAdapter::new(connector);
540
541 Ok(EasyHttpConnectorBuilder {
542 connector,
543 _phantom: PhantomData,
544 })
545 }
546
547 #[inline(always)]
548 pub fn try_with_default_connection_pool<C: ExtensionsMut>(
550 self,
551 ) -> Result<DefaultConnectionPoolBuilder<T, C>, BoxError> {
552 self.try_with_connection_pool(Default::default())
553 }
554
555 pub fn with_custom_connection_pool<P, R>(
566 self,
567 pool: P,
568 req_to_conn_id: R,
569 wait_for_pool_timeout: Option<Duration>,
570 ) -> EasyHttpConnectorBuilder<PooledConnector<T, P, R>, PoolStage> {
571 let connector = PooledConnector::new(self.connector, pool, req_to_conn_id)
572 .maybe_with_wait_for_pool_timeout(wait_for_pool_timeout);
573
574 EasyHttpConnectorBuilder {
575 connector,
576 _phantom: PhantomData,
577 }
578 }
579}
580
581impl<T, S> EasyHttpConnectorBuilder<T, S> {
582 pub fn build_client<Body, ModifiedBody, ConnResponse>(
584 self,
585 ) -> super::EasyHttpWebClient<Body, T::Output, ()>
586 where
587 Body: StreamingBody<Data: Send + 'static, Error: Into<BoxError>> + Unpin + Send + 'static,
588 ModifiedBody:
589 StreamingBody<Data: Send + 'static, Error: Into<BoxError>> + Unpin + Send + 'static,
590 T: Service<
591 Request<Body>,
592 Output = EstablishedClientConnection<ConnResponse, Request<ModifiedBody>>,
593 Error: Into<BoxError>,
594 >,
595 ConnResponse: ExtensionsMut,
596 {
597 super::EasyHttpWebClient::new(self.connector)
598 }
599
600 pub fn build_connector(self) -> T {
602 self.connector
603 }
604}