Coverage Report

Created: 2026-07-25 06:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/h2/src/codec/framed_write.rs
Line
Count
Source
1
use crate::codec::UserError;
2
use crate::codec::UserError::*;
3
use crate::frame::{self, Frame, FrameSize};
4
use crate::hpack;
5
6
use bytes::{Buf, BufMut, BytesMut};
7
use std::pin::Pin;
8
use std::task::{Context, Poll};
9
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
10
use tokio_util::io::poll_write_buf;
11
12
use std::io::{self, Cursor};
13
14
// A macro to get around a method needing to borrow &mut self
15
macro_rules! limited_write_buf {
16
    ($self:expr) => {{
17
        let limit = $self.max_frame_size() + frame::HEADER_LEN;
18
        $self.buf.get_mut().limit(limit)
19
    }};
20
}
21
22
#[derive(Debug)]
23
pub struct FramedWrite<T, B> {
24
    /// Upstream `AsyncWrite`
25
    inner: T,
26
    final_flush_done: bool,
27
28
    encoder: Encoder<B>,
29
}
30
31
#[derive(Debug)]
32
struct Encoder<B> {
33
    /// HPACK encoder
34
    hpack: hpack::Encoder,
35
36
    /// Write buffer
37
    ///
38
    /// TODO: Should this be a ring buffer?
39
    buf: Cursor<BytesMut>,
40
41
    /// Next frame to encode
42
    next: Option<Next<B>>,
43
44
    /// Last data frame
45
    last_data_frame: Option<frame::Data<B>>,
46
47
    /// Max frame size, this is specified by the peer
48
    max_frame_size: FrameSize,
49
50
    /// Chain payloads bigger than this.
51
    chain_threshold: usize,
52
53
    /// Min buffer required to attempt to write a frame
54
    min_buffer_capacity: usize,
55
}
56
57
#[derive(Debug)]
58
enum Next<B> {
59
    Data(frame::Data<B>),
60
    Continuation(frame::Continuation),
61
}
62
63
/// Initialize the connection with this amount of write buffer.
64
///
65
/// The minimum MAX_FRAME_SIZE is 16kb, so always be able to send a HEADERS
66
/// frame that big.
67
const DEFAULT_BUFFER_CAPACITY: usize = 16 * 1_024;
68
69
/// Chain payloads bigger than this when vectored I/O is enabled. The remote
70
/// will never advertise a max frame size less than this (well, the spec says
71
/// the max frame size can't be less than 16kb, so not even close).
72
const CHAIN_THRESHOLD: usize = 256;
73
74
/// Chain payloads bigger than this when vectored I/O is **not** enabled.
75
/// A larger value in this scenario will reduce the number of small and
76
/// fragmented data being sent, and hereby improve the throughput.
77
const CHAIN_THRESHOLD_WITHOUT_VECTORED_IO: usize = 1024;
78
79
// TODO: Make generic
80
impl<T, B> FramedWrite<T, B>
81
where
82
    T: AsyncWrite + Unpin,
83
    B: Buf,
84
{
85
13.7k
    pub fn new(inner: T) -> FramedWrite<T, B> {
86
13.7k
        let chain_threshold = if inner.is_write_vectored() {
87
0
            CHAIN_THRESHOLD
88
        } else {
89
13.7k
            CHAIN_THRESHOLD_WITHOUT_VECTORED_IO
90
        };
91
13.7k
        FramedWrite {
92
13.7k
            inner,
93
13.7k
            final_flush_done: false,
94
13.7k
            encoder: Encoder {
95
13.7k
                hpack: hpack::Encoder::default(),
96
13.7k
                buf: Cursor::new(BytesMut::with_capacity(DEFAULT_BUFFER_CAPACITY)),
97
13.7k
                next: None,
98
13.7k
                last_data_frame: None,
99
13.7k
                max_frame_size: frame::DEFAULT_MAX_FRAME_SIZE,
100
13.7k
                chain_threshold,
101
13.7k
                min_buffer_capacity: chain_threshold + frame::HEADER_LEN,
102
13.7k
            },
103
13.7k
        }
104
13.7k
    }
Unexecuted instantiation: <h2::codec::framed_write::FramedWrite<_, _>>::new
<h2::codec::framed_write::FramedWrite<h2_support::mock::Mock, h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::new
Line
Count
Source
85
863
    pub fn new(inner: T) -> FramedWrite<T, B> {
86
863
        let chain_threshold = if inner.is_write_vectored() {
87
0
            CHAIN_THRESHOLD
88
        } else {
89
863
            CHAIN_THRESHOLD_WITHOUT_VECTORED_IO
90
        };
91
863
        FramedWrite {
92
863
            inner,
93
863
            final_flush_done: false,
94
863
            encoder: Encoder {
95
863
                hpack: hpack::Encoder::default(),
96
863
                buf: Cursor::new(BytesMut::with_capacity(DEFAULT_BUFFER_CAPACITY)),
97
863
                next: None,
98
863
                last_data_frame: None,
99
863
                max_frame_size: frame::DEFAULT_MAX_FRAME_SIZE,
100
863
                chain_threshold,
101
863
                min_buffer_capacity: chain_threshold + frame::HEADER_LEN,
102
863
            },
103
863
        }
104
863
    }
<h2::codec::framed_write::FramedWrite<h2_support::mock::Pipe, bytes::bytes::Bytes>>::new
Line
Count
Source
85
863
    pub fn new(inner: T) -> FramedWrite<T, B> {
86
863
        let chain_threshold = if inner.is_write_vectored() {
87
0
            CHAIN_THRESHOLD
88
        } else {
89
863
            CHAIN_THRESHOLD_WITHOUT_VECTORED_IO
90
        };
91
863
        FramedWrite {
92
863
            inner,
93
863
            final_flush_done: false,
94
863
            encoder: Encoder {
95
863
                hpack: hpack::Encoder::default(),
96
863
                buf: Cursor::new(BytesMut::with_capacity(DEFAULT_BUFFER_CAPACITY)),
97
863
                next: None,
98
863
                last_data_frame: None,
99
863
                max_frame_size: frame::DEFAULT_MAX_FRAME_SIZE,
100
863
                chain_threshold,
101
863
                min_buffer_capacity: chain_threshold + frame::HEADER_LEN,
102
863
            },
103
863
        }
104
863
    }
<h2::codec::framed_write::FramedWrite<fuzz_e2e::MockIo, h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::new
Line
Count
Source
85
12.0k
    pub fn new(inner: T) -> FramedWrite<T, B> {
86
12.0k
        let chain_threshold = if inner.is_write_vectored() {
87
0
            CHAIN_THRESHOLD
88
        } else {
89
12.0k
            CHAIN_THRESHOLD_WITHOUT_VECTORED_IO
90
        };
91
12.0k
        FramedWrite {
92
12.0k
            inner,
93
12.0k
            final_flush_done: false,
94
12.0k
            encoder: Encoder {
95
12.0k
                hpack: hpack::Encoder::default(),
96
12.0k
                buf: Cursor::new(BytesMut::with_capacity(DEFAULT_BUFFER_CAPACITY)),
97
12.0k
                next: None,
98
12.0k
                last_data_frame: None,
99
12.0k
                max_frame_size: frame::DEFAULT_MAX_FRAME_SIZE,
100
12.0k
                chain_threshold,
101
12.0k
                min_buffer_capacity: chain_threshold + frame::HEADER_LEN,
102
12.0k
            },
103
12.0k
        }
104
12.0k
    }
105
106
    /// Returns `Ready` when `send` is able to accept a frame
107
    ///
108
    /// Calling this function may result in the current contents of the buffer
109
    /// to be flushed to `T`.
110
1.13M
    pub fn poll_ready(&mut self, cx: &mut Context) -> Poll<io::Result<()>> {
111
1.13M
        if !self.encoder.has_capacity() {
112
            // Try flushing
113
478k
            ready!(self.flush(cx))?;
114
115
2.87k
            if !self.encoder.has_capacity() {
116
0
                return Poll::Pending;
117
2.87k
            }
118
660k
        }
119
120
662k
        Poll::Ready(Ok(()))
121
1.13M
    }
Unexecuted instantiation: <h2::codec::framed_write::FramedWrite<_, _>>::poll_ready
<h2::codec::framed_write::FramedWrite<fuzz_e2e::MockIo, h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::poll_ready
Line
Count
Source
110
1.13M
    pub fn poll_ready(&mut self, cx: &mut Context) -> Poll<io::Result<()>> {
111
1.13M
        if !self.encoder.has_capacity() {
112
            // Try flushing
113
478k
            ready!(self.flush(cx))?;
114
115
2.87k
            if !self.encoder.has_capacity() {
116
0
                return Poll::Pending;
117
2.87k
            }
118
660k
        }
119
120
662k
        Poll::Ready(Ok(()))
121
1.13M
    }
122
123
    /// Buffer a frame.
124
    ///
125
    /// `poll_ready` must be called first to ensure that a frame may be
126
    /// accepted.
127
288k
    pub fn buffer(&mut self, item: Frame<B>) -> Result<(), UserError> {
128
288k
        self.encoder.buffer(item)
129
288k
    }
Unexecuted instantiation: <h2::codec::framed_write::FramedWrite<_, _>>::buffer
<h2::codec::framed_write::FramedWrite<h2_support::mock::Mock, h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::buffer
Line
Count
Source
127
863
    pub fn buffer(&mut self, item: Frame<B>) -> Result<(), UserError> {
128
863
        self.encoder.buffer(item)
129
863
    }
<h2::codec::framed_write::FramedWrite<fuzz_e2e::MockIo, h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::buffer
Line
Count
Source
127
288k
    pub fn buffer(&mut self, item: Frame<B>) -> Result<(), UserError> {
128
288k
        self.encoder.buffer(item)
129
288k
    }
130
131
    /// Flush buffered data to the wire
132
680k
    pub fn flush(&mut self, cx: &mut Context) -> Poll<io::Result<()>> {
133
680k
        let span = tracing::trace_span!("FramedWrite::flush");
134
680k
        let _e = span.enter();
135
136
        loop {
137
693k
            while !self.encoder.is_empty() {
138
482k
                let n = match self.encoder.next {
139
482k
                    Some(Next::Data(ref mut frame)) => {
140
482k
                        tracing::trace!(queued_data_frame = true);
141
482k
                        let mut buf = (&mut self.encoder.buf).chain(frame.payload_mut());
142
482k
                        ready!(poll_write_buf(Pin::new(&mut self.inner), cx, &mut buf))?
143
                    }
144
                    _ => {
145
27.7k
                        tracing::trace!(queued_data_frame = false);
146
27.7k
                        ready!(poll_write_buf(
147
27.7k
                            Pin::new(&mut self.inner),
148
27.7k
                            cx,
149
27.7k
                            &mut self.encoder.buf
150
27.7k
                        ))?
151
                    }
152
                };
153
12.5k
                if n == 0 {
154
                    // No progress is possible; retrying would busy-loop.
155
0
                    tracing::trace!("write returned zero, but non-zero bytes remaining");
156
0
                    return Poll::Ready(Err(io::ErrorKind::WriteZero.into()));
157
12.5k
                }
158
            }
159
160
183k
            match self.encoder.unset_frame() {
161
0
                ControlFlow::Continue => (),
162
183k
                ControlFlow::Break => break,
163
            }
164
        }
165
166
183k
        tracing::trace!("flushing buffer");
167
        // Flush the upstream
168
183k
        ready!(Pin::new(&mut self.inner).poll_flush(cx))?;
169
170
183k
        Poll::Ready(Ok(()))
171
680k
    }
Unexecuted instantiation: <h2::codec::framed_write::FramedWrite<_, _>>::flush
<h2::codec::framed_write::FramedWrite<h2_support::mock::Pipe, bytes::bytes::Bytes>>::flush
Line
Count
Source
132
863
    pub fn flush(&mut self, cx: &mut Context) -> Poll<io::Result<()>> {
133
863
        let span = tracing::trace_span!("FramedWrite::flush");
134
863
        let _e = span.enter();
135
136
        loop {
137
863
            while !self.encoder.is_empty() {
138
0
                let n = match self.encoder.next {
139
0
                    Some(Next::Data(ref mut frame)) => {
140
0
                        tracing::trace!(queued_data_frame = true);
141
0
                        let mut buf = (&mut self.encoder.buf).chain(frame.payload_mut());
142
0
                        ready!(poll_write_buf(Pin::new(&mut self.inner), cx, &mut buf))?
143
                    }
144
                    _ => {
145
0
                        tracing::trace!(queued_data_frame = false);
146
0
                        ready!(poll_write_buf(
147
0
                            Pin::new(&mut self.inner),
148
0
                            cx,
149
0
                            &mut self.encoder.buf
150
0
                        ))?
151
                    }
152
                };
153
0
                if n == 0 {
154
                    // No progress is possible; retrying would busy-loop.
155
0
                    tracing::trace!("write returned zero, but non-zero bytes remaining");
156
0
                    return Poll::Ready(Err(io::ErrorKind::WriteZero.into()));
157
0
                }
158
            }
159
160
863
            match self.encoder.unset_frame() {
161
0
                ControlFlow::Continue => (),
162
863
                ControlFlow::Break => break,
163
            }
164
        }
165
166
863
        tracing::trace!("flushing buffer");
167
        // Flush the upstream
168
863
        ready!(Pin::new(&mut self.inner).poll_flush(cx))?;
169
170
863
        Poll::Ready(Ok(()))
171
863
    }
<h2::codec::framed_write::FramedWrite<fuzz_e2e::MockIo, h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::flush
Line
Count
Source
132
679k
    pub fn flush(&mut self, cx: &mut Context) -> Poll<io::Result<()>> {
133
679k
        let span = tracing::trace_span!("FramedWrite::flush");
134
679k
        let _e = span.enter();
135
136
        loop {
137
692k
            while !self.encoder.is_empty() {
138
482k
                let n = match self.encoder.next {
139
482k
                    Some(Next::Data(ref mut frame)) => {
140
482k
                        tracing::trace!(queued_data_frame = true);
141
482k
                        let mut buf = (&mut self.encoder.buf).chain(frame.payload_mut());
142
482k
                        ready!(poll_write_buf(Pin::new(&mut self.inner), cx, &mut buf))?
143
                    }
144
                    _ => {
145
27.7k
                        tracing::trace!(queued_data_frame = false);
146
27.7k
                        ready!(poll_write_buf(
147
27.7k
                            Pin::new(&mut self.inner),
148
27.7k
                            cx,
149
27.7k
                            &mut self.encoder.buf
150
27.7k
                        ))?
151
                    }
152
                };
153
12.5k
                if n == 0 {
154
                    // No progress is possible; retrying would busy-loop.
155
0
                    tracing::trace!("write returned zero, but non-zero bytes remaining");
156
0
                    return Poll::Ready(Err(io::ErrorKind::WriteZero.into()));
157
12.5k
                }
158
            }
159
160
182k
            match self.encoder.unset_frame() {
161
0
                ControlFlow::Continue => (),
162
182k
                ControlFlow::Break => break,
163
            }
164
        }
165
166
182k
        tracing::trace!("flushing buffer");
167
        // Flush the upstream
168
182k
        ready!(Pin::new(&mut self.inner).poll_flush(cx))?;
169
170
182k
        Poll::Ready(Ok(()))
171
679k
    }
172
173
    /// Close the codec
174
10.5k
    pub fn shutdown(&mut self, cx: &mut Context) -> Poll<io::Result<()>> {
175
10.5k
        if !self.final_flush_done {
176
10.5k
            ready!(self.flush(cx))?;
177
1.58k
            self.final_flush_done = true;
178
0
        }
179
1.58k
        Pin::new(&mut self.inner).poll_shutdown(cx)
180
10.5k
    }
Unexecuted instantiation: <h2::codec::framed_write::FramedWrite<_, _>>::shutdown
<h2::codec::framed_write::FramedWrite<h2_support::mock::Pipe, bytes::bytes::Bytes>>::shutdown
Line
Count
Source
174
863
    pub fn shutdown(&mut self, cx: &mut Context) -> Poll<io::Result<()>> {
175
863
        if !self.final_flush_done {
176
863
            ready!(self.flush(cx))?;
177
863
            self.final_flush_done = true;
178
0
        }
179
863
        Pin::new(&mut self.inner).poll_shutdown(cx)
180
863
    }
<h2::codec::framed_write::FramedWrite<fuzz_e2e::MockIo, h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::shutdown
Line
Count
Source
174
9.68k
    pub fn shutdown(&mut self, cx: &mut Context) -> Poll<io::Result<()>> {
175
9.68k
        if !self.final_flush_done {
176
9.68k
            ready!(self.flush(cx))?;
177
725
            self.final_flush_done = true;
178
0
        }
179
725
        Pin::new(&mut self.inner).poll_shutdown(cx)
180
9.68k
    }
181
}
182
183
#[must_use]
184
enum ControlFlow {
185
    Continue,
186
    Break,
187
}
188
189
impl<B> Encoder<B>
190
where
191
    B: Buf,
192
{
193
183k
    fn unset_frame(&mut self) -> ControlFlow {
194
        // Clear internal buffer
195
183k
        self.buf.set_position(0);
196
183k
        self.buf.get_mut().clear();
197
198
        // The data frame has been written, so unset it
199
183k
        match self.next.take() {
200
2.74k
            Some(Next::Data(frame)) => {
201
2.74k
                self.last_data_frame = Some(frame);
202
2.74k
                debug_assert!(self.is_empty());
203
2.74k
                ControlFlow::Break
204
            }
205
0
            Some(Next::Continuation(frame)) => {
206
                // Buffer the continuation frame, then try to write again
207
0
                let mut buf = limited_write_buf!(self);
208
0
                if let Some(continuation) = frame.encode(&mut buf) {
209
0
                    self.next = Some(Next::Continuation(continuation));
210
0
                }
211
0
                ControlFlow::Continue
212
            }
213
180k
            None => ControlFlow::Break,
214
        }
215
183k
    }
Unexecuted instantiation: <h2::codec::framed_write::Encoder<_>>::unset_frame
<h2::codec::framed_write::Encoder<bytes::bytes::Bytes>>::unset_frame
Line
Count
Source
193
863
    fn unset_frame(&mut self) -> ControlFlow {
194
        // Clear internal buffer
195
863
        self.buf.set_position(0);
196
863
        self.buf.get_mut().clear();
197
198
        // The data frame has been written, so unset it
199
863
        match self.next.take() {
200
0
            Some(Next::Data(frame)) => {
201
0
                self.last_data_frame = Some(frame);
202
0
                debug_assert!(self.is_empty());
203
0
                ControlFlow::Break
204
            }
205
0
            Some(Next::Continuation(frame)) => {
206
                // Buffer the continuation frame, then try to write again
207
0
                let mut buf = limited_write_buf!(self);
208
0
                if let Some(continuation) = frame.encode(&mut buf) {
209
0
                    self.next = Some(Next::Continuation(continuation));
210
0
                }
211
0
                ControlFlow::Continue
212
            }
213
863
            None => ControlFlow::Break,
214
        }
215
863
    }
<h2::codec::framed_write::Encoder<h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::unset_frame
Line
Count
Source
193
182k
    fn unset_frame(&mut self) -> ControlFlow {
194
        // Clear internal buffer
195
182k
        self.buf.set_position(0);
196
182k
        self.buf.get_mut().clear();
197
198
        // The data frame has been written, so unset it
199
182k
        match self.next.take() {
200
2.74k
            Some(Next::Data(frame)) => {
201
2.74k
                self.last_data_frame = Some(frame);
202
2.74k
                debug_assert!(self.is_empty());
203
2.74k
                ControlFlow::Break
204
            }
205
0
            Some(Next::Continuation(frame)) => {
206
                // Buffer the continuation frame, then try to write again
207
0
                let mut buf = limited_write_buf!(self);
208
0
                if let Some(continuation) = frame.encode(&mut buf) {
209
0
                    self.next = Some(Next::Continuation(continuation));
210
0
                }
211
0
                ControlFlow::Continue
212
            }
213
179k
            None => ControlFlow::Break,
214
        }
215
182k
    }
216
217
288k
    fn buffer(&mut self, item: Frame<B>) -> Result<(), UserError> {
218
        // Ensure that we have enough capacity to accept the write.
219
288k
        assert!(self.has_capacity());
220
288k
        let span = tracing::trace_span!("FramedWrite::buffer", frame = ?item);
221
288k
        let _e = span.enter();
222
223
288k
        tracing::debug!(frame = ?item, "send");
224
225
288k
        match item {
226
18.9k
            Frame::Data(mut v) => {
227
                // Ensure that the payload is not greater than the max frame.
228
18.9k
                let len = v.payload().remaining();
229
230
18.9k
                if len > self.max_frame_size() {
231
0
                    return Err(PayloadTooBig);
232
18.9k
                }
233
234
18.9k
                if len >= self.chain_threshold {
235
4.18k
                    let head = v.head();
236
237
                    // Encode the frame head to the buffer
238
4.18k
                    head.encode(len, self.buf.get_mut());
239
240
4.18k
                    if self.buf.get_ref().remaining() < self.chain_threshold {
241
2.47k
                        let extra_bytes = self.chain_threshold - self.buf.remaining();
242
2.47k
                        self.buf.get_mut().put(v.payload_mut().take(extra_bytes));
243
2.47k
                    }
244
245
                    // Save the data frame
246
4.18k
                    self.next = Some(Next::Data(v));
247
                } else {
248
14.7k
                    v.encode_chunk(self.buf.get_mut());
249
250
                    // The chunk has been fully encoded, so there is no need to
251
                    // keep it around
252
14.7k
                    assert_eq!(v.payload().remaining(), 0, "chunk not fully encoded");
253
254
                    // Save off the last frame...
255
14.7k
                    self.last_data_frame = Some(v);
256
                }
257
            }
258
236k
            Frame::Headers(v) => {
259
236k
                let mut buf = limited_write_buf!(self);
260
236k
                if let Some(continuation) = v.encode(&mut self.hpack, &mut buf) {
261
0
                    self.next = Some(Next::Continuation(continuation));
262
236k
                }
263
            }
264
0
            Frame::PushPromise(v) => {
265
0
                let mut buf = limited_write_buf!(self);
266
0
                if let Some(continuation) = v.encode(&mut self.hpack, &mut buf) {
267
0
                    self.next = Some(Next::Continuation(continuation));
268
0
                }
269
            }
270
19.1k
            Frame::Settings(v) => {
271
19.1k
                v.encode(self.buf.get_mut());
272
19.1k
                tracing::trace!(rem = self.buf.remaining(), "encoded settings");
273
            }
274
6.66k
            Frame::GoAway(v) => {
275
6.66k
                v.encode(self.buf.get_mut());
276
6.66k
                tracing::trace!(rem = self.buf.remaining(), "encoded go_away");
277
            }
278
473
            Frame::Ping(v) => {
279
473
                v.encode(self.buf.get_mut());
280
473
                tracing::trace!(rem = self.buf.remaining(), "encoded ping");
281
            }
282
48
            Frame::WindowUpdate(v) => {
283
48
                v.encode(self.buf.get_mut());
284
48
                tracing::trace!(rem = self.buf.remaining(), "encoded window_update");
285
            }
286
287
            Frame::Priority(_) => {
288
                /*
289
                v.encode(self.buf.get_mut());
290
                tracing::trace!("encoded priority; rem={:?}", self.buf.remaining());
291
                */
292
0
                unimplemented!();
293
            }
294
7.42k
            Frame::Reset(v) => {
295
7.42k
                v.encode(self.buf.get_mut());
296
7.42k
                tracing::trace!(rem = self.buf.remaining(), "encoded reset");
297
            }
298
        }
299
300
288k
        Ok(())
301
288k
    }
Unexecuted instantiation: <h2::codec::framed_write::Encoder<_>>::buffer
<h2::codec::framed_write::Encoder<h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::buffer
Line
Count
Source
217
863
    fn buffer(&mut self, item: Frame<B>) -> Result<(), UserError> {
218
        // Ensure that we have enough capacity to accept the write.
219
863
        assert!(self.has_capacity());
220
863
        let span = tracing::trace_span!("FramedWrite::buffer", frame = ?item);
221
863
        let _e = span.enter();
222
223
863
        tracing::debug!(frame = ?item, "send");
224
225
863
        match item {
226
0
            Frame::Data(mut v) => {
227
                // Ensure that the payload is not greater than the max frame.
228
0
                let len = v.payload().remaining();
229
230
0
                if len > self.max_frame_size() {
231
0
                    return Err(PayloadTooBig);
232
0
                }
233
234
0
                if len >= self.chain_threshold {
235
0
                    let head = v.head();
236
237
                    // Encode the frame head to the buffer
238
0
                    head.encode(len, self.buf.get_mut());
239
240
0
                    if self.buf.get_ref().remaining() < self.chain_threshold {
241
0
                        let extra_bytes = self.chain_threshold - self.buf.remaining();
242
0
                        self.buf.get_mut().put(v.payload_mut().take(extra_bytes));
243
0
                    }
244
245
                    // Save the data frame
246
0
                    self.next = Some(Next::Data(v));
247
                } else {
248
0
                    v.encode_chunk(self.buf.get_mut());
249
250
                    // The chunk has been fully encoded, so there is no need to
251
                    // keep it around
252
0
                    assert_eq!(v.payload().remaining(), 0, "chunk not fully encoded");
253
254
                    // Save off the last frame...
255
0
                    self.last_data_frame = Some(v);
256
                }
257
            }
258
0
            Frame::Headers(v) => {
259
0
                let mut buf = limited_write_buf!(self);
260
0
                if let Some(continuation) = v.encode(&mut self.hpack, &mut buf) {
261
0
                    self.next = Some(Next::Continuation(continuation));
262
0
                }
263
            }
264
0
            Frame::PushPromise(v) => {
265
0
                let mut buf = limited_write_buf!(self);
266
0
                if let Some(continuation) = v.encode(&mut self.hpack, &mut buf) {
267
0
                    self.next = Some(Next::Continuation(continuation));
268
0
                }
269
            }
270
863
            Frame::Settings(v) => {
271
863
                v.encode(self.buf.get_mut());
272
863
                tracing::trace!(rem = self.buf.remaining(), "encoded settings");
273
            }
274
0
            Frame::GoAway(v) => {
275
0
                v.encode(self.buf.get_mut());
276
0
                tracing::trace!(rem = self.buf.remaining(), "encoded go_away");
277
            }
278
0
            Frame::Ping(v) => {
279
0
                v.encode(self.buf.get_mut());
280
0
                tracing::trace!(rem = self.buf.remaining(), "encoded ping");
281
            }
282
0
            Frame::WindowUpdate(v) => {
283
0
                v.encode(self.buf.get_mut());
284
0
                tracing::trace!(rem = self.buf.remaining(), "encoded window_update");
285
            }
286
287
            Frame::Priority(_) => {
288
                /*
289
                v.encode(self.buf.get_mut());
290
                tracing::trace!("encoded priority; rem={:?}", self.buf.remaining());
291
                */
292
0
                unimplemented!();
293
            }
294
0
            Frame::Reset(v) => {
295
0
                v.encode(self.buf.get_mut());
296
0
                tracing::trace!(rem = self.buf.remaining(), "encoded reset");
297
            }
298
        }
299
300
863
        Ok(())
301
863
    }
<h2::codec::framed_write::Encoder<h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::buffer
Line
Count
Source
217
288k
    fn buffer(&mut self, item: Frame<B>) -> Result<(), UserError> {
218
        // Ensure that we have enough capacity to accept the write.
219
288k
        assert!(self.has_capacity());
220
288k
        let span = tracing::trace_span!("FramedWrite::buffer", frame = ?item);
221
288k
        let _e = span.enter();
222
223
288k
        tracing::debug!(frame = ?item, "send");
224
225
288k
        match item {
226
18.9k
            Frame::Data(mut v) => {
227
                // Ensure that the payload is not greater than the max frame.
228
18.9k
                let len = v.payload().remaining();
229
230
18.9k
                if len > self.max_frame_size() {
231
0
                    return Err(PayloadTooBig);
232
18.9k
                }
233
234
18.9k
                if len >= self.chain_threshold {
235
4.18k
                    let head = v.head();
236
237
                    // Encode the frame head to the buffer
238
4.18k
                    head.encode(len, self.buf.get_mut());
239
240
4.18k
                    if self.buf.get_ref().remaining() < self.chain_threshold {
241
2.47k
                        let extra_bytes = self.chain_threshold - self.buf.remaining();
242
2.47k
                        self.buf.get_mut().put(v.payload_mut().take(extra_bytes));
243
2.47k
                    }
244
245
                    // Save the data frame
246
4.18k
                    self.next = Some(Next::Data(v));
247
                } else {
248
14.7k
                    v.encode_chunk(self.buf.get_mut());
249
250
                    // The chunk has been fully encoded, so there is no need to
251
                    // keep it around
252
14.7k
                    assert_eq!(v.payload().remaining(), 0, "chunk not fully encoded");
253
254
                    // Save off the last frame...
255
14.7k
                    self.last_data_frame = Some(v);
256
                }
257
            }
258
236k
            Frame::Headers(v) => {
259
236k
                let mut buf = limited_write_buf!(self);
260
236k
                if let Some(continuation) = v.encode(&mut self.hpack, &mut buf) {
261
0
                    self.next = Some(Next::Continuation(continuation));
262
236k
                }
263
            }
264
0
            Frame::PushPromise(v) => {
265
0
                let mut buf = limited_write_buf!(self);
266
0
                if let Some(continuation) = v.encode(&mut self.hpack, &mut buf) {
267
0
                    self.next = Some(Next::Continuation(continuation));
268
0
                }
269
            }
270
18.3k
            Frame::Settings(v) => {
271
18.3k
                v.encode(self.buf.get_mut());
272
18.3k
                tracing::trace!(rem = self.buf.remaining(), "encoded settings");
273
            }
274
6.66k
            Frame::GoAway(v) => {
275
6.66k
                v.encode(self.buf.get_mut());
276
6.66k
                tracing::trace!(rem = self.buf.remaining(), "encoded go_away");
277
            }
278
473
            Frame::Ping(v) => {
279
473
                v.encode(self.buf.get_mut());
280
473
                tracing::trace!(rem = self.buf.remaining(), "encoded ping");
281
            }
282
48
            Frame::WindowUpdate(v) => {
283
48
                v.encode(self.buf.get_mut());
284
48
                tracing::trace!(rem = self.buf.remaining(), "encoded window_update");
285
            }
286
287
            Frame::Priority(_) => {
288
                /*
289
                v.encode(self.buf.get_mut());
290
                tracing::trace!("encoded priority; rem={:?}", self.buf.remaining());
291
                */
292
0
                unimplemented!();
293
            }
294
7.42k
            Frame::Reset(v) => {
295
7.42k
                v.encode(self.buf.get_mut());
296
7.42k
                tracing::trace!(rem = self.buf.remaining(), "encoded reset");
297
            }
298
        }
299
300
288k
        Ok(())
301
288k
    }
302
303
1.42M
    fn has_capacity(&self) -> bool {
304
1.42M
        self.next.is_none()
305
953k
            && (self.buf.get_ref().capacity() - self.buf.get_ref().len()
306
953k
                >= self.min_buffer_capacity)
307
1.42M
    }
Unexecuted instantiation: <h2::codec::framed_write::Encoder<_>>::has_capacity
<h2::codec::framed_write::Encoder<h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::has_capacity
Line
Count
Source
303
863
    fn has_capacity(&self) -> bool {
304
863
        self.next.is_none()
305
863
            && (self.buf.get_ref().capacity() - self.buf.get_ref().len()
306
863
                >= self.min_buffer_capacity)
307
863
    }
<h2::codec::framed_write::Encoder<h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::has_capacity
Line
Count
Source
303
1.42M
    fn has_capacity(&self) -> bool {
304
1.42M
        self.next.is_none()
305
952k
            && (self.buf.get_ref().capacity() - self.buf.get_ref().len()
306
952k
                >= self.min_buffer_capacity)
307
1.42M
    }
308
309
693k
    fn is_empty(&self) -> bool {
310
484k
        match self.next {
311
484k
            Some(Next::Data(ref frame)) => !frame.payload().has_remaining(),
312
208k
            _ => !self.buf.has_remaining(),
313
        }
314
693k
    }
Unexecuted instantiation: <h2::codec::framed_write::Encoder<_>>::is_empty
<h2::codec::framed_write::Encoder<bytes::bytes::Bytes>>::is_empty
Line
Count
Source
309
863
    fn is_empty(&self) -> bool {
310
0
        match self.next {
311
0
            Some(Next::Data(ref frame)) => !frame.payload().has_remaining(),
312
863
            _ => !self.buf.has_remaining(),
313
        }
314
863
    }
<h2::codec::framed_write::Encoder<h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::is_empty
Line
Count
Source
309
692k
    fn is_empty(&self) -> bool {
310
484k
        match self.next {
311
484k
            Some(Next::Data(ref frame)) => !frame.payload().has_remaining(),
312
207k
            _ => !self.buf.has_remaining(),
313
        }
314
692k
    }
315
}
316
317
impl<B> Encoder<B> {
318
449k
    fn max_frame_size(&self) -> usize {
319
449k
        self.max_frame_size as usize
320
449k
    }
Unexecuted instantiation: <h2::codec::framed_write::Encoder<_>>::max_frame_size
Unexecuted instantiation: <h2::codec::framed_write::Encoder<h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::max_frame_size
Unexecuted instantiation: <h2::codec::framed_write::Encoder<bytes::bytes::Bytes>>::max_frame_size
<h2::codec::framed_write::Encoder<h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::max_frame_size
Line
Count
Source
318
449k
    fn max_frame_size(&self) -> usize {
319
449k
        self.max_frame_size as usize
320
449k
    }
321
}
322
323
impl<T, B> FramedWrite<T, B> {
324
    /// Returns the max frame size that can be sent
325
194k
    pub fn max_frame_size(&self) -> usize {
326
194k
        self.encoder.max_frame_size()
327
194k
    }
Unexecuted instantiation: <h2::codec::framed_write::FramedWrite<_, _>>::max_frame_size
<h2::codec::framed_write::FramedWrite<fuzz_e2e::MockIo, h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::max_frame_size
Line
Count
Source
325
194k
    pub fn max_frame_size(&self) -> usize {
326
194k
        self.encoder.max_frame_size()
327
194k
    }
328
329
    /// Set the peer's max frame size.
330
155
    pub fn set_max_frame_size(&mut self, val: usize) {
331
155
        assert!(val <= frame::MAX_MAX_FRAME_SIZE as usize);
332
155
        self.encoder.max_frame_size = val as FrameSize;
333
155
    }
Unexecuted instantiation: <h2::codec::framed_write::FramedWrite<_, _>>::set_max_frame_size
<h2::codec::framed_write::FramedWrite<fuzz_e2e::MockIo, h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::set_max_frame_size
Line
Count
Source
330
155
    pub fn set_max_frame_size(&mut self, val: usize) {
331
155
        assert!(val <= frame::MAX_MAX_FRAME_SIZE as usize);
332
155
        self.encoder.max_frame_size = val as FrameSize;
333
155
    }
334
335
    /// Set the peer's header table size.
336
1.61k
    pub fn set_header_table_size(&mut self, val: usize) {
337
1.61k
        self.encoder.hpack.update_max_size(val);
338
1.61k
    }
Unexecuted instantiation: <h2::codec::framed_write::FramedWrite<_, _>>::set_header_table_size
<h2::codec::framed_write::FramedWrite<fuzz_e2e::MockIo, h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::set_header_table_size
Line
Count
Source
336
1.61k
    pub fn set_header_table_size(&mut self, val: usize) {
337
1.61k
        self.encoder.hpack.update_max_size(val);
338
1.61k
    }
339
340
    /// Retrieve the last data frame that has been sent
341
633k
    pub fn take_last_data_frame(&mut self) -> Option<frame::Data<B>> {
342
633k
        self.encoder.last_data_frame.take()
343
633k
    }
Unexecuted instantiation: <h2::codec::framed_write::FramedWrite<_, _>>::take_last_data_frame
<h2::codec::framed_write::FramedWrite<fuzz_e2e::MockIo, h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::take_last_data_frame
Line
Count
Source
341
633k
    pub fn take_last_data_frame(&mut self) -> Option<frame::Data<B>> {
342
633k
        self.encoder.last_data_frame.take()
343
633k
    }
344
345
863
    pub fn get_mut(&mut self) -> &mut T {
346
863
        &mut self.inner
347
863
    }
Unexecuted instantiation: <h2::codec::framed_write::FramedWrite<_, _>>::get_mut
<h2::codec::framed_write::FramedWrite<h2_support::mock::Pipe, bytes::bytes::Bytes>>::get_mut
Line
Count
Source
345
863
    pub fn get_mut(&mut self) -> &mut T {
346
863
        &mut self.inner
347
863
    }
348
}
349
350
impl<T: AsyncRead + Unpin, B> AsyncRead for FramedWrite<T, B> {
351
678k
    fn poll_read(
352
678k
        mut self: Pin<&mut Self>,
353
678k
        cx: &mut Context<'_>,
354
678k
        buf: &mut ReadBuf,
355
678k
    ) -> Poll<io::Result<()>> {
356
678k
        Pin::new(&mut self.inner).poll_read(cx, buf)
357
678k
    }
Unexecuted instantiation: <h2::codec::framed_write::FramedWrite<_, _> as tokio::io::async_read::AsyncRead>::poll_read
Unexecuted instantiation: <h2::codec::framed_write::FramedWrite<h2_support::mock::Pipe, bytes::bytes::Bytes> as tokio::io::async_read::AsyncRead>::poll_read
<h2::codec::framed_write::FramedWrite<fuzz_e2e::MockIo, h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>> as tokio::io::async_read::AsyncRead>::poll_read
Line
Count
Source
351
678k
    fn poll_read(
352
678k
        mut self: Pin<&mut Self>,
353
678k
        cx: &mut Context<'_>,
354
678k
        buf: &mut ReadBuf,
355
678k
    ) -> Poll<io::Result<()>> {
356
678k
        Pin::new(&mut self.inner).poll_read(cx, buf)
357
678k
    }
358
}
359
360
// We never project the Pin to `B`.
361
impl<T: Unpin, B> Unpin for FramedWrite<T, B> {}
362
363
#[cfg(feature = "unstable")]
364
mod unstable {
365
    use super::*;
366
367
    impl<T, B> FramedWrite<T, B> {
368
0
        pub fn get_ref(&self) -> &T {
369
0
            &self.inner
370
0
        }
371
    }
372
}