feat: Add Grpc::with_origin for clients (#1017)
This commit is contained in:
@@ -48,30 +48,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
|
|
||||||
let client = hyper::Client::builder().build(connector);
|
let client = hyper::Client::builder().build(connector);
|
||||||
|
|
||||||
// Hyper expects an absolute `Uri` to allow it to know which server to connect too.
|
// Using `with_origin` will let the codegenerated client set the `scheme` and
|
||||||
// Currently, tonic's generated code only sets the `path_and_query` section so we
|
// `authority` from the porvided `Uri`.
|
||||||
// are going to write a custom tower layer in front of the hyper client to add the
|
|
||||||
// scheme and authority.
|
|
||||||
//
|
|
||||||
// Again, this Uri is `example.com` because our tls certs is signed with this SNI but above
|
|
||||||
// we actually map this back to `[::1]:50051` before the `Uri` is passed to hyper's `HttpConnector`
|
|
||||||
// to allow it to correctly establish the tcp connection to the local `tls-server`.
|
|
||||||
let uri = Uri::from_static("https://example.com");
|
let uri = Uri::from_static("https://example.com");
|
||||||
let svc = tower::ServiceBuilder::new()
|
let mut client = EchoClient::with_origin(client, uri);
|
||||||
.map_request(move |mut req: http::Request<tonic::body::BoxBody>| {
|
|
||||||
let uri = Uri::builder()
|
|
||||||
.scheme(uri.scheme().unwrap().clone())
|
|
||||||
.authority(uri.authority().unwrap().clone())
|
|
||||||
.path_and_query(req.uri().path_and_query().unwrap().clone())
|
|
||||||
.build()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
*req.uri_mut() = uri;
|
|
||||||
req
|
|
||||||
})
|
|
||||||
.service(client);
|
|
||||||
|
|
||||||
let mut client = EchoClient::new(svc);
|
|
||||||
|
|
||||||
let request = tonic::Request::new(EchoRequest {
|
let request = tonic::Request::new(EchoRequest {
|
||||||
message: "hello".into(),
|
message: "hello".into(),
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ pub fn generate<T: Service>(
|
|||||||
clippy::let_unit_value,
|
clippy::let_unit_value,
|
||||||
)]
|
)]
|
||||||
use tonic::codegen::*;
|
use tonic::codegen::*;
|
||||||
|
use tonic::codegen::http::Uri;
|
||||||
|
|
||||||
#service_doc
|
#service_doc
|
||||||
#(#struct_attributes)*
|
#(#struct_attributes)*
|
||||||
@@ -66,6 +67,11 @@ pub fn generate<T: Service>(
|
|||||||
Self { inner }
|
Self { inner }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_origin(inner: T, origin: Uri) -> Self {
|
||||||
|
let inner = tonic::client::Grpc::with_origin(inner, origin);
|
||||||
|
Self { inner }
|
||||||
|
}
|
||||||
|
|
||||||
pub fn with_interceptor<F>(inner: T, interceptor: F) -> #service_ident<InterceptedService<T, F>>
|
pub fn with_interceptor<F>(inner: T, interceptor: F) -> #service_ident<InterceptedService<T, F>>
|
||||||
where
|
where
|
||||||
F: tonic::service::Interceptor,
|
F: tonic::service::Interceptor,
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ use std::fmt;
|
|||||||
/// [gRPC protocol definition]: https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#requests
|
/// [gRPC protocol definition]: https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#requests
|
||||||
pub struct Grpc<T> {
|
pub struct Grpc<T> {
|
||||||
inner: T,
|
inner: T,
|
||||||
|
origin: Uri,
|
||||||
/// Which compression encodings does the client accept?
|
/// Which compression encodings does the client accept?
|
||||||
accept_compression_encodings: EnabledCompressionEncodings,
|
accept_compression_encodings: EnabledCompressionEncodings,
|
||||||
/// The compression encoding that will be applied to requests.
|
/// The compression encoding that will be applied to requests.
|
||||||
@@ -41,6 +42,20 @@ impl<T> Grpc<T> {
|
|||||||
pub fn new(inner: T) -> Self {
|
pub fn new(inner: T) -> Self {
|
||||||
Self {
|
Self {
|
||||||
inner,
|
inner,
|
||||||
|
origin: Uri::default(),
|
||||||
|
send_compression_encodings: None,
|
||||||
|
accept_compression_encodings: EnabledCompressionEncodings::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new gRPC client with the provided [`GrpcService`] and `Uri`.
|
||||||
|
///
|
||||||
|
/// The provided Uri will use only the scheme and authority parts as the
|
||||||
|
/// path_and_query portion will be set for each method.
|
||||||
|
pub fn with_origin(inner: T, origin: Uri) -> Self {
|
||||||
|
Self {
|
||||||
|
inner,
|
||||||
|
origin,
|
||||||
send_compression_encodings: None,
|
send_compression_encodings: None,
|
||||||
accept_compression_encodings: EnabledCompressionEncodings::default(),
|
accept_compression_encodings: EnabledCompressionEncodings::default(),
|
||||||
}
|
}
|
||||||
@@ -211,8 +226,13 @@ impl<T> Grpc<T> {
|
|||||||
M1: Send + Sync + 'static,
|
M1: Send + Sync + 'static,
|
||||||
M2: Send + Sync + 'static,
|
M2: Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
|
let scheme = self.origin.scheme().cloned();
|
||||||
|
let authority = self.origin.authority().cloned();
|
||||||
|
|
||||||
let mut parts = Parts::default();
|
let mut parts = Parts::default();
|
||||||
parts.path_and_query = Some(path);
|
parts.path_and_query = Some(path);
|
||||||
|
parts.scheme = scheme;
|
||||||
|
parts.authority = authority;
|
||||||
|
|
||||||
let uri = Uri::from_parts(parts).expect("path_and_query only is valid Uri");
|
let uri = Uri::from_parts(parts).expect("path_and_query only is valid Uri");
|
||||||
|
|
||||||
@@ -296,6 +316,7 @@ impl<T: Clone> Clone for Grpc<T> {
|
|||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
inner: self.inner.clone(),
|
inner: self.inner.clone(),
|
||||||
|
origin: self.origin.clone(),
|
||||||
send_compression_encodings: self.send_compression_encodings,
|
send_compression_encodings: self.send_compression_encodings,
|
||||||
accept_compression_encodings: self.accept_compression_encodings,
|
accept_compression_encodings: self.accept_compression_encodings,
|
||||||
}
|
}
|
||||||
@@ -308,6 +329,8 @@ impl<T: fmt::Debug> fmt::Debug for Grpc<T> {
|
|||||||
|
|
||||||
f.field("inner", &self.inner);
|
f.field("inner", &self.inner);
|
||||||
|
|
||||||
|
f.field("origin", &self.origin);
|
||||||
|
|
||||||
f.field("compression_encoding", &self.send_compression_encodings);
|
f.field("compression_encoding", &self.send_compression_encodings);
|
||||||
|
|
||||||
f.field(
|
f.field(
|
||||||
|
|||||||
Reference in New Issue
Block a user