Skip to main content

hyper/client/
dispatch.rs

1use std::task::{Context, Poll};
2#[cfg(feature = "http2")]
3use std::{future::Future, pin::Pin};
4
5#[cfg(feature = "http2")]
6use http::{Request, Response};
7#[cfg(feature = "http2")]
8use http_body::Body;
9#[cfg(feature = "http2")]
10use pin_project_lite::pin_project;
11use tokio::sync::{mpsc, oneshot};
12
13#[cfg(feature = "http2")]
14use crate::{body::Incoming, proto::h2::client::ResponseFutMap};
15
16pub(crate) type RetryPromise<T, U> = oneshot::Receiver<Result<U, TrySendError<T>>>;
17pub(crate) type Promise<T> = oneshot::Receiver<Result<T, crate::Error>>;
18
19/// An error when calling `try_send_request`.
20///
21/// There is a possibility of an error occurring on a connection in-between the
22/// time that a request is queued and when it is actually written to the IO
23/// transport. If that happens, it is safe to return the request back to the
24/// caller, as it was never fully sent.
25#[derive(Debug)]
26pub struct TrySendError<T> {
27    pub(crate) error: crate::Error,
28    pub(crate) message: Option<T>,
29}
30
31pub(crate) fn channel<T, U>() -> (Sender<T, U>, Receiver<T, U>) {
32    let (tx, rx) = mpsc::unbounded_channel();
33    let (giver, taker) = want::new();
34    let tx = Sender {
35        #[cfg(feature = "http1")]
36        buffered_once: false,
37        giver,
38        inner: tx,
39    };
40    let rx = Receiver { inner: rx, taker };
41    (tx, rx)
42}
43
44/// A bounded sender of requests and callbacks for when responses are ready.
45///
46/// While the inner sender is unbounded, the Giver is used to determine
47/// if the Receiver is ready for another request.
48pub(crate) struct Sender<T, U> {
49    /// One message is always allowed, even if the Receiver hasn't asked
50    /// for it yet. This boolean keeps track of whether we've sent one
51    /// without notice.
52    #[cfg(feature = "http1")]
53    buffered_once: bool,
54    /// The Giver helps watch that the Receiver side has been polled
55    /// when the queue is empty. This helps us know when a request and
56    /// response have been fully processed, and a connection is ready
57    /// for more.
58    giver: want::Giver,
59    /// Actually bounded by the Giver, plus `buffered_once`.
60    inner: mpsc::UnboundedSender<Envelope<T, U>>,
61}
62
63/// An unbounded version.
64///
65/// Cannot poll the Giver, but can still use it to determine if the Receiver
66/// has been dropped. However, this version can be cloned.
67#[cfg(feature = "http2")]
68pub(crate) struct UnboundedSender<T, U> {
69    /// Only used for `is_closed`, since `mpsc::UnboundedSender` cannot be checked.
70    giver: want::SharedGiver,
71    inner: mpsc::UnboundedSender<Envelope<T, U>>,
72}
73
74impl<T, U> Sender<T, U> {
75    #[cfg(feature = "http1")]
76    pub(crate) fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<crate::Result<()>> {
77        self.giver
78            .poll_want(cx)
79            .map_err(|_| crate::Error::new_closed())
80    }
81
82    #[cfg(feature = "http1")]
83    pub(crate) fn is_ready(&self) -> bool {
84        self.giver.is_wanting()
85    }
86
87    #[cfg(feature = "http1")]
88    pub(crate) fn is_closed(&self) -> bool {
89        self.giver.is_canceled()
90    }
91
92    #[cfg(feature = "http1")]
93    fn can_send(&mut self) -> bool {
94        if self.giver.give() || !self.buffered_once {
95            // If the receiver is ready *now*, then of course we can send.
96            //
97            // If the receiver isn't ready yet, but we don't have anything
98            // in the channel yet, then allow one message.
99            self.buffered_once = true;
100            true
101        } else {
102            false
103        }
104    }
105
106    #[cfg(feature = "http1")]
107    pub(crate) fn try_send(&mut self, val: T) -> Result<RetryPromise<T, U>, T> {
108        if !self.can_send() {
109            return Err(val);
110        }
111        let (tx, rx) = oneshot::channel();
112        self.inner
113            .send(Envelope(Some((val, Callback::Retry(Some(tx))))))
114            .map(move |()| rx)
115            .map_err(|mut e| (e.0).0.take().expect("envelope not dropped").0)
116    }
117
118    #[cfg(feature = "http1")]
119    pub(crate) fn send(&mut self, val: T) -> Result<Promise<U>, T> {
120        if !self.can_send() {
121            return Err(val);
122        }
123        let (tx, rx) = oneshot::channel();
124        self.inner
125            .send(Envelope(Some((val, Callback::NoRetry(Some(tx))))))
126            .map(move |()| rx)
127            .map_err(|mut e| (e.0).0.take().expect("envelope not dropped").0)
128    }
129
130    #[cfg(feature = "http2")]
131    pub(crate) fn unbound(self) -> UnboundedSender<T, U> {
132        UnboundedSender {
133            giver: self.giver.shared(),
134            inner: self.inner,
135        }
136    }
137}
138
139#[cfg(feature = "http2")]
140impl<T, U> UnboundedSender<T, U> {
141    pub(crate) fn is_ready(&self) -> bool {
142        !self.giver.is_canceled()
143    }
144
145    pub(crate) fn is_closed(&self) -> bool {
146        self.giver.is_canceled()
147    }
148
149    pub(crate) fn try_send(&mut self, val: T) -> Result<RetryPromise<T, U>, T> {
150        let (tx, rx) = oneshot::channel();
151        self.inner
152            .send(Envelope(Some((val, Callback::Retry(Some(tx))))))
153            .map(move |()| rx)
154            .map_err(|mut e| (e.0).0.take().expect("envelope not dropped").0)
155    }
156
157    pub(crate) fn send(&mut self, val: T) -> Result<Promise<U>, T> {
158        let (tx, rx) = oneshot::channel();
159        self.inner
160            .send(Envelope(Some((val, Callback::NoRetry(Some(tx))))))
161            .map(move |()| rx)
162            .map_err(|mut e| (e.0).0.take().expect("envelope not dropped").0)
163    }
164}
165
166#[cfg(feature = "http2")]
167impl<T, U> Clone for UnboundedSender<T, U> {
168    fn clone(&self) -> Self {
169        UnboundedSender {
170            giver: self.giver.clone(),
171            inner: self.inner.clone(),
172        }
173    }
174}
175
176pub(crate) struct Receiver<T, U> {
177    inner: mpsc::UnboundedReceiver<Envelope<T, U>>,
178    taker: want::Taker,
179}
180
181impl<T, U> Receiver<T, U> {
182    pub(crate) fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<(T, Callback<T, U>)>> {
183        match self.inner.poll_recv(cx) {
184            Poll::Ready(item) => {
185                // A want signaled after finding the queue empty can land after
186                // the Sender's `give()` for the message taken here, as can one
187                // signaled on a coop-budget Pending with a message queued.
188                // Withdraw it, or the Sender reports this connection as ready
189                // while it is still serving this message.
190                self.taker.unwant();
191                Poll::Ready(item.map(|mut env| env.0.take().expect("envelope not dropped")))
192            }
193            Poll::Pending => {
194                self.taker.want();
195                Poll::Pending
196            }
197        }
198    }
199
200    #[cfg(feature = "http1")]
201    pub(crate) fn close(&mut self) {
202        self.taker.cancel();
203        self.inner.close();
204    }
205
206    #[cfg(feature = "http1")]
207    pub(crate) fn try_recv(&mut self) -> Option<(T, Callback<T, U>)> {
208        match crate::common::task::now_or_never(self.inner.recv()) {
209            Some(Some(mut env)) => env.0.take(),
210            _ => None,
211        }
212    }
213}
214
215impl<T, U> Drop for Receiver<T, U> {
216    fn drop(&mut self) {
217        // Notify the giver about the closure first, before dropping
218        // the mpsc::Receiver.
219        self.taker.cancel();
220    }
221}
222
223struct Envelope<T, U>(Option<(T, Callback<T, U>)>);
224
225impl<T, U> Drop for Envelope<T, U> {
226    fn drop(&mut self) {
227        if let Some((val, cb)) = self.0.take() {
228            cb.send(Err(TrySendError {
229                error: crate::Error::new_canceled().with("connection closed"),
230                message: Some(val),
231            }));
232        }
233    }
234}
235
236pub(crate) enum Callback<T, U> {
237    #[allow(unused)]
238    Retry(Option<oneshot::Sender<Result<U, TrySendError<T>>>>),
239    NoRetry(Option<oneshot::Sender<Result<U, crate::Error>>>),
240}
241
242impl<T, U> Drop for Callback<T, U> {
243    fn drop(&mut self) {
244        match self {
245            Callback::Retry(tx) => {
246                if let Some(tx) = tx.take() {
247                    let _ = tx.send(Err(TrySendError {
248                        error: dispatch_gone(),
249                        message: None,
250                    }));
251                }
252            }
253            Callback::NoRetry(tx) => {
254                if let Some(tx) = tx.take() {
255                    let _ = tx.send(Err(dispatch_gone()));
256                }
257            }
258        }
259    }
260}
261
262#[cold]
263fn dispatch_gone() -> crate::Error {
264    // FIXME(nox): What errors do we want here?
265    crate::Error::new_user_dispatch_gone().with(if std::thread::panicking() {
266        "user code panicked"
267    } else {
268        "runtime dropped the dispatch task"
269    })
270}
271
272impl<T, U> Callback<T, U> {
273    #[cfg(feature = "http2")]
274    pub(crate) fn is_canceled(&self) -> bool {
275        match self {
276            Callback::Retry(Some(tx)) => tx.is_closed(),
277            Callback::NoRetry(Some(tx)) => tx.is_closed(),
278            _ => unreachable!(),
279        }
280    }
281
282    pub(crate) fn poll_canceled(&mut self, cx: &mut Context<'_>) -> Poll<()> {
283        match self {
284            Callback::Retry(Some(tx)) => tx.poll_closed(cx),
285            Callback::NoRetry(Some(tx)) => tx.poll_closed(cx),
286            _ => unreachable!(),
287        }
288    }
289
290    pub(crate) fn send(mut self, val: Result<U, TrySendError<T>>) {
291        match &mut self {
292            Callback::Retry(tx) => {
293                let _ = tx
294                    .take()
295                    .expect("callback sender not dropped before send")
296                    .send(val);
297            }
298            Callback::NoRetry(tx) => {
299                let _ = tx
300                    .take()
301                    .expect("callback sender not dropped before send")
302                    .send(val.map_err(|e| e.error));
303            }
304        }
305    }
306}
307
308impl<T> TrySendError<T> {
309    /// Take the message from this error.
310    ///
311    /// The message will not always have been recovered. If an error occurs
312    /// after the message has been serialized onto the connection, it will not
313    /// be available here.
314    pub fn take_message(&mut self) -> Option<T> {
315        self.message.take()
316    }
317
318    /// Returns a reference to the recovered message.
319    ///
320    /// The message will not always have been recovered. If an error occurs
321    /// after the message has been serialized onto the connection, it will not
322    /// be available here.
323    pub fn message(&self) -> Option<&T> {
324        self.message.as_ref()
325    }
326
327    /// Consumes this to return the inner error.
328    pub fn into_error(self) -> crate::Error {
329        self.error
330    }
331
332    /// Returns a reference to the inner error.
333    pub fn error(&self) -> &crate::Error {
334        &self.error
335    }
336}
337
338#[cfg(feature = "http2")]
339pin_project! {
340    pub struct SendWhen<B, E>
341    where
342        B: Body,
343        B: 'static,
344    {
345        #[pin]
346        pub(crate) when: ResponseFutMap<B, E>,
347        #[pin]
348        pub(crate) call_back: Option<Callback<Request<B>, Response<Incoming>>>,
349    }
350}
351
352#[cfg(feature = "http2")]
353impl<B, E> Future for SendWhen<B, E>
354where
355    B: Body + 'static,
356    E: crate::rt::bounds::Http2UpgradedExec<B::Data>,
357{
358    type Output = ();
359
360    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
361        let mut this = self.project();
362
363        let mut call_back = this.call_back.take().expect("polled after complete");
364
365        match Pin::new(&mut this.when).poll(cx) {
366            Poll::Ready(Ok(res)) => {
367                call_back.send(Ok(res));
368                Poll::Ready(())
369            }
370            Poll::Pending => {
371                // check if the callback is canceled
372                match call_back.poll_canceled(cx) {
373                    Poll::Ready(v) => v,
374                    Poll::Pending => {
375                        // Move call_back back to struct before return
376                        this.call_back.set(Some(call_back));
377                        return Poll::Pending;
378                    }
379                }
380                trace!("send_when canceled");
381                // Tell pipe_task to reset the h2 stream so that
382                // RST_STREAM is sent and flow-control capacity freed.
383                this.when.as_mut().cancel();
384                Poll::Ready(())
385            }
386            Poll::Ready(Err((error, message))) => {
387                call_back.send(Err(TrySendError { error, message }));
388                Poll::Ready(())
389            }
390        }
391    }
392}
393
394#[cfg(test)]
395mod tests {
396    #[cfg(feature = "nightly")]
397    extern crate test;
398
399    use std::future::Future;
400    use std::pin::Pin;
401    use std::task::{Context, Poll};
402
403    use super::{channel, Callback, Receiver};
404
405    #[derive(Debug)]
406    struct Custom(#[allow(dead_code)] i32);
407
408    impl<T, U> Future for Receiver<T, U> {
409        type Output = Option<(T, Callback<T, U>)>;
410
411        fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
412            self.poll_recv(cx)
413        }
414    }
415
416    /// Helper to check if the future is ready after polling once.
417    struct PollOnce<'fut, F>(&'fut mut F);
418
419    impl<F, T> Future for PollOnce<'_, F>
420    where
421        F: Future<Output = T> + Unpin,
422    {
423        type Output = Option<()>;
424
425        fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
426            match Pin::new(&mut self.0).poll(cx) {
427                Poll::Ready(_) => Poll::Ready(Some(())),
428                Poll::Pending => Poll::Ready(None),
429            }
430        }
431    }
432
433    #[cfg(not(miri))]
434    #[tokio::test]
435    async fn drop_receiver_sends_cancel_errors() {
436        let _ = pretty_env_logger::try_init();
437
438        let (mut tx, mut rx) = channel::<Custom, ()>();
439
440        // must poll once for try_send to succeed
441        assert!(PollOnce(&mut rx).await.is_none(), "rx empty");
442
443        let promise = tx.try_send(Custom(43)).unwrap();
444        drop(rx);
445
446        let fulfilled = promise.await;
447        let err = fulfilled
448            .expect("fulfilled")
449            .expect_err("promise should error");
450        match (err.error.is_canceled(), err.message) {
451            (true, Some(_)) => (),
452            e => panic!("expected Error::Cancel(_), found {:?}", e),
453        }
454    }
455
456    #[cfg(not(miri))]
457    #[tokio::test]
458    async fn sender_checks_for_want_on_send() {
459        let (mut tx, mut rx) = channel::<Custom, ()>();
460
461        // one is allowed to buffer, second is rejected
462        tx.try_send(Custom(1)).expect("1 buffered");
463        tx.try_send(Custom(2)).expect_err("2 not ready");
464
465        assert!(PollOnce(&mut rx).await.is_some(), "rx once");
466
467        // Even though 1 has been popped, only 1 could be buffered for the
468        // lifetime of the channel.
469        tx.try_send(Custom(2)).expect_err("2 still not ready");
470
471        assert!(PollOnce(&mut rx).await.is_none(), "rx empty");
472
473        tx.try_send(Custom(2)).expect("2 ready");
474    }
475
476    #[cfg(feature = "http2")]
477    #[test]
478    fn unbounded_sender_doesnt_bound_on_want() {
479        let (tx, rx) = channel::<Custom, ()>();
480        let mut tx = tx.unbound();
481
482        tx.try_send(Custom(1)).unwrap();
483        tx.try_send(Custom(2)).unwrap();
484        tx.try_send(Custom(3)).unwrap();
485
486        drop(rx);
487
488        tx.try_send(Custom(4)).unwrap_err();
489    }
490
491    #[cfg(feature = "nightly")]
492    #[bench]
493    fn giver_queue_throughput(b: &mut test::Bencher) {
494        use crate::{body::Incoming, Request, Response};
495
496        let rt = tokio::runtime::Builder::new_current_thread()
497            .build()
498            .unwrap();
499        let (mut tx, mut rx) = channel::<Request<Incoming>, Response<Incoming>>();
500
501        b.iter(move || {
502            tx.send(Request::new(Incoming::empty())).unwrap();
503            rt.block_on(async {
504                loop {
505                    let poll_once = PollOnce(&mut rx);
506                    let opt = poll_once.await;
507                    if opt.is_none() {
508                        break;
509                    }
510                }
511            });
512        })
513    }
514
515    #[cfg(feature = "nightly")]
516    #[bench]
517    fn giver_queue_not_ready(b: &mut test::Bencher) {
518        let rt = tokio::runtime::Builder::new_current_thread()
519            .build()
520            .unwrap();
521        let (_tx, mut rx) = channel::<i32, ()>();
522        b.iter(move || {
523            rt.block_on(async {
524                let poll_once = PollOnce(&mut rx);
525                assert!(poll_once.await.is_none());
526            });
527        })
528    }
529
530    #[cfg(feature = "nightly")]
531    #[bench]
532    fn giver_queue_cancel(b: &mut test::Bencher) {
533        let (_tx, mut rx) = channel::<i32, ()>();
534
535        b.iter(move || {
536            rx.taker.cancel();
537        })
538    }
539}