1use super::Channel;
26#[cfg(feature = "_tls-any")]
27use super::ClientTlsConfig;
28#[cfg(feature = "_tls-any")]
29use super::service::TlsConnector;
30use super::service::{self, Executor, SharedExec};
31use super::uds_connector::UdsConnector;
32use crate::transport::Error;
33#[cfg(feature = "_tls-any")]
34use crate::transport::error;
35use bytes::Bytes;
36use http::{HeaderValue, uri::Uri};
37use hyper::rt;
38use hyper_util::client::legacy::connect::HttpConnector;
39#[cfg(feature = "_tls-any")]
40use std::sync::Arc;
41use std::{fmt, future::Future, net::IpAddr, pin::Pin, str, str::FromStr, time::Duration};
42#[cfg(feature = "_tls-any")]
43use tokio_rustls::rustls::client::danger::ServerCertVerifier;
44use tower_service::Service;
45
46#[derive(Clone, PartialEq, Eq, Hash)]
47pub(crate) enum EndpointType {
48 Uri(Uri),
49 Uds(String),
50}
51
52#[derive(Clone)]
56pub struct Endpoint {
57 pub(crate) uri: EndpointType,
58 fallback_uri: Uri,
59 pub(crate) origin: Option<Uri>,
60 pub(crate) user_agent: Option<HeaderValue>,
61 pub(crate) timeout: Option<Duration>,
62 pub(crate) concurrency_limit: Option<usize>,
63 pub(crate) rate_limit: Option<(u64, Duration)>,
64 #[cfg(feature = "_tls-any")]
65 pub(crate) tls: Option<TlsConnector>,
66 pub(crate) buffer_size: Option<usize>,
67 pub(crate) init_stream_window_size: Option<u32>,
68 pub(crate) init_connection_window_size: Option<u32>,
69 pub(crate) max_frame_size: Option<u32>,
70 pub(crate) tcp_keepalive: Option<Duration>,
71 pub(crate) tcp_keepalive_interval: Option<Duration>,
72 pub(crate) tcp_keepalive_retries: Option<u32>,
73 pub(crate) tcp_nodelay: bool,
74 pub(crate) http2_keep_alive_interval: Option<Duration>,
75 pub(crate) http2_keep_alive_timeout: Option<Duration>,
76 pub(crate) http2_keep_alive_while_idle: Option<bool>,
77 pub(crate) http2_header_table_size: Option<u32>,
78 pub(crate) http2_max_header_list_size: Option<u32>,
79 pub(crate) http2_max_concurrent_reset_streams: Option<usize>,
80 pub(crate) http2_reset_stream_duration: Option<Duration>,
81 pub(crate) http2_max_local_error_reset_streams: Option<Option<usize>>,
82 pub(crate) connect_timeout: Option<Duration>,
83 pub(crate) http2_adaptive_window: Option<bool>,
84 pub(crate) local_address: Option<IpAddr>,
85 pub(crate) executor: SharedExec,
86}
87
88impl Endpoint {
89 #[doc(hidden)]
92 pub fn new<D>(dst: D) -> Result<Self, Error>
93 where
94 D: TryInto<Self>,
95 D::Error: Into<crate::BoxError>,
96 {
97 let me = dst.try_into().map_err(|e| Error::from_source(e.into()))?;
98 #[cfg(feature = "_tls-any")]
99 if let EndpointType::Uri(uri) = &me.uri
100 && me.tls.is_none()
101 && uri.scheme() == Some(&http::uri::Scheme::HTTPS)
102 {
103 return me.tls_config(ClientTlsConfig::new().with_enabled_roots());
104 }
105 Ok(me)
106 }
107
108 fn new_uri(uri: Uri) -> Self {
109 Self {
110 uri: EndpointType::Uri(uri.clone()),
111 fallback_uri: uri,
112 origin: None,
113 user_agent: None,
114 concurrency_limit: None,
115 rate_limit: None,
116 timeout: None,
117 #[cfg(feature = "_tls-any")]
118 tls: None,
119 buffer_size: None,
120 init_stream_window_size: None,
121 init_connection_window_size: None,
122 max_frame_size: None,
123 tcp_keepalive: None,
124 tcp_keepalive_interval: None,
125 tcp_keepalive_retries: None,
126 tcp_nodelay: true,
127 http2_keep_alive_interval: None,
128 http2_keep_alive_timeout: None,
129 http2_keep_alive_while_idle: None,
130 http2_header_table_size: None,
131 http2_max_header_list_size: None,
132 http2_max_concurrent_reset_streams: None,
133 http2_reset_stream_duration: None,
134 http2_max_local_error_reset_streams: None,
135 connect_timeout: None,
136 http2_adaptive_window: None,
137 executor: SharedExec::tokio(),
138 local_address: None,
139 }
140 }
141
142 fn new_uds(uds_filepath: &str) -> Self {
143 Self {
144 uri: EndpointType::Uds(uds_filepath.to_string()),
145 fallback_uri: Uri::from_static("http://tonic"),
146 origin: None,
147 user_agent: None,
148 concurrency_limit: None,
149 rate_limit: None,
150 timeout: None,
151 #[cfg(feature = "_tls-any")]
152 tls: None,
153 buffer_size: None,
154 init_stream_window_size: None,
155 init_connection_window_size: None,
156 max_frame_size: None,
157 tcp_keepalive: None,
158 tcp_keepalive_interval: None,
159 tcp_keepalive_retries: None,
160 tcp_nodelay: true,
161 http2_keep_alive_interval: None,
162 http2_keep_alive_timeout: None,
163 http2_keep_alive_while_idle: None,
164 http2_header_table_size: None,
165 http2_max_header_list_size: None,
166 http2_max_concurrent_reset_streams: None,
167 http2_reset_stream_duration: None,
168 http2_max_local_error_reset_streams: None,
169 connect_timeout: None,
170 http2_adaptive_window: None,
171 executor: SharedExec::tokio(),
172 local_address: None,
173 }
174 }
175
176 pub fn from_static(s: &'static str) -> Self {
187 if s.starts_with("unix:") {
188 let uds_filepath = s
189 .strip_prefix("unix://")
190 .or_else(|| s.strip_prefix("unix:"))
191 .expect("Invalid unix domain socket URI");
192 Self::new_uds(uds_filepath)
193 } else {
194 let uri = Uri::from_static(s);
195 Self::new_uri(uri)
196 }
197 }
198
199 pub fn from_shared(s: impl Into<Bytes>) -> Result<Self, Error> {
206 let s = str::from_utf8(&s.into())
207 .map_err(|e| Error::new_invalid_uri().with(e))?
208 .to_string();
209 if s.starts_with("unix:") {
210 let uds_filepath = s
211 .strip_prefix("unix://")
212 .or_else(|| s.strip_prefix("unix:"))
213 .ok_or(Error::new_invalid_uri())?;
214 Ok(Self::new_uds(uds_filepath))
215 } else {
216 let uri = Uri::from_maybe_shared(s).map_err(|e| Error::new_invalid_uri().with(e))?;
217 Ok(Self::from(uri))
218 }
219 }
220
221 pub fn user_agent<T>(self, user_agent: T) -> Result<Self, Error>
233 where
234 T: TryInto<HeaderValue>,
235 {
236 user_agent
237 .try_into()
238 .map(|ua| Endpoint {
239 user_agent: Some(ua),
240 ..self
241 })
242 .map_err(|_| Error::new_invalid_user_agent())
243 }
244
245 pub fn origin(self, origin: Uri) -> Self {
258 Endpoint {
259 origin: Some(origin),
260 ..self
261 }
262 }
263
264 pub fn timeout(self, dur: Duration) -> Self {
281 Endpoint {
282 timeout: Some(dur),
283 ..self
284 }
285 }
286
287 pub fn connect_timeout(self, dur: Duration) -> Self {
298 Endpoint {
299 connect_timeout: Some(dur),
300 ..self
301 }
302 }
303
304 pub fn tcp_keepalive(self, tcp_keepalive: Option<Duration>) -> Self {
312 Endpoint {
313 tcp_keepalive,
314 ..self
315 }
316 }
317
318 pub fn tcp_keepalive_interval(self, tcp_keepalive_interval: Option<Duration>) -> Self {
325 Endpoint {
326 tcp_keepalive_interval,
327 ..self
328 }
329 }
330
331 pub fn tcp_keepalive_retries(self, tcp_keepalive_retries: Option<u32>) -> Self {
337 Endpoint {
338 tcp_keepalive_retries,
339 ..self
340 }
341 }
342
343 pub fn concurrency_limit(self, limit: usize) -> Self {
351 Endpoint {
352 concurrency_limit: Some(limit),
353 ..self
354 }
355 }
356
357 pub fn rate_limit(self, limit: u64, duration: Duration) -> Self {
366 Endpoint {
367 rate_limit: Some((limit, duration)),
368 ..self
369 }
370 }
371
372 pub fn initial_stream_window_size(self, sz: impl Into<Option<u32>>) -> Self {
379 Endpoint {
380 init_stream_window_size: sz.into(),
381 ..self
382 }
383 }
384
385 pub fn initial_connection_window_size(self, sz: impl Into<Option<u32>>) -> Self {
389 Endpoint {
390 init_connection_window_size: sz.into(),
391 ..self
392 }
393 }
394
395 pub fn buffer_size(self, sz: impl Into<Option<usize>>) -> Self {
399 Endpoint {
400 buffer_size: sz.into(),
401 ..self
402 }
403 }
404
405 #[cfg(feature = "_tls-any")]
407 pub fn tls_config(self, tls_config: ClientTlsConfig) -> Result<Self, Error> {
408 match &self.uri {
409 EndpointType::Uri(uri) => Ok(Endpoint {
410 tls: Some(
411 tls_config
412 .into_tls_connector(uri)
413 .map_err(Error::from_source)?,
414 ),
415 ..self
416 }),
417 EndpointType::Uds(_) => Err(Error::new(error::Kind::InvalidTlsConfigForUds)),
418 }
419 }
420
421 #[cfg(feature = "_tls-any")]
443 pub fn tls_config_with_verifier(
444 self,
445 tls_config: ClientTlsConfig,
446 verifier: Arc<dyn ServerCertVerifier>,
447 ) -> Result<Self, Error> {
448 match &self.uri {
449 EndpointType::Uri(uri) => Ok(Endpoint {
450 tls: Some(
451 tls_config
452 .into_tls_connector_with_verifier(uri, verifier)
453 .map_err(Error::from_source)?,
454 ),
455 ..self
456 }),
457 EndpointType::Uds(_) => Err(Error::new(error::Kind::InvalidTlsConfigForUds)),
458 }
459 }
460
461 pub fn tcp_nodelay(self, enabled: bool) -> Self {
463 Endpoint {
464 tcp_nodelay: enabled,
465 ..self
466 }
467 }
468
469 pub fn http2_keep_alive_interval(self, interval: Duration) -> Self {
471 Endpoint {
472 http2_keep_alive_interval: Some(interval),
473 ..self
474 }
475 }
476
477 pub fn keep_alive_timeout(self, duration: Duration) -> Self {
479 Endpoint {
480 http2_keep_alive_timeout: Some(duration),
481 ..self
482 }
483 }
484
485 pub fn keep_alive_while_idle(self, enabled: bool) -> Self {
487 Endpoint {
488 http2_keep_alive_while_idle: Some(enabled),
489 ..self
490 }
491 }
492
493 pub fn http2_adaptive_window(self, enabled: bool) -> Self {
495 Endpoint {
496 http2_adaptive_window: Some(enabled),
497 ..self
498 }
499 }
500
501 pub fn http2_header_table_size(self, size: u32) -> Self {
508 Endpoint {
509 http2_header_table_size: Some(size),
510 ..self
511 }
512 }
513
514 pub fn http2_max_header_list_size(self, size: u32) -> Self {
518 Endpoint {
519 http2_max_header_list_size: Some(size),
520 ..self
521 }
522 }
523
524 #[must_use]
531 pub fn http2_max_concurrent_reset_streams(self, max: usize) -> Self {
532 Endpoint {
533 http2_max_concurrent_reset_streams: Some(max),
534 ..self
535 }
536 }
537
538 #[must_use]
542 pub fn http2_reset_stream_duration(self, duration: Duration) -> Self {
543 Endpoint {
544 http2_reset_stream_duration: Some(duration),
545 ..self
546 }
547 }
548
549 #[must_use]
555 pub fn http2_max_local_error_reset_streams(self, max: impl Into<Option<usize>>) -> Self {
556 Endpoint {
557 http2_max_local_error_reset_streams: Some(max.into()),
558 ..self
559 }
560 }
561
562 #[must_use]
576 pub fn max_frame_size(self, frame_size: impl Into<Option<u32>>) -> Self {
577 Endpoint {
578 max_frame_size: frame_size.into(),
579 ..self
580 }
581 }
582
583 pub fn executor<E>(mut self, executor: E) -> Self
587 where
588 E: Executor<Pin<Box<dyn Future<Output = ()> + Send>>> + Send + Sync + 'static,
589 {
590 self.executor = SharedExec::new(executor);
591 self
592 }
593
594 pub(crate) fn connector<C>(&self, c: C) -> service::Connector<C> {
595 service::Connector::new(
596 c,
597 #[cfg(feature = "_tls-any")]
598 self.tls.clone(),
599 )
600 }
601
602 pub fn local_address(self, addr: Option<IpAddr>) -> Self {
606 Endpoint {
607 local_address: addr,
608 ..self
609 }
610 }
611
612 pub(crate) fn http_connector(&self) -> service::Connector<HttpConnector> {
613 let mut http = HttpConnector::new();
614 http.enforce_http(false);
615 http.set_nodelay(self.tcp_nodelay);
616 http.set_keepalive(self.tcp_keepalive);
617 http.set_keepalive_interval(self.tcp_keepalive_interval);
618 http.set_keepalive_retries(self.tcp_keepalive_retries);
619 http.set_connect_timeout(self.connect_timeout);
620 http.set_local_address(self.local_address);
621 self.connector(http)
622 }
623
624 pub(crate) fn uds_connector(&self, uds_filepath: &str) -> service::Connector<UdsConnector> {
625 self.connector(UdsConnector::new(uds_filepath))
626 }
627
628 pub async fn connect(&self) -> Result<Channel, Error> {
630 match &self.uri {
631 EndpointType::Uri(_) => Channel::connect(self.http_connector(), self.clone()).await,
632 EndpointType::Uds(uds_filepath) => {
633 Channel::connect(self.uds_connector(uds_filepath.as_str()), self.clone()).await
634 }
635 }
636 }
637
638 pub fn connect_lazy(&self) -> Channel {
643 match &self.uri {
644 EndpointType::Uri(_) => Channel::new(self.http_connector(), self.clone()),
645 EndpointType::Uds(uds_filepath) => {
646 Channel::new(self.uds_connector(uds_filepath.as_str()), self.clone())
647 }
648 }
649 }
650
651 pub async fn connect_with_connector<C>(&self, connector: C) -> Result<Channel, Error>
659 where
660 C: Service<Uri> + Send + 'static,
661 C::Response: rt::Read + rt::Write + Send + Unpin,
662 C::Future: Send,
663 crate::BoxError: From<C::Error> + Send,
664 {
665 let connector = self.connector(connector);
666
667 if let Some(connect_timeout) = self.connect_timeout {
668 let mut connector = hyper_timeout::TimeoutConnector::new(connector);
669 connector.set_connect_timeout(Some(connect_timeout));
670 Channel::connect(connector, self.clone()).await
671 } else {
672 Channel::connect(connector, self.clone()).await
673 }
674 }
675
676 pub fn connect_with_connector_lazy<C>(&self, connector: C) -> Channel
684 where
685 C: Service<Uri> + Send + 'static,
686 C::Response: rt::Read + rt::Write + Send + Unpin,
687 C::Future: Send,
688 crate::BoxError: From<C::Error> + Send,
689 {
690 let connector = self.connector(connector);
691 if let Some(connect_timeout) = self.connect_timeout {
692 let mut connector = hyper_timeout::TimeoutConnector::new(connector);
693 connector.set_connect_timeout(Some(connect_timeout));
694 Channel::new(connector, self.clone())
695 } else {
696 Channel::new(connector, self.clone())
697 }
698 }
699
700 pub fn uri(&self) -> &Uri {
710 match &self.uri {
711 EndpointType::Uri(uri) => uri,
712 EndpointType::Uds(_) => &self.fallback_uri,
713 }
714 }
715
716 pub fn get_tcp_nodelay(&self) -> bool {
718 self.tcp_nodelay
719 }
720
721 pub fn get_connect_timeout(&self) -> Option<Duration> {
723 self.connect_timeout
724 }
725
726 pub fn get_tcp_keepalive(&self) -> Option<Duration> {
732 self.tcp_keepalive
733 }
734
735 pub fn get_tcp_keepalive_interval(&self) -> Option<Duration> {
737 self.tcp_keepalive_interval
738 }
739
740 pub fn get_tcp_keepalive_retries(&self) -> Option<u32> {
742 self.tcp_keepalive_retries
743 }
744}
745
746impl From<Uri> for Endpoint {
747 fn from(uri: Uri) -> Self {
748 Self::new_uri(uri)
749 }
750}
751
752impl TryFrom<Bytes> for Endpoint {
753 type Error = Error;
754
755 fn try_from(t: Bytes) -> Result<Self, Self::Error> {
756 Self::from_shared(t)
757 }
758}
759
760impl TryFrom<String> for Endpoint {
761 type Error = Error;
762
763 fn try_from(t: String) -> Result<Self, Self::Error> {
764 Self::from_shared(t.into_bytes())
765 }
766}
767
768impl TryFrom<&'static str> for Endpoint {
769 type Error = Error;
770
771 fn try_from(t: &'static str) -> Result<Self, Self::Error> {
772 Self::from_shared(t.as_bytes())
773 }
774}
775
776impl fmt::Debug for Endpoint {
777 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
778 f.debug_struct("Endpoint").finish()
779 }
780}
781
782impl FromStr for Endpoint {
783 type Err = Error;
784
785 fn from_str(s: &str) -> Result<Self, Self::Err> {
786 Self::try_from(s.to_string())
787 }
788}