simple_dns/dns/
character_string.rs

1use crate::{
2    bytes_buffer::BytesBuffer,
3    dns::WireFormat,
4    lib::{
5        fmt::{Debug, Display, Formatter},
6        Cow, String, ToString, TryFrom, Write,
7    },
8    SimpleDnsError,
9};
10
11use super::MAX_CHARACTER_STRING_LENGTH;
12
13/// CharacterString is expressed in one or two ways:
14/// - as a contiguous set of characters without interior spaces,
15/// - or as a string beginning with a " and ending with a ".  
16///
17/// Inside a " delimited string any character can occur, except for a " itself,  
18/// which must be quoted using \ (back slash).
19#[derive(PartialEq, Eq, Hash, Clone)]
20pub struct CharacterString<'a> {
21    pub(crate) data: Cow<'a, [u8]>,
22}
23
24impl<'a> CharacterString<'a> {
25    /// Creates a new validated CharacterString
26    pub fn new(data: &'a [u8]) -> crate::Result<Self> {
27        Self::internal_new(Cow::Borrowed(data))
28    }
29
30    fn internal_new(data: Cow<'a, [u8]>) -> crate::Result<Self> {
31        if data.len() > MAX_CHARACTER_STRING_LENGTH {
32            return Err(SimpleDnsError::InvalidCharacterString);
33        }
34        Ok(Self { data })
35    }
36
37    /// Transforms the inner data into its owned type
38    pub fn into_owned<'b>(self) -> CharacterString<'b> {
39        CharacterString {
40            data: self.data.into_owned().into(),
41        }
42    }
43}
44
45impl<'a> TryFrom<CharacterString<'a>> for String {
46    type Error = crate::SimpleDnsError;
47
48    fn try_from(val: CharacterString<'a>) -> Result<Self, Self::Error> {
49        match String::from_utf8(val.data.into()) {
50            Ok(s) => Ok(s),
51            Err(e) => Err(SimpleDnsError::InvalidUtf8String(e)),
52        }
53    }
54}
55
56impl<'a> WireFormat<'a> for CharacterString<'a> {
57    const MINIMUM_LEN: usize = 1;
58
59    fn parse(data: &mut BytesBuffer<'a>) -> crate::Result<Self>
60    where
61        Self: Sized,
62    {
63        let length = data.get_u8()? as usize;
64        if length > MAX_CHARACTER_STRING_LENGTH {
65            return Err(SimpleDnsError::InvalidCharacterString);
66        }
67
68        let data = data.get_slice(length)?;
69
70        Ok(Self {
71            data: Cow::Borrowed(data),
72        })
73    }
74
75    fn write_to<T: Write>(&self, out: &mut T) -> crate::Result<()> {
76        out.write_all(&[self.data.len() as u8])?;
77        out.write_all(&self.data)
78    }
79
80    fn len(&self) -> usize {
81        self.data.len() + Self::MINIMUM_LEN
82    }
83}
84
85impl<'a> TryFrom<&'a str> for CharacterString<'a> {
86    type Error = crate::SimpleDnsError;
87
88    fn try_from(value: &'a str) -> Result<Self, Self::Error> {
89        CharacterString::internal_new(Cow::Borrowed(value.as_bytes()))
90    }
91}
92
93impl TryFrom<String> for CharacterString<'_> {
94    type Error = crate::SimpleDnsError;
95
96    fn try_from(value: String) -> Result<Self, Self::Error> {
97        CharacterString::internal_new(Cow::Owned(value.as_bytes().into()))
98    }
99}
100
101impl Display for CharacterString<'_> {
102    fn fmt(&self, f: &mut Formatter<'_>) -> crate::lib::fmt::Result {
103        match crate::lib::str::from_utf8(&self.data) {
104            Ok(s) => f.write_str(s),
105            Err(_) => {
106                let s = crate::lib::String::from_utf8_lossy(&self.data);
107                f.write_str(&s)
108            }
109        }
110    }
111}
112
113impl Debug for CharacterString<'_> {
114    fn fmt(&self, f: &mut Formatter<'_>) -> crate::lib::fmt::Result {
115        f.debug_struct("CharacterString")
116            .field("data", &self.to_string())
117            .finish()
118    }
119}
120
121#[cfg(test)]
122mod tests {
123    use super::*;
124    use crate::lib::Vec;
125
126    #[test]
127    fn construct_valid_character_string() {
128        assert!(CharacterString::new(b"Iamvalid").is_ok());
129        assert!(CharacterString::new(br#""I am valid""#).is_ok());
130        assert!(CharacterString::new(br#""I am \" also valid""#).is_ok());
131        assert!(CharacterString::new(b"I am valid").is_ok());
132
133        let long_string = [0u8; 300];
134        assert!(CharacterString::new(&long_string).is_err());
135    }
136
137    #[test]
138    fn parse() {
139        let c_string = CharacterString::parse(&mut BytesBuffer::new(b"\x0esome_long_text"));
140        assert!(c_string.is_ok());
141        let c_string = c_string.unwrap();
142        assert_eq!(15, c_string.len());
143        assert_eq!("some_long_text", c_string.to_string());
144    }
145
146    #[test]
147    fn append_to_vec() {
148        let mut out = Vec::new();
149        let c_string = CharacterString::new("some_long_text".as_bytes()).unwrap();
150        c_string.write_to(&mut out).unwrap();
151
152        assert_eq!(b"\x0esome_long_text", &out[..]);
153        assert_eq!(b"\x0esome_long_text", &out[..]);
154    }
155
156    #[test]
157    fn panic_display() {
158        let c = CharacterString::new(&[0xFF]).expect("failed to create character string");
159        assert_eq!(c.to_string(), "\u{FFFD}");
160    }
161}