From 65032021e0e34575125c177660aa39b512368313 Mon Sep 17 00:00:00 2001 From: Jonas Irgens Kylling Date: Tue, 30 Sep 2025 17:35:01 +0200 Subject: [PATCH 1/2] Override origin on Endpoints This change sets origin on Endpoints, such that the LoadBalancedChannel can be used with proxies which route to backend services based on origin. My use case is to be able to use the same grpc client for both DNS based load balancing, and for accessing internal gRPC services through proxies (this is useful for testing). --- CHANGELOG.md | 3 +++ ginepro/src/service_definition.rs | 16 +++++++++++++++- ginepro/src/service_probe.rs | 22 +++++++++++++++++++++- 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6987d87..929bd29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Other +- Changed endpoint construction to set origin for compatibility with SNI based servers. + ## [0.9.0](https://github.com/TrueLayer/ginepro/compare/ginepro-v0.8.2...ginepro-v0.8.1) - 2025-07-24 ### Breaking changes diff --git a/ginepro/src/service_definition.rs b/ginepro/src/service_definition.rs index 0850d85..1c659d4 100644 --- a/ginepro/src/service_definition.rs +++ b/ginepro/src/service_definition.rs @@ -8,6 +8,8 @@ pub struct ServiceDefinition { hostname: String, /// The service port. port: u16, + /// Authority + authority: http::uri::Authority, } impl ServiceDefinition { @@ -21,7 +23,15 @@ impl ServiceDefinition { .map_err(anyhow::Error::from) .context("invalid 'hostname'")?; - Ok(Self { hostname, port }) + let authority = format!("{}:{}", hostname, port) + .parse() + .context("invalid 'hostname'")?; + + Ok(Self { + hostname, + port, + authority, + }) } /// Get the `hostname` part of a `ServiceDefinition`. @@ -29,6 +39,10 @@ impl ServiceDefinition { &self.hostname } + pub(crate) fn authority(&self) -> &http::uri::Authority { + &self.authority + } + /// Get the `port` part of a `ServiceDefinition`. pub fn port(&self) -> u16 { self.port diff --git a/ginepro/src/service_probe.rs b/ginepro/src/service_probe.rs index 0e65708..41f3362 100644 --- a/ginepro/src/service_probe.rs +++ b/ginepro/src/service_probe.rs @@ -34,6 +34,7 @@ where Lookup: LookupService, { service_definition: ServiceDefinition, + origin: http::uri::Uri, scheme: http::uri::Scheme, dns_lookup: Lookup, probe_interval: tokio::time::Duration, @@ -70,8 +71,10 @@ impl GrpcServiceProbe { config: GrpcServiceProbeConfig, endpoint_reporter: Sender>, ) -> GrpcServiceProbe { + let origin = create_origin(config.service_definition.authority().clone()); Self { service_definition: config.service_definition, + origin, dns_lookup: config.dns_lookup, probe_interval: config.probe_interval, endpoint_timeout: config.endpoint_timeout, @@ -85,9 +88,15 @@ impl GrpcServiceProbe { /// Enable tls for all endpoints. pub fn with_tls(self, tls_config: ClientTlsConfig) -> GrpcServiceProbe { + let mut parts = self.origin.into_parts(); + parts.scheme = Some(http::uri::Scheme::HTTPS); + let origin = parts + .try_into() + .expect("Invalid URI. Impossible as all parts are present"); Self { tls_config: Some(tls_config), scheme: http::uri::Scheme::HTTPS, + origin, ..self } } @@ -215,7 +224,8 @@ impl GrpcServiceProbe { .map_err(|err| { tracing::warn!("endpoint creation error: {:?}", err); }) - .ok()?; + .ok()? + .origin(self.origin.clone()); if let Some(ref tls_config) = self.tls_config { endpoint = endpoint @@ -237,3 +247,13 @@ impl GrpcServiceProbe { Some(endpoint) } } + +fn create_origin(authority: http::uri::Authority) -> http::uri::Uri { + let mut parts = http::uri::Parts::default(); + parts.scheme = Some(http::uri::Scheme::HTTP); + parts.authority = Some(authority); + parts.path_and_query = Some(http::uri::PathAndQuery::from_static("")); + parts + .try_into() + .expect("Invalid URI. Impossible as all parts are present") +} From 8f3084bb31c32e189facfdb8c23a7cfdccb23b64 Mon Sep 17 00:00:00 2001 From: Jonas Irgens Kylling Date: Tue, 30 Dec 2025 16:40:48 +0100 Subject: [PATCH 2/2] Fix path_and_query --- ginepro/src/service_probe.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ginepro/src/service_probe.rs b/ginepro/src/service_probe.rs index 41f3362..3def8bc 100644 --- a/ginepro/src/service_probe.rs +++ b/ginepro/src/service_probe.rs @@ -252,7 +252,7 @@ fn create_origin(authority: http::uri::Authority) -> http::uri::Uri { let mut parts = http::uri::Parts::default(); parts.scheme = Some(http::uri::Scheme::HTTP); parts.authority = Some(authority); - parts.path_and_query = Some(http::uri::PathAndQuery::from_static("")); + parts.path_and_query = Some(http::uri::PathAndQuery::from_static("/")); parts .try_into() .expect("Invalid URI. Impossible as all parts are present")