domain/base/name/
parsed.rs

1//! Parsed domain names.
2//!
3//! This is a private module. Its public types are re-exported by the parent
4//! module.
5
6use super::super::cmp::CanonicalOrd;
7use super::super::wire::{FormError, ParseError};
8use super::dname::Dname;
9use super::label::{Label, LabelTypeError};
10use super::relative::RelativeDname;
11use super::traits::{FlattenInto, ToDname, ToLabelIter};
12use core::{cmp, fmt, hash};
13use octseq::builder::{
14    BuilderAppendError, EmptyBuilder, FreezeBuilder, FromBuilder,
15    OctetsBuilder,
16};
17use octseq::octets::Octets;
18use octseq::parse::Parser;
19
20//------------ ParsedDname ---------------------------------------------------
21
22/// A domain name parsed from a DNS message.
23///
24/// In an attempt to keep messages small, DNS uses a procedure called ‘name
25/// compression.’ It tries to minimize the space used for repeatedly
26/// appearing domain names by simply refering to the first occurence of the
27/// name. This works not only for complete names but also for suffixes. In
28/// this case, the first unique labels of the name are included and then a
29/// pointer is included for the remainder of the name.
30///
31/// A consequence of this is that when parsing a domain name, its labels can
32/// be scattered all over the message and we would need to allocate some
33/// space to re-assemble the original name. However, in many cases we don’t
34/// need the complete name. Many operations can be performed by just
35/// iterating over the labels which we can do in place.
36///
37/// `ParsedDname` deals with such names. It takes a copy of a [`Parser`]
38/// representing a reference to the underlying DNS message and, if nedded,
39/// traverses over the name starting at the current position of the parser.
40/// When being created, the type quickly walks over the name to check that it
41/// is, indeed, a valid name. While this does take a bit of time, it spares
42/// you having to deal with possible parse errors later on.
43///
44/// `ParsedDname` implementes the [`ToDname`] trait, so you can use it
45/// everywhere where a generic absolute domain name is accepted. In
46/// particular, you can compare it to other names or chain it to the end of a
47/// relative name. If necessary, [`ToDname::to_name`] can be used to produce
48/// a flat, self-contained [`Dname`].
49///
50/// [`Dname`]: struct.Dname.html
51/// [`Parser`]: ../parse/struct.Parser.html
52/// [`ToDname`]: trait.ToDname.html
53/// [`ToDname::to_name`]: trait.ToDname.html#method.to_name
54#[derive(Clone, Copy)]
55pub struct ParsedDname<Octs> {
56    /// The octets the name is embedded in.
57    ///
58    /// This needs to be the full message as compression pointers in the name
59    /// are indexes into this sequence.
60    octets: Octs,
61
62    /// The start position of the name within `octets`.
63    pos: usize,
64
65    /// The length of the uncompressed name in octets.
66    ///
67    /// We need this for implementing `ToLabelIter`.
68    name_len: u16,
69
70    /// Whether the name is compressed.
71    ///
72    /// This allows various neat optimizations for the case where it isn’t.
73    compressed: bool,
74}
75
76impl<Octs> ParsedDname<Octs> {
77    /// Returns whether the name is compressed.
78    pub fn is_compressed(&self) -> bool {
79        self.compressed
80    }
81
82    /// Returns whether the name is the root label only.
83    pub fn is_root(&self) -> bool {
84        self.name_len == 1
85    }
86
87    /// Returns a correctly positioned parser.
88    fn parser(&self) -> Parser<Octs>
89    where
90        Octs: AsRef<[u8]>,
91    {
92        let mut res = Parser::from_ref(&self.octets);
93        res.advance(self.pos).expect("illegal pos in ParsedDname");
94        res
95    }
96
97    /// Returns an equivalent name for a reference to the contained octets.
98    pub fn ref_octets(&self) -> ParsedDname<&Octs> {
99        ParsedDname {
100            octets: &self.octets,
101            pos: self.pos,
102            name_len: self.name_len,
103            compressed: self.compressed,
104        }
105    }
106}
107
108impl<'a, Octs: Octets + ?Sized> ParsedDname<&'a Octs> {
109    #[must_use]
110    pub fn deref_octets(&self) -> ParsedDname<Octs::Range<'a>> {
111        ParsedDname {
112            octets: self.octets.range(..),
113            pos: self.pos,
114            name_len: self.name_len,
115            compressed: self.compressed,
116        }
117    }
118}
119
120/// # Working with Labels
121///
122impl<Octs: AsRef<[u8]>> ParsedDname<Octs> {
123    /// Returns an iterator over the labels of the name.
124    pub fn iter(&self) -> ParsedDnameIter {
125        ParsedDnameIter::new(self.octets.as_ref(), self.pos, self.name_len)
126    }
127
128    /// Returns an iterator over the suffixes of the name.
129    ///
130    /// The returned iterator starts with the full name and then for each
131    /// additional step returns a name with the left-most label stripped off
132    /// until it reaches the root label.
133    pub fn iter_suffixes(&self) -> ParsedSuffixIter<Octs> {
134        ParsedSuffixIter::new(self)
135    }
136
137    /// Returns the number of labels in the domain name.
138    pub fn label_count(&self) -> usize {
139        self.iter().count()
140    }
141
142    /// Returns a reference to the first label.
143    pub fn first(&self) -> &Label {
144        self.iter().next().unwrap()
145    }
146
147    /// Returns a reference to the last label.
148    ///
149    /// Because the last label in an absolute name is always the root label,
150    /// this method can return a static reference. It is also a wee bit silly,
151    /// but here for completeness.
152    pub fn last(&self) -> &'static Label {
153        Label::root()
154    }
155
156    /// Determines whether `base` is a prefix of `self`.
157    pub fn starts_with<N: ToLabelIter>(&self, base: &N) -> bool {
158        <Self as ToLabelIter>::starts_with(self, base)
159    }
160
161    /// Determines whether `base` is a suffix of `self`.
162    pub fn ends_with<N: ToLabelIter>(&self, base: &N) -> bool {
163        <Self as ToLabelIter>::ends_with(self, base)
164    }
165
166    /// Splits off the first label.
167    ///
168    /// If this name is longer than just the root label, returns the first
169    /// label as a relative name and removes it from the name itself. If the
170    /// name is only the root label, returns `None` and does nothing.
171    pub fn split_first(&mut self) -> Option<RelativeDname<Octs::Range<'_>>>
172    where
173        Octs: Octets,
174    {
175        if self.name_len == 1 {
176            return None;
177        }
178        let mut name_len = self.name_len;
179        let range = {
180            let mut parser = self.parser();
181            let len = loop {
182                match LabelType::peek(&parser).unwrap() {
183                    LabelType::Normal(0) => {
184                        unreachable!()
185                    }
186                    LabelType::Normal(label_len) => break label_len + 1,
187                    LabelType::Compressed(pos) => {
188                        parser.seek(pos).unwrap();
189                    }
190                }
191            };
192            name_len -= len;
193            parser.pos()..parser.pos() + usize::from(len)
194        };
195        self.pos = range.end;
196        self.name_len = name_len;
197        Some(unsafe {
198            RelativeDname::from_octets_unchecked(self.octets.range(range))
199        })
200    }
201
202    /// Reduces the name to the parent of the current name.
203    ///
204    /// If the name consists of the root label only, returns `false` and does
205    /// nothing. Otherwise, drops the first label and returns `true`.
206    pub fn parent(&mut self) -> bool {
207        if self.name_len == 1 {
208            return false;
209        }
210        let (pos, len) = {
211            let mut parser = self.parser();
212            let len = loop {
213                match LabelType::peek(&parser).unwrap() {
214                    LabelType::Normal(0) => {
215                        unreachable!()
216                    }
217                    LabelType::Normal(label_len) => break label_len + 1,
218                    LabelType::Compressed(pos) => {
219                        parser.seek(pos).unwrap();
220                    }
221                }
222            };
223            (parser.pos() + usize::from(len), len)
224        };
225        self.name_len -= len;
226        self.pos = pos;
227        true
228    }
229}
230
231impl<Octs> ParsedDname<Octs> {
232    pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
233        parser: &mut Parser<'a, Src>,
234    ) -> Result<Self, ParseError> {
235        ParsedDname::parse_ref(parser).map(|res| res.deref_octets())
236    }
237}
238
239impl<'a, Octs: AsRef<[u8]> + ?Sized> ParsedDname<&'a Octs> {
240    pub fn parse_ref(
241        parser: &mut Parser<'a, Octs>,
242    ) -> Result<Self, ParseError> {
243        let mut name_len = 0;
244        let mut pos = parser.pos();
245
246        // Phase One: No compression pointers have been found yet.
247        //
248        // Parse labels. If we encounter the root label, return an
249        // uncompressed name. Otherwise continue to phase two.
250        let mut ptr = loop {
251            match LabelType::parse(parser)? {
252                LabelType::Normal(0) => {
253                    // Root label.
254                    name_len += 1;
255                    return Ok(ParsedDname {
256                        octets: parser.octets_ref(),
257                        pos,
258                        name_len,
259                        compressed: false,
260                    });
261                }
262                LabelType::Normal(label_len) => {
263                    parser.advance(usize::from(label_len))?;
264                    name_len += label_len + 1;
265                    if name_len >= 255 {
266                        return Err(ParsedDnameError::LongName.into());
267                    }
268                }
269                LabelType::Compressed(ptr) => {
270                    break ptr;
271                }
272            }
273        };
274
275        // Phase Two: Compression has occured.
276        //
277        // Now we need to add up label lengths until we encounter the root
278        // label or the name becomes too long.
279        //
280        // We are going to work on a temporary parser so we can jump around.
281        // The actual parser has already reached the end of the name, so we
282        // can just shadow it. (Because parsers are copy, dereferencing them
283        // clones them.)
284        let mut parser = *parser;
285        let mut compressed = true;
286        loop {
287            // Check that the compression pointer points backwards. Because
288            // it is 16 bit long and the current position is behind the label
289            // header, it needs to less than the current position minus 2 --
290            // less so can’t point to itself.
291            if ptr >= parser.pos() - 2 {
292                return Err(ParsedDnameError::ExcessiveCompression.into());
293            }
294
295            // If this is the first label, the returned name may as well start
296            // here.
297            if name_len == 0 {
298                pos = ptr;
299                compressed = false;
300            }
301
302            // Reposition and read next label.
303            parser.seek(ptr)?;
304
305            loop {
306                match LabelType::parse(&mut parser)? {
307                    LabelType::Normal(0) => {
308                        // Root label.
309                        name_len += 1;
310                        return Ok(ParsedDname {
311                            octets: parser.octets_ref(),
312                            pos,
313                            name_len,
314                            compressed,
315                        });
316                    }
317                    LabelType::Normal(label_len) => {
318                        parser.advance(usize::from(label_len))?;
319                        name_len += label_len + 1;
320                        if name_len >= 255 {
321                            return Err(ParsedDnameError::LongName.into());
322                        }
323                    }
324                    LabelType::Compressed(new_ptr) => {
325                        ptr = new_ptr;
326                        compressed = true;
327                        break;
328                    }
329                }
330            }
331        }
332    }
333}
334
335impl ParsedDname<()> {
336    /// Skip over a domain name.
337    ///
338    /// This will only check the uncompressed part of the name. If the name
339    /// is compressed but the compression pointer is invalid or the name
340    /// pointed to is invalid or too long, the function will still succeed.
341    ///
342    /// If you need to check that the name you are skipping over is valid, you
343    /// will have to use `parse` and drop the result.
344    pub fn skip<Src: AsRef<[u8]> + ?Sized>(
345        parser: &mut Parser<Src>,
346    ) -> Result<(), ParseError> {
347        let mut len = 0;
348        loop {
349            match LabelType::parse(parser) {
350                Ok(LabelType::Normal(0)) => {
351                    len += 1;
352                    if len > 255 {
353                        return Err(ParsedDnameError::LongName.into());
354                    }
355                    return Ok(());
356                }
357                Ok(LabelType::Normal(label_len)) => {
358                    parser.advance(label_len.into())?;
359                    len += label_len + 1;
360                    if len > 255 {
361                        return Err(ParsedDnameError::LongName.into());
362                    }
363                }
364                Ok(LabelType::Compressed(_)) => return Ok(()),
365                Err(err) => return Err(err),
366            }
367        }
368    }
369}
370
371//--- From
372
373impl<Octs: AsRef<[u8]>> From<Dname<Octs>> for ParsedDname<Octs> {
374    fn from(name: Dname<Octs>) -> ParsedDname<Octs> {
375        let name_len = name.compose_len();
376        ParsedDname {
377            octets: name.into_octets(),
378            pos: 0,
379            name_len,
380            compressed: false,
381        }
382    }
383}
384
385//--- FlattenInto
386
387impl<Octs, Target> FlattenInto<Dname<Target>> for ParsedDname<Octs>
388where
389    Octs: Octets,
390    Target: FromBuilder,
391    <Target as FromBuilder>::Builder: EmptyBuilder,
392{
393    type AppendError = BuilderAppendError<Target>;
394
395    fn try_flatten_into(self) -> Result<Dname<Target>, Self::AppendError> {
396        let mut builder =
397            Target::Builder::with_capacity(self.compose_len().into());
398        if let Some(slice) = self.as_flat_slice() {
399            builder.append_slice(slice)?;
400        } else {
401            self.iter_labels()
402                .try_for_each(|label| label.compose(&mut builder))?;
403        }
404        Ok(unsafe { Dname::from_octets_unchecked(builder.freeze()) })
405    }
406}
407
408//--- PartialEq and Eq
409
410impl<Octs, N> PartialEq<N> for ParsedDname<Octs>
411where
412    Octs: AsRef<[u8]>,
413    N: ToDname + ?Sized,
414{
415    fn eq(&self, other: &N) -> bool {
416        self.name_eq(other)
417    }
418}
419
420impl<Octs: AsRef<[u8]>> Eq for ParsedDname<Octs> {}
421
422//--- PartialOrd, Ord, and CanonicalOrd
423
424impl<Octs, N> PartialOrd<N> for ParsedDname<Octs>
425where
426    Octs: AsRef<[u8]>,
427    N: ToDname + ?Sized,
428{
429    fn partial_cmp(&self, other: &N) -> Option<cmp::Ordering> {
430        Some(self.name_cmp(other))
431    }
432}
433
434impl<Octs: AsRef<[u8]>> Ord for ParsedDname<Octs> {
435    fn cmp(&self, other: &Self) -> cmp::Ordering {
436        self.name_cmp(other)
437    }
438}
439
440impl<Octs, N> CanonicalOrd<N> for ParsedDname<Octs>
441where
442    Octs: AsRef<[u8]>,
443    N: ToDname + ?Sized,
444{
445    fn canonical_cmp(&self, other: &N) -> cmp::Ordering {
446        self.name_cmp(other)
447    }
448}
449
450//--- Hash
451
452impl<Octs: AsRef<[u8]>> hash::Hash for ParsedDname<Octs> {
453    fn hash<H: hash::Hasher>(&self, state: &mut H) {
454        for item in self.iter() {
455            item.hash(state)
456        }
457    }
458}
459
460//--- ToLabelIter and ToDname
461
462impl<Octs: AsRef<[u8]>> ToLabelIter for ParsedDname<Octs> {
463    type LabelIter<'s> = ParsedDnameIter<'s> where Octs: 's;
464
465    fn iter_labels(&self) -> Self::LabelIter<'_> {
466        self.iter()
467    }
468
469    fn compose_len(&self) -> u16 {
470        self.name_len
471    }
472}
473
474impl<Octs: AsRef<[u8]>> ToDname for ParsedDname<Octs> {
475    fn as_flat_slice(&self) -> Option<&[u8]> {
476        if self.compressed {
477            None
478        } else {
479            Some(
480                &self.octets.as_ref()
481                    [self.pos..self.pos + usize::from(self.name_len)],
482            )
483        }
484    }
485}
486
487//--- IntoIterator
488
489impl<'a, Octs> IntoIterator for &'a ParsedDname<Octs>
490where
491    Octs: AsRef<[u8]>,
492{
493    type Item = &'a Label;
494    type IntoIter = ParsedDnameIter<'a>;
495
496    fn into_iter(self) -> Self::IntoIter {
497        self.iter()
498    }
499}
500
501//--- Display and Debug
502
503impl<Octs: AsRef<[u8]>> fmt::Display for ParsedDname<Octs> {
504    /// Formats the domain name.
505    ///
506    /// This will produce the domain name in common display format without
507    /// the trailing dot.
508    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
509        let mut iter = self.iter();
510        write!(f, "{}", iter.next().unwrap())?;
511        for label in iter {
512            if !label.is_root() {
513                write!(f, ".{}", label)?
514            }
515        }
516        Ok(())
517    }
518}
519
520impl<Octs: AsRef<[u8]>> fmt::Debug for ParsedDname<Octs> {
521    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
522        write!(f, "ParsedDname({}.)", self)
523    }
524}
525
526//------------ ParsedDnameIter -----------------------------------------------
527
528/// An iterator over the labels in a parsed domain name.
529#[derive(Clone)]
530pub struct ParsedDnameIter<'a> {
531    slice: &'a [u8],
532    pos: usize,
533    len: u16,
534}
535
536impl<'a> ParsedDnameIter<'a> {
537    /// Creates a new iterator from the parser and the name length.
538    ///
539    /// The parser must be positioned at the beginning of the name.
540    pub(crate) fn new(slice: &'a [u8], pos: usize, len: u16) -> Self {
541        ParsedDnameIter { slice, pos, len }
542    }
543
544    /// Returns the next label.
545    ///
546    /// This just assumes that there is a label at the current beginning
547    /// of the parser. This may lead to funny results if there isn’t,
548    /// including panics if the label head is illegal or points beyond the
549    /// end of the message.
550    fn get_label(&mut self) -> &'a Label {
551        let end = loop {
552            let ltype = self.slice[self.pos];
553            self.pos += 1;
554            match ltype {
555                0..=0x3F => break self.pos + (ltype as usize),
556                0xC0..=0xFF => {
557                    self.pos = (self.slice[self.pos] as usize)
558                        | (((ltype as usize) & 0x3F) << 8);
559                }
560                _ => panic!("bad label"),
561            }
562        };
563        let res = unsafe {
564            Label::from_slice_unchecked(&self.slice[self.pos..end])
565        };
566        self.pos = end;
567        self.len -= res.compose_len();
568        res
569    }
570}
571
572impl<'a> Iterator for ParsedDnameIter<'a> {
573    type Item = &'a Label;
574
575    fn next(&mut self) -> Option<&'a Label> {
576        if self.len == 0 {
577            return None;
578        }
579        Some(self.get_label())
580    }
581}
582
583impl<'a> DoubleEndedIterator for ParsedDnameIter<'a> {
584    fn next_back(&mut self) -> Option<&'a Label> {
585        if self.len == 0 {
586            return None;
587        }
588        let mut tmp = self.clone();
589        let label = loop {
590            let label = tmp.get_label();
591            if tmp.len == 0 {
592                break label;
593            }
594        };
595        self.len -= label.compose_len();
596        Some(label)
597    }
598}
599
600//------------ ParsedSuffixIter ----------------------------------------------
601
602/// An iterator over ever shorter suffixes of a parsed domain name.
603#[derive(Clone)]
604pub struct ParsedSuffixIter<'a, Octs: ?Sized> {
605    name: Option<ParsedDname<&'a Octs>>,
606}
607
608impl<'a, Octs> ParsedSuffixIter<'a, Octs> {
609    /// Creates a new iterator cloning `name`.
610    fn new(name: &'a ParsedDname<Octs>) -> Self {
611        ParsedSuffixIter {
612            name: Some(name.ref_octets()),
613        }
614    }
615}
616
617impl<'a, Octs: Octets + ?Sized> Iterator for ParsedSuffixIter<'a, Octs> {
618    type Item = ParsedDname<Octs::Range<'a>>;
619
620    fn next(&mut self) -> Option<Self::Item> {
621        let name = match self.name {
622            Some(ref mut name) => name,
623            None => return None,
624        };
625        let res = name.deref_octets();
626        if !name.parent() {
627            self.name = None
628        }
629        Some(res)
630    }
631}
632
633//------------ LabelType -----------------------------------------------------
634
635/// The type of a label.
636#[derive(Clone, Copy, Debug, Eq, PartialEq)]
637enum LabelType {
638    /// A normal label with its size in octets.
639    Normal(u16),
640
641    /// A compressed label with the position of where to continue.
642    Compressed(usize),
643}
644
645impl LabelType {
646    /// Attempts to take a label type from the beginning of `parser`.
647    pub fn parse<Octs: AsRef<[u8]> + ?Sized>(
648        parser: &mut Parser<Octs>,
649    ) -> Result<Self, ParseError> {
650        let ltype = parser.parse_u8()?;
651        match ltype {
652            0..=0x3F => Ok(LabelType::Normal(ltype.into())),
653            0xC0..=0xFF => {
654                let res = usize::from(parser.parse_u8()?);
655                let res = res | ((usize::from(ltype) & 0x3F) << 8);
656                Ok(LabelType::Compressed(res))
657            }
658            _ => Err(ParseError::Form(FormError::new("invalid label type"))),
659        }
660    }
661
662    /// Returns the label type at the beginning of `parser` without advancing.
663    pub fn peek<Ref: AsRef<[u8]> + ?Sized>(
664        parser: &Parser<Ref>,
665    ) -> Result<Self, ParseError> {
666        let ltype = parser.peek(1)?[0];
667        match ltype {
668            0..=0x3F => Ok(LabelType::Normal(ltype.into())),
669            0xC0..=0xFF => {
670                let res = usize::from(parser.peek(2)?[1]);
671                let res = res | ((usize::from(ltype) & 0x3F) << 8);
672                Ok(LabelType::Compressed(res))
673            }
674            _ => Err(ParseError::Form(FormError::new("invalid label type"))),
675        }
676    }
677}
678
679//------------ ParsedDnameError ----------------------------------------------
680
681/// Parsing a domain name failed.
682#[derive(Clone, Copy, Debug, Eq, PartialEq)]
683pub enum ParsedDnameError {
684    /// A bad label was encountered.
685    BadLabel(LabelTypeError),
686
687    /// The name is longer than the 255 octets allowed.
688    LongName,
689
690    /// Too many compression pointers.
691    ExcessiveCompression,
692}
693
694impl fmt::Display for ParsedDnameError {
695    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
696        FormError::from(*self).fmt(f)
697    }
698}
699
700#[cfg(feature = "std")]
701impl std::error::Error for ParsedDnameError {}
702
703impl From<LabelTypeError> for ParsedDnameError {
704    fn from(err: LabelTypeError) -> Self {
705        ParsedDnameError::BadLabel(err)
706    }
707}
708
709impl From<ParsedDnameError> for FormError {
710    fn from(err: ParsedDnameError) -> FormError {
711        match err {
712            ParsedDnameError::BadLabel(_) => {
713                FormError::new("invalid label type")
714            }
715            ParsedDnameError::LongName => FormError::new("long domain name"),
716            ParsedDnameError::ExcessiveCompression => {
717                FormError::new("too many compression pointers")
718            }
719        }
720    }
721}
722
723impl From<ParsedDnameError> for ParseError {
724    fn from(err: ParsedDnameError) -> ParseError {
725        ParseError::Form(err.into())
726    }
727}
728
729//============ Testing =======================================================
730
731#[cfg(test)]
732mod test {
733    use super::*;
734    use crate::base::name::{Dname, RelativeDname};
735
736    macro_rules! name {
737        (root) => {
738            name!(b"123\0", 3, 1, false)
739        };
740        (flat) => {
741            name!(b"\x03www\x07example\x03com\0\xc0\0", 0, 17, false)
742        };
743        (copy) => {
744            name!(b"\x03www\x07example\x03com\0\xc0\0", 17, 17, false)
745        };
746        (once) => {
747            name!(b"\x03com\0\x03www\x07example\xC0\0", 5, 17, true)
748        };
749        (twice) => {
750            name!(b"\x03com\0\x07example\xc0\0\x03www\xc0\x05", 15, 17, true)
751        };
752
753        ($bytes:expr, $start:expr, $len:expr, $compressed:expr) => {{
754            let mut parser = Parser::from_ref($bytes.as_ref());
755            parser.advance($start).unwrap();
756            ParsedDname {
757                octets: $bytes.as_ref(),
758                pos: $start,
759                name_len: $len,
760                compressed: $compressed,
761            }
762        }};
763    }
764
765    static WECR: &[u8] = b"\x03www\x07example\x03com\0";
766
767    #[test]
768    fn len() {
769        assert_eq!(name!(root).compose_len(), 1);
770        assert_eq!(name!(flat).compose_len(), 17);
771        assert_eq!(name!(once).compose_len(), 17);
772        assert_eq!(name!(twice).compose_len(), 17);
773    }
774
775    #[test]
776    fn is_compressed() {
777        assert!(!name!(root).is_compressed());
778        assert!(!name!(flat).is_compressed());
779        assert!(name!(once).is_compressed());
780        assert!(name!(twice).is_compressed());
781    }
782
783    #[test]
784    fn is_root() {
785        assert!(name!(root).is_root());
786        assert!(!name!(flat).is_root());
787        assert!(!name!(once).is_root());
788        assert!(!name!(twice).is_root());
789    }
790
791    #[test]
792    fn iter() {
793        use crate::base::name::dname::test::cmp_iter;
794
795        let labels: &[&[u8]] = &[b"www", b"example", b"com", b""];
796        cmp_iter(name!(root).iter(), &[b""]);
797        cmp_iter(name!(flat).iter(), labels);
798        cmp_iter(name!(once).iter(), labels);
799        cmp_iter(name!(twice).iter(), labels);
800    }
801
802    #[test]
803    fn iter_back() {
804        use crate::base::name::dname::test::cmp_iter_back;
805
806        let labels: &[&[u8]] = &[b"", b"com", b"example", b"www"];
807        cmp_iter_back(name!(root).iter(), &[b""]);
808        cmp_iter_back(name!(flat).iter(), labels);
809        cmp_iter_back(name!(once).iter(), labels);
810        cmp_iter_back(name!(twice).iter(), labels);
811    }
812
813    fn cmp_iter_suffixes<'a, I>(iter: I, labels: &[&[u8]])
814    where
815        I: Iterator<Item = ParsedDname<&'a [u8]>>,
816    {
817        for (name, labels) in iter.zip(labels) {
818            let mut iter = name.iter();
819            let labels = Dname::from_slice(labels).unwrap();
820            let mut labels_iter = labels.iter();
821            loop {
822                match (iter.next(), labels_iter.next()) {
823                    (Some(left), Some(right)) => assert_eq!(left, right),
824                    (None, None) => break,
825                    (_, None) => panic!("extra items in iterator"),
826                    (None, _) => panic!("missing items in iterator"),
827                }
828            }
829        }
830    }
831
832    #[test]
833    fn iter_suffixes() {
834        let suffixes: &[&[u8]] = &[
835            b"\x03www\x07example\x03com\0",
836            b"\x07example\x03com\0",
837            b"\x03com\0",
838            b"\0",
839        ];
840        cmp_iter_suffixes(name!(root).iter_suffixes(), &[b"\0"]);
841        cmp_iter_suffixes(name!(flat).iter_suffixes(), suffixes);
842        cmp_iter_suffixes(name!(once).iter_suffixes(), suffixes);
843        cmp_iter_suffixes(name!(twice).iter_suffixes(), suffixes);
844    }
845
846    #[test]
847    fn label_count() {
848        assert_eq!(name!(root).label_count(), 1);
849        assert_eq!(name!(flat).label_count(), 4);
850        assert_eq!(name!(once).label_count(), 4);
851        assert_eq!(name!(twice).label_count(), 4);
852    }
853
854    #[test]
855    fn first() {
856        assert_eq!(name!(root).first().as_slice(), b"");
857        assert_eq!(name!(flat).first().as_slice(), b"www");
858        assert_eq!(name!(once).first().as_slice(), b"www");
859        assert_eq!(name!(twice).first().as_slice(), b"www");
860    }
861
862    #[test]
863    fn starts_with() {
864        let root = name!(root);
865        let flat_wec = name!(flat);
866        let once_wec = name!(once);
867        let twice_wec = name!(twice);
868
869        let test = Dname::root_ref();
870        assert!(root.starts_with(&test));
871        assert!(!flat_wec.starts_with(&test));
872        assert!(!once_wec.starts_with(&test));
873        assert!(!twice_wec.starts_with(&test));
874
875        let test = RelativeDname::empty_ref();
876        assert!(root.starts_with(&test));
877        assert!(flat_wec.starts_with(&test));
878        assert!(once_wec.starts_with(&test));
879        assert!(twice_wec.starts_with(&test));
880
881        let test = RelativeDname::from_slice(b"\x03www").unwrap();
882        assert!(!root.starts_with(&test));
883        assert!(flat_wec.starts_with(&test));
884        assert!(once_wec.starts_with(&test));
885        assert!(twice_wec.starts_with(&test));
886
887        let test = RelativeDname::from_slice(b"\x03www\x07example").unwrap();
888        assert!(!root.starts_with(&test));
889        assert!(flat_wec.starts_with(&test));
890        assert!(once_wec.starts_with(&test));
891        assert!(twice_wec.starts_with(&test));
892
893        let test =
894            RelativeDname::from_slice(b"\x03www\x07example\x03com").unwrap();
895        assert!(!root.starts_with(&test));
896        assert!(flat_wec.starts_with(&test));
897        assert!(once_wec.starts_with(&test));
898        assert!(twice_wec.starts_with(&test));
899
900        let test = Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap();
901        assert!(!root.starts_with(&test));
902        assert!(flat_wec.starts_with(&test));
903        assert!(once_wec.starts_with(&test));
904        assert!(twice_wec.starts_with(&test));
905
906        let test = RelativeDname::from_slice(b"\x07example\x03com").unwrap();
907        assert!(!root.starts_with(&test));
908        assert!(!flat_wec.starts_with(&test));
909        assert!(!once_wec.starts_with(&test));
910        assert!(!twice_wec.starts_with(&test));
911
912        let test = RelativeDname::from_octets(b"\x03www".as_ref())
913            .unwrap()
914            .chain(
915                RelativeDname::from_octets(b"\x07example".as_ref()).unwrap(),
916            )
917            .unwrap();
918        assert!(!root.starts_with(&test));
919        assert!(flat_wec.starts_with(&test));
920        assert!(once_wec.starts_with(&test));
921        assert!(twice_wec.starts_with(&test));
922
923        let test = test
924            .chain(RelativeDname::from_octets(b"\x03com".as_ref()).unwrap())
925            .unwrap();
926        assert!(!root.starts_with(&test));
927        assert!(flat_wec.starts_with(&test));
928        assert!(once_wec.starts_with(&test));
929        assert!(twice_wec.starts_with(&test));
930    }
931
932    #[test]
933    fn ends_with() {
934        let root = name!(root);
935        let flat_wec = name!(flat);
936        let once_wec = name!(once);
937        let twice_wec = name!(twice);
938        let wecr =
939            Dname::from_octets(b"\x03www\x07example\x03com\0".as_ref())
940                .unwrap();
941
942        for name in wecr.iter_suffixes() {
943            if name.is_root() {
944                assert!(root.ends_with(&name))
945            } else {
946                assert!(!root.ends_with(&name))
947            }
948            assert!(flat_wec.ends_with(&name));
949            assert!(once_wec.ends_with(&name));
950            assert!(twice_wec.ends_with(&name));
951        }
952    }
953
954    #[test]
955    #[cfg(feature = "std")]
956    fn split_first() {
957        fn split_first_wec(mut name: ParsedDname<&[u8]>) {
958            assert_eq!(
959                name.to_vec().as_slice(),
960                b"\x03www\x07example\x03com\0"
961            );
962            assert_eq!(
963                name.split_first().unwrap().as_slice(),
964                b"\x03www".as_ref()
965            );
966            assert_eq!(name.to_vec().as_slice(), b"\x07example\x03com\0");
967            assert_eq!(
968                name.split_first().unwrap().as_slice(),
969                b"\x07example".as_ref()
970            );
971            assert_eq!(name.to_vec().as_slice(), b"\x03com\0");
972            assert_eq!(
973                name.split_first().unwrap().as_slice(),
974                b"\x03com".as_ref()
975            );
976            assert_eq!(name.to_vec().as_slice(), b"\0");
977            assert_eq!(name.split_first(), None);
978            assert_eq!(name.split_first(), None);
979        }
980
981        split_first_wec(name!(flat));
982        split_first_wec(name!(once));
983        split_first_wec(name!(twice));
984    }
985
986    #[test]
987    #[cfg(feature = "std")]
988    fn parent() {
989        fn parent_wec(mut name: ParsedDname<&[u8]>) {
990            assert_eq!(
991                name.to_vec().as_slice(),
992                b"\x03www\x07example\x03com\0"
993            );
994            assert!(name.parent());
995            assert_eq!(name.to_vec().as_slice(), b"\x07example\x03com\0");
996            assert!(name.parent());
997            assert_eq!(name.to_vec().as_slice(), b"\x03com\0");
998            assert!(name.parent());
999            assert_eq!(name.to_vec().as_slice(), b"\0");
1000            assert!(!name.parent());
1001            assert!(!name.parent());
1002        }
1003
1004        parent_wec(name!(flat));
1005        parent_wec(name!(once));
1006        parent_wec(name!(twice));
1007    }
1008
1009    #[test]
1010    #[cfg(feature = "std")]
1011    fn parse_and_skip() {
1012        use std::vec::Vec;
1013
1014        fn name_eq(parsed: ParsedDname<&[u8]>, name: ParsedDname<&[u8]>) {
1015            assert_eq!(parsed.octets, name.octets);
1016            assert_eq!(parsed.pos, name.pos);
1017            assert_eq!(parsed.name_len, name.name_len);
1018            assert_eq!(parsed.compressed, name.compressed);
1019        }
1020
1021        fn parse(
1022            mut parser: Parser<&[u8]>,
1023            equals: ParsedDname<&[u8]>,
1024            compose_len: usize,
1025        ) {
1026            let end = parser.pos() + compose_len;
1027            name_eq(ParsedDname::parse(&mut parser).unwrap(), equals);
1028            assert_eq!(parser.pos(), end);
1029        }
1030
1031        fn skip(name: ParsedDname<&[u8]>, len: usize) {
1032            let mut parser = name.parser();
1033            let pos = parser.pos();
1034            assert_eq!(ParsedDname::skip(&mut parser), Ok(()));
1035            assert_eq!(parser.pos(), pos + len);
1036        }
1037
1038        fn p(slice: &[u8], pos: usize) -> Parser<[u8]> {
1039            let mut res = Parser::from_ref(slice);
1040            res.advance(pos).unwrap();
1041            res
1042        }
1043
1044        // Correctly formatted names.
1045        parse(name!(root).parser(), name!(root), 1);
1046        parse(name!(flat).parser(), name!(flat), 17);
1047        parse(name!(copy).parser(), name!(flat), 2);
1048        parse(name!(once).parser(), name!(once), 14);
1049        parse(name!(twice).parser(), name!(twice), 6);
1050        skip(name!(root), 1);
1051        skip(name!(flat), 17);
1052        skip(name!(copy), 2);
1053        skip(name!(once), 14);
1054        skip(name!(twice), 6);
1055
1056        // Short buffer in the middle of a label.
1057        let mut parser = p(b"\x03www\x07exam", 0);
1058        assert_eq!(
1059            ParsedDname::parse(&mut parser.clone()),
1060            Err(ParseError::ShortInput)
1061        );
1062        assert_eq!(
1063            ParsedDname::skip(&mut parser),
1064            Err(ParseError::ShortInput)
1065        );
1066
1067        // Short buffer at end of label.
1068        let mut parser = p(b"\x03www\x07example", 0);
1069        assert_eq!(
1070            ParsedDname::parse(&mut parser.clone()),
1071            Err(ParseError::ShortInput)
1072        );
1073        assert_eq!(
1074            ParsedDname::skip(&mut parser),
1075            Err(ParseError::ShortInput)
1076        );
1077
1078        // Compression pointer beyond the end of buffer.
1079        let mut parser = p(b"\x03www\xc0\xee12", 0);
1080        assert!(ParsedDname::parse(&mut parser.clone()).is_err());
1081        assert_eq!(ParsedDname::skip(&mut parser), Ok(()));
1082        assert_eq!(parser.remaining(), 2);
1083
1084        // Compression pointer to itself
1085        assert!(ParsedDname::parse(&mut p(b"\x03www\xc0\x0412", 4)).is_err());
1086
1087        // Compression pointer forward
1088        assert!(ParsedDname::parse(&mut p(b"\x03www\xc0\x0612", 4)).is_err());
1089
1090        // Bad label header.
1091        let mut parser = p(b"\x03www\x07example\xbffoo", 0);
1092        assert!(ParsedDname::parse(&mut parser.clone()).is_err());
1093        assert!(ParsedDname::skip(&mut parser).is_err());
1094
1095        // Long name: 255 bytes is fine.
1096        let mut buf = Vec::from(&b"\x03123\0"[..]);
1097        for _ in 0..25 {
1098            buf.extend_from_slice(b"\x09123456789");
1099        }
1100        buf.extend_from_slice(b"\xc0\x0012");
1101        let mut parser = Parser::from_ref(buf.as_slice());
1102        parser.advance(5).unwrap();
1103        let name = ParsedDname::parse(&mut parser.clone()).unwrap();
1104        assert_eq!(name.compose_len(), 255);
1105        assert_eq!(ParsedDname::skip(&mut parser), Ok(()));
1106        assert_eq!(parser.remaining(), 2);
1107
1108        // Long name: 256 bytes are bad.
1109        let mut buf = Vec::from(&b"\x041234\x00"[..]);
1110        for _ in 0..25 {
1111            buf.extend_from_slice(b"\x09123456789");
1112        }
1113        buf.extend_from_slice(b"\xc0\x0012");
1114        let mut parser = Parser::from_ref(buf.as_slice());
1115        parser.advance(6).unwrap();
1116        assert!(ParsedDname::parse(&mut parser.clone()).is_err());
1117        assert_eq!(ParsedDname::skip(&mut parser), Ok(()));
1118        assert_eq!(parser.remaining(), 2);
1119
1120        // Long name through recursion
1121        let mut parser = p(b"\x03www\xc0\x0012", 0);
1122        assert!(ParsedDname::parse(&mut parser.clone()).is_err());
1123        assert_eq!(ParsedDname::skip(&mut parser), Ok(()));
1124        assert_eq!(parser.remaining(), 2);
1125
1126        // Single-step infinite recursion
1127        let mut parser = p(b"\xc0\x0012", 0);
1128        assert!(ParsedDname::parse(&mut parser.clone()).is_err());
1129        assert_eq!(ParsedDname::skip(&mut parser), Ok(()));
1130        assert_eq!(parser.remaining(), 2);
1131
1132        // Two-step infinite recursion
1133        let mut parser = p(b"\xc0\x02\xc0\x0012", 2);
1134        assert!(ParsedDname::parse(&mut parser.clone()).is_err());
1135        assert_eq!(ParsedDname::skip(&mut parser), Ok(()));
1136        assert_eq!(parser.remaining(), 2);
1137    }
1138
1139    #[test]
1140    #[cfg(feature = "std")]
1141    fn compose() {
1142        use octseq::builder::infallible;
1143        use std::vec::Vec;
1144
1145        fn step(name: ParsedDname<&[u8]>, result: &[u8]) {
1146            let mut buf = Vec::new();
1147            infallible(name.compose(&mut buf));
1148            assert_eq!(buf.as_slice(), result);
1149        }
1150
1151        step(name!(root), b"\x00");
1152        step(name!(flat), WECR);
1153        step(name!(once), WECR);
1154        step(name!(twice), WECR);
1155    }
1156
1157    // XXX TODO compose_canonical
1158
1159    #[test]
1160    fn as_flat_slice() {
1161        assert_eq!(name!(root).as_flat_slice(), Some(b"\x00".as_ref()));
1162        assert_eq!(name!(flat).as_flat_slice(), Some(WECR));
1163        assert_eq!(name!(once).as_flat_slice(), None);
1164        assert_eq!(name!(twice).as_flat_slice(), None);
1165    }
1166
1167    #[test]
1168    fn eq() {
1169        fn step<N: ToDname + fmt::Debug>(name: N) {
1170            assert_eq!(name!(flat), &name);
1171            assert_eq!(name!(once), &name);
1172            assert_eq!(name!(twice), &name);
1173        }
1174
1175        fn ne_step<N: ToDname + fmt::Debug>(name: N) {
1176            assert_ne!(name!(flat), &name);
1177            assert_ne!(name!(once), &name);
1178            assert_ne!(name!(twice), &name);
1179        }
1180
1181        step(name!(flat));
1182        step(name!(once));
1183        step(name!(twice));
1184
1185        step(Dname::from_slice(b"\x03www\x07example\x03com\x00").unwrap());
1186        step(Dname::from_slice(b"\x03wWw\x07EXAMPLE\x03com\x00").unwrap());
1187        step(
1188            RelativeDname::from_octets(b"\x03www\x07example\x03com")
1189                .unwrap()
1190                .chain_root(),
1191        );
1192        step(
1193            RelativeDname::from_octets(b"\x03www\x07example")
1194                .unwrap()
1195                .chain(Dname::from_octets(b"\x03com\x00").unwrap())
1196                .unwrap(),
1197        );
1198
1199        ne_step(Dname::from_slice(b"\x03ww4\x07EXAMPLE\x03com\x00").unwrap());
1200    }
1201
1202    // XXX TODO Test for cmp and hash.
1203}