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::DnameIter;
9use super::traits::{FlattenInto, ToDname, ToLabelIter, ToRelativeDname};
10use super::uncertain::UncertainDname;
11use super::Dname;
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 the `chain` method on
22/// [`RelativeDname`], [`UncertainDname`], or on [`Chain`] itself.
23///
24/// The chain can be both an absolute or relative domain name—and implements
25/// the respective traits [`ToDname`] or [`ToRelativeDname`]—, 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/// [`RelativeDname`]: struct.RelativeDname.html#method.chain
32/// [`Chain`]: #method.chain
33/// [`ToDname`]: trait.ToDname.html
34/// [`ToRelativeDname`]: trait.ToRelativeDname.html
35/// [`UncertainDname`]: struct.UncertainDname.html#method.chain
36#[derive(Clone, Debug)]
37#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
38pub struct Chain<L, R> {
39    /// The first domain name.
40    left: L,
41
42    /// The second domain name.
43    right: R,
44}
45
46impl<L: ToLabelIter, R: ToLabelIter> Chain<L, R> {
47    /// Creates a new chain from a first and second name.
48    pub(super) fn new(left: L, right: R) -> Result<Self, LongChainError> {
49        if usize::from(left.compose_len() + right.compose_len())
50            > Dname::MAX_LEN
51        {
52            // TODO can't infer a specific type for Dname here
53            Err(LongChainError)
54        } else {
55            Ok(Chain { left, right })
56        }
57    }
58}
59
60impl<Octets: AsRef<[u8]>, R: ToLabelIter> Chain<UncertainDname<Octets>, R> {
61    /// Creates a chain from an uncertain name.
62    ///
63    /// This function is separate because the ultimate size depends on the
64    /// variant of the left name.
65    pub(super) fn new_uncertain(
66        left: UncertainDname<Octets>,
67        right: R,
68    ) -> Result<Self, LongChainError> {
69        if let UncertainDname::Relative(ref name) = left {
70            if usize::from(name.compose_len() + right.compose_len())
71                > Dname::MAX_LEN
72            {
73                return Err(LongChainError);
74            }
75        }
76        Ok(Chain { left, right })
77    }
78}
79
80impl<L, R> Chain<L, R> {
81    pub fn scan<S: Scanner<Dname = Self>>(
82        scanner: &mut S,
83    ) -> Result<Self, S::Error> {
84        scanner.scan_dname()
85    }
86}
87
88impl<L: ToRelativeDname, R: ToLabelIter> Chain<L, R> {
89    /// Extends the chain with another domain name.
90    ///
91    /// While the method accepts anything [`Compose`] as the second element of
92    /// the chain, the resulting `Chain` will only implement [`ToDname`] or
93    /// [`ToRelativeDname`] if if also implements [`ToDname`] or
94    /// [`ToRelativeDname`], respectively.
95    ///
96    /// The method will fail with an error if the chained name is longer than
97    /// 255 bytes.
98    ///
99    /// [`Compose`]: ../compose/trait.Compose.html
100    /// [`ToDname`]: trait.ToDname.html
101    /// [`ToRelativeDname`]: trait.ToRelativeDname.html
102    pub fn chain<N: ToLabelIter>(
103        self,
104        other: N,
105    ) -> Result<Chain<Self, N>, LongChainError> {
106        Chain::new(self, other)
107    }
108}
109
110impl<L, R> Chain<L, R> {
111    /// Unwraps the chain into its two constituent components.
112    pub fn unwrap(self) -> (L, R) {
113        (self.left, self.right)
114    }
115}
116
117//--- ToLabelIter, ToRelativeDname, ToDname
118
119impl<L: ToRelativeDname, R: ToLabelIter> ToLabelIter for Chain<L, R> {
120    type LabelIter<'a> = ChainIter<'a, L, R> where L: 'a, R: 'a;
121
122    fn iter_labels(&self) -> Self::LabelIter<'_> {
123        ChainIter(self.left.iter_labels().chain(self.right.iter_labels()))
124    }
125
126    fn compose_len(&self) -> u16 {
127        self.left
128            .compose_len()
129            .checked_add(self.right.compose_len())
130            .expect("long domain name")
131    }
132}
133
134impl<Octs, R> ToLabelIter for Chain<UncertainDname<Octs>, R>
135where
136    Octs: AsRef<[u8]>,
137    R: ToDname,
138{
139    type LabelIter<'a> = UncertainChainIter<'a, Octs, R>
140        where Octs: 'a, R: 'a;
141
142    fn iter_labels(&self) -> Self::LabelIter<'_> {
143        match self.left {
144            UncertainDname::Absolute(ref name) => {
145                UncertainChainIter::Absolute(name.iter_labels())
146            }
147            UncertainDname::Relative(ref name) => {
148                UncertainChainIter::Relative(ChainIter(
149                    name.iter_labels().chain(self.right.iter_labels()),
150                ))
151            }
152        }
153    }
154
155    fn compose_len(&self) -> u16 {
156        match self.left {
157            UncertainDname::Absolute(ref name) => name.compose_len(),
158            UncertainDname::Relative(ref name) => name
159                .compose_len()
160                .checked_add(self.right.compose_len())
161                .expect("long domain name"),
162        }
163    }
164}
165
166impl<L: ToRelativeDname, R: ToRelativeDname> ToRelativeDname for Chain<L, R> {}
167
168impl<L: ToRelativeDname, R: ToDname> ToDname for Chain<L, R> {}
169
170impl<Octets, R> ToDname for Chain<UncertainDname<Octets>, R>
171where
172    Octets: AsRef<[u8]>,
173    R: ToDname,
174{
175}
176
177//--- FlattenInto
178
179impl<L, R, Target> FlattenInto<Dname<Target>> for Chain<L, R>
180where
181    L: ToRelativeDname,
182    R: ToDname,
183    R: FlattenInto<Dname<Target>, AppendError = BuilderAppendError<Target>>,
184    Target: FromBuilder,
185    <Target as FromBuilder>::Builder: EmptyBuilder,
186{
187    type AppendError = BuilderAppendError<Target>;
188
189    fn try_flatten_into(self) -> Result<Dname<Target>, Self::AppendError> {
190        if self.left.is_empty() {
191            self.right.try_flatten_into()
192        } else {
193            let mut builder =
194                Target::Builder::with_capacity(self.compose_len().into());
195            self.compose(&mut builder)?;
196            Ok(unsafe { Dname::from_octets_unchecked(builder.freeze()) })
197        }
198    }
199}
200
201//--- Display
202
203impl<L: fmt::Display, R: fmt::Display> fmt::Display for Chain<L, R> {
204    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
205        write!(f, "{}.{}", self.left, self.right)
206    }
207}
208
209//------------ ChainIter -----------------------------------------------------
210
211/// The label iterator for chained domain names.
212#[derive(Debug)]
213pub struct ChainIter<'a, L: ToLabelIter + 'a, R: ToLabelIter + 'a>(
214    iter::Chain<L::LabelIter<'a>, R::LabelIter<'a>>,
215);
216
217impl<'a, L, R> Clone for ChainIter<'a, L, R>
218where
219    L: ToLabelIter,
220    R: ToLabelIter,
221{
222    fn clone(&self) -> Self {
223        ChainIter(self.0.clone())
224    }
225}
226
227impl<'a, L, R> Iterator for ChainIter<'a, L, R>
228where
229    L: ToLabelIter,
230    R: ToLabelIter,
231{
232    type Item = &'a Label;
233
234    fn next(&mut self) -> Option<Self::Item> {
235        self.0.next()
236    }
237}
238
239impl<'a, L, R> DoubleEndedIterator for ChainIter<'a, L, R>
240where
241    L: ToLabelIter,
242    R: ToLabelIter,
243{
244    fn next_back(&mut self) -> Option<Self::Item> {
245        self.0.next_back()
246    }
247}
248
249//------------ UncertainChainIter --------------------------------------------
250
251/// The label iterator for domain name chains with uncertain domain names.
252pub enum UncertainChainIter<'a, Octets: AsRef<[u8]>, R: ToLabelIter> {
253    Absolute(DnameIter<'a>),
254    Relative(ChainIter<'a, UncertainDname<Octets>, R>),
255}
256
257impl<'a, Octets, R> Clone for UncertainChainIter<'a, Octets, R>
258where
259    Octets: AsRef<[u8]>,
260    R: ToLabelIter,
261{
262    fn clone(&self) -> Self {
263        use UncertainChainIter::*;
264
265        match *self {
266            Absolute(ref inner) => Absolute(inner.clone()),
267            Relative(ref inner) => Relative(inner.clone()),
268        }
269    }
270}
271
272impl<'a, Octets, R> Iterator for UncertainChainIter<'a, Octets, R>
273where
274    Octets: AsRef<[u8]>,
275    R: ToLabelIter,
276{
277    type Item = &'a Label;
278
279    fn next(&mut self) -> Option<Self::Item> {
280        match *self {
281            UncertainChainIter::Absolute(ref mut inner) => inner.next(),
282            UncertainChainIter::Relative(ref mut inner) => inner.next(),
283        }
284    }
285}
286
287impl<'a, Octets, R> DoubleEndedIterator for UncertainChainIter<'a, Octets, R>
288where
289    Octets: AsRef<[u8]>,
290    R: ToLabelIter,
291{
292    fn next_back(&mut self) -> Option<Self::Item> {
293        match *self {
294            UncertainChainIter::Absolute(ref mut inner) => inner.next_back(),
295            UncertainChainIter::Relative(ref mut inner) => inner.next_back(),
296        }
297    }
298}
299
300//============ Error Types ===================================================
301
302//------------ LongChainError ------------------------------------------------
303
304/// Chaining domain names would exceed the size limit.
305#[derive(Clone, Copy, Debug, Eq, PartialEq)]
306pub struct LongChainError;
307
308//--- Display and Error
309
310impl fmt::Display for LongChainError {
311    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
312        f.write_str("long domain name")
313    }
314}
315
316#[cfg(feature = "std")]
317impl std::error::Error for LongChainError {}
318
319//============ Testing =======================================================
320
321#[cfg(test)]
322#[cfg(feature = "std")]
323mod test {
324    use super::*;
325    use crate::base::name::{Dname, RelativeDname, ToLabelIter};
326    use octseq::builder::infallible;
327
328    /// Tests that `ToDname` and `ToRelativeDname` are implemented for the
329    /// right types.
330    #[test]
331    #[cfg(feature = "std")]
332    fn impls() {
333        fn assert_to_dname<T: ToDname>(_: &T) {}
334        fn assert_to_relative_dname<T: ToRelativeDname>(_: &T) {}
335
336        let rel = RelativeDname::empty_ref()
337            .chain(RelativeDname::empty_ref())
338            .unwrap();
339        assert_to_relative_dname(&rel);
340        assert_to_dname(
341            &RelativeDname::empty_ref().chain(Dname::root_ref()).unwrap(),
342        );
343        assert_to_dname(
344            &RelativeDname::empty_ref()
345                .chain(RelativeDname::empty_ref())
346                .unwrap()
347                .chain(Dname::root_ref())
348                .unwrap(),
349        );
350        assert_to_dname(&rel.clone().chain(Dname::root_ref()).unwrap());
351        assert_to_relative_dname(
352            &rel.chain(RelativeDname::empty_ref()).unwrap(),
353        );
354        assert_to_dname(
355            &UncertainDname::root_vec().chain(Dname::root_vec()).unwrap(),
356        );
357        assert_to_dname(
358            &UncertainDname::empty_vec()
359                .chain(Dname::root_vec())
360                .unwrap(),
361        );
362    }
363
364    /// Tests that a chain never becomes too long.
365    #[test]
366    fn name_limit() {
367        use crate::base::name::DnameBuilder;
368
369        let mut builder = DnameBuilder::new_vec();
370        for _ in 0..25 {
371            // 9 bytes label is 10 bytes in total
372            builder.append_label(b"123456789").unwrap();
373        }
374        let left = builder.finish();
375        assert_eq!(left.len(), 250);
376
377        let mut builder = DnameBuilder::new_vec();
378        builder.append_slice(b"123").unwrap();
379        let five_abs = builder.clone().into_dname().unwrap();
380        assert_eq!(five_abs.len(), 5);
381        builder.push(b'4').unwrap();
382        let five_rel = builder.clone().finish();
383        assert_eq!(five_rel.len(), 5);
384        let six_abs = builder.clone().into_dname().unwrap();
385        assert_eq!(six_abs.len(), 6);
386        builder.push(b'5').unwrap();
387        let six_rel = builder.finish();
388        assert_eq!(six_rel.len(), 6);
389
390        assert_eq!(
391            left.clone().chain(five_abs.clone()).unwrap().compose_len(),
392            255
393        );
394        assert_eq!(
395            left.clone().chain(five_rel.clone()).unwrap().compose_len(),
396            255
397        );
398        assert!(left.clone().chain(six_abs.clone()).is_err());
399        assert!(left.clone().chain(six_rel).is_err());
400        assert!(left
401            .clone()
402            .chain(five_rel.clone())
403            .unwrap()
404            .chain(five_abs.clone())
405            .is_err());
406        assert!(left
407            .clone()
408            .chain(five_rel.clone())
409            .unwrap()
410            .chain(five_rel)
411            .is_err());
412
413        let left = UncertainDname::from(left);
414        assert_eq!(left.clone().chain(five_abs).unwrap().compose_len(), 255);
415        assert!(left.clone().chain(six_abs.clone()).is_err());
416
417        let left = UncertainDname::from(left.into_absolute().unwrap());
418        println!("{:?}", left);
419        assert_eq!(left.chain(six_abs).unwrap().compose_len(), 251);
420    }
421
422    /// Checks the impl of ToLabelIter: iter_labels and compose_len.
423    #[test]
424    fn to_label_iter_impl() {
425        fn check_impl<N: ToLabelIter>(name: N, labels: &[&[u8]]) {
426            let labels = labels.iter().map(|s| Label::from_slice(s).unwrap());
427            assert!(name.iter_labels().eq(labels));
428            assert_eq!(
429                name.iter_labels().map(|l| l.compose_len()).sum::<u16>(),
430                name.compose_len()
431            );
432        }
433
434        let w = RelativeDname::from_octets(b"\x03www".as_ref()).unwrap();
435        let ec = RelativeDname::from_octets(b"\x07example\x03com".as_ref())
436            .unwrap();
437        let ecr =
438            Dname::from_octets(b"\x07example\x03com\x00".as_ref()).unwrap();
439        let fbr = Dname::from_octets(b"\x03foo\x03bar\x00".as_ref()).unwrap();
440
441        check_impl(
442            w.clone().chain(ec.clone()).unwrap(),
443            &[b"www", b"example", b"com"],
444        );
445        check_impl(
446            w.clone().chain(ecr.clone()).unwrap(),
447            &[b"www", b"example", b"com", b""],
448        );
449        check_impl(
450            w.clone()
451                .chain(ec.clone())
452                .unwrap()
453                .chain(Dname::root_ref())
454                .unwrap(),
455            &[b"www", b"example", b"com", b""],
456        );
457        check_impl(
458            RelativeDname::empty_slice()
459                .chain(Dname::root_slice())
460                .unwrap(),
461            &[b""],
462        );
463
464        check_impl(
465            UncertainDname::from(w.clone()).chain(ecr.clone()).unwrap(),
466            &[b"www", b"example", b"com", b""],
467        );
468        check_impl(
469            UncertainDname::from(ecr.clone())
470                .chain(fbr.clone())
471                .unwrap(),
472            &[b"example", b"com", b""],
473        );
474    }
475
476    /// Tests that composing works as expected.
477    #[test]
478    fn compose() {
479        use std::vec::Vec;
480
481        let w = RelativeDname::from_octets(b"\x03www".as_ref()).unwrap();
482        let ec = RelativeDname::from_octets(b"\x07example\x03com".as_ref())
483            .unwrap();
484        let ecr =
485            Dname::from_octets(b"\x07example\x03com\x00".as_ref()).unwrap();
486        let fbr = Dname::from_octets(b"\x03foo\x03bar\x00".as_ref()).unwrap();
487
488        let mut buf = Vec::new();
489        infallible(w.clone().chain(ec.clone()).unwrap().compose(&mut buf));
490        assert_eq!(buf, b"\x03www\x07example\x03com".as_ref());
491
492        let mut buf = Vec::new();
493        infallible(w.clone().chain(ecr.clone()).unwrap().compose(&mut buf));
494        assert_eq!(buf, b"\x03www\x07example\x03com\x00");
495
496        let mut buf = Vec::new();
497        infallible(
498            w.clone()
499                .chain(ec.clone())
500                .unwrap()
501                .chain(Dname::root_ref())
502                .unwrap()
503                .compose(&mut buf),
504        );
505        assert_eq!(buf, b"\x03www\x07example\x03com\x00");
506
507        let mut buf = Vec::new();
508        infallible(
509            UncertainDname::from(w.clone())
510                .chain(ecr.clone())
511                .unwrap()
512                .compose(&mut buf),
513        );
514        assert_eq!(buf, b"\x03www\x07example\x03com\x00");
515
516        let mut buf = Vec::new();
517        infallible(
518            UncertainDname::from(ecr.clone())
519                .chain(fbr.clone())
520                .unwrap()
521                .compose(&mut buf),
522        );
523        assert_eq!(buf, b"\x07example\x03com\x00");
524    }
525}