Skip to content

Commit 3486d80

Browse files
committed
tonic: Use BoxBody from http-body crate
As of `http-body` 0.4.1 its has had a `BoxBody` type similar to `tonic::body::BoxBody`. It also has `Empty` and `Body::map_{data,err}`. That means all the custom body things we had in tonic can basically be replaced with that. Note that this is a breaking change so we should merge this next time we decide to ship a breaking release. The breaking changes are: - `tonic::body::Body` has been removed. I think its fine for users to depend directly on `http-body` if they need this trait. - `tonic::body::BoxBody` is now just a type alias for `http_body::combinators::BoxBody<Bytes, Status>`. So the methods it previously had are gone. The replacements are - `tonic::body::Body::new` -> `http_body::Body::boxed` - `tonic::body::Body::map_from` -> `http_body::Body::map_data` and `http_body::Body::map_err` depending on which part you want to map. - `tonic::body::Body::empty` -> `http_body::Empty` Additionally a `Sync` bound has been added to a few methods. I actually don't think this is a breaking change because the old `tonic::body::Body` trait had `Sync` as a supertrait meaning the `Sync` requirement was already there. Fixes #557
1 parent 7f1af64 commit 3486d80

File tree

13 files changed

+49
-250
lines changed

13 files changed

+49
-250
lines changed

tonic-build/src/client.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@ pub fn generate<T: Service>(
3737

3838
impl<T> #service_ident<T>
3939
where T: tonic::client::GrpcService<tonic::body::BoxBody>,
40-
T::ResponseBody: Body + HttpBody + Send + 'static,
40+
T::ResponseBody: Body + Send + Sync + 'static,
4141
T::Error: Into<StdError>,
42-
<T::ResponseBody as HttpBody>::Error: Into<StdError> + Send, {
42+
<T::ResponseBody as Body>::Error: Into<StdError> + Send, {
4343
pub fn new(inner: T) -> Self {
4444
let inner = tonic::client::Grpc::new(inner);
4545
Self { inner }

tonic-build/src/server.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ pub fn generate<T: Service>(
6969
impl<T, B> Service<http::Request<B>> for #server_service<T>
7070
where
7171
T: #server_trait,
72-
B: HttpBody + Send + Sync + 'static,
72+
B: Body + Send + Sync + 'static,
7373
B::Error: Into<StdError> + Send + 'static,
7474
{
7575
type Response = http::Response<tonic::body::BoxBody>;
@@ -91,7 +91,7 @@ pub fn generate<T: Service>(
9191
.status(200)
9292
.header("grpc-status", "12")
9393
.header("content-type", "application/grpc")
94-
.body(tonic::body::BoxBody::empty())
94+
.body(empty_body())
9595
.unwrap())
9696
}),
9797
}

tonic-reflection/tests/proto/grpc.reflection.v1alpha.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -166,9 +166,9 @@ pub mod server_reflection_client {
166166
impl<T> ServerReflectionClient<T>
167167
where
168168
T: tonic::client::GrpcService<tonic::body::BoxBody>,
169-
T::ResponseBody: Body + HttpBody + Send + 'static,
169+
T::ResponseBody: Body + Body + Send + 'static,
170170
T::Error: Into<StdError>,
171-
<T::ResponseBody as HttpBody>::Error: Into<StdError> + Send,
171+
<T::ResponseBody as Body>::Error: Into<StdError> + Send,
172172
{
173173
pub fn new(inner: T) -> Self {
174174
let inner = tonic::client::Grpc::new(inner);
@@ -254,7 +254,7 @@ pub mod server_reflection_server {
254254
impl<T, B> Service<http::Request<B>> for ServerReflectionServer<T>
255255
where
256256
T: ServerReflection,
257-
B: HttpBody + Send + Sync + 'static,
257+
B: Body + Send + Sync + 'static,
258258
B::Error: Into<StdError> + Send + 'static,
259259
{
260260
type Response = http::Response<tonic::body::BoxBody>;
@@ -309,7 +309,7 @@ pub mod server_reflection_server {
309309
.status(200)
310310
.header("grpc-status", "12")
311311
.header("content-type", "application/grpc")
312-
.body(tonic::body::BoxBody::empty())
312+
.body(empty_body())
313313
.unwrap())
314314
}),
315315
}

tonic-reflection/tests/proto/mod.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -166,9 +166,9 @@ pub mod server_reflection_client {
166166
impl<T> ServerReflectionClient<T>
167167
where
168168
T: tonic::client::GrpcService<tonic::body::BoxBody>,
169-
T::ResponseBody: Body + HttpBody + Send + 'static,
169+
T::ResponseBody: Body + Send + 'static,
170170
T::Error: Into<StdError>,
171-
<T::ResponseBody as HttpBody>::Error: Into<StdError> + Send,
171+
<T::ResponseBody as Body>::Error: Into<StdError> + Send,
172172
{
173173
pub fn new(inner: T) -> Self {
174174
let inner = tonic::client::Grpc::new(inner);
@@ -254,7 +254,7 @@ pub mod server_reflection_server {
254254
impl<T, B> Service<http::Request<B>> for ServerReflectionServer<T>
255255
where
256256
T: ServerReflection,
257-
B: HttpBody + Send + Sync + 'static,
257+
B: Body + Send + Sync + 'static,
258258
B::Error: Into<StdError> + Send + 'static,
259259
{
260260
type Response = http::Response<tonic::body::BoxBody>;
@@ -309,7 +309,7 @@ pub mod server_reflection_server {
309309
.status(200)
310310
.header("grpc-status", "12")
311311
.header("content-type", "application/grpc")
312-
.body(tonic::body::BoxBody::empty())
312+
.body(empty_body())
313313
.unwrap())
314314
}),
315315
}

tonic/benches-disabled/benchmarks/compiled_protos/helloworld.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ pub mod client {
3232
impl<T> GreeterClient<T>
3333
where
3434
T: tonic::client::GrpcService<tonic::body::BoxBody>,
35-
T::ResponseBody: Body + HttpBody + Send + 'static,
35+
T::ResponseBody: Body + Send + 'static,
3636
T::Error: Into<StdError>,
37-
<T::ResponseBody as HttpBody>::Error: Into<StdError> + Send,
38-
<T::ResponseBody as HttpBody>::Data: Into<bytes::Bytes> + Send,
37+
<T::ResponseBody as Body>::Error: Into<StdError> + Send,
38+
<T::ResponseBody as Body>::Data: Into<bytes::Bytes> + Send,
3939
{
4040
pub fn new(inner: T) -> Self {
4141
let inner = tonic::client::Grpc::new(inner);
@@ -158,7 +158,7 @@ pub mod server {
158158
Ok(http::Response::builder()
159159
.status(200)
160160
.header("grpc-status", "12")
161-
.body(tonic::body::BoxBody::empty())
161+
.body(empty_body())
162162
.unwrap())
163163
}),
164164
}

tonic/src/body.rs

+7-213
Original file line numberDiff line numberDiff line change
@@ -1,218 +1,12 @@
11
//! HTTP specific body utilities.
2-
//!
3-
//! This module contains traits and helper types to work with http bodies. Most
4-
//! of the types in this module are based around [`http_body::Body`].
52
6-
use crate::{Error, Status};
7-
use bytes::{Buf, Bytes};
8-
use http_body::Body as HttpBody;
9-
use std::{
10-
fmt,
11-
pin::Pin,
12-
task::{Context, Poll},
13-
};
3+
use crate::Status;
4+
use bytes::Bytes;
5+
use http_body::{Body, Empty};
146

15-
/// A trait alias for [`http_body::Body`].
16-
pub trait Body: sealed::Sealed + Send + Sync {
17-
/// The body data type.
18-
type Data: Buf;
19-
/// The errors produced from the body.
20-
type Error: Into<Error>;
7+
/// A type erased HTTP body used for tonic services.
8+
pub type BoxBody = http_body::combinators::BoxBody<Bytes, Status>;
219

22-
/// Check if the stream is over or not.
23-
///
24-
/// Reference [`http_body::Body::is_end_stream`].
25-
fn is_end_stream(&self) -> bool;
26-
27-
/// Poll for more data from the body.
28-
///
29-
/// Reference [`http_body::Body::poll_data`].
30-
fn poll_data(
31-
self: Pin<&mut Self>,
32-
cx: &mut Context<'_>,
33-
) -> Poll<Option<Result<Self::Data, Self::Error>>>;
34-
35-
/// Poll for the trailing headers.
36-
///
37-
/// Reference [`http_body::Body::poll_trailers`].
38-
fn poll_trailers(
39-
self: Pin<&mut Self>,
40-
cx: &mut Context<'_>,
41-
) -> Poll<Result<Option<http::HeaderMap>, Self::Error>>;
42-
}
43-
44-
impl<T> Body for T
45-
where
46-
T: HttpBody + Send + Sync + 'static,
47-
T::Error: Into<Error>,
48-
{
49-
type Data = T::Data;
50-
type Error = T::Error;
51-
52-
fn is_end_stream(&self) -> bool {
53-
HttpBody::is_end_stream(self)
54-
}
55-
56-
fn poll_data(
57-
self: Pin<&mut Self>,
58-
cx: &mut Context<'_>,
59-
) -> Poll<Option<Result<Self::Data, Self::Error>>> {
60-
HttpBody::poll_data(self, cx)
61-
}
62-
63-
fn poll_trailers(
64-
self: Pin<&mut Self>,
65-
cx: &mut Context<'_>,
66-
) -> Poll<Result<Option<http::HeaderMap>, Self::Error>> {
67-
HttpBody::poll_trailers(self, cx)
68-
}
69-
}
70-
71-
impl<T> sealed::Sealed for T
72-
where
73-
T: HttpBody,
74-
T::Error: Into<Error>,
75-
{
76-
}
77-
78-
mod sealed {
79-
pub trait Sealed {}
80-
}
81-
82-
/// A type erased http body.
83-
pub struct BoxBody {
84-
inner: Pin<Box<dyn Body<Data = Bytes, Error = Status> + Send + Sync + 'static>>,
85-
}
86-
87-
struct MapBody<B>(B);
88-
89-
impl BoxBody {
90-
/// Create a new `BoxBody` mapping item and error to the default types.
91-
pub fn new<B>(inner: B) -> Self
92-
where
93-
B: Body<Data = Bytes, Error = Status> + Send + Sync + 'static,
94-
{
95-
BoxBody {
96-
inner: Box::pin(inner),
97-
}
98-
}
99-
100-
/// Create a new `BoxBody` mapping item and error to the default types.
101-
pub fn map_from<B>(inner: B) -> Self
102-
where
103-
B: Body + Send + Sync + 'static,
104-
B::Error: Into<crate::Error>,
105-
{
106-
BoxBody {
107-
inner: Box::pin(MapBody(inner)),
108-
}
109-
}
110-
111-
/// Create a new `BoxBody` that is empty.
112-
pub fn empty() -> Self {
113-
BoxBody {
114-
inner: Box::pin(EmptyBody::default()),
115-
}
116-
}
117-
}
118-
119-
impl HttpBody for BoxBody {
120-
type Data = Bytes;
121-
type Error = Status;
122-
123-
fn is_end_stream(&self) -> bool {
124-
self.inner.is_end_stream()
125-
}
126-
127-
fn poll_data(
128-
mut self: Pin<&mut Self>,
129-
cx: &mut Context<'_>,
130-
) -> Poll<Option<Result<Self::Data, Self::Error>>> {
131-
Body::poll_data(self.inner.as_mut(), cx)
132-
}
133-
134-
fn poll_trailers(
135-
mut self: Pin<&mut Self>,
136-
cx: &mut Context<'_>,
137-
) -> Poll<Result<Option<http::HeaderMap>, Self::Error>> {
138-
Body::poll_trailers(self.inner.as_mut(), cx)
139-
}
140-
}
141-
142-
impl<B> HttpBody for MapBody<B>
143-
where
144-
B: Body,
145-
B::Error: Into<crate::Error>,
146-
{
147-
type Data = Bytes;
148-
type Error = Status;
149-
150-
fn is_end_stream(&self) -> bool {
151-
self.0.is_end_stream()
152-
}
153-
154-
fn poll_data(
155-
self: Pin<&mut Self>,
156-
cx: &mut Context<'_>,
157-
) -> Poll<Option<Result<Self::Data, Self::Error>>> {
158-
let v = unsafe {
159-
let me = self.get_unchecked_mut();
160-
Pin::new_unchecked(&mut me.0).poll_data(cx)
161-
};
162-
match futures_util::ready!(v) {
163-
Some(Ok(mut i)) => Poll::Ready(Some(Ok(i.copy_to_bytes(i.remaining())))),
164-
Some(Err(e)) => {
165-
let err = Status::map_error(e.into());
166-
Poll::Ready(Some(Err(err)))
167-
}
168-
None => Poll::Ready(None),
169-
}
170-
}
171-
172-
fn poll_trailers(
173-
self: Pin<&mut Self>,
174-
cx: &mut Context<'_>,
175-
) -> Poll<Result<Option<http::HeaderMap>, Self::Error>> {
176-
let v = unsafe {
177-
let me = self.get_unchecked_mut();
178-
Pin::new_unchecked(&mut me.0).poll_trailers(cx)
179-
};
180-
181-
let v = futures_util::ready!(v).map_err(|e| Status::from_error(&*e.into()));
182-
Poll::Ready(v)
183-
}
184-
}
185-
186-
impl fmt::Debug for BoxBody {
187-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
188-
f.debug_struct("BoxBody").finish()
189-
}
190-
}
191-
192-
#[derive(Debug, Default)]
193-
struct EmptyBody {
194-
_p: (),
195-
}
196-
197-
impl HttpBody for EmptyBody {
198-
type Data = Bytes;
199-
type Error = Status;
200-
201-
fn is_end_stream(&self) -> bool {
202-
true
203-
}
204-
205-
fn poll_data(
206-
self: Pin<&mut Self>,
207-
_cx: &mut Context<'_>,
208-
) -> Poll<Option<Result<Self::Data, Self::Error>>> {
209-
Poll::Ready(None)
210-
}
211-
212-
fn poll_trailers(
213-
self: Pin<&mut Self>,
214-
_cx: &mut Context<'_>,
215-
) -> Poll<Result<Option<http::HeaderMap>, Self::Error>> {
216-
Poll::Ready(Ok(None))
217-
}
10+
pub(crate) fn empty() -> BoxBody {
11+
Empty::new().map_err(|err| match err {}).boxed()
21812
}

tonic/src/client/grpc.rs

+10-10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::{
2-
body::{Body, BoxBody},
2+
body::BoxBody,
33
client::GrpcService,
44
codec::{encode_client, Codec, Streaming},
55
interceptor::Interceptor,
@@ -11,7 +11,7 @@ use http::{
1111
header::{HeaderValue, CONTENT_TYPE, TE},
1212
uri::{Parts, PathAndQuery, Uri},
1313
};
14-
use http_body::Body as HttpBody;
14+
use http_body::Body;
1515
use std::fmt;
1616

1717
/// A gRPC client dispatcher.
@@ -71,8 +71,8 @@ impl<T> Grpc<T> {
7171
) -> Result<Response<M2>, Status>
7272
where
7373
T: GrpcService<BoxBody>,
74-
T::ResponseBody: Body + HttpBody + Send + 'static,
75-
<T::ResponseBody as HttpBody>::Error: Into<crate::Error>,
74+
T::ResponseBody: Body + Send + Sync + 'static,
75+
<T::ResponseBody as Body>::Error: Into<crate::Error>,
7676
C: Codec<Encode = M1, Decode = M2>,
7777
M1: Send + Sync + 'static,
7878
M2: Send + Sync + 'static,
@@ -90,8 +90,8 @@ impl<T> Grpc<T> {
9090
) -> Result<Response<M2>, Status>
9191
where
9292
T: GrpcService<BoxBody>,
93-
T::ResponseBody: Body + HttpBody + Send + 'static,
94-
<T::ResponseBody as HttpBody>::Error: Into<crate::Error>,
93+
T::ResponseBody: Body + Send + Sync + 'static,
94+
<T::ResponseBody as Body>::Error: Into<crate::Error>,
9595
S: Stream<Item = M1> + Send + Sync + 'static,
9696
C: Codec<Encode = M1, Decode = M2>,
9797
M1: Send + Sync + 'static,
@@ -126,8 +126,8 @@ impl<T> Grpc<T> {
126126
) -> Result<Response<Streaming<M2>>, Status>
127127
where
128128
T: GrpcService<BoxBody>,
129-
T::ResponseBody: Body + HttpBody + Send + 'static,
130-
<T::ResponseBody as HttpBody>::Error: Into<crate::Error>,
129+
T::ResponseBody: Body + Send + Sync + 'static,
130+
<T::ResponseBody as Body>::Error: Into<crate::Error>,
131131
C: Codec<Encode = M1, Decode = M2>,
132132
M1: Send + Sync + 'static,
133133
M2: Send + Sync + 'static,
@@ -145,8 +145,8 @@ impl<T> Grpc<T> {
145145
) -> Result<Response<Streaming<M2>>, Status>
146146
where
147147
T: GrpcService<BoxBody>,
148-
T::ResponseBody: Body + HttpBody + Send + 'static,
149-
<T::ResponseBody as HttpBody>::Error: Into<crate::Error>,
148+
T::ResponseBody: Body + Send + Sync + 'static,
149+
<T::ResponseBody as Body>::Error: Into<crate::Error>,
150150
S: Stream<Item = M1> + Send + Sync + 'static,
151151
C: Codec<Encode = M1, Decode = M2>,
152152
M1: Send + Sync + 'static,

0 commit comments

Comments
 (0)