1use core::fmt;
4
5use crate::quic::varint::{
6 QuicVarInt, QuicVarIntBuildError, QuicVarIntBuilder, QuicVarIntLen, QuicVarIntParseError,
7};
8
9use super::envelope::{
10 Http3Frame, Http3FrameBuildError, Http3FrameEnvelopePlan, Http3FrameParseError,
11};
12use crate::http3::codepoints::Http3FrameType;
13
14#[derive(Clone, Copy, Debug, Eq, PartialEq)]
16pub enum Http3FramePayloadField {
17 PushId,
19 GoawayIdentifier,
21 SettingIdentifier,
23 SettingValue,
25}
26
27impl fmt::Display for Http3FramePayloadField {
28 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29 match self {
30 Self::PushId => f.write_str("Push ID"),
31 Self::GoawayIdentifier => f.write_str("GOAWAY identifier"),
32 Self::SettingIdentifier => f.write_str("SETTINGS identifier"),
33 Self::SettingValue => f.write_str("SETTINGS value"),
34 }
35 }
36}
37
38#[derive(Clone, Copy, Debug, Eq, PartialEq)]
40pub enum Http3FramePayloadParseError {
41 Frame(Http3FrameParseError),
43 WrongFrameType {
45 expected: Http3FrameType,
47 actual: Http3FrameType,
49 },
50 PayloadVarInt {
52 field: Http3FramePayloadField,
54 offset: usize,
56 error: QuicVarIntParseError,
58 },
59 TrailingPayload {
61 consumed: usize,
63 actual: usize,
65 },
66}
67
68impl fmt::Display for Http3FramePayloadParseError {
69 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70 match self {
71 Self::Frame(error) => write!(f, "HTTP/3 frame: {error}"),
72 Self::WrongFrameType { expected, actual } => write!(
73 f,
74 "wrong HTTP/3 frame type: expected {}, got {}",
75 expected.value(),
76 actual.value()
77 ),
78 Self::PayloadVarInt {
79 field,
80 offset,
81 error,
82 } => write!(
83 f,
84 "HTTP/3 {field} variable-length integer at payload offset {offset}: {error}"
85 ),
86 Self::TrailingPayload { consumed, actual } => write!(
87 f,
88 "HTTP/3 frame payload has trailing bytes: consumed {consumed}, got {actual}"
89 ),
90 }
91 }
92}
93
94impl core::error::Error for Http3FramePayloadParseError {
95 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
96 match self {
97 Self::Frame(error) => Some(error),
98 Self::WrongFrameType { .. }
99 | Self::PayloadVarInt { .. }
100 | Self::TrailingPayload { .. } => None,
101 }
102 }
103}
104
105#[derive(Clone, Copy, Debug, Eq, PartialEq)]
107pub enum Http3FramePayloadBuildError {
108 Frame(Http3FrameBuildError),
110 PayloadVarInt {
112 field: Http3FramePayloadField,
114 error: QuicVarIntBuildError,
116 },
117 PayloadLengthOverflow {
119 current: usize,
121 addition: usize,
123 },
124}
125
126impl fmt::Display for Http3FramePayloadBuildError {
127 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
128 match self {
129 Self::Frame(error) => write!(f, "HTTP/3 frame: {error}"),
130 Self::PayloadVarInt { field, error } => {
131 write!(f, "HTTP/3 {field} variable-length integer: {error}")
132 }
133 Self::PayloadLengthOverflow { current, addition } => write!(
134 f,
135 "HTTP/3 frame payload length overflows: {current} plus {addition} bytes"
136 ),
137 }
138 }
139}
140
141impl core::error::Error for Http3FramePayloadBuildError {
142 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
143 match self {
144 Self::Frame(error) => Some(error),
145 Self::PayloadVarInt { .. } | Self::PayloadLengthOverflow { .. } => None,
146 }
147 }
148}
149
150pub(in crate::http3) struct EncodedVarInt {
151 bytes: [u8; 8],
152 pub(super) len: QuicVarIntLen,
153}
154
155impl EncodedVarInt {
156 pub(in crate::http3) fn bytes(&self) -> &[u8] {
157 &self.bytes[..self.len.byte_len()]
158 }
159
160 pub(in crate::http3) const fn byte_len(&self) -> usize {
161 self.len.byte_len()
162 }
163}
164
165pub(in crate::http3) fn encode_varint(value: u64) -> Result<EncodedVarInt, QuicVarIntBuildError> {
166 let mut bytes = [0; 8];
167 let varint = QuicVarIntBuilder::new(&mut bytes, value).build()?;
168 let len = varint.encoded_len();
169 Ok(EncodedVarInt { bytes, len })
170}
171
172pub(super) fn envelope(
173 frame_type: Http3FrameType,
174 payload_length: usize,
175 destination: &mut [u8],
176) -> Result<Http3FrameEnvelopePlan, Http3FramePayloadBuildError> {
177 Http3FrameEnvelopePlan::new(frame_type, payload_length, destination.len())
178 .map_err(Http3FramePayloadBuildError::Frame)
179}
180
181pub(super) fn add_payload(current: usize, addition: usize) -> Option<usize> {
182 current.checked_add(addition)
183}
184
185pub(in crate::http3) fn validate_type(
186 frame: Http3Frame<'_>,
187 expected: Http3FrameType,
188) -> Result<(), Http3FramePayloadParseError> {
189 let actual = frame.frame_type();
190 if actual != expected {
191 return Err(Http3FramePayloadParseError::WrongFrameType { expected, actual });
192 }
193 Ok(())
194}
195
196pub(in crate::http3) fn parse_payload_varint<'a>(
197 bytes: &'a [u8],
198 field: Http3FramePayloadField,
199 offset: usize,
200) -> Result<QuicVarInt<'a>, Http3FramePayloadParseError> {
201 QuicVarInt::parse(bytes).map_err(|error| Http3FramePayloadParseError::PayloadVarInt {
202 field,
203 offset,
204 error,
205 })
206}
207
208pub(super) fn parse_exact_varint<'a>(
209 payload: &'a [u8],
210 field: Http3FramePayloadField,
211) -> Result<QuicVarInt<'a>, Http3FramePayloadParseError> {
212 let varint = parse_payload_varint(payload, field, 0)?;
213 if varint.byte_len() != payload.len() {
214 return Err(Http3FramePayloadParseError::TrailingPayload {
215 consumed: varint.byte_len(),
216 actual: payload.len(),
217 });
218 }
219 Ok(varint)
220}