Skip to main content

hyper/body/
incoming.rs

1use std::fmt;
2#[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
3use std::future::Future;
4use std::pin::Pin;
5use std::task::{Context, Poll};
6
7use bytes::Bytes;
8#[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
9use futures_channel::{mpsc, oneshot};
10#[cfg(all(
11    any(feature = "http1", feature = "http2"),
12    any(feature = "client", feature = "server")
13))]
14use futures_core::ready;
15#[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
16use futures_core::{stream::FusedStream, Stream}; // for mpsc::Receiver
17#[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
18use http::HeaderMap;
19use http_body::{Body, Frame, SizeHint};
20
21#[cfg(all(
22    any(feature = "http1", feature = "http2"),
23    any(feature = "client", feature = "server")
24))]
25use super::DecodedLength;
26#[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
27use crate::common::watch;
28#[cfg(all(feature = "http2", any(feature = "client", feature = "server")))]
29use crate::proto::h2::ping;
30
31#[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
32type BodySender = mpsc::Sender<Result<Bytes, crate::Error>>;
33#[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
34type TrailersSender = oneshot::Sender<HeaderMap>;
35
36/// A stream of `Bytes`, used when receiving bodies from the network.
37///
38/// Note that Users should not instantiate this struct directly. When working with the hyper client,
39/// `Incoming` is returned to you in responses. Similarly, when operating with the hyper server,
40/// it is provided within requests.
41///
42/// # Examples
43///
44/// ```rust,ignore
45/// async fn echo(
46///    req: Request<hyper::body::Incoming>,
47/// ) -> Result<Response<BoxBody<Bytes, hyper::Error>>, hyper::Error> {
48///    //Here, you can process `Incoming`
49/// }
50/// ```
51#[must_use = "streams do nothing unless polled"]
52pub struct Incoming {
53    kind: Kind,
54}
55
56enum Kind {
57    Empty,
58    #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
59    Chan {
60        content_length: DecodedLength,
61        want_tx: watch::Sender,
62        data_rx: mpsc::Receiver<Result<Bytes, crate::Error>>,
63        trailers_rx: oneshot::Receiver<HeaderMap>,
64    },
65    #[cfg(all(feature = "http2", any(feature = "client", feature = "server")))]
66    H2 {
67        content_length: DecodedLength,
68        data_done: bool,
69        ping: ping::Recorder,
70        recv: h2::RecvStream,
71    },
72    #[cfg(feature = "ffi")]
73    Ffi(crate::ffi::UserBody),
74}
75
76/// A sender half created through [`Body::channel()`].
77///
78/// Useful when wanting to stream chunks from another thread.
79///
80/// ## Body Closing
81///
82/// Note that the request body will always be closed normally when the sender is dropped (meaning
83/// that the empty terminating chunk will be sent to the remote). If you desire to close the
84/// connection with an incomplete response (e.g. in the case of an error during asynchronous
85/// processing), call the [`Sender::abort()`] method to abort the body in an abnormal fashion.
86///
87/// [`Body::channel()`]: struct.Body.html#method.channel
88/// [`Sender::abort()`]: struct.Sender.html#method.abort
89#[must_use = "Sender does nothing unless sent on"]
90#[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
91pub(crate) struct Sender {
92    want_rx: watch::Receiver,
93    data_tx: BodySender,
94    trailers_tx: Option<TrailersSender>,
95}
96
97#[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
98const WANT_PENDING: usize = 1;
99#[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
100const WANT_READY: usize = 2;
101
102impl Incoming {
103    /// Create a `Body` stream with an associated sender half.
104    ///
105    /// Useful when wanting to stream chunks from another thread.
106    #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
107    #[inline]
108    #[cfg(test)]
109    pub(crate) fn channel() -> (Sender, Incoming) {
110        Self::new_channel(DecodedLength::CHUNKED, /*wanter =*/ false)
111    }
112
113    #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
114    pub(crate) fn new_channel(content_length: DecodedLength, wanter: bool) -> (Sender, Incoming) {
115        let (data_tx, data_rx) = mpsc::channel(0);
116        let (trailers_tx, trailers_rx) = oneshot::channel();
117
118        // If wanter is true, `Sender::poll_ready()` won't becoming ready
119        // until the `Body` has been polled for data once.
120        let want = if wanter { WANT_PENDING } else { WANT_READY };
121
122        let (want_tx, want_rx) = watch::channel(want);
123
124        let tx = Sender {
125            want_rx,
126            data_tx,
127            trailers_tx: Some(trailers_tx),
128        };
129        let rx = Incoming::new(Kind::Chan {
130            content_length,
131            want_tx,
132            data_rx,
133            trailers_rx,
134        });
135
136        (tx, rx)
137    }
138
139    fn new(kind: Kind) -> Incoming {
140        Incoming { kind }
141    }
142
143    #[allow(dead_code)]
144    pub(crate) fn empty() -> Incoming {
145        Incoming::new(Kind::Empty)
146    }
147
148    #[cfg(feature = "ffi")]
149    pub(crate) fn ffi() -> Incoming {
150        Incoming::new(Kind::Ffi(crate::ffi::UserBody::new()))
151    }
152
153    #[cfg(all(feature = "http2", any(feature = "client", feature = "server")))]
154    pub(crate) fn h2(
155        recv: h2::RecvStream,
156        mut content_length: DecodedLength,
157        ping: ping::Recorder,
158    ) -> Self {
159        // If the stream is already EOS, then the "unknown length" is clearly
160        // actually ZERO.
161        if !content_length.is_exact() && recv.is_end_stream() {
162            content_length = DecodedLength::ZERO;
163        }
164
165        Incoming::new(Kind::H2 {
166            data_done: false,
167            ping,
168            content_length,
169            recv,
170        })
171    }
172
173    #[cfg(feature = "ffi")]
174    pub(crate) fn as_ffi_mut(&mut self) -> &mut crate::ffi::UserBody {
175        if !matches!(self.kind, Kind::Ffi(_)) {
176            self.kind = Kind::Ffi(crate::ffi::UserBody::new());
177        }
178
179        match &mut self.kind {
180            Kind::Ffi(body) => body,
181            _ => unreachable!(),
182        }
183    }
184}
185
186impl Body for Incoming {
187    type Data = Bytes;
188    type Error = crate::Error;
189
190    fn poll_frame(
191        #[cfg_attr(
192            not(all(
193                any(feature = "http1", feature = "http2"),
194                any(feature = "client", feature = "server")
195            )),
196            allow(unused_mut)
197        )]
198        mut self: Pin<&mut Self>,
199        #[cfg_attr(
200            not(all(
201                any(feature = "http1", feature = "http2"),
202                any(feature = "client", feature = "server")
203            )),
204            allow(unused_variables)
205        )]
206        cx: &mut Context<'_>,
207    ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
208        match &mut self.kind {
209            Kind::Empty => Poll::Ready(None),
210            #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
211            Kind::Chan {
212                content_length: len,
213                data_rx,
214                want_tx,
215                trailers_rx,
216            } => {
217                want_tx.send(WANT_READY);
218
219                if !data_rx.is_terminated() {
220                    if let Some(chunk) = ready!(Pin::new(data_rx).poll_next(cx)?) {
221                        len.sub_if(chunk.len() as u64);
222                        return Poll::Ready(Some(Ok(Frame::data(chunk))));
223                    }
224                }
225
226                // check trailers after data is terminated
227                match ready!(Pin::new(trailers_rx).poll(cx)) {
228                    Ok(t) => Poll::Ready(Some(Ok(Frame::trailers(t)))),
229                    Err(_) => Poll::Ready(None),
230                }
231            }
232            #[cfg(all(feature = "http2", any(feature = "client", feature = "server")))]
233            Kind::H2 {
234                data_done,
235                ping,
236                recv: h2,
237                content_length: len,
238            } => {
239                if !*data_done {
240                    match ready!(h2.poll_data(cx)) {
241                        Some(Ok(bytes)) => {
242                            let _ = h2.flow_control().release_capacity(bytes.len());
243                            len.sub_if(bytes.len() as u64);
244                            ping.record_data(bytes.len());
245                            return Poll::Ready(Some(Ok(Frame::data(bytes))));
246                        }
247                        Some(Err(e)) => {
248                            if let Some(h2::Reason::NO_ERROR) = e.reason() {
249                                // As mentioned in RFC 7540 Section 8.1, a RST_STREAM with NO_ERROR
250                                // indicates an early response, and should cause the body reading
251                                // to stop, but not fail it:
252                                return Poll::Ready(None);
253                            } else {
254                                return Poll::Ready(Some(Err(crate::Error::new_body(e))));
255                            }
256                        }
257                        None => {
258                            *data_done = true;
259                            // fall through to trailers
260                        }
261                    }
262                }
263
264                // after data, check trailers
265                match ready!(h2.poll_trailers(cx)) {
266                    Ok(t) => {
267                        ping.record_non_data();
268                        Poll::Ready(Ok(t.map(Frame::trailers)).transpose())
269                    }
270                    Err(e) => {
271                        if let Some(h2::Reason::NO_ERROR) = e.reason() {
272                            // Same as above, a RST_STREAM with NO_ERROR indicates an early
273                            // response, and should cause reading the trailers to stop, but
274                            // not fail it:
275                            Poll::Ready(None)
276                        } else {
277                            Poll::Ready(Some(Err(crate::Error::new_h2(e))))
278                        }
279                    }
280                }
281            }
282
283            #[cfg(feature = "ffi")]
284            Kind::Ffi(body) => body.poll_data(cx),
285        }
286    }
287
288    fn is_end_stream(&self) -> bool {
289        match &self.kind {
290            Kind::Empty => true,
291            #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
292            Kind::Chan { content_length, .. } => *content_length == DecodedLength::ZERO,
293            #[cfg(all(feature = "http2", any(feature = "client", feature = "server")))]
294            Kind::H2 { recv: h2, .. } => h2.is_end_stream(),
295            #[cfg(feature = "ffi")]
296            Kind::Ffi(..) => false,
297        }
298    }
299
300    fn size_hint(&self) -> SizeHint {
301        #[cfg(all(
302            any(feature = "http1", feature = "http2"),
303            any(feature = "client", feature = "server")
304        ))]
305        fn opt_len(decoded_length: DecodedLength) -> SizeHint {
306            if let Some(content_length) = decoded_length.into_opt() {
307                SizeHint::with_exact(content_length)
308            } else {
309                SizeHint::default()
310            }
311        }
312
313        match self.kind {
314            Kind::Empty => SizeHint::with_exact(0),
315            #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
316            Kind::Chan { content_length, .. } => opt_len(content_length),
317            #[cfg(all(feature = "http2", any(feature = "client", feature = "server")))]
318            Kind::H2 { content_length, .. } => opt_len(content_length),
319            #[cfg(feature = "ffi")]
320            Kind::Ffi(..) => SizeHint::default(),
321        }
322    }
323}
324
325impl fmt::Debug for Incoming {
326    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
327        #[cfg(any(
328            all(
329                any(feature = "http1", feature = "http2"),
330                any(feature = "client", feature = "server")
331            ),
332            feature = "ffi"
333        ))]
334        #[derive(Debug)]
335        struct Streaming;
336        #[derive(Debug)]
337        struct Empty;
338
339        let mut builder = f.debug_tuple("Body");
340        match self.kind {
341            Kind::Empty => builder.field(&Empty),
342            #[cfg(any(
343                all(
344                    any(feature = "http1", feature = "http2"),
345                    any(feature = "client", feature = "server")
346                ),
347                feature = "ffi"
348            ))]
349            _ => builder.field(&Streaming),
350        };
351
352        builder.finish()
353    }
354}
355
356#[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
357impl Sender {
358    /// Check to see if this `Sender` can send more data.
359    pub(crate) fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<crate::Result<()>> {
360        // Check if the receiver end has tried polling for the body yet
361        ready!(self.poll_want(cx)?);
362        self.data_tx
363            .poll_ready(cx)
364            .map_err(|_| crate::Error::new_closed())
365    }
366
367    fn poll_want(&mut self, cx: &mut Context<'_>) -> Poll<crate::Result<()>> {
368        match self.want_rx.load(cx) {
369            WANT_READY => Poll::Ready(Ok(())),
370            WANT_PENDING => Poll::Pending,
371            watch::CLOSED => Poll::Ready(Err(crate::Error::new_closed())),
372            unexpected => unreachable!("want_rx value: {}", unexpected),
373        }
374    }
375
376    #[cfg(test)]
377    async fn ready(&mut self) -> crate::Result<()> {
378        futures_util::future::poll_fn(|cx| self.poll_ready(cx)).await
379    }
380
381    /// Send data on data channel when it is ready.
382    #[cfg(test)]
383    #[allow(unused)]
384    pub(crate) async fn send_data(&mut self, chunk: Bytes) -> crate::Result<()> {
385        self.ready().await?;
386        self.data_tx
387            .try_send(Ok(chunk))
388            .map_err(|_| crate::Error::new_closed())
389    }
390
391    /// Send trailers on trailers channel.
392    #[allow(unused)]
393    #[allow(clippy::unused_async_trait_impl)]
394    pub(crate) async fn send_trailers(&mut self, trailers: HeaderMap) -> crate::Result<()> {
395        let tx = match self.trailers_tx.take() {
396            Some(tx) => tx,
397            None => return Err(crate::Error::new_closed()),
398        };
399        tx.send(trailers).map_err(|_| crate::Error::new_closed())
400    }
401
402    /// Try to send data on this channel.
403    ///
404    /// # Errors
405    ///
406    /// Returns `Err(Bytes)` if the channel could not (currently) accept
407    /// another `Bytes`.
408    ///
409    /// # Note
410    ///
411    /// This is mostly useful for when trying to send from some other thread
412    /// that doesn't have an async context. If in an async context, prefer
413    /// `send_data()` instead.
414    #[cfg(feature = "http1")]
415    pub(crate) fn try_send_data(&mut self, chunk: Bytes) -> Result<(), Bytes> {
416        self.data_tx
417            .try_send(Ok(chunk))
418            .map_err(|err| err.into_inner().expect("just sent Ok"))
419    }
420
421    #[cfg(feature = "http1")]
422    pub(crate) fn try_send_trailers(
423        &mut self,
424        trailers: HeaderMap,
425    ) -> Result<(), Option<HeaderMap>> {
426        let tx = match self.trailers_tx.take() {
427            Some(tx) => tx,
428            None => return Err(None),
429        };
430
431        tx.send(trailers).map_err(Some)
432    }
433
434    #[cfg(test)]
435    pub(crate) fn abort(mut self) {
436        self.send_error(crate::Error::new_body_write_aborted());
437    }
438
439    pub(crate) fn send_error(&mut self, err: crate::Error) {
440        let _ = self
441            .data_tx
442            // clone so the send works even if buffer is full
443            .clone()
444            .try_send(Err(err));
445    }
446}
447
448#[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
449impl fmt::Debug for Sender {
450    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
451        #[derive(Debug)]
452        struct Open;
453        #[derive(Debug)]
454        struct Closed;
455
456        let mut builder = f.debug_tuple("Sender");
457        match self.want_rx.peek() {
458            watch::CLOSED => builder.field(&Closed),
459            _ => builder.field(&Open),
460        };
461
462        builder.finish()
463    }
464}
465
466#[cfg(test)]
467mod tests {
468    #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
469    use std::mem;
470    #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
471    use std::task::Poll;
472
473    #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
474    use super::{Body, Incoming, SizeHint};
475    #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
476    use super::{DecodedLength, Sender};
477    #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
478    use http_body_util::BodyExt;
479
480    #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
481    #[test]
482    fn test_size_of() {
483        // These are mostly to help catch *accidentally* increasing
484        // the size by too much.
485
486        let body_size = mem::size_of::<Incoming>();
487        let body_expected_size = mem::size_of::<u64>() * 5;
488        assert!(
489            body_size <= body_expected_size,
490            "Body size = {} <= {}",
491            body_size,
492            body_expected_size,
493        );
494
495        assert_eq!(
496            mem::size_of::<Sender>(),
497            mem::size_of::<usize>() * 5,
498            "Sender"
499        );
500
501        assert_eq!(
502            mem::size_of::<Sender>(),
503            mem::size_of::<Option<Sender>>(),
504            "Option<Sender>"
505        );
506    }
507
508    #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
509    #[test]
510    fn size_hint() {
511        fn eq(body: Incoming, b: SizeHint, note: &str) {
512            let a = body.size_hint();
513            assert_eq!(a.lower(), b.lower(), "lower for {:?}", note);
514            assert_eq!(a.upper(), b.upper(), "upper for {:?}", note);
515        }
516
517        eq(Incoming::empty(), SizeHint::with_exact(0), "empty");
518
519        eq(Incoming::channel().1, SizeHint::new(), "channel");
520
521        eq(
522            Incoming::new_channel(DecodedLength::new(4), /*wanter =*/ false).1,
523            SizeHint::with_exact(4),
524            "channel with length",
525        );
526    }
527
528    #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
529    #[cfg(not(miri))]
530    #[tokio::test]
531    async fn channel_abort() {
532        let (tx, mut rx) = Incoming::channel();
533
534        tx.abort();
535
536        let err = rx.frame().await.unwrap().unwrap_err();
537        assert!(err.is_body_write_aborted(), "{:?}", err);
538    }
539
540    #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
541    #[cfg(all(not(miri), feature = "http1"))]
542    #[tokio::test]
543    async fn channel_abort_when_buffer_is_full() {
544        let (mut tx, mut rx) = Incoming::channel();
545
546        tx.try_send_data("chunk 1".into()).expect("send 1");
547        // buffer is full, but can still send abort
548        tx.abort();
549
550        let chunk1 = rx
551            .frame()
552            .await
553            .expect("item 1")
554            .expect("chunk 1")
555            .into_data()
556            .unwrap();
557        assert_eq!(chunk1, "chunk 1");
558
559        let err = rx.frame().await.unwrap().unwrap_err();
560        assert!(err.is_body_write_aborted(), "{:?}", err);
561    }
562
563    #[cfg(feature = "http1")]
564    #[test]
565    fn channel_buffers_one() {
566        let (mut tx, _rx) = Incoming::channel();
567
568        tx.try_send_data("chunk 1".into()).expect("send 1");
569
570        // buffer is now full
571        let chunk2 = tx.try_send_data("chunk 2".into()).expect_err("send 2");
572        assert_eq!(chunk2, "chunk 2");
573    }
574
575    #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
576    #[cfg(not(miri))]
577    #[tokio::test]
578    async fn channel_empty() {
579        let (_, mut rx) = Incoming::channel();
580
581        assert!(rx.frame().await.is_none());
582    }
583
584    #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
585    #[test]
586    fn channel_ready() {
587        let (mut tx, _rx) = Incoming::new_channel(DecodedLength::CHUNKED, /*wanter = */ false);
588
589        let mut tx_ready = tokio_test::task::spawn(tx.ready());
590
591        assert!(tx_ready.poll().is_ready(), "tx is ready immediately");
592    }
593
594    #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
595    #[test]
596    fn channel_wanter() {
597        let (mut tx, mut rx) =
598            Incoming::new_channel(DecodedLength::CHUNKED, /*wanter = */ true);
599
600        let mut tx_ready = tokio_test::task::spawn(tx.ready());
601        let mut rx_data = tokio_test::task::spawn(rx.frame());
602
603        assert!(
604            tx_ready.poll().is_pending(),
605            "tx isn't ready before rx has been polled"
606        );
607
608        assert!(rx_data.poll().is_pending(), "poll rx.data");
609        assert!(tx_ready.is_woken(), "rx poll wakes tx");
610
611        assert!(
612            tx_ready.poll().is_ready(),
613            "tx is ready after rx has been polled"
614        );
615    }
616
617    #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
618    #[test]
619    fn channel_notices_closure() {
620        let (mut tx, rx) = Incoming::new_channel(DecodedLength::CHUNKED, /*wanter = */ true);
621
622        let mut tx_ready = tokio_test::task::spawn(tx.ready());
623
624        assert!(
625            tx_ready.poll().is_pending(),
626            "tx isn't ready before rx has been polled"
627        );
628
629        drop(rx);
630        assert!(tx_ready.is_woken(), "dropping rx wakes tx");
631
632        match &tx_ready.poll() {
633            Poll::Ready(Err(e)) if e.is_closed() => (),
634            unexpected => panic!("tx poll ready unexpected: {:?}", unexpected),
635        }
636    }
637}