use super::super::varint::QuicVarInt;
use super::parse::{QuicFrameField, QuicFrameParseError};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct QuicConnectionCloseFrame<'a> {
bytes: &'a [u8],
frame_type: QuicVarInt<'a>,
error_code: QuicVarInt<'a>,
triggering_frame_type: Option<QuicVarInt<'a>>,
reason_phrase_length: QuicVarInt<'a>,
reason_phrase: &'a [u8],
}
impl<'a> QuicConnectionCloseFrame<'a> {
pub const fn as_bytes(self) -> &'a [u8] {
self.bytes
}
pub const fn frame_type(self) -> QuicVarInt<'a> {
self.frame_type
}
pub const fn error_code(self) -> QuicVarInt<'a> {
self.error_code
}
pub const fn triggering_frame_type(self) -> Option<QuicVarInt<'a>> {
self.triggering_frame_type
}
pub const fn reason_phrase_length(self) -> QuicVarInt<'a> {
self.reason_phrase_length
}
pub const fn reason_phrase(self) -> &'a [u8] {
self.reason_phrase
}
}
pub(super) fn parse_connection_close<'a>(
bytes: &'a [u8],
frame_type: QuicVarInt<'a>,
offset: usize,
) -> Result<(QuicConnectionCloseFrame<'a>, &'a [u8]), QuicFrameParseError> {
let mut start = frame_type.byte_len();
let error_code = parse_field(
bytes,
start,
offset,
QuicFrameField::ConnectionCloseErrorCode,
)?;
start += error_code.byte_len();
let triggering_frame_type = if frame_type.value() == 0x1c {
let triggering_frame_type =
parse_field(bytes, start, offset, QuicFrameField::TriggeringFrameType)?;
start += triggering_frame_type.byte_len();
Some(triggering_frame_type)
} else {
None
};
let reason_phrase_length =
parse_field(bytes, start, offset, QuicFrameField::ReasonPhraseLength)?;
start += reason_phrase_length.byte_len();
let reason_length_value = reason_phrase_length.value();
let reason_length = usize::try_from(reason_length_value).map_err(|_| {
QuicFrameParseError::LengthNotRepresentable {
field: QuicFrameField::ReasonPhraseLength,
offset: offset + start - reason_phrase_length.byte_len(),
value: reason_length_value,
}
})?;
let reason_offset = offset + start;
let end = start
.checked_add(reason_length)
.ok_or(QuicFrameParseError::LengthOverflow {
field: QuicFrameField::ReasonPhrase,
offset: reason_offset,
length: reason_length,
})?;
let available = bytes.len() - start;
if available < reason_length {
return Err(QuicFrameParseError::IncompleteBytes {
field: QuicFrameField::ReasonPhrase,
offset: reason_offset,
required: reason_length,
available,
});
}
Ok((
QuicConnectionCloseFrame {
bytes: &bytes[..end],
frame_type,
error_code,
triggering_frame_type,
reason_phrase_length,
reason_phrase: &bytes[start..end],
},
&bytes[end..],
))
}
fn parse_field<'a>(
bytes: &'a [u8],
start: usize,
offset: usize,
field: QuicFrameField,
) -> Result<QuicVarInt<'a>, QuicFrameParseError> {
QuicVarInt::parse(&bytes[start..]).map_err(|error| QuicFrameParseError::Field {
field,
offset: offset + start,
error,
})
}