use crate::protocols::transport::common::hex_bytes;
use crate::{CrafterError, Result};
use super::{connection_id::QUIC_CONNECTION_ID_MAX_LEN, QuicConnectionId, QuicVarInt};
pub const QUIC_STATELESS_RESET_TOKEN_LEN: usize = 16;
const QUIC_PATH_VALIDATION_DATA_LEN: usize = 8;
pub const QUIC_TRANSPORT_ERROR_NO_ERROR: QuicVarInt = QuicVarInt::from_u64_unchecked(0x00);
pub const QUIC_TRANSPORT_ERROR_INTERNAL_ERROR: QuicVarInt = QuicVarInt::from_u64_unchecked(0x01);
pub const QUIC_TRANSPORT_ERROR_CONNECTION_REFUSED: QuicVarInt =
QuicVarInt::from_u64_unchecked(0x02);
pub const QUIC_TRANSPORT_ERROR_FLOW_CONTROL_ERROR: QuicVarInt =
QuicVarInt::from_u64_unchecked(0x03);
pub const QUIC_TRANSPORT_ERROR_STREAM_LIMIT_ERROR: QuicVarInt =
QuicVarInt::from_u64_unchecked(0x04);
pub const QUIC_TRANSPORT_ERROR_STREAM_STATE_ERROR: QuicVarInt =
QuicVarInt::from_u64_unchecked(0x05);
pub const QUIC_TRANSPORT_ERROR_FINAL_SIZE_ERROR: QuicVarInt = QuicVarInt::from_u64_unchecked(0x06);
pub const QUIC_TRANSPORT_ERROR_FRAME_ENCODING_ERROR: QuicVarInt =
QuicVarInt::from_u64_unchecked(0x07);
pub const QUIC_TRANSPORT_ERROR_TRANSPORT_PARAMETER_ERROR: QuicVarInt =
QuicVarInt::from_u64_unchecked(0x08);
pub const QUIC_TRANSPORT_ERROR_CONNECTION_ID_LIMIT_ERROR: QuicVarInt =
QuicVarInt::from_u64_unchecked(0x09);
pub const QUIC_TRANSPORT_ERROR_PROTOCOL_VIOLATION: QuicVarInt =
QuicVarInt::from_u64_unchecked(0x0a);
pub const QUIC_TRANSPORT_ERROR_INVALID_TOKEN: QuicVarInt = QuicVarInt::from_u64_unchecked(0x0b);
pub const QUIC_TRANSPORT_ERROR_APPLICATION_ERROR: QuicVarInt = QuicVarInt::from_u64_unchecked(0x0c);
pub const QUIC_TRANSPORT_ERROR_CRYPTO_BUFFER_EXCEEDED: QuicVarInt =
QuicVarInt::from_u64_unchecked(0x0d);
pub const QUIC_TRANSPORT_ERROR_KEY_UPDATE_ERROR: QuicVarInt = QuicVarInt::from_u64_unchecked(0x0e);
pub const QUIC_TRANSPORT_ERROR_AEAD_LIMIT_REACHED: QuicVarInt =
QuicVarInt::from_u64_unchecked(0x0f);
pub const QUIC_TRANSPORT_ERROR_NO_VIABLE_PATH: QuicVarInt = QuicVarInt::from_u64_unchecked(0x10);
pub const QUIC_TRANSPORT_ERROR_VERSION_NEGOTIATION_ERROR: QuicVarInt =
QuicVarInt::from_u64_unchecked(0x11);
pub const QUIC_TRANSPORT_ERROR_CRYPTO_ERROR_START: QuicVarInt =
QuicVarInt::from_u64_unchecked(0x0100);
pub const QUIC_TRANSPORT_ERROR_CRYPTO_ERROR_END: QuicVarInt =
QuicVarInt::from_u64_unchecked(0x01ff);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum QuicKnownFrameType {
Padding,
Ping,
Ack,
AckEcn,
ResetStream,
StopSending,
Crypto,
NewToken,
Stream,
MaxData,
MaxStreamData,
MaxStreams,
DataBlocked,
StreamDataBlocked,
StreamsBlocked,
NewConnectionId,
RetireConnectionId,
PathChallenge,
PathResponse,
ConnectionCloseTransport,
ConnectionCloseApplication,
HandshakeDone,
Datagram,
DatagramLen,
}
impl QuicKnownFrameType {
pub const fn name(self) -> &'static str {
match self {
Self::Padding => "PADDING",
Self::Ping => "PING",
Self::Ack => "ACK",
Self::AckEcn => "ACK_ECN",
Self::ResetStream => "RESET_STREAM",
Self::StopSending => "STOP_SENDING",
Self::Crypto => "CRYPTO",
Self::NewToken => "NEW_TOKEN",
Self::Stream => "STREAM",
Self::MaxData => "MAX_DATA",
Self::MaxStreamData => "MAX_STREAM_DATA",
Self::MaxStreams => "MAX_STREAMS",
Self::DataBlocked => "DATA_BLOCKED",
Self::StreamDataBlocked => "STREAM_DATA_BLOCKED",
Self::StreamsBlocked => "STREAMS_BLOCKED",
Self::NewConnectionId => "NEW_CONNECTION_ID",
Self::RetireConnectionId => "RETIRE_CONNECTION_ID",
Self::PathChallenge => "PATH_CHALLENGE",
Self::PathResponse => "PATH_RESPONSE",
Self::ConnectionCloseTransport => "CONNECTION_CLOSE_TRANSPORT",
Self::ConnectionCloseApplication => "CONNECTION_CLOSE_APPLICATION",
Self::HandshakeDone => "HANDSHAKE_DONE",
Self::Datagram => "DATAGRAM",
Self::DatagramLen => "DATAGRAM_LEN",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum QuicFrameKind {
Known(QuicKnownFrameType),
Unknown,
Empty,
Truncated,
}
impl QuicFrameKind {
pub const fn label(self) -> &'static str {
match self {
Self::Known(kind) => kind.name(),
Self::Unknown => "UNKNOWN",
Self::Empty => "EMPTY",
Self::Truncated => "TRUNCATED",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct QuicAckRange {
gap: QuicVarInt,
ack_range_length: QuicVarInt,
}
impl QuicAckRange {
pub const fn new(gap: QuicVarInt, ack_range_length: QuicVarInt) -> Self {
Self {
gap,
ack_range_length,
}
}
pub fn from_values(gap: u64, ack_range_length: u64) -> Result<Self> {
Ok(Self {
gap: QuicVarInt::new(gap)?,
ack_range_length: QuicVarInt::new(ack_range_length)?,
})
}
pub const fn gap(self) -> QuicVarInt {
self.gap
}
pub const fn ack_range_length(self) -> QuicVarInt {
self.ack_range_length
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct QuicAckEcnCounts {
ect0_count: QuicVarInt,
ect1_count: QuicVarInt,
ce_count: QuicVarInt,
}
impl QuicAckEcnCounts {
pub const fn new(ect0_count: QuicVarInt, ect1_count: QuicVarInt, ce_count: QuicVarInt) -> Self {
Self {
ect0_count,
ect1_count,
ce_count,
}
}
pub fn from_values(ect0_count: u64, ect1_count: u64, ce_count: u64) -> Result<Self> {
Ok(Self {
ect0_count: QuicVarInt::new(ect0_count)?,
ect1_count: QuicVarInt::new(ect1_count)?,
ce_count: QuicVarInt::new(ce_count)?,
})
}
pub const fn ect0_count(self) -> QuicVarInt {
self.ect0_count
}
pub const fn ect1_count(self) -> QuicVarInt {
self.ect1_count
}
pub const fn ce_count(self) -> QuicVarInt {
self.ce_count
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct QuicAckFrame {
largest_acknowledged: QuicVarInt,
ack_delay: QuicVarInt,
first_ack_range: QuicVarInt,
ack_ranges: Vec<QuicAckRange>,
ecn_counts: Option<QuicAckEcnCounts>,
}
impl QuicAckFrame {
pub fn new(
largest_acknowledged: QuicVarInt,
ack_delay: QuicVarInt,
first_ack_range: QuicVarInt,
ack_ranges: impl IntoIterator<Item = QuicAckRange>,
) -> Self {
Self {
largest_acknowledged,
ack_delay,
first_ack_range,
ack_ranges: ack_ranges.into_iter().collect(),
ecn_counts: None,
}
}
pub fn from_values(
largest_acknowledged: u64,
ack_delay: u64,
first_ack_range: u64,
ack_ranges: impl IntoIterator<Item = QuicAckRange>,
) -> Result<Self> {
Ok(Self::new(
QuicVarInt::new(largest_acknowledged)?,
QuicVarInt::new(ack_delay)?,
QuicVarInt::new(first_ack_range)?,
ack_ranges,
))
}
pub fn with_ecn_counts(mut self, ecn_counts: QuicAckEcnCounts) -> Self {
self.ecn_counts = Some(ecn_counts);
self
}
pub const fn is_ecn(&self) -> bool {
self.ecn_counts.is_some()
}
pub const fn frame_type(&self) -> QuicKnownFrameType {
if self.is_ecn() {
QuicKnownFrameType::AckEcn
} else {
QuicKnownFrameType::Ack
}
}
pub const fn largest_acknowledged(&self) -> QuicVarInt {
self.largest_acknowledged
}
pub const fn ack_delay(&self) -> QuicVarInt {
self.ack_delay
}
pub const fn first_ack_range(&self) -> QuicVarInt {
self.first_ack_range
}
pub fn ack_ranges(&self) -> &[QuicAckRange] {
&self.ack_ranges
}
pub fn ack_range_count(&self) -> Result<QuicVarInt> {
QuicVarInt::new(u64::try_from(self.ack_ranges.len()).map_err(|_| {
CrafterError::invalid_field_value("quic.frame.ack.range_count", "too many ACK ranges")
})?)
}
pub const fn ecn_counts(&self) -> Option<QuicAckEcnCounts> {
self.ecn_counts
}
pub fn decode(bytes: impl AsRef<[u8]>) -> Result<Self> {
let bytes = bytes.as_ref();
let (frame, consumed) = decode_ack_frame(bytes)?;
if consumed != bytes.len() {
return Err(CrafterError::invalid_field_value(
"quic.frame.ack",
"ACK frame has trailing bytes",
));
}
Ok(frame)
}
pub fn encode(&self, out: &mut Vec<u8>) -> Result<()> {
let frame_type = if self.is_ecn() { 0x03 } else { 0x02 };
QuicVarInt::from_u64_unchecked(frame_type).encode(out)?;
self.largest_acknowledged.encode(out)?;
self.ack_delay.encode(out)?;
self.ack_range_count()?.encode(out)?;
self.first_ack_range.encode(out)?;
for range in &self.ack_ranges {
range.gap.encode(out)?;
range.ack_range_length.encode(out)?;
}
if let Some(ecn_counts) = self.ecn_counts {
ecn_counts.ect0_count.encode(out)?;
ecn_counts.ect1_count.encode(out)?;
ecn_counts.ce_count.encode(out)?;
}
Ok(())
}
pub fn encode_to_vec(&self) -> Result<Vec<u8>> {
let mut out = Vec::new();
self.encode(&mut out)?;
Ok(out)
}
pub fn summary(&self) -> String {
let mut summary = format!(
"kind={} largest_acknowledged={} ack_delay={} first_ack_range={} ranges={}",
self.frame_type().name(),
self.largest_acknowledged.value(),
self.ack_delay.value(),
self.first_ack_range.value(),
self.ack_ranges.len()
);
if let Some(ecn_counts) = self.ecn_counts {
summary.push_str(&format!(
" ect0={} ect1={} ce={}",
ecn_counts.ect0_count.value(),
ecn_counts.ect1_count.value(),
ecn_counts.ce_count.value()
));
}
summary
}
pub fn inspection_fields(&self) -> Vec<(&'static str, String)> {
let mut fields = vec![
(
"ack_largest_acknowledged",
self.largest_acknowledged.value().to_string(),
),
("ack_delay", self.ack_delay.value().to_string()),
("ack_range_count", self.ack_ranges.len().to_string()),
("ack_first_range", self.first_ack_range.value().to_string()),
];
for range in &self.ack_ranges {
fields.push((
"ack_range",
format!(
"gap={} length={}",
range.gap.value(),
range.ack_range_length.value()
),
));
}
if let Some(ecn_counts) = self.ecn_counts {
fields.extend([
("ack_ecn_ect0", ecn_counts.ect0_count.value().to_string()),
("ack_ecn_ect1", ecn_counts.ect1_count.value().to_string()),
("ack_ecn_ce", ecn_counts.ce_count.value().to_string()),
]);
}
fields
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct QuicResetStreamFrame {
stream_id: QuicVarInt,
application_error_code: QuicVarInt,
final_size: QuicVarInt,
}
impl QuicResetStreamFrame {
pub const fn new(
stream_id: QuicVarInt,
application_error_code: QuicVarInt,
final_size: QuicVarInt,
) -> Self {
Self {
stream_id,
application_error_code,
final_size,
}
}
pub fn from_values(
stream_id: u64,
application_error_code: u64,
final_size: u64,
) -> Result<Self> {
Ok(Self::new(
QuicVarInt::new(stream_id)?,
QuicVarInt::new(application_error_code)?,
QuicVarInt::new(final_size)?,
))
}
pub const fn stream_id(self) -> QuicVarInt {
self.stream_id
}
pub const fn application_error_code(self) -> QuicVarInt {
self.application_error_code
}
pub const fn final_size(self) -> QuicVarInt {
self.final_size
}
pub fn decode(bytes: impl AsRef<[u8]>) -> Result<Self> {
let bytes = bytes.as_ref();
let (frame, consumed) = decode_reset_stream_frame(bytes)?;
if consumed != bytes.len() {
return Err(CrafterError::invalid_field_value(
"quic.frame.reset_stream",
"RESET_STREAM frame has trailing bytes",
));
}
Ok(frame)
}
pub fn encode(self, out: &mut Vec<u8>) -> Result<()> {
QuicVarInt::from_u64_unchecked(0x04).encode(out)?;
self.stream_id.encode(out)?;
self.application_error_code.encode(out)?;
self.final_size.encode(out)?;
Ok(())
}
pub fn encode_to_vec(self) -> Result<Vec<u8>> {
let mut out = Vec::new();
self.encode(&mut out)?;
Ok(out)
}
pub fn summary(self) -> String {
format!(
"kind=RESET_STREAM stream_id={} application_error_code={} final_size={}",
self.stream_id.value(),
self.application_error_code.value(),
self.final_size.value()
)
}
pub fn inspection_fields(self) -> Vec<(&'static str, String)> {
vec![
("reset_stream_id", self.stream_id.value().to_string()),
(
"reset_stream_application_error_code",
self.application_error_code.value().to_string(),
),
(
"reset_stream_final_size",
self.final_size.value().to_string(),
),
]
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct QuicStopSendingFrame {
stream_id: QuicVarInt,
application_error_code: QuicVarInt,
}
impl QuicStopSendingFrame {
pub const fn new(stream_id: QuicVarInt, application_error_code: QuicVarInt) -> Self {
Self {
stream_id,
application_error_code,
}
}
pub fn from_values(stream_id: u64, application_error_code: u64) -> Result<Self> {
Ok(Self::new(
QuicVarInt::new(stream_id)?,
QuicVarInt::new(application_error_code)?,
))
}
pub const fn stream_id(self) -> QuicVarInt {
self.stream_id
}
pub const fn application_error_code(self) -> QuicVarInt {
self.application_error_code
}
pub fn decode(bytes: impl AsRef<[u8]>) -> Result<Self> {
let bytes = bytes.as_ref();
let (frame, consumed) = decode_stop_sending_frame(bytes)?;
if consumed != bytes.len() {
return Err(CrafterError::invalid_field_value(
"quic.frame.stop_sending",
"STOP_SENDING frame has trailing bytes",
));
}
Ok(frame)
}
pub fn encode(self, out: &mut Vec<u8>) -> Result<()> {
QuicVarInt::from_u64_unchecked(0x05).encode(out)?;
self.stream_id.encode(out)?;
self.application_error_code.encode(out)?;
Ok(())
}
pub fn encode_to_vec(self) -> Result<Vec<u8>> {
let mut out = Vec::new();
self.encode(&mut out)?;
Ok(out)
}
pub fn summary(self) -> String {
format!(
"kind=STOP_SENDING stream_id={} application_error_code={}",
self.stream_id.value(),
self.application_error_code.value()
)
}
pub fn inspection_fields(self) -> Vec<(&'static str, String)> {
vec![
("stop_sending_stream_id", self.stream_id.value().to_string()),
(
"stop_sending_application_error_code",
self.application_error_code.value().to_string(),
),
]
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct QuicCryptoFrame {
offset: QuicVarInt,
length: Option<QuicVarInt>,
data: Vec<u8>,
}
impl QuicCryptoFrame {
pub fn new(offset: QuicVarInt, data: impl AsRef<[u8]>) -> Self {
Self {
offset,
length: None,
data: data.as_ref().to_vec(),
}
}
pub fn from_values(offset: u64, data: impl AsRef<[u8]>) -> Result<Self> {
Ok(Self::new(QuicVarInt::new(offset)?, data))
}
pub fn with_length(mut self, length: QuicVarInt) -> Self {
self.length = Some(length);
self
}
pub const fn offset(&self) -> QuicVarInt {
self.offset
}
pub fn length(&self) -> Result<QuicVarInt> {
match self.length {
Some(length) => Ok(length),
None => QuicVarInt::new(u64::try_from(self.data.len()).map_err(|_| {
CrafterError::invalid_field_value(
"quic.frame.crypto.length",
"data length exceeds u64",
)
})?),
}
}
pub const fn length_override(&self) -> Option<QuicVarInt> {
self.length
}
pub fn data(&self) -> &[u8] {
&self.data
}
pub fn decode(bytes: impl AsRef<[u8]>) -> Result<Self> {
let bytes = bytes.as_ref();
let (frame, consumed) = decode_crypto_frame(bytes)?;
if consumed != bytes.len() {
return Err(CrafterError::invalid_field_value(
"quic.frame.crypto",
"CRYPTO frame has trailing bytes",
));
}
Ok(frame)
}
pub fn encode(&self, out: &mut Vec<u8>) -> Result<()> {
QuicVarInt::from_u64_unchecked(0x06).encode(out)?;
self.offset.encode(out)?;
self.length()?.encode(out)?;
out.extend_from_slice(&self.data);
Ok(())
}
pub fn encode_to_vec(&self) -> Result<Vec<u8>> {
let mut out = Vec::new();
self.encode(&mut out)?;
Ok(out)
}
pub fn summary(&self) -> String {
format!(
"kind=CRYPTO offset={} length={} data_len={}",
self.offset.value(),
self.length().map(|length| length.value()).unwrap_or(0),
self.data.len()
)
}
pub fn inspection_fields(&self) -> Vec<(&'static str, String)> {
vec![
("crypto_offset", self.offset.value().to_string()),
(
"crypto_length",
self.length()
.map(|length| length.value().to_string())
.unwrap_or_else(|_| "<invalid>".to_string()),
),
("crypto_data_len", self.data.len().to_string()),
("crypto_data", hex_bytes(&self.data)),
]
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct QuicNewTokenFrame {
token_length: Option<QuicVarInt>,
token: Vec<u8>,
}
impl QuicNewTokenFrame {
pub fn new(token: impl AsRef<[u8]>) -> Self {
Self {
token_length: None,
token: token.as_ref().to_vec(),
}
}
pub fn with_token_length(mut self, token_length: QuicVarInt) -> Self {
self.token_length = Some(token_length);
self
}
pub fn token_length(&self) -> Result<QuicVarInt> {
match self.token_length {
Some(token_length) => Ok(token_length),
None => QuicVarInt::new(u64::try_from(self.token.len()).map_err(|_| {
CrafterError::invalid_field_value(
"quic.frame.new_token.token_length",
"token length exceeds u64",
)
})?),
}
}
pub const fn token_length_override(&self) -> Option<QuicVarInt> {
self.token_length
}
pub fn token(&self) -> &[u8] {
&self.token
}
pub fn decode(bytes: impl AsRef<[u8]>) -> Result<Self> {
let bytes = bytes.as_ref();
let (frame, consumed) = decode_new_token_frame(bytes)?;
if consumed != bytes.len() {
return Err(CrafterError::invalid_field_value(
"quic.frame.new_token",
"NEW_TOKEN frame has trailing bytes",
));
}
Ok(frame)
}
pub fn encode(&self, out: &mut Vec<u8>) -> Result<()> {
QuicVarInt::from_u64_unchecked(0x07).encode(out)?;
self.token_length()?.encode(out)?;
out.extend_from_slice(&self.token);
Ok(())
}
pub fn encode_to_vec(&self) -> Result<Vec<u8>> {
let mut out = Vec::new();
self.encode(&mut out)?;
Ok(out)
}
pub fn summary(&self) -> String {
format!(
"kind=NEW_TOKEN token_length={} token_len={}",
self.token_length()
.map(|length| length.value())
.unwrap_or(0),
self.token.len()
)
}
pub fn inspection_fields(&self) -> Vec<(&'static str, String)> {
vec![
(
"new_token_length",
self.token_length()
.map(|length| length.value().to_string())
.unwrap_or_else(|_| "<invalid>".to_string()),
),
("new_token_len", self.token.len().to_string()),
("new_token", hex_bytes(&self.token)),
]
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct QuicStreamFrame {
stream_id: QuicVarInt,
offset: Option<QuicVarInt>,
include_length: bool,
length: Option<QuicVarInt>,
fin: bool,
data: Vec<u8>,
}
impl QuicStreamFrame {
pub fn new(stream_id: QuicVarInt, data: impl AsRef<[u8]>) -> Self {
Self {
stream_id,
offset: None,
include_length: true,
length: None,
fin: false,
data: data.as_ref().to_vec(),
}
}
pub fn from_values(stream_id: u64, data: impl AsRef<[u8]>) -> Result<Self> {
Ok(Self::new(QuicVarInt::new(stream_id)?, data))
}
pub fn with_offset(mut self, offset: QuicVarInt) -> Self {
self.offset = Some(offset);
self
}
pub fn with_length(mut self, length: QuicVarInt) -> Self {
self.include_length = true;
self.length = Some(length);
self
}
pub fn without_length(mut self) -> Self {
self.include_length = false;
self.length = None;
self
}
pub fn with_fin(mut self, fin: bool) -> Self {
self.fin = fin;
self
}
pub const fn stream_id(&self) -> QuicVarInt {
self.stream_id
}
pub const fn offset(&self) -> Option<QuicVarInt> {
self.offset
}
pub const fn has_length(&self) -> bool {
self.include_length
}
pub fn length(&self) -> Result<Option<QuicVarInt>> {
if !self.include_length {
return Ok(None);
}
match self.length {
Some(length) => Ok(Some(length)),
None => Ok(Some(QuicVarInt::new(
u64::try_from(self.data.len()).map_err(|_| {
CrafterError::invalid_field_value(
"quic.frame.stream.length",
"data length exceeds u64",
)
})?,
)?)),
}
}
pub const fn length_override(&self) -> Option<QuicVarInt> {
self.length
}
pub const fn fin(&self) -> bool {
self.fin
}
pub fn data(&self) -> &[u8] {
&self.data
}
pub fn decode(bytes: impl AsRef<[u8]>) -> Result<Self> {
let bytes = bytes.as_ref();
let (frame, consumed) = decode_stream_frame(bytes)?;
if consumed != bytes.len() {
return Err(CrafterError::invalid_field_value(
"quic.frame.stream",
"STREAM frame has trailing bytes",
));
}
Ok(frame)
}
pub fn encode(&self, out: &mut Vec<u8>) -> Result<()> {
let mut frame_type = 0x08;
if self.offset.is_some() {
frame_type |= 0x04;
}
if self.include_length {
frame_type |= 0x02;
}
if self.fin {
frame_type |= 0x01;
}
QuicVarInt::from_u64_unchecked(frame_type).encode(out)?;
self.stream_id.encode(out)?;
if let Some(offset) = self.offset {
offset.encode(out)?;
}
if let Some(length) = self.length()? {
length.encode(out)?;
}
out.extend_from_slice(&self.data);
Ok(())
}
pub fn encode_to_vec(&self) -> Result<Vec<u8>> {
let mut out = Vec::new();
self.encode(&mut out)?;
Ok(out)
}
pub fn summary(&self) -> String {
let offset = self
.offset
.map(|offset| offset.value().to_string())
.unwrap_or_else(|| "<none>".to_string());
let length = self
.length()
.ok()
.flatten()
.map(|length| length.value().to_string())
.unwrap_or_else(|| "<packet-end>".to_string());
format!(
"kind=STREAM stream_id={} offset={} length={} fin={} data_len={}",
self.stream_id.value(),
offset,
length,
self.fin,
self.data.len()
)
}
pub fn inspection_fields(&self) -> Vec<(&'static str, String)> {
vec![
("stream_id", self.stream_id.value().to_string()),
(
"stream_offset",
self.offset
.map(|offset| offset.value().to_string())
.unwrap_or_else(|| "<none>".to_string()),
),
(
"stream_length",
self.length()
.ok()
.flatten()
.map(|length| length.value().to_string())
.unwrap_or_else(|| "<packet-end>".to_string()),
),
("stream_fin", self.fin.to_string()),
("stream_data_len", self.data.len().to_string()),
("stream_data", hex_bytes(&self.data)),
]
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct QuicMaxDataFrame {
maximum_data: QuicVarInt,
}
impl QuicMaxDataFrame {
pub const fn new(maximum_data: QuicVarInt) -> Self {
Self { maximum_data }
}
pub fn from_value(maximum_data: u64) -> Result<Self> {
Ok(Self::new(QuicVarInt::new(maximum_data)?))
}
pub const fn maximum_data(self) -> QuicVarInt {
self.maximum_data
}
pub fn decode(bytes: impl AsRef<[u8]>) -> Result<Self> {
let bytes = bytes.as_ref();
let (frame, consumed) = decode_max_data_frame(bytes)?;
if consumed != bytes.len() {
return Err(CrafterError::invalid_field_value(
"quic.frame.max_data",
"MAX_DATA frame has trailing bytes",
));
}
Ok(frame)
}
pub fn encode(self, out: &mut Vec<u8>) -> Result<()> {
QuicVarInt::from_u64_unchecked(0x10).encode(out)?;
self.maximum_data.encode(out)?;
Ok(())
}
pub fn encode_to_vec(self) -> Result<Vec<u8>> {
let mut out = Vec::new();
self.encode(&mut out)?;
Ok(out)
}
pub fn summary(self) -> String {
format!("kind=MAX_DATA maximum_data={}", self.maximum_data.value())
}
pub fn inspection_fields(self) -> Vec<(&'static str, String)> {
vec![("max_data", self.maximum_data.value().to_string())]
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct QuicMaxStreamDataFrame {
stream_id: QuicVarInt,
maximum_stream_data: QuicVarInt,
}
impl QuicMaxStreamDataFrame {
pub const fn new(stream_id: QuicVarInt, maximum_stream_data: QuicVarInt) -> Self {
Self {
stream_id,
maximum_stream_data,
}
}
pub fn from_values(stream_id: u64, maximum_stream_data: u64) -> Result<Self> {
Ok(Self::new(
QuicVarInt::new(stream_id)?,
QuicVarInt::new(maximum_stream_data)?,
))
}
pub const fn stream_id(self) -> QuicVarInt {
self.stream_id
}
pub const fn maximum_stream_data(self) -> QuicVarInt {
self.maximum_stream_data
}
pub fn decode(bytes: impl AsRef<[u8]>) -> Result<Self> {
let bytes = bytes.as_ref();
let (frame, consumed) = decode_max_stream_data_frame(bytes)?;
if consumed != bytes.len() {
return Err(CrafterError::invalid_field_value(
"quic.frame.max_stream_data",
"MAX_STREAM_DATA frame has trailing bytes",
));
}
Ok(frame)
}
pub fn encode(self, out: &mut Vec<u8>) -> Result<()> {
QuicVarInt::from_u64_unchecked(0x11).encode(out)?;
self.stream_id.encode(out)?;
self.maximum_stream_data.encode(out)?;
Ok(())
}
pub fn encode_to_vec(self) -> Result<Vec<u8>> {
let mut out = Vec::new();
self.encode(&mut out)?;
Ok(out)
}
pub fn summary(self) -> String {
format!(
"kind=MAX_STREAM_DATA stream_id={} maximum_stream_data={}",
self.stream_id.value(),
self.maximum_stream_data.value()
)
}
pub fn inspection_fields(self) -> Vec<(&'static str, String)> {
vec![
(
"max_stream_data_stream_id",
self.stream_id.value().to_string(),
),
(
"max_stream_data",
self.maximum_stream_data.value().to_string(),
),
]
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum QuicStreamDirection {
Bidirectional,
Unidirectional,
}
impl QuicStreamDirection {
pub const fn max_streams_frame_type(self) -> u64 {
match self {
Self::Bidirectional => 0x12,
Self::Unidirectional => 0x13,
}
}
pub const fn label(self) -> &'static str {
match self {
Self::Bidirectional => "bidirectional",
Self::Unidirectional => "unidirectional",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct QuicMaxStreamsFrame {
direction: QuicStreamDirection,
maximum_streams: QuicVarInt,
}
impl QuicMaxStreamsFrame {
pub const fn new(direction: QuicStreamDirection, maximum_streams: QuicVarInt) -> Self {
Self {
direction,
maximum_streams,
}
}
pub const fn bidirectional(maximum_streams: QuicVarInt) -> Self {
Self::new(QuicStreamDirection::Bidirectional, maximum_streams)
}
pub const fn unidirectional(maximum_streams: QuicVarInt) -> Self {
Self::new(QuicStreamDirection::Unidirectional, maximum_streams)
}
pub fn from_value(direction: QuicStreamDirection, maximum_streams: u64) -> Result<Self> {
Ok(Self::new(direction, QuicVarInt::new(maximum_streams)?))
}
pub const fn direction(self) -> QuicStreamDirection {
self.direction
}
pub const fn maximum_streams(self) -> QuicVarInt {
self.maximum_streams
}
pub fn decode(bytes: impl AsRef<[u8]>) -> Result<Self> {
let bytes = bytes.as_ref();
let (frame, consumed) = decode_max_streams_frame(bytes)?;
if consumed != bytes.len() {
return Err(CrafterError::invalid_field_value(
"quic.frame.max_streams",
"MAX_STREAMS frame has trailing bytes",
));
}
Ok(frame)
}
pub fn encode(self, out: &mut Vec<u8>) -> Result<()> {
QuicVarInt::from_u64_unchecked(self.direction.max_streams_frame_type()).encode(out)?;
self.maximum_streams.encode(out)?;
Ok(())
}
pub fn encode_to_vec(self) -> Result<Vec<u8>> {
let mut out = Vec::new();
self.encode(&mut out)?;
Ok(out)
}
pub fn summary(self) -> String {
format!(
"kind=MAX_STREAMS direction={} maximum_streams={}",
self.direction.label(),
self.maximum_streams.value()
)
}
pub fn inspection_fields(self) -> Vec<(&'static str, String)> {
vec![
("max_streams_direction", self.direction.label().to_string()),
("max_streams", self.maximum_streams.value().to_string()),
]
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct QuicDataBlockedFrame {
data_limit: QuicVarInt,
}
impl QuicDataBlockedFrame {
pub const fn new(data_limit: QuicVarInt) -> Self {
Self { data_limit }
}
pub fn from_value(data_limit: u64) -> Result<Self> {
Ok(Self::new(QuicVarInt::new(data_limit)?))
}
pub const fn data_limit(self) -> QuicVarInt {
self.data_limit
}
pub fn decode(bytes: impl AsRef<[u8]>) -> Result<Self> {
let bytes = bytes.as_ref();
let (frame, consumed) = decode_data_blocked_frame(bytes)?;
if consumed != bytes.len() {
return Err(CrafterError::invalid_field_value(
"quic.frame.data_blocked",
"DATA_BLOCKED frame has trailing bytes",
));
}
Ok(frame)
}
pub fn encode(self, out: &mut Vec<u8>) -> Result<()> {
QuicVarInt::from_u64_unchecked(0x14).encode(out)?;
self.data_limit.encode(out)?;
Ok(())
}
pub fn encode_to_vec(self) -> Result<Vec<u8>> {
let mut out = Vec::new();
self.encode(&mut out)?;
Ok(out)
}
pub fn summary(self) -> String {
format!("kind=DATA_BLOCKED data_limit={}", self.data_limit.value())
}
pub fn inspection_fields(self) -> Vec<(&'static str, String)> {
vec![("data_blocked_limit", self.data_limit.value().to_string())]
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct QuicStreamDataBlockedFrame {
stream_id: QuicVarInt,
maximum_stream_data: QuicVarInt,
}
impl QuicStreamDataBlockedFrame {
pub const fn new(stream_id: QuicVarInt, maximum_stream_data: QuicVarInt) -> Self {
Self {
stream_id,
maximum_stream_data,
}
}
pub fn from_values(stream_id: u64, maximum_stream_data: u64) -> Result<Self> {
Ok(Self::new(
QuicVarInt::new(stream_id)?,
QuicVarInt::new(maximum_stream_data)?,
))
}
pub const fn stream_id(self) -> QuicVarInt {
self.stream_id
}
pub const fn maximum_stream_data(self) -> QuicVarInt {
self.maximum_stream_data
}
pub fn decode(bytes: impl AsRef<[u8]>) -> Result<Self> {
let bytes = bytes.as_ref();
let (frame, consumed) = decode_stream_data_blocked_frame(bytes)?;
if consumed != bytes.len() {
return Err(CrafterError::invalid_field_value(
"quic.frame.stream_data_blocked",
"STREAM_DATA_BLOCKED frame has trailing bytes",
));
}
Ok(frame)
}
pub fn encode(self, out: &mut Vec<u8>) -> Result<()> {
QuicVarInt::from_u64_unchecked(0x15).encode(out)?;
self.stream_id.encode(out)?;
self.maximum_stream_data.encode(out)?;
Ok(())
}
pub fn encode_to_vec(self) -> Result<Vec<u8>> {
let mut out = Vec::new();
self.encode(&mut out)?;
Ok(out)
}
pub fn summary(self) -> String {
format!(
"kind=STREAM_DATA_BLOCKED stream_id={} maximum_stream_data={}",
self.stream_id.value(),
self.maximum_stream_data.value()
)
}
pub fn inspection_fields(self) -> Vec<(&'static str, String)> {
vec![
(
"stream_data_blocked_stream_id",
self.stream_id.value().to_string(),
),
(
"stream_data_blocked_maximum_stream_data",
self.maximum_stream_data.value().to_string(),
),
]
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct QuicStreamsBlockedFrame {
direction: QuicStreamDirection,
maximum_streams: QuicVarInt,
}
impl QuicStreamsBlockedFrame {
pub const fn new(direction: QuicStreamDirection, maximum_streams: QuicVarInt) -> Self {
Self {
direction,
maximum_streams,
}
}
pub const fn bidirectional(maximum_streams: QuicVarInt) -> Self {
Self::new(QuicStreamDirection::Bidirectional, maximum_streams)
}
pub const fn unidirectional(maximum_streams: QuicVarInt) -> Self {
Self::new(QuicStreamDirection::Unidirectional, maximum_streams)
}
pub fn from_value(direction: QuicStreamDirection, maximum_streams: u64) -> Result<Self> {
Ok(Self::new(direction, QuicVarInt::new(maximum_streams)?))
}
pub const fn direction(self) -> QuicStreamDirection {
self.direction
}
pub const fn maximum_streams(self) -> QuicVarInt {
self.maximum_streams
}
pub fn decode(bytes: impl AsRef<[u8]>) -> Result<Self> {
let bytes = bytes.as_ref();
let (frame, consumed) = decode_streams_blocked_frame(bytes)?;
if consumed != bytes.len() {
return Err(CrafterError::invalid_field_value(
"quic.frame.streams_blocked",
"STREAMS_BLOCKED frame has trailing bytes",
));
}
Ok(frame)
}
pub fn encode(self, out: &mut Vec<u8>) -> Result<()> {
let frame_type = match self.direction {
QuicStreamDirection::Bidirectional => 0x16,
QuicStreamDirection::Unidirectional => 0x17,
};
QuicVarInt::from_u64_unchecked(frame_type).encode(out)?;
self.maximum_streams.encode(out)?;
Ok(())
}
pub fn encode_to_vec(self) -> Result<Vec<u8>> {
let mut out = Vec::new();
self.encode(&mut out)?;
Ok(out)
}
pub fn summary(self) -> String {
format!(
"kind=STREAMS_BLOCKED direction={} maximum_streams={}",
self.direction.label(),
self.maximum_streams.value()
)
}
pub fn inspection_fields(self) -> Vec<(&'static str, String)> {
vec![
(
"streams_blocked_direction",
self.direction.label().to_string(),
),
("streams_blocked", self.maximum_streams.value().to_string()),
]
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct QuicNewConnectionIdFrame {
sequence_number: QuicVarInt,
retire_prior_to: QuicVarInt,
connection_id_length: Option<u8>,
connection_id: QuicConnectionId,
stateless_reset_token: [u8; QUIC_STATELESS_RESET_TOKEN_LEN],
}
impl QuicNewConnectionIdFrame {
pub fn new(
sequence_number: QuicVarInt,
retire_prior_to: QuicVarInt,
connection_id: QuicConnectionId,
stateless_reset_token: [u8; QUIC_STATELESS_RESET_TOKEN_LEN],
) -> Self {
Self {
sequence_number,
retire_prior_to,
connection_id_length: None,
connection_id,
stateless_reset_token,
}
}
pub fn from_values(
sequence_number: u64,
retire_prior_to: u64,
connection_id: impl AsRef<[u8]>,
stateless_reset_token: [u8; QUIC_STATELESS_RESET_TOKEN_LEN],
) -> Result<Self> {
Ok(Self::new(
QuicVarInt::new(sequence_number)?,
QuicVarInt::new(retire_prior_to)?,
QuicConnectionId::try_from_bytes(connection_id)?,
stateless_reset_token,
))
}
pub fn with_connection_id_length(mut self, connection_id_length: u8) -> Self {
self.connection_id_length = Some(connection_id_length);
self
}
pub const fn sequence_number(&self) -> QuicVarInt {
self.sequence_number
}
pub const fn retire_prior_to(&self) -> QuicVarInt {
self.retire_prior_to
}
pub fn connection_id_length(&self) -> Result<u8> {
if let Some(connection_id_length) = self.connection_id_length {
return Ok(connection_id_length);
}
validate_new_connection_id_len(self.connection_id.len())?;
u8::try_from(self.connection_id.len()).map_err(|_| {
CrafterError::invalid_field_value(
"quic.frame.new_connection_id.connection_id_length",
"Connection ID length exceeds u8",
)
})
}
pub const fn connection_id_length_override(&self) -> Option<u8> {
self.connection_id_length
}
pub fn connection_id(&self) -> &QuicConnectionId {
&self.connection_id
}
pub const fn stateless_reset_token(&self) -> &[u8; QUIC_STATELESS_RESET_TOKEN_LEN] {
&self.stateless_reset_token
}
pub fn decode(bytes: impl AsRef<[u8]>) -> Result<Self> {
let bytes = bytes.as_ref();
let (frame, consumed) = decode_new_connection_id_frame(bytes)?;
if consumed != bytes.len() {
return Err(CrafterError::invalid_field_value(
"quic.frame.new_connection_id",
"NEW_CONNECTION_ID frame has trailing bytes",
));
}
Ok(frame)
}
pub fn encode(&self, out: &mut Vec<u8>) -> Result<()> {
QuicVarInt::from_u64_unchecked(0x18).encode(out)?;
self.sequence_number.encode(out)?;
self.retire_prior_to.encode(out)?;
out.push(self.connection_id_length()?);
out.extend_from_slice(self.connection_id.as_bytes());
out.extend_from_slice(&self.stateless_reset_token);
Ok(())
}
pub fn encode_to_vec(&self) -> Result<Vec<u8>> {
let mut out = Vec::new();
self.encode(&mut out)?;
Ok(out)
}
pub fn summary(&self) -> String {
format!(
"kind=NEW_CONNECTION_ID sequence_number={} retire_prior_to={} connection_id_len={} connection_id={}",
self.sequence_number.value(),
self.retire_prior_to.value(),
self.connection_id.len(),
self.connection_id.to_hex()
)
}
pub fn inspection_fields(&self) -> Vec<(&'static str, String)> {
vec![
(
"new_connection_id_sequence_number",
self.sequence_number.value().to_string(),
),
(
"new_connection_id_retire_prior_to",
self.retire_prior_to.value().to_string(),
),
(
"new_connection_id_length",
self.connection_id_length()
.map(|len| len.to_string())
.unwrap_or_else(|_| "<invalid>".to_string()),
),
(
"new_connection_id_len",
self.connection_id.len().to_string(),
),
("new_connection_id", self.connection_id.to_hex()),
(
"new_connection_id_stateless_reset_token",
hex_bytes(&self.stateless_reset_token),
),
]
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct QuicRetireConnectionIdFrame {
sequence_number: QuicVarInt,
}
impl QuicRetireConnectionIdFrame {
pub const fn new(sequence_number: QuicVarInt) -> Self {
Self { sequence_number }
}
pub fn from_value(sequence_number: u64) -> Result<Self> {
Ok(Self::new(QuicVarInt::new(sequence_number)?))
}
pub const fn sequence_number(self) -> QuicVarInt {
self.sequence_number
}
pub fn decode(bytes: impl AsRef<[u8]>) -> Result<Self> {
let bytes = bytes.as_ref();
let (frame, consumed) = decode_retire_connection_id_frame(bytes)?;
if consumed != bytes.len() {
return Err(CrafterError::invalid_field_value(
"quic.frame.retire_connection_id",
"RETIRE_CONNECTION_ID frame has trailing bytes",
));
}
Ok(frame)
}
pub fn encode(self, out: &mut Vec<u8>) -> Result<()> {
QuicVarInt::from_u64_unchecked(0x19).encode(out)?;
self.sequence_number.encode(out)?;
Ok(())
}
pub fn encode_to_vec(self) -> Result<Vec<u8>> {
let mut out = Vec::new();
self.encode(&mut out)?;
Ok(out)
}
pub fn summary(self) -> String {
format!(
"kind=RETIRE_CONNECTION_ID sequence_number={}",
self.sequence_number.value()
)
}
pub fn inspection_fields(self) -> Vec<(&'static str, String)> {
vec![(
"retire_connection_id_sequence_number",
self.sequence_number.value().to_string(),
)]
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct QuicPathChallengeFrame {
data: [u8; QUIC_PATH_VALIDATION_DATA_LEN],
}
impl QuicPathChallengeFrame {
pub const fn new(data: [u8; QUIC_PATH_VALIDATION_DATA_LEN]) -> Self {
Self { data }
}
pub const fn data(&self) -> &[u8; QUIC_PATH_VALIDATION_DATA_LEN] {
&self.data
}
pub fn decode(bytes: impl AsRef<[u8]>) -> Result<Self> {
let bytes = bytes.as_ref();
let (frame, consumed) = decode_path_challenge_frame(bytes)?;
if consumed != bytes.len() {
return Err(CrafterError::invalid_field_value(
"quic.frame.path_challenge",
"PATH_CHALLENGE frame has trailing bytes",
));
}
Ok(frame)
}
pub fn encode(self, out: &mut Vec<u8>) -> Result<()> {
QuicVarInt::from_u64_unchecked(0x1a).encode(out)?;
out.extend_from_slice(&self.data);
Ok(())
}
pub fn encode_to_vec(self) -> Result<Vec<u8>> {
let mut out = Vec::new();
self.encode(&mut out)?;
Ok(out)
}
pub fn summary(self) -> String {
format!("kind=PATH_CHALLENGE data={}", hex_bytes(&self.data))
}
pub fn inspection_fields(self) -> Vec<(&'static str, String)> {
vec![("path_challenge_data", hex_bytes(&self.data))]
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct QuicPathResponseFrame {
data: [u8; QUIC_PATH_VALIDATION_DATA_LEN],
}
impl QuicPathResponseFrame {
pub const fn new(data: [u8; QUIC_PATH_VALIDATION_DATA_LEN]) -> Self {
Self { data }
}
pub const fn data(&self) -> &[u8; QUIC_PATH_VALIDATION_DATA_LEN] {
&self.data
}
pub fn decode(bytes: impl AsRef<[u8]>) -> Result<Self> {
let bytes = bytes.as_ref();
let (frame, consumed) = decode_path_response_frame(bytes)?;
if consumed != bytes.len() {
return Err(CrafterError::invalid_field_value(
"quic.frame.path_response",
"PATH_RESPONSE frame has trailing bytes",
));
}
Ok(frame)
}
pub fn encode(self, out: &mut Vec<u8>) -> Result<()> {
QuicVarInt::from_u64_unchecked(0x1b).encode(out)?;
out.extend_from_slice(&self.data);
Ok(())
}
pub fn encode_to_vec(self) -> Result<Vec<u8>> {
let mut out = Vec::new();
self.encode(&mut out)?;
Ok(out)
}
pub fn summary(self) -> String {
format!("kind=PATH_RESPONSE data={}", hex_bytes(&self.data))
}
pub fn inspection_fields(self) -> Vec<(&'static str, String)> {
vec![("path_response_data", hex_bytes(&self.data))]
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum QuicConnectionCloseKind {
Transport,
Application,
}
impl QuicConnectionCloseKind {
pub const fn frame_type_value(self) -> u64 {
match self {
Self::Transport => 0x1c,
Self::Application => 0x1d,
}
}
pub const fn label(self) -> &'static str {
match self {
Self::Transport => "transport",
Self::Application => "application",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct QuicConnectionCloseFrame {
kind: QuicConnectionCloseKind,
error_code: QuicVarInt,
frame_type: Option<QuicVarInt>,
reason_length: Option<QuicVarInt>,
reason_phrase: Vec<u8>,
}
impl QuicConnectionCloseFrame {
pub fn transport(
error_code: QuicVarInt,
frame_type: QuicVarInt,
reason_phrase: impl AsRef<[u8]>,
) -> Self {
Self {
kind: QuicConnectionCloseKind::Transport,
error_code,
frame_type: Some(frame_type),
reason_length: None,
reason_phrase: reason_phrase.as_ref().to_vec(),
}
}
pub fn application(error_code: QuicVarInt, reason_phrase: impl AsRef<[u8]>) -> Self {
Self {
kind: QuicConnectionCloseKind::Application,
error_code,
frame_type: None,
reason_length: None,
reason_phrase: reason_phrase.as_ref().to_vec(),
}
}
pub fn with_reason_length(mut self, reason_length: QuicVarInt) -> Self {
self.reason_length = Some(reason_length);
self
}
pub const fn kind(&self) -> QuicConnectionCloseKind {
self.kind
}
pub const fn error_code(&self) -> QuicVarInt {
self.error_code
}
pub const fn triggering_frame_type(&self) -> Option<QuicVarInt> {
self.frame_type
}
pub fn reason_length(&self) -> Result<QuicVarInt> {
match self.reason_length {
Some(reason_length) => Ok(reason_length),
None => QuicVarInt::new(u64::try_from(self.reason_phrase.len()).map_err(|_| {
CrafterError::invalid_field_value(
"quic.frame.connection_close.reason_length",
"reason phrase length exceeds u64",
)
})?),
}
}
pub const fn reason_length_override(&self) -> Option<QuicVarInt> {
self.reason_length
}
pub fn reason_phrase(&self) -> &[u8] {
&self.reason_phrase
}
pub fn reason_phrase_str(&self) -> Option<&str> {
core::str::from_utf8(&self.reason_phrase).ok()
}
pub fn reason_phrase_lossy(&self) -> String {
String::from_utf8_lossy(&self.reason_phrase).into_owned()
}
pub fn decode(bytes: impl AsRef<[u8]>) -> Result<Self> {
let bytes = bytes.as_ref();
let (frame, consumed) = decode_connection_close_frame(bytes)?;
if consumed != bytes.len() {
return Err(CrafterError::invalid_field_value(
"quic.frame.connection_close",
"CONNECTION_CLOSE frame has trailing bytes",
));
}
Ok(frame)
}
pub fn encode(&self, out: &mut Vec<u8>) -> Result<()> {
QuicVarInt::from_u64_unchecked(self.kind.frame_type_value()).encode(out)?;
self.error_code.encode(out)?;
if let Some(frame_type) = self.frame_type {
frame_type.encode(out)?;
}
self.reason_length()?.encode(out)?;
out.extend_from_slice(&self.reason_phrase);
Ok(())
}
pub fn encode_to_vec(&self) -> Result<Vec<u8>> {
let mut out = Vec::new();
self.encode(&mut out)?;
Ok(out)
}
pub fn summary(&self) -> String {
match self.kind {
QuicConnectionCloseKind::Transport => format!(
"kind=CONNECTION_CLOSE_TRANSPORT error_code=0x{:x} frame_type=0x{:x} reason_len={}",
self.error_code.value(),
self.frame_type.map(QuicVarInt::value).unwrap_or(0),
self.reason_phrase.len()
),
QuicConnectionCloseKind::Application => format!(
"kind=CONNECTION_CLOSE_APPLICATION error_code=0x{:x} reason_len={}",
self.error_code.value(),
self.reason_phrase.len()
),
}
}
pub fn inspection_fields(&self) -> Vec<(&'static str, String)> {
vec![
("connection_close_kind", self.kind.label().to_string()),
(
"connection_close_error_code",
format!("0x{:x}", self.error_code.value()),
),
(
"connection_close_frame_type",
self.frame_type
.map(|frame_type| format!("0x{:x}", frame_type.value()))
.unwrap_or_else(|| "<none>".to_string()),
),
(
"connection_close_reason_length",
self.reason_length()
.map(|length| length.value().to_string())
.unwrap_or_else(|_| "<invalid>".to_string()),
),
(
"connection_close_reason_len",
self.reason_phrase.len().to_string(),
),
("connection_close_reason", hex_bytes(&self.reason_phrase)),
("connection_close_reason_text", self.reason_phrase_lossy()),
]
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct QuicHandshakeDoneFrame;
impl QuicHandshakeDoneFrame {
pub const fn new() -> Self {
Self
}
pub fn decode(bytes: impl AsRef<[u8]>) -> Result<Self> {
let bytes = bytes.as_ref();
let (frame, consumed) = decode_handshake_done_frame(bytes)?;
if consumed != bytes.len() {
return Err(CrafterError::invalid_field_value(
"quic.frame.handshake_done",
"HANDSHAKE_DONE frame has trailing bytes",
));
}
Ok(frame)
}
pub fn encode(self, out: &mut Vec<u8>) -> Result<()> {
QuicVarInt::from_u64_unchecked(0x1e).encode(out)?;
Ok(())
}
pub fn encode_to_vec(self) -> Result<Vec<u8>> {
let mut out = Vec::new();
self.encode(&mut out)?;
Ok(out)
}
pub const fn summary(self) -> &'static str {
"kind=HANDSHAKE_DONE"
}
pub fn inspection_fields(self) -> Vec<(&'static str, String)> {
vec![("handshake_done", "true".to_string())]
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct QuicDatagramFrame {
include_length: bool,
length: Option<QuicVarInt>,
data: Vec<u8>,
}
impl QuicDatagramFrame {
pub fn new(data: impl AsRef<[u8]>) -> Self {
Self {
include_length: true,
length: None,
data: data.as_ref().to_vec(),
}
}
pub fn with_length(mut self, length: QuicVarInt) -> Self {
self.include_length = true;
self.length = Some(length);
self
}
pub fn without_length(mut self) -> Self {
self.include_length = false;
self.length = None;
self
}
pub const fn has_length(&self) -> bool {
self.include_length
}
pub const fn frame_type_value(&self) -> u64 {
if self.include_length {
0x31
} else {
0x30
}
}
pub fn length(&self) -> Result<Option<QuicVarInt>> {
if !self.include_length {
return Ok(None);
}
match self.length {
Some(length) => Ok(Some(length)),
None => Ok(Some(QuicVarInt::new(
u64::try_from(self.data.len()).map_err(|_| {
CrafterError::invalid_field_value(
"quic.frame.datagram.length",
"data length exceeds u64",
)
})?,
)?)),
}
}
pub const fn length_override(&self) -> Option<QuicVarInt> {
self.length
}
pub fn data(&self) -> &[u8] {
&self.data
}
pub fn decode(bytes: impl AsRef<[u8]>) -> Result<Self> {
let bytes = bytes.as_ref();
let (frame, consumed) = decode_datagram_frame(bytes)?;
if consumed != bytes.len() {
return Err(CrafterError::invalid_field_value(
"quic.frame.datagram",
"DATAGRAM frame has trailing bytes",
));
}
Ok(frame)
}
pub fn encode(&self, out: &mut Vec<u8>) -> Result<()> {
QuicVarInt::from_u64_unchecked(self.frame_type_value()).encode(out)?;
if let Some(length) = self.length()? {
length.encode(out)?;
}
out.extend_from_slice(&self.data);
Ok(())
}
pub fn encode_to_vec(&self) -> Result<Vec<u8>> {
let mut out = Vec::new();
self.encode(&mut out)?;
Ok(out)
}
pub fn summary(&self) -> String {
let kind = if self.include_length {
"DATAGRAM_LEN"
} else {
"DATAGRAM"
};
let length = self
.length()
.ok()
.flatten()
.map(|length| length.value().to_string())
.unwrap_or_else(|| "<none>".to_string());
format!(
"kind={kind} has_length={} length={length} data_len={}",
self.include_length,
self.data.len()
)
}
pub fn inspection_fields(&self) -> Vec<(&'static str, String)> {
vec![
("datagram_has_length", self.include_length.to_string()),
(
"datagram_length",
self.length()
.ok()
.flatten()
.map(|length| length.value().to_string())
.unwrap_or_else(|| "<none>".to_string()),
),
("datagram_data_len", self.data.len().to_string()),
("datagram_data", hex_bytes(&self.data)),
]
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct QuicUnknownFrame {
frame_type: QuicVarInt,
raw_following_bytes: Vec<u8>,
}
impl QuicUnknownFrame {
pub fn new(frame_type: QuicVarInt, raw_following_bytes: impl AsRef<[u8]>) -> Self {
Self {
frame_type,
raw_following_bytes: raw_following_bytes.as_ref().to_vec(),
}
}
pub fn decode(bytes: impl AsRef<[u8]>) -> Result<Self> {
let bytes = bytes.as_ref();
let (frame_type, offset) = decode_frame_varint(bytes, 0, "quic.frame.unknown.type")?;
Ok(Self::new(frame_type, &bytes[offset..]))
}
pub const fn frame_type(&self) -> QuicVarInt {
self.frame_type
}
pub const fn frame_type_value(&self) -> u64 {
self.frame_type.value()
}
pub fn raw_following_bytes(&self) -> &[u8] {
&self.raw_following_bytes
}
pub fn encode(&self, out: &mut Vec<u8>) -> Result<()> {
self.frame_type.encode(out)?;
out.extend_from_slice(&self.raw_following_bytes);
Ok(())
}
pub fn encode_to_vec(&self) -> Result<Vec<u8>> {
let mut out = Vec::new();
self.encode(&mut out)?;
Ok(out)
}
pub fn summary(&self) -> String {
format!(
"kind=UNKNOWN type=0x{:x} following_len={}",
self.frame_type.value(),
self.raw_following_bytes.len()
)
}
pub fn inspection_fields(&self) -> Vec<(&'static str, String)> {
vec![
(
"unknown_frame_type",
format!("0x{:x}", self.frame_type.value()),
),
(
"unknown_following_len",
self.raw_following_bytes.len().to_string(),
),
(
"unknown_following_bytes",
hex_bytes(&self.raw_following_bytes),
),
]
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct QuicFrame {
bytes: Vec<u8>,
kind: QuicFrameKind,
}
impl QuicFrame {
pub fn from_bytes(bytes: impl AsRef<[u8]>) -> Self {
let bytes = bytes.as_ref();
Self {
bytes: bytes.to_vec(),
kind: classify_frame_kind(bytes),
}
}
pub fn padding(count: usize) -> Self {
let bytes = vec![0x00; count];
Self {
kind: classify_frame_kind(&bytes),
bytes,
}
}
pub fn ping() -> Self {
Self {
bytes: vec![0x01],
kind: QuicFrameKind::Known(QuicKnownFrameType::Ping),
}
}
pub fn from_unknown_frame(unknown: QuicUnknownFrame) -> Result<Self> {
Ok(Self::from_bytes(unknown.encode_to_vec()?))
}
pub fn unknown(frame_type: QuicVarInt, raw_following_bytes: impl AsRef<[u8]>) -> Result<Self> {
Self::from_unknown_frame(QuicUnknownFrame::new(frame_type, raw_following_bytes))
}
pub fn from_ack_frame(ack: QuicAckFrame) -> Result<Self> {
Ok(Self::from_bytes(ack.encode_to_vec()?))
}
pub fn ack(
largest_acknowledged: QuicVarInt,
ack_delay: QuicVarInt,
first_ack_range: QuicVarInt,
ack_ranges: impl IntoIterator<Item = QuicAckRange>,
) -> Result<Self> {
Self::from_ack_frame(QuicAckFrame::new(
largest_acknowledged,
ack_delay,
first_ack_range,
ack_ranges,
))
}
pub fn ack_ecn(
largest_acknowledged: QuicVarInt,
ack_delay: QuicVarInt,
first_ack_range: QuicVarInt,
ack_ranges: impl IntoIterator<Item = QuicAckRange>,
ecn_counts: QuicAckEcnCounts,
) -> Result<Self> {
Self::from_ack_frame(
QuicAckFrame::new(largest_acknowledged, ack_delay, first_ack_range, ack_ranges)
.with_ecn_counts(ecn_counts),
)
}
pub fn from_reset_stream_frame(reset_stream: QuicResetStreamFrame) -> Result<Self> {
Ok(Self::from_bytes(reset_stream.encode_to_vec()?))
}
pub fn reset_stream(
stream_id: QuicVarInt,
application_error_code: QuicVarInt,
final_size: QuicVarInt,
) -> Result<Self> {
Self::from_reset_stream_frame(QuicResetStreamFrame::new(
stream_id,
application_error_code,
final_size,
))
}
pub fn from_stop_sending_frame(stop_sending: QuicStopSendingFrame) -> Result<Self> {
Ok(Self::from_bytes(stop_sending.encode_to_vec()?))
}
pub fn stop_sending(stream_id: QuicVarInt, application_error_code: QuicVarInt) -> Result<Self> {
Self::from_stop_sending_frame(QuicStopSendingFrame::new(stream_id, application_error_code))
}
pub fn from_crypto_frame(crypto: QuicCryptoFrame) -> Result<Self> {
Ok(Self::from_bytes(crypto.encode_to_vec()?))
}
pub fn crypto(offset: QuicVarInt, data: impl AsRef<[u8]>) -> Result<Self> {
Self::from_crypto_frame(QuicCryptoFrame::new(offset, data))
}
pub fn from_new_token_frame(new_token: QuicNewTokenFrame) -> Result<Self> {
Ok(Self::from_bytes(new_token.encode_to_vec()?))
}
pub fn new_token(token: impl AsRef<[u8]>) -> Result<Self> {
Self::from_new_token_frame(QuicNewTokenFrame::new(token))
}
pub fn from_stream_frame(stream: QuicStreamFrame) -> Result<Self> {
Ok(Self::from_bytes(stream.encode_to_vec()?))
}
pub fn stream(stream_id: QuicVarInt, data: impl AsRef<[u8]>) -> Result<Self> {
Self::from_stream_frame(QuicStreamFrame::new(stream_id, data))
}
pub fn from_max_data_frame(max_data: QuicMaxDataFrame) -> Result<Self> {
Ok(Self::from_bytes(max_data.encode_to_vec()?))
}
pub fn max_data(maximum_data: QuicVarInt) -> Result<Self> {
Self::from_max_data_frame(QuicMaxDataFrame::new(maximum_data))
}
pub fn from_max_stream_data_frame(max_stream_data: QuicMaxStreamDataFrame) -> Result<Self> {
Ok(Self::from_bytes(max_stream_data.encode_to_vec()?))
}
pub fn max_stream_data(stream_id: QuicVarInt, maximum_stream_data: QuicVarInt) -> Result<Self> {
Self::from_max_stream_data_frame(QuicMaxStreamDataFrame::new(
stream_id,
maximum_stream_data,
))
}
pub fn from_max_streams_frame(max_streams: QuicMaxStreamsFrame) -> Result<Self> {
Ok(Self::from_bytes(max_streams.encode_to_vec()?))
}
pub fn max_streams(
direction: QuicStreamDirection,
maximum_streams: QuicVarInt,
) -> Result<Self> {
Self::from_max_streams_frame(QuicMaxStreamsFrame::new(direction, maximum_streams))
}
pub fn max_streams_bidirectional(maximum_streams: QuicVarInt) -> Result<Self> {
Self::from_max_streams_frame(QuicMaxStreamsFrame::bidirectional(maximum_streams))
}
pub fn max_streams_unidirectional(maximum_streams: QuicVarInt) -> Result<Self> {
Self::from_max_streams_frame(QuicMaxStreamsFrame::unidirectional(maximum_streams))
}
pub fn from_data_blocked_frame(data_blocked: QuicDataBlockedFrame) -> Result<Self> {
Ok(Self::from_bytes(data_blocked.encode_to_vec()?))
}
pub fn data_blocked(data_limit: QuicVarInt) -> Result<Self> {
Self::from_data_blocked_frame(QuicDataBlockedFrame::new(data_limit))
}
pub fn from_stream_data_blocked_frame(
stream_data_blocked: QuicStreamDataBlockedFrame,
) -> Result<Self> {
Ok(Self::from_bytes(stream_data_blocked.encode_to_vec()?))
}
pub fn stream_data_blocked(
stream_id: QuicVarInt,
maximum_stream_data: QuicVarInt,
) -> Result<Self> {
Self::from_stream_data_blocked_frame(QuicStreamDataBlockedFrame::new(
stream_id,
maximum_stream_data,
))
}
pub fn from_streams_blocked_frame(streams_blocked: QuicStreamsBlockedFrame) -> Result<Self> {
Ok(Self::from_bytes(streams_blocked.encode_to_vec()?))
}
pub fn streams_blocked(
direction: QuicStreamDirection,
maximum_streams: QuicVarInt,
) -> Result<Self> {
Self::from_streams_blocked_frame(QuicStreamsBlockedFrame::new(direction, maximum_streams))
}
pub fn streams_blocked_bidirectional(maximum_streams: QuicVarInt) -> Result<Self> {
Self::from_streams_blocked_frame(QuicStreamsBlockedFrame::bidirectional(maximum_streams))
}
pub fn streams_blocked_unidirectional(maximum_streams: QuicVarInt) -> Result<Self> {
Self::from_streams_blocked_frame(QuicStreamsBlockedFrame::unidirectional(maximum_streams))
}
pub fn from_new_connection_id_frame(
new_connection_id: QuicNewConnectionIdFrame,
) -> Result<Self> {
Ok(Self::from_bytes(new_connection_id.encode_to_vec()?))
}
pub fn new_connection_id(
sequence_number: QuicVarInt,
retire_prior_to: QuicVarInt,
connection_id: QuicConnectionId,
stateless_reset_token: [u8; QUIC_STATELESS_RESET_TOKEN_LEN],
) -> Result<Self> {
Self::from_new_connection_id_frame(QuicNewConnectionIdFrame::new(
sequence_number,
retire_prior_to,
connection_id,
stateless_reset_token,
))
}
pub fn from_retire_connection_id_frame(
retire_connection_id: QuicRetireConnectionIdFrame,
) -> Result<Self> {
Ok(Self::from_bytes(retire_connection_id.encode_to_vec()?))
}
pub fn retire_connection_id(sequence_number: QuicVarInt) -> Result<Self> {
Self::from_retire_connection_id_frame(QuicRetireConnectionIdFrame::new(sequence_number))
}
pub fn from_path_challenge_frame(path_challenge: QuicPathChallengeFrame) -> Result<Self> {
Ok(Self::from_bytes(path_challenge.encode_to_vec()?))
}
pub fn path_challenge(data: [u8; QUIC_PATH_VALIDATION_DATA_LEN]) -> Result<Self> {
Self::from_path_challenge_frame(QuicPathChallengeFrame::new(data))
}
pub fn from_path_response_frame(path_response: QuicPathResponseFrame) -> Result<Self> {
Ok(Self::from_bytes(path_response.encode_to_vec()?))
}
pub fn path_response(data: [u8; QUIC_PATH_VALIDATION_DATA_LEN]) -> Result<Self> {
Self::from_path_response_frame(QuicPathResponseFrame::new(data))
}
pub fn from_connection_close_frame(connection_close: QuicConnectionCloseFrame) -> Result<Self> {
Ok(Self::from_bytes(connection_close.encode_to_vec()?))
}
pub fn connection_close_transport(
error_code: QuicVarInt,
frame_type: QuicVarInt,
reason_phrase: impl AsRef<[u8]>,
) -> Result<Self> {
Self::from_connection_close_frame(QuicConnectionCloseFrame::transport(
error_code,
frame_type,
reason_phrase,
))
}
pub fn connection_close_application(
error_code: QuicVarInt,
reason_phrase: impl AsRef<[u8]>,
) -> Result<Self> {
Self::from_connection_close_frame(QuicConnectionCloseFrame::application(
error_code,
reason_phrase,
))
}
pub fn from_handshake_done_frame(handshake_done: QuicHandshakeDoneFrame) -> Result<Self> {
Ok(Self::from_bytes(handshake_done.encode_to_vec()?))
}
pub fn handshake_done() -> Result<Self> {
Self::from_handshake_done_frame(QuicHandshakeDoneFrame::new())
}
pub fn from_datagram_frame(datagram: QuicDatagramFrame) -> Result<Self> {
Ok(Self::from_bytes(datagram.encode_to_vec()?))
}
pub fn datagram(data: impl AsRef<[u8]>) -> Result<Self> {
Self::from_datagram_frame(QuicDatagramFrame::new(data))
}
pub fn datagram_without_length(data: impl AsRef<[u8]>) -> Result<Self> {
Self::from_datagram_frame(QuicDatagramFrame::new(data).without_length())
}
pub fn decode_sequence(bytes: impl AsRef<[u8]>) -> Result<Vec<Self>> {
let bytes = bytes.as_ref();
let mut frames = Vec::new();
let mut offset = 0;
while offset < bytes.len() {
let (frame_type, consumed) = QuicVarInt::decode(&bytes[offset..])?;
match frame_type.value() {
0x00 if bytes[offset] == 0x00 => {
let start = offset;
offset += 1;
while offset < bytes.len() && bytes[offset] == 0x00 {
offset += 1;
}
frames.push(Self::from_bytes(&bytes[start..offset]));
}
0x01 => {
let end = offset + consumed;
frames.push(Self::from_bytes(&bytes[offset..end]));
offset = end;
}
0x02 | 0x03 => {
let (_, ack_len) = decode_ack_frame(&bytes[offset..])?;
let end = offset + ack_len;
frames.push(Self::from_bytes(&bytes[offset..end]));
offset = end;
}
0x04 => {
let (_, reset_stream_len) = decode_reset_stream_frame(&bytes[offset..])?;
let end = offset + reset_stream_len;
frames.push(Self::from_bytes(&bytes[offset..end]));
offset = end;
}
0x05 => {
let (_, stop_sending_len) = decode_stop_sending_frame(&bytes[offset..])?;
let end = offset + stop_sending_len;
frames.push(Self::from_bytes(&bytes[offset..end]));
offset = end;
}
0x06 => {
let (_, crypto_len) = decode_crypto_frame(&bytes[offset..])?;
let end = offset + crypto_len;
frames.push(Self::from_bytes(&bytes[offset..end]));
offset = end;
}
0x07 => {
let (_, new_token_len) = decode_new_token_frame(&bytes[offset..])?;
let end = offset + new_token_len;
frames.push(Self::from_bytes(&bytes[offset..end]));
offset = end;
}
0x08..=0x0f => {
let (_, stream_len) = decode_stream_frame(&bytes[offset..])?;
let end = offset + stream_len;
frames.push(Self::from_bytes(&bytes[offset..end]));
offset = end;
}
0x10 => {
let (_, max_data_len) = decode_max_data_frame(&bytes[offset..])?;
let end = offset + max_data_len;
frames.push(Self::from_bytes(&bytes[offset..end]));
offset = end;
}
0x11 => {
let (_, max_stream_data_len) = decode_max_stream_data_frame(&bytes[offset..])?;
let end = offset + max_stream_data_len;
frames.push(Self::from_bytes(&bytes[offset..end]));
offset = end;
}
0x12 | 0x13 => {
let (_, max_streams_len) = decode_max_streams_frame(&bytes[offset..])?;
let end = offset + max_streams_len;
frames.push(Self::from_bytes(&bytes[offset..end]));
offset = end;
}
0x14 => {
let (_, data_blocked_len) = decode_data_blocked_frame(&bytes[offset..])?;
let end = offset + data_blocked_len;
frames.push(Self::from_bytes(&bytes[offset..end]));
offset = end;
}
0x15 => {
let (_, stream_data_blocked_len) =
decode_stream_data_blocked_frame(&bytes[offset..])?;
let end = offset + stream_data_blocked_len;
frames.push(Self::from_bytes(&bytes[offset..end]));
offset = end;
}
0x16 | 0x17 => {
let (_, streams_blocked_len) = decode_streams_blocked_frame(&bytes[offset..])?;
let end = offset + streams_blocked_len;
frames.push(Self::from_bytes(&bytes[offset..end]));
offset = end;
}
0x18 => {
let (_, new_connection_id_len) =
decode_new_connection_id_frame(&bytes[offset..])?;
let end = offset + new_connection_id_len;
frames.push(Self::from_bytes(&bytes[offset..end]));
offset = end;
}
0x19 => {
let (_, retire_connection_id_len) =
decode_retire_connection_id_frame(&bytes[offset..])?;
let end = offset + retire_connection_id_len;
frames.push(Self::from_bytes(&bytes[offset..end]));
offset = end;
}
0x1a => {
let (_, path_challenge_len) = decode_path_challenge_frame(&bytes[offset..])?;
let end = offset + path_challenge_len;
frames.push(Self::from_bytes(&bytes[offset..end]));
offset = end;
}
0x1b => {
let (_, path_response_len) = decode_path_response_frame(&bytes[offset..])?;
let end = offset + path_response_len;
frames.push(Self::from_bytes(&bytes[offset..end]));
offset = end;
}
0x1c | 0x1d => {
let (_, connection_close_len) =
decode_connection_close_frame(&bytes[offset..])?;
let end = offset + connection_close_len;
frames.push(Self::from_bytes(&bytes[offset..end]));
offset = end;
}
0x1e => {
let (_, handshake_done_len) = decode_handshake_done_frame(&bytes[offset..])?;
let end = offset + handshake_done_len;
frames.push(Self::from_bytes(&bytes[offset..end]));
offset = end;
}
0x30 | 0x31 => {
let (_, datagram_len) = decode_datagram_frame(&bytes[offset..])?;
let end = offset + datagram_len;
frames.push(Self::from_bytes(&bytes[offset..end]));
offset = end;
}
_ => {
frames.push(Self::from_bytes(&bytes[offset..]));
break;
}
}
}
Ok(frames)
}
pub fn encode_sequence(frames: impl IntoIterator<Item = Self>) -> Vec<u8> {
let mut out = Vec::new();
for frame in frames {
frame.encode(&mut out);
}
out
}
pub fn encoded_sequence_len<'a>(frames: impl IntoIterator<Item = &'a Self>) -> usize {
frames.into_iter().map(Self::encoded_len).sum()
}
pub const fn kind(&self) -> QuicFrameKind {
self.kind
}
pub fn is_padding(&self) -> bool {
matches!(self.kind, QuicFrameKind::Known(QuicKnownFrameType::Padding))
&& self.bytes.iter().all(|byte| *byte == 0x00)
}
pub fn padding_len(&self) -> Option<usize> {
self.is_padding().then_some(self.bytes.len())
}
pub fn is_ping(&self) -> bool {
matches!(self.kind, QuicFrameKind::Known(QuicKnownFrameType::Ping))
&& self.frame_type_value() == Some(0x01)
&& self.frame_type_encoded_len() == Some(self.bytes.len())
}
pub fn ack_frame(&self) -> Result<Option<QuicAckFrame>> {
match self.frame_type_value() {
Some(0x02 | 0x03) => Ok(Some(QuicAckFrame::decode(&self.bytes)?)),
_ => Ok(None),
}
}
pub fn reset_stream_frame(&self) -> Result<Option<QuicResetStreamFrame>> {
match self.frame_type_value() {
Some(0x04) => Ok(Some(QuicResetStreamFrame::decode(&self.bytes)?)),
_ => Ok(None),
}
}
pub fn stop_sending_frame(&self) -> Result<Option<QuicStopSendingFrame>> {
match self.frame_type_value() {
Some(0x05) => Ok(Some(QuicStopSendingFrame::decode(&self.bytes)?)),
_ => Ok(None),
}
}
pub fn crypto_frame(&self) -> Result<Option<QuicCryptoFrame>> {
match self.frame_type_value() {
Some(0x06) => Ok(Some(QuicCryptoFrame::decode(&self.bytes)?)),
_ => Ok(None),
}
}
pub fn new_token_frame(&self) -> Result<Option<QuicNewTokenFrame>> {
match self.frame_type_value() {
Some(0x07) => Ok(Some(QuicNewTokenFrame::decode(&self.bytes)?)),
_ => Ok(None),
}
}
pub fn stream_frame(&self) -> Result<Option<QuicStreamFrame>> {
match self.frame_type_value() {
Some(0x08..=0x0f) => Ok(Some(QuicStreamFrame::decode(&self.bytes)?)),
_ => Ok(None),
}
}
pub fn max_data_frame(&self) -> Result<Option<QuicMaxDataFrame>> {
match self.frame_type_value() {
Some(0x10) => Ok(Some(QuicMaxDataFrame::decode(&self.bytes)?)),
_ => Ok(None),
}
}
pub fn max_stream_data_frame(&self) -> Result<Option<QuicMaxStreamDataFrame>> {
match self.frame_type_value() {
Some(0x11) => Ok(Some(QuicMaxStreamDataFrame::decode(&self.bytes)?)),
_ => Ok(None),
}
}
pub fn max_streams_frame(&self) -> Result<Option<QuicMaxStreamsFrame>> {
match self.frame_type_value() {
Some(0x12 | 0x13) => Ok(Some(QuicMaxStreamsFrame::decode(&self.bytes)?)),
_ => Ok(None),
}
}
pub fn data_blocked_frame(&self) -> Result<Option<QuicDataBlockedFrame>> {
match self.frame_type_value() {
Some(0x14) => Ok(Some(QuicDataBlockedFrame::decode(&self.bytes)?)),
_ => Ok(None),
}
}
pub fn stream_data_blocked_frame(&self) -> Result<Option<QuicStreamDataBlockedFrame>> {
match self.frame_type_value() {
Some(0x15) => Ok(Some(QuicStreamDataBlockedFrame::decode(&self.bytes)?)),
_ => Ok(None),
}
}
pub fn streams_blocked_frame(&self) -> Result<Option<QuicStreamsBlockedFrame>> {
match self.frame_type_value() {
Some(0x16 | 0x17) => Ok(Some(QuicStreamsBlockedFrame::decode(&self.bytes)?)),
_ => Ok(None),
}
}
pub fn new_connection_id_frame(&self) -> Result<Option<QuicNewConnectionIdFrame>> {
match self.frame_type_value() {
Some(0x18) => Ok(Some(QuicNewConnectionIdFrame::decode(&self.bytes)?)),
_ => Ok(None),
}
}
pub fn retire_connection_id_frame(&self) -> Result<Option<QuicRetireConnectionIdFrame>> {
match self.frame_type_value() {
Some(0x19) => Ok(Some(QuicRetireConnectionIdFrame::decode(&self.bytes)?)),
_ => Ok(None),
}
}
pub fn path_challenge_frame(&self) -> Result<Option<QuicPathChallengeFrame>> {
match self.frame_type_value() {
Some(0x1a) => Ok(Some(QuicPathChallengeFrame::decode(&self.bytes)?)),
_ => Ok(None),
}
}
pub fn path_response_frame(&self) -> Result<Option<QuicPathResponseFrame>> {
match self.frame_type_value() {
Some(0x1b) => Ok(Some(QuicPathResponseFrame::decode(&self.bytes)?)),
_ => Ok(None),
}
}
pub fn connection_close_frame(&self) -> Result<Option<QuicConnectionCloseFrame>> {
match self.frame_type_value() {
Some(0x1c | 0x1d) => Ok(Some(QuicConnectionCloseFrame::decode(&self.bytes)?)),
_ => Ok(None),
}
}
pub fn handshake_done_frame(&self) -> Result<Option<QuicHandshakeDoneFrame>> {
match self.frame_type_value() {
Some(0x1e) => Ok(Some(QuicHandshakeDoneFrame::decode(&self.bytes)?)),
_ => Ok(None),
}
}
pub fn datagram_frame(&self) -> Result<Option<QuicDatagramFrame>> {
match self.frame_type_value() {
Some(0x30 | 0x31) => Ok(Some(QuicDatagramFrame::decode(&self.bytes)?)),
_ => Ok(None),
}
}
pub fn as_bytes(&self) -> &[u8] {
&self.bytes
}
pub fn len(&self) -> usize {
self.bytes.len()
}
pub fn encoded_len(&self) -> usize {
self.len()
}
pub fn is_empty(&self) -> bool {
self.bytes.is_empty()
}
pub fn frame_type(&self) -> Option<QuicVarInt> {
QuicVarInt::decode(&self.bytes)
.ok()
.map(|(frame_type, _)| frame_type)
}
pub fn frame_type_value(&self) -> Option<u64> {
self.frame_type().map(QuicVarInt::value)
}
pub fn frame_type_encoded_len(&self) -> Option<usize> {
QuicVarInt::decode(&self.bytes)
.ok()
.map(|(_, consumed)| consumed)
}
pub fn unknown_frame(&self) -> Result<Option<QuicUnknownFrame>> {
match self.kind {
QuicFrameKind::Unknown => Ok(Some(QuicUnknownFrame::decode(&self.bytes)?)),
_ => Ok(None),
}
}
pub fn encode(&self, out: &mut Vec<u8>) {
out.extend_from_slice(&self.bytes);
}
pub fn encode_to_vec(&self) -> Vec<u8> {
self.bytes.clone()
}
pub fn summary(&self) -> String {
if let Some(padding_len) = self.padding_len() {
return format!("kind=PADDING padding_len={padding_len}");
}
if let Ok(Some(ack)) = self.ack_frame() {
return ack.summary();
}
if let Ok(Some(reset_stream)) = self.reset_stream_frame() {
return reset_stream.summary();
}
if let Ok(Some(stop_sending)) = self.stop_sending_frame() {
return stop_sending.summary();
}
if let Ok(Some(crypto)) = self.crypto_frame() {
return crypto.summary();
}
if let Ok(Some(new_token)) = self.new_token_frame() {
return new_token.summary();
}
if let Ok(Some(stream)) = self.stream_frame() {
return stream.summary();
}
if let Ok(Some(max_data)) = self.max_data_frame() {
return max_data.summary();
}
if let Ok(Some(max_stream_data)) = self.max_stream_data_frame() {
return max_stream_data.summary();
}
if let Ok(Some(max_streams)) = self.max_streams_frame() {
return max_streams.summary();
}
if let Ok(Some(data_blocked)) = self.data_blocked_frame() {
return data_blocked.summary();
}
if let Ok(Some(stream_data_blocked)) = self.stream_data_blocked_frame() {
return stream_data_blocked.summary();
}
if let Ok(Some(streams_blocked)) = self.streams_blocked_frame() {
return streams_blocked.summary();
}
if let Ok(Some(new_connection_id)) = self.new_connection_id_frame() {
return new_connection_id.summary();
}
if let Ok(Some(retire_connection_id)) = self.retire_connection_id_frame() {
return retire_connection_id.summary();
}
if let Ok(Some(path_challenge)) = self.path_challenge_frame() {
return path_challenge.summary();
}
if let Ok(Some(path_response)) = self.path_response_frame() {
return path_response.summary();
}
if let Ok(Some(connection_close)) = self.connection_close_frame() {
return connection_close.summary();
}
if let Ok(Some(handshake_done)) = self.handshake_done_frame() {
return handshake_done.summary().to_string();
}
if let Ok(Some(datagram)) = self.datagram_frame() {
return datagram.summary();
}
match self.frame_type() {
Some(frame_type) => format!(
"kind={} type=0x{:x} raw_len={}",
self.kind.label(),
frame_type.value(),
self.bytes.len()
),
None if self.bytes.is_empty() => "kind=EMPTY type=<empty> raw_len=0".to_string(),
None => format!(
"kind=TRUNCATED type=<truncated> raw_len={}",
self.bytes.len()
),
}
}
pub fn inspection_fields(&self) -> Vec<(&'static str, String)> {
let mut fields = vec![
("frame_kind", self.kind.label().to_string()),
(
"frame_type",
self.frame_type()
.map(|frame_type| format!("0x{:x}", frame_type.value()))
.unwrap_or_else(|| "<unavailable>".to_string()),
),
(
"frame_type_encoded_len",
self.frame_type_encoded_len()
.map(|len| len.to_string())
.unwrap_or_else(|| "<unavailable>".to_string()),
),
("raw_len", self.bytes.len().to_string()),
("raw_bytes", hex_bytes(&self.bytes)),
];
if let Some(padding_len) = self.padding_len() {
fields.push(("padding_len", padding_len.to_string()));
}
if let Ok(Some(ack)) = self.ack_frame() {
fields.extend(ack.inspection_fields());
}
if let Ok(Some(reset_stream)) = self.reset_stream_frame() {
fields.extend(reset_stream.inspection_fields());
}
if let Ok(Some(stop_sending)) = self.stop_sending_frame() {
fields.extend(stop_sending.inspection_fields());
}
if let Ok(Some(crypto)) = self.crypto_frame() {
fields.extend(crypto.inspection_fields());
}
if let Ok(Some(new_token)) = self.new_token_frame() {
fields.extend(new_token.inspection_fields());
}
if let Ok(Some(stream)) = self.stream_frame() {
fields.extend(stream.inspection_fields());
}
if let Ok(Some(max_data)) = self.max_data_frame() {
fields.extend(max_data.inspection_fields());
}
if let Ok(Some(max_stream_data)) = self.max_stream_data_frame() {
fields.extend(max_stream_data.inspection_fields());
}
if let Ok(Some(max_streams)) = self.max_streams_frame() {
fields.extend(max_streams.inspection_fields());
}
if let Ok(Some(data_blocked)) = self.data_blocked_frame() {
fields.extend(data_blocked.inspection_fields());
}
if let Ok(Some(stream_data_blocked)) = self.stream_data_blocked_frame() {
fields.extend(stream_data_blocked.inspection_fields());
}
if let Ok(Some(streams_blocked)) = self.streams_blocked_frame() {
fields.extend(streams_blocked.inspection_fields());
}
if let Ok(Some(new_connection_id)) = self.new_connection_id_frame() {
fields.extend(new_connection_id.inspection_fields());
}
if let Ok(Some(retire_connection_id)) = self.retire_connection_id_frame() {
fields.extend(retire_connection_id.inspection_fields());
}
if let Ok(Some(path_challenge)) = self.path_challenge_frame() {
fields.extend(path_challenge.inspection_fields());
}
if let Ok(Some(path_response)) = self.path_response_frame() {
fields.extend(path_response.inspection_fields());
}
if let Ok(Some(connection_close)) = self.connection_close_frame() {
fields.extend(connection_close.inspection_fields());
}
if let Ok(Some(handshake_done)) = self.handshake_done_frame() {
fields.extend(handshake_done.inspection_fields());
}
if let Ok(Some(datagram)) = self.datagram_frame() {
fields.extend(datagram.inspection_fields());
}
if let Ok(Some(unknown)) = self.unknown_frame() {
fields.extend(unknown.inspection_fields());
}
fields
}
}
impl Default for QuicFrameKind {
fn default() -> Self {
Self::Empty
}
}
fn decode_ack_frame(bytes: &[u8]) -> Result<(QuicAckFrame, usize)> {
let (frame_type, mut offset) = decode_frame_varint(bytes, 0, "quic.frame.type")?;
let is_ecn = match frame_type.value() {
0x02 => false,
0x03 => true,
_ => {
return Err(CrafterError::invalid_field_value(
"quic.frame.ack.type",
"ACK frame type must be 0x02 or 0x03",
))
}
};
let (largest_acknowledged, next) =
decode_frame_varint(bytes, offset, "quic.frame.ack.largest_acknowledged")?;
offset = next;
let (ack_delay, next) = decode_frame_varint(bytes, offset, "quic.frame.ack.ack_delay")?;
offset = next;
let (range_count, next) = decode_frame_varint(bytes, offset, "quic.frame.ack.range_count")?;
offset = next;
let (first_ack_range, next) = decode_frame_varint(bytes, offset, "quic.frame.ack.first_range")?;
offset = next;
let mut ack_ranges = Vec::new();
for _ in 0..range_count.value() {
let (gap, next) = decode_frame_varint(bytes, offset, "quic.frame.ack.range.gap")?;
offset = next;
let (ack_range_length, next) =
decode_frame_varint(bytes, offset, "quic.frame.ack.range.length")?;
offset = next;
ack_ranges.push(QuicAckRange::new(gap, ack_range_length));
}
let ecn_counts = if is_ecn {
let (ect0_count, next) = decode_frame_varint(bytes, offset, "quic.frame.ack.ecn.ect0")?;
offset = next;
let (ect1_count, next) = decode_frame_varint(bytes, offset, "quic.frame.ack.ecn.ect1")?;
offset = next;
let (ce_count, next) = decode_frame_varint(bytes, offset, "quic.frame.ack.ecn.ce")?;
offset = next;
Some(QuicAckEcnCounts::new(ect0_count, ect1_count, ce_count))
} else {
None
};
Ok((
QuicAckFrame {
largest_acknowledged,
ack_delay,
first_ack_range,
ack_ranges,
ecn_counts,
},
offset,
))
}
fn decode_reset_stream_frame(bytes: &[u8]) -> Result<(QuicResetStreamFrame, usize)> {
let (frame_type, mut offset) = decode_frame_varint(bytes, 0, "quic.frame.type")?;
if frame_type.value() != 0x04 {
return Err(CrafterError::invalid_field_value(
"quic.frame.reset_stream.type",
"RESET_STREAM frame type must be 0x04",
));
}
let (stream_id, next) =
decode_frame_varint(bytes, offset, "quic.frame.reset_stream.stream_id")?;
offset = next;
let (application_error_code, next) = decode_frame_varint(
bytes,
offset,
"quic.frame.reset_stream.application_error_code",
)?;
offset = next;
let (final_size, next) =
decode_frame_varint(bytes, offset, "quic.frame.reset_stream.final_size")?;
offset = next;
Ok((
QuicResetStreamFrame::new(stream_id, application_error_code, final_size),
offset,
))
}
fn decode_stop_sending_frame(bytes: &[u8]) -> Result<(QuicStopSendingFrame, usize)> {
let (frame_type, mut offset) = decode_frame_varint(bytes, 0, "quic.frame.type")?;
if frame_type.value() != 0x05 {
return Err(CrafterError::invalid_field_value(
"quic.frame.stop_sending.type",
"STOP_SENDING frame type must be 0x05",
));
}
let (stream_id, next) =
decode_frame_varint(bytes, offset, "quic.frame.stop_sending.stream_id")?;
offset = next;
let (application_error_code, next) = decode_frame_varint(
bytes,
offset,
"quic.frame.stop_sending.application_error_code",
)?;
offset = next;
Ok((
QuicStopSendingFrame::new(stream_id, application_error_code),
offset,
))
}
fn decode_crypto_frame(bytes: &[u8]) -> Result<(QuicCryptoFrame, usize)> {
let (frame_type, mut offset) = decode_frame_varint(bytes, 0, "quic.frame.type")?;
if frame_type.value() != 0x06 {
return Err(CrafterError::invalid_field_value(
"quic.frame.crypto.type",
"CRYPTO frame type must be 0x06",
));
}
let (crypto_offset, next) = decode_frame_varint(bytes, offset, "quic.frame.crypto.offset")?;
offset = next;
let (length, next) = decode_frame_varint(bytes, offset, "quic.frame.crypto.length")?;
offset = next;
let data_len = usize::try_from(length.value()).map_err(|_| {
CrafterError::invalid_field_value("quic.frame.crypto.length", "length exceeds usize")
})?;
let available = bytes.len().saturating_sub(offset);
if available < data_len {
return Err(CrafterError::buffer_too_short(
"quic.frame.crypto.data",
data_len,
available,
));
}
let end = offset + data_len;
Ok((
QuicCryptoFrame::new(crypto_offset, &bytes[offset..end]).with_length(length),
end,
))
}
fn decode_new_token_frame(bytes: &[u8]) -> Result<(QuicNewTokenFrame, usize)> {
let (frame_type, mut offset) = decode_frame_varint(bytes, 0, "quic.frame.type")?;
if frame_type.value() != 0x07 {
return Err(CrafterError::invalid_field_value(
"quic.frame.new_token.type",
"NEW_TOKEN frame type must be 0x07",
));
}
let (token_length, next) =
decode_frame_varint(bytes, offset, "quic.frame.new_token.token_length")?;
offset = next;
let token_len = usize::try_from(token_length.value()).map_err(|_| {
CrafterError::invalid_field_value(
"quic.frame.new_token.token_length",
"length exceeds usize",
)
})?;
let available = bytes.len().saturating_sub(offset);
if available < token_len {
return Err(CrafterError::buffer_too_short(
"quic.frame.new_token.token",
token_len,
available,
));
}
let end = offset + token_len;
Ok((
QuicNewTokenFrame::new(&bytes[offset..end]).with_token_length(token_length),
end,
))
}
fn decode_stream_frame(bytes: &[u8]) -> Result<(QuicStreamFrame, usize)> {
let (frame_type, mut offset) = decode_frame_varint(bytes, 0, "quic.frame.type")?;
let frame_type_value = frame_type.value();
if !(0x08..=0x0f).contains(&frame_type_value) {
return Err(CrafterError::invalid_field_value(
"quic.frame.stream.type",
"STREAM frame type must be 0x08..0x0f",
));
}
let has_offset = frame_type_value & 0x04 != 0;
let has_length = frame_type_value & 0x02 != 0;
let fin = frame_type_value & 0x01 != 0;
let (stream_id, next) = decode_frame_varint(bytes, offset, "quic.frame.stream.stream_id")?;
offset = next;
let stream_offset = if has_offset {
let (stream_offset, next) = decode_frame_varint(bytes, offset, "quic.frame.stream.offset")?;
offset = next;
Some(stream_offset)
} else {
None
};
let (length, data_len) = if has_length {
let (length, next) = decode_frame_varint(bytes, offset, "quic.frame.stream.length")?;
offset = next;
let data_len = usize::try_from(length.value()).map_err(|_| {
CrafterError::invalid_field_value("quic.frame.stream.length", "length exceeds usize")
})?;
(Some(length), data_len)
} else {
(None, bytes.len().saturating_sub(offset))
};
let available = bytes.len().saturating_sub(offset);
if available < data_len {
return Err(CrafterError::buffer_too_short(
"quic.frame.stream.data",
data_len,
available,
));
}
let end = offset + data_len;
let mut stream = QuicStreamFrame::new(stream_id, &bytes[offset..end]).with_fin(fin);
if let Some(stream_offset) = stream_offset {
stream = stream.with_offset(stream_offset);
}
stream = match length {
Some(length) => stream.with_length(length),
None => stream.without_length(),
};
Ok((stream, end))
}
fn decode_max_data_frame(bytes: &[u8]) -> Result<(QuicMaxDataFrame, usize)> {
let (frame_type, mut offset) = decode_frame_varint(bytes, 0, "quic.frame.type")?;
if frame_type.value() != 0x10 {
return Err(CrafterError::invalid_field_value(
"quic.frame.max_data.type",
"MAX_DATA frame type must be 0x10",
));
}
let (maximum_data, next) =
decode_frame_varint(bytes, offset, "quic.frame.max_data.maximum_data")?;
offset = next;
Ok((QuicMaxDataFrame::new(maximum_data), offset))
}
fn decode_max_stream_data_frame(bytes: &[u8]) -> Result<(QuicMaxStreamDataFrame, usize)> {
let (frame_type, mut offset) = decode_frame_varint(bytes, 0, "quic.frame.type")?;
if frame_type.value() != 0x11 {
return Err(CrafterError::invalid_field_value(
"quic.frame.max_stream_data.type",
"MAX_STREAM_DATA frame type must be 0x11",
));
}
let (stream_id, next) =
decode_frame_varint(bytes, offset, "quic.frame.max_stream_data.stream_id")?;
offset = next;
let (maximum_stream_data, next) = decode_frame_varint(
bytes,
offset,
"quic.frame.max_stream_data.maximum_stream_data",
)?;
offset = next;
Ok((
QuicMaxStreamDataFrame::new(stream_id, maximum_stream_data),
offset,
))
}
fn decode_max_streams_frame(bytes: &[u8]) -> Result<(QuicMaxStreamsFrame, usize)> {
let (frame_type, mut offset) = decode_frame_varint(bytes, 0, "quic.frame.type")?;
let direction = match frame_type.value() {
0x12 => QuicStreamDirection::Bidirectional,
0x13 => QuicStreamDirection::Unidirectional,
_ => {
return Err(CrafterError::invalid_field_value(
"quic.frame.max_streams.type",
"MAX_STREAMS frame type must be 0x12 or 0x13",
))
}
};
let (maximum_streams, next) =
decode_frame_varint(bytes, offset, "quic.frame.max_streams.maximum_streams")?;
offset = next;
Ok((QuicMaxStreamsFrame::new(direction, maximum_streams), offset))
}
fn decode_data_blocked_frame(bytes: &[u8]) -> Result<(QuicDataBlockedFrame, usize)> {
let (frame_type, mut offset) = decode_frame_varint(bytes, 0, "quic.frame.type")?;
if frame_type.value() != 0x14 {
return Err(CrafterError::invalid_field_value(
"quic.frame.data_blocked.type",
"DATA_BLOCKED frame type must be 0x14",
));
}
let (data_limit, next) =
decode_frame_varint(bytes, offset, "quic.frame.data_blocked.data_limit")?;
offset = next;
Ok((QuicDataBlockedFrame::new(data_limit), offset))
}
fn decode_stream_data_blocked_frame(bytes: &[u8]) -> Result<(QuicStreamDataBlockedFrame, usize)> {
let (frame_type, mut offset) = decode_frame_varint(bytes, 0, "quic.frame.type")?;
if frame_type.value() != 0x15 {
return Err(CrafterError::invalid_field_value(
"quic.frame.stream_data_blocked.type",
"STREAM_DATA_BLOCKED frame type must be 0x15",
));
}
let (stream_id, next) =
decode_frame_varint(bytes, offset, "quic.frame.stream_data_blocked.stream_id")?;
offset = next;
let (maximum_stream_data, next) = decode_frame_varint(
bytes,
offset,
"quic.frame.stream_data_blocked.maximum_stream_data",
)?;
offset = next;
Ok((
QuicStreamDataBlockedFrame::new(stream_id, maximum_stream_data),
offset,
))
}
fn decode_streams_blocked_frame(bytes: &[u8]) -> Result<(QuicStreamsBlockedFrame, usize)> {
let (frame_type, mut offset) = decode_frame_varint(bytes, 0, "quic.frame.type")?;
let direction = match frame_type.value() {
0x16 => QuicStreamDirection::Bidirectional,
0x17 => QuicStreamDirection::Unidirectional,
_ => {
return Err(CrafterError::invalid_field_value(
"quic.frame.streams_blocked.type",
"STREAMS_BLOCKED frame type must be 0x16 or 0x17",
))
}
};
let (maximum_streams, next) =
decode_frame_varint(bytes, offset, "quic.frame.streams_blocked.maximum_streams")?;
offset = next;
Ok((
QuicStreamsBlockedFrame::new(direction, maximum_streams),
offset,
))
}
fn decode_new_connection_id_frame(bytes: &[u8]) -> Result<(QuicNewConnectionIdFrame, usize)> {
let (frame_type, mut offset) = decode_frame_varint(bytes, 0, "quic.frame.type")?;
if frame_type.value() != 0x18 {
return Err(CrafterError::invalid_field_value(
"quic.frame.new_connection_id.type",
"NEW_CONNECTION_ID frame type must be 0x18",
));
}
let (sequence_number, next) = decode_frame_varint(
bytes,
offset,
"quic.frame.new_connection_id.sequence_number",
)?;
offset = next;
let (retire_prior_to, next) = decode_frame_varint(
bytes,
offset,
"quic.frame.new_connection_id.retire_prior_to",
)?;
offset = next;
let available = bytes.len().saturating_sub(offset);
if available < 1 {
return Err(CrafterError::buffer_too_short(
"quic.frame.new_connection_id.connection_id_length",
1,
available,
));
}
let connection_id_length = bytes[offset];
offset += 1;
let connection_id_len = usize::from(connection_id_length);
validate_new_connection_id_len(connection_id_len)?;
let available = bytes.len().saturating_sub(offset);
if available < connection_id_len {
return Err(CrafterError::buffer_too_short(
"quic.frame.new_connection_id.connection_id",
connection_id_len,
available,
));
}
let connection_id = QuicConnectionId::from_bytes(&bytes[offset..offset + connection_id_len]);
offset += connection_id_len;
let available = bytes.len().saturating_sub(offset);
if available < QUIC_STATELESS_RESET_TOKEN_LEN {
return Err(CrafterError::buffer_too_short(
"quic.frame.new_connection_id.stateless_reset_token",
QUIC_STATELESS_RESET_TOKEN_LEN,
available,
));
}
let mut stateless_reset_token = [0u8; QUIC_STATELESS_RESET_TOKEN_LEN];
stateless_reset_token.copy_from_slice(&bytes[offset..offset + QUIC_STATELESS_RESET_TOKEN_LEN]);
offset += QUIC_STATELESS_RESET_TOKEN_LEN;
Ok((
QuicNewConnectionIdFrame::new(
sequence_number,
retire_prior_to,
connection_id,
stateless_reset_token,
)
.with_connection_id_length(connection_id_length),
offset,
))
}
fn validate_new_connection_id_len(len: usize) -> Result<()> {
if (1..=QUIC_CONNECTION_ID_MAX_LEN).contains(&len) {
Ok(())
} else {
Err(CrafterError::invalid_field_value(
"quic.frame.new_connection_id.connection_id_length",
"NEW_CONNECTION_ID connection ID length must be 1..=20",
))
}
}
fn decode_retire_connection_id_frame(bytes: &[u8]) -> Result<(QuicRetireConnectionIdFrame, usize)> {
let (frame_type, mut offset) = decode_frame_varint(bytes, 0, "quic.frame.type")?;
if frame_type.value() != 0x19 {
return Err(CrafterError::invalid_field_value(
"quic.frame.retire_connection_id.type",
"RETIRE_CONNECTION_ID frame type must be 0x19",
));
}
let (sequence_number, next) = decode_frame_varint(
bytes,
offset,
"quic.frame.retire_connection_id.sequence_number",
)?;
offset = next;
Ok((QuicRetireConnectionIdFrame::new(sequence_number), offset))
}
fn decode_path_challenge_frame(bytes: &[u8]) -> Result<(QuicPathChallengeFrame, usize)> {
let (data, consumed) = decode_path_validation_data(
bytes,
0x1a,
"quic.frame.path_challenge.type",
"PATH_CHALLENGE frame type must be 0x1a",
"quic.frame.path_challenge.data",
)?;
Ok((QuicPathChallengeFrame::new(data), consumed))
}
fn decode_path_response_frame(bytes: &[u8]) -> Result<(QuicPathResponseFrame, usize)> {
let (data, consumed) = decode_path_validation_data(
bytes,
0x1b,
"quic.frame.path_response.type",
"PATH_RESPONSE frame type must be 0x1b",
"quic.frame.path_response.data",
)?;
Ok((QuicPathResponseFrame::new(data), consumed))
}
fn decode_path_validation_data(
bytes: &[u8],
expected_type: u64,
type_context: &'static str,
type_reason: &'static str,
data_context: &'static str,
) -> Result<([u8; QUIC_PATH_VALIDATION_DATA_LEN], usize)> {
let (frame_type, offset) = decode_frame_varint(bytes, 0, "quic.frame.type")?;
if frame_type.value() != expected_type {
return Err(CrafterError::invalid_field_value(type_context, type_reason));
}
let available = bytes.len().saturating_sub(offset);
if available < QUIC_PATH_VALIDATION_DATA_LEN {
return Err(CrafterError::buffer_too_short(
data_context,
QUIC_PATH_VALIDATION_DATA_LEN,
available,
));
}
let mut data = [0u8; QUIC_PATH_VALIDATION_DATA_LEN];
data.copy_from_slice(&bytes[offset..offset + QUIC_PATH_VALIDATION_DATA_LEN]);
Ok((data, offset + QUIC_PATH_VALIDATION_DATA_LEN))
}
fn decode_connection_close_frame(bytes: &[u8]) -> Result<(QuicConnectionCloseFrame, usize)> {
let (frame_type, mut offset) = decode_frame_varint(bytes, 0, "quic.frame.type")?;
let kind = match frame_type.value() {
0x1c => QuicConnectionCloseKind::Transport,
0x1d => QuicConnectionCloseKind::Application,
_ => {
return Err(CrafterError::invalid_field_value(
"quic.frame.connection_close.type",
"CONNECTION_CLOSE frame type must be 0x1c or 0x1d",
))
}
};
let (error_code, next) =
decode_frame_varint(bytes, offset, "quic.frame.connection_close.error_code")?;
offset = next;
let triggering_frame_type = if kind == QuicConnectionCloseKind::Transport {
let (triggering_frame_type, next) =
decode_frame_varint(bytes, offset, "quic.frame.connection_close.frame_type")?;
offset = next;
Some(triggering_frame_type)
} else {
None
};
let (reason_length, next) =
decode_frame_varint(bytes, offset, "quic.frame.connection_close.reason_length")?;
offset = next;
let reason_len = usize::try_from(reason_length.value()).map_err(|_| {
CrafterError::invalid_field_value(
"quic.frame.connection_close.reason_length",
"length exceeds usize",
)
})?;
let available = bytes.len().saturating_sub(offset);
if available < reason_len {
return Err(CrafterError::buffer_too_short(
"quic.frame.connection_close.reason_phrase",
reason_len,
available,
));
}
let end = offset + reason_len;
let frame = match kind {
QuicConnectionCloseKind::Transport => QuicConnectionCloseFrame::transport(
error_code,
triggering_frame_type.expect("transport close has a decoded frame type"),
&bytes[offset..end],
),
QuicConnectionCloseKind::Application => {
QuicConnectionCloseFrame::application(error_code, &bytes[offset..end])
}
}
.with_reason_length(reason_length);
Ok((frame, end))
}
fn decode_handshake_done_frame(bytes: &[u8]) -> Result<(QuicHandshakeDoneFrame, usize)> {
let (frame_type, offset) = decode_frame_varint(bytes, 0, "quic.frame.type")?;
match frame_type.value() {
0x1e => Ok((QuicHandshakeDoneFrame::new(), offset)),
_ => Err(CrafterError::invalid_field_value(
"quic.frame.handshake_done.type",
"HANDSHAKE_DONE frame type must be 0x1e",
)),
}
}
fn decode_datagram_frame(bytes: &[u8]) -> Result<(QuicDatagramFrame, usize)> {
let (frame_type, mut offset) = decode_frame_varint(bytes, 0, "quic.frame.type")?;
let frame_type_value = frame_type.value();
if !matches!(frame_type_value, 0x30 | 0x31) {
return Err(CrafterError::invalid_field_value(
"quic.frame.datagram.type",
"DATAGRAM frame type must be 0x30 or 0x31",
));
}
let (length, data_len) = if frame_type_value & 0x01 != 0 {
let (length, next) = decode_frame_varint(bytes, offset, "quic.frame.datagram.length")?;
offset = next;
let data_len = usize::try_from(length.value()).map_err(|_| {
CrafterError::invalid_field_value("quic.frame.datagram.length", "length exceeds usize")
})?;
(Some(length), data_len)
} else {
(None, bytes.len().saturating_sub(offset))
};
let available = bytes.len().saturating_sub(offset);
if available < data_len {
return Err(CrafterError::buffer_too_short(
"quic.frame.datagram.data",
data_len,
available,
));
}
let end = offset + data_len;
let mut datagram = QuicDatagramFrame::new(&bytes[offset..end]);
datagram = match length {
Some(length) => datagram.with_length(length),
None => datagram.without_length(),
};
Ok((datagram, end))
}
fn decode_frame_varint(
bytes: &[u8],
offset: usize,
context: &'static str,
) -> Result<(QuicVarInt, usize)> {
match QuicVarInt::decode(&bytes[offset..]) {
Ok((value, consumed)) => Ok((value, offset + consumed)),
Err(CrafterError::BufferTooShort {
required,
available,
..
}) => Err(CrafterError::buffer_too_short(context, required, available)),
Err(error) => Err(error),
}
}
fn classify_frame_kind(bytes: &[u8]) -> QuicFrameKind {
if bytes.is_empty() {
return QuicFrameKind::Empty;
}
let Ok((frame_type, consumed)) = QuicVarInt::decode(bytes) else {
return QuicFrameKind::Truncated;
};
if frame_type.value() == 0x00 {
return if bytes.iter().all(|byte| *byte == 0x00) {
QuicFrameKind::Known(QuicKnownFrameType::Padding)
} else {
QuicFrameKind::Unknown
};
}
if matches!(frame_type.value(), 0x01 | 0x1e) && consumed != bytes.len() {
return QuicFrameKind::Unknown;
}
match known_frame_type(frame_type.value()) {
Some(kind) => QuicFrameKind::Known(kind),
None => QuicFrameKind::Unknown,
}
}
fn known_frame_type(frame_type: u64) -> Option<QuicKnownFrameType> {
match frame_type {
0x00 => Some(QuicKnownFrameType::Padding),
0x01 => Some(QuicKnownFrameType::Ping),
0x02 => Some(QuicKnownFrameType::Ack),
0x03 => Some(QuicKnownFrameType::AckEcn),
0x04 => Some(QuicKnownFrameType::ResetStream),
0x05 => Some(QuicKnownFrameType::StopSending),
0x06 => Some(QuicKnownFrameType::Crypto),
0x07 => Some(QuicKnownFrameType::NewToken),
0x08..=0x0f => Some(QuicKnownFrameType::Stream),
0x10 => Some(QuicKnownFrameType::MaxData),
0x11 => Some(QuicKnownFrameType::MaxStreamData),
0x12 | 0x13 => Some(QuicKnownFrameType::MaxStreams),
0x14 => Some(QuicKnownFrameType::DataBlocked),
0x15 => Some(QuicKnownFrameType::StreamDataBlocked),
0x16 | 0x17 => Some(QuicKnownFrameType::StreamsBlocked),
0x18 => Some(QuicKnownFrameType::NewConnectionId),
0x19 => Some(QuicKnownFrameType::RetireConnectionId),
0x1a => Some(QuicKnownFrameType::PathChallenge),
0x1b => Some(QuicKnownFrameType::PathResponse),
0x1c => Some(QuicKnownFrameType::ConnectionCloseTransport),
0x1d => Some(QuicKnownFrameType::ConnectionCloseApplication),
0x1e => Some(QuicKnownFrameType::HandshakeDone),
0x30 => Some(QuicKnownFrameType::Datagram),
0x31 => Some(QuicKnownFrameType::DatagramLen),
_ => None,
}
}
#[cfg(test)]
mod tests {
use crate::protocols::quic::{QuicIntegerTransportParameter, QuicTransportParameter};
use crate::CrafterError;
use super::*;
fn v(value: u64) -> QuicVarInt {
QuicVarInt::new(value).unwrap()
}
#[test]
fn quic_summary_inspection_frame_summary_preserves_unknown_codepoint() {
let frame = QuicFrame::from_bytes([0x40, 0xaf, 0xaa]);
assert_eq!(frame.summary(), "kind=UNKNOWN type=0xaf raw_len=3");
let fields = frame.inspection_fields();
assert!(fields.contains(&("frame_kind", "UNKNOWN".to_string())));
assert!(fields.contains(&("frame_type", "0xaf".to_string())));
assert!(fields.contains(&("frame_type_encoded_len", "2".to_string())));
assert!(fields.contains(&("raw_bytes", "40 af aa".to_string())));
}
#[test]
fn quic_frame_skeleton_empty_sequence_roundtrips() -> crate::Result<()> {
let frames = QuicFrame::decode_sequence([])?;
assert!(frames.is_empty());
assert_eq!(QuicFrame::encode_sequence(frames), Vec::<u8>::new());
Ok(())
}
#[test]
fn quic_frame_skeleton_unknown_frame_roundtrips() -> crate::Result<()> {
let bytes = [0x40, 0xaf, 0xaa];
let frames = QuicFrame::decode_sequence(bytes)?;
assert_eq!(frames.len(), 1);
let frame = &frames[0];
assert_eq!(frame.kind(), QuicFrameKind::Unknown);
assert_eq!(frame.frame_type_value(), Some(0xaf));
assert_eq!(frame.frame_type_encoded_len(), Some(2));
assert_eq!(frame.encoded_len(), bytes.len());
assert_eq!(frame.encode_to_vec(), bytes);
assert_eq!(QuicFrame::encode_sequence(frames), bytes);
Ok(())
}
#[test]
fn quic_frame_unknown_preservation_keeps_indeterminate_tail_at_packet_boundary(
) -> crate::Result<()> {
let bytes = [0x40, 0xaf, 0xde, 0xad, 0x01];
let frames = QuicFrame::decode_sequence(bytes)?;
assert_eq!(frames.len(), 1);
let frame = &frames[0];
assert_eq!(frame.kind(), QuicFrameKind::Unknown);
let unknown = frame.unknown_frame()?.unwrap();
assert_eq!(unknown.frame_type_value(), 0xaf);
assert_eq!(unknown.raw_following_bytes(), &[0xde, 0xad, 0x01]);
assert_eq!(unknown.summary(), "kind=UNKNOWN type=0xaf following_len=3");
assert_eq!(frame.as_bytes(), &bytes);
assert_eq!(QuicFrame::encode_sequence(frames), bytes);
Ok(())
}
#[test]
fn quic_frame_unknown_preservation_builds_caller_bounded_unknown_frame() -> crate::Result<()> {
let unknown = QuicUnknownFrame::new(v(0x3e75), [0xaa, 0xbb]);
let frame = QuicFrame::from_unknown_frame(unknown.clone())?;
assert_eq!(unknown.encode_to_vec()?, [0x7e, 0x75, 0xaa, 0xbb]);
assert_eq!(frame.kind(), QuicFrameKind::Unknown);
assert_eq!(frame.frame_type_value(), Some(0x3e75));
assert_eq!(frame.unknown_frame()?.unwrap(), unknown);
assert!(frame
.inspection_fields()
.contains(&("unknown_following_bytes", "aa bb".to_string())));
Ok(())
}
#[test]
fn quic_frame_unknown_preservation_truncated_type_reports_structured_error() {
assert_eq!(
QuicUnknownFrame::decode([0x40]).unwrap_err(),
CrafterError::buffer_too_short("quic.frame.unknown.type", 2, 1)
);
}
#[test]
fn quic_frame_skeleton_truncated_type_reports_structured_error() {
assert_eq!(
QuicFrame::decode_sequence([0x40]).unwrap_err(),
CrafterError::buffer_too_short("quic.varint", 2, 1)
);
let frame = QuicFrame::from_bytes([0x40]);
assert_eq!(frame.kind(), QuicFrameKind::Truncated);
assert_eq!(frame.summary(), "kind=TRUNCATED type=<truncated> raw_len=1");
}
#[test]
fn quic_frame_sequence_decode_splits_ordered_cleartext_payload_until_end() -> crate::Result<()>
{
let bytes = [0x00, 0x00, 0x01, 0x06, 0x00, 0x02, 0xaa, 0xbb, 0x1e];
let frames = QuicFrame::decode_sequence(bytes)?;
assert_eq!(frames.len(), 4);
assert_eq!(frames[0].padding_len(), Some(2));
assert!(frames[1].is_ping());
assert_eq!(frames[2].crypto_frame()?.unwrap().data(), &[0xaa, 0xbb]);
assert!(frames[3].handshake_done_frame()?.is_some());
assert_eq!(QuicFrame::encode_sequence(frames), bytes);
Ok(())
}
#[test]
fn quic_frame_sequence_decode_preserves_unknown_tail_without_guessing_boundary(
) -> crate::Result<()> {
let bytes = [0x01, 0x40, 0xaf, 0xde, 0xad, 0x1e];
let frames = QuicFrame::decode_sequence(bytes)?;
assert_eq!(frames.len(), 2);
assert!(frames[0].is_ping());
let unknown = frames[1].unknown_frame()?.unwrap();
assert_eq!(unknown.frame_type_value(), 0xaf);
assert_eq!(unknown.raw_following_bytes(), &[0xde, 0xad, 0x1e]);
assert_eq!(QuicFrame::encode_sequence(frames), bytes);
Ok(())
}
#[test]
fn quic_frame_sequence_decode_truncated_known_frame_reports_structured_error() {
assert_eq!(
QuicFrame::decode_sequence([0x01, 0x06, 0x00, 0x03, 0xaa]).unwrap_err(),
CrafterError::buffer_too_short("quic.frame.crypto.data", 3, 1)
);
}
#[test]
fn quic_frame_sequence_decode_keeps_quic_payload_raw_unless_called_explicitly(
) -> crate::Result<()> {
let payload = [0x01, 0x06, 0x00, 0x01, 0xaa];
let quic = crate::protocols::quic::Quic::from_bytes(payload);
assert_eq!(quic.payload_bytes(), payload);
assert_eq!(quic.frame_count(), 0);
let frames = QuicFrame::decode_sequence(quic.payload_bytes())?;
assert_eq!(frames.len(), 2);
assert!(frames[0].is_ping());
assert_eq!(frames[1].crypto_frame()?.unwrap().data(), &[0xaa]);
Ok(())
}
#[test]
fn quic_frame_padding_ping_sequence_roundtrips() -> crate::Result<()> {
let bytes = [0x00, 0x00, 0x00, 0x01, 0x00];
let frames = QuicFrame::decode_sequence(bytes)?;
assert_eq!(frames.len(), 3);
assert_eq!(
frames[0].kind(),
QuicFrameKind::Known(QuicKnownFrameType::Padding)
);
assert_eq!(frames[0].padding_len(), Some(3));
assert!(frames[1].is_ping());
assert_eq!(frames[2].padding_len(), Some(1));
assert_eq!(QuicFrame::encode_sequence(frames), bytes);
Ok(())
}
#[test]
fn quic_frame_padding_ping_builders_emit_selected_bytes() {
let frames = [QuicFrame::padding(4), QuicFrame::ping()];
assert_eq!(
QuicFrame::encode_sequence(frames),
[0x00, 0x00, 0x00, 0x00, 0x01]
);
}
#[test]
fn quic_frame_sequence_encode_preserves_order_and_reports_encoded_len() -> crate::Result<()> {
let frames = vec![
QuicFrame::ping(),
QuicFrame::crypto(v(0), [0xaa, 0xbb])?,
QuicFrame::unknown(v(0xaf), [0xcc])?,
];
assert_eq!(QuicFrame::encoded_sequence_len(frames.iter()), 9);
assert_eq!(
QuicFrame::encode_sequence(frames),
[0x01, 0x06, 0x00, 0x02, 0xaa, 0xbb, 0x40, 0xaf, 0xcc]
);
Ok(())
}
#[test]
fn quic_frame_padding_ping_summary_reports_names() {
let padding = QuicFrame::padding(2);
let ping = QuicFrame::ping();
assert_eq!(padding.summary(), "kind=PADDING padding_len=2");
assert_eq!(ping.summary(), "kind=PING type=0x1 raw_len=1");
assert!(padding
.inspection_fields()
.contains(&("padding_len", "2".to_string())));
}
#[test]
fn quic_frame_ack_decodes_ranges_and_continues_sequence() -> crate::Result<()> {
let bytes = [0x02, 10, 1, 1, 2, 0, 3, 0x01];
let frames = QuicFrame::decode_sequence(bytes)?;
assert_eq!(frames.len(), 2);
assert_eq!(
frames[0].kind(),
QuicFrameKind::Known(QuicKnownFrameType::Ack)
);
let ack = frames[0].ack_frame()?.unwrap();
assert!(!ack.is_ecn());
assert_eq!(ack.largest_acknowledged().value(), 10);
assert_eq!(ack.ack_delay().value(), 1);
assert_eq!(ack.ack_range_count()?.value(), 1);
assert_eq!(ack.first_ack_range().value(), 2);
assert_eq!(ack.ack_ranges(), &[QuicAckRange::from_values(0, 3)?]);
assert!(frames[1].is_ping());
assert_eq!(QuicFrame::encode_sequence(frames), bytes);
Ok(())
}
#[test]
fn quic_frame_ack_ecn_serializes_counts() -> crate::Result<()> {
let frame = QuicFrame::ack_ecn(
v(10),
v(0),
v(2),
[QuicAckRange::from_values(1, 4)?],
QuicAckEcnCounts::from_values(5, 6, 7)?,
)?;
assert_eq!(frame.as_bytes(), &[0x03, 10, 0, 1, 2, 1, 4, 5, 6, 7]);
let ack = frame.ack_frame()?.unwrap();
assert!(ack.is_ecn());
assert_eq!(ack.ecn_counts().unwrap().ect0_count().value(), 5);
assert_eq!(ack.ecn_counts().unwrap().ect1_count().value(), 6);
assert_eq!(ack.ecn_counts().unwrap().ce_count().value(), 7);
Ok(())
}
#[test]
fn quic_frame_ack_malformed_range_varint_reports_structured_error() {
assert_eq!(
QuicFrame::decode_sequence([0x02, 10, 1, 1, 2, 0]).unwrap_err(),
CrafterError::buffer_too_short("quic.frame.ack.range.length", 1, 0)
);
}
#[test]
fn quic_frame_ack_summary_reports_ack_fields() -> crate::Result<()> {
let frame = QuicFrame::ack(v(9), v(3), v(2), [QuicAckRange::from_values(0, 1)?])?;
assert_eq!(
frame.summary(),
"kind=ACK largest_acknowledged=9 ack_delay=3 first_ack_range=2 ranges=1"
);
let fields = frame.inspection_fields();
assert!(fields.contains(&("ack_largest_acknowledged", "9".to_string())));
assert!(fields.contains(&("ack_range", "gap=0 length=1".to_string())));
Ok(())
}
#[test]
fn quic_frame_reset_stream_decodes_and_continues_sequence() -> crate::Result<()> {
let bytes = [0x04, 4, 0x12, 9, 0x01];
let frames = QuicFrame::decode_sequence(bytes)?;
assert_eq!(frames.len(), 2);
assert_eq!(
frames[0].kind(),
QuicFrameKind::Known(QuicKnownFrameType::ResetStream)
);
let reset_stream = frames[0].reset_stream_frame()?.unwrap();
assert_eq!(reset_stream.stream_id().value(), 4);
assert_eq!(reset_stream.application_error_code().value(), 0x12);
assert_eq!(reset_stream.final_size().value(), 9);
assert!(frames[1].is_ping());
assert_eq!(QuicFrame::encode_sequence(frames), bytes);
Ok(())
}
#[test]
fn quic_frame_reset_stream_serializes_unknown_error_codes() -> crate::Result<()> {
let reset_stream = QuicResetStreamFrame::from_values(1, 0x1234, 63)?;
let frame = QuicFrame::from_reset_stream_frame(reset_stream)?;
assert_eq!(frame.as_bytes(), &[0x04, 0x01, 0x52, 0x34, 0x3f]);
assert_eq!(
frame.summary(),
"kind=RESET_STREAM stream_id=1 application_error_code=4660 final_size=63"
);
Ok(())
}
#[test]
fn quic_frame_reset_stream_malformed_varint_reports_structured_error() {
assert_eq!(
QuicFrame::decode_sequence([0x04, 1, 2, 0x40]).unwrap_err(),
CrafterError::buffer_too_short("quic.frame.reset_stream.final_size", 2, 1)
);
}
#[test]
fn quic_frame_stop_sending_decodes_and_continues_sequence() -> crate::Result<()> {
let bytes = [0x05, 4, 0x12, 0x01];
let frames = QuicFrame::decode_sequence(bytes)?;
assert_eq!(frames.len(), 2);
assert_eq!(
frames[0].kind(),
QuicFrameKind::Known(QuicKnownFrameType::StopSending)
);
let stop_sending = frames[0].stop_sending_frame()?.unwrap();
assert_eq!(stop_sending.stream_id().value(), 4);
assert_eq!(stop_sending.application_error_code().value(), 0x12);
assert!(frames[1].is_ping());
assert_eq!(QuicFrame::encode_sequence(frames), bytes);
Ok(())
}
#[test]
fn quic_frame_stop_sending_serializes_unknown_error_codes() -> crate::Result<()> {
let stop_sending = QuicStopSendingFrame::from_values(1, 0x1234)?;
let frame = QuicFrame::from_stop_sending_frame(stop_sending)?;
assert_eq!(frame.as_bytes(), &[0x05, 0x01, 0x52, 0x34]);
assert_eq!(
frame.summary(),
"kind=STOP_SENDING stream_id=1 application_error_code=4660"
);
Ok(())
}
#[test]
fn quic_frame_stop_sending_malformed_varint_reports_structured_error() {
assert_eq!(
QuicFrame::decode_sequence([0x05, 1, 0x40]).unwrap_err(),
CrafterError::buffer_too_short("quic.frame.stop_sending.application_error_code", 2, 1)
);
}
#[test]
fn quic_frame_crypto_decodes_data_and_continues_sequence() -> crate::Result<()> {
let bytes = [0x06, 2, 3, 0xaa, 0xbb, 0xcc, 0x01];
let frames = QuicFrame::decode_sequence(bytes)?;
assert_eq!(frames.len(), 2);
assert_eq!(
frames[0].kind(),
QuicFrameKind::Known(QuicKnownFrameType::Crypto)
);
let crypto = frames[0].crypto_frame()?.unwrap();
assert_eq!(crypto.offset().value(), 2);
assert_eq!(crypto.length()?.value(), 3);
assert_eq!(crypto.data(), &[0xaa, 0xbb, 0xcc]);
assert!(frames[1].is_ping());
assert_eq!(QuicFrame::encode_sequence(frames), bytes);
Ok(())
}
#[test]
fn quic_frame_crypto_auto_fills_length() -> crate::Result<()> {
let frame = QuicFrame::crypto(v(0), [0x16, 0x03, 0x03])?;
assert_eq!(frame.as_bytes(), &[0x06, 0x00, 0x03, 0x16, 0x03, 0x03]);
assert_eq!(frame.summary(), "kind=CRYPTO offset=0 length=3 data_len=3");
Ok(())
}
#[test]
fn quic_frame_crypto_preserves_explicit_malformed_length() -> crate::Result<()> {
let crypto = QuicCryptoFrame::new(v(0), [0xaa]).with_length(v(3));
let frame = QuicFrame::from_crypto_frame(crypto)?;
assert_eq!(frame.as_bytes(), &[0x06, 0x00, 0x03, 0xaa]);
assert_eq!(
frame.crypto_frame().unwrap_err(),
CrafterError::buffer_too_short("quic.frame.crypto.data", 3, 1)
);
Ok(())
}
#[test]
fn quic_frame_crypto_truncated_data_reports_structured_error() {
assert_eq!(
QuicFrame::decode_sequence([0x06, 0, 3, 0xaa]).unwrap_err(),
CrafterError::buffer_too_short("quic.frame.crypto.data", 3, 1)
);
}
#[test]
fn quic_frame_new_token_decodes_token_and_continues_sequence() -> crate::Result<()> {
let bytes = [0x07, 3, 0xde, 0xad, 0xbe, 0x01];
let frames = QuicFrame::decode_sequence(bytes)?;
assert_eq!(frames.len(), 2);
assert_eq!(
frames[0].kind(),
QuicFrameKind::Known(QuicKnownFrameType::NewToken)
);
let new_token = frames[0].new_token_frame()?.unwrap();
assert_eq!(new_token.token_length()?.value(), 3);
assert_eq!(new_token.token(), &[0xde, 0xad, 0xbe]);
assert!(frames[1].is_ping());
assert_eq!(QuicFrame::encode_sequence(frames), bytes);
Ok(())
}
#[test]
fn quic_frame_new_token_builder_auto_fills_length() -> crate::Result<()> {
let frame = QuicFrame::new_token([0xde, 0xad])?;
assert_eq!(frame.as_bytes(), &[0x07, 0x02, 0xde, 0xad]);
assert_eq!(frame.summary(), "kind=NEW_TOKEN token_length=2 token_len=2");
Ok(())
}
#[test]
fn quic_frame_new_token_empty_token_is_byte_complete() -> crate::Result<()> {
let frame = QuicFrame::new_token([])?;
let decoded = frame.new_token_frame()?.unwrap();
assert_eq!(frame.as_bytes(), &[0x07, 0x00]);
assert_eq!(decoded.token(), &[]);
assert_eq!(decoded.token_length()?.value(), 0);
Ok(())
}
#[test]
fn quic_frame_new_token_preserves_explicit_malformed_length() -> crate::Result<()> {
let new_token = QuicNewTokenFrame::new([0xaa]).with_token_length(v(3));
let frame = QuicFrame::from_new_token_frame(new_token)?;
assert_eq!(frame.as_bytes(), &[0x07, 0x03, 0xaa]);
assert_eq!(
frame.new_token_frame().unwrap_err(),
CrafterError::buffer_too_short("quic.frame.new_token.token", 3, 1)
);
Ok(())
}
#[test]
fn quic_frame_new_token_truncated_token_reports_structured_error() {
assert_eq!(
QuicFrame::decode_sequence([0x07, 3, 0xaa]).unwrap_err(),
CrafterError::buffer_too_short("quic.frame.new_token.token", 3, 1)
);
}
#[test]
fn quic_frame_stream_decodes_offset_length_fin_and_continues_sequence() -> crate::Result<()> {
let bytes = [0x0f, 4, 2, 3, 0xaa, 0xbb, 0xcc, 0x01];
let frames = QuicFrame::decode_sequence(bytes)?;
assert_eq!(frames.len(), 2);
assert_eq!(
frames[0].kind(),
QuicFrameKind::Known(QuicKnownFrameType::Stream)
);
let stream = frames[0].stream_frame()?.unwrap();
assert_eq!(stream.stream_id().value(), 4);
assert_eq!(stream.offset().unwrap().value(), 2);
assert_eq!(stream.length()?.unwrap().value(), 3);
assert!(stream.fin());
assert_eq!(stream.data(), &[0xaa, 0xbb, 0xcc]);
assert!(frames[1].is_ping());
assert_eq!(QuicFrame::encode_sequence(frames), bytes);
Ok(())
}
#[test]
fn quic_frame_stream_builder_auto_fills_length() -> crate::Result<()> {
let stream = QuicStreamFrame::new(v(1), [0xaa, 0xbb])
.with_offset(v(10))
.with_fin(true);
let frame = QuicFrame::from_stream_frame(stream)?;
assert_eq!(frame.as_bytes(), &[0x0f, 0x01, 0x0a, 0x02, 0xaa, 0xbb]);
assert_eq!(
frame.summary(),
"kind=STREAM stream_id=1 offset=10 length=2 fin=true data_len=2"
);
Ok(())
}
#[test]
fn quic_frame_stream_without_length_consumes_packet_remainder() -> crate::Result<()> {
let bytes = [0x08, 1, 0xaa, 0x01];
let frames = QuicFrame::decode_sequence(bytes)?;
assert_eq!(frames.len(), 1);
let stream = frames[0].stream_frame()?.unwrap();
assert!(!stream.has_length());
assert_eq!(stream.length()?, None);
assert_eq!(stream.data(), &[0xaa, 0x01]);
assert_eq!(QuicFrame::encode_sequence(frames), bytes);
Ok(())
}
#[test]
fn quic_frame_stream_preserves_explicit_malformed_length() -> crate::Result<()> {
let stream = QuicStreamFrame::new(v(1), [0xaa]).with_length(v(3));
let frame = QuicFrame::from_stream_frame(stream)?;
assert_eq!(frame.as_bytes(), &[0x0a, 0x01, 0x03, 0xaa]);
assert_eq!(
frame.stream_frame().unwrap_err(),
CrafterError::buffer_too_short("quic.frame.stream.data", 3, 1)
);
Ok(())
}
#[test]
fn quic_frame_stream_truncated_data_reports_structured_error() {
assert_eq!(
QuicFrame::decode_sequence([0x0a, 1, 3, 0xaa]).unwrap_err(),
CrafterError::buffer_too_short("quic.frame.stream.data", 3, 1)
);
}
#[test]
fn quic_frame_max_data_decodes_and_continues_sequence() -> crate::Result<()> {
let bytes = [0x10, 0x44, 0x00, 0x01];
let frames = QuicFrame::decode_sequence(bytes)?;
assert_eq!(frames.len(), 2);
assert_eq!(
frames[0].kind(),
QuicFrameKind::Known(QuicKnownFrameType::MaxData)
);
let max_data = frames[0].max_data_frame()?.unwrap();
assert_eq!(max_data.maximum_data().value(), 1024);
assert!(frames[1].is_ping());
assert_eq!(QuicFrame::encode_sequence(frames), bytes);
Ok(())
}
#[test]
fn quic_frame_max_data_serializes_and_summarizes() -> crate::Result<()> {
let frame = QuicFrame::max_data(v(63))?;
assert_eq!(frame.as_bytes(), &[0x10, 0x3f]);
assert_eq!(frame.summary(), "kind=MAX_DATA maximum_data=63");
assert!(frame
.inspection_fields()
.contains(&("max_data", "63".to_string())));
Ok(())
}
#[test]
fn quic_frame_max_data_malformed_varint_reports_structured_error() {
assert_eq!(
QuicFrame::decode_sequence([0x10, 0x40]).unwrap_err(),
CrafterError::buffer_too_short("quic.frame.max_data.maximum_data", 2, 1)
);
}
#[test]
fn quic_frame_max_stream_data_decodes_and_continues_sequence() -> crate::Result<()> {
let bytes = [0x11, 0x04, 0x44, 0x00, 0x01];
let frames = QuicFrame::decode_sequence(bytes)?;
assert_eq!(frames.len(), 2);
assert_eq!(
frames[0].kind(),
QuicFrameKind::Known(QuicKnownFrameType::MaxStreamData)
);
let max_stream_data = frames[0].max_stream_data_frame()?.unwrap();
assert_eq!(max_stream_data.stream_id().value(), 4);
assert_eq!(max_stream_data.maximum_stream_data().value(), 1024);
assert!(frames[1].is_ping());
assert_eq!(QuicFrame::encode_sequence(frames), bytes);
Ok(())
}
#[test]
fn quic_frame_max_stream_data_serializes_and_summarizes() -> crate::Result<()> {
let frame = QuicFrame::max_stream_data(v(1), v(63))?;
assert_eq!(frame.as_bytes(), &[0x11, 0x01, 0x3f]);
assert_eq!(
frame.summary(),
"kind=MAX_STREAM_DATA stream_id=1 maximum_stream_data=63"
);
assert!(frame
.inspection_fields()
.contains(&("max_stream_data", "63".to_string())));
Ok(())
}
#[test]
fn quic_frame_max_stream_data_malformed_varint_reports_structured_error() {
assert_eq!(
QuicFrame::decode_sequence([0x11, 1, 0x40]).unwrap_err(),
CrafterError::buffer_too_short("quic.frame.max_stream_data.maximum_stream_data", 2, 1)
);
}
#[test]
fn quic_frame_max_streams_decodes_bidirectional_and_continues_sequence() -> crate::Result<()> {
let bytes = [0x12, 0x44, 0x00, 0x01];
let frames = QuicFrame::decode_sequence(bytes)?;
assert_eq!(frames.len(), 2);
assert_eq!(
frames[0].kind(),
QuicFrameKind::Known(QuicKnownFrameType::MaxStreams)
);
let max_streams = frames[0].max_streams_frame()?.unwrap();
assert_eq!(max_streams.direction(), QuicStreamDirection::Bidirectional);
assert_eq!(max_streams.maximum_streams().value(), 1024);
assert!(frames[1].is_ping());
assert_eq!(QuicFrame::encode_sequence(frames), bytes);
Ok(())
}
#[test]
fn quic_frame_max_streams_decodes_unidirectional() -> crate::Result<()> {
let frame = QuicMaxStreamsFrame::decode([0x13, 0x3f])?;
assert_eq!(frame.direction(), QuicStreamDirection::Unidirectional);
assert_eq!(frame.maximum_streams().value(), 63);
assert_eq!(frame.encode_to_vec()?, [0x13, 0x3f]);
Ok(())
}
#[test]
fn quic_frame_max_streams_serializes_and_summarizes() -> crate::Result<()> {
let frame = QuicFrame::max_streams_unidirectional(v(63))?;
assert_eq!(frame.as_bytes(), &[0x13, 0x3f]);
assert_eq!(
frame.summary(),
"kind=MAX_STREAMS direction=unidirectional maximum_streams=63"
);
assert!(frame
.inspection_fields()
.contains(&("max_streams_direction", "unidirectional".to_string())));
assert_eq!(
QuicFrame::max_streams_bidirectional(v(1))?.as_bytes(),
&[0x12, 0x01]
);
Ok(())
}
#[test]
fn quic_frame_max_streams_malformed_varint_reports_structured_error() {
assert_eq!(
QuicFrame::decode_sequence([0x12, 0x40]).unwrap_err(),
CrafterError::buffer_too_short("quic.frame.max_streams.maximum_streams", 2, 1)
);
}
#[test]
fn quic_frame_data_blocked_decodes_and_continues_sequence() -> crate::Result<()> {
let bytes = [0x14, 0x44, 0x00, 0x01];
let frames = QuicFrame::decode_sequence(bytes)?;
assert_eq!(frames.len(), 2);
assert_eq!(
frames[0].kind(),
QuicFrameKind::Known(QuicKnownFrameType::DataBlocked)
);
let data_blocked = frames[0].data_blocked_frame()?.unwrap();
assert_eq!(data_blocked.data_limit().value(), 1024);
assert!(frames[1].is_ping());
assert_eq!(QuicFrame::encode_sequence(frames), bytes);
Ok(())
}
#[test]
fn quic_frame_data_blocked_serializes_and_summarizes() -> crate::Result<()> {
let frame = QuicFrame::data_blocked(v(63))?;
assert_eq!(frame.as_bytes(), &[0x14, 0x3f]);
assert_eq!(frame.summary(), "kind=DATA_BLOCKED data_limit=63");
assert!(frame
.inspection_fields()
.contains(&("data_blocked_limit", "63".to_string())));
Ok(())
}
#[test]
fn quic_frame_data_blocked_malformed_varint_reports_structured_error() {
assert_eq!(
QuicFrame::decode_sequence([0x14, 0x40]).unwrap_err(),
CrafterError::buffer_too_short("quic.frame.data_blocked.data_limit", 2, 1)
);
}
#[test]
fn quic_frame_stream_data_blocked_decodes_and_continues_sequence() -> crate::Result<()> {
let bytes = [0x15, 0x04, 0x44, 0x00, 0x01];
let frames = QuicFrame::decode_sequence(bytes)?;
assert_eq!(frames.len(), 2);
assert_eq!(
frames[0].kind(),
QuicFrameKind::Known(QuicKnownFrameType::StreamDataBlocked)
);
let stream_data_blocked = frames[0].stream_data_blocked_frame()?.unwrap();
assert_eq!(stream_data_blocked.stream_id().value(), 4);
assert_eq!(stream_data_blocked.maximum_stream_data().value(), 1024);
assert!(frames[1].is_ping());
assert_eq!(QuicFrame::encode_sequence(frames), bytes);
Ok(())
}
#[test]
fn quic_frame_stream_data_blocked_serializes_and_summarizes() -> crate::Result<()> {
let frame = QuicFrame::stream_data_blocked(v(1), v(63))?;
assert_eq!(frame.as_bytes(), &[0x15, 0x01, 0x3f]);
assert_eq!(
frame.summary(),
"kind=STREAM_DATA_BLOCKED stream_id=1 maximum_stream_data=63"
);
assert!(frame
.inspection_fields()
.contains(&("stream_data_blocked_maximum_stream_data", "63".to_string())));
Ok(())
}
#[test]
fn quic_frame_stream_data_blocked_malformed_varint_reports_structured_error() {
assert_eq!(
QuicFrame::decode_sequence([0x15, 1, 0x40]).unwrap_err(),
CrafterError::buffer_too_short(
"quic.frame.stream_data_blocked.maximum_stream_data",
2,
1
)
);
}
#[test]
fn quic_frame_streams_blocked_decodes_bidirectional_and_continues_sequence() -> crate::Result<()>
{
let bytes = [0x16, 0x44, 0x00, 0x01];
let frames = QuicFrame::decode_sequence(bytes)?;
assert_eq!(frames.len(), 2);
assert_eq!(
frames[0].kind(),
QuicFrameKind::Known(QuicKnownFrameType::StreamsBlocked)
);
let streams_blocked = frames[0].streams_blocked_frame()?.unwrap();
assert_eq!(
streams_blocked.direction(),
QuicStreamDirection::Bidirectional
);
assert_eq!(streams_blocked.maximum_streams().value(), 1024);
assert!(frames[1].is_ping());
assert_eq!(QuicFrame::encode_sequence(frames), bytes);
Ok(())
}
#[test]
fn quic_frame_streams_blocked_decodes_unidirectional() -> crate::Result<()> {
let frame = QuicStreamsBlockedFrame::decode([0x17, 0x3f])?;
assert_eq!(frame.direction(), QuicStreamDirection::Unidirectional);
assert_eq!(frame.maximum_streams().value(), 63);
assert_eq!(frame.encode_to_vec()?, [0x17, 0x3f]);
Ok(())
}
#[test]
fn quic_frame_streams_blocked_serializes_and_summarizes() -> crate::Result<()> {
let frame = QuicFrame::streams_blocked_unidirectional(v(63))?;
assert_eq!(frame.as_bytes(), &[0x17, 0x3f]);
assert_eq!(
frame.summary(),
"kind=STREAMS_BLOCKED direction=unidirectional maximum_streams=63"
);
assert!(frame
.inspection_fields()
.contains(&("streams_blocked_direction", "unidirectional".to_string())));
assert_eq!(
QuicFrame::streams_blocked_bidirectional(v(1))?.as_bytes(),
&[0x16, 0x01]
);
Ok(())
}
#[test]
fn quic_frame_streams_blocked_malformed_varint_reports_structured_error() {
assert_eq!(
QuicFrame::decode_sequence([0x17, 0x40]).unwrap_err(),
CrafterError::buffer_too_short("quic.frame.streams_blocked.maximum_streams", 2, 1)
);
}
#[test]
fn quic_frame_new_connection_id_decodes_and_continues_sequence() -> crate::Result<()> {
let token = [
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
0x0e, 0x0f,
];
let mut bytes = vec![0x18, 0x01, 0x00, 0x04, 0x83, 0x94, 0xc8, 0xf0];
bytes.extend_from_slice(&token);
bytes.push(0x01);
let frames = QuicFrame::decode_sequence(&bytes)?;
assert_eq!(frames.len(), 2);
assert_eq!(
frames[0].kind(),
QuicFrameKind::Known(QuicKnownFrameType::NewConnectionId)
);
let new_connection_id = frames[0].new_connection_id_frame()?.unwrap();
assert_eq!(new_connection_id.sequence_number().value(), 1);
assert_eq!(new_connection_id.retire_prior_to().value(), 0);
assert_eq!(new_connection_id.connection_id_length()?, 4);
assert_eq!(
new_connection_id.connection_id().as_bytes(),
&[0x83, 0x94, 0xc8, 0xf0]
);
assert_eq!(new_connection_id.stateless_reset_token(), &token);
assert!(frames[1].is_ping());
assert_eq!(QuicFrame::encode_sequence(frames), bytes);
Ok(())
}
#[test]
fn quic_frame_new_connection_id_serializes_and_summarizes() -> crate::Result<()> {
let token = [0xab; QUIC_STATELESS_RESET_TOKEN_LEN];
let frame = QuicFrame::new_connection_id(
v(3),
v(1),
QuicConnectionId::from_bytes([0xaa, 0xbb]),
token,
)?;
let mut expected = vec![0x18, 0x03, 0x01, 0x02, 0xaa, 0xbb];
expected.extend_from_slice(&token);
assert_eq!(frame.as_bytes(), expected);
assert_eq!(
frame.summary(),
"kind=NEW_CONNECTION_ID sequence_number=3 retire_prior_to=1 connection_id_len=2 connection_id=aabb"
);
assert!(frame.inspection_fields().contains(&(
"new_connection_id_stateless_reset_token",
"ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab".to_string()
)));
Ok(())
}
#[test]
fn quic_frame_new_connection_id_preserves_explicit_malformed_length() -> crate::Result<()> {
let token = [0; QUIC_STATELESS_RESET_TOKEN_LEN];
let frame = QuicNewConnectionIdFrame::new(
v(1),
v(0),
QuicConnectionId::from_bytes([0xaa, 0xbb, 0xcc]),
token,
)
.with_connection_id_length(1);
let encoded = frame.encode_to_vec()?;
assert_eq!(frame.connection_id_length_override(), Some(1));
assert_eq!(encoded[3], 1);
assert_eq!(
encoded.len(),
1 + 1 + 1 + 1 + 3 + QUIC_STATELESS_RESET_TOKEN_LEN
);
Ok(())
}
#[test]
fn quic_frame_new_connection_id_invalid_connection_id_lengths_report_structured_errors() {
assert_eq!(
QuicFrame::decode_sequence([0x18, 0x01, 0x00, 0x00]).unwrap_err(),
CrafterError::invalid_field_value(
"quic.frame.new_connection_id.connection_id_length",
"NEW_CONNECTION_ID connection ID length must be 1..=20"
)
);
assert_eq!(
QuicFrame::decode_sequence([0x18, 0x01, 0x00, 0x15]).unwrap_err(),
CrafterError::invalid_field_value(
"quic.frame.new_connection_id.connection_id_length",
"NEW_CONNECTION_ID connection ID length must be 1..=20"
)
);
}
#[test]
fn quic_frame_new_connection_id_truncated_connection_id_reports_structured_error() {
assert_eq!(
QuicFrame::decode_sequence([0x18, 0x01, 0x00, 0x04, 0xaa, 0xbb]).unwrap_err(),
CrafterError::buffer_too_short("quic.frame.new_connection_id.connection_id", 4, 2)
);
}
#[test]
fn quic_frame_new_connection_id_truncated_reset_token_reports_structured_error() {
let mut bytes = vec![0x18, 0x01, 0x00, 0x02, 0xaa, 0xbb];
bytes.extend_from_slice(&[0xcc; QUIC_STATELESS_RESET_TOKEN_LEN - 1]);
assert_eq!(
QuicFrame::decode_sequence(bytes).unwrap_err(),
CrafterError::buffer_too_short(
"quic.frame.new_connection_id.stateless_reset_token",
QUIC_STATELESS_RESET_TOKEN_LEN,
QUIC_STATELESS_RESET_TOKEN_LEN - 1
)
);
}
#[test]
fn quic_frame_retire_connection_id_decodes_and_continues_sequence() -> crate::Result<()> {
let bytes = [0x19, 0x44, 0x00, 0x01];
let frames = QuicFrame::decode_sequence(bytes)?;
assert_eq!(frames.len(), 2);
assert_eq!(
frames[0].kind(),
QuicFrameKind::Known(QuicKnownFrameType::RetireConnectionId)
);
let retire_connection_id = frames[0].retire_connection_id_frame()?.unwrap();
assert_eq!(retire_connection_id.sequence_number().value(), 1024);
assert!(frames[1].is_ping());
assert_eq!(QuicFrame::encode_sequence(frames), bytes);
Ok(())
}
#[test]
fn quic_frame_retire_connection_id_serializes_and_summarizes() -> crate::Result<()> {
let frame = QuicFrame::retire_connection_id(v(63))?;
assert_eq!(frame.as_bytes(), &[0x19, 0x3f]);
assert_eq!(
frame.summary(),
"kind=RETIRE_CONNECTION_ID sequence_number=63"
);
assert!(frame
.inspection_fields()
.contains(&("retire_connection_id_sequence_number", "63".to_string())));
Ok(())
}
#[test]
fn quic_frame_retire_connection_id_malformed_varint_reports_structured_error() {
assert_eq!(
QuicFrame::decode_sequence([0x19, 0x40]).unwrap_err(),
CrafterError::buffer_too_short("quic.frame.retire_connection_id.sequence_number", 2, 1)
);
}
#[test]
fn quic_frame_path_challenge_response_decodes_and_continues_sequence() -> crate::Result<()> {
let challenge = [0, 1, 2, 3, 4, 5, 6, 7];
let response = [8, 9, 10, 11, 12, 13, 14, 15];
let mut bytes = vec![0x1a];
bytes.extend_from_slice(&challenge);
bytes.push(0x1b);
bytes.extend_from_slice(&response);
bytes.push(0x01);
let frames = QuicFrame::decode_sequence(&bytes)?;
assert_eq!(frames.len(), 3);
assert_eq!(
frames[0].kind(),
QuicFrameKind::Known(QuicKnownFrameType::PathChallenge)
);
assert_eq!(
frames[0].path_challenge_frame()?.unwrap().data(),
&challenge
);
assert_eq!(
frames[1].kind(),
QuicFrameKind::Known(QuicKnownFrameType::PathResponse)
);
assert_eq!(frames[1].path_response_frame()?.unwrap().data(), &response);
assert!(frames[2].is_ping());
assert_eq!(QuicFrame::encode_sequence(frames), bytes);
Ok(())
}
#[test]
fn quic_frame_path_challenge_response_serializes_and_summarizes() -> crate::Result<()> {
let challenge = QuicFrame::path_challenge([0xaa; QUIC_PATH_VALIDATION_DATA_LEN])?;
let response = QuicFrame::path_response([0xbb; QUIC_PATH_VALIDATION_DATA_LEN])?;
assert_eq!(
challenge.as_bytes(),
&[0x1a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa]
);
assert_eq!(
challenge.summary(),
"kind=PATH_CHALLENGE data=aa aa aa aa aa aa aa aa"
);
assert_eq!(
response.as_bytes(),
&[0x1b, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb]
);
assert!(response
.inspection_fields()
.contains(&("path_response_data", "bb bb bb bb bb bb bb bb".to_string())));
Ok(())
}
#[test]
fn quic_frame_path_challenge_response_truncated_data_reports_structured_error() {
assert_eq!(
QuicFrame::decode_sequence([0x1a, 0, 1, 2, 3, 4, 5, 6]).unwrap_err(),
CrafterError::buffer_too_short("quic.frame.path_challenge.data", 8, 7)
);
assert_eq!(
QuicFrame::decode_sequence([0x1b, 0, 1, 2, 3, 4, 5, 6]).unwrap_err(),
CrafterError::buffer_too_short("quic.frame.path_response.data", 8, 7)
);
}
#[test]
fn quic_frame_connection_close_decodes_transport_application_and_continues_sequence(
) -> crate::Result<()> {
let bytes = [
0x1c, 0x07, 0x08, 0x03, b'b', b'a', b'd', 0x1d, 0x0c, 0x02, b'n', b'o', 0x01,
];
let frames = QuicFrame::decode_sequence(bytes)?;
assert_eq!(frames.len(), 3);
assert_eq!(
frames[0].kind(),
QuicFrameKind::Known(QuicKnownFrameType::ConnectionCloseTransport)
);
let transport = frames[0].connection_close_frame()?.unwrap();
assert_eq!(transport.kind(), QuicConnectionCloseKind::Transport);
assert_eq!(
transport.error_code(),
QUIC_TRANSPORT_ERROR_FRAME_ENCODING_ERROR
);
assert_eq!(transport.triggering_frame_type().unwrap().value(), 0x08);
assert_eq!(transport.reason_phrase_str(), Some("bad"));
assert_eq!(
frames[1].kind(),
QuicFrameKind::Known(QuicKnownFrameType::ConnectionCloseApplication)
);
let application = frames[1].connection_close_frame()?.unwrap();
assert_eq!(application.kind(), QuicConnectionCloseKind::Application);
assert_eq!(
application.error_code(),
QUIC_TRANSPORT_ERROR_APPLICATION_ERROR
);
assert_eq!(application.triggering_frame_type(), None);
assert_eq!(application.reason_phrase(), b"no");
assert!(frames[2].is_ping());
assert_eq!(QuicFrame::encode_sequence(frames), bytes);
Ok(())
}
#[test]
fn quic_frame_connection_close_serializes_unknown_error_codes() -> crate::Result<()> {
let frame = QuicFrame::connection_close_transport(
QuicVarInt::from_u64_unchecked(0x1234),
QuicVarInt::from_u64_unchecked(0xaf),
b"why",
)?;
assert_eq!(
frame.as_bytes(),
&[0x1c, 0x52, 0x34, 0x40, 0xaf, 0x03, b'w', b'h', b'y']
);
assert_eq!(
frame.summary(),
"kind=CONNECTION_CLOSE_TRANSPORT error_code=0x1234 frame_type=0xaf reason_len=3"
);
assert!(frame
.inspection_fields()
.contains(&("connection_close_reason_text", "why".to_string())));
Ok(())
}
#[test]
fn quic_frame_connection_close_preserves_explicit_malformed_reason_length() -> crate::Result<()>
{
let frame =
QuicConnectionCloseFrame::application(QUIC_TRANSPORT_ERROR_APPLICATION_ERROR, b"oops")
.with_reason_length(v(1));
let encoded = frame.encode_to_vec()?;
assert_eq!(frame.reason_length_override(), Some(v(1)));
assert_eq!(encoded, [0x1d, 0x0c, 0x01, b'o', b'o', b'p', b's']);
Ok(())
}
#[test]
fn quic_frame_connection_close_malformed_reason_length_reports_structured_error() {
assert_eq!(
QuicFrame::decode_sequence([0x1d, 0x0c, 0x03, b'n']).unwrap_err(),
CrafterError::buffer_too_short("quic.frame.connection_close.reason_phrase", 3, 1)
);
}
#[test]
fn quic_frame_connection_close_malformed_varint_reports_structured_error() {
assert_eq!(
QuicFrame::decode_sequence([0x1c, 0x07, 0x40]).unwrap_err(),
CrafterError::buffer_too_short("quic.frame.connection_close.frame_type", 2, 1)
);
}
#[test]
fn quic_frame_handshake_done_decodes_without_consuming_following_frames() -> crate::Result<()> {
let bytes = [0x1e, 0x01, 0x1e, 0x00, 0x00];
let frames = QuicFrame::decode_sequence(bytes)?;
assert_eq!(frames.len(), 4);
assert_eq!(
frames[0].kind(),
QuicFrameKind::Known(QuicKnownFrameType::HandshakeDone)
);
assert!(frames[0].handshake_done_frame()?.is_some());
assert!(frames[1].is_ping());
assert_eq!(
frames[2].kind(),
QuicFrameKind::Known(QuicKnownFrameType::HandshakeDone)
);
assert_eq!(frames[2].len(), 1);
assert_eq!(frames[3].padding_len(), Some(2));
assert_eq!(QuicFrame::encode_sequence(frames), bytes);
Ok(())
}
#[test]
fn quic_frame_handshake_done_serializes_and_summarizes() -> crate::Result<()> {
let typed = QuicHandshakeDoneFrame::new();
let frame = QuicFrame::handshake_done()?;
assert_eq!(typed.encode_to_vec()?, [0x1e]);
assert_eq!(typed.summary(), "kind=HANDSHAKE_DONE");
assert_eq!(frame.as_bytes(), &[0x1e]);
assert_eq!(frame.summary(), "kind=HANDSHAKE_DONE");
assert!(frame
.inspection_fields()
.contains(&("handshake_done", "true".to_string())));
Ok(())
}
#[test]
fn quic_frame_handshake_done_rejects_trailing_bytes_for_single_frame_decode() {
assert_eq!(
QuicHandshakeDoneFrame::decode([0x1e, 0x01]).unwrap_err(),
CrafterError::invalid_field_value(
"quic.frame.handshake_done",
"HANDSHAKE_DONE frame has trailing bytes"
)
);
assert_eq!(
QuicFrame::from_bytes([0x1e, 0x01]).kind(),
QuicFrameKind::Unknown
);
}
#[test]
fn quic_frame_datagram_len_decodes_and_continues_sequence() -> crate::Result<()> {
let bytes = [0x31, 0x03, 0xaa, 0xbb, 0xcc, 0x01];
let frames = QuicFrame::decode_sequence(bytes)?;
assert_eq!(frames.len(), 2);
assert_eq!(
frames[0].kind(),
QuicFrameKind::Known(QuicKnownFrameType::DatagramLen)
);
let datagram = frames[0].datagram_frame()?.unwrap();
assert!(datagram.has_length());
assert_eq!(datagram.frame_type_value(), 0x31);
assert_eq!(datagram.length()?.unwrap().value(), 3);
assert_eq!(datagram.length_override(), Some(v(3)));
assert_eq!(datagram.data(), &[0xaa, 0xbb, 0xcc]);
assert!(frames[1].is_ping());
assert_eq!(QuicFrame::encode_sequence(frames), bytes);
Ok(())
}
#[test]
fn quic_frame_datagram_without_length_consumes_packet_remainder() -> crate::Result<()> {
let bytes = [0x30, 0xaa, 0x01];
let frames = QuicFrame::decode_sequence(bytes)?;
assert_eq!(frames.len(), 1);
assert_eq!(
frames[0].kind(),
QuicFrameKind::Known(QuicKnownFrameType::Datagram)
);
let datagram = frames[0].datagram_frame()?.unwrap();
assert!(!datagram.has_length());
assert_eq!(datagram.frame_type_value(), 0x30);
assert_eq!(datagram.length()?, None);
assert_eq!(datagram.length_override(), None);
assert_eq!(datagram.data(), &[0xaa, 0x01]);
assert_eq!(QuicFrame::encode_sequence(frames), bytes);
Ok(())
}
#[test]
fn quic_frame_datagram_builders_emit_selected_variants() -> crate::Result<()> {
let with_length = QuicFrame::datagram([0xde, 0xad])?;
let without_length = QuicFrame::datagram_without_length([0xde, 0xad])?;
let empty_with_length = QuicFrame::from_datagram_frame(QuicDatagramFrame::new([]))?;
let empty_without_length =
QuicFrame::from_datagram_frame(QuicDatagramFrame::new([]).without_length())?;
assert_eq!(with_length.as_bytes(), &[0x31, 0x02, 0xde, 0xad]);
assert_eq!(without_length.as_bytes(), &[0x30, 0xde, 0xad]);
assert_eq!(empty_with_length.as_bytes(), &[0x31, 0x00]);
assert_eq!(empty_without_length.as_bytes(), &[0x30]);
assert_eq!(
with_length.summary(),
"kind=DATAGRAM_LEN has_length=true length=2 data_len=2"
);
assert_eq!(
without_length.summary(),
"kind=DATAGRAM has_length=false length=<none> data_len=2"
);
let fields = with_length.inspection_fields();
assert!(fields.contains(&("datagram_has_length", "true".to_string())));
assert!(fields.contains(&("datagram_length", "2".to_string())));
assert!(fields.contains(&("datagram_data", "de ad".to_string())));
Ok(())
}
#[test]
fn quic_frame_datagram_preserves_explicit_malformed_length() -> crate::Result<()> {
let datagram = QuicDatagramFrame::new([0xaa]).with_length(v(3));
let frame = QuicFrame::from_datagram_frame(datagram)?;
assert_eq!(frame.as_bytes(), &[0x31, 0x03, 0xaa]);
assert_eq!(
frame.datagram_frame().unwrap_err(),
CrafterError::buffer_too_short("quic.frame.datagram.data", 3, 1)
);
Ok(())
}
#[test]
fn quic_frame_datagram_malformed_values_report_structured_errors() {
assert_eq!(
QuicDatagramFrame::decode([0x2f]).unwrap_err(),
CrafterError::invalid_field_value(
"quic.frame.datagram.type",
"DATAGRAM frame type must be 0x30 or 0x31"
)
);
assert_eq!(
QuicFrame::decode_sequence([0x31, 0x40]).unwrap_err(),
CrafterError::buffer_too_short("quic.frame.datagram.length", 2, 1)
);
assert_eq!(
QuicFrame::decode_sequence([0x31, 0x03, 0xaa]).unwrap_err(),
CrafterError::buffer_too_short("quic.frame.datagram.data", 3, 1)
);
}
#[test]
fn quic_frame_datagram_transport_parameter_linkage_is_inspectable() -> crate::Result<()> {
let parameter = QuicTransportParameter::max_datagram_frame_size(v(1200))?;
let frame = QuicFrame::datagram([0xaa, 0xbb])?;
let datagram = frame.datagram_frame()?.unwrap();
assert_eq!(
parameter.integer_type(),
Some(QuicIntegerTransportParameter::MaxDatagramFrameSize)
);
assert_eq!(parameter.integer_value()?.unwrap().value(), 1200);
assert!(datagram.encode_to_vec()?.len() <= 1200);
assert_eq!(datagram.data(), &[0xaa, 0xbb]);
Ok(())
}
}