Skip to content

Commit 8345dfe

Browse files
committed
Make TowerToHyperService crate-private
This also requires vendoring it in the rustls example, which doesn’t use a server type. Making the type crate-private means we can delete some unused methods.
1 parent 791b138 commit 8345dfe

File tree

3 files changed

+82
-35
lines changed

3 files changed

+82
-35
lines changed

examples/Cargo.toml

+3-2
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ tower = ["dep:hyper", "dep:hyper-util", "dep:tower", "dep:http"]
280280
json-codec = ["dep:serde", "dep:serde_json", "dep:bytes"]
281281
compression = ["tonic/gzip"]
282282
tls = ["tonic/tls"]
283-
tls-rustls = ["dep:hyper", "dep:hyper-util", "dep:hyper-rustls", "dep:tower", "tower-http/util", "tower-http/add-extension", "dep:rustls-pemfile", "dep:tokio-rustls"]
283+
tls-rustls = ["dep:hyper", "dep:hyper-util", "dep:hyper-rustls", "dep:tower", "tower-http/util", "tower-http/add-extension", "dep:rustls-pemfile", "dep:tokio-rustls", "dep:pin-project", "dep:http-body-util"]
284284
dynamic-load-balance = ["dep:tower"]
285285
timeout = ["tokio/time", "dep:tower"]
286286
tls-client-auth = ["tonic/tls"]
@@ -315,14 +315,15 @@ http = { version = "1", optional = true }
315315
http-body = { version = "1", optional = true }
316316
http-body-util = { version = "0.1", optional = true }
317317
hyper = { version = "1", optional = true }
318-
hyper-util = { version = "0.1", optional = true }
318+
hyper-util = { version = ">=0.1.4, <0.2", optional = true }
319319
listenfd = { version = "1.0", optional = true }
320320
bytes = { version = "1", optional = true }
321321
h2 = { version = "0.3", optional = true }
322322
tokio-rustls = { version = "0.26", optional = true, features = ["ring", "tls12"], default-features = false }
323323
hyper-rustls = { version = "0.27.0", features = ["http2", "ring", "tls12"], optional = true, default-features = false }
324324
rustls-pemfile = { version = "2.0.0", optional = true }
325325
tower-http = { version = "0.5", optional = true }
326+
pin-project = { version = "1.0.11", optional = true }
326327

327328
[build-dependencies]
328329
tonic-build = { path = "../tonic-build", features = ["prost"] }

examples/src/tls_rustls/server.rs

+70-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ pub mod pb {
22
tonic::include_proto!("/grpc.examples.unaryecho");
33
}
44

5+
use http_body_util::BodyExt;
56
use hyper::server::conn::http2::Builder;
67
use hyper_util::rt::{TokioExecutor, TokioIo};
78
use pb::{EchoRequest, EchoResponse};
@@ -14,8 +15,8 @@ use tokio_rustls::{
1415
},
1516
TlsAcceptor,
1617
};
17-
use tonic::transport::server::TowerToHyperService;
18-
use tonic::{transport::Server, Request, Response, Status};
18+
use tonic::{body::BoxBody, transport::Server, Request, Response, Status};
19+
use tower::{BoxError, ServiceExt};
1920
use tower_http::ServiceBuilderExt;
2021

2122
#[tokio::main]
@@ -122,3 +123,70 @@ impl pb::echo_server::Echo for EchoServer {
122123
Ok(Response::new(EchoResponse { message }))
123124
}
124125
}
126+
127+
/// An adaptor which converts a [`tower::Service`] to a [`hyper::service::Service`].
128+
///
129+
/// The [`hyper::service::Service`] trait is used by hyper to handle incoming requests,
130+
/// and does not support the `poll_ready` method that is used by tower services.
131+
///
132+
/// This is provided here because the equivalent adaptor in hyper-util does not support
133+
/// tonic::body::BoxBody bodies.
134+
#[derive(Debug, Clone)]
135+
struct TowerToHyperService<S> {
136+
service: S,
137+
}
138+
139+
impl<S> TowerToHyperService<S> {
140+
/// Create a new `TowerToHyperService` from a tower service.
141+
fn new(service: S) -> Self {
142+
Self { service }
143+
}
144+
}
145+
146+
impl<S> hyper::service::Service<hyper::Request<hyper::body::Incoming>> for TowerToHyperService<S>
147+
where
148+
S: tower::Service<hyper::Request<BoxBody>> + Clone,
149+
S::Error: Into<BoxError> + 'static,
150+
{
151+
type Response = S::Response;
152+
type Error = BoxError;
153+
type Future = TowerToHyperServiceFuture<S, hyper::Request<BoxBody>>;
154+
155+
fn call(&self, req: hyper::Request<hyper::body::Incoming>) -> Self::Future {
156+
let req = req.map(|incoming| {
157+
incoming
158+
.map_err(|err| Status::from_error(err.into()))
159+
.boxed_unsync()
160+
});
161+
TowerToHyperServiceFuture {
162+
future: self.service.clone().oneshot(req),
163+
}
164+
}
165+
}
166+
167+
/// Future returned by [`TowerToHyperService`].
168+
#[derive(Debug)]
169+
#[pin_project::pin_project]
170+
struct TowerToHyperServiceFuture<S, R>
171+
where
172+
S: tower::Service<R>,
173+
{
174+
#[pin]
175+
future: tower::util::Oneshot<S, R>,
176+
}
177+
178+
impl<S, R> std::future::Future for TowerToHyperServiceFuture<S, R>
179+
where
180+
S: tower::Service<R>,
181+
S::Error: Into<BoxError> + 'static,
182+
{
183+
type Output = Result<S::Response, BoxError>;
184+
185+
#[inline]
186+
fn poll(
187+
self: std::pin::Pin<&mut Self>,
188+
cx: &mut std::task::Context<'_>,
189+
) -> std::task::Poll<Self::Output> {
190+
self.project().future.poll(cx).map_err(Into::into)
191+
}
192+
}

tonic/src/transport/server/mod.rs

+9-31
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,9 @@ mod tls;
1010
mod unix;
1111

1212
use tokio_stream::StreamExt as _;
13-
use tower::util::BoxCloneService;
14-
use tower::util::Oneshot;
15-
use tower::ServiceExt;
16-
use tracing::debug;
17-
use tracing::trace;
13+
use tracing::{debug, trace};
1814

19-
pub use super::service::Routes;
20-
pub use super::service::RoutesBuilder;
15+
pub use super::service::{Routes, RoutesBuilder};
2116

2217
pub use conn::{Connected, TcpConnectInfo};
2318
use hyper_util::rt::{TokioExecutor, TokioIo};
@@ -43,19 +38,17 @@ use crate::transport::Error;
4338

4439
use self::recover_error::RecoverError;
4540
use super::service::{GrpcTimeout, ServerIo};
46-
use crate::body::boxed;
47-
use crate::body::BoxBody;
41+
use crate::body::{boxed, BoxBody};
4842
use crate::server::NamedService;
4943
use bytes::Bytes;
5044
use http::{Request, Response};
5145
use http_body_util::BodyExt;
5246
use hyper::body::Incoming;
5347
use pin_project::pin_project;
54-
use std::future::poll_fn;
5548
use std::{
5649
convert::Infallible,
5750
fmt,
58-
future::{self, Future},
51+
future::{self, poll_fn, Future},
5952
marker::PhantomData,
6053
net::SocketAddr,
6154
pin::{pin, Pin},
@@ -69,8 +62,8 @@ use tower::{
6962
layer::util::{Identity, Stack},
7063
layer::Layer,
7164
limit::concurrency::ConcurrencyLimitLayer,
72-
util::Either,
73-
Service, ServiceBuilder,
65+
util::{BoxCloneService, Either, Oneshot},
66+
Service, ServiceBuilder, ServiceExt,
7467
};
7568

7669
type BoxHttpBody = crate::body::BoxBody;
@@ -673,30 +666,15 @@ type ConnectionBuilder = hyper_util::server::conn::auto::Builder<TokioExecutor>;
673666
/// The [`hyper::service::Service`] trait is used by hyper to handle incoming requests,
674667
/// and does not support the `poll_ready` method that is used by tower services.
675668
#[derive(Debug, Copy, Clone)]
676-
pub struct TowerToHyperService<S> {
669+
pub(crate) struct TowerToHyperService<S> {
677670
service: S,
678671
}
679672

680673
impl<S> TowerToHyperService<S> {
681674
/// Create a new `TowerToHyperService` from a tower service.
682-
pub fn new(service: S) -> Self {
675+
pub(crate) fn new(service: S) -> Self {
683676
Self { service }
684677
}
685-
686-
/// Extract the inner tower service.
687-
pub fn into_inner(self) -> S {
688-
self.service
689-
}
690-
691-
/// Get a reference to the inner tower service.
692-
pub fn as_inner(&self) -> &S {
693-
&self.service
694-
}
695-
696-
/// Get a mutable reference to the inner tower service.
697-
pub fn as_inner_mut(&mut self) -> &mut S {
698-
&mut self.service
699-
}
700678
}
701679

702680
impl<S> hyper::service::Service<Request<Incoming>> for TowerToHyperService<S>
@@ -719,7 +697,7 @@ where
719697
/// Future returned by [`TowerToHyperService`].
720698
#[derive(Debug)]
721699
#[pin_project]
722-
pub struct TowerToHyperServiceFuture<S, R>
700+
pub(crate) struct TowerToHyperServiceFuture<S, R>
723701
where
724702
S: tower_service::Service<R>,
725703
{

0 commit comments

Comments
 (0)