2
2
3
3
use std:: {
4
4
convert:: Infallible ,
5
+ error:: Error as StdError ,
5
6
fmt:: Debug ,
6
7
future:: { poll_fn, Future , IntoFuture } ,
7
8
io,
@@ -11,6 +12,7 @@ use std::{
11
12
12
13
use axum_core:: { body:: Body , extract:: Request , response:: Response } ;
13
14
use futures_util:: { pin_mut, FutureExt } ;
15
+ use http_body:: Body as HttpBody ;
14
16
use hyper:: body:: Incoming ;
15
17
use hyper_util:: rt:: { TokioExecutor , TokioIo } ;
16
18
#[ cfg( any( feature = "http1" , feature = "http2" ) ) ]
@@ -94,12 +96,15 @@ pub use self::listener::{Listener, ListenerExt, TapIo};
94
96
/// [`HandlerWithoutStateExt::into_make_service_with_connect_info`]: crate::handler::HandlerWithoutStateExt::into_make_service_with_connect_info
95
97
/// [`HandlerService::into_make_service_with_connect_info`]: crate::handler::HandlerService::into_make_service_with_connect_info
96
98
#[ cfg( all( feature = "tokio" , any( feature = "http1" , feature = "http2" ) ) ) ]
97
- pub fn serve < L , M , S > ( listener : L , make_service : M ) -> Serve < L , M , S >
99
+ pub fn serve < L , M , S , B > ( listener : L , make_service : M ) -> Serve < L , M , S , B >
98
100
where
99
101
L : Listener ,
100
102
M : for < ' a > Service < IncomingStream < ' a , L > , Error = Infallible , Response = S > ,
101
- S : Service < Request , Response = Response , Error = Infallible > + Clone + Send + ' static ,
103
+ S : Service < Request , Response = Response < B > , Error = Infallible > + Clone + Send + ' static ,
102
104
S :: Future : Send ,
105
+ B : HttpBody + Send + ' static ,
106
+ B :: Data : Send ,
107
+ B :: Error : Into < Box < dyn StdError + Send + Sync > > ,
103
108
{
104
109
Serve {
105
110
listener,
@@ -111,14 +116,14 @@ where
111
116
/// Future returned by [`serve`].
112
117
#[ cfg( all( feature = "tokio" , any( feature = "http1" , feature = "http2" ) ) ) ]
113
118
#[ must_use = "futures must be awaited or polled" ]
114
- pub struct Serve < L , M , S > {
119
+ pub struct Serve < L , M , S , B > {
115
120
listener : L ,
116
121
make_service : M ,
117
- _marker : PhantomData < S > ,
122
+ _marker : PhantomData < ( S , B ) > ,
118
123
}
119
124
120
125
#[ cfg( all( feature = "tokio" , any( feature = "http1" , feature = "http2" ) ) ) ]
121
- impl < L , M , S > Serve < L , M , S >
126
+ impl < L , M , S , B > Serve < L , M , S , B >
122
127
where
123
128
L : Listener ,
124
129
{
@@ -148,7 +153,7 @@ where
148
153
///
149
154
/// Similarly to [`serve`], although this future resolves to `io::Result<()>`, it will never
150
155
/// error. It returns `Ok(())` only after the `signal` future completes.
151
- pub fn with_graceful_shutdown < F > ( self , signal : F ) -> WithGracefulShutdown < L , M , S , F >
156
+ pub fn with_graceful_shutdown < F > ( self , signal : F ) -> WithGracefulShutdown < L , M , S , F , B >
152
157
where
153
158
F : Future < Output = ( ) > + Send + ' static ,
154
159
{
@@ -167,7 +172,7 @@ where
167
172
}
168
173
169
174
#[ cfg( all( feature = "tokio" , any( feature = "http1" , feature = "http2" ) ) ) ]
170
- impl < L , M , S > Debug for Serve < L , M , S >
175
+ impl < L , M , S , B > Debug for Serve < L , M , S , B >
171
176
where
172
177
L : Debug + ' static ,
173
178
M : Debug ,
@@ -188,14 +193,17 @@ where
188
193
}
189
194
190
195
#[ cfg( all( feature = "tokio" , any( feature = "http1" , feature = "http2" ) ) ) ]
191
- impl < L , M , S > IntoFuture for Serve < L , M , S >
196
+ impl < L , M , S , B > IntoFuture for Serve < L , M , S , B >
192
197
where
193
198
L : Listener ,
194
199
L :: Addr : Debug ,
195
200
M : for < ' a > Service < IncomingStream < ' a , L > , Error = Infallible , Response = S > + Send + ' static ,
196
201
for < ' a > <M as Service < IncomingStream < ' a , L > > >:: Future : Send ,
197
- S : Service < Request , Response = Response , Error = Infallible > + Clone + Send + ' static ,
202
+ S : Service < Request , Response = Response < B > , Error = Infallible > + Clone + Send + ' static ,
198
203
S :: Future : Send ,
204
+ B : HttpBody + Send + ' static ,
205
+ B :: Data : Send ,
206
+ B :: Error : Into < Box < dyn StdError + Send + Sync > > ,
199
207
{
200
208
type Output = io:: Result < ( ) > ;
201
209
type IntoFuture = private:: ServeFuture ;
@@ -209,15 +217,15 @@ where
209
217
/// Serve future with graceful shutdown enabled.
210
218
#[ cfg( all( feature = "tokio" , any( feature = "http1" , feature = "http2" ) ) ) ]
211
219
#[ must_use = "futures must be awaited or polled" ]
212
- pub struct WithGracefulShutdown < L , M , S , F > {
220
+ pub struct WithGracefulShutdown < L , M , S , F , B > {
213
221
listener : L ,
214
222
make_service : M ,
215
223
signal : F ,
216
- _marker : PhantomData < S > ,
224
+ _marker : PhantomData < ( S , B ) > ,
217
225
}
218
226
219
227
#[ cfg( all( feature = "tokio" , any( feature = "http1" , feature = "http2" ) ) ) ]
220
- impl < L , M , S , F > WithGracefulShutdown < L , M , S , F >
228
+ impl < L , M , S , F , B > WithGracefulShutdown < L , M , S , F , B >
221
229
where
222
230
L : Listener ,
223
231
{
@@ -228,7 +236,7 @@ where
228
236
}
229
237
230
238
#[ cfg( all( feature = "tokio" , any( feature = "http1" , feature = "http2" ) ) ) ]
231
- impl < L , M , S , F > Debug for WithGracefulShutdown < L , M , S , F >
239
+ impl < L , M , S , F , B > Debug for WithGracefulShutdown < L , M , S , F , B >
232
240
where
233
241
L : Debug + ' static ,
234
242
M : Debug ,
@@ -252,15 +260,18 @@ where
252
260
}
253
261
254
262
#[ cfg( all( feature = "tokio" , any( feature = "http1" , feature = "http2" ) ) ) ]
255
- impl < L , M , S , F > IntoFuture for WithGracefulShutdown < L , M , S , F >
263
+ impl < L , M , S , F , B > IntoFuture for WithGracefulShutdown < L , M , S , F , B >
256
264
where
257
265
L : Listener ,
258
266
L :: Addr : Debug ,
259
267
M : for < ' a > Service < IncomingStream < ' a , L > , Error = Infallible , Response = S > + Send + ' static ,
260
268
for < ' a > <M as Service < IncomingStream < ' a , L > > >:: Future : Send ,
261
- S : Service < Request , Response = Response , Error = Infallible > + Clone + Send + ' static ,
269
+ S : Service < Request , Response = Response < B > , Error = Infallible > + Clone + Send + ' static ,
262
270
S :: Future : Send ,
263
271
F : Future < Output = ( ) > + Send + ' static ,
272
+ B : HttpBody + Send + ' static ,
273
+ B :: Data : Send ,
274
+ B :: Error : Into < Box < dyn StdError + Send + Sync > > ,
264
275
{
265
276
type Output = io:: Result < ( ) > ;
266
277
type IntoFuture = private:: ServeFuture ;
@@ -274,15 +285,18 @@ where
274
285
}
275
286
276
287
#[ cfg( all( feature = "tokio" , any( feature = "http1" , feature = "http2" ) ) ) ]
277
- impl < L , M , S , F > WithGracefulShutdown < L , M , S , F >
288
+ impl < L , M , S , F , B > WithGracefulShutdown < L , M , S , F , B >
278
289
where
279
290
L : Listener ,
280
291
L :: Addr : Debug ,
281
292
M : for < ' a > Service < IncomingStream < ' a , L > , Error = Infallible , Response = S > + Send + ' static ,
282
293
for < ' a > <M as Service < IncomingStream < ' a , L > > >:: Future : Send ,
283
- S : Service < Request , Response = Response , Error = Infallible > + Clone + Send + ' static ,
294
+ S : Service < Request , Response = Response < B > , Error = Infallible > + Clone + Send + ' static ,
284
295
S :: Future : Send ,
285
296
F : Future < Output = ( ) > + Send + ' static ,
297
+ B : HttpBody + Send + ' static ,
298
+ B :: Data : Send ,
299
+ B :: Error : Into < Box < dyn StdError + Send + Sync > > ,
286
300
{
287
301
async fn run ( self ) {
288
302
let Self {
@@ -439,14 +453,15 @@ mod tests {
439
453
} ;
440
454
441
455
use axum_core:: { body:: Body , extract:: Request } ;
442
- use http:: StatusCode ;
456
+ use http:: { Response , StatusCode } ;
443
457
use hyper_util:: rt:: TokioIo ;
444
458
#[ cfg( unix) ]
445
459
use tokio:: net:: UnixListener ;
446
460
use tokio:: {
447
461
io:: { self , AsyncRead , AsyncWrite } ,
448
462
net:: TcpListener ,
449
463
} ;
464
+ use tower:: ServiceBuilder ;
450
465
451
466
#[ cfg( unix) ]
452
467
use super :: IncomingStream ;
@@ -458,7 +473,7 @@ mod tests {
458
473
handler:: { Handler , HandlerWithoutStateExt } ,
459
474
routing:: get,
460
475
serve:: ListenerExt ,
461
- Router ,
476
+ Router , ServiceExt ,
462
477
} ;
463
478
464
479
#[ allow( dead_code, unused_must_use) ]
@@ -686,4 +701,31 @@ mod tests {
686
701
let body = String :: from_utf8 ( body. to_vec ( ) ) . unwrap ( ) ;
687
702
assert_eq ! ( body, "Hello, World!" ) ;
688
703
}
704
+
705
+ #[ crate :: test]
706
+ async fn serving_with_custom_body_type ( ) {
707
+ struct CustomBody ;
708
+ impl http_body:: Body for CustomBody {
709
+ type Data = bytes:: Bytes ;
710
+ type Error = std:: convert:: Infallible ;
711
+ fn poll_frame (
712
+ self : std:: pin:: Pin < & mut Self > ,
713
+ _cx : & mut std:: task:: Context < ' _ > ,
714
+ ) -> std:: task:: Poll < Option < Result < http_body:: Frame < Self :: Data > , Self :: Error > > >
715
+ {
716
+ #![ allow( clippy:: unreachable) ] // The implementation is not used, we just need to provide one.
717
+ unreachable ! ( ) ;
718
+ }
719
+ }
720
+
721
+ let app = ServiceBuilder :: new ( )
722
+ . layer_fn ( |_| tower:: service_fn ( |_| std:: future:: ready ( Ok ( Response :: new ( CustomBody ) ) ) ) )
723
+ . service ( Router :: < ( ) > :: new ( ) . route ( "/hello" , get ( || async { } ) ) ) ;
724
+ let addr = "0.0.0.0:0" ;
725
+
726
+ _ = serve (
727
+ TcpListener :: bind ( addr) . await . unwrap ( ) ,
728
+ app. into_make_service ( ) ,
729
+ ) ;
730
+ }
689
731
}
0 commit comments