hyper/proto/h2/
upgrade.rs1use std::future::Future;
2use std::io::Cursor;
3use std::pin::Pin;
4use std::task::{Context, Poll};
5
6use bytes::{Buf, Bytes};
7use futures_channel::{mpsc, oneshot};
8use futures_core::{ready, Stream};
9use h2::{Reason, RecvStream, SendStream};
10use pin_project_lite::pin_project;
11
12use super::ping::Recorder;
13use super::SendBuf;
14use crate::rt::{Read, ReadBufCursor, Write};
15
16pub(super) fn pair<B>(
17 send_stream: SendStream<SendBuf<B>>,
18 recv_stream: RecvStream,
19 ping: Recorder,
20) -> (H2Upgraded, UpgradedSendStreamTask<B>) {
21 let (tx, rx) = mpsc::channel(1);
22 let (error_tx, error_rx) = oneshot::channel();
23
24 (
25 H2Upgraded {
26 send_stream: UpgradedSendStreamBridge { tx, error_rx },
27 recv_stream,
28 ping,
29 buf: Bytes::new(),
30 },
31 UpgradedSendStreamTask {
32 h2_tx: send_stream,
33 rx,
34 buffered: None,
35 error_tx: Some(error_tx),
36 },
37 )
38}
39
40pub(super) struct H2Upgraded {
41 ping: Recorder,
42 send_stream: UpgradedSendStreamBridge,
43 recv_stream: RecvStream,
44 buf: Bytes,
45}
46
47struct UpgradedSendStreamBridge {
48 tx: mpsc::Sender<Cursor<Box<[u8]>>>,
49 error_rx: oneshot::Receiver<crate::Error>,
50}
51
52pin_project! {
53 #[must_use = "futures do nothing unless polled"]
54 pub struct UpgradedSendStreamTask<B> {
55 #[pin]
56 h2_tx: SendStream<SendBuf<B>>,
57 #[pin]
58 rx: mpsc::Receiver<Cursor<Box<[u8]>>>,
59 buffered: Option<Cursor<Box<[u8]>>>,
60 error_tx: Option<oneshot::Sender<crate::Error>>,
61 }
62}
63
64impl<B> UpgradedSendStreamTask<B>
67where
68 B: Buf,
69{
70 fn tick(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), crate::Error>> {
71 let mut me = self.project();
72
73 loop {
78 match me.h2_tx.poll_reset(cx) {
79 Poll::Ready(Ok(reason)) => {
80 trace!("stream received RST_STREAM: {:?}", reason);
81 return Poll::Ready(Err(crate::Error::new_body_write(::h2::Error::from(
82 reason,
83 ))));
84 }
85 Poll::Ready(Err(err)) => {
86 return Poll::Ready(Err(crate::Error::new_body_write(err)))
87 }
88 Poll::Pending => (),
89 }
90
91 if me.buffered.is_some() {
95 while me.h2_tx.capacity() == 0 {
97 match ready!(me.h2_tx.poll_capacity(cx)) {
98 Some(Ok(0)) => {}
99 Some(Ok(_)) => break,
100 Some(Err(e)) => return Poll::Ready(Err(crate::Error::new_body_write(e))),
101 None => {
102 return Poll::Ready(Err(crate::Error::new_body_write(
106 "send stream capacity unexpectedly closed",
107 )));
108 }
109 }
110 }
111
112 let cursor = me.buffered.take().expect("checked is_some above");
113 me.h2_tx
114 .send_data(SendBuf::Cursor(cursor), false)
115 .map_err(crate::Error::new_body_write)?;
116 continue;
117 }
118
119 match me.rx.as_mut().poll_next(cx) {
120 Poll::Ready(Some(cursor)) => {
121 me.h2_tx.reserve_capacity(1);
127 *me.buffered = Some(cursor);
128 }
129 Poll::Ready(None) => {
130 me.h2_tx
131 .send_data(SendBuf::None, true)
132 .map_err(crate::Error::new_body_write)?;
133 return Poll::Ready(Ok(()));
134 }
135 Poll::Pending => {
136 return Poll::Pending;
137 }
138 }
139 }
140 }
141}
142
143impl<B> Future for UpgradedSendStreamTask<B>
144where
145 B: Buf,
146{
147 type Output = ();
148
149 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
150 match self.as_mut().tick(cx) {
151 Poll::Ready(Ok(())) => Poll::Ready(()),
152 Poll::Ready(Err(err)) => {
153 if let Some(tx) = self.error_tx.take() {
154 let _oh_well = tx.send(err);
155 }
156 Poll::Ready(())
157 }
158 Poll::Pending => Poll::Pending,
159 }
160 }
161}
162
163impl Read for H2Upgraded {
166 fn poll_read(
167 mut self: Pin<&mut Self>,
168 cx: &mut Context<'_>,
169 mut read_buf: ReadBufCursor<'_>,
170 ) -> Poll<Result<(), std::io::Error>> {
171 if self.buf.is_empty() {
172 self.buf = loop {
173 match ready!(self.recv_stream.poll_data(cx)) {
174 None => return Poll::Ready(Ok(())),
175 Some(Ok(buf)) if buf.is_empty() && !self.recv_stream.is_end_stream() => {}
176 Some(Ok(buf)) => {
177 self.ping.record_data(buf.len());
178 break buf;
179 }
180 Some(Err(e)) => {
181 return Poll::Ready(match e.reason() {
182 Some(Reason::NO_ERROR) | Some(Reason::CANCEL) => Ok(()),
183 Some(Reason::STREAM_CLOSED) => {
184 Err(std::io::Error::new(std::io::ErrorKind::BrokenPipe, e))
185 }
186 _ => Err(h2_to_io_error(e)),
187 })
188 }
189 }
190 };
191 }
192 let cnt = std::cmp::min(self.buf.len(), read_buf.remaining());
193 read_buf.put_slice(&self.buf[..cnt]);
194 self.buf.advance(cnt);
195 let _ = self.recv_stream.flow_control().release_capacity(cnt);
196 Poll::Ready(Ok(()))
197 }
198}
199
200impl Write for H2Upgraded {
201 fn poll_write(
202 mut self: Pin<&mut Self>,
203 cx: &mut Context<'_>,
204 buf: &[u8],
205 ) -> Poll<Result<usize, std::io::Error>> {
206 if buf.is_empty() {
207 return Poll::Ready(Ok(0));
208 }
209
210 match self.send_stream.tx.poll_ready(cx) {
211 Poll::Ready(Ok(())) => {}
212 Poll::Ready(Err(_task_dropped)) => {
213 return match Pin::new(&mut self.send_stream.error_rx).poll(cx) {
216 Poll::Ready(Ok(reason)) => Poll::Ready(Err(io_error(reason))),
217 Poll::Ready(Err(_task_dropped)) => {
218 Poll::Ready(Err(std::io::ErrorKind::BrokenPipe.into()))
219 }
220 Poll::Pending => Poll::Pending,
221 };
222 }
223 Poll::Pending => return Poll::Pending,
224 }
225
226 let n = buf.len();
227 match self.send_stream.tx.start_send(Cursor::new(buf.into())) {
228 Ok(()) => Poll::Ready(Ok(n)),
229 Err(_task_dropped) => {
230 match Pin::new(&mut self.send_stream.error_rx).poll(cx) {
233 Poll::Ready(Ok(reason)) => Poll::Ready(Err(io_error(reason))),
234 Poll::Ready(Err(_task_dropped)) => {
235 Poll::Ready(Err(std::io::ErrorKind::BrokenPipe.into()))
236 }
237 Poll::Pending => Poll::Pending,
238 }
239 }
240 }
241 }
242
243 fn poll_flush(
244 mut self: Pin<&mut Self>,
245 cx: &mut Context<'_>,
246 ) -> Poll<Result<(), std::io::Error>> {
247 match self.send_stream.tx.poll_ready(cx) {
248 Poll::Ready(Ok(())) => Poll::Ready(Ok(())),
249 Poll::Ready(Err(_task_dropped)) => {
250 match Pin::new(&mut self.send_stream.error_rx).poll(cx) {
253 Poll::Ready(Ok(reason)) => Poll::Ready(Err(io_error(reason))),
254 Poll::Ready(Err(_task_dropped)) => Poll::Ready(Ok(())),
255 Poll::Pending => Poll::Pending,
256 }
257 }
258 Poll::Pending => Poll::Pending,
259 }
260 }
261
262 fn poll_shutdown(
263 mut self: Pin<&mut Self>,
264 cx: &mut Context<'_>,
265 ) -> Poll<Result<(), std::io::Error>> {
266 self.send_stream.tx.close_channel();
267 match Pin::new(&mut self.send_stream.error_rx).poll(cx) {
268 Poll::Ready(Ok(reason)) => Poll::Ready(Err(io_error(reason))),
269 Poll::Ready(Err(_task_dropped)) => Poll::Ready(Ok(())),
270 Poll::Pending => Poll::Pending,
271 }
272 }
273}
274
275fn io_error(e: crate::Error) -> std::io::Error {
276 std::io::Error::new(std::io::ErrorKind::Other, e)
277}
278
279fn h2_to_io_error(e: h2::Error) -> std::io::Error {
280 if e.is_io() {
281 e.into_io()
282 .expect("h2 error reported io cause without an underlying io error")
283 } else {
284 std::io::Error::new(std::io::ErrorKind::Other, e)
285 }
286}