1use super::{HttpConnector, http_inspector::HttpVersionAdapter};
2use crate::{
3 Layer, Service,
4 dns::DnsResolver,
5 error::{BoxError, OpaqueError},
6 extensions::ExtensionsMut,
7 http::{Request, StreamingBody, client::proxy::layer::HttpProxyConnector},
8 net::client::{
9 EstablishedClientConnection,
10 pool::{
11 LruDropPool, PooledConnector,
12 http::{BasicHttpConId, BasicHttpConnIdentifier, HttpPooledConnectorConfig},
13 },
14 },
15 tcp::client::service::TcpConnector,
16};
17use std::{marker::PhantomData, time::Duration};
18
19#[cfg(feature = "boring")]
20use crate::tls::boring::client as boring_client;
21
22#[cfg(feature = "rustls")]
23use crate::tls::rustls::client as rustls_client;
24
25#[cfg(any(feature = "rustls", feature = "boring"))]
26use crate::http::client::http_inspector::HttpsAlpnModifier;
27
28#[cfg(feature = "socks5")]
29use crate::{http::client::proxy_connector::ProxyConnector, proxy::socks5::Socks5ProxyConnector};
30
31#[derive(Default)]
33pub struct EasyHttpWebClientBuilder<C = (), S = ()> {
34 connector: C,
35 _phantom: PhantomData<S>,
36}
37
38#[non_exhaustive]
39#[derive(Debug)]
40pub struct TransportStage;
41#[non_exhaustive]
42#[derive(Debug)]
43pub struct ProxyTunnelStage;
44#[non_exhaustive]
45#[derive(Debug)]
46pub struct ProxyStage;
47#[non_exhaustive]
48#[derive(Debug)]
49pub struct HttpStage;
50#[non_exhaustive]
51#[derive(Debug)]
52pub struct PoolStage;
53
54impl EasyHttpWebClientBuilder {
55 #[must_use]
56 pub fn new() -> Self {
57 Self::default()
58 }
59
60 #[must_use]
61 pub fn with_default_transport_connector(
62 self,
63 ) -> EasyHttpWebClientBuilder<TcpConnector, TransportStage> {
64 let connector = TcpConnector::default();
65 EasyHttpWebClientBuilder {
66 connector,
67 _phantom: PhantomData,
68 }
69 }
70
71 pub fn with_custom_transport_connector<C>(
73 self,
74 connector: C,
75 ) -> EasyHttpWebClientBuilder<C, TransportStage> {
76 EasyHttpWebClientBuilder {
77 connector,
78 _phantom: PhantomData,
79 }
80 }
81}
82
83impl EasyHttpWebClientBuilder<TcpConnector, TransportStage> {
84 pub fn with_dns_resolver<T: DnsResolver + Clone>(
86 self,
87 resolver: T,
88 ) -> EasyHttpWebClientBuilder<TcpConnector<T>, TransportStage> {
89 let connector = self.connector.with_dns(resolver);
90 EasyHttpWebClientBuilder {
91 connector,
92 _phantom: PhantomData,
93 }
94 }
95}
96
97impl<T> EasyHttpWebClientBuilder<T, TransportStage> {
98 #[cfg(any(feature = "rustls", feature = "boring"))]
99 pub fn with_custom_tls_proxy_connector<L>(
101 self,
102 connector_layer: L,
103 ) -> EasyHttpWebClientBuilder<L::Service, ProxyTunnelStage>
104 where
105 L: Layer<T>,
106 {
107 let connector = connector_layer.into_layer(self.connector);
108 EasyHttpWebClientBuilder {
109 connector,
110 _phantom: PhantomData,
111 }
112 }
113
114 #[cfg(feature = "boring")]
115 pub fn with_tls_proxy_support_using_boringssl(
121 self,
122 ) -> EasyHttpWebClientBuilder<
123 boring_client::TlsConnector<T, boring_client::ConnectorKindTunnel>,
124 ProxyTunnelStage,
125 > {
126 let connector = boring_client::TlsConnector::tunnel(self.connector, None);
127 EasyHttpWebClientBuilder {
128 connector,
129 _phantom: PhantomData,
130 }
131 }
132
133 #[cfg(feature = "boring")]
134 pub fn with_tls_proxy_support_using_boringssl_config(
140 self,
141 config: std::sync::Arc<boring_client::TlsConnectorDataBuilder>,
142 ) -> EasyHttpWebClientBuilder<
143 boring_client::TlsConnector<T, boring_client::ConnectorKindTunnel>,
144 ProxyTunnelStage,
145 > {
146 let connector =
147 boring_client::TlsConnector::tunnel(self.connector, None).with_connector_data(config);
148 EasyHttpWebClientBuilder {
149 connector,
150 _phantom: PhantomData,
151 }
152 }
153
154 #[cfg(feature = "rustls")]
155 pub fn with_tls_proxy_support_using_rustls(
161 self,
162 ) -> EasyHttpWebClientBuilder<
163 rustls_client::TlsConnector<T, rustls_client::ConnectorKindTunnel>,
164 ProxyTunnelStage,
165 > {
166 let connector = rustls_client::TlsConnector::tunnel(self.connector, None);
167
168 EasyHttpWebClientBuilder {
169 connector,
170 _phantom: PhantomData,
171 }
172 }
173
174 #[cfg(feature = "rustls")]
175 pub fn with_tls_proxy_support_using_rustls_config(
181 self,
182 config: rustls_client::TlsConnectorData,
183 ) -> EasyHttpWebClientBuilder<
184 rustls_client::TlsConnector<T, rustls_client::ConnectorKindTunnel>,
185 ProxyTunnelStage,
186 > {
187 let connector =
188 rustls_client::TlsConnector::tunnel(self.connector, None).with_connector_data(config);
189
190 EasyHttpWebClientBuilder {
191 connector,
192 _phantom: PhantomData,
193 }
194 }
195
196 pub fn without_tls_proxy_support(self) -> EasyHttpWebClientBuilder<T, ProxyTunnelStage> {
202 EasyHttpWebClientBuilder {
203 connector: self.connector,
204 _phantom: PhantomData,
205 }
206 }
207}
208
209impl<T> EasyHttpWebClientBuilder<T, ProxyTunnelStage> {
210 pub fn with_custom_proxy_connector<L>(
212 self,
213 connector_layer: L,
214 ) -> EasyHttpWebClientBuilder<L::Service, ProxyStage>
215 where
216 L: Layer<T>,
217 {
218 let connector = connector_layer.into_layer(self.connector);
219 EasyHttpWebClientBuilder {
220 connector,
221 _phantom: PhantomData,
222 }
223 }
224
225 #[cfg(feature = "socks5")]
226 pub fn with_proxy_support(
234 self,
235 ) -> EasyHttpWebClientBuilder<ProxyConnector<std::sync::Arc<T>>, ProxyStage> {
236 use rama_http_backend::client::proxy::layer::HttpProxyConnectorLayer;
237 use rama_socks5::Socks5ProxyConnectorLayer;
238
239 let connector = ProxyConnector::optional(
240 self.connector,
241 Socks5ProxyConnectorLayer::required(),
242 HttpProxyConnectorLayer::required(),
243 );
244
245 EasyHttpWebClientBuilder {
246 connector,
247 _phantom: PhantomData,
248 }
249 }
250
251 #[cfg(not(feature = "socks5"))]
252 pub fn with_proxy_support(self) -> EasyHttpWebClientBuilder<HttpProxyConnector<T>, ProxyStage> {
262 self.with_http_proxy_support()
263 }
264
265 pub fn with_http_proxy_support(
273 self,
274 ) -> EasyHttpWebClientBuilder<HttpProxyConnector<T>, ProxyStage> {
275 let connector = HttpProxyConnector::optional(self.connector);
276
277 EasyHttpWebClientBuilder {
278 connector,
279 _phantom: PhantomData,
280 }
281 }
282
283 #[cfg(feature = "socks5")]
284 pub fn with_socks5_proxy_support(
288 self,
289 ) -> EasyHttpWebClientBuilder<Socks5ProxyConnector<T>, ProxyStage> {
290 let connector = Socks5ProxyConnector::optional(self.connector);
291
292 EasyHttpWebClientBuilder {
293 connector,
294 _phantom: PhantomData,
295 }
296 }
297
298 pub fn without_proxy_support(self) -> EasyHttpWebClientBuilder<T, ProxyStage> {
300 EasyHttpWebClientBuilder {
301 connector: self.connector,
302 _phantom: PhantomData,
303 }
304 }
305}
306
307impl<T> EasyHttpWebClientBuilder<T, ProxyStage> {
308 #[cfg(any(feature = "rustls", feature = "boring"))]
309 pub fn with_custom_tls_connector<L>(
323 self,
324 connector_layer: L,
325 ) -> EasyHttpWebClientBuilder<
326 HttpConnector<L::Service, (HttpsAlpnModifier, HttpVersionAdapter)>,
327 HttpStage,
328 >
329 where
330 L: Layer<T>,
331 {
332 let connector = connector_layer.into_layer(self.connector);
333
334 let connector = HttpConnector::new(connector)
335 .with_jit_req_inspector((HttpsAlpnModifier::default(), HttpVersionAdapter::default()));
336
337 EasyHttpWebClientBuilder {
338 connector,
339 _phantom: PhantomData,
340 }
341 }
342
343 #[cfg(feature = "boring")]
344 pub fn with_tls_support_using_boringssl(
358 self,
359 config: Option<std::sync::Arc<boring_client::TlsConnectorDataBuilder>>,
360 ) -> EasyHttpWebClientBuilder<
361 HttpConnector<boring_client::TlsConnector<T>, (HttpsAlpnModifier, HttpVersionAdapter)>,
362 HttpStage,
363 > {
364 let connector =
365 boring_client::TlsConnector::auto(self.connector).maybe_with_connector_data(config);
366
367 let connector = HttpConnector::new(connector)
368 .with_jit_req_inspector((HttpsAlpnModifier::default(), HttpVersionAdapter::default()));
369
370 EasyHttpWebClientBuilder {
371 connector,
372 _phantom: PhantomData,
373 }
374 }
375
376 #[cfg(feature = "rustls")]
377 pub fn with_tls_support_using_rustls(
391 self,
392 config: Option<rustls_client::TlsConnectorData>,
393 ) -> EasyHttpWebClientBuilder<
394 HttpConnector<rustls_client::TlsConnector<T>, (HttpsAlpnModifier, HttpVersionAdapter)>,
395 HttpStage,
396 > {
397 let connector =
398 rustls_client::TlsConnector::auto(self.connector).maybe_with_connector_data(config);
399
400 let connector = HttpConnector::new(connector)
401 .with_jit_req_inspector((HttpsAlpnModifier::default(), HttpVersionAdapter::default()));
402
403 EasyHttpWebClientBuilder {
404 connector,
405 _phantom: PhantomData,
406 }
407 }
408
409 pub fn without_tls_support(
420 self,
421 ) -> EasyHttpWebClientBuilder<HttpConnector<T, HttpVersionAdapter>, HttpStage> {
422 let connector = HttpConnector::new(self.connector)
423 .with_jit_req_inspector(HttpVersionAdapter::default());
424
425 EasyHttpWebClientBuilder {
426 connector,
427 _phantom: PhantomData,
428 }
429 }
430}
431
432impl<T, I1, I2> EasyHttpWebClientBuilder<HttpConnector<T, I1, I2>, HttpStage> {
433 pub fn with_advanced_jit_req_inspector<I>(
438 self,
439 http_req_inspector: I,
440 ) -> EasyHttpWebClientBuilder<HttpConnector<T, I, I2>, HttpStage> {
441 EasyHttpWebClientBuilder {
442 connector: self.connector.with_jit_req_inspector(http_req_inspector),
443 _phantom: PhantomData,
444 }
445 }
446
447 pub fn without_jit_req_inspector(
452 self,
453 ) -> EasyHttpWebClientBuilder<HttpConnector<T, (), I2>, HttpStage> {
454 EasyHttpWebClientBuilder {
455 connector: self.connector.with_jit_req_inspector(()),
456 _phantom: PhantomData,
457 }
458 }
459
460 #[cfg(any(feature = "rustls", feature = "boring"))]
461 pub fn with_jit_req_inspector<I>(
475 self,
476 http_req_inspector: I,
477 ) -> EasyHttpWebClientBuilder<
478 HttpConnector<T, (HttpsAlpnModifier, HttpVersionAdapter, I), I2>,
479 HttpStage,
480 > {
481 EasyHttpWebClientBuilder {
482 connector: self.connector.with_jit_req_inspector((
483 HttpsAlpnModifier::default(),
484 HttpVersionAdapter::default(),
485 http_req_inspector,
486 )),
487 _phantom: PhantomData,
488 }
489 }
490
491 #[cfg(not(any(feature = "rustls", feature = "boring")))]
492 pub fn with_jit_req_inspector<I>(
503 self,
504 http_req_inspector: I,
505 ) -> EasyHttpWebClientBuilder<HttpConnector<T, (HttpVersionAdapter, I), I2>, HttpStage> {
506 EasyHttpWebClientBuilder {
507 connector: self
508 .connector
509 .with_jit_req_inspector((HttpVersionAdapter::default(), http_req_inspector)),
510 _phantom: PhantomData,
511 }
512 }
513
514 pub fn with_svc_req_inspector<I>(
516 self,
517 http_req_inspector: I,
518 ) -> EasyHttpWebClientBuilder<HttpConnector<T, I1, I>, HttpStage> {
519 EasyHttpWebClientBuilder {
520 connector: self.connector.with_svc_req_inspector(http_req_inspector),
521 _phantom: PhantomData,
522 }
523 }
524}
525
526type DefaultConnectionPoolBuilder<T, C> = EasyHttpWebClientBuilder<
527 PooledConnector<T, LruDropPool<C, BasicHttpConId>, BasicHttpConnIdentifier>,
528 PoolStage,
529>;
530
531impl<T> EasyHttpWebClientBuilder<T, HttpStage> {
532 pub fn with_connection_pool<C>(
544 self,
545 config: HttpPooledConnectorConfig,
546 ) -> Result<DefaultConnectionPoolBuilder<T, C>, OpaqueError> {
547 let connector = config.build_connector(self.connector)?;
548
549 Ok(EasyHttpWebClientBuilder {
550 connector,
551 _phantom: PhantomData,
552 })
553 }
554
555 pub fn with_custom_connection_pool<P, R>(
562 self,
563 pool: P,
564 req_to_conn_id: R,
565 wait_for_pool_timeout: Option<Duration>,
566 ) -> EasyHttpWebClientBuilder<PooledConnector<T, P, R>, PoolStage> {
567 let connector = PooledConnector::new(self.connector, pool, req_to_conn_id)
568 .maybe_with_wait_for_pool_timeout(wait_for_pool_timeout);
569
570 EasyHttpWebClientBuilder {
571 connector,
572 _phantom: PhantomData,
573 }
574 }
575}
576
577impl<T, S> EasyHttpWebClientBuilder<T, S> {
578 pub fn build<Body, ModifiedBody, ConnResponse>(
580 self,
581 ) -> super::EasyHttpWebClient<Body, T::Response>
582 where
583 Body: StreamingBody<Data: Send + 'static, Error: Into<BoxError>> + Unpin + Send + 'static,
584 ModifiedBody:
585 StreamingBody<Data: Send + 'static, Error: Into<BoxError>> + Unpin + Send + 'static,
586 T: Service<
587 Request<Body>,
588 Response = EstablishedClientConnection<ConnResponse, Request<ModifiedBody>>,
589 Error = BoxError,
590 >,
591 ConnResponse: ExtensionsMut,
592 {
593 super::EasyHttpWebClient::new(self.connector.boxed())
594 }
595}