1use std::{
2 future::Future,
3 pin::Pin,
4 sync::{atomic::AtomicBool, Arc},
5 task::ready,
6};
7
8use bytes::BufMut;
9use futures_util::FutureExt;
10use http::Request;
11use http_body::Body;
12use send_wrapper::SendWrapper;
13use tokio::io::{AsyncRead, AsyncWrite};
14
15pub struct Upgraded {
26 reader: SendWrapper<Pin<Box<dyn AsyncRead + Unpin>>>,
27 writer: SendWrapper<Pin<Box<dyn AsyncWrite + Unpin>>>,
28 leftover: Option<bytes::Bytes>,
29 has_ended: bool,
30}
31
32impl Upgraded {
33 #[inline]
34 pub(super) fn new(
35 io: impl AsyncRead + AsyncWrite + Unpin + 'static,
36 leftover: Option<bytes::Bytes>,
37 ) -> Self {
38 let (reader, writer) = tokio::io::split(io);
39 Self {
40 reader: SendWrapper::new(Box::pin(reader)),
41 writer: SendWrapper::new(Box::pin(writer)),
42 leftover,
43 has_ended: false,
44 }
45 }
46}
47
48impl AsyncRead for Upgraded {
49 #[inline]
50 fn poll_read(
51 mut self: std::pin::Pin<&mut Self>,
52 cx: &mut std::task::Context<'_>,
53 buf: &mut tokio::io::ReadBuf<'_>,
54 ) -> std::task::Poll<std::io::Result<()>> {
55 let orig_buf_len = buf.remaining();
56 if let Some(leftover) = &mut self.leftover {
57 let slice_len = leftover.len().min(buf.remaining());
58 let leftover_to_write = leftover.split_to(slice_len);
59 buf.put(leftover_to_write);
60 if leftover.is_empty() {
61 self.leftover = None;
62 }
63 return std::task::Poll::Ready(Ok(()));
64 }
65 match (*self.reader).as_mut().poll_read(cx, buf) {
66 std::task::Poll::Ready(Err(e))
67 if matches!(e.kind(), std::io::ErrorKind::UnexpectedEof) =>
68 {
69 self.has_ended = true;
70 std::task::Poll::Ready(Ok(()))
71 }
72 poll => {
73 if poll.is_ready() && buf.remaining() == orig_buf_len {
74 self.has_ended = true;
79 }
80 poll
81 }
82 }
83 }
84}
85
86impl AsyncWrite for Upgraded {
87 #[inline]
88 fn poll_write(
89 mut self: std::pin::Pin<&mut Self>,
90 cx: &mut std::task::Context<'_>,
91 buf: &[u8],
92 ) -> std::task::Poll<std::io::Result<usize>> {
93 match (*self.writer).as_mut().poll_write(cx, buf) {
94 std::task::Poll::Ready(Err(e))
95 if self.has_ended && matches!(e.kind(), std::io::ErrorKind::BrokenPipe) =>
96 {
97 std::task::Poll::Ready(Ok(0))
98 }
99 poll => poll,
100 }
101 }
102
103 #[inline]
104 fn poll_flush(
105 mut self: std::pin::Pin<&mut Self>,
106 cx: &mut std::task::Context<'_>,
107 ) -> std::task::Poll<std::io::Result<()>> {
108 match (*self.writer).as_mut().poll_flush(cx) {
109 std::task::Poll::Ready(Err(e))
110 if self.has_ended && matches!(e.kind(), std::io::ErrorKind::BrokenPipe) =>
111 {
112 std::task::Poll::Ready(Ok(()))
113 }
114 poll => poll,
115 }
116 }
117
118 #[inline]
119 fn poll_shutdown(
120 mut self: std::pin::Pin<&mut Self>,
121 cx: &mut std::task::Context<'_>,
122 ) -> std::task::Poll<std::io::Result<()>> {
123 match (*self.writer).as_mut().poll_shutdown(cx) {
124 std::task::Poll::Ready(Err(e))
125 if self.has_ended && matches!(e.kind(), std::io::ErrorKind::BrokenPipe) =>
126 {
127 std::task::Poll::Ready(Ok(()))
128 }
129 poll => poll,
130 }
131 }
132
133 #[inline]
134 fn is_write_vectored(&self) -> bool {
135 self.writer.is_write_vectored()
136 }
137
138 #[inline]
139 fn poll_write_vectored(
140 mut self: Pin<&mut Self>,
141 cx: &mut std::task::Context<'_>,
142 bufs: &[std::io::IoSlice<'_>],
143 ) -> std::task::Poll<std::io::Result<usize>> {
144 (*self.writer).as_mut().poll_write_vectored(cx, bufs)
145 }
146}
147
148#[derive(Clone)]
149pub(super) struct Upgrade {
150 inner: Arc<futures_util::lock::Mutex<oneshot::AsyncReceiver<Upgraded>>>,
151 pub(super) upgraded: Arc<AtomicBool>,
152}
153
154impl Upgrade {
155 #[inline]
156 pub(super) fn new(inner: oneshot::AsyncReceiver<Upgraded>) -> Self {
157 Self {
158 inner: Arc::new(futures_util::lock::Mutex::new(inner)),
159 upgraded: Arc::new(AtomicBool::new(false)),
160 }
161 }
162}
163
164impl Future for Upgrade {
165 type Output = Option<Upgraded>;
166
167 #[inline]
168 fn poll(
169 self: Pin<&mut Self>,
170 cx: &mut std::task::Context<'_>,
171 ) -> std::task::Poll<Self::Output> {
172 let mut inner = ready!(self.inner.lock().poll_unpin(cx));
173 match inner.poll_unpin(cx) {
174 std::task::Poll::Ready(result) => std::task::Poll::Ready(result.ok()),
175 std::task::Poll::Pending => std::task::Poll::Pending,
176 }
177 }
178}
179
180#[derive(Clone)]
200pub struct OnUpgrade {
201 inner: Upgrade,
202}
203
204impl Future for OnUpgrade {
205 type Output = Option<Upgraded>;
206
207 #[inline]
208 fn poll(
209 mut self: Pin<&mut Self>,
210 cx: &mut std::task::Context<'_>,
211 ) -> std::task::Poll<Self::Output> {
212 self.inner.poll_unpin(cx)
213 }
214}
215
216#[inline]
231pub fn prepare_upgrade(req: &mut Request<impl Body>) -> Option<OnUpgrade> {
232 req.extensions_mut().remove::<Upgrade>().map(|inner| {
233 inner
234 .upgraded
235 .store(true, std::sync::atomic::Ordering::Relaxed);
236 OnUpgrade { inner }
237 })
238}