1use std::fmt;
2use std::pin::Pin;
3use std::task::{Context, Poll};
4
5use bytes::Bytes;
6#[cfg(all(
7 any(feature = "http1", feature = "http2"),
8 any(feature = "client", feature = "server")
9))]
10use futures_core::ready;
11use http_body::{Body, Frame, SizeHint};
12
13#[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
14use super::chan;
15#[cfg(all(
16 any(feature = "http1", feature = "http2"),
17 any(feature = "client", feature = "server")
18))]
19use super::DecodedLength;
20#[cfg(all(feature = "http2", any(feature = "client", feature = "server")))]
21use crate::proto::h2::ping;
22
23#[must_use = "streams do nothing unless polled"]
39pub struct Incoming {
40 kind: Kind,
41}
42
43enum Kind {
44 Empty,
45 #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
46 Chan {
47 content_length: DecodedLength,
48 rx: chan::Receiver,
49 },
50 #[cfg(all(feature = "http2", any(feature = "client", feature = "server")))]
51 H2 {
52 content_length: DecodedLength,
53 data_done: bool,
54 ping: ping::Recorder,
55 recv: h2::RecvStream,
56 },
57 #[cfg(feature = "ffi")]
58 Ffi(crate::ffi::UserBody),
59}
60
61#[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
75pub(crate) use super::chan::Sender;
76
77impl Incoming {
78 #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
82 #[inline]
83 #[cfg(test)]
84 pub(crate) fn channel() -> (Sender, Incoming) {
85 Self::new_channel(DecodedLength::CHUNKED, false)
86 }
87
88 #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
89 pub(crate) fn new_channel(content_length: DecodedLength, wanter: bool) -> (Sender, Incoming) {
90 let (tx, rx) = chan::channel(wanter);
91 let rx = Incoming::new(Kind::Chan { content_length, rx });
92
93 (tx, rx)
94 }
95
96 fn new(kind: Kind) -> Incoming {
97 Incoming { kind }
98 }
99
100 #[allow(dead_code)]
101 pub(crate) fn empty() -> Incoming {
102 Incoming::new(Kind::Empty)
103 }
104
105 #[cfg(feature = "ffi")]
106 pub(crate) fn ffi() -> Incoming {
107 Incoming::new(Kind::Ffi(crate::ffi::UserBody::new()))
108 }
109
110 #[cfg(all(feature = "http2", any(feature = "client", feature = "server")))]
111 pub(crate) fn h2(
112 recv: h2::RecvStream,
113 mut content_length: DecodedLength,
114 ping: ping::Recorder,
115 ) -> Self {
116 if !content_length.is_exact() && recv.is_end_stream() {
119 content_length = DecodedLength::ZERO;
120 }
121
122 Incoming::new(Kind::H2 {
123 data_done: false,
124 ping,
125 content_length,
126 recv,
127 })
128 }
129
130 #[cfg(feature = "ffi")]
131 pub(crate) fn as_ffi_mut(&mut self) -> &mut crate::ffi::UserBody {
132 if !matches!(self.kind, Kind::Ffi(_)) {
133 self.kind = Kind::Ffi(crate::ffi::UserBody::new());
134 }
135
136 match &mut self.kind {
137 Kind::Ffi(body) => body,
138 _ => unreachable!(),
139 }
140 }
141}
142
143impl Body for Incoming {
144 type Data = Bytes;
145 type Error = crate::Error;
146
147 fn poll_frame(
148 #[cfg_attr(
149 not(all(
150 any(feature = "http1", feature = "http2"),
151 any(feature = "client", feature = "server")
152 )),
153 allow(unused_mut)
154 )]
155 mut self: Pin<&mut Self>,
156 #[cfg_attr(
157 not(all(
158 any(feature = "http1", feature = "http2"),
159 any(feature = "client", feature = "server")
160 )),
161 allow(unused_variables)
162 )]
163 cx: &mut Context<'_>,
164 ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
165 match &mut self.kind {
166 Kind::Empty => Poll::Ready(None),
167 #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
168 Kind::Chan {
169 content_length: len,
170 rx,
171 } => {
172 if let Some(chunk) = ready!(rx.poll_next(cx)?) {
173 len.sub_if(chunk.len() as u64);
174 return Poll::Ready(Some(Ok(Frame::data(chunk))));
175 }
176 Poll::Ready(rx.take_trailers().map(Frame::trailers).map(Ok))
177 }
178 #[cfg(all(feature = "http2", any(feature = "client", feature = "server")))]
179 Kind::H2 {
180 data_done,
181 ping,
182 recv: h2,
183 content_length: len,
184 } => {
185 if !*data_done {
186 match ready!(h2.poll_data(cx)) {
187 Some(Ok(bytes)) => {
188 let _ = h2.flow_control().release_capacity(bytes.len());
189 len.sub_if(bytes.len() as u64);
190 ping.record_data(bytes.len());
191 return Poll::Ready(Some(Ok(Frame::data(bytes))));
192 }
193 Some(Err(e)) => {
194 if let Some(h2::Reason::NO_ERROR) = e.reason() {
195 return Poll::Ready(None);
199 } else {
200 return Poll::Ready(Some(Err(crate::Error::new_body(e))));
201 }
202 }
203 None => {
204 *data_done = true;
205 }
207 }
208 }
209
210 match ready!(h2.poll_trailers(cx)) {
212 Ok(t) => {
213 ping.record_non_data();
214 Poll::Ready(Ok(t.map(Frame::trailers)).transpose())
215 }
216 Err(e) => {
217 if let Some(h2::Reason::NO_ERROR) = e.reason() {
218 Poll::Ready(None)
222 } else {
223 Poll::Ready(Some(Err(crate::Error::new_h2(e))))
224 }
225 }
226 }
227 }
228
229 #[cfg(feature = "ffi")]
230 Kind::Ffi(body) => body.poll_data(cx),
231 }
232 }
233
234 fn is_end_stream(&self) -> bool {
235 match &self.kind {
236 Kind::Empty => true,
237 #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
238 Kind::Chan { content_length, .. } => *content_length == DecodedLength::ZERO,
239 #[cfg(all(feature = "http2", any(feature = "client", feature = "server")))]
240 Kind::H2 { recv: h2, .. } => h2.is_end_stream(),
241 #[cfg(feature = "ffi")]
242 Kind::Ffi(..) => false,
243 }
244 }
245
246 fn size_hint(&self) -> SizeHint {
247 #[cfg(all(
248 any(feature = "http1", feature = "http2"),
249 any(feature = "client", feature = "server")
250 ))]
251 fn opt_len(decoded_length: DecodedLength) -> SizeHint {
252 if let Some(content_length) = decoded_length.into_opt() {
253 SizeHint::with_exact(content_length)
254 } else {
255 SizeHint::default()
256 }
257 }
258
259 match self.kind {
260 Kind::Empty => SizeHint::with_exact(0),
261 #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
262 Kind::Chan { content_length, .. } => opt_len(content_length),
263 #[cfg(all(feature = "http2", any(feature = "client", feature = "server")))]
264 Kind::H2 { content_length, .. } => opt_len(content_length),
265 #[cfg(feature = "ffi")]
266 Kind::Ffi(..) => SizeHint::default(),
267 }
268 }
269}
270
271impl fmt::Debug for Incoming {
272 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
273 #[cfg(any(
274 all(
275 any(feature = "http1", feature = "http2"),
276 any(feature = "client", feature = "server")
277 ),
278 feature = "ffi"
279 ))]
280 #[derive(Debug)]
281 struct Streaming;
282 #[derive(Debug)]
283 struct Empty;
284
285 let mut builder = f.debug_tuple("Body");
286 match self.kind {
287 Kind::Empty => builder.field(&Empty),
288 #[cfg(any(
289 all(
290 any(feature = "http1", feature = "http2"),
291 any(feature = "client", feature = "server")
292 ),
293 feature = "ffi"
294 ))]
295 _ => builder.field(&Streaming),
296 };
297
298 builder.finish()
299 }
300}
301
302#[cfg(test)]
303mod tests {
304 #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
305 use std::mem;
306 #[cfg(all(feature = "nightly", not(miri)))]
307 use std::pin::Pin;
308 #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
309 use std::task::Poll;
310
311 #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
312 use super::{Body, Incoming, SizeHint};
313 #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
314 use super::{DecodedLength, Sender};
315 #[cfg(all(feature = "nightly", not(miri)))]
316 use bytes::Bytes;
317 #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
318 use http_body_util::BodyExt;
319
320 #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
321 #[test]
322 fn test_size_of() {
323 let body_size = mem::size_of::<Incoming>();
327 let body_expected_size = mem::size_of::<u64>() * 5;
328 assert!(
329 body_size <= body_expected_size,
330 "Body size = {} <= {}",
331 body_size,
332 body_expected_size,
333 );
334
335 assert_eq!(
336 mem::size_of::<Sender>(),
337 mem::size_of::<usize>() * 2,
338 "Sender"
339 );
340
341 assert_eq!(
342 mem::size_of::<Sender>(),
343 mem::size_of::<Option<Sender>>(),
344 "Option<Sender>"
345 );
346 }
347
348 #[cfg(all(feature = "nightly", not(miri)))]
349 #[bench]
350 fn bench_channel_create_and_drop(b: &mut test::Bencher) {
351 b.iter(|| {
352 let _ = test::black_box(Incoming::new_channel(
353 DecodedLength::CHUNKED,
354 false,
355 ));
356 });
357 }
358
359 #[cfg(all(feature = "nightly", not(miri)))]
360 #[bench]
361 fn bench_channel_data_handoff(b: &mut test::Bencher) {
362 let (mut tx, mut body) =
363 Incoming::new_channel(DecodedLength::CHUNKED, false);
364 let mut cx = std::task::Context::from_waker(std::task::Waker::noop());
365
366 b.iter(|| {
367 assert!(tx.poll_ready(&mut cx).is_ready());
368 tx.try_send_data(Bytes::from_static(b"hello world"))
369 .unwrap();
370 let frame = match Pin::new(&mut body).poll_frame(&mut cx) {
371 Poll::Ready(Some(Ok(frame))) => frame,
372 unexpected => panic!("unexpected body poll: {unexpected:?}"),
373 };
374 test::black_box(frame);
375 });
376 }
377
378 #[cfg(all(feature = "nightly", not(miri)))]
379 #[bench]
380 fn bench_channel_want_transition(b: &mut test::Bencher) {
381 let mut cx = std::task::Context::from_waker(std::task::Waker::noop());
382
383 b.iter(|| {
384 let (mut tx, mut body) =
385 Incoming::new_channel(DecodedLength::CHUNKED, true);
386 assert!(tx.poll_ready(&mut cx).is_pending());
387 assert!(Pin::new(&mut body).poll_frame(&mut cx).is_pending());
388 assert!(tx.poll_ready(&mut cx).is_ready());
389 let _ = test::black_box((tx, body));
390 });
391 }
392
393 #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
394 #[test]
395 fn size_hint() {
396 fn eq(body: Incoming, b: SizeHint, note: &str) {
397 let a = body.size_hint();
398 assert_eq!(a.lower(), b.lower(), "lower for {:?}", note);
399 assert_eq!(a.upper(), b.upper(), "upper for {:?}", note);
400 }
401
402 eq(Incoming::empty(), SizeHint::with_exact(0), "empty");
403
404 eq(Incoming::channel().1, SizeHint::new(), "channel");
405
406 eq(
407 Incoming::new_channel(DecodedLength::new(4), false).1,
408 SizeHint::with_exact(4),
409 "channel with length",
410 );
411 }
412
413 #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
414 #[cfg(not(miri))]
415 #[tokio::test]
416 async fn channel_abort() {
417 let (tx, mut rx) = Incoming::channel();
418
419 tx.abort();
420
421 let err = rx.frame().await.unwrap().unwrap_err();
422 assert!(err.is_body_write_aborted(), "{:?}", err);
423 }
424
425 #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
426 #[cfg(all(not(miri), feature = "http1"))]
427 #[tokio::test]
428 async fn channel_abort_when_buffer_is_full() {
429 let (mut tx, mut rx) = Incoming::channel();
430
431 tx.try_send_data("chunk 1".into()).expect("send 1");
432 tx.abort();
434
435 let chunk1 = rx
436 .frame()
437 .await
438 .expect("item 1")
439 .expect("chunk 1")
440 .into_data()
441 .unwrap();
442 assert_eq!(chunk1, "chunk 1");
443
444 let err = rx.frame().await.unwrap().unwrap_err();
445 assert!(err.is_body_write_aborted(), "{:?}", err);
446 }
447
448 #[cfg(feature = "http1")]
449 #[test]
450 fn channel_buffers_one() {
451 let (mut tx, _rx) = Incoming::channel();
452
453 tx.try_send_data("chunk 1".into()).expect("send 1");
454
455 let chunk2 = tx.try_send_data("chunk 2".into()).expect_err("send 2");
457 assert_eq!(chunk2, "chunk 2");
458 }
459
460 #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
461 #[cfg(not(miri))]
462 #[tokio::test]
463 async fn channel_empty() {
464 let (_, mut rx) = Incoming::channel();
465
466 assert!(rx.frame().await.is_none());
467 }
468
469 #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
470 #[test]
471 fn channel_ready() {
472 let (mut tx, _rx) = Incoming::new_channel(DecodedLength::CHUNKED, false);
473
474 let mut tx_ready = tokio_test::task::spawn(tx.ready());
475
476 assert!(tx_ready.poll().is_ready(), "tx is ready immediately");
477 }
478
479 #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
480 #[test]
481 fn channel_wanter() {
482 let (mut tx, mut rx) =
483 Incoming::new_channel(DecodedLength::CHUNKED, true);
484
485 let mut tx_ready = tokio_test::task::spawn(tx.ready());
486 let mut rx_data = tokio_test::task::spawn(rx.frame());
487
488 assert!(
489 tx_ready.poll().is_pending(),
490 "tx isn't ready before rx has been polled"
491 );
492
493 assert!(rx_data.poll().is_pending(), "poll rx.data");
494 assert!(tx_ready.is_woken(), "rx poll wakes tx");
495
496 assert!(
497 tx_ready.poll().is_ready(),
498 "tx is ready after rx has been polled"
499 );
500 }
501
502 #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
503 #[test]
504 fn channel_notices_closure() {
505 let (mut tx, rx) = Incoming::new_channel(DecodedLength::CHUNKED, true);
506
507 let mut tx_ready = tokio_test::task::spawn(tx.ready());
508
509 assert!(
510 tx_ready.poll().is_pending(),
511 "tx isn't ready before rx has been polled"
512 );
513
514 drop(rx);
515 assert!(tx_ready.is_woken(), "dropping rx wakes tx");
516
517 match &tx_ready.poll() {
518 Poll::Ready(Err(e)) if e.is_closed() => (),
519 unexpected => panic!("tx poll ready unexpected: {:?}", unexpected),
520 }
521 }
522}