domain/base/name/
chain.rs

1//! A chain of domain names.
2//!
3//! This is a private module. Its public types are re-exported by the parent
4//! crate.
5
6use super::super::scan::Scanner;
7use super::label::Label;
8use super::relative::NameIter;
9use super::traits::{FlattenInto, ToLabelIter, ToName, ToRelativeName};
10use super::uncertain::UncertainName;
11use super::Name;
12use core::{fmt, iter};
13use octseq::builder::{
14    BuilderAppendError, EmptyBuilder, FreezeBuilder, FromBuilder,
15};
16
17//------------ Chain ---------------------------------------------------------
18
19/// Two domain names chained together.
20///
21/// This type is the result of calling [`RelativeName::chain`],
22/// [`UncertainName::chain`], or [`Chain::chain`].
23///
24/// The chain can be both an absolute or relative domain name—and implements
25/// the respective traits [`ToName`] or [`ToRelativeName`]—, depending on
26/// whether the second name is absolute or relative.
27///
28/// A chain on an uncertain name is special in that the second name is only
29/// used if the uncertain name is relative.
30///
31/// [`RelativeName::chain`]: super::RelativeName::chain
32#[derive(Clone, Debug)]
33#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
34pub struct Chain<L, R> {
35    /// The first domain name.
36    left: L,
37
38    /// The second domain name.
39    right: R,
40}
41
42impl<L: ToLabelIter, R: ToLabelIter> Chain<L, R> {
43    /// Creates a new chain from a first and second name.
44    pub(super) fn new(left: L, right: R) -> Result<Self, LongChainError> {
45        if usize::from(left.compose_len() + right.compose_len())
46            > Name::MAX_LEN
47        {
48            // TODO can't infer a specific type for Name here
49            Err(LongChainError(()))
50        } else {
51            Ok(Chain { left, right })
52        }
53    }
54}
55
56impl<Octets: AsRef<[u8]>, R: ToLabelIter> Chain<UncertainName<Octets>, R> {
57    /// Creates a chain from an uncertain name.
58    ///
59    /// This function is separate because the ultimate size depends on the
60    /// variant of the left name.
61    pub(super) fn new_uncertain(
62        left: UncertainName<Octets>,
63        right: R,
64    ) -> Result<Self, LongChainError> {
65        if let UncertainName::Relative(ref name) = left {
66            if usize::from(name.compose_len() + right.compose_len())
67                > Name::MAX_LEN
68            {
69                return Err(LongChainError(()));
70            }
71        }
72        Ok(Chain { left, right })
73    }
74}
75
76impl<L, R> Chain<L, R> {
77    pub fn scan<S: Scanner<Name = Self>>(
78        scanner: &mut S,
79    ) -> Result<Self, S::Error> {
80        scanner.scan_name()
81    }
82}
83
84impl<L: ToRelativeName, R: ToLabelIter> Chain<L, R> {
85    /// Extends the chain with another domain name.
86    ///
87    /// While the method accepts anything [`Compose`] as the second element of
88    /// the chain, the resulting `Chain` will only implement [`ToName`] or
89    /// [`ToRelativeName`] if if also implements [`ToName`] or
90    /// [`ToRelativeName`], respectively.
91    ///
92    /// The method will fail with an error if the chained name is longer than
93    /// 255 bytes.
94    ///
95    /// [`Compose`]: crate::base::wire::Compose
96    pub fn chain<N: ToLabelIter>(
97        self,
98        other: N,
99    ) -> Result<Chain<Self, N>, LongChainError> {
100        Chain::new(self, other)
101    }
102}
103
104impl<L, R> Chain<L, R>
105where
106    Self: ToLabelIter,
107{
108    /// Returns an object that displays an absolute name with a final dot.
109    ///
110    /// The chain itself displays without a final dot unless the chain
111    /// results in an absolute name with the root label only. This method can
112    /// be used to display a chain that results in an absolute name with a
113    /// single dot at its end.
114    pub fn fmt_with_dot(&self) -> impl fmt::Display + '_ {
115        DisplayWithDot(self)
116    }
117}
118
119impl<L, R> Chain<L, R> {
120    /// Unwraps the chain into its two constituent components.
121    pub fn unwrap(self) -> (L, R) {
122        (self.left, self.right)
123    }
124}
125
126//--- ToLabelIter, ToRelativeName, ToName
127
128impl<L: ToRelativeName, R: ToLabelIter> ToLabelIter for Chain<L, R> {
129    type LabelIter<'a>
130        = ChainIter<'a, L, R>
131    where
132        L: 'a,
133        R: 'a;
134
135    fn iter_labels(&self) -> Self::LabelIter<'_> {
136        ChainIter(self.left.iter_labels().chain(self.right.iter_labels()))
137    }
138
139    fn compose_len(&self) -> u16 {
140        self.left
141            .compose_len()
142            .checked_add(self.right.compose_len())
143            .expect("long domain name")
144    }
145}
146
147impl<Octs, R> ToLabelIter for Chain<UncertainName<Octs>, R>
148where
149    Octs: AsRef<[u8]>,
150    R: ToName,
151{
152    type LabelIter<'a>
153        = UncertainChainIter<'a, Octs, R>
154    where
155        Octs: 'a,
156        R: 'a;
157
158    fn iter_labels(&self) -> Self::LabelIter<'_> {
159        match self.left {
160            UncertainName::Absolute(ref name) => {
161                UncertainChainIter::Absolute(name.iter_labels())
162            }
163            UncertainName::Relative(ref name) => {
164                UncertainChainIter::Relative(ChainIter(
165                    name.iter_labels().chain(self.right.iter_labels()),
166                ))
167            }
168        }
169    }
170
171    fn compose_len(&self) -> u16 {
172        match self.left {
173            UncertainName::Absolute(ref name) => name.compose_len(),
174            UncertainName::Relative(ref name) => name
175                .compose_len()
176                .checked_add(self.right.compose_len())
177                .expect("long domain name"),
178        }
179    }
180}
181
182impl<L: ToRelativeName, R: ToRelativeName> ToRelativeName for Chain<L, R> {}
183
184impl<L: ToRelativeName, R: ToName> ToName for Chain<L, R> {}
185
186impl<Octets, R> ToName for Chain<UncertainName<Octets>, R>
187where
188    Octets: AsRef<[u8]>,
189    R: ToName,
190{
191}
192
193//--- FlattenInto
194
195impl<L, R, Target> FlattenInto<Name<Target>> for Chain<L, R>
196where
197    L: ToRelativeName,
198    R: ToName,
199    R: FlattenInto<Name<Target>, AppendError = BuilderAppendError<Target>>,
200    Target: FromBuilder,
201    <Target as FromBuilder>::Builder: EmptyBuilder,
202{
203    type AppendError = BuilderAppendError<Target>;
204
205    fn try_flatten_into(self) -> Result<Name<Target>, Self::AppendError> {
206        if self.left.is_empty() {
207            self.right.try_flatten_into()
208        } else {
209            let mut builder =
210                Target::Builder::with_capacity(self.compose_len().into());
211            self.compose(&mut builder)?;
212            Ok(unsafe { Name::from_octets_unchecked(builder.freeze()) })
213        }
214    }
215}
216
217//--- Display
218
219impl<L, R> fmt::Display for Chain<L, R>
220where
221    Self: ToLabelIter,
222{
223    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
224        let mut empty = true;
225        for label in self.iter_labels() {
226            if label.is_root() {
227                if empty {
228                    f.write_str(".")?
229                }
230            } else {
231                if !empty {
232                    f.write_str(".")?
233                } else {
234                    empty = false;
235                }
236                label.fmt(f)?;
237            }
238        }
239        Ok(())
240    }
241}
242
243//------------ ChainIter -----------------------------------------------------
244
245/// The label iterator for chained domain names.
246#[derive(Debug)]
247pub struct ChainIter<'a, L: ToLabelIter + 'a, R: ToLabelIter + 'a>(
248    iter::Chain<L::LabelIter<'a>, R::LabelIter<'a>>,
249);
250
251impl<L, R> Clone for ChainIter<'_, L, R>
252where
253    L: ToLabelIter,
254    R: ToLabelIter,
255{
256    fn clone(&self) -> Self {
257        ChainIter(self.0.clone())
258    }
259}
260
261impl<'a, L, R> Iterator for ChainIter<'a, L, R>
262where
263    L: ToLabelIter,
264    R: ToLabelIter,
265{
266    type Item = &'a Label;
267
268    fn next(&mut self) -> Option<Self::Item> {
269        self.0.next()
270    }
271}
272
273impl<L, R> DoubleEndedIterator for ChainIter<'_, L, R>
274where
275    L: ToLabelIter,
276    R: ToLabelIter,
277{
278    fn next_back(&mut self) -> Option<Self::Item> {
279        self.0.next_back()
280    }
281}
282
283//------------ UncertainChainIter --------------------------------------------
284
285/// The label iterator for domain name chains with uncertain domain names.
286pub enum UncertainChainIter<'a, Octets: AsRef<[u8]>, R: ToLabelIter> {
287    Absolute(NameIter<'a>),
288    Relative(ChainIter<'a, UncertainName<Octets>, R>),
289}
290
291impl<Octets, R> Clone for UncertainChainIter<'_, Octets, R>
292where
293    Octets: AsRef<[u8]>,
294    R: ToLabelIter,
295{
296    fn clone(&self) -> Self {
297        use UncertainChainIter::*;
298
299        match *self {
300            Absolute(ref inner) => Absolute(inner.clone()),
301            Relative(ref inner) => Relative(inner.clone()),
302        }
303    }
304}
305
306impl<'a, Octets, R> Iterator for UncertainChainIter<'a, Octets, R>
307where
308    Octets: AsRef<[u8]>,
309    R: ToLabelIter,
310{
311    type Item = &'a Label;
312
313    fn next(&mut self) -> Option<Self::Item> {
314        match *self {
315            UncertainChainIter::Absolute(ref mut inner) => inner.next(),
316            UncertainChainIter::Relative(ref mut inner) => inner.next(),
317        }
318    }
319}
320
321impl<Octets, R> DoubleEndedIterator for UncertainChainIter<'_, Octets, R>
322where
323    Octets: AsRef<[u8]>,
324    R: ToLabelIter,
325{
326    fn next_back(&mut self) -> Option<Self::Item> {
327        match *self {
328            UncertainChainIter::Absolute(ref mut inner) => inner.next_back(),
329            UncertainChainIter::Relative(ref mut inner) => inner.next_back(),
330        }
331    }
332}
333
334//------------ DisplayWithDot ------------------------------------------------
335
336struct DisplayWithDot<'a, L, R>(&'a Chain<L, R>);
337
338impl<L, R> fmt::Display for DisplayWithDot<'_, L, R>
339where
340    Chain<L, R>: ToLabelIter,
341{
342    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
343        let mut empty = true;
344        for label in self.0.iter_labels() {
345            if label.is_root() {
346                f.write_str(".")?
347            } else {
348                if !empty {
349                    f.write_str(".")?
350                } else {
351                    empty = false;
352                }
353                label.fmt(f)?;
354            }
355        }
356        Ok(())
357    }
358}
359
360//============ Error Types ===================================================
361
362//------------ LongChainError ------------------------------------------------
363
364/// Chaining domain names would exceed the size limit.
365#[derive(Clone, Copy, Debug, Eq, PartialEq)]
366pub struct LongChainError(());
367
368//--- Display and Error
369
370impl fmt::Display for LongChainError {
371    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
372        f.write_str("long domain name")
373    }
374}
375
376#[cfg(feature = "std")]
377impl std::error::Error for LongChainError {}
378
379//============ Testing =======================================================
380
381#[cfg(test)]
382#[cfg(feature = "std")]
383mod test {
384    use super::*;
385    use crate::base::name::RelativeName;
386    use octseq::builder::infallible;
387
388    /// Tests that `ToName` and `ToRelativeName` are implemented for the
389    /// right types.
390    #[test]
391    #[cfg(feature = "std")]
392    fn impls() {
393        fn assert_to_name<T: ToName>(_: &T) {}
394        fn assert_to_relative_name<T: ToRelativeName>(_: &T) {}
395
396        let rel = RelativeName::empty_ref()
397            .chain(RelativeName::empty_ref())
398            .unwrap();
399        assert_to_relative_name(&rel);
400        assert_to_name(
401            &RelativeName::empty_ref().chain(Name::root_ref()).unwrap(),
402        );
403        assert_to_name(
404            &RelativeName::empty_ref()
405                .chain(RelativeName::empty_ref())
406                .unwrap()
407                .chain(Name::root_ref())
408                .unwrap(),
409        );
410        assert_to_name(&rel.clone().chain(Name::root_ref()).unwrap());
411        assert_to_relative_name(
412            &rel.chain(RelativeName::empty_ref()).unwrap(),
413        );
414        assert_to_name(
415            &UncertainName::root_vec().chain(Name::root_vec()).unwrap(),
416        );
417        assert_to_name(
418            &UncertainName::empty_vec().chain(Name::root_vec()).unwrap(),
419        );
420    }
421
422    /// Tests that a chain never becomes too long.
423    #[test]
424    fn name_limit() {
425        use crate::base::name::NameBuilder;
426
427        let mut builder = NameBuilder::new_vec();
428        for _ in 0..25 {
429            // 9 bytes label is 10 bytes in total
430            builder.append_label(b"123456789").unwrap();
431        }
432        let left = builder.finish();
433        assert_eq!(left.len(), 250);
434
435        let mut builder = NameBuilder::new_vec();
436        builder.append_slice(b"123").unwrap();
437        let five_abs = builder.clone().into_name().unwrap();
438        assert_eq!(five_abs.len(), 5);
439        builder.push(b'4').unwrap();
440        let five_rel = builder.clone().finish();
441        assert_eq!(five_rel.len(), 5);
442        let six_abs = builder.clone().into_name().unwrap();
443        assert_eq!(six_abs.len(), 6);
444        builder.push(b'5').unwrap();
445        let six_rel = builder.finish();
446        assert_eq!(six_rel.len(), 6);
447
448        assert_eq!(
449            left.clone().chain(five_abs.clone()).unwrap().compose_len(),
450            255
451        );
452        assert_eq!(
453            left.clone().chain(five_rel.clone()).unwrap().compose_len(),
454            255
455        );
456        assert!(left.clone().chain(six_abs.clone()).is_err());
457        assert!(left.clone().chain(six_rel).is_err());
458        assert!(left
459            .clone()
460            .chain(five_rel.clone())
461            .unwrap()
462            .chain(five_abs.clone())
463            .is_err());
464        assert!(left
465            .clone()
466            .chain(five_rel.clone())
467            .unwrap()
468            .chain(five_rel)
469            .is_err());
470
471        let left = UncertainName::from(left);
472        assert_eq!(left.clone().chain(five_abs).unwrap().compose_len(), 255);
473        assert!(left.clone().chain(six_abs.clone()).is_err());
474
475        let left = UncertainName::from(left.into_absolute().unwrap());
476        println!("{:?}", left);
477        assert_eq!(left.chain(six_abs).unwrap().compose_len(), 251);
478    }
479
480    /// Checks the impl of ToLabelIter: iter_labels and compose_len.
481    #[test]
482    fn to_label_iter_impl() {
483        fn check_impl<N: ToLabelIter>(name: N, labels: &[&[u8]]) {
484            let labels = labels.iter().map(|s| Label::from_slice(s).unwrap());
485            assert!(name.iter_labels().eq(labels));
486            assert_eq!(
487                name.iter_labels().map(|l| l.compose_len()).sum::<u16>(),
488                name.compose_len()
489            );
490        }
491
492        let w = RelativeName::from_octets(b"\x03www".as_ref()).unwrap();
493        let ec = RelativeName::from_octets(b"\x07example\x03com".as_ref())
494            .unwrap();
495        let ecr =
496            Name::from_octets(b"\x07example\x03com\x00".as_ref()).unwrap();
497        let fbr = Name::from_octets(b"\x03foo\x03bar\x00".as_ref()).unwrap();
498
499        check_impl(
500            w.clone().chain(ec.clone()).unwrap(),
501            &[b"www", b"example", b"com"],
502        );
503        check_impl(
504            w.clone().chain(ecr.clone()).unwrap(),
505            &[b"www", b"example", b"com", b""],
506        );
507        check_impl(
508            w.clone()
509                .chain(ec.clone())
510                .unwrap()
511                .chain(Name::root_ref())
512                .unwrap(),
513            &[b"www", b"example", b"com", b""],
514        );
515        check_impl(
516            RelativeName::empty_slice()
517                .chain(Name::root_slice())
518                .unwrap(),
519            &[b""],
520        );
521
522        check_impl(
523            UncertainName::from(w.clone()).chain(ecr.clone()).unwrap(),
524            &[b"www", b"example", b"com", b""],
525        );
526        check_impl(
527            UncertainName::from(ecr.clone()).chain(fbr.clone()).unwrap(),
528            &[b"example", b"com", b""],
529        );
530    }
531
532    /// Tests that composing works as expected.
533    #[test]
534    fn compose() {
535        use std::vec::Vec;
536
537        let w = RelativeName::from_octets(b"\x03www".as_ref()).unwrap();
538        let ec = RelativeName::from_octets(b"\x07example\x03com".as_ref())
539            .unwrap();
540        let ecr =
541            Name::from_octets(b"\x07example\x03com\x00".as_ref()).unwrap();
542        let fbr = Name::from_octets(b"\x03foo\x03bar\x00".as_ref()).unwrap();
543
544        let mut buf = Vec::new();
545        infallible(w.clone().chain(ec.clone()).unwrap().compose(&mut buf));
546        assert_eq!(buf, b"\x03www\x07example\x03com".as_ref());
547
548        let mut buf = Vec::new();
549        infallible(w.clone().chain(ecr.clone()).unwrap().compose(&mut buf));
550        assert_eq!(buf, b"\x03www\x07example\x03com\x00");
551
552        let mut buf = Vec::new();
553        infallible(
554            w.clone()
555                .chain(ec.clone())
556                .unwrap()
557                .chain(Name::root_ref())
558                .unwrap()
559                .compose(&mut buf),
560        );
561        assert_eq!(buf, b"\x03www\x07example\x03com\x00");
562
563        let mut buf = Vec::new();
564        infallible(
565            UncertainName::from(w.clone())
566                .chain(ecr.clone())
567                .unwrap()
568                .compose(&mut buf),
569        );
570        assert_eq!(buf, b"\x03www\x07example\x03com\x00");
571
572        let mut buf = Vec::new();
573        infallible(
574            UncertainName::from(ecr.clone())
575                .chain(fbr.clone())
576                .unwrap()
577                .compose(&mut buf),
578        );
579        assert_eq!(buf, b"\x07example\x03com\x00");
580    }
581
582    /// Tests that displaying works as expected.
583    ///
584    /// The tricky bit is to produce to correct number of dots between the
585    /// left and the right part and at the end of the chain. This is made
586    /// difficult by empty relative names and absolute root names. So this
587    /// is what we are testing below in a number of combinations.
588    #[test]
589    fn display() {
590        fn cmp<E: fmt::Debug, L, R>(
591            chain: Result<Chain<L, R>, E>,
592            out: &str,
593            dot_out: &str,
594        ) where
595            Chain<L, R>: ToLabelIter,
596        {
597            use std::string::ToString;
598
599            let chain = chain.unwrap();
600            assert_eq!(chain.to_string(), out);
601            assert_eq!(chain.fmt_with_dot().to_string(), dot_out);
602        }
603
604        // An empty relative name.
605        let empty = &RelativeName::from_octets(b"".as_slice()).unwrap();
606
607        // An empty relative name wrapped in an uncertain name.
608        let uempty = &UncertainName::from(empty.clone());
609
610        // A non-empty relative name. We are using two labels here just to
611        // have that covered as well.
612        let rel =
613            &RelativeName::from_octets(b"\x03www\x07example".as_slice())
614                .unwrap();
615
616        // A non-empty relative name wrapped in an uncertain name.
617        let urel = &UncertainName::from(rel.clone());
618
619        // The root name which is an absolute name.
620        let root = &Name::from_octets(b"\0".as_slice()).unwrap();
621
622        // The root name wrapped in an uncertain name.
623        let uroot = &UncertainName::from(root.clone());
624
625        // A “normal” absolute name.
626        let abs = &Name::from_octets(b"\x03com\0".as_slice()).unwrap();
627
628        // A “normal” absolute name wrapped in an uncertain name.
629        let uabs = &UncertainName::from(abs.clone());
630
631        // Now we produce all possible cases and their expected result. First
632        // result is for normal display, second is for fmt_with_dot.
633        //
634        // If the left side of the chain is a relative name,
635        // the right side can be relative, absolute, or uncertain.
636        cmp(empty.chain(empty), "", "");
637        cmp(empty.chain(uempty), "", "");
638        cmp(empty.chain(rel), "www.example", "www.example");
639        cmp(empty.chain(urel), "www.example", "www.example");
640        cmp(empty.chain(root), ".", ".");
641        cmp(empty.chain(uroot), ".", ".");
642        cmp(empty.chain(abs), "com", "com.");
643        cmp(empty.chain(uabs), "com", "com.");
644
645        cmp(rel.chain(empty), "www.example", "www.example");
646        cmp(rel.chain(uempty), "www.example", "www.example");
647        cmp(
648            rel.chain(rel),
649            "www.example.www.example",
650            "www.example.www.example",
651        );
652        cmp(
653            rel.chain(urel),
654            "www.example.www.example",
655            "www.example.www.example",
656        );
657        cmp(rel.chain(root), "www.example", "www.example.");
658        cmp(rel.chain(uroot), "www.example", "www.example.");
659        cmp(rel.chain(abs), "www.example.com", "www.example.com.");
660        cmp(rel.chain(uabs), "www.example.com", "www.example.com.");
661
662        // If the left side of a chain is an uncertain name, the right side
663        // must be an absolute name.
664        cmp(uempty.clone().chain(root), ".", ".");
665        cmp(uempty.clone().chain(abs), "com", "com.");
666        cmp(urel.clone().chain(root), "www.example", "www.example.");
667        cmp(
668            urel.clone().chain(abs),
669            "www.example.com",
670            "www.example.com.",
671        );
672        cmp(uroot.clone().chain(root), ".", ".");
673        cmp(uroot.clone().chain(abs), ".", ".");
674        cmp(uabs.clone().chain(root), "com", "com.");
675        cmp(uabs.clone().chain(abs), "com", "com.");
676    }
677}