Skip to main content

moqtap_client/
datagram_prefix.rs

1//! The fields of a received datagram up to its Extension Headers Length.
2//!
3//! On drafts 11 through 16 the codec's datagram header decoder refuses an
4//! announced extension block with a length of 0 as a bare `InvalidField`,
5//! which it also returns for other faults. Each draft's `recv_datagram` reads
6//! the prefix again here, after that refusal, to tell whether the empty block
7//! was the fault, since the drafts answer it with a session close.
8
9use moqtap_codec::varint::VarInt;
10
11/// Which fields a datagram Type puts before its Extension Headers Length.
12pub(crate) struct Prefix {
13    /// An Object ID field is present; absent, the Object ID is 0.
14    pub object_id: bool,
15    /// A Publisher Priority byte is present.
16    pub priority: bool,
17}
18
19/// The Object ID of a datagram whose Type announces an extension block and
20/// whose Extension Headers Length is 0, or `None` for any other datagram.
21///
22/// `prefix` answers, for the Type's value and its encoded width in bytes, the
23/// fields before the length when the Type announces a block the draft's rule
24/// covers, and `None` for every other Type.
25pub(crate) fn empty_extension_block(
26    data: &[u8],
27    prefix: impl Fn(u64, usize) -> Option<Prefix>,
28) -> Option<u64> {
29    let mut cursor = data;
30    let datagram_type = VarInt::decode(&mut cursor).ok()?.into_inner();
31    let layout = prefix(datagram_type, data.len() - cursor.len())?;
32    VarInt::decode(&mut cursor).ok()?;
33    VarInt::decode(&mut cursor).ok()?;
34    let object_id =
35        if layout.object_id { VarInt::decode(&mut cursor).ok()?.into_inner() } else { 0 };
36    if layout.priority {
37        cursor = cursor.get(1..)?;
38    }
39    (VarInt::decode(&mut cursor).ok()?.into_inner() == 0).then_some(object_id)
40}