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 let connector = connector_layer.into_layer(self.connector);
101
102 EasyHttpConnectorBuilder {
103 connector,
104 _phantom: PhantomData,
105 }
106 }
107}
108
109impl EasyHttpConnectorBuilder<TcpConnector, TransportStage> {
110 pub fn with_dns_resolver<T: DnsResolver + Clone>(
112 self,
113 resolver: T,
114 ) -> EasyHttpConnectorBuilder<TcpConnector<T>, TransportStage> {
115 let connector = self.connector.with_dns(resolver);
116 EasyHttpConnectorBuilder {
117 connector,
118 _phantom: PhantomData,
119 }
120 }
121}
122
123impl<T> EasyHttpConnectorBuilder<T, TransportStage> {
124 #[cfg(any(feature = "rustls", feature = "boring"))]
125 pub fn with_custom_tls_proxy_connector<L>(
127 self,
128 connector_layer: L,
129 ) -> EasyHttpConnectorBuilder<L::Service, ProxyTunnelStage>
130 where
131 L: Layer<T>,
132 {
133 let connector = connector_layer.into_layer(self.connector);
134 EasyHttpConnectorBuilder {
135 connector,
136 _phantom: PhantomData,
137 }
138 }
139
140 #[cfg(feature = "boring")]
141 #[cfg_attr(docsrs, doc(cfg(feature = "boring")))]
142 pub fn with_tls_proxy_support_using_boringssl(
148 self,
149 ) -> EasyHttpConnectorBuilder<
150 boring_client::TlsConnector<T, boring_client::ConnectorKindTunnel>,
151 ProxyTunnelStage,
152 > {
153 let connector = boring_client::TlsConnector::tunnel(self.connector, None);
154 EasyHttpConnectorBuilder {
155 connector,
156 _phantom: PhantomData,
157 }
158 }
159
160 #[cfg(feature = "boring")]
161 #[cfg_attr(docsrs, doc(cfg(feature = "boring")))]
162 pub fn with_tls_proxy_support_using_boringssl_config(
168 self,
169 config: std::sync::Arc<boring_client::TlsConnectorDataBuilder>,
170 ) -> EasyHttpConnectorBuilder<
171 boring_client::TlsConnector<T, boring_client::ConnectorKindTunnel>,
172 ProxyTunnelStage,
173 > {
174 let connector =
175 boring_client::TlsConnector::tunnel(self.connector, None).with_connector_data(config);
176 EasyHttpConnectorBuilder {
177 connector,
178 _phantom: PhantomData,
179 }
180 }
181
182 #[cfg(feature = "rustls")]
183 #[cfg_attr(docsrs, doc(cfg(feature = "rustls")))]
184 pub fn with_tls_proxy_support_using_rustls(
190 self,
191 ) -> EasyHttpConnectorBuilder<
192 rustls_client::TlsConnector<T, rustls_client::ConnectorKindTunnel>,
193 ProxyTunnelStage,
194 > {
195 let connector = rustls_client::TlsConnector::tunnel(self.connector, None);
196
197 EasyHttpConnectorBuilder {
198 connector,
199 _phantom: PhantomData,
200 }
201 }
202
203 #[cfg(feature = "rustls")]
204 #[cfg_attr(docsrs, doc(cfg(feature = "rustls")))]
205 pub fn with_tls_proxy_support_using_rustls_config(
211 self,
212 config: rustls_client::TlsConnectorData,
213 ) -> EasyHttpConnectorBuilder<
214 rustls_client::TlsConnector<T, rustls_client::ConnectorKindTunnel>,
215 ProxyTunnelStage,
216 > {
217 let connector =
218 rustls_client::TlsConnector::tunnel(self.connector, None).with_connector_data(config);
219
220 EasyHttpConnectorBuilder {
221 connector,
222 _phantom: PhantomData,
223 }
224 }
225
226 pub fn without_tls_proxy_support(self) -> EasyHttpConnectorBuilder<T, ProxyTunnelStage> {
232 EasyHttpConnectorBuilder {
233 connector: self.connector,
234 _phantom: PhantomData,
235 }
236 }
237}
238
239impl<T> EasyHttpConnectorBuilder<T, ProxyTunnelStage> {
240 pub fn with_custom_proxy_connector<L>(
242 self,
243 connector_layer: L,
244 ) -> EasyHttpConnectorBuilder<L::Service, ProxyStage>
245 where
246 L: Layer<T>,
247 {
248 let connector = connector_layer.into_layer(self.connector);
249 EasyHttpConnectorBuilder {
250 connector,
251 _phantom: PhantomData,
252 }
253 }
254
255 #[cfg(feature = "socks5")]
256 #[cfg_attr(docsrs, doc(cfg(feature = "socks5")))]
257 pub fn with_proxy_support(
265 self,
266 ) -> EasyHttpConnectorBuilder<ProxyConnector<std::sync::Arc<T>>, ProxyStage> {
267 use rama_http_backend::client::proxy::layer::HttpProxyConnectorLayer;
268 use rama_socks5::Socks5ProxyConnectorLayer;
269
270 let connector = ProxyConnector::optional(
271 self.connector,
272 Socks5ProxyConnectorLayer::required(),
273 HttpProxyConnectorLayer::required(),
274 );
275
276 EasyHttpConnectorBuilder {
277 connector,
278 _phantom: PhantomData,
279 }
280 }
281
282 #[cfg(not(feature = "socks5"))]
283 pub fn with_proxy_support(self) -> EasyHttpConnectorBuilder<HttpProxyConnector<T>, ProxyStage> {
293 self.with_http_proxy_support()
294 }
295
296 pub fn with_http_proxy_support(
304 self,
305 ) -> EasyHttpConnectorBuilder<HttpProxyConnector<T>, ProxyStage> {
306 let connector = HttpProxyConnector::optional(self.connector);
307
308 EasyHttpConnectorBuilder {
309 connector,
310 _phantom: PhantomData,
311 }
312 }
313
314 #[cfg(feature = "socks5")]
315 #[cfg_attr(docsrs, doc(cfg(feature = "socks5")))]
316 pub fn with_socks5_proxy_support(
320 self,
321 ) -> EasyHttpConnectorBuilder<Socks5ProxyConnector<T>, ProxyStage> {
322 let connector = Socks5ProxyConnector::optional(self.connector);
323
324 EasyHttpConnectorBuilder {
325 connector,
326 _phantom: PhantomData,
327 }
328 }
329
330 pub fn without_proxy_support(self) -> EasyHttpConnectorBuilder<T, ProxyStage> {
332 EasyHttpConnectorBuilder {
333 connector: self.connector,
334 _phantom: PhantomData,
335 }
336 }
337}
338
339impl<T> EasyHttpConnectorBuilder<T, ProxyStage> {
340 #[cfg(any(feature = "rustls", feature = "boring"))]
341 pub fn with_custom_tls_connector<L>(
348 self,
349 connector_layer: L,
350 ) -> EasyHttpConnectorBuilder<L::Service, TlsStage>
351 where
352 L: Layer<T>,
353 {
354 let connector = connector_layer.into_layer(self.connector);
355
356 EasyHttpConnectorBuilder {
357 connector,
358 _phantom: PhantomData,
359 }
360 }
361
362 #[cfg(feature = "boring")]
363 #[cfg_attr(docsrs, doc(cfg(feature = "boring")))]
364 pub fn with_tls_support_using_boringssl(
370 self,
371 config: Option<std::sync::Arc<boring_client::TlsConnectorDataBuilder>>,
372 ) -> EasyHttpConnectorBuilder<RequestVersionAdapter<boring_client::TlsConnector<T>>, TlsStage>
373 {
374 let connector =
375 boring_client::TlsConnector::auto(self.connector).maybe_with_connector_data(config);
376 let connector = RequestVersionAdapter::new(connector);
377
378 EasyHttpConnectorBuilder {
379 connector,
380 _phantom: PhantomData,
381 }
382 }
383
384 #[cfg(feature = "boring")]
385 #[cfg_attr(docsrs, doc(cfg(feature = "boring")))]
386 pub fn with_tls_support_using_boringssl_and_default_http_version(
395 self,
396 config: Option<std::sync::Arc<boring_client::TlsConnectorDataBuilder>>,
397 default_http_version: rama_http::Version,
398 ) -> EasyHttpConnectorBuilder<RequestVersionAdapter<boring_client::TlsConnector<T>>, TlsStage>
399 {
400 let connector =
401 boring_client::TlsConnector::auto(self.connector).maybe_with_connector_data(config);
402 let connector =
403 RequestVersionAdapter::new(connector).with_default_version(default_http_version);
404
405 EasyHttpConnectorBuilder {
406 connector,
407 _phantom: PhantomData,
408 }
409 }
410
411 #[cfg(feature = "rustls")]
412 #[cfg_attr(docsrs, doc(cfg(feature = "rustls")))]
413 pub fn with_tls_support_using_rustls(
419 self,
420 config: Option<rustls_client::TlsConnectorData>,
421 ) -> EasyHttpConnectorBuilder<RequestVersionAdapter<rustls_client::TlsConnector<T>>, TlsStage>
422 {
423 let connector =
424 rustls_client::TlsConnector::auto(self.connector).maybe_with_connector_data(config);
425 let connector = RequestVersionAdapter::new(connector);
426
427 EasyHttpConnectorBuilder {
428 connector,
429 _phantom: PhantomData,
430 }
431 }
432
433 #[cfg(feature = "rustls")]
434 #[cfg_attr(docsrs, doc(cfg(feature = "rustls")))]
435 pub fn with_tls_support_using_rustls_and_default_http_version(
444 self,
445 config: Option<rustls_client::TlsConnectorData>,
446 default_http_version: rama_http::Version,
447 ) -> EasyHttpConnectorBuilder<RequestVersionAdapter<rustls_client::TlsConnector<T>>, TlsStage>
448 {
449 let connector =
450 rustls_client::TlsConnector::auto(self.connector).maybe_with_connector_data(config);
451 let connector =
452 RequestVersionAdapter::new(connector).with_default_version(default_http_version);
453
454 EasyHttpConnectorBuilder {
455 connector,
456 _phantom: PhantomData,
457 }
458 }
459
460 pub fn without_tls_support(self) -> EasyHttpConnectorBuilder<T, TlsStage> {
462 EasyHttpConnectorBuilder {
463 connector: self.connector,
464 _phantom: PhantomData,
465 }
466 }
467}
468
469impl<T> EasyHttpConnectorBuilder<T, TlsStage> {
470 pub fn with_default_http_connector<Body>(
472 self,
473 exec: Executor,
474 ) -> EasyHttpConnectorBuilder<HttpConnector<T, Body>, HttpStage> {
475 let connector = HttpConnector::new(self.connector, exec);
476
477 EasyHttpConnectorBuilder {
478 connector,
479 _phantom: PhantomData,
480 }
481 }
482
483 pub fn with_custom_http_connector<L>(
485 self,
486 connector_layer: L,
487 ) -> EasyHttpConnectorBuilder<L::Service, HttpStage>
488 where
489 L: Layer<T>,
490 {
491 let connector = connector_layer.into_layer(self.connector);
492
493 EasyHttpConnectorBuilder {
494 connector,
495 _phantom: PhantomData,
496 }
497 }
498}
499
500type DefaultConnectionPoolBuilder<T, C> = EasyHttpConnectorBuilder<
501 RequestVersionAdapter<
502 PooledConnector<T, LruDropPool<C, BasicHttpConId>, BasicHttpConnIdentifier>,
503 >,
504 PoolStage,
505>;
506
507impl<T> EasyHttpConnectorBuilder<T, HttpStage> {
508 pub fn try_with_connection_pool<C: ExtensionsMut>(
524 self,
525 config: HttpPooledConnectorConfig,
526 ) -> Result<DefaultConnectionPoolBuilder<T, C>, OpaqueError> {
527 let connector = config.build_connector(self.connector)?;
528 let connector = RequestVersionAdapter::new(connector);
529
530 Ok(EasyHttpConnectorBuilder {
531 connector,
532 _phantom: PhantomData,
533 })
534 }
535
536 #[inline(always)]
537 pub fn try_with_default_connection_pool<C: ExtensionsMut>(
539 self,
540 ) -> Result<DefaultConnectionPoolBuilder<T, C>, OpaqueError> {
541 self.try_with_connection_pool(Default::default())
542 }
543
544 pub fn with_custom_connection_pool<P, R>(
555 self,
556 pool: P,
557 req_to_conn_id: R,
558 wait_for_pool_timeout: Option<Duration>,
559 ) -> EasyHttpConnectorBuilder<PooledConnector<T, P, R>, PoolStage> {
560 let connector = PooledConnector::new(self.connector, pool, req_to_conn_id)
561 .maybe_with_wait_for_pool_timeout(wait_for_pool_timeout);
562
563 EasyHttpConnectorBuilder {
564 connector,
565 _phantom: PhantomData,
566 }
567 }
568}
569
570impl<T, S> EasyHttpConnectorBuilder<T, S> {
571 pub fn build_client<Body, ModifiedBody, ConnResponse>(
573 self,
574 ) -> super::EasyHttpWebClient<Body, T::Output, ()>
575 where
576 Body: StreamingBody<Data: Send + 'static, Error: Into<BoxError>> + Unpin + Send + 'static,
577 ModifiedBody:
578 StreamingBody<Data: Send + 'static, Error: Into<BoxError>> + Unpin + Send + 'static,
579 T: Service<
580 Request<Body>,
581 Output = EstablishedClientConnection<ConnResponse, Request<ModifiedBody>>,
582 Error = BoxError,
583 >,
584 ConnResponse: ExtensionsMut,
585 {
586 super::EasyHttpWebClient::new(self.connector.boxed())
587 }
588
589 pub fn build_connector(self) -> T {
591 self.connector
592 }
593}