From 44c6e5e63503c422fd1627ebdf0b09ff975917b9 Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Fri, 4 Apr 2025 17:01:33 -0500 Subject: [PATCH 1/2] grpc-web: relax bounds for inner service's response body --- tonic-web/Cargo.toml | 1 + tonic-web/src/service.rs | 42 ++++++++++++++++++++++++++++------------ 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/tonic-web/Cargo.toml b/tonic-web/Cargo.toml index b3301aaa4..b656d00ee 100644 --- a/tonic-web/Cargo.toml +++ b/tonic-web/Cargo.toml @@ -29,6 +29,7 @@ tracing = "0.1" [dev-dependencies] tokio = { version = "1", features = ["macros", "rt"] } tower-http = { version = "0.6", features = ["cors"] } +axum = "0.8" [lints] workspace = true diff --git a/tonic-web/src/service.rs b/tonic-web/src/service.rs index a60a724ba..c463686e0 100644 --- a/tonic-web/src/service.rs +++ b/tonic-web/src/service.rs @@ -43,13 +43,15 @@ impl GrpcWebService { } } -impl Service> for GrpcWebService +impl Service> for GrpcWebService where - S: Service, Response = Response>, - B: http_body::Body + Send + 'static, - B::Error: Into + fmt::Display, + S: Service, Response = Response>, + ReqBody: http_body::Body + Send + 'static, + ReqBody::Error: Into + fmt::Display, + ResBody: http_body::Body + Send + 'static, + ResBody::Error: Into + fmt::Display, { - type Response = S::Response; + type Response = Response; type Error = S::Error; type Future = ResponseFuture; @@ -57,7 +59,7 @@ where self.inner.poll_ready(cx) } - fn call(&mut self, req: Request) -> Self::Future { + fn call(&mut self, req: Request) -> Self::Future { match RequestKind::new(req.headers(), req.method(), req.version()) { // A valid grpc-web request, regardless of HTTP version. // @@ -152,9 +154,11 @@ impl Case { } } -impl Future for ResponseFuture +impl Future for ResponseFuture where - F: Future, E>>, + F: Future, E>>, + B: http_body::Body + Send + 'static, + B::Error: Into + fmt::Display, { type Output = Result, E>; @@ -167,7 +171,10 @@ where Poll::Ready(Ok(coerce_response(res, *accept))) } - CaseProj::Other { future } => future.poll(cx), + CaseProj::Other { future } => { + let res = ready!(future.poll(cx))?; + Poll::Ready(Ok(res.map(Body::new))) + } CaseProj::ImmediateResponse { res } => { let res = Response::from_parts(res.take().unwrap(), Body::empty()); Poll::Ready(Ok(res)) @@ -255,16 +262,16 @@ mod tests { #[derive(Debug, Clone)] struct Svc; - impl tower_service::Service> for Svc { + impl tower_service::Service> for Svc { type Response = Response; - type Error = String; + type Error = std::convert::Infallible; type Future = BoxFuture; fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll> { Poll::Ready(Ok(())) } - fn call(&mut self, _: Request) -> Self::Future { + fn call(&mut self, _: Request) -> Self::Future { Box::pin(async { Ok(Response::new(Body::default())) }) } } @@ -313,6 +320,17 @@ mod tests { assert_eq!(res.status(), StatusCode::OK); } + #[tokio::test] + async fn web_layer_with_axum() { + let mut svc = axum::routing::Router::new() + .route("/", axum::routing::post_service(Svc)) + .layer(crate::GrpcWebLayer::new()); + + let res = svc.call(request()).await.unwrap(); + + assert_eq!(res.status(), StatusCode::OK); + } + #[tokio::test] async fn without_origin() { let mut svc = enable(Svc); From 10f005acd25e9d4d2ecd69e287228d27db85ce65 Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Sat, 5 Apr 2025 09:24:35 -0500 Subject: [PATCH 2/2] address feedback --- tonic-web/Cargo.toml | 2 +- tonic-web/src/service.rs | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/tonic-web/Cargo.toml b/tonic-web/Cargo.toml index b656d00ee..487efe709 100644 --- a/tonic-web/Cargo.toml +++ b/tonic-web/Cargo.toml @@ -29,7 +29,7 @@ tracing = "0.1" [dev-dependencies] tokio = { version = "1", features = ["macros", "rt"] } tower-http = { version = "0.6", features = ["cors"] } -axum = "0.8" +axum = { version = "0.8", default-features = false } [lints] workspace = true diff --git a/tonic-web/src/service.rs b/tonic-web/src/service.rs index c463686e0..ab9abc0b8 100644 --- a/tonic-web/src/service.rs +++ b/tonic-web/src/service.rs @@ -171,10 +171,7 @@ where Poll::Ready(Ok(coerce_response(res, *accept))) } - CaseProj::Other { future } => { - let res = ready!(future.poll(cx))?; - Poll::Ready(Ok(res.map(Body::new))) - } + CaseProj::Other { future } => future.poll(cx).map_ok(|res| res.map(Body::new)), CaseProj::ImmediateResponse { res } => { let res = Response::from_parts(res.take().unwrap(), Body::empty()); Poll::Ready(Ok(res))