Skip to main content

hyper/proto/h2/
mod.rs

1use std::error::Error as StdError;
2use std::future::Future;
3use std::io::{Cursor, IoSlice};
4use std::pin::Pin;
5use std::task::{Context, Poll};
6
7use bytes::Buf;
8use futures_core::ready;
9use h2::SendStream;
10use http::header::{HeaderName, CONNECTION, TRANSFER_ENCODING, UPGRADE};
11use http::HeaderMap;
12use pin_project_lite::pin_project;
13
14use crate::body::Body;
15
16pub(crate) mod ping;
17pub(crate) mod upgrade;
18
19cfg_client! {
20    pub(crate) mod client;
21    pub(crate) use self::client::ClientTask;
22}
23
24cfg_server! {
25    pub(crate) mod server;
26    pub(crate) use self::server::Server;
27}
28
29/// Default initial stream window size defined in HTTP2 spec.
30pub(crate) const SPEC_WINDOW_SIZE: u32 = 65_535;
31
32// List of connection headers from RFC 9110 Section 7.6.1
33//
34// TE headers are allowed in HTTP/2 requests as long as the value is "trailers", so they're
35// tested separately.
36static CONNECTION_HEADERS: [HeaderName; 4] = [
37    HeaderName::from_static("keep-alive"),
38    HeaderName::from_static("proxy-connection"),
39    TRANSFER_ENCODING,
40    UPGRADE,
41];
42
43enum MessageKind {
44    #[cfg(feature = "client")]
45    Request,
46    #[cfg(feature = "server")]
47    Response,
48}
49
50fn strip_connection_headers(headers: &mut HeaderMap, kind: MessageKind) {
51    for header in &CONNECTION_HEADERS {
52        if headers.remove(header).is_some() {
53            warn!("Connection header illegal in HTTP/2: {}", header.as_str());
54        }
55    }
56
57    #[cfg(not(feature = "client"))]
58    let _ = kind;
59    #[cfg(feature = "client")]
60    if matches!(kind, MessageKind::Request) {
61        if headers
62            .get(http::header::TE)
63            .map_or(false, |te_header| te_header != "trailers")
64        {
65            warn!("TE headers not set to \"trailers\" are illegal in HTTP/2 requests");
66            headers.remove(http::header::TE);
67        }
68    } else if headers.remove(http::header::TE).is_some() {
69        warn!("TE headers illegal in HTTP/2 responses");
70    }
71
72    if let Some(header) = headers.remove(CONNECTION) {
73        warn!(
74            "Connection header illegal in HTTP/2: {}",
75            CONNECTION.as_str()
76        );
77        // A `Connection` header may have a comma-separated list of names of other headers that
78        // are meant for only this specific connection.
79        //
80        // Iterate these names and remove them as headers. Connection-specific headers are
81        // forbidden in HTTP2, as that information has been moved into frame types of the h2
82        // protocol.
83        if let Ok(header_contents) = header.to_str() {
84            for name in header_contents.split(',') {
85                let name = name.trim();
86                headers.remove(name);
87            }
88        }
89    }
90}
91
92// body adapters used by both Client and Server
93
94pin_project! {
95    pub(crate) struct PipeToSendStream<S>
96    where
97        S: Body,
98    {
99        body_tx: SendStream<SendBuf<S::Data>>,
100        data_done: bool,
101        // A data chunk that has been polled from the body but is still waiting
102        // for stream-level capacity before it can be shipped. Stored here so
103        // it survives across `Poll::Pending` returns from `poll_capacity`; if
104        // we left the chunk in a local, it would be dropped on every repoll.
105        buffered_data: Option<Peeked<S::Data>>,
106        #[pin]
107        stream: S,
108    }
109}
110
111struct Peeked<D> {
112    data: D,
113    is_eos: bool,
114}
115
116impl<S> PipeToSendStream<S>
117where
118    S: Body,
119{
120    fn new(stream: S, tx: SendStream<SendBuf<S::Data>>) -> PipeToSendStream<S> {
121        PipeToSendStream {
122            body_tx: tx,
123            data_done: false,
124            buffered_data: None,
125            stream,
126        }
127    }
128
129    #[cfg(feature = "client")]
130    fn send_reset(self: Pin<&mut Self>, reason: h2::Reason) {
131        self.project().body_tx.send_reset(reason);
132    }
133}
134
135impl<S> Future for PipeToSendStream<S>
136where
137    S: Body,
138    S::Error: Into<Box<dyn StdError + Send + Sync>>,
139{
140    type Output = crate::Result<()>;
141
142    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
143        let mut me = self.project();
144        loop {
145            // Register for RST_STREAM notification while we wait for the next
146            // body chunk or for send capacity, so the task wakes up if the
147            // peer resets the stream.
148            if let Poll::Ready(reason) = me
149                .body_tx
150                .poll_reset(cx)
151                .map_err(crate::Error::new_body_write)?
152            {
153                debug!("stream received RST_STREAM: {:?}", reason);
154                return Poll::Ready(Err(crate::Error::new_body_write(::h2::Error::from(reason))));
155            }
156
157            // If a previously-polled chunk is still waiting for stream-level
158            // send capacity, drive that to completion before touching the
159            // body again.
160            if me.buffered_data.is_some() {
161                while me.body_tx.capacity() == 0 {
162                    match ready!(me.body_tx.poll_capacity(cx)) {
163                        Some(Ok(0)) => {}
164                        Some(Ok(_)) => break,
165                        Some(Err(e)) => return Poll::Ready(Err(crate::Error::new_body_write(e))),
166                        None => {
167                            // None means the stream is no longer in a
168                            // streaming state, we either finished it
169                            // somehow, or the remote reset us.
170                            return Poll::Ready(Err(crate::Error::new_body_write(
171                                "send stream capacity unexpectedly closed",
172                            )));
173                        }
174                    }
175                }
176
177                let peeked = me.buffered_data.take().expect("checked is_some above");
178                let buf = SendBuf::Buf(peeked.data);
179                me.body_tx
180                    .send_data(buf, peeked.is_eos)
181                    .map_err(crate::Error::new_body_write)?;
182
183                if peeked.is_eos {
184                    return Poll::Ready(Ok(()));
185                }
186                continue;
187            }
188
189            // Poll for the next body frame *before* reserving any connection
190            // flow-control capacity. Reserving capacity speculatively (even a
191            // single byte) pins that capacity on the connection-level window,
192            // which can deadlock a second stream when talking to peers that
193            // only emit WINDOW_UPDATE once their receive window is fully
194            // exhausted. See #4003.
195            match ready!(me.stream.as_mut().poll_frame(cx)) {
196                Some(Ok(frame)) => {
197                    if frame.is_data() {
198                        let chunk = frame.into_data().unwrap_or_else(|_| unreachable!());
199                        let is_eos = me.stream.is_end_stream();
200                        let len = chunk.remaining();
201                        trace!("send body chunk: {} bytes, eos={}", len, is_eos);
202
203                        if len == 0 {
204                            // Zero-length data frames need no capacity; send
205                            // them straight through so trailing empty frames
206                            // (e.g. an explicit end-of-stream marker) are
207                            // delivered.
208                            let buf = SendBuf::Buf(chunk);
209                            me.body_tx
210                                .send_data(buf, is_eos)
211                                .map_err(crate::Error::new_body_write)?;
212
213                            if is_eos {
214                                return Poll::Ready(Ok(()));
215                            }
216                            continue;
217                        }
218
219                        // Reserve exactly the chunk size so we never pin more
220                        // connection-level flow-control window than we are
221                        // about to consume. Stash the chunk in `self` so it
222                        // survives the upcoming `poll_capacity` wait even if
223                        // it returns `Poll::Pending`.
224                        me.body_tx.reserve_capacity(len);
225                        *me.buffered_data = Some(Peeked {
226                            data: chunk,
227                            is_eos,
228                        });
229                    } else if frame.is_trailers() {
230                        // no more DATA, so give any capacity back
231                        me.body_tx.reserve_capacity(0);
232                        me.body_tx
233                            .send_trailers(frame.into_trailers().unwrap_or_else(|_| unreachable!()))
234                            .map_err(crate::Error::new_body_write)?;
235                        return Poll::Ready(Ok(()));
236                    } else {
237                        trace!("discarding unknown frame");
238                        // loop again
239                    }
240                }
241                Some(Err(e)) => return Poll::Ready(Err(me.body_tx.on_user_err(e))),
242                None => {
243                    // no more frames means we're done here
244                    // but at this point, we haven't sent an EOS DATA, or
245                    // any trailers, so send an empty EOS DATA.
246                    return Poll::Ready(me.body_tx.send_eos_frame());
247                }
248            }
249        }
250    }
251}
252
253trait SendStreamExt {
254    fn on_user_err<E>(&mut self, err: E) -> crate::Error
255    where
256        E: Into<Box<dyn std::error::Error + Send + Sync>>;
257    fn send_eos_frame(&mut self) -> crate::Result<()>;
258}
259
260impl<B: Buf> SendStreamExt for SendStream<SendBuf<B>> {
261    fn on_user_err<E>(&mut self, err: E) -> crate::Error
262    where
263        E: Into<Box<dyn std::error::Error + Send + Sync>>,
264    {
265        let err = crate::Error::new_user_body(err);
266        debug!("send body user stream error: {}", err);
267        self.send_reset(err.h2_reason());
268        err
269    }
270
271    fn send_eos_frame(&mut self) -> crate::Result<()> {
272        trace!("send body eos");
273        self.send_data(SendBuf::None, true)
274            .map_err(crate::Error::new_body_write)
275    }
276}
277
278#[repr(usize)]
279enum SendBuf<B> {
280    Buf(B),
281    Cursor(Cursor<Box<[u8]>>),
282    None,
283}
284
285impl<B: Buf> Buf for SendBuf<B> {
286    #[inline]
287    fn remaining(&self) -> usize {
288        match *self {
289            Self::Buf(ref b) => b.remaining(),
290            Self::Cursor(ref c) => Buf::remaining(c),
291            Self::None => 0,
292        }
293    }
294
295    #[inline]
296    fn chunk(&self) -> &[u8] {
297        match *self {
298            Self::Buf(ref b) => b.chunk(),
299            Self::Cursor(ref c) => c.chunk(),
300            Self::None => &[],
301        }
302    }
303
304    #[inline]
305    fn advance(&mut self, cnt: usize) {
306        match *self {
307            Self::Buf(ref mut b) => b.advance(cnt),
308            Self::Cursor(ref mut c) => c.advance(cnt),
309            Self::None => {}
310        }
311    }
312
313    fn chunks_vectored<'a>(&'a self, dst: &mut [IoSlice<'a>]) -> usize {
314        match *self {
315            Self::Buf(ref b) => b.chunks_vectored(dst),
316            Self::Cursor(ref c) => c.chunks_vectored(dst),
317            Self::None => 0,
318        }
319    }
320}