@@ -6,13 +6,15 @@ use std::task::{ready, Context, Poll};
6
6
use http:: { header, HeaderMap , HeaderValue , Method , Request , Response , StatusCode , Version } ;
7
7
use pin_project:: pin_project;
8
8
use tonic:: metadata:: GRPC_CONTENT_TYPE ;
9
- use tonic:: { body :: Body , server:: NamedService } ;
9
+ use tonic:: server:: NamedService ;
10
10
use tower_service:: Service ;
11
11
use tracing:: { debug, trace} ;
12
12
13
13
use crate :: call:: content_types:: is_grpc_web;
14
14
use crate :: call:: { Encoding , GrpcWebCall } ;
15
15
16
+ use bytes:: Bytes ;
17
+
16
18
/// Service implementing the grpc-web protocol.
17
19
#[ derive( Debug , Clone ) ]
18
20
pub struct GrpcWebService < S > {
@@ -45,9 +47,9 @@ impl<S> GrpcWebService<S> {
45
47
46
48
impl < S , B > Service < Request < B > > for GrpcWebService < S >
47
49
where
48
- S : Service < Request < Body > , Response = Response < Body > > ,
49
- B : http_body:: Body < Data = bytes:: Bytes > + Send + ' static ,
50
- B :: Error : Into < crate :: BoxError > + fmt:: Display ,
50
+ S : Service < Request < B > , Response = Response < B > > ,
51
+ B : http_body:: Body < Data = bytes:: Bytes > + BoxedBody + Send + ' static ,
52
+ B :: Error : Into < crate :: BoxError > + std :: error :: Error + fmt:: Display + Send + Sync ,
51
53
{
52
54
type Response = S :: Response ;
53
55
type Error = S :: Error ;
@@ -100,7 +102,7 @@ where
100
102
debug ! ( kind = "other h2" , content_type = ?req. headers( ) . get( header:: CONTENT_TYPE ) ) ;
101
103
ResponseFuture {
102
104
case : Case :: Other {
103
- future : self . inner . call ( req. map ( Body :: new) ) ,
105
+ future : self . inner . call ( req. map ( B :: new) ) ,
104
106
} ,
105
107
}
106
108
}
@@ -152,11 +154,13 @@ impl<F> Case<F> {
152
154
}
153
155
}
154
156
155
- impl < F , E > Future for ResponseFuture < F >
157
+ impl < F , E , A > Future for ResponseFuture < F >
156
158
where
157
- F : Future < Output = Result < Response < Body > , E > > ,
159
+ F : Future < Output = Result < Response < A > , E > > ,
160
+ A : BoxedBody + ' static ,
161
+ <A as http_body:: Body >:: Error : std:: error:: Error + Send + Sync + ' static ,
158
162
{
159
- type Output = Result < Response < Body > , E > ;
163
+ type Output = Result < Response < A > , E > ;
160
164
161
165
fn poll ( self : Pin < & mut Self > , cx : & mut Context < ' _ > ) -> Poll < Self :: Output > {
162
166
let mut this = self . project ( ) ;
@@ -169,7 +173,7 @@ where
169
173
}
170
174
CaseProj :: Other { future } => future. poll ( cx) ,
171
175
CaseProj :: ImmediateResponse { res } => {
172
- let res = Response :: from_parts ( res. take ( ) . unwrap ( ) , Body :: empty ( ) ) ;
176
+ let res = Response :: from_parts ( res. take ( ) . unwrap ( ) , A :: empty ( ) ) ;
173
177
Poll :: Ready ( Ok ( res) )
174
178
}
175
179
}
@@ -203,9 +207,9 @@ impl<'a> RequestKind<'a> {
203
207
// Mutating request headers to conform to a gRPC request is not really
204
208
// necessary for us at this point. We could remove most of these except
205
209
// maybe for inserting `header::TE`, which tonic should check?
206
- fn coerce_request < B > ( mut req : Request < B > , encoding : Encoding ) -> Request < Body >
210
+ fn coerce_request < B > ( mut req : Request < B > , encoding : Encoding ) -> Request < B >
207
211
where
208
- B : http_body:: Body < Data = bytes:: Bytes > + Send + ' static ,
212
+ B : http_body:: Body < Data = bytes:: Bytes > + BoxedBody + Send + ' static ,
209
213
B :: Error : Into < crate :: BoxError > + fmt:: Display ,
210
214
{
211
215
req. headers_mut ( ) . remove ( header:: CONTENT_LENGTH ) ;
@@ -221,17 +225,15 @@ where
221
225
HeaderValue :: from_static ( "identity,deflate,gzip" ) ,
222
226
) ;
223
227
224
- req. map ( |b| Body :: new ( GrpcWebCall :: request ( b, encoding) ) )
228
+ req. map ( |b| B :: new ( GrpcWebCall :: request ( b, encoding) ) )
225
229
}
226
230
227
- fn coerce_response < B > ( res : Response < B > , encoding : Encoding ) -> Response < Body >
231
+ fn coerce_response < B > ( res : Response < B > , encoding : Encoding ) -> Response < B >
228
232
where
229
- B : http_body:: Body < Data = bytes:: Bytes > + Send + ' static ,
233
+ B : http_body:: Body < Data = bytes:: Bytes > + BoxedBody + Send + ' static ,
230
234
B :: Error : Into < crate :: BoxError > + fmt:: Display ,
231
235
{
232
- let mut res = res
233
- . map ( |b| GrpcWebCall :: response ( b, encoding) )
234
- . map ( Body :: new) ;
236
+ let mut res = res. map ( |b| GrpcWebCall :: response ( b, encoding) ) . map ( B :: new) ;
235
237
236
238
res. headers_mut ( ) . insert (
237
239
header:: CONTENT_TYPE ,
@@ -241,6 +243,45 @@ where
241
243
res
242
244
}
243
245
246
+ /// Alias for a type-erased error type.
247
+ type BoxError = Box < dyn std:: error:: Error + Send + Sync > ;
248
+
249
+ trait BoxedBody : http_body:: Body < Data = bytes:: Bytes > + Send {
250
+ fn new < B > ( body : B ) -> Self
251
+ where
252
+ B : http_body:: Body < Data = Bytes > + Send + ' static ,
253
+ B :: Error : Into < BoxError > ;
254
+
255
+ fn empty ( ) -> Self ;
256
+ }
257
+
258
+ impl BoxedBody for tonic:: body:: Body {
259
+ fn new < B > ( body : B ) -> Self
260
+ where
261
+ B : http_body:: Body < Data = Bytes > + Send + ' static ,
262
+ B :: Error : Into < BoxError > ,
263
+ {
264
+ Self :: new ( body)
265
+ }
266
+
267
+ fn empty ( ) -> Self {
268
+ Self :: empty ( )
269
+ }
270
+ }
271
+ #[ cfg( feature = "axum" ) ]
272
+ impl BoxedBody for axum:: body:: Body {
273
+ fn new < B > ( body : B ) -> Self
274
+ where
275
+ B : http_body:: Body < Data = Bytes > + Send + ' static ,
276
+ B :: Error : Into < BoxError > ,
277
+ {
278
+ Self :: new ( body)
279
+ }
280
+
281
+ fn empty ( ) -> Self {
282
+ Self :: empty ( )
283
+ }
284
+ }
244
285
#[ cfg( test) ]
245
286
mod tests {
246
287
use super :: * ;
0 commit comments