1use http::{HeaderMap, HeaderValue, Uri};
8use hyper_util::client::legacy::connect::HttpConnector;
9use hyper_util::client::legacy::Client as HyperClient;
10use hyper_util::rt::TokioExecutor;
11use oxihttp_core::OxiHttpError;
12use std::sync::Arc;
13use std::time::Duration;
14
15use crate::middleware::ClientMiddleware;
16use crate::proxy::{ProxyConnector, ProxyKind};
17use crate::redirect::RedirectPolicy;
18use crate::resolver::BoxResolver;
19use crate::retry::RetryPolicy;
20
21#[cfg(feature = "socks")]
22use crate::proxy::Socks5Connector;
23
24#[cfg(feature = "tls")]
25use crate::connector::OxiHttpsConnector;
26#[cfg(feature = "tls")]
27use crate::tls;
28
29use super::Client;
31#[cfg(feature = "tls")]
32use super::TlsRebuildConfig;
33
34#[derive(Debug, Clone, Default)]
40pub struct Http2Settings {
41 pub initial_stream_window_size: Option<u32>,
43 pub initial_connection_window_size: Option<u32>,
45 pub adaptive_window: Option<bool>,
47 pub keep_alive_interval: Option<std::time::Duration>,
49 pub keep_alive_timeout: Option<std::time::Duration>,
51 pub max_frame_size: Option<u32>,
53 pub max_concurrent_reset_streams: Option<usize>,
55 pub max_send_buf_size: Option<usize>,
57}
58
59pub(crate) fn apply_http2_settings(
64 builder: &mut hyper_util::client::legacy::Builder,
65 settings: &Http2Settings,
66) {
67 if let Some(sz) = settings.initial_stream_window_size {
68 builder.http2_initial_stream_window_size(sz);
69 }
70 if let Some(sz) = settings.initial_connection_window_size {
71 builder.http2_initial_connection_window_size(sz);
72 }
73 if let Some(adaptive) = settings.adaptive_window {
74 builder.http2_adaptive_window(adaptive);
75 }
76 if let Some(interval) = settings.keep_alive_interval {
77 builder.http2_keep_alive_interval(interval);
78 }
79 if let Some(timeout) = settings.keep_alive_timeout {
80 builder.http2_keep_alive_timeout(timeout);
81 }
82 if let Some(sz) = settings.max_frame_size {
83 builder.http2_max_frame_size(sz);
84 }
85 if let Some(n) = settings.max_concurrent_reset_streams {
86 builder.http2_max_concurrent_reset_streams(n);
87 }
88 if let Some(sz) = settings.max_send_buf_size {
89 builder.http2_max_send_buf_size(sz);
90 }
91}
92
93pub struct ClientBuilder {
99 pub(super) pool_max_idle_per_host: Option<usize>,
100 pub(super) pool_idle_timeout: Option<Duration>,
101 pub(super) connect_timeout: Option<Duration>,
102 pub(super) read_timeout: Option<Duration>,
103 pub(super) redirect_policy: RedirectPolicy,
104 pub(super) retry_policy: Option<RetryPolicy>,
105 pub(super) default_headers: HeaderMap,
106 pub(super) user_agent: Option<String>,
107 pub(super) decompression: bool,
108 pub(super) middleware: Vec<Arc<dyn ClientMiddleware>>,
110 pub(super) proxy: Option<ProxyKind>,
112 pub(super) cookie_jar: Option<Arc<std::sync::Mutex<oxihttp_core::CookieJar>>>,
114 pub(super) http2_settings: Option<Http2Settings>,
116 pub(super) tcp_nodelay: Option<bool>,
118 pub(super) tcp_keepalive: Option<Duration>,
120 pub(super) resolver: Option<Arc<dyn crate::resolver::DnsResolver>>,
122 #[cfg(feature = "tls")]
124 pub(super) trusted_certs_der: Vec<Vec<u8>>,
125 #[cfg(feature = "tls")]
126 pub(super) alpn: Vec<String>,
127 #[cfg(feature = "tls")]
128 pub(super) accept_invalid_certs: bool,
129 #[cfg(feature = "tls")]
130 pub(super) use_webpki_roots: bool,
131 #[cfg(feature = "tls")]
133 pub(super) key_log_path: Option<std::path::PathBuf>,
134 #[cfg(feature = "tls")]
136 pub(super) early_data: bool,
137}
138
139impl ClientBuilder {
140 pub fn new() -> Self {
142 Self {
143 pool_max_idle_per_host: None,
144 pool_idle_timeout: None,
145 connect_timeout: None,
146 read_timeout: None,
147 redirect_policy: RedirectPolicy::default(),
148 retry_policy: None,
149 default_headers: HeaderMap::new(),
150 user_agent: None,
151 decompression: false,
152 middleware: Vec::new(),
153 proxy: None,
154 cookie_jar: None,
155 http2_settings: None,
156 tcp_nodelay: None,
157 tcp_keepalive: None,
158 resolver: None,
159 #[cfg(feature = "tls")]
160 trusted_certs_der: Vec::new(),
161 #[cfg(feature = "tls")]
162 alpn: Vec::new(),
163 #[cfg(feature = "tls")]
164 accept_invalid_certs: false,
165 #[cfg(feature = "tls")]
166 use_webpki_roots: false,
167 #[cfg(feature = "tls")]
168 key_log_path: None,
169 #[cfg(feature = "tls")]
170 early_data: false,
171 }
172 }
173
174 pub fn pool_max_idle_per_host(mut self, n: usize) -> Self {
176 self.pool_max_idle_per_host = Some(n);
177 self
178 }
179
180 pub fn pool_idle_timeout(mut self, duration: Duration) -> Self {
182 self.pool_idle_timeout = Some(duration);
183 self
184 }
185
186 pub fn connect_timeout(mut self, duration: Duration) -> Self {
188 self.connect_timeout = Some(duration);
189 self
190 }
191
192 pub fn read_timeout(mut self, duration: Duration) -> Self {
194 self.read_timeout = Some(duration);
195 self
196 }
197
198 pub fn redirect_policy(mut self, policy: RedirectPolicy) -> Self {
200 self.redirect_policy = policy;
201 self
202 }
203
204 pub fn retry_policy(mut self, policy: RetryPolicy) -> Self {
206 self.retry_policy = Some(policy);
207 self
208 }
209
210 pub fn default_headers(mut self, headers: HeaderMap) -> Self {
212 self.default_headers = headers;
213 self
214 }
215
216 pub fn user_agent(mut self, agent: impl Into<String>) -> Self {
218 self.user_agent = Some(agent.into());
219 self
220 }
221
222 pub fn with_decompression(mut self, enabled: bool) -> Self {
229 self.decompression = enabled;
230 self
231 }
232
233 pub fn with_middleware<M: ClientMiddleware + 'static>(mut self, m: M) -> Self {
254 self.middleware.push(Arc::new(m));
255 self
256 }
257
258 pub fn with_layer<M: ClientMiddleware + 'static>(self, m: M) -> Self {
264 self.with_middleware(m)
265 }
266
267 pub fn with_cookie_jar(mut self, jar: Arc<std::sync::Mutex<oxihttp_core::CookieJar>>) -> Self {
271 self.cookie_jar = Some(jar);
272 self
273 }
274
275 pub fn with_new_cookie_jar(mut self) -> Self {
277 self.cookie_jar = Some(Arc::new(std::sync::Mutex::new(
278 oxihttp_core::CookieJar::new(),
279 )));
280 self
281 }
282
283 pub fn with_http2_settings(mut self, settings: Http2Settings) -> Self {
287 self.http2_settings = Some(settings);
288 self
289 }
290
291 pub fn with_tcp_nodelay(mut self, nodelay: bool) -> Self {
293 self.tcp_nodelay = Some(nodelay);
294 self
295 }
296
297 pub fn with_tcp_keepalive(mut self, duration: Duration) -> Self {
299 self.tcp_keepalive = Some(duration);
300 self
301 }
302
303 pub fn with_resolver<R: crate::resolver::DnsResolver>(mut self, r: R) -> Self {
310 self.resolver = Some(Arc::new(r));
311 self
312 }
313
314 pub fn with_http_proxy(mut self, uri: Uri) -> Self {
321 self.proxy = Some(ProxyKind::HttpConnect(uri));
322 self
323 }
324
325 #[cfg(feature = "socks")]
330 pub fn with_socks5_proxy(mut self, uri: Uri) -> Self {
331 self.proxy = Some(ProxyKind::Socks5(uri));
332 self
333 }
334
335 pub fn build_proxy(self) -> Result<Client<ProxyConnector>, OxiHttpError> {
339 let proxy_uri = match self.proxy.as_ref() {
340 Some(ProxyKind::HttpConnect(u)) => u.clone(),
341 #[cfg(feature = "socks")]
342 Some(ProxyKind::Socks5(_)) => {
343 return Err(OxiHttpError::ConnectionPool(
344 "SOCKS5 proxy configured; use build_socks5_proxy() instead".into(),
345 ))
346 }
347 None => {
348 return Err(OxiHttpError::ConnectionPool(
349 "no proxy configured; call with_http_proxy() first".into(),
350 ))
351 }
352 };
353 let connector = ProxyConnector::new(proxy_uri, self.connect_timeout);
354 let mut builder = HyperClient::builder(TokioExecutor::new());
355 if let Some(n) = self.pool_max_idle_per_host {
356 builder.pool_max_idle_per_host(n);
357 }
358 if let Some(dur) = self.pool_idle_timeout {
359 builder.pool_idle_timeout(dur);
360 }
361 if let Some(ref h2) = self.http2_settings {
362 apply_http2_settings(&mut builder, h2);
363 }
364 let inner = builder.build(connector);
365 let mut default_headers = self.default_headers;
366 if let Some(agent) = &self.user_agent {
367 if let Ok(val) = HeaderValue::from_str(agent) {
368 default_headers.insert(http::header::USER_AGENT, val);
369 }
370 }
371 Ok(Client {
372 inner,
373 redirect_policy: self.redirect_policy,
374 retry_policy: self.retry_policy,
375 default_headers,
376 connect_timeout: self.connect_timeout,
377 read_timeout: self.read_timeout,
378 decompression: self.decompression,
379 middleware: self.middleware,
380 cookie_jar: self.cookie_jar.clone(),
381 #[cfg(feature = "tls")]
382 tls_rebuild: None,
383 })
384 }
385
386 #[cfg(feature = "socks")]
390 pub fn build_socks5_proxy(self) -> Result<Client<Socks5Connector>, OxiHttpError> {
391 let proxy_uri = match self.proxy.as_ref() {
392 Some(ProxyKind::Socks5(u)) => u.clone(),
393 Some(ProxyKind::HttpConnect(_)) => {
394 return Err(OxiHttpError::ConnectionPool(
395 "HTTP CONNECT proxy configured; use build_proxy() instead".into(),
396 ))
397 }
398 None => {
399 return Err(OxiHttpError::ConnectionPool(
400 "no proxy configured; call with_socks5_proxy() first".into(),
401 ))
402 }
403 };
404 let connector = Socks5Connector::new(proxy_uri, self.connect_timeout);
405 let mut builder = HyperClient::builder(TokioExecutor::new());
406 if let Some(n) = self.pool_max_idle_per_host {
407 builder.pool_max_idle_per_host(n);
408 }
409 if let Some(dur) = self.pool_idle_timeout {
410 builder.pool_idle_timeout(dur);
411 }
412 if let Some(ref h2) = self.http2_settings {
413 apply_http2_settings(&mut builder, h2);
414 }
415 let inner = builder.build(connector);
416 let mut default_headers = self.default_headers;
417 if let Some(agent) = &self.user_agent {
418 if let Ok(val) = HeaderValue::from_str(agent) {
419 default_headers.insert(http::header::USER_AGENT, val);
420 }
421 }
422 Ok(Client {
423 inner,
424 redirect_policy: self.redirect_policy,
425 retry_policy: self.retry_policy,
426 default_headers,
427 connect_timeout: self.connect_timeout,
428 read_timeout: self.read_timeout,
429 decompression: self.decompression,
430 middleware: self.middleware,
431 cookie_jar: self.cookie_jar.clone(),
432 #[cfg(feature = "tls")]
433 tls_rebuild: None,
434 })
435 }
436
437 #[cfg(feature = "tls")]
443 pub fn build_proxy_https(
444 self,
445 ) -> Result<Client<OxiHttpsConnector<ProxyConnector>>, OxiHttpError> {
446 let proxy_uri = match self.proxy.as_ref() {
447 Some(ProxyKind::HttpConnect(u)) => u.clone(),
448 #[cfg(feature = "socks")]
449 Some(ProxyKind::Socks5(_)) => {
450 return Err(OxiHttpError::ConnectionPool(
451 "SOCKS5 proxy configured; use build_socks5_proxy_https() instead".into(),
452 ))
453 }
454 None => {
455 return Err(OxiHttpError::ConnectionPool(
456 "no proxy configured; call with_http_proxy() first".into(),
457 ))
458 }
459 };
460
461 let tls_connector = tls::build_tls_connector(
462 &self.trusted_certs_der,
463 &self.alpn,
464 self.accept_invalid_certs,
465 self.use_webpki_roots,
466 self.key_log_path.clone(),
467 self.early_data,
468 )?;
469
470 let http_connector = ProxyConnector::new(proxy_uri, self.connect_timeout);
471 let https_connector = OxiHttpsConnector::new(http_connector, tls_connector);
472
473 let mut builder = HyperClient::builder(TokioExecutor::new());
474 if let Some(n) = self.pool_max_idle_per_host {
475 builder.pool_max_idle_per_host(n);
476 }
477 if let Some(dur) = self.pool_idle_timeout {
478 builder.pool_idle_timeout(dur);
479 }
480 if let Some(ref h2) = self.http2_settings {
481 apply_http2_settings(&mut builder, h2);
482 }
483 let inner = builder.build(https_connector);
484 let mut default_headers = self.default_headers;
485 if let Some(agent) = &self.user_agent {
486 if let Ok(val) = HeaderValue::from_str(agent) {
487 default_headers.insert(http::header::USER_AGENT, val);
488 }
489 }
490 Ok(Client {
491 inner,
492 redirect_policy: self.redirect_policy,
493 retry_policy: self.retry_policy,
494 default_headers,
495 connect_timeout: self.connect_timeout,
496 read_timeout: self.read_timeout,
497 decompression: self.decompression,
498 middleware: self.middleware,
499 cookie_jar: self.cookie_jar.clone(),
500 #[cfg(feature = "tls")]
501 tls_rebuild: None,
502 })
503 }
504
505 #[cfg(all(feature = "tls", feature = "socks"))]
511 pub fn build_socks5_proxy_https(
512 self,
513 ) -> Result<Client<OxiHttpsConnector<Socks5Connector>>, OxiHttpError> {
514 let proxy_uri = match self.proxy.as_ref() {
515 Some(ProxyKind::Socks5(u)) => u.clone(),
516 Some(ProxyKind::HttpConnect(_)) => {
517 return Err(OxiHttpError::ConnectionPool(
518 "HTTP CONNECT proxy configured; use build_proxy_https() instead".into(),
519 ))
520 }
521 None => {
522 return Err(OxiHttpError::ConnectionPool(
523 "no proxy configured; call with_socks5_proxy() first".into(),
524 ))
525 }
526 };
527
528 let tls_connector = tls::build_tls_connector(
529 &self.trusted_certs_der,
530 &self.alpn,
531 self.accept_invalid_certs,
532 self.use_webpki_roots,
533 self.key_log_path.clone(),
534 self.early_data,
535 )?;
536
537 let socks_connector = Socks5Connector::new(proxy_uri, self.connect_timeout);
538 let https_connector = OxiHttpsConnector::new(socks_connector, tls_connector);
539
540 let mut builder = HyperClient::builder(TokioExecutor::new());
541 if let Some(n) = self.pool_max_idle_per_host {
542 builder.pool_max_idle_per_host(n);
543 }
544 if let Some(dur) = self.pool_idle_timeout {
545 builder.pool_idle_timeout(dur);
546 }
547 if let Some(ref h2) = self.http2_settings {
548 apply_http2_settings(&mut builder, h2);
549 }
550 let inner = builder.build(https_connector);
551 let mut default_headers = self.default_headers;
552 if let Some(agent) = &self.user_agent {
553 if let Ok(val) = HeaderValue::from_str(agent) {
554 default_headers.insert(http::header::USER_AGENT, val);
555 }
556 }
557 Ok(Client {
558 inner,
559 redirect_policy: self.redirect_policy,
560 retry_policy: self.retry_policy,
561 default_headers,
562 connect_timeout: self.connect_timeout,
563 read_timeout: self.read_timeout,
564 decompression: self.decompression,
565 middleware: self.middleware,
566 cookie_jar: self.cookie_jar.clone(),
567 #[cfg(feature = "tls")]
568 tls_rebuild: None,
569 })
570 }
571
572 #[cfg(feature = "tls")]
579 pub fn with_tls(mut self) -> Self {
580 self.use_webpki_roots = true;
581 self
582 }
583
584 #[cfg(feature = "tls")]
586 pub fn with_webpki_roots(mut self) -> Self {
587 self.use_webpki_roots = true;
588 self
589 }
590
591 #[cfg(feature = "tls")]
595 pub fn with_trusted_cert_der(mut self, der: Vec<u8>) -> Self {
596 self.trusted_certs_der.push(der);
597 self
598 }
599
600 #[cfg(feature = "tls")]
602 pub fn with_alpn(mut self, protocols: &[&str]) -> Self {
603 self.alpn = protocols.iter().map(|s| s.to_string()).collect();
604 self
605 }
606
607 #[cfg(feature = "tls")]
611 pub fn with_danger_accept_invalid_certs(mut self) -> Self {
612 self.accept_invalid_certs = true;
613 self
614 }
615
616 #[cfg(feature = "tls")]
622 pub fn with_key_log_file(mut self, path: std::path::PathBuf) -> Self {
623 self.key_log_path = Some(path);
624 self
625 }
626
627 #[cfg(feature = "tls")]
637 pub fn with_early_data(mut self) -> Self {
638 self.early_data = true;
639 self
640 }
641
642 pub fn build(self) -> Result<Client, OxiHttpError> {
646 let mut builder = HyperClient::builder(TokioExecutor::new());
647
648 if let Some(n) = self.pool_max_idle_per_host {
649 builder.pool_max_idle_per_host(n);
650 }
651 if let Some(dur) = self.pool_idle_timeout {
652 builder.pool_idle_timeout(dur);
653 }
654 if let Some(ref h2) = self.http2_settings {
655 apply_http2_settings(&mut builder, h2);
656 }
657
658 let mut http = HttpConnector::new();
660 http.enforce_http(false);
661 if let Some(dur) = self.connect_timeout {
662 http.set_connect_timeout(Some(dur));
663 }
664 if let Some(nodelay) = self.tcp_nodelay {
665 http.set_nodelay(nodelay);
666 }
667 if let Some(ka) = self.tcp_keepalive {
668 http.set_keepalive(Some(ka));
669 }
670
671 let inner = builder.build(http);
672
673 let mut default_headers = self.default_headers;
674 if let Some(agent) = &self.user_agent {
675 if let Ok(val) = HeaderValue::from_str(agent) {
676 default_headers.insert(http::header::USER_AGENT, val);
677 }
678 }
679
680 Ok(Client {
681 inner,
682 redirect_policy: self.redirect_policy,
683 retry_policy: self.retry_policy,
684 default_headers,
685 connect_timeout: self.connect_timeout,
686 read_timeout: self.read_timeout,
687 decompression: self.decompression,
688 middleware: self.middleware,
689 cookie_jar: self.cookie_jar.clone(),
690 #[cfg(feature = "tls")]
691 tls_rebuild: None,
692 })
693 }
694
695 #[cfg(feature = "tls")]
701 pub fn build_https(self) -> Result<super::HttpsClient, OxiHttpError> {
702 let connector = tls::build_tls_connector(
703 &self.trusted_certs_der,
704 &self.alpn,
705 self.accept_invalid_certs,
706 self.use_webpki_roots,
707 self.key_log_path.clone(),
708 self.early_data,
709 )?;
710
711 let mut http = HttpConnector::new();
712 http.enforce_http(false);
717 if let Some(dur) = self.connect_timeout {
718 http.set_connect_timeout(Some(dur));
719 }
720 if let Some(nodelay) = self.tcp_nodelay {
721 http.set_nodelay(nodelay);
722 }
723 if let Some(ka) = self.tcp_keepalive {
724 http.set_keepalive(Some(ka));
725 }
726 let https_connector = OxiHttpsConnector::new(http, connector);
727
728 let mut builder = HyperClient::builder(TokioExecutor::new());
729
730 if let Some(n) = self.pool_max_idle_per_host {
731 builder.pool_max_idle_per_host(n);
732 }
733 if let Some(dur) = self.pool_idle_timeout {
734 builder.pool_idle_timeout(dur);
735 }
736 if let Some(ref h2) = self.http2_settings {
737 apply_http2_settings(&mut builder, h2);
738 }
739
740 let inner = builder.build(https_connector);
741
742 let mut default_headers = self.default_headers;
743 if let Some(agent) = &self.user_agent {
744 if let Ok(val) = HeaderValue::from_str(agent) {
745 default_headers.insert(http::header::USER_AGENT, val);
746 }
747 }
748
749 let tls_rebuild = Arc::new(TlsRebuildConfig {
750 trusted_certs_der: self.trusted_certs_der.clone(),
751 alpn: self.alpn.clone(),
752 accept_invalid_certs: self.accept_invalid_certs,
753 use_webpki_roots: self.use_webpki_roots,
754 key_log_path: self.key_log_path.clone(),
755 early_data: self.early_data,
756 connect_timeout: self.connect_timeout,
757 tcp_nodelay: self.tcp_nodelay,
758 tcp_keepalive: self.tcp_keepalive,
759 http2_settings: self.http2_settings.clone(),
760 pool_max_idle_per_host: self.pool_max_idle_per_host,
761 pool_idle_timeout: self.pool_idle_timeout,
762 });
763
764 Ok(Client {
765 inner,
766 redirect_policy: self.redirect_policy,
767 retry_policy: self.retry_policy,
768 default_headers,
769 connect_timeout: self.connect_timeout,
770 read_timeout: self.read_timeout,
771 decompression: self.decompression,
772 middleware: self.middleware,
773 cookie_jar: self.cookie_jar.clone(),
774 tls_rebuild: Some(tls_rebuild),
775 })
776 }
777
778 pub fn build_with_resolver(self) -> Result<super::ResolverClient, OxiHttpError> {
784 let resolver = self.resolver.ok_or_else(|| {
785 OxiHttpError::Dns("with_resolver must be called before build_with_resolver".into())
786 })?;
787 let mut http = HttpConnector::new_with_resolver(BoxResolver(resolver));
788 http.enforce_http(false);
789 if let Some(dur) = self.connect_timeout {
790 http.set_connect_timeout(Some(dur));
791 }
792 if let Some(nodelay) = self.tcp_nodelay {
793 http.set_nodelay(nodelay);
794 }
795 if let Some(ka) = self.tcp_keepalive {
796 http.set_keepalive(Some(ka));
797 }
798
799 let mut builder = HyperClient::builder(TokioExecutor::new());
800 if let Some(n) = self.pool_max_idle_per_host {
801 builder.pool_max_idle_per_host(n);
802 }
803 if let Some(d) = self.pool_idle_timeout {
804 builder.pool_idle_timeout(d);
805 }
806 if let Some(ref h2) = self.http2_settings {
807 apply_http2_settings(&mut builder, h2);
808 }
809
810 let mut default_headers = self.default_headers;
811 if let Some(agent) = &self.user_agent {
812 if let Ok(val) = HeaderValue::from_str(agent) {
813 default_headers.insert(http::header::USER_AGENT, val);
814 }
815 }
816
817 Ok(Client {
818 inner: builder.build(http),
819 connect_timeout: self.connect_timeout,
820 read_timeout: self.read_timeout,
821 redirect_policy: self.redirect_policy,
822 retry_policy: self.retry_policy,
823 default_headers,
824 decompression: self.decompression,
825 middleware: self.middleware,
826 cookie_jar: self.cookie_jar,
827 #[cfg(feature = "tls")]
828 tls_rebuild: None,
829 })
830 }
831
832 #[cfg(feature = "tls")]
837 pub fn build_https_with_resolver(self) -> Result<super::ResolverHttpsClient, OxiHttpError> {
838 let resolver = self.resolver.ok_or_else(|| {
839 OxiHttpError::Dns(
840 "with_resolver must be called before build_https_with_resolver".into(),
841 )
842 })?;
843
844 let tls_connector = tls::build_tls_connector(
845 &self.trusted_certs_der,
846 &self.alpn,
847 self.accept_invalid_certs,
848 self.use_webpki_roots,
849 self.key_log_path.clone(),
850 self.early_data,
851 )?;
852
853 let mut http = HttpConnector::new_with_resolver(BoxResolver(resolver));
854 http.enforce_http(false);
855 if let Some(dur) = self.connect_timeout {
856 http.set_connect_timeout(Some(dur));
857 }
858 if let Some(nodelay) = self.tcp_nodelay {
859 http.set_nodelay(nodelay);
860 }
861 if let Some(ka) = self.tcp_keepalive {
862 http.set_keepalive(Some(ka));
863 }
864
865 let connector = crate::connector::OxiHttpsConnector::new(http, tls_connector);
866
867 let mut builder = HyperClient::builder(TokioExecutor::new());
868 if let Some(n) = self.pool_max_idle_per_host {
869 builder.pool_max_idle_per_host(n);
870 }
871 if let Some(d) = self.pool_idle_timeout {
872 builder.pool_idle_timeout(d);
873 }
874 if let Some(ref h2) = self.http2_settings {
875 apply_http2_settings(&mut builder, h2);
876 }
877
878 let mut default_headers = self.default_headers;
879 if let Some(agent) = &self.user_agent {
880 if let Ok(val) = HeaderValue::from_str(agent) {
881 default_headers.insert(http::header::USER_AGENT, val);
882 }
883 }
884
885 Ok(Client {
886 inner: builder.build(connector),
887 connect_timeout: self.connect_timeout,
888 read_timeout: self.read_timeout,
889 redirect_policy: self.redirect_policy,
890 retry_policy: self.retry_policy,
891 default_headers,
892 decompression: self.decompression,
893 middleware: self.middleware,
894 cookie_jar: self.cookie_jar,
895 #[cfg(feature = "tls")]
896 tls_rebuild: None,
897 })
898 }
899}
900
901impl Default for ClientBuilder {
902 fn default() -> Self {
903 Self::new()
904 }
905}
906
907impl std::fmt::Debug for ClientBuilder {
908 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
909 f.debug_struct("ClientBuilder")
910 .field("pool_max_idle_per_host", &self.pool_max_idle_per_host)
911 .field("pool_idle_timeout", &self.pool_idle_timeout)
912 .field("connect_timeout", &self.connect_timeout)
913 .field("read_timeout", &self.read_timeout)
914 .field("redirect_policy", &self.redirect_policy)
915 .field("retry_policy", &self.retry_policy)
916 .field("decompression", &self.decompression)
917 .field("user_agent", &self.user_agent)
918 .field("tcp_nodelay", &self.tcp_nodelay)
919 .field("tcp_keepalive", &self.tcp_keepalive)
920 .finish_non_exhaustive()
921 }
922}