Skip to main content

hyper/body/
chan.rs

1use std::fmt;
2use std::sync::{Arc, Mutex};
3use std::task::{Context, Poll};
4
5use atomic_waker::AtomicWaker;
6use bytes::Bytes;
7use http::HeaderMap;
8
9use crate::common::lock::LockResultExt;
10
11pub(crate) fn channel(wanter: bool) -> (Sender, Receiver) {
12    let shared = Arc::new(Shared {
13        state: Mutex::new(State {
14            item: None,
15            pending_error: None,
16            trailers: None,
17            sender_open: true,
18            receiver_open: true,
19            want: !wanter,
20        }),
21        sender_waker: AtomicWaker::new(),
22        receiver_waker: AtomicWaker::new(),
23    });
24
25    (
26        Sender {
27            shared: Arc::clone(&shared),
28            trailers_sent: false,
29        },
30        Receiver {
31            shared,
32            terminated: false,
33        },
34    )
35}
36
37#[must_use = "Sender does nothing unless sent on"]
38pub(crate) struct Sender {
39    shared: Arc<Shared>,
40    trailers_sent: bool,
41}
42
43pub(crate) struct Receiver {
44    shared: Arc<Shared>,
45    terminated: bool,
46}
47
48struct Shared {
49    state: Mutex<State>,
50    sender_waker: AtomicWaker,
51    receiver_waker: AtomicWaker,
52}
53
54struct State {
55    item: Option<Result<Bytes, crate::Error>>,
56    // An error must not displace data which was already accepted. The old
57    // mpsc channel achieved this by sending the error from a cloned sender.
58    pending_error: Option<crate::Error>,
59    trailers: Option<HeaderMap>,
60    sender_open: bool,
61    receiver_open: bool,
62    want: bool,
63}
64
65impl Sender {
66    pub(crate) fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<crate::Result<()>> {
67        self.shared.sender_waker.register(cx.waker());
68        let state = self.shared.state.lock().panic_if_poisoned();
69        if !state.receiver_open {
70            Poll::Ready(Err(crate::Error::new_closed()))
71        } else if state.want && state.item.is_none() && state.pending_error.is_none() {
72            Poll::Ready(Ok(()))
73        } else {
74            Poll::Pending
75        }
76    }
77
78    #[cfg(test)]
79    pub(crate) async fn ready(&mut self) -> crate::Result<()> {
80        futures_util::future::poll_fn(|cx| self.poll_ready(cx)).await
81    }
82
83    #[cfg(test)]
84    #[allow(dead_code)]
85    pub(crate) async fn send_data(&mut self, chunk: Bytes) -> crate::Result<()> {
86        self.ready().await?;
87        self.try_send_data(chunk)
88            .map_err(|_| crate::Error::new_closed())
89    }
90
91    pub(crate) fn try_send_data(&mut self, chunk: Bytes) -> Result<(), Bytes> {
92        let mut state = self.shared.state.lock().panic_if_poisoned();
93        if !state.receiver_open
94            || !state.want
95            || state.item.is_some()
96            || state.pending_error.is_some()
97        {
98            return Err(chunk);
99        }
100        state.item = Some(Ok(chunk));
101        drop(state);
102        self.shared.receiver_waker.wake();
103        Ok(())
104    }
105
106    pub(crate) fn try_send_trailers(
107        &mut self,
108        trailers: HeaderMap,
109    ) -> Result<(), Option<HeaderMap>> {
110        if self.trailers_sent {
111            return Err(None);
112        }
113        self.trailers_sent = true;
114
115        let mut state = self.shared.state.lock().panic_if_poisoned();
116        if !state.receiver_open {
117            return Err(Some(trailers));
118        }
119        state.trailers = Some(trailers);
120        drop(state);
121        self.shared.receiver_waker.wake();
122        Ok(())
123    }
124
125    #[allow(dead_code)]
126    #[allow(clippy::unused_async_trait_impl)]
127    #[allow(clippy::map_err_ignore)]
128    pub(crate) async fn send_trailers(&mut self, trailers: HeaderMap) -> crate::Result<()> {
129        self.try_send_trailers(trailers)
130            .map_err(|_| crate::Error::new_closed())
131    }
132
133    pub(crate) fn send_error(&mut self, err: crate::Error) {
134        let mut state = self.shared.state.lock().panic_if_poisoned();
135        if !state.receiver_open {
136            return;
137        }
138        if state.item.is_none() {
139            state.item = Some(Err(err));
140        } else if state.pending_error.is_none() {
141            state.pending_error = Some(err);
142        }
143        drop(state);
144        self.shared.receiver_waker.wake();
145    }
146
147    #[cfg(test)]
148    pub(crate) fn abort(mut self) {
149        self.send_error(crate::Error::new_body_write_aborted());
150    }
151
152    fn is_closed(&self) -> bool {
153        !self.shared.state.lock().panic_if_poisoned().receiver_open
154    }
155}
156
157impl Receiver {
158    pub(crate) fn poll_next(
159        &mut self,
160        cx: &mut Context<'_>,
161    ) -> Poll<Option<Result<bytes::Bytes, crate::Error>>> {
162        if self.terminated {
163            return Poll::Ready(None);
164        }
165
166        self.shared.receiver_waker.register(cx.waker());
167        let mut state = self.shared.state.lock().panic_if_poisoned();
168        let wake_sender = if !state.want {
169            state.want = true;
170            true
171        } else {
172            false
173        };
174        if let Some(item) = state.item.take() {
175            drop(state);
176            self.shared.sender_waker.wake();
177            return Poll::Ready(Some(item));
178        }
179        if let Some(err) = state.pending_error.take() {
180            drop(state);
181            if wake_sender {
182                self.shared.sender_waker.wake();
183            }
184            return Poll::Ready(Some(Err(err)));
185        }
186        let sender_open = state.sender_open;
187        drop(state);
188        if wake_sender {
189            self.shared.sender_waker.wake();
190        }
191        if sender_open {
192            Poll::Pending
193        } else {
194            self.terminated = true;
195            Poll::Ready(None)
196        }
197    }
198
199    pub(crate) fn take_trailers(&mut self) -> Option<HeaderMap> {
200        debug_assert!(self.terminated, "data channel still open before trailers");
201        let mut state = self.shared.state.lock().panic_if_poisoned();
202        state.trailers.take()
203    }
204}
205
206impl Drop for Sender {
207    fn drop(&mut self) {
208        let mut state = self.shared.state.lock().panic_if_poisoned();
209        state.sender_open = false;
210        let receiver_open = state.receiver_open;
211        drop(state);
212        if receiver_open {
213            self.shared.receiver_waker.wake();
214        }
215    }
216}
217
218impl Drop for Receiver {
219    fn drop(&mut self) {
220        let mut state = self.shared.state.lock().panic_if_poisoned();
221        state.receiver_open = false;
222        let sender_open = state.sender_open;
223        drop(state);
224        if sender_open {
225            self.shared.sender_waker.wake();
226        }
227    }
228}
229
230impl fmt::Debug for Sender {
231    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
232        if self.is_closed() {
233            f.debug_tuple("Sender").field(&"Closed").finish()
234        } else {
235            f.debug_tuple("Sender").field(&"Open").finish()
236        }
237    }
238}
239
240#[cfg(test)]
241mod tests {
242    use std::{
243        sync::atomic::{AtomicUsize, Ordering},
244        task::{Wake, Waker},
245    };
246
247    use super::*;
248
249    async fn recv(rx: &mut Receiver) -> Option<Result<Bytes, crate::Error>> {
250        futures_util::future::poll_fn(|cx| rx.poll_next(cx)).await
251    }
252
253    #[tokio::test]
254    async fn error_queued_behind_accepted_data() {
255        let (mut tx, mut rx) = channel(false);
256        tx.try_send_data(Bytes::from_static(b"data")).unwrap();
257        tx.send_error(crate::Error::new_incomplete());
258        drop(tx);
259
260        assert_eq!(recv(&mut rx).await.unwrap().unwrap(), "data");
261        assert!(recv(&mut rx).await.unwrap().is_err());
262        assert!(recv(&mut rx).await.is_none());
263    }
264
265    #[tokio::test]
266    async fn trailers_follow_data_close() {
267        let (mut tx, mut rx) = channel(false);
268        let mut trailers = HeaderMap::new();
269        trailers.insert("x-trailer", "value".parse().unwrap());
270        tx.try_send_trailers(trailers).unwrap();
271        drop(tx);
272
273        assert!(recv(&mut rx).await.is_none());
274        assert_eq!(rx.take_trailers().unwrap()["x-trailer"], "value");
275    }
276
277    #[test]
278    fn drop_wakes_only_an_open_peer() {
279        struct Count(AtomicUsize);
280
281        impl Wake for Count {
282            fn wake(self: Arc<Self>) {
283                self.0.fetch_add(1, Ordering::Relaxed);
284            }
285        }
286
287        let count = Arc::new(Count(AtomicUsize::new(0)));
288        let waker = Waker::from(count.clone());
289        let mut cx = Context::from_waker(&waker);
290        let wakes = || count.0.load(Ordering::Relaxed);
291
292        // A receiver dropped after the sender does not wake the sender's stale waker.
293        let (mut tx, rx) = channel(true);
294        assert!(tx.poll_ready(&mut cx).is_pending());
295        drop(tx);
296        drop(rx);
297        assert_eq!(wakes(), 0);
298
299        // Nor does a sender dropped after the receiver.
300        let (tx, mut rx) = channel(false);
301        assert!(rx.poll_next(&mut cx).is_pending());
302        drop(rx);
303        drop(tx);
304        assert_eq!(wakes(), 0);
305
306        // An open peer is still woken to observe the close.
307        let (mut tx, rx) = channel(true);
308        assert!(tx.poll_ready(&mut cx).is_pending());
309        drop(rx);
310        assert_eq!(wakes(), 1);
311        let (tx, mut rx) = channel(false);
312        assert!(rx.poll_next(&mut cx).is_pending());
313        drop(tx);
314        assert_eq!(wakes(), 2);
315    }
316}