/src/neqo/neqo-http3/src/frames/reader.rs
Line | Count | Source |
1 | | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
2 | | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
3 | | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your |
4 | | // option. This file may not be copied, modified, or distributed |
5 | | // except according to those terms. |
6 | | |
7 | | use std::{cmp::min, fmt::Debug, time::Instant}; |
8 | | |
9 | | use neqo_common::{ |
10 | | Decoder, IncrementalDecoderBuffer, IncrementalDecoderIgnore, IncrementalDecoderUint, |
11 | | hex_snip_middle, hex_with_len, qtrace, |
12 | | }; |
13 | | use neqo_transport::{Connection, StreamId}; |
14 | | |
15 | | use super::hframe::HFrameType; |
16 | | use crate::{Error, RecvStream, Res}; |
17 | | |
18 | | const MAX_READ_SIZE: usize = 2048; // Given a practical MTU of 1500 bytes, this seems reasonable. |
19 | | |
20 | | pub trait FrameDecoder<T> { |
21 | | /// Fuzzing corpus name for this frame type. If `Some`, decoded frames will be |
22 | | /// written to the fuzzing corpus with this name. |
23 | | #[cfg(feature = "build-fuzzing-corpus")] |
24 | | const FUZZING_CORPUS: Option<&'static str> = None; |
25 | | |
26 | | fn is_known_type(frame_type: HFrameType) -> bool; |
27 | | |
28 | | /// # Errors |
29 | | /// |
30 | | /// Returns `HttpFrameUnexpected` if frames is not allowed, i.e. is a `H3_RESERVED_FRAME_TYPES`. |
31 | 1.83M | fn frame_type_allowed(_frame_type: HFrameType) -> Res<()> { |
32 | 1.83M | Ok(()) |
33 | 1.83M | } <neqo_http3::frames::wtframe::WebTransportFrame as neqo_http3::frames::reader::FrameDecoder<neqo_http3::frames::wtframe::WebTransportFrame>>::frame_type_allowed Line | Count | Source | 31 | 1.83M | fn frame_type_allowed(_frame_type: HFrameType) -> Res<()> { | 32 | 1.83M | Ok(()) | 33 | 1.83M | } |
Unexecuted instantiation: <neqo_http3::frames::capsule::Capsule as neqo_http3::frames::reader::FrameDecoder<neqo_http3::frames::capsule::Capsule>>::frame_type_allowed Unexecuted instantiation: <neqo_http3::frames::wtframe::WebTransportFrame as neqo_http3::frames::reader::FrameDecoder<neqo_http3::frames::wtframe::WebTransportFrame>>::frame_type_allowed |
34 | | |
35 | | /// # Errors |
36 | | /// |
37 | | /// If a frame cannot be properly decoded. |
38 | | fn decode(frame_type: HFrameType, frame_len: u64, data: Option<&[u8]>) -> Res<Option<T>>; |
39 | | } |
40 | | |
41 | | #[expect(clippy::module_name_repetitions, reason = "This is OK.")] |
42 | | pub trait StreamReader { |
43 | | /// # Errors |
44 | | /// |
45 | | /// An error may happen while reading a stream, e.g. early close, protocol error, etc. |
46 | | /// Return an error if the stream was closed on the transport layer, but that information is not |
47 | | /// yet consumed on the http/3 layer. |
48 | | fn read_data(&mut self, buf: &mut [u8], now: Instant) -> Res<(usize, bool)>; |
49 | | } |
50 | | |
51 | | pub struct StreamReaderConnectionWrapper<'a> { |
52 | | conn: &'a mut Connection, |
53 | | stream_id: StreamId, |
54 | | } |
55 | | |
56 | | impl<'a> StreamReaderConnectionWrapper<'a> { |
57 | 0 | pub const fn new(conn: &'a mut Connection, stream_id: StreamId) -> Self { |
58 | 0 | Self { conn, stream_id } |
59 | 0 | } |
60 | | } |
61 | | |
62 | | impl StreamReader for StreamReaderConnectionWrapper<'_> { |
63 | | /// # Errors |
64 | | /// |
65 | | /// An error may happen while reading a stream, e.g. early close, protocol error, etc. |
66 | 0 | fn read_data(&mut self, buf: &mut [u8], _now: Instant) -> Res<(usize, bool)> { |
67 | 0 | let res = self.conn.stream_recv(self.stream_id, buf)?; |
68 | 0 | Ok(res) |
69 | 0 | } |
70 | | } |
71 | | |
72 | | pub struct StreamReaderRecvStreamWrapper<'a> { |
73 | | recv_stream: &'a mut Box<dyn RecvStream>, |
74 | | conn: &'a mut Connection, |
75 | | } |
76 | | |
77 | | impl<'a> StreamReaderRecvStreamWrapper<'a> { |
78 | | #[cfg_attr(fuzzing, expect(private_interfaces, reason = "OK for fuzzing."))] |
79 | 0 | pub fn new(conn: &'a mut Connection, recv_stream: &'a mut Box<dyn RecvStream>) -> Self { |
80 | 0 | Self { recv_stream, conn } |
81 | 0 | } |
82 | | } |
83 | | |
84 | | impl StreamReader for StreamReaderRecvStreamWrapper<'_> { |
85 | | /// # Errors |
86 | | /// |
87 | | /// An error may happen while reading a stream, e.g. early close, protocol error, etc. |
88 | 0 | fn read_data(&mut self, buf: &mut [u8], now: Instant) -> Res<(usize, bool)> { |
89 | 0 | self.recv_stream.read_data(self.conn, buf, now) |
90 | 0 | } |
91 | | } |
92 | | |
93 | | #[derive(Clone, Debug)] |
94 | | enum FrameReaderState { |
95 | | GetType { decoder: IncrementalDecoderUint }, |
96 | | GetLength { decoder: IncrementalDecoderUint }, |
97 | | GetData { decoder: IncrementalDecoderBuffer }, |
98 | | UnknownFrameDischargeData { decoder: IncrementalDecoderIgnore }, |
99 | | } |
100 | | |
101 | | #[expect(clippy::module_name_repetitions, reason = "This is OK.")] |
102 | | pub struct FrameReader { |
103 | | state: FrameReaderState, |
104 | | frame_type: HFrameType, |
105 | | frame_len: u64, |
106 | | buffer: [u8; MAX_READ_SIZE], |
107 | | } |
108 | | |
109 | | impl Debug for FrameReader { |
110 | 0 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
111 | 0 | let frame_len = self |
112 | 0 | .frame_len |
113 | 0 | .try_into() |
114 | 0 | .unwrap_or(usize::MAX) |
115 | 0 | .min(self.buffer.len()); |
116 | 0 | f.debug_struct("FrameReader") |
117 | 0 | .field("state", &self.state) |
118 | 0 | .field("frame_type", &self.frame_type) |
119 | 0 | .field("frame", &hex_snip_middle(&self.buffer[..frame_len])) |
120 | 0 | .finish() |
121 | 0 | } |
122 | | } |
123 | | |
124 | | impl FrameReader { |
125 | | #[must_use] |
126 | 6.05k | pub fn new() -> Self { |
127 | 6.05k | Self { |
128 | 6.05k | state: FrameReaderState::GetType { |
129 | 6.05k | decoder: IncrementalDecoderUint::default(), |
130 | 6.05k | }, |
131 | 6.05k | frame_type: HFrameType(u64::MAX), |
132 | 6.05k | frame_len: 0, |
133 | 6.05k | buffer: [0; MAX_READ_SIZE], |
134 | 6.05k | } |
135 | 6.05k | } |
136 | | |
137 | | #[must_use] |
138 | 0 | pub fn new_with_type(frame_type: HFrameType) -> Self { |
139 | 0 | Self { |
140 | 0 | state: FrameReaderState::GetLength { |
141 | 0 | decoder: IncrementalDecoderUint::default(), |
142 | 0 | }, |
143 | 0 | frame_type, |
144 | 0 | frame_len: 0, |
145 | 0 | buffer: [0; MAX_READ_SIZE], |
146 | 0 | } |
147 | 0 | } |
148 | | |
149 | 1.91M | fn reset(&mut self) { |
150 | 1.91M | self.state = FrameReaderState::GetType { |
151 | 1.91M | decoder: IncrementalDecoderUint::default(), |
152 | 1.91M | }; |
153 | 1.91M | } |
154 | | |
155 | 4.04M | fn min_remaining(&self) -> usize { |
156 | 4.04M | match &self.state { |
157 | 1.92M | FrameReaderState::GetType { decoder } | FrameReaderState::GetLength { decoder } => { |
158 | 3.85M | decoder.min_remaining() |
159 | | } |
160 | 57.2k | FrameReaderState::GetData { decoder } => decoder.min_remaining(), |
161 | 138k | FrameReaderState::UnknownFrameDischargeData { decoder } => decoder.min_remaining(), |
162 | | } |
163 | 4.04M | } |
164 | | |
165 | 1.57k | const fn decoding_in_progress(&self) -> bool { |
166 | 1.57k | if let FrameReaderState::GetType { decoder } = &self.state { |
167 | 437 | decoder.decoding_in_progress() |
168 | | } else { |
169 | 1.14k | true |
170 | | } |
171 | 1.57k | } |
172 | | |
173 | | /// Returns true if QUIC stream was closed. |
174 | | /// |
175 | | /// # Errors |
176 | | /// |
177 | | /// May return `HttpFrame` if a frame cannot be decoded. |
178 | | /// and `TransportStreamDoesNotExist` if `stream_recv` fails. |
179 | 6.05k | pub fn receive<T: FrameDecoder<T>>( |
180 | 6.05k | &mut self, |
181 | 6.05k | stream_reader: &mut dyn StreamReader, |
182 | 6.05k | now: Instant, |
183 | 6.05k | ) -> Res<(Option<T>, bool)> { |
184 | | loop { |
185 | 4.04M | let to_read = min(self.min_remaining(), self.buffer.len()); |
186 | 4.04M | let (output, read, fin) = match stream_reader |
187 | 4.04M | .read_data(&mut self.buffer[..to_read], now) |
188 | 4.04M | .map_err(|e| Error::map_stream_recv_errors(&e))? Unexecuted instantiation: <neqo_http3::frames::reader::FrameReader>::receive::<neqo_http3::frames::wtframe::WebTransportFrame>::{closure#0}Unexecuted instantiation: <neqo_http3::frames::reader::FrameReader>::receive::<neqo_http3::frames::hframe::HFrame>::{closure#0}Unexecuted instantiation: <neqo_http3::frames::reader::FrameReader>::receive::<neqo_http3::frames::capsule::Capsule>::{closure#0}Unexecuted instantiation: <neqo_http3::frames::reader::FrameReader>::receive::<neqo_http3::frames::wtframe::WebTransportFrame>::{closure#0}Unexecuted instantiation: <neqo_http3::frames::reader::FrameReader>::receive::<neqo_http3::frames::hframe::HFrame>::{closure#0} |
189 | | { |
190 | 0 | (0, f) => (None, false, f), |
191 | 4.04M | (amount, f) => { |
192 | 4.04M | qtrace!("FrameReader::receive: reading {amount} byte, fin={f}"); |
193 | 4.04M | (self.consume::<T>(amount)?, true, f) |
194 | | } |
195 | | }; |
196 | | |
197 | 4.04M | if output.is_some() { |
198 | 1.73k | break Ok((output, fin)); |
199 | 4.04M | } |
200 | | |
201 | 4.04M | if fin { |
202 | 1.57k | if self.decoding_in_progress() { |
203 | 1.26k | break Err(Error::HttpFrame); |
204 | 312 | } |
205 | 312 | break Ok((None, fin)); |
206 | 4.04M | } |
207 | | |
208 | 4.04M | if !read { |
209 | | // There was no new data, exit the loop. |
210 | 0 | break Ok((None, false)); |
211 | 4.04M | } |
212 | | } |
213 | 6.05k | } <neqo_http3::frames::reader::FrameReader>::receive::<neqo_http3::frames::wtframe::WebTransportFrame> Line | Count | Source | 179 | 888 | pub fn receive<T: FrameDecoder<T>>( | 180 | 888 | &mut self, | 181 | 888 | stream_reader: &mut dyn StreamReader, | 182 | 888 | now: Instant, | 183 | 888 | ) -> Res<(Option<T>, bool)> { | 184 | | loop { | 185 | 3.73M | let to_read = min(self.min_remaining(), self.buffer.len()); | 186 | 3.73M | let (output, read, fin) = match stream_reader | 187 | 3.73M | .read_data(&mut self.buffer[..to_read], now) | 188 | 3.73M | .map_err(|e| Error::map_stream_recv_errors(&e))? | 189 | | { | 190 | 0 | (0, f) => (None, false, f), | 191 | 3.73M | (amount, f) => { | 192 | 3.73M | qtrace!("FrameReader::receive: reading {amount} byte, fin={f}"); | 193 | 3.73M | (self.consume::<T>(amount)?, true, f) | 194 | | } | 195 | | }; | 196 | | | 197 | 3.73M | if output.is_some() { | 198 | 69 | break Ok((output, fin)); | 199 | 3.73M | } | 200 | | | 201 | 3.73M | if fin { | 202 | 724 | if self.decoding_in_progress() { | 203 | 614 | break Err(Error::HttpFrame); | 204 | 110 | } | 205 | 110 | break Ok((None, fin)); | 206 | 3.73M | } | 207 | | | 208 | 3.73M | if !read { | 209 | | // There was no new data, exit the loop. | 210 | 0 | break Ok((None, false)); | 211 | 3.73M | } | 212 | | } | 213 | 888 | } |
Unexecuted instantiation: <neqo_http3::frames::reader::FrameReader>::receive::<neqo_http3::frames::hframe::HFrame> Unexecuted instantiation: <neqo_http3::frames::reader::FrameReader>::receive::<neqo_http3::frames::capsule::Capsule> Unexecuted instantiation: <neqo_http3::frames::reader::FrameReader>::receive::<neqo_http3::frames::wtframe::WebTransportFrame> <neqo_http3::frames::reader::FrameReader>::receive::<neqo_http3::frames::hframe::HFrame> Line | Count | Source | 179 | 5.16k | pub fn receive<T: FrameDecoder<T>>( | 180 | 5.16k | &mut self, | 181 | 5.16k | stream_reader: &mut dyn StreamReader, | 182 | 5.16k | now: Instant, | 183 | 5.16k | ) -> Res<(Option<T>, bool)> { | 184 | | loop { | 185 | 311k | let to_read = min(self.min_remaining(), self.buffer.len()); | 186 | 311k | let (output, read, fin) = match stream_reader | 187 | 311k | .read_data(&mut self.buffer[..to_read], now) | 188 | 311k | .map_err(|e| Error::map_stream_recv_errors(&e))? | 189 | | { | 190 | 0 | (0, f) => (None, false, f), | 191 | 311k | (amount, f) => { | 192 | 311k | qtrace!("FrameReader::receive: reading {amount} byte, fin={f}"); | 193 | 311k | (self.consume::<T>(amount)?, true, f) | 194 | | } | 195 | | }; | 196 | | | 197 | 309k | if output.is_some() { | 198 | 1.66k | break Ok((output, fin)); | 199 | 307k | } | 200 | | | 201 | 307k | if fin { | 202 | 855 | if self.decoding_in_progress() { | 203 | 653 | break Err(Error::HttpFrame); | 204 | 202 | } | 205 | 202 | break Ok((None, fin)); | 206 | 306k | } | 207 | | | 208 | 306k | if !read { | 209 | | // There was no new data, exit the loop. | 210 | 0 | break Ok((None, false)); | 211 | 306k | } | 212 | | } | 213 | 5.16k | } |
|
214 | | |
215 | | /// # Errors |
216 | | /// |
217 | | /// May return `HttpFrame` if a frame cannot be decoded. |
218 | 4.04M | fn consume<T: FrameDecoder<T>>(&mut self, amount: usize) -> Res<Option<T>> { |
219 | 4.04M | let mut input = Decoder::from(&self.buffer[..amount]); |
220 | 4.04M | match &mut self.state { |
221 | 1.92M | FrameReaderState::GetType { decoder } => { |
222 | 1.92M | if let Some(v) = decoder.consume(&mut input) { |
223 | 1.92M | qtrace!("FrameReader::receive: read frame type {v}"); |
224 | 1.92M | self.frame_type_decoded::<T>(HFrameType(v))?; |
225 | 6.23k | } |
226 | | } |
227 | 1.92M | FrameReaderState::GetLength { decoder } => { |
228 | 1.92M | if let Some(len) = decoder.consume(&mut input) { |
229 | 1.92M | qtrace!( |
230 | | "FrameReader::receive: frame type {:?} length {len}", |
231 | | self.frame_type |
232 | | ); |
233 | 1.92M | return self.frame_length_decoded::<T>(len); |
234 | 3.86k | } |
235 | | } |
236 | 57.2k | FrameReaderState::GetData { decoder } => { |
237 | 57.2k | if let Some(data) = decoder.consume(&mut input) { |
238 | 4.44k | qtrace!( |
239 | | "received frame {:?}: {}", |
240 | | self.frame_type, |
241 | 0 | hex_with_len(&data[..]) |
242 | | ); |
243 | 4.44k | return self.frame_data_decoded::<T>(&data); |
244 | 52.7k | } |
245 | | } |
246 | 138k | FrameReaderState::UnknownFrameDischargeData { decoder } => { |
247 | 138k | if decoder.consume(&mut input) { |
248 | 134k | self.reset(); |
249 | 134k | } |
250 | | } |
251 | | } |
252 | 2.12M | Ok(None) |
253 | 4.04M | } <neqo_http3::frames::reader::FrameReader>::consume::<neqo_http3::frames::wtframe::WebTransportFrame> Line | Count | Source | 218 | 3.73M | fn consume<T: FrameDecoder<T>>(&mut self, amount: usize) -> Res<Option<T>> { | 219 | 3.73M | let mut input = Decoder::from(&self.buffer[..amount]); | 220 | 3.73M | match &mut self.state { | 221 | 1.83M | FrameReaderState::GetType { decoder } => { | 222 | 1.83M | if let Some(v) = decoder.consume(&mut input) { | 223 | 1.83M | qtrace!("FrameReader::receive: read frame type {v}"); | 224 | 1.83M | self.frame_type_decoded::<T>(HFrameType(v))?; | 225 | 1.68k | } | 226 | | } | 227 | 1.83M | FrameReaderState::GetLength { decoder } => { | 228 | 1.83M | if let Some(len) = decoder.consume(&mut input) { | 229 | 1.83M | qtrace!( | 230 | | "FrameReader::receive: frame type {:?} length {len}", | 231 | | self.frame_type | 232 | | ); | 233 | 1.83M | return self.frame_length_decoded::<T>(len); | 234 | 1.33k | } | 235 | | } | 236 | 4.92k | FrameReaderState::GetData { decoder } => { | 237 | 4.92k | if let Some(data) = decoder.consume(&mut input) { | 238 | 161 | qtrace!( | 239 | | "received frame {:?}: {}", | 240 | | self.frame_type, | 241 | 0 | hex_with_len(&data[..]) | 242 | | ); | 243 | 161 | return self.frame_data_decoded::<T>(&data); | 244 | 4.76k | } | 245 | | } | 246 | 57.7k | FrameReaderState::UnknownFrameDischargeData { decoder } => { | 247 | 57.7k | if decoder.consume(&mut input) { | 248 | 55.2k | self.reset(); | 249 | 55.2k | } | 250 | | } | 251 | | } | 252 | 1.90M | Ok(None) | 253 | 3.73M | } |
Unexecuted instantiation: <neqo_http3::frames::reader::FrameReader>::consume::<neqo_http3::frames::hframe::HFrame> Unexecuted instantiation: <neqo_http3::frames::reader::FrameReader>::consume::<neqo_http3::frames::capsule::Capsule> Unexecuted instantiation: <neqo_http3::frames::reader::FrameReader>::consume::<neqo_http3::frames::wtframe::WebTransportFrame> <neqo_http3::frames::reader::FrameReader>::consume::<neqo_http3::frames::hframe::HFrame> Line | Count | Source | 218 | 311k | fn consume<T: FrameDecoder<T>>(&mut self, amount: usize) -> Res<Option<T>> { | 219 | 311k | let mut input = Decoder::from(&self.buffer[..amount]); | 220 | 311k | match &mut self.state { | 221 | 90.6k | FrameReaderState::GetType { decoder } => { | 222 | 90.6k | if let Some(v) = decoder.consume(&mut input) { | 223 | 86.1k | qtrace!("FrameReader::receive: read frame type {v}"); | 224 | 86.1k | self.frame_type_decoded::<T>(HFrameType(v))?; | 225 | 4.55k | } | 226 | | } | 227 | 88.5k | FrameReaderState::GetLength { decoder } => { | 228 | 88.5k | if let Some(len) = decoder.consume(&mut input) { | 229 | 85.9k | qtrace!( | 230 | | "FrameReader::receive: frame type {:?} length {len}", | 231 | | self.frame_type | 232 | | ); | 233 | 85.9k | return self.frame_length_decoded::<T>(len); | 234 | 2.52k | } | 235 | | } | 236 | 52.3k | FrameReaderState::GetData { decoder } => { | 237 | 52.3k | if let Some(data) = decoder.consume(&mut input) { | 238 | 4.28k | qtrace!( | 239 | | "received frame {:?}: {}", | 240 | | self.frame_type, | 241 | 0 | hex_with_len(&data[..]) | 242 | | ); | 243 | 4.28k | return self.frame_data_decoded::<T>(&data); | 244 | 48.0k | } | 245 | | } | 246 | 80.3k | FrameReaderState::UnknownFrameDischargeData { decoder } => { | 247 | 80.3k | if decoder.consume(&mut input) { | 248 | 79.4k | self.reset(); | 249 | 79.4k | } | 250 | | } | 251 | | } | 252 | 221k | Ok(None) | 253 | 311k | } |
|
254 | 1.92M | fn frame_type_decoded<T: FrameDecoder<T>>(&mut self, frame_type: HFrameType) -> Res<()> { |
255 | 1.92M | T::frame_type_allowed(frame_type)?; |
256 | 1.92M | self.frame_type = frame_type; |
257 | 1.92M | self.state = FrameReaderState::GetLength { |
258 | 1.92M | decoder: IncrementalDecoderUint::default(), |
259 | 1.92M | }; |
260 | 1.92M | Ok(()) |
261 | 1.92M | } <neqo_http3::frames::reader::FrameReader>::frame_type_decoded::<neqo_http3::frames::wtframe::WebTransportFrame> Line | Count | Source | 254 | 1.83M | fn frame_type_decoded<T: FrameDecoder<T>>(&mut self, frame_type: HFrameType) -> Res<()> { | 255 | 1.83M | T::frame_type_allowed(frame_type)?; | 256 | 1.83M | self.frame_type = frame_type; | 257 | 1.83M | self.state = FrameReaderState::GetLength { | 258 | 1.83M | decoder: IncrementalDecoderUint::default(), | 259 | 1.83M | }; | 260 | 1.83M | Ok(()) | 261 | 1.83M | } |
Unexecuted instantiation: <neqo_http3::frames::reader::FrameReader>::frame_type_decoded::<neqo_http3::frames::hframe::HFrame> Unexecuted instantiation: <neqo_http3::frames::reader::FrameReader>::frame_type_decoded::<neqo_http3::frames::capsule::Capsule> Unexecuted instantiation: <neqo_http3::frames::reader::FrameReader>::frame_type_decoded::<neqo_http3::frames::wtframe::WebTransportFrame> <neqo_http3::frames::reader::FrameReader>::frame_type_decoded::<neqo_http3::frames::hframe::HFrame> Line | Count | Source | 254 | 86.1k | fn frame_type_decoded<T: FrameDecoder<T>>(&mut self, frame_type: HFrameType) -> Res<()> { | 255 | 86.1k | T::frame_type_allowed(frame_type)?; | 256 | 86.1k | self.frame_type = frame_type; | 257 | 86.1k | self.state = FrameReaderState::GetLength { | 258 | 86.1k | decoder: IncrementalDecoderUint::default(), | 259 | 86.1k | }; | 260 | 86.1k | Ok(()) | 261 | 86.1k | } |
|
262 | | |
263 | 1.92M | fn frame_length_decoded<T: FrameDecoder<T>>(&mut self, len: u64) -> Res<Option<T>> { |
264 | 1.92M | self.frame_len = len; |
265 | 1.92M | match T::decode( |
266 | 1.92M | self.frame_type, |
267 | 1.92M | self.frame_len, |
268 | 1.92M | if len > 0 { None } else { Some(&[]) }, |
269 | 10 | )? { |
270 | 17 | Some(f) => { |
271 | | #[cfg(feature = "build-fuzzing-corpus")] |
272 | | if let Some(corpus) = T::FUZZING_CORPUS { |
273 | | // Write zero-length frames to the fuzzing corpus to test parsing of frames with |
274 | | // only type and length fields. |
275 | | self.write_item_to_fuzzing_corpus(corpus, None); |
276 | | } |
277 | 17 | self.reset(); |
278 | 17 | return Ok(Some(f)); |
279 | | } |
280 | | None => { |
281 | 1.92M | if T::is_known_type(self.frame_type) { |
282 | 4.83k | self.state = FrameReaderState::GetData { |
283 | 4.83k | decoder: IncrementalDecoderBuffer::new( |
284 | 4.83k | usize::try_from(len).or(Err(Error::HttpFrame))?, |
285 | | ), |
286 | | }; |
287 | 1.91M | } else if self.frame_len == 0 { |
288 | 1.78M | self.reset(); |
289 | 1.78M | } else { |
290 | 135k | self.state = FrameReaderState::UnknownFrameDischargeData { |
291 | 135k | decoder: IncrementalDecoderIgnore::new( |
292 | 135k | usize::try_from(len).or(Err(Error::HttpFrame))?, |
293 | | ), |
294 | | }; |
295 | | } |
296 | | } |
297 | | } |
298 | 1.92M | Ok(None) |
299 | 1.92M | } <neqo_http3::frames::reader::FrameReader>::frame_length_decoded::<neqo_http3::frames::wtframe::WebTransportFrame> Line | Count | Source | 263 | 1.83M | fn frame_length_decoded<T: FrameDecoder<T>>(&mut self, len: u64) -> Res<Option<T>> { | 264 | 1.83M | self.frame_len = len; | 265 | 1.83M | match T::decode( | 266 | 1.83M | self.frame_type, | 267 | 1.83M | self.frame_len, | 268 | 1.83M | if len > 0 { None } else { Some(&[]) }, | 269 | 3 | )? { | 270 | 0 | Some(f) => { | 271 | | #[cfg(feature = "build-fuzzing-corpus")] | 272 | | if let Some(corpus) = T::FUZZING_CORPUS { | 273 | | // Write zero-length frames to the fuzzing corpus to test parsing of frames with | 274 | | // only type and length fields. | 275 | | self.write_item_to_fuzzing_corpus(corpus, None); | 276 | | } | 277 | 0 | self.reset(); | 278 | 0 | return Ok(Some(f)); | 279 | | } | 280 | | None => { | 281 | 1.83M | if T::is_known_type(self.frame_type) { | 282 | 358 | self.state = FrameReaderState::GetData { | 283 | 358 | decoder: IncrementalDecoderBuffer::new( | 284 | 358 | usize::try_from(len).or(Err(Error::HttpFrame))?, | 285 | | ), | 286 | | }; | 287 | 1.83M | } else if self.frame_len == 0 { | 288 | 1.77M | self.reset(); | 289 | 1.77M | } else { | 290 | 55.5k | self.state = FrameReaderState::UnknownFrameDischargeData { | 291 | 55.5k | decoder: IncrementalDecoderIgnore::new( | 292 | 55.5k | usize::try_from(len).or(Err(Error::HttpFrame))?, | 293 | | ), | 294 | | }; | 295 | | } | 296 | | } | 297 | | } | 298 | 1.83M | Ok(None) | 299 | 1.83M | } |
Unexecuted instantiation: <neqo_http3::frames::reader::FrameReader>::frame_length_decoded::<neqo_http3::frames::hframe::HFrame> Unexecuted instantiation: <neqo_http3::frames::reader::FrameReader>::frame_length_decoded::<neqo_http3::frames::capsule::Capsule> Unexecuted instantiation: <neqo_http3::frames::reader::FrameReader>::frame_length_decoded::<neqo_http3::frames::wtframe::WebTransportFrame> <neqo_http3::frames::reader::FrameReader>::frame_length_decoded::<neqo_http3::frames::hframe::HFrame> Line | Count | Source | 263 | 85.9k | fn frame_length_decoded<T: FrameDecoder<T>>(&mut self, len: u64) -> Res<Option<T>> { | 264 | 85.9k | self.frame_len = len; | 265 | 85.9k | match T::decode( | 266 | 85.9k | self.frame_type, | 267 | 85.9k | self.frame_len, | 268 | 85.9k | if len > 0 { None } else { Some(&[]) }, | 269 | 7 | )? { | 270 | 17 | Some(f) => { | 271 | | #[cfg(feature = "build-fuzzing-corpus")] | 272 | | if let Some(corpus) = T::FUZZING_CORPUS { | 273 | | // Write zero-length frames to the fuzzing corpus to test parsing of frames with | 274 | | // only type and length fields. | 275 | | self.write_item_to_fuzzing_corpus(corpus, None); | 276 | | } | 277 | 17 | self.reset(); | 278 | 17 | return Ok(Some(f)); | 279 | | } | 280 | | None => { | 281 | 85.9k | if T::is_known_type(self.frame_type) { | 282 | 4.47k | self.state = FrameReaderState::GetData { | 283 | 4.47k | decoder: IncrementalDecoderBuffer::new( | 284 | 4.47k | usize::try_from(len).or(Err(Error::HttpFrame))?, | 285 | | ), | 286 | | }; | 287 | 81.4k | } else if self.frame_len == 0 { | 288 | 1.73k | self.reset(); | 289 | 1.73k | } else { | 290 | 79.7k | self.state = FrameReaderState::UnknownFrameDischargeData { | 291 | 79.7k | decoder: IncrementalDecoderIgnore::new( | 292 | 79.7k | usize::try_from(len).or(Err(Error::HttpFrame))?, | 293 | | ), | 294 | | }; | 295 | | } | 296 | | } | 297 | | } | 298 | 85.9k | Ok(None) | 299 | 85.9k | } |
|
300 | | |
301 | 4.44k | fn frame_data_decoded<T: FrameDecoder<T>>(&mut self, data: &[u8]) -> Res<Option<T>> { |
302 | | #[cfg(feature = "build-fuzzing-corpus")] |
303 | | if let Some(corpus) = T::FUZZING_CORPUS { |
304 | | self.write_item_to_fuzzing_corpus(corpus, Some(data)); |
305 | | } |
306 | | |
307 | 4.44k | let res = T::decode(self.frame_type, self.frame_len, Some(data))?; |
308 | 1.71k | self.reset(); |
309 | 1.71k | Ok(res) |
310 | 4.44k | } <neqo_http3::frames::reader::FrameReader>::frame_data_decoded::<neqo_http3::frames::wtframe::WebTransportFrame> Line | Count | Source | 301 | 161 | fn frame_data_decoded<T: FrameDecoder<T>>(&mut self, data: &[u8]) -> Res<Option<T>> { | 302 | | #[cfg(feature = "build-fuzzing-corpus")] | 303 | | if let Some(corpus) = T::FUZZING_CORPUS { | 304 | | self.write_item_to_fuzzing_corpus(corpus, Some(data)); | 305 | | } | 306 | | | 307 | 161 | let res = T::decode(self.frame_type, self.frame_len, Some(data))?; | 308 | 69 | self.reset(); | 309 | 69 | Ok(res) | 310 | 161 | } |
Unexecuted instantiation: <neqo_http3::frames::reader::FrameReader>::frame_data_decoded::<neqo_http3::frames::hframe::HFrame> Unexecuted instantiation: <neqo_http3::frames::reader::FrameReader>::frame_data_decoded::<neqo_http3::frames::capsule::Capsule> Unexecuted instantiation: <neqo_http3::frames::reader::FrameReader>::frame_data_decoded::<neqo_http3::frames::wtframe::WebTransportFrame> <neqo_http3::frames::reader::FrameReader>::frame_data_decoded::<neqo_http3::frames::hframe::HFrame> Line | Count | Source | 301 | 4.28k | fn frame_data_decoded<T: FrameDecoder<T>>(&mut self, data: &[u8]) -> Res<Option<T>> { | 302 | | #[cfg(feature = "build-fuzzing-corpus")] | 303 | | if let Some(corpus) = T::FUZZING_CORPUS { | 304 | | self.write_item_to_fuzzing_corpus(corpus, Some(data)); | 305 | | } | 306 | | | 307 | 4.28k | let res = T::decode(self.frame_type, self.frame_len, Some(data))?; | 308 | 1.64k | self.reset(); | 309 | 1.64k | Ok(res) | 310 | 4.28k | } |
|
311 | | |
312 | | #[cfg(feature = "build-fuzzing-corpus")] |
313 | | /// Write `HFrame` data to indicated fuzzing corpus. |
314 | | /// |
315 | | /// The output consists of the varint-encoded frame type and length, followed by the optional |
316 | | /// payload data. |
317 | | fn write_item_to_fuzzing_corpus(&self, corpus: &str, data: Option<&[u8]>) { |
318 | | // We need to include the frame type and length varints before the data |
319 | | // to create a complete frame that the fuzzer can process. |
320 | | let mut encoder = neqo_common::Encoder::default(); |
321 | | encoder.encode_varint(self.frame_type.0); |
322 | | encoder.encode_varint(self.frame_len); |
323 | | if let Some(d) = data { |
324 | | encoder.encode(d); |
325 | | } |
326 | | neqo_common::write_item_to_fuzzing_corpus(corpus, encoder.as_ref()); |
327 | | } |
328 | | } |