use super::super::varint::QuicVarInt;
use super::parse::{QuicFrameField, QuicFrameParseError};
const MAX_STREAM_RANGE_END: u64 = (1 << 62) - 1;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct QuicStreamFrame<'a> {
bytes: &'a [u8],
frame_type: QuicVarInt<'a>,
stream_id: QuicVarInt<'a>,
offset: Option<QuicVarInt<'a>>,
length: Option<QuicVarInt<'a>>,
stream_data: &'a [u8],
}
impl<'a> QuicStreamFrame<'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 stream_id(self) -> QuicVarInt<'a> {
self.stream_id
}
pub const fn offset(self) -> Option<QuicVarInt<'a>> {
self.offset
}
pub const fn length(self) -> Option<QuicVarInt<'a>> {
self.length
}
pub const fn stream_data(self) -> &'a [u8] {
self.stream_data
}
pub const fn fin(self) -> bool {
self.frame_type.value() & 0x01 != 0
}
}
pub(super) fn parse_stream<'a>(
bytes: &'a [u8],
frame_type: QuicVarInt<'a>,
offset: usize,
) -> Result<(QuicStreamFrame<'a>, &'a [u8]), QuicFrameParseError> {
let flags = frame_type.value();
let has_offset = flags & 0x04 != 0;
let has_length = flags & 0x02 != 0;
let stream_id_start = frame_type.byte_len();
let stream_id_offset = offset + stream_id_start;
let stream_id = QuicVarInt::parse(&bytes[stream_id_start..]).map_err(|error| {
QuicFrameParseError::Field {
field: QuicFrameField::StreamId,
offset: stream_id_offset,
error,
}
})?;
let mut data_start = stream_id_start + stream_id.byte_len();
let range_offset = offset + data_start;
let stream_offset = if has_offset {
let field_offset = offset + data_start;
let value = QuicVarInt::parse(&bytes[data_start..]).map_err(|error| {
QuicFrameParseError::Field {
field: QuicFrameField::StreamOffset,
offset: field_offset,
error,
}
})?;
data_start += value.byte_len();
Some(value)
} else {
None
};
let length = if has_length {
let field_offset = offset + data_start;
let value = QuicVarInt::parse(&bytes[data_start..]).map_err(|error| {
QuicFrameParseError::Field {
field: QuicFrameField::StreamLength,
offset: field_offset,
error,
}
})?;
data_start += value.byte_len();
Some((value, field_offset))
} else {
None
};
let start = stream_offset.map_or(0, QuicVarInt::value);
let data_offset = offset + data_start;
let (length_varint, data_end) = match length {
Some((length, length_offset)) => {
let data_length = length.value();
validate_range(start, data_length, range_offset)?;
let length_usize = usize::try_from(data_length).map_err(|_| {
QuicFrameParseError::LengthNotRepresentable {
field: QuicFrameField::StreamLength,
offset: length_offset,
value: data_length,
}
})?;
let data_end = data_start.checked_add(length_usize).ok_or(
QuicFrameParseError::LengthOverflow {
field: QuicFrameField::StreamData,
offset: data_offset,
length: length_usize,
},
)?;
let available = bytes.len() - data_start;
if available < length_usize {
return Err(QuicFrameParseError::IncompleteBytes {
field: QuicFrameField::StreamData,
offset: data_offset,
required: length_usize,
available,
});
}
(Some(length), data_end)
}
None => {
let data_end = bytes.len();
let data_length = match u64::try_from(data_end - data_start) {
Ok(value) => value,
Err(_) => {
return Err(QuicFrameParseError::ImplicitLengthNotRepresentable {
field: QuicFrameField::StreamData,
offset: data_offset,
length: data_end - data_start,
});
}
};
validate_range(start, data_length, range_offset)?;
(None, data_end)
}
};
Ok((
QuicStreamFrame {
bytes: &bytes[..data_end],
frame_type,
stream_id,
offset: stream_offset,
length: length_varint,
stream_data: &bytes[data_start..data_end],
},
&bytes[data_end..],
))
}
fn validate_range(start: u64, length: u64, offset: usize) -> Result<(), QuicFrameParseError> {
if start
.checked_add(length)
.is_none_or(|end| end > MAX_STREAM_RANGE_END)
{
return Err(QuicFrameParseError::FieldRangeOutOfRange {
field: QuicFrameField::StreamOffset,
offset,
start,
length,
maximum: MAX_STREAM_RANGE_END,
});
}
Ok(())
}