domain_core/bits/name/
label.rs

1//! Domain name labels.
2//!
3//! This is a private module. Its public types are re-exported by the parent
4//! module.
5
6use std::{cmp, fmt, hash, ops};
7use bytes::BufMut;
8use ::bits::compose::Compose;
9use ::bits::parse::ShortBuf;
10
11
12//------------ Label ---------------------------------------------------------
13
14/// A slice with the content of a domain name label.
15///
16/// This is an unsized type wrapping the content of a valid label.
17///
18/// There are two types of such labels: normal labels and binary labels.
19/// Normal labels consist of up to 63 bytes of data. Binary labels are a
20/// sequence of up to 256 one-bit labels. They have been invented for reverse
21/// pointer records for IPv6 but have quickly been found to be rather
22/// unwieldly and were never widely implemented. Subsequently they have been
23/// declared historic and are forbidden to be supported. So we don’t.
24///
25/// In theory there can be even more types of labels, but based on the
26/// experience with binary labels, it is very unlikely that there ever will
27/// be any.
28///
29/// Consequently, `Label` will only ever contain a byte slice of up to 63
30/// bytes. It only contains the label’s content, not the length octet it is
31/// preceded by in wire format. The type derefs to `[u8]`, providing access
32/// to all of a byte slice’s methods. As an usized type, it needs to be used
33/// behind some kind of pointer, most likely a reference.
34///
35/// `Label` differs from a byte slice in how it compares: as labels are to be
36/// case-insensititve, all the comparision traits as well as `Hash` are
37/// implemented igoring ASCII-case.
38pub struct Label([u8]);
39
40/// # Creation
41///
42impl Label {
43    /// Creates a label from the underlying byte slice without any checking.
44    pub(super) unsafe fn from_slice_unchecked(slice: &[u8]) -> &Self {
45        &*(slice as *const [u8] as *const Self)
46    }
47
48    /// Returns a static reference to the root label.
49    ///
50    /// The root label is an empty label.
51    pub fn root() -> &'static Self {
52        unsafe { Self::from_slice_unchecked(b"") }
53    }
54
55    /// Returns a static reference to the wildcard label `"*"`.
56    pub fn wildcard() -> &'static Self {
57        unsafe { Self::from_slice_unchecked(b"*") }
58    }
59
60    /// Converts a byte slice into a label.
61    ///
62    /// This will fail if the slice is longer than 63 bytes.
63    pub fn from_slice(slice: &[u8]) -> Result<&Self, LongLabelError> {
64        if slice.len() > 63 {
65            Err(LongLabelError)
66        }
67        else {
68            Ok(unsafe { Self::from_slice_unchecked(slice) })
69        }
70    }
71
72    /// Splits a label from the beginning of a byte slice.
73    ///
74    /// On success, the functon returns a label and the remainder of
75    /// the slice.
76    pub fn split_from(slice: &[u8])
77                      -> Result<(&Self, &[u8]), SplitLabelError> {
78        let head = match slice.get(0) {
79            Some(ch) => *ch,
80            None => return Err(SplitLabelError::ShortBuf)
81        };
82        let end = match head {
83            0 ... 0x3F => (head as usize) + 1,
84            0x40 ... 0x7F => {
85                return Err(
86                    SplitLabelError::BadType(LabelTypeError::Extended(head))
87                )
88            }
89            0xC0 ... 0xFF => {
90                let res = match slice.get(1) {
91                    Some(ch) => u16::from(*ch),
92                    None => return Err(SplitLabelError::ShortBuf)
93                };
94                let res = res | ((u16::from(head) & 0x3F) << 8);
95                return Err(SplitLabelError::Pointer(res))
96            }
97            _ => {
98                return Err(
99                    SplitLabelError::BadType(LabelTypeError::Undefined)
100                )
101            }
102        };
103        if slice.len() < end {
104            return Err(SplitLabelError::ShortBuf)
105        }
106        Ok((unsafe { Self::from_slice_unchecked(&slice[1..end]) },
107            &slice[end..]))
108    }
109
110    /// Returns a reference to the underlying byte slice.
111    pub fn as_slice(&self) -> &[u8] {
112        self.as_ref()
113    }
114
115    /// Returns a mutable reference to the underlying byte slice.
116    pub fn as_slice_mut(&mut self) -> &mut [u8] {
117        self.as_mut()
118    }
119}
120
121/// # Properties
122///
123impl Label {
124    /// Returns whether the label is the root label.
125    pub fn is_root(&self) -> bool {
126        self.is_empty()
127    }
128}
129
130
131//--- Compose
132
133impl Compose for Label {
134    fn compose_len(&self) -> usize {
135        self.len() + 1
136    }
137
138    fn compose<B: BufMut>(&self, buf: &mut B) {
139        buf.put_u8(self.len() as u8);
140        buf.put_slice(self.as_ref());
141    }
142}
143
144
145//--- Deref, DerefMut, AsRef, and AsMut
146
147impl ops::Deref for Label {
148    type Target = [u8];
149
150    fn deref(&self) -> &[u8] {
151        self.as_ref()
152    }
153}
154
155impl ops::DerefMut for Label {
156    fn deref_mut(&mut self) -> &mut [u8] {
157        self.as_mut()
158    }
159}
160
161impl AsRef<[u8]> for Label {
162    fn as_ref(&self) -> &[u8] {
163        unsafe { &*(self as *const Self as *const [u8]) }
164    }
165}
166
167impl AsMut<[u8]> for Label {
168    fn as_mut(&mut self) -> &mut [u8] {
169        unsafe { &mut *(self as *mut Label as *mut [u8]) }
170    }
171}
172
173
174//--- PartialEq and Eq
175
176impl PartialEq for Label {
177    fn eq(&self, other: &Self) -> bool {
178        self.eq_ignore_ascii_case(other)
179    }
180}
181
182impl Eq for Label { }
183
184
185//--- PartialOrd and Ord
186
187impl PartialOrd for Label {
188    /// Returns an ordering between `self` and `other`.
189    ///
190    /// The canonical sort order for labels is defined in section 6.1 of
191    /// RFC 4034.
192    ///
193    /// In short, labels are ordered like octet strings except that
194    /// the case of ASCII letters is ignored.
195    ///
196    /// [RFC 4034]: https://tools.ietf.org/html/rfc4034
197    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
198        self.iter().map(u8::to_ascii_lowercase).partial_cmp(
199            other.iter().map(u8::to_ascii_lowercase)
200        )
201    }
202}
203
204impl Ord for Label {
205    fn cmp(&self, other: &Self) -> cmp::Ordering {
206        self.iter().map(u8::to_ascii_lowercase).cmp(
207            other.iter().map(u8::to_ascii_lowercase)
208        )
209    }
210}
211
212
213//--- Hash
214
215impl hash::Hash for Label {
216    fn hash<H: hash::Hasher>(&self, state: &mut H) {
217        // Include the length in the hash so we can simply hash over the
218        // labels when building a name’s hash.
219        (self.len() as u8).hash(state);
220        for c in self.iter() {
221            c.to_ascii_lowercase().hash(state)
222        }
223    }
224}
225
226
227//--- IntoIterator
228
229impl<'a> IntoIterator for &'a Label {
230    type Item = &'a u8;
231    type IntoIter = ::std::slice::Iter<'a, u8>;
232
233    fn into_iter(self) -> Self::IntoIter {
234        self.iter()
235    }
236}
237
238
239//--- Display and Debug
240
241impl fmt::Display for Label {
242    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
243        for &ch in self.iter() {
244            if ch == b' ' || ch == b'.' || ch == b'\\' {
245                write!(f, "\\{}", ch as char)?;
246            }
247            else if ch < b' ' || ch >= 0x7F {
248                write!(f, "\\{:03}", ch)?;
249            }
250            else {
251                write!(f, "{}", (ch as char))?;
252            }
253        }
254        Ok(())
255    }
256}
257
258impl fmt::Debug for Label {
259    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
260        f.write_str("Label(")?;
261        fmt::Display::fmt(self, f)?;
262        f.write_str(")")
263    }
264}
265
266
267//------------ LabelTypeError ------------------------------------------------
268
269/// A bad label type was encountered.
270#[derive(Clone, Copy, Debug, Eq, Fail, PartialEq)]
271pub enum LabelTypeError {
272    /// The label was of the undefined type `0b10`.
273    #[fail(display="undefined label type")]
274    Undefined,
275
276    /// The label was of extended label type given.
277    /// 
278    /// The type value will be in the range `0x40` to `0x7F`, that is, it
279    /// includes the original label type bits `0b01`.
280    #[fail(display="unknown extended label 0x{:02x}", _0)]
281    Extended(u8),
282}
283
284
285//------------ LongLabelError ------------------------------------------------
286
287/// A label was longer than the allowed 63 bytes.
288#[derive(Clone, Copy, Debug, Eq, Fail, PartialEq)]
289#[fail(display="long label")]
290pub struct LongLabelError;
291
292
293//------------ SplitLabelError -----------------------------------------------
294
295/// An error happened while splitting a label from a bytes slice.
296#[derive(Clone, Copy, Debug, Eq, Fail, PartialEq)]
297pub enum SplitLabelError {
298    /// The label was a pointer to the given position.
299    #[fail(display="compressed domain name")]
300    Pointer(u16),
301
302    /// The label type was invalid.
303    #[fail(display="{}", _0)]
304    BadType(LabelTypeError),
305
306    /// The bytes slice was too short.
307    #[fail(display="unexpected end of input")]
308    ShortBuf,
309}
310
311impl From<LabelTypeError> for SplitLabelError {
312    fn from(err: LabelTypeError) -> SplitLabelError {
313        SplitLabelError::BadType(err)
314    }
315}
316
317impl From<ShortBuf> for SplitLabelError {
318    fn from(_: ShortBuf) -> SplitLabelError {
319        SplitLabelError::ShortBuf
320    }
321}
322
323
324//============ Testing =======================================================
325
326#[cfg(test)]
327mod test {
328    use super::*;
329
330    #[test]
331    fn from_slice() {
332        let x = [0u8; 10];
333        assert_eq!(Label::from_slice(&x[..]).unwrap().as_slice(),
334                   &x[..]);
335        let x = [0u8; 63];
336        assert_eq!(Label::from_slice(&x[..]).unwrap().as_slice(),
337                   &x[..]);
338        let x = [0u8; 64];
339        assert!(Label::from_slice(&x[..]).is_err());
340    }
341
342    #[test]
343    fn split_from() {
344        // regular label
345        assert_eq!(Label::split_from(b"\x03www\x07example\x03com\0").unwrap(),
346                   (Label::from_slice(b"www").unwrap(),
347                    &b"\x07example\x03com\0"[..]));
348
349        // final regular label
350        assert_eq!(Label::split_from(b"\x03www").unwrap(),
351                   (Label::from_slice(b"www").unwrap(),
352                    &b""[..]));
353
354        // root label
355        assert_eq!(Label::split_from(b"\0some").unwrap(),
356                   (Label::from_slice(b"").unwrap(),
357                    &b"some"[..]));
358
359        // short slice
360        assert_eq!(Label::split_from(b"\x03ww"),
361                   Err(SplitLabelError::ShortBuf));
362
363        // empty slice
364        assert_eq!(Label::split_from(b""),
365                   Err(SplitLabelError::ShortBuf));
366
367        // compressed label
368        assert_eq!(Label::split_from(b"\xc0\x05foo"),
369                   Err(SplitLabelError::Pointer(5)));
370
371        // undefined label type
372        assert_eq!(Label::split_from(b"\xb3foo"),
373                   Err(LabelTypeError::Undefined.into()));
374
375        // extended label type
376        assert_eq!(Label::split_from(b"\x66foo"),
377                   Err(LabelTypeError::Extended(0x66).into()));
378    }
379
380    #[test]
381    fn compose() {
382        use bytes::BytesMut;
383
384        let mut buf = BytesMut::with_capacity(64);
385        assert_eq!(Label::root().compose_len(), 1);
386        Label::root().compose(&mut buf);
387        assert_eq!(buf.freeze(), &b"\0"[..]);
388
389        let mut buf = BytesMut::with_capacity(64);
390        let label = Label::from_slice(b"123").unwrap();
391        assert_eq!(label.compose_len(), 4);
392        label.compose(&mut buf);
393        assert_eq!(buf.freeze(), &b"\x03123"[..]);
394    }
395
396    #[test]
397    fn eq() {
398        assert_eq!(Label::from_slice(b"example").unwrap(),
399                   Label::from_slice(b"eXAMple").unwrap());
400        assert_ne!(Label::from_slice(b"example").unwrap(),
401                   Label::from_slice(b"e4ample").unwrap());
402    }
403
404    #[test]
405    fn cmp() {
406        use std::cmp::Ordering;
407
408        let labels = [Label::root(),
409                      Label::from_slice(b"\x01").unwrap(),
410                      Label::from_slice(b"*").unwrap(),
411                      Label::from_slice(b"\xc8").unwrap()];
412        for i in 0..labels.len() {
413            for j in 0..labels.len() {
414                let ord = if i < j { Ordering::Less }
415                          else if i == j { Ordering::Equal }
416                          else { Ordering::Greater };
417                assert_eq!(labels[i].partial_cmp(&labels[j]), Some(ord));
418                assert_eq!(labels[i].cmp(&labels[j]), ord);
419            }
420        }
421
422        let l1 = Label::from_slice(b"example").unwrap();
423        let l2 = Label::from_slice(b"eXAMple").unwrap();
424        assert_eq!(l1.partial_cmp(&l2), Some(Ordering::Equal));
425        assert_eq!(l1.cmp(&l2), Ordering::Equal);
426    }
427
428    #[test]
429    fn hash() {
430        use std::collections::hash_map::DefaultHasher;
431        use std::hash::{Hash, Hasher};
432
433        let mut s1 = DefaultHasher::new();
434        let mut s2 = DefaultHasher::new();
435        Label::from_slice(b"example").unwrap().hash(&mut s1);
436        Label::from_slice(b"eXAMple").unwrap().hash(&mut s2);
437        assert_eq!(s1.finish(), s2.finish());
438    }
439}