1use rama_core::rt::Executor;
2
3use super::HttpConnector;
4use crate::{
5 Layer, Service,
6 dns::client::resolver::DnsAddressResolver,
7 error::BoxError,
8 extensions::ExtensionsRef,
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(any(feature = "rustls", feature = "boring"))]
28use crate::net::tls::client::TlsClientConfig;
29#[cfg(feature = "rustls")]
30use crate::tls::rustls::client as rustls_client;
31
32#[cfg(feature = "socks5")]
33use crate::{http::client::proxy_connector::ProxyConnector, proxy::socks5::Socks5ProxyConnector};
34
35#[derive(Default)]
37pub struct EasyHttpConnectorBuilder<C = (), S = ()> {
38 connector: C,
39 _phantom: PhantomData<S>,
40}
41
42#[non_exhaustive]
43#[derive(Debug)]
44pub struct TransportStage;
45#[non_exhaustive]
46#[derive(Debug)]
47pub struct ProxyTunnelStage;
48#[non_exhaustive]
49#[derive(Debug)]
50pub struct ProxyStage;
51#[non_exhaustive]
52#[derive(Debug)]
53pub struct TlsStage;
54#[non_exhaustive]
55#[derive(Debug)]
56pub struct HttpStage;
57#[non_exhaustive]
58#[derive(Debug)]
59pub struct PoolStage;
60
61impl EasyHttpConnectorBuilder {
62 #[must_use]
63 pub fn new() -> Self {
64 Self::default()
65 }
66
67 #[must_use]
68 pub fn with_default_transport_connector(
69 self,
70 ) -> EasyHttpConnectorBuilder<TcpConnector, TransportStage> {
71 let connector = TcpConnector::default();
72 EasyHttpConnectorBuilder {
73 connector,
74 _phantom: PhantomData,
75 }
76 }
77
78 pub fn with_custom_transport_connector<C>(
80 self,
81 connector: C,
82 ) -> EasyHttpConnectorBuilder<C, TransportStage> {
83 EasyHttpConnectorBuilder {
84 connector,
85 _phantom: PhantomData,
86 }
87 }
88}
89
90impl<T, Stage> EasyHttpConnectorBuilder<T, Stage> {
91 pub fn with_custom_connector<L>(
96 self,
97 connector_layer: L,
98 ) -> EasyHttpConnectorBuilder<L::Service, Stage>
99 where
100 L: Layer<T>,
101 {
102 self.map_connector(|c| connector_layer.into_layer(c))
103 }
104
105 pub fn map_connector<T2>(
110 self,
111 map_fn: impl FnOnce(T) -> T2,
112 ) -> EasyHttpConnectorBuilder<T2, Stage> {
113 let connector = map_fn(self.connector);
114 EasyHttpConnectorBuilder {
115 connector,
116 _phantom: PhantomData,
117 }
118 }
119}
120
121impl EasyHttpConnectorBuilder<TcpConnector, TransportStage> {
122 pub fn with_dns_address_resolver<T: DnsAddressResolver + Clone>(
125 self,
126 resolver: T,
127 ) -> EasyHttpConnectorBuilder<TcpConnector<T>, TransportStage> {
128 let connector = self.connector.with_dns(resolver);
129 EasyHttpConnectorBuilder {
130 connector,
131 _phantom: PhantomData,
132 }
133 }
134}
135
136impl<T> EasyHttpConnectorBuilder<T, TransportStage> {
137 #[cfg(any(feature = "rustls", feature = "boring"))]
138 pub fn with_custom_tls_proxy_connector<L>(
140 self,
141 connector_layer: L,
142 ) -> EasyHttpConnectorBuilder<L::Service, ProxyTunnelStage>
143 where
144 L: Layer<T>,
145 {
146 let connector = connector_layer.into_layer(self.connector);
147 EasyHttpConnectorBuilder {
148 connector,
149 _phantom: PhantomData,
150 }
151 }
152
153 #[cfg(feature = "boring")]
154 #[cfg_attr(docsrs, doc(cfg(feature = "boring")))]
155 pub fn with_tls_proxy_support_using_boringssl(
161 self,
162 ) -> EasyHttpConnectorBuilder<
163 boring_client::TlsConnector<T, boring_client::ConnectorKindTunnel>,
164 ProxyTunnelStage,
165 > {
166 let connector = boring_client::TlsConnector::tunnel(self.connector, None);
167 EasyHttpConnectorBuilder {
168 connector,
169 _phantom: PhantomData,
170 }
171 }
172
173 #[cfg(feature = "boring")]
174 #[cfg_attr(docsrs, doc(cfg(feature = "boring")))]
175 pub fn with_tls_proxy_support_using_boringssl_config(
181 self,
182 config: TlsClientConfig,
183 ) -> EasyHttpConnectorBuilder<
184 boring_client::TlsConnector<T, boring_client::ConnectorKindTunnel>,
185 ProxyTunnelStage,
186 > {
187 let connector =
188 boring_client::TlsConnector::tunnel(self.connector, None).with_base_config(config);
189 EasyHttpConnectorBuilder {
190 connector,
191 _phantom: PhantomData,
192 }
193 }
194
195 #[cfg(feature = "rustls")]
196 #[cfg_attr(docsrs, doc(cfg(feature = "rustls")))]
197 pub fn with_tls_proxy_support_using_rustls(
203 self,
204 ) -> EasyHttpConnectorBuilder<
205 rustls_client::TlsConnector<T, rustls_client::ConnectorKindTunnel>,
206 ProxyTunnelStage,
207 > {
208 let connector = rustls_client::TlsConnector::tunnel(self.connector, None);
209
210 EasyHttpConnectorBuilder {
211 connector,
212 _phantom: PhantomData,
213 }
214 }
215
216 #[cfg(feature = "rustls")]
217 #[cfg_attr(docsrs, doc(cfg(feature = "rustls")))]
218 pub fn with_tls_proxy_support_using_rustls_config(
224 self,
225 config: TlsClientConfig,
226 ) -> EasyHttpConnectorBuilder<
227 rustls_client::TlsConnector<T, rustls_client::ConnectorKindTunnel>,
228 ProxyTunnelStage,
229 > {
230 let connector =
231 rustls_client::TlsConnector::tunnel(self.connector, None).with_base_config(config);
232
233 EasyHttpConnectorBuilder {
234 connector,
235 _phantom: PhantomData,
236 }
237 }
238
239 pub fn without_tls_proxy_support(self) -> EasyHttpConnectorBuilder<T, ProxyTunnelStage> {
245 EasyHttpConnectorBuilder {
246 connector: self.connector,
247 _phantom: PhantomData,
248 }
249 }
250}
251
252impl<T> EasyHttpConnectorBuilder<T, ProxyTunnelStage> {
253 pub fn with_custom_proxy_connector<L>(
255 self,
256 connector_layer: L,
257 ) -> EasyHttpConnectorBuilder<L::Service, ProxyStage>
258 where
259 L: Layer<T>,
260 {
261 let connector = connector_layer.into_layer(self.connector);
262 EasyHttpConnectorBuilder {
263 connector,
264 _phantom: PhantomData,
265 }
266 }
267
268 #[cfg(not(feature = "socks5"))]
269 pub fn with_proxy_support(self) -> EasyHttpConnectorBuilder<HttpProxyConnector<T>, ProxyStage> {
279 self.with_http_proxy_support()
280 }
281
282 pub fn with_http_proxy_support(
290 self,
291 ) -> EasyHttpConnectorBuilder<HttpProxyConnector<T>, ProxyStage> {
292 let connector = HttpProxyConnector::optional(self.connector);
293
294 EasyHttpConnectorBuilder {
295 connector,
296 _phantom: PhantomData,
297 }
298 }
299
300 #[cfg(feature = "socks5")]
301 #[cfg_attr(docsrs, doc(cfg(feature = "socks5")))]
302 pub fn with_socks5_proxy_support(
306 self,
307 ) -> EasyHttpConnectorBuilder<Socks5ProxyConnector<T>, ProxyStage> {
308 let connector = Socks5ProxyConnector::optional(self.connector);
309
310 EasyHttpConnectorBuilder {
311 connector,
312 _phantom: PhantomData,
313 }
314 }
315
316 pub fn without_proxy_support(self) -> EasyHttpConnectorBuilder<T, ProxyStage> {
318 EasyHttpConnectorBuilder {
319 connector: self.connector,
320 _phantom: PhantomData,
321 }
322 }
323}
324
325impl<T: Clone> EasyHttpConnectorBuilder<T, ProxyTunnelStage> {
326 #[cfg(feature = "socks5")]
327 #[cfg_attr(docsrs, doc(cfg(feature = "socks5")))]
328 pub fn with_proxy_support(self) -> EasyHttpConnectorBuilder<ProxyConnector<T>, ProxyStage> {
336 use rama_http_backend::client::proxy::layer::HttpProxyConnectorLayer;
337 use rama_socks5::Socks5ProxyConnectorLayer;
338
339 let connector = ProxyConnector::optional(
340 self.connector,
341 Socks5ProxyConnectorLayer::required(),
342 HttpProxyConnectorLayer::required(),
343 );
344
345 EasyHttpConnectorBuilder {
346 connector,
347 _phantom: PhantomData,
348 }
349 }
350}
351
352impl<T> EasyHttpConnectorBuilder<T, ProxyStage> {
353 #[cfg(any(feature = "rustls", feature = "boring"))]
354 pub fn with_custom_tls_connector<L>(
361 self,
362 connector_layer: L,
363 ) -> EasyHttpConnectorBuilder<L::Service, TlsStage>
364 where
365 L: Layer<T>,
366 {
367 let connector = connector_layer.into_layer(self.connector);
368
369 EasyHttpConnectorBuilder {
370 connector,
371 _phantom: PhantomData,
372 }
373 }
374
375 #[cfg(feature = "boring")]
376 #[cfg_attr(docsrs, doc(cfg(feature = "boring")))]
377 pub fn with_tls_support_using_boringssl(
383 self,
384 config: TlsClientConfig,
385 ) -> EasyHttpConnectorBuilder<RequestVersionAdapter<boring_client::TlsConnector<T>>, TlsStage>
386 {
387 let connector = boring_client::TlsConnector::auto(self.connector).with_base_config(config);
388 let connector = RequestVersionAdapter::new(connector);
389
390 EasyHttpConnectorBuilder {
391 connector,
392 _phantom: PhantomData,
393 }
394 }
395
396 #[cfg(feature = "boring")]
397 #[cfg_attr(docsrs, doc(cfg(feature = "boring")))]
398 pub fn with_tls_support_using_boringssl_and_default_http_version(
407 self,
408 config: TlsClientConfig,
409 default_http_version: rama_http::Version,
410 ) -> EasyHttpConnectorBuilder<RequestVersionAdapter<boring_client::TlsConnector<T>>, TlsStage>
411 {
412 let connector = boring_client::TlsConnector::auto(self.connector).with_base_config(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: TlsClientConfig,
432 ) -> EasyHttpConnectorBuilder<RequestVersionAdapter<rustls_client::TlsConnector<T>>, TlsStage>
433 {
434 let connector = rustls_client::TlsConnector::auto(self.connector).with_base_config(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: TlsClientConfig,
456 default_http_version: rama_http::Version,
457 ) -> EasyHttpConnectorBuilder<RequestVersionAdapter<rustls_client::TlsConnector<T>>, TlsStage>
458 {
459 let connector = rustls_client::TlsConnector::auto(self.connector).with_base_config(config);
460 let connector =
461 RequestVersionAdapter::new(connector).with_default_version(default_http_version);
462
463 EasyHttpConnectorBuilder {
464 connector,
465 _phantom: PhantomData,
466 }
467 }
468
469 pub fn without_tls_support(self) -> EasyHttpConnectorBuilder<T, TlsStage> {
471 EasyHttpConnectorBuilder {
472 connector: self.connector,
473 _phantom: PhantomData,
474 }
475 }
476}
477
478impl<T> EasyHttpConnectorBuilder<T, TlsStage> {
479 pub fn with_default_http_connector<Body>(
481 self,
482 exec: Executor,
483 ) -> EasyHttpConnectorBuilder<HttpConnector<T, Body>, HttpStage> {
484 let connector = HttpConnector::new(self.connector, exec);
485
486 EasyHttpConnectorBuilder {
487 connector,
488 _phantom: PhantomData,
489 }
490 }
491
492 pub fn with_custom_http_connector<L>(
494 self,
495 connector_layer: L,
496 ) -> EasyHttpConnectorBuilder<L::Service, HttpStage>
497 where
498 L: Layer<T>,
499 {
500 let connector = connector_layer.into_layer(self.connector);
501
502 EasyHttpConnectorBuilder {
503 connector,
504 _phantom: PhantomData,
505 }
506 }
507}
508
509type DefaultConnectionPoolBuilder<T, C> = EasyHttpConnectorBuilder<
510 RequestVersionAdapter<
511 PooledConnector<T, LruDropPool<C, BasicHttpConId>, BasicHttpConnIdentifier>,
512 >,
513 PoolStage,
514>;
515
516impl<T> EasyHttpConnectorBuilder<T, HttpStage> {
517 pub fn try_with_connection_pool<C: ExtensionsRef>(
533 self,
534 config: HttpPooledConnectorConfig,
535 ) -> Result<DefaultConnectionPoolBuilder<T, C>, BoxError> {
536 let connector = config.build_connector(self.connector)?;
537 let connector = RequestVersionAdapter::new(connector);
538
539 Ok(EasyHttpConnectorBuilder {
540 connector,
541 _phantom: PhantomData,
542 })
543 }
544
545 #[inline(always)]
546 pub fn try_with_default_connection_pool<C: ExtensionsRef>(
548 self,
549 ) -> Result<DefaultConnectionPoolBuilder<T, C>, BoxError> {
550 self.try_with_connection_pool(Default::default())
551 }
552
553 pub fn with_custom_connection_pool<P, R>(
564 self,
565 pool: P,
566 req_to_conn_id: R,
567 wait_for_pool_timeout: Option<Duration>,
568 ) -> EasyHttpConnectorBuilder<PooledConnector<T, P, R>, PoolStage> {
569 let connector = PooledConnector::new(self.connector, pool, req_to_conn_id)
570 .maybe_with_wait_for_pool_timeout(wait_for_pool_timeout);
571
572 EasyHttpConnectorBuilder {
573 connector,
574 _phantom: PhantomData,
575 }
576 }
577}
578
579impl<T, S> EasyHttpConnectorBuilder<T, S> {
580 pub fn build_client<Body, ModifiedBody, ConnResponse>(
582 self,
583 ) -> super::EasyHttpWebClient<Body, T::Output, ()>
584 where
585 Body: StreamingBody<Data: Send + 'static, Error: Into<BoxError>> + Unpin + Send + 'static,
586 ModifiedBody:
587 StreamingBody<Data: Send + 'static, Error: Into<BoxError>> + Unpin + Send + 'static,
588 T: Service<
589 Request<Body>,
590 Output = EstablishedClientConnection<ConnResponse, Request<ModifiedBody>>,
591 Error: Into<BoxError>,
592 >,
593 ConnResponse: ExtensionsRef,
594 {
595 super::EasyHttpWebClient::new(self.connector)
596 }
597
598 pub fn build_connector(self) -> T {
600 self.connector
601 }
602}