ndn_packet/
data.rs

1#[cfg(not(feature = "std"))]
2use alloc::sync::Arc;
3#[cfg(feature = "std")]
4use std::sync::Arc;
5
6#[cfg(not(feature = "std"))]
7use core::cell::OnceCell as OnceLock;
8#[cfg(feature = "std")]
9use std::sync::OnceLock;
10
11use bytes::Bytes;
12
13use crate::tlv_type;
14use crate::{MetaInfo, Name, PacketError, SignatureInfo};
15use ndn_tlv::TlvReader;
16
17/// An NDN Data packet.
18///
19/// Stores wire-format bytes for zero-copy CS storage and signature verification.
20/// The signed region is contiguous in the wire encoding — it is sliced directly
21/// from `raw` without copying.
22#[derive(Debug)]
23pub struct Data {
24    /// Wire-format bytes of the full Data TLV.
25    pub(crate) raw: Bytes,
26
27    /// Byte range of the signed region within `raw`.
28    signed_start: usize,
29    signed_end: usize,
30
31    /// Byte range of the SignatureValue within `raw`.
32    sig_value_start: usize,
33    sig_value_end: usize,
34
35    /// Name — always decoded eagerly.
36    pub name: Arc<Name>,
37
38    /// MetaInfo — decoded on first access.
39    meta_info: OnceLock<Option<MetaInfo>>,
40
41    /// Content payload — decoded on first access.
42    content: OnceLock<Option<Bytes>>,
43
44    /// Signature info — decoded on first access.
45    sig_info: OnceLock<Option<SignatureInfo>>,
46}
47
48impl Data {
49    /// Decode a Data packet from raw wire bytes.
50    pub fn decode(raw: Bytes) -> Result<Self, PacketError> {
51        let mut reader = TlvReader::new(raw.clone());
52        let (typ, value) = reader.read_tlv()?;
53        if typ != tlv_type::DATA {
54            return Err(PacketError::UnknownPacketType(typ));
55        }
56
57        // Signed region starts at byte 2 (after outer TLV header) and ends
58        // just before the SignatureValue TLV. We track byte offsets here;
59        // a full implementation would scan for the SignatureValue boundary.
60        let outer_header_len = raw.len() - value.len();
61        let signed_start = outer_header_len;
62
63        let mut inner = TlvReader::new(value.clone());
64        let (name_typ, name_val) = inner.read_tlv()?;
65        if name_typ != tlv_type::NAME {
66            return Err(PacketError::UnknownPacketType(name_typ));
67        }
68        let name = Name::decode(name_val)?;
69
70        if name.is_empty() {
71            return Err(PacketError::MalformedPacket(
72                "Data Name must have at least one component".into(),
73            ));
74        }
75
76        // Scan for SignatureValue to determine the signed region end.
77        let mut sig_value_start = 0;
78        let mut sig_value_end = 0;
79        let _ = scan_for_sig_value(
80            &raw,
81            outer_header_len,
82            &mut sig_value_start,
83            &mut sig_value_end,
84        );
85        let signed_end = if sig_value_start > 0 {
86            sig_value_start
87        } else {
88            raw.len()
89        };
90
91        Ok(Self {
92            raw,
93            signed_start,
94            signed_end,
95            sig_value_start,
96            sig_value_end,
97            name: Arc::new(name),
98            meta_info: OnceLock::new(),
99            content: OnceLock::new(),
100            sig_info: OnceLock::new(),
101        })
102    }
103
104    /// The signed region — a zero-copy slice suitable for signature verification.
105    pub fn signed_region(&self) -> &[u8] {
106        &self.raw[self.signed_start..self.signed_end]
107    }
108
109    /// The signature value bytes — a zero-copy slice.
110    ///
111    /// `sig_value_start` points to the `SignatureValue` TLV's type byte (`0x17`).
112    /// This method parses past the type and length to return only the raw value bytes.
113    pub fn sig_value(&self) -> &[u8] {
114        if self.sig_value_start == 0 || self.sig_value_end == 0 {
115            return &[];
116        }
117        // Parse the SignatureValue TLV header to find where the value bytes begin.
118        let sig_tlv = self.raw.slice(self.sig_value_start..self.sig_value_end);
119        let mut r = TlvReader::new(sig_tlv);
120        match r.read_tlv() {
121            Ok((_, val)) => {
122                let val_start = self.sig_value_end - val.len();
123                &self.raw[val_start..self.sig_value_end]
124            }
125            Err(_) => &[],
126        }
127    }
128
129    pub fn raw(&self) -> &Bytes {
130        &self.raw
131    }
132
133    /// The implicit SHA-256 digest of this Data packet — the SHA-256 hash
134    /// of the full wire encoding. Used for exact Data retrieval via
135    /// ImplicitSha256DigestComponent (type 0x01) in Interest names.
136    #[cfg(feature = "std")]
137    pub fn implicit_digest(&self) -> ring::digest::Digest {
138        ring::digest::digest(&ring::digest::SHA256, &self.raw)
139    }
140
141    pub fn content(&self) -> Option<&Bytes> {
142        self.content
143            .get_or_init(|| decode_content(&self.raw).ok().flatten())
144            .as_ref()
145    }
146
147    pub fn meta_info(&self) -> Option<&MetaInfo> {
148        self.meta_info
149            .get_or_init(|| decode_meta_info(&self.raw).ok().flatten())
150            .as_ref()
151    }
152
153    pub fn sig_info(&self) -> Option<&SignatureInfo> {
154        self.sig_info
155            .get_or_init(|| decode_sig_info(&self.raw).ok().flatten())
156            .as_ref()
157    }
158
159    /// Parse the delegation list from a Link object (ContentType=LINK).
160    ///
161    /// Per NDN Packet Format v0.3 §6.3.1, when ContentType is LINK the Content
162    /// field contains one or more Name TLVs. Returns `None` if this Data is not
163    /// a Link or has no content.
164    #[cfg(feature = "std")]
165    pub fn link_delegations(&self) -> Option<Vec<Arc<Name>>> {
166        let mi = self.meta_info()?;
167        if mi.content_type != crate::meta_info::ContentType::Link {
168            return None;
169        }
170        let content = self.content()?;
171        let mut reader = TlvReader::new(content.clone());
172        let mut names = Vec::new();
173        while !reader.is_empty() {
174            let (typ, val) = reader.read_tlv().ok()?;
175            if typ == tlv_type::NAME {
176                names.push(Arc::new(Name::decode(val).ok()?));
177            }
178        }
179        if names.is_empty() { None } else { Some(names) }
180    }
181}
182
183fn scan_for_sig_value(
184    raw: &Bytes,
185    start: usize,
186    sig_start: &mut usize,
187    sig_end: &mut usize,
188) -> Result<(), PacketError> {
189    let mut reader = TlvReader::new(raw.slice(start..));
190    while !reader.is_empty() {
191        let pos = start + reader.position();
192        let (typ, val) = reader.read_tlv()?;
193        if typ == tlv_type::SIGNATURE_VALUE {
194            *sig_start = pos;
195            *sig_end = start + reader.position();
196            return Ok(());
197        }
198        let _ = val;
199    }
200    Ok(())
201}
202
203fn decode_content(raw: &Bytes) -> Result<Option<Bytes>, PacketError> {
204    let mut reader = TlvReader::new(raw.clone());
205    let (_, value) = reader.read_tlv()?;
206    let mut inner = TlvReader::new(value);
207    while !inner.is_empty() {
208        let (typ, val) = inner.read_tlv()?;
209        if typ == tlv_type::CONTENT {
210            return Ok(Some(val));
211        }
212    }
213    Ok(None)
214}
215
216fn decode_meta_info(raw: &Bytes) -> Result<Option<MetaInfo>, PacketError> {
217    let mut reader = TlvReader::new(raw.clone());
218    let (_, value) = reader.read_tlv()?;
219    let mut inner = TlvReader::new(value);
220    while !inner.is_empty() {
221        let (typ, val) = inner.read_tlv()?;
222        if typ == tlv_type::META_INFO {
223            return Ok(Some(MetaInfo::decode(val)?));
224        }
225    }
226    Ok(None)
227}
228
229#[cfg(test)]
230pub(crate) fn build_data_packet(
231    components: &[&[u8]],
232    content: &[u8],
233    freshness_ms: Option<u64>,
234    sig_type_code: u8,
235    sig_value: &[u8],
236) -> Bytes {
237    let mut w = ndn_tlv::TlvWriter::new();
238    w.write_nested(tlv_type::DATA, |w| {
239        w.write_nested(tlv_type::NAME, |w| {
240            for comp in components {
241                w.write_tlv(tlv_type::NAME_COMPONENT, comp);
242            }
243        });
244        if let Some(ms) = freshness_ms {
245            w.write_nested(tlv_type::META_INFO, |w| {
246                w.write_tlv(tlv_type::FRESHNESS_PERIOD, &ms.to_be_bytes());
247            });
248        }
249        w.write_tlv(tlv_type::CONTENT, content);
250        w.write_nested(tlv_type::SIGNATURE_INFO, |w| {
251            w.write_tlv(tlv_type::SIGNATURE_TYPE, &[sig_type_code]);
252        });
253        w.write_tlv(tlv_type::SIGNATURE_VALUE, sig_value);
254    });
255    w.finish()
256}
257
258fn decode_sig_info(raw: &Bytes) -> Result<Option<SignatureInfo>, PacketError> {
259    let mut reader = TlvReader::new(raw.clone());
260    let (_, value) = reader.read_tlv()?;
261    let mut inner = TlvReader::new(value);
262    while !inner.is_empty() {
263        let (typ, val) = inner.read_tlv()?;
264        if typ == tlv_type::SIGNATURE_INFO {
265            return Ok(Some(SignatureInfo::decode(val)?));
266        }
267    }
268    Ok(None)
269}
270
271#[cfg(test)]
272mod tests {
273    use super::*;
274
275    // ── Data::decode — name ───────────────────────────────────────────────────
276
277    #[test]
278    fn decode_name() {
279        let raw = build_data_packet(&[b"edu", b"ucla"], b"hello", None, 5, &[0xAB]);
280        let d = Data::decode(raw).unwrap();
281        assert_eq!(d.name.len(), 2);
282        assert_eq!(d.name.components()[0].value.as_ref(), b"edu");
283        assert_eq!(d.name.components()[1].value.as_ref(), b"ucla");
284    }
285
286    // ── content (lazy) ────────────────────────────────────────────────────────
287
288    #[test]
289    fn decode_content() {
290        let raw = build_data_packet(&[b"test"], b"payload", None, 0, &[0x00]);
291        let d = Data::decode(raw).unwrap();
292        let content = d.content().expect("content present");
293        assert_eq!(content.as_ref(), b"payload");
294    }
295
296    #[test]
297    fn decode_empty_content() {
298        let raw = build_data_packet(&[b"test"], b"", None, 0, &[0x00]);
299        let d = Data::decode(raw).unwrap();
300        // Empty content — the TLV is present so we get Some with empty bytes.
301        let content = d.content().expect("content present");
302        assert_eq!(content.len(), 0);
303    }
304
305    // ── meta_info (lazy) ──────────────────────────────────────────────────────
306
307    #[test]
308    fn decode_meta_info_freshness() {
309        let raw = build_data_packet(&[b"test"], b"", Some(5000), 5, &[0x00]);
310        let d = Data::decode(raw).unwrap();
311        let mi = d.meta_info().expect("meta_info present");
312        assert_eq!(
313            mi.freshness_period,
314            Some(std::time::Duration::from_millis(5000))
315        );
316    }
317
318    #[test]
319    fn decode_no_meta_info() {
320        let raw = build_data_packet(&[b"test"], b"data", None, 0, &[0x00]);
321        let d = Data::decode(raw).unwrap();
322        assert!(d.meta_info().is_none());
323    }
324
325    // ── sig_info (lazy) ───────────────────────────────────────────────────────
326
327    #[test]
328    fn decode_sig_info_type() {
329        let raw = build_data_packet(&[b"test"], b"", None, 5, &[0xAB]);
330        let d = Data::decode(raw).unwrap();
331        let si = d.sig_info().expect("sig_info present");
332        assert_eq!(si.sig_type, crate::SignatureType::SignatureEd25519);
333    }
334
335    // ── signed_region and sig_value ───────────────────────────────────────────
336
337    #[test]
338    fn signed_region_excludes_sig_value() {
339        let sig_bytes: &[u8] = &[0xDE, 0xAD, 0xBE, 0xEF];
340        let raw = build_data_packet(&[b"test"], b"content", None, 5, sig_bytes);
341        let d = Data::decode(raw.clone()).unwrap();
342
343        let region = d.signed_region();
344        // Signed region must not be empty.
345        assert!(!region.is_empty());
346        // Signed region must not contain the sig value bytes at the end.
347        // (The last 4 bytes of the packet are the sig value content; they should
348        //  not appear at the end of the signed region.)
349        assert!(!region.ends_with(sig_bytes));
350    }
351
352    #[test]
353    fn sig_value_correct_bytes() {
354        let sig_bytes: &[u8] = &[0x11, 0x22, 0x33, 0x44];
355        let raw = build_data_packet(&[b"test"], b"content", None, 5, sig_bytes);
356        let d = Data::decode(raw).unwrap();
357        // sig_value() returns only the VALUE bytes inside the SignatureValue TLV.
358        assert_eq!(d.sig_value(), sig_bytes);
359    }
360
361    #[test]
362    fn signed_end_equals_sig_value_start() {
363        // The signed region must end exactly where the SignatureValue TLV begins —
364        // they are adjacent in the NDN wire encoding.
365        let raw = build_data_packet(&[b"n"], b"x", None, 0, &[0xAB, 0xCD]);
366        let d = Data::decode(raw).unwrap();
367        assert_eq!(d.signed_end, d.sig_value_start);
368    }
369
370    // ── raw field ─────────────────────────────────────────────────────────────
371
372    #[test]
373    fn raw_field_is_full_wire_bytes() {
374        let raw = build_data_packet(&[b"test"], b"hi", None, 0, &[0x00]);
375        let d = Data::decode(raw.clone()).unwrap();
376        assert_eq!(d.raw(), &raw);
377    }
378
379    // ── link_delegations ───────────────────────────────────────────────────
380
381    fn build_link_data(name_comps: &[&[u8]], delegations: &[&[&[u8]]]) -> Bytes {
382        let mut content_w = ndn_tlv::TlvWriter::new();
383        for del in delegations {
384            content_w.write_nested(tlv_type::NAME, |w| {
385                for comp in *del {
386                    w.write_tlv(tlv_type::NAME_COMPONENT, comp);
387                }
388            });
389        }
390        let content_bytes = content_w.finish();
391
392        let mut w = ndn_tlv::TlvWriter::new();
393        w.write_nested(tlv_type::DATA, |w| {
394            w.write_nested(tlv_type::NAME, |w| {
395                for comp in name_comps {
396                    w.write_tlv(tlv_type::NAME_COMPONENT, comp);
397                }
398            });
399            w.write_nested(tlv_type::META_INFO, |w| {
400                w.write_tlv(tlv_type::CONTENT_TYPE, &[1]); // LINK = 1
401            });
402            w.write_tlv(tlv_type::CONTENT, &content_bytes);
403            w.write_nested(tlv_type::SIGNATURE_INFO, |w| {
404                w.write_tlv(tlv_type::SIGNATURE_TYPE, &[0]);
405            });
406            w.write_tlv(tlv_type::SIGNATURE_VALUE, &[0x00]);
407        });
408        w.finish()
409    }
410
411    #[test]
412    fn link_delegations_parsed() {
413        let raw = build_link_data(
414            &[b"link"],
415            &[&[b"ndn", b"gateway1"], &[b"ndn", b"gateway2"]],
416        );
417        let d = Data::decode(raw).unwrap();
418        let dels = d.link_delegations().expect("delegations present");
419        assert_eq!(dels.len(), 2);
420        assert_eq!(dels[0].components()[1].value.as_ref(), b"gateway1");
421        assert_eq!(dels[1].components()[1].value.as_ref(), b"gateway2");
422    }
423
424    #[test]
425    fn non_link_data_has_no_delegations() {
426        let raw = build_data_packet(&[b"test"], b"payload", None, 5, &[0x00]);
427        let d = Data::decode(raw).unwrap();
428        assert!(d.link_delegations().is_none());
429    }
430
431    // ── implicit_digest ────────────────────────────────────────────────────
432
433    #[test]
434    fn implicit_digest_is_sha256_of_raw() {
435        let raw = build_data_packet(&[b"test"], b"content", None, 5, &[0xAB]);
436        let d = Data::decode(raw.clone()).unwrap();
437        let expected = ring::digest::digest(&ring::digest::SHA256, &raw);
438        assert_eq!(d.implicit_digest().as_ref(), expected.as_ref());
439    }
440
441    // ── error cases ───────────────────────────────────────────────────────────
442
443    #[test]
444    fn decode_wrong_type_errors() {
445        let mut w = ndn_tlv::TlvWriter::new();
446        w.write_nested(0x05, |w| {
447            // INTEREST type, not DATA
448            w.write_nested(crate::tlv_type::NAME, |w| {
449                w.write_tlv(crate::tlv_type::NAME_COMPONENT, b"test");
450            });
451        });
452        assert!(matches!(
453            Data::decode(w.finish()).unwrap_err(),
454            crate::PacketError::UnknownPacketType(0x05)
455        ));
456    }
457}