Coverage Report

Created: 2026-08-31 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/h2/src/frame/data.rs
Line
Count
Source
1
use crate::frame::{util, Error, Frame, Head, Kind, StreamId};
2
use bytes::{Buf, BufMut, Bytes};
3
4
use std::fmt;
5
6
/// Data frame
7
///
8
/// Data frames convey arbitrary, variable-length sequences of octets associated
9
/// with a stream. One or more DATA frames are used, for instance, to carry HTTP
10
/// request or response payloads.
11
#[derive(Eq, PartialEq)]
12
pub struct Data<T = Bytes> {
13
    stream_id: StreamId,
14
    data: T,
15
    flags: DataFlags,
16
    pad_len: Option<u8>,
17
}
18
19
#[derive(Copy, Clone, Default, Eq, PartialEq)]
20
struct DataFlags(u8);
21
22
const END_STREAM: u8 = 0x1;
23
const PADDED: u8 = 0x8;
24
const ALL: u8 = END_STREAM | PADDED;
25
26
impl<T> Data<T> {
27
    /// Creates a new DATA frame.
28
406k
    pub fn new(stream_id: StreamId, payload: T) -> Self {
29
406k
        assert!(!stream_id.is_zero());
30
31
406k
        Data {
32
406k
            stream_id,
33
406k
            data: payload,
34
406k
            flags: DataFlags::default(),
35
406k
            pad_len: None,
36
406k
        }
37
406k
    }
38
39
    /// Returns the stream identifier that this frame is associated with.
40
    ///
41
    /// This cannot be a zero stream identifier.
42
16.0k
    pub fn stream_id(&self) -> StreamId {
43
16.0k
        self.stream_id
44
16.0k
    }
45
46
    /// Gets the value of the `END_STREAM` flag for this frame.
47
    ///
48
    /// If true, this frame is the last that the endpoint will send for the
49
    /// identified stream.
50
    ///
51
    /// Setting this flag causes the stream to enter one of the "half-closed"
52
    /// states or the "closed" state (Section 5.1).
53
428k
    pub fn is_end_stream(&self) -> bool {
54
428k
        self.flags.is_end_stream()
55
428k
    }
56
57
    /// Sets the value for the `END_STREAM` flag on this frame.
58
434k
    pub fn set_end_stream(&mut self, val: bool) {
59
434k
        if val {
60
419k
            self.flags.set_end_stream();
61
419k
        } else {
62
15.1k
            self.flags.unset_end_stream();
63
15.1k
        }
64
434k
    }
Unexecuted instantiation: <h2::frame::data::Data>::set_end_stream
<h2::frame::data::Data>::set_end_stream
Line
Count
Source
58
434k
    pub fn set_end_stream(&mut self, val: bool) {
59
434k
        if val {
60
419k
            self.flags.set_end_stream();
61
419k
        } else {
62
15.1k
            self.flags.unset_end_stream();
63
15.1k
        }
64
434k
    }
65
66
    /// Returns whether the `PADDED` flag is set on this frame.
67
    #[cfg(feature = "unstable")]
68
    pub fn is_padded(&self) -> bool {
69
        self.flags.is_padded()
70
    }
71
72
    /// Sets the value for the `PADDED` flag on this frame.
73
    #[cfg(feature = "unstable")]
74
0
    pub fn set_padded(&mut self) {
75
0
        self.flags.set_padded();
76
0
    }
77
78
    /// Returns a reference to this frame's payload.
79
    ///
80
    /// This does **not** include any padding that might have been originally
81
    /// included.
82
1.29M
    pub fn payload(&self) -> &T {
83
1.29M
        &self.data
84
1.29M
    }
<h2::frame::data::Data>::payload
Line
Count
Source
82
492k
    pub fn payload(&self) -> &T {
83
492k
        &self.data
84
492k
    }
Unexecuted instantiation: <h2::frame::data::Data<h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::payload
<h2::frame::data::Data<h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::payload
Line
Count
Source
82
805k
    pub fn payload(&self) -> &T {
83
805k
        &self.data
84
805k
    }
85
86
    /// Returns a mutable reference to this frame's payload.
87
    ///
88
    /// This does **not** include any padding that might have been originally
89
    /// included.
90
747k
    pub fn payload_mut(&mut self) -> &mut T {
91
747k
        &mut self.data
92
747k
    }
Unexecuted instantiation: <h2::frame::data::Data<h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::payload_mut
Unexecuted instantiation: <h2::frame::data::Data>::payload_mut
<h2::frame::data::Data<h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::payload_mut
Line
Count
Source
90
747k
    pub fn payload_mut(&mut self) -> &mut T {
91
747k
        &mut self.data
92
747k
    }
93
94
    /// Consumes `self` and returns the frame's payload.
95
    ///
96
    /// This does **not** include any padding that might have been originally
97
    /// included.
98
456
    pub fn into_payload(self) -> T {
99
456
        self.data
100
456
    }
101
102
15.6k
    pub(crate) fn head(&self) -> Head {
103
15.6k
        Head::new(Kind::Data, self.flags.into(), self.stream_id)
104
15.6k
    }
Unexecuted instantiation: <h2::frame::data::Data<h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::head
<h2::frame::data::Data<h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::head
Line
Count
Source
102
15.6k
    pub(crate) fn head(&self) -> Head {
103
15.6k
        Head::new(Kind::Data, self.flags.into(), self.stream_id)
104
15.6k
    }
105
106
29.7k
    pub(crate) fn map<F, U>(self, f: F) -> Data<U>
107
29.7k
    where
108
29.7k
        F: FnOnce(T) -> U,
109
    {
110
29.7k
        Data {
111
29.7k
            stream_id: self.stream_id,
112
29.7k
            data: f(self.data),
113
29.7k
            flags: self.flags,
114
29.7k
            pad_len: self.pad_len,
115
29.7k
        }
116
29.7k
    }
<h2::frame::data::Data<h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::map::<<h2::proto::streams::prioritize::Prioritize>::reclaim_frame_inner<bytes::bytes::Bytes>::{closure#0}, bytes::bytes::Bytes>
Line
Count
Source
106
14.1k
    pub(crate) fn map<F, U>(self, f: F) -> Data<U>
107
14.1k
    where
108
14.1k
        F: FnOnce(T) -> U,
109
    {
110
14.1k
        Data {
111
14.1k
            stream_id: self.stream_id,
112
14.1k
            data: f(self.data),
113
14.1k
            flags: self.flags,
114
14.1k
            pad_len: self.pad_len,
115
14.1k
        }
116
14.1k
    }
<h2::frame::data::Data>::map::<<h2::proto::streams::prioritize::Prioritize>::pop_frame<bytes::bytes::Bytes>::{closure#2}, h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>
Line
Count
Source
106
15.6k
    pub(crate) fn map<F, U>(self, f: F) -> Data<U>
107
15.6k
    where
108
15.6k
        F: FnOnce(T) -> U,
109
    {
110
15.6k
        Data {
111
15.6k
            stream_id: self.stream_id,
112
15.6k
            data: f(self.data),
113
15.6k
            flags: self.flags,
114
15.6k
            pad_len: self.pad_len,
115
15.6k
        }
116
15.6k
    }
Unexecuted instantiation: <h2::frame::data::Data>::map::<<h2::proto::streams::prioritize::Prioritize>::pop_frame<bytes::bytes::Bytes>::{closure#3}, h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>
117
}
118
119
impl Data<Bytes> {
120
16.1k
    pub(crate) fn load(head: Head, mut payload: Bytes) -> Result<Self, Error> {
121
16.1k
        let flags = DataFlags::load(head.flag());
122
123
        // The stream identifier must not be zero
124
16.1k
        if head.stream_id().is_zero() {
125
31
            return Err(Error::InvalidStreamId);
126
16.1k
        }
127
128
16.1k
        let pad_len = if flags.is_padded() {
129
557
            let len = util::strip_padding(&mut payload)?;
130
525
            Some(len)
131
        } else {
132
15.5k
            None
133
        };
134
135
16.0k
        Ok(Data {
136
16.0k
            stream_id: head.stream_id(),
137
16.0k
            data: payload,
138
16.0k
            flags,
139
16.0k
            pad_len,
140
16.0k
        })
141
16.1k
    }
142
143
22.1k
    pub(crate) fn flow_controlled_len(&self) -> usize {
144
22.1k
        if let Some(pad_len) = self.pad_len {
145
            // if PADDED, pad length field counts too (the + 1)
146
880
            self.data.len() + usize::from(pad_len) + 1
147
        } else {
148
21.2k
            self.data.len()
149
        }
150
22.1k
    }
151
}
152
153
#[cfg(test)]
154
mod tests {
155
    use super::*;
156
    use bytes::Bytes;
157
158
    fn data_frame(data: &[u8], pad_len: Option<u8>) -> Data<Bytes> {
159
        Data {
160
            stream_id: StreamId::from(1),
161
            data: Bytes::copy_from_slice(data),
162
            flags: DataFlags::default(),
163
            pad_len,
164
        }
165
    }
166
167
    #[test]
168
    fn padding_overhead_no_padding() {
169
        let frame = data_frame(b"hello", None);
170
        assert_eq!(frame.flow_controlled_len() - frame.payload().len(), 0);
171
    }
172
173
    #[test]
174
    fn padding_overhead_small() {
175
        let frame = data_frame(b"hello", Some(10));
176
        assert_eq!(frame.flow_controlled_len() - frame.payload().len(), 11);
177
    }
178
179
    #[test]
180
    fn padding_overhead_max_does_not_overflow() {
181
        // Regression: the old padded_len() returned u8, so pad_len=255
182
        // caused 255u8 + 1 = 0. The correct overhead is 256.
183
        let frame = data_frame(b"", Some(255));
184
        assert_eq!(frame.flow_controlled_len() - frame.payload().len(), 256);
185
    }
186
187
    #[test]
188
    fn padding_overhead_max_with_data() {
189
        let frame = data_frame(b"hello", Some(255));
190
        assert_eq!(frame.flow_controlled_len() - frame.payload().len(), 256);
191
        assert_eq!(frame.flow_controlled_len(), 261);
192
    }
193
}
194
195
impl<T: Buf> Data<T> {
196
    /// Encode the data frame into the `dst` buffer.
197
    ///
198
    /// # Panics
199
    ///
200
    /// Panics if `dst` cannot contain the data frame.
201
12.2k
    pub(crate) fn encode_chunk<U: BufMut>(&mut self, dst: &mut U) {
202
12.2k
        let len = self.data.remaining();
203
204
12.2k
        assert!(dst.remaining_mut() >= len);
205
206
12.2k
        self.head().encode(len, dst);
207
12.2k
        dst.put(&mut self.data);
208
12.2k
    }
Unexecuted instantiation: <h2::frame::data::Data<h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::encode_chunk::<bytes::bytes_mut::BytesMut>
<h2::frame::data::Data<h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>::encode_chunk::<bytes::bytes_mut::BytesMut>
Line
Count
Source
201
12.2k
    pub(crate) fn encode_chunk<U: BufMut>(&mut self, dst: &mut U) {
202
12.2k
        let len = self.data.remaining();
203
204
12.2k
        assert!(dst.remaining_mut() >= len);
205
206
12.2k
        self.head().encode(len, dst);
207
12.2k
        dst.put(&mut self.data);
208
12.2k
    }
209
}
210
211
impl<T> From<Data<T>> for Frame<T> {
212
470k
    fn from(src: Data<T>) -> Self {
213
470k
        Frame::Data(src)
214
470k
    }
<h2::frame::Frame as core::convert::From<h2::frame::data::Data>>::from
Line
Count
Source
212
470k
    fn from(src: Data<T>) -> Self {
213
470k
        Frame::Data(src)
214
470k
    }
Unexecuted instantiation: <h2::frame::Frame<h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>> as core::convert::From<h2::frame::data::Data<h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>>>>::from
215
}
216
217
impl<T> fmt::Debug for Data<T> {
218
0
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
219
0
        let mut f = fmt.debug_struct("Data");
220
0
        f.field("stream_id", &self.stream_id);
221
0
        if !self.flags.is_empty() {
222
0
            f.field("flags", &self.flags);
223
0
        }
224
0
        if let Some(ref pad_len) = self.pad_len {
225
0
            f.field("pad_len", pad_len);
226
0
        }
227
        // `data` bytes purposefully excluded
228
0
        f.finish()
229
0
    }
Unexecuted instantiation: <h2::frame::data::Data<h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>> as core::fmt::Debug>::fmt
Unexecuted instantiation: <h2::frame::data::Data as core::fmt::Debug>::fmt
Unexecuted instantiation: <h2::frame::data::Data<h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>> as core::fmt::Debug>::fmt
Unexecuted instantiation: <h2::frame::data::Data as core::fmt::Debug>::fmt
230
}
231
232
// ===== impl DataFlags =====
233
234
impl DataFlags {
235
16.1k
    fn load(bits: u8) -> DataFlags {
236
16.1k
        DataFlags(bits & ALL)
237
16.1k
    }
238
239
0
    fn is_empty(&self) -> bool {
240
0
        self.0 == 0
241
0
    }
242
243
428k
    fn is_end_stream(&self) -> bool {
244
428k
        self.0 & END_STREAM == END_STREAM
245
428k
    }
246
247
419k
    fn set_end_stream(&mut self) {
248
419k
        self.0 |= END_STREAM
249
419k
    }
250
251
15.1k
    fn unset_end_stream(&mut self) {
252
15.1k
        self.0 &= !END_STREAM
253
15.1k
    }
254
255
16.1k
    fn is_padded(&self) -> bool {
256
16.1k
        self.0 & PADDED == PADDED
257
16.1k
    }
258
259
    #[cfg(feature = "unstable")]
260
0
    fn set_padded(&mut self) {
261
0
        self.0 |= PADDED
262
0
    }
263
}
264
265
impl From<DataFlags> for u8 {
266
15.6k
    fn from(src: DataFlags) -> u8 {
267
15.6k
        src.0
268
15.6k
    }
269
}
270
271
impl fmt::Debug for DataFlags {
272
0
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
273
0
        util::debug_flags(fmt, self.0)
274
0
            .flag_if(self.is_end_stream(), "END_STREAM")
275
0
            .flag_if(self.is_padded(), "PADDED")
276
0
            .finish()
277
0
    }
278
}