1#[cfg(all(feature = "alloc", feature = "std"))]
4use alloc::borrow::Cow;
5#[cfg(feature = "alloc")]
6use alloc::string::{String, ToString};
7use core::hash::{Hash, Hasher};
8use core::{fmt, mem, str};
9#[cfg(feature = "std")]
10use std::error::Error as StdError;
11
12#[non_exhaustive]
46#[derive(Clone, Eq, Hash, PartialEq)]
47pub enum ServerName<'a> {
48    DnsName(DnsName<'a>),
52
53    IpAddress(IpAddr),
56}
57
58impl ServerName<'_> {
59    #[cfg(feature = "alloc")]
61    pub fn to_owned(&self) -> ServerName<'static> {
62        match self {
63            Self::DnsName(d) => ServerName::DnsName(d.to_owned()),
64            Self::IpAddress(i) => ServerName::IpAddress(*i),
65        }
66    }
67
68    #[cfg(feature = "std")]
73    pub fn to_str(&self) -> Cow<'_, str> {
74        match self {
75            Self::DnsName(d) => d.as_ref().into(),
76            Self::IpAddress(i) => std::net::IpAddr::from(*i).to_string().into(),
77        }
78    }
79}
80
81impl fmt::Debug for ServerName<'_> {
82    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
83        match self {
84            Self::DnsName(d) => f.debug_tuple("DnsName").field(&d.as_ref()).finish(),
85            Self::IpAddress(i) => f.debug_tuple("IpAddress").field(i).finish(),
86        }
87    }
88}
89
90#[cfg(feature = "alloc")]
91impl TryFrom<String> for ServerName<'static> {
92    type Error = InvalidDnsNameError;
93
94    fn try_from(value: String) -> Result<Self, Self::Error> {
95        match DnsName::try_from_string(value) {
96            Ok(dns) => Ok(Self::DnsName(dns)),
97            Err(value) => match IpAddr::try_from(value.as_str()) {
98                Ok(ip) => Ok(Self::IpAddress(ip)),
99                Err(_) => Err(InvalidDnsNameError),
100            },
101        }
102    }
103}
104
105impl<'a> TryFrom<&'a [u8]> for ServerName<'a> {
106    type Error = InvalidDnsNameError;
107
108    fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
109        match str::from_utf8(value) {
110            Ok(s) => Self::try_from(s),
111            Err(_) => Err(InvalidDnsNameError),
112        }
113    }
114}
115
116impl<'a> TryFrom<&'a str> for ServerName<'a> {
118    type Error = InvalidDnsNameError;
119    fn try_from(s: &'a str) -> Result<Self, Self::Error> {
120        match DnsName::try_from(s) {
121            Ok(dns) => Ok(Self::DnsName(dns)),
122            Err(InvalidDnsNameError) => match IpAddr::try_from(s) {
123                Ok(ip) => Ok(Self::IpAddress(ip)),
124                Err(_) => Err(InvalidDnsNameError),
125            },
126        }
127    }
128}
129
130impl From<IpAddr> for ServerName<'_> {
131    fn from(addr: IpAddr) -> Self {
132        Self::IpAddress(addr)
133    }
134}
135
136#[cfg(feature = "std")]
137impl From<std::net::IpAddr> for ServerName<'_> {
138    fn from(addr: std::net::IpAddr) -> Self {
139        Self::IpAddress(addr.into())
140    }
141}
142
143impl From<Ipv4Addr> for ServerName<'_> {
144    fn from(v4: Ipv4Addr) -> Self {
145        Self::IpAddress(IpAddr::V4(v4))
146    }
147}
148
149impl From<Ipv6Addr> for ServerName<'_> {
150    fn from(v6: Ipv6Addr) -> Self {
151        Self::IpAddress(IpAddr::V6(v6))
152    }
153}
154
155#[cfg(feature = "std")]
156impl From<std::net::Ipv4Addr> for ServerName<'_> {
157    fn from(v4: std::net::Ipv4Addr) -> Self {
158        Self::IpAddress(IpAddr::V4(v4.into()))
159    }
160}
161
162#[cfg(feature = "std")]
163impl From<std::net::Ipv6Addr> for ServerName<'_> {
164    fn from(v6: std::net::Ipv6Addr) -> Self {
165        Self::IpAddress(IpAddr::V6(v6.into()))
166    }
167}
168
169impl<'a> From<DnsName<'a>> for ServerName<'a> {
170    fn from(dns_name: DnsName<'a>) -> Self {
171        Self::DnsName(dns_name)
172    }
173}
174
175#[derive(Clone, Debug, Eq, Hash, PartialEq)]
177pub struct DnsName<'a>(DnsNameInner<'a>);
178
179impl<'a> DnsName<'a> {
180    pub fn borrow(&'a self) -> Self {
182        Self(match self {
183            Self(DnsNameInner::Borrowed(s)) => DnsNameInner::Borrowed(s),
184            #[cfg(feature = "alloc")]
185            Self(DnsNameInner::Owned(s)) => DnsNameInner::Borrowed(s.as_str()),
186        })
187    }
188
189    #[cfg(feature = "alloc")]
192    pub fn to_lowercase_owned(&self) -> DnsName<'static> {
193        DnsName(DnsNameInner::Owned(self.as_ref().to_ascii_lowercase()))
194    }
195
196    #[cfg(feature = "alloc")]
198    pub fn to_owned(&self) -> DnsName<'static> {
199        DnsName(DnsNameInner::Owned(match self {
200            Self(DnsNameInner::Borrowed(s)) => s.to_string(),
201            #[cfg(feature = "alloc")]
202            Self(DnsNameInner::Owned(s)) => s.clone(),
203        }))
204    }
205
206    #[cfg(feature = "alloc")]
207    fn try_from_string(s: String) -> Result<Self, String> {
208        match validate(s.as_bytes()) {
209            Ok(_) => Ok(Self(DnsNameInner::Owned(s))),
210            Err(_) => Err(s),
211        }
212    }
213
214    pub const fn try_from_str(s: &str) -> Result<DnsName<'_>, InvalidDnsNameError> {
216        match validate(s.as_bytes()) {
217            Ok(_) => Ok(DnsName(DnsNameInner::Borrowed(s))),
218            Err(err) => Err(err),
219        }
220    }
221}
222
223#[cfg(feature = "alloc")]
224impl TryFrom<String> for DnsName<'static> {
225    type Error = InvalidDnsNameError;
226
227    fn try_from(value: String) -> Result<Self, Self::Error> {
228        Self::try_from_string(value).map_err(|_| InvalidDnsNameError)
229    }
230}
231
232impl<'a> TryFrom<&'a str> for DnsName<'a> {
233    type Error = InvalidDnsNameError;
234
235    fn try_from(value: &'a str) -> Result<Self, Self::Error> {
236        DnsName::try_from_str(value)
237    }
238}
239
240impl<'a> TryFrom<&'a [u8]> for DnsName<'a> {
241    type Error = InvalidDnsNameError;
242
243    fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
244        validate(value)?;
245        Ok(Self(DnsNameInner::Borrowed(str::from_utf8(value).unwrap())))
246    }
247}
248
249impl AsRef<str> for DnsName<'_> {
250    fn as_ref(&self) -> &str {
251        match self {
252            Self(DnsNameInner::Borrowed(s)) => s,
253            #[cfg(feature = "alloc")]
254            Self(DnsNameInner::Owned(s)) => s.as_str(),
255        }
256    }
257}
258
259#[derive(Clone, Eq)]
260enum DnsNameInner<'a> {
261    Borrowed(&'a str),
262    #[cfg(feature = "alloc")]
263    Owned(String),
264}
265
266impl PartialEq<Self> for DnsNameInner<'_> {
267    fn eq(&self, other: &Self) -> bool {
268        match (self, other) {
269            (Self::Borrowed(s), Self::Borrowed(o)) => s.eq_ignore_ascii_case(o),
270            #[cfg(feature = "alloc")]
271            (Self::Borrowed(s), Self::Owned(o)) => s.eq_ignore_ascii_case(o.as_str()),
272            #[cfg(feature = "alloc")]
273            (Self::Owned(s), Self::Borrowed(o)) => s.eq_ignore_ascii_case(o),
274            #[cfg(feature = "alloc")]
275            (Self::Owned(s), Self::Owned(o)) => s.eq_ignore_ascii_case(o.as_str()),
276        }
277    }
278}
279
280impl Hash for DnsNameInner<'_> {
281    fn hash<H: Hasher>(&self, state: &mut H) {
282        let s = match self {
283            Self::Borrowed(s) => s,
284            #[cfg(feature = "alloc")]
285            Self::Owned(s) => s.as_str(),
286        };
287
288        s.chars().for_each(|c| c.to_ascii_lowercase().hash(state));
289    }
290}
291
292impl fmt::Debug for DnsNameInner<'_> {
293    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
294        match self {
295            Self::Borrowed(s) => f.write_fmt(format_args!("{s:?}")),
296            #[cfg(feature = "alloc")]
297            Self::Owned(s) => f.write_fmt(format_args!("{s:?}")),
298        }
299    }
300}
301
302#[derive(Debug)]
305pub struct InvalidDnsNameError;
306
307impl fmt::Display for InvalidDnsNameError {
308    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
309        f.write_str("invalid dns name")
310    }
311}
312
313#[cfg(feature = "std")]
314impl StdError for InvalidDnsNameError {}
315
316const fn validate(input: &[u8]) -> Result<(), InvalidDnsNameError> {
317    enum State {
318        Start,
319        Next,
320        NumericOnly { len: usize },
321        NextAfterNumericOnly,
322        Subsequent { len: usize },
323        Hyphen { len: usize },
324    }
325
326    use State::*;
327    let mut state = Start;
328
329    const MAX_LABEL_LENGTH: usize = 63;
331
332    const MAX_NAME_LENGTH: usize = 253;
334
335    if input.len() > MAX_NAME_LENGTH {
336        return Err(InvalidDnsNameError);
337    }
338
339    let mut idx = 0;
340    while idx < input.len() {
341        let ch = input[idx];
342        state = match (state, ch) {
343            (Start | Next | NextAfterNumericOnly | Hyphen { .. }, b'.') => {
344                return Err(InvalidDnsNameError);
345            }
346            (Subsequent { .. }, b'.') => Next,
347            (NumericOnly { .. }, b'.') => NextAfterNumericOnly,
348            (Subsequent { len } | NumericOnly { len } | Hyphen { len }, _)
349                if len >= MAX_LABEL_LENGTH =>
350            {
351                return Err(InvalidDnsNameError);
352            }
353            (Start | Next | NextAfterNumericOnly, b'0'..=b'9') => NumericOnly { len: 1 },
354            (NumericOnly { len }, b'0'..=b'9') => NumericOnly { len: len + 1 },
355            (Start | Next | NextAfterNumericOnly, b'a'..=b'z' | b'A'..=b'Z' | b'_') => {
356                Subsequent { len: 1 }
357            }
358            (Subsequent { len } | NumericOnly { len } | Hyphen { len }, b'-') => {
359                Hyphen { len: len + 1 }
360            }
361            (
362                Subsequent { len } | NumericOnly { len } | Hyphen { len },
363                b'a'..=b'z' | b'A'..=b'Z' | b'_' | b'0'..=b'9',
364            ) => Subsequent { len: len + 1 },
365            _ => return Err(InvalidDnsNameError),
366        };
367        idx += 1;
368    }
369
370    if matches!(
371        state,
372        Start | Hyphen { .. } | NumericOnly { .. } | NextAfterNumericOnly
373    ) {
374        return Err(InvalidDnsNameError);
375    }
376
377    Ok(())
378}
379
380#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
386pub enum IpAddr {
387    V4(Ipv4Addr),
389    V6(Ipv6Addr),
391}
392
393impl TryFrom<&str> for IpAddr {
394    type Error = AddrParseError;
395
396    fn try_from(value: &str) -> Result<Self, Self::Error> {
397        match Ipv4Addr::try_from(value) {
398            Ok(v4) => Ok(Self::V4(v4)),
399            Err(_) => match Ipv6Addr::try_from(value) {
400                Ok(v6) => Ok(Self::V6(v6)),
401                Err(e) => Err(e),
402            },
403        }
404    }
405}
406
407#[cfg(feature = "std")]
408impl From<std::net::IpAddr> for IpAddr {
409    fn from(addr: std::net::IpAddr) -> Self {
410        match addr {
411            std::net::IpAddr::V4(v4) => Self::V4(v4.into()),
412            std::net::IpAddr::V6(v6) => Self::V6(v6.into()),
413        }
414    }
415}
416
417#[cfg(feature = "std")]
418impl From<IpAddr> for std::net::IpAddr {
419    fn from(value: IpAddr) -> Self {
420        match value {
421            IpAddr::V4(v4) => Self::from(std::net::Ipv4Addr::from(v4)),
422            IpAddr::V6(v6) => Self::from(std::net::Ipv6Addr::from(v6)),
423        }
424    }
425}
426
427#[cfg(feature = "std")]
428impl From<std::net::Ipv4Addr> for IpAddr {
429    fn from(v4: std::net::Ipv4Addr) -> Self {
430        Self::V4(v4.into())
431    }
432}
433
434#[cfg(feature = "std")]
435impl From<std::net::Ipv6Addr> for IpAddr {
436    fn from(v6: std::net::Ipv6Addr) -> Self {
437        Self::V6(v6.into())
438    }
439}
440
441#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
447pub struct Ipv4Addr([u8; 4]);
448
449impl From<[u8; 4]> for Ipv4Addr {
450    fn from(value: [u8; 4]) -> Self {
451        Self(value)
452    }
453}
454
455impl TryFrom<&str> for Ipv4Addr {
456    type Error = AddrParseError;
457
458    fn try_from(value: &str) -> Result<Self, Self::Error> {
459        if value.len() > 15 {
461            Err(AddrParseError(AddrKind::Ipv4))
462        } else {
463            Parser::new(value.as_bytes()).parse_with(|p| p.read_ipv4_addr(), AddrKind::Ipv4)
464        }
465    }
466}
467
468#[cfg(feature = "std")]
469impl From<std::net::Ipv4Addr> for Ipv4Addr {
470    fn from(addr: std::net::Ipv4Addr) -> Self {
471        Self(addr.octets())
472    }
473}
474
475#[cfg(feature = "std")]
476impl From<Ipv4Addr> for std::net::Ipv4Addr {
477    fn from(value: Ipv4Addr) -> Self {
478        Self::from(value.0)
479    }
480}
481
482impl AsRef<[u8; 4]> for Ipv4Addr {
483    fn as_ref(&self) -> &[u8; 4] {
484        &self.0
485    }
486}
487
488#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
494pub struct Ipv6Addr([u8; 16]);
495
496impl TryFrom<&str> for Ipv6Addr {
497    type Error = AddrParseError;
498
499    fn try_from(value: &str) -> Result<Self, Self::Error> {
500        Parser::new(value.as_bytes()).parse_with(|p| p.read_ipv6_addr(), AddrKind::Ipv6)
501    }
502}
503
504impl From<[u16; 8]> for Ipv6Addr {
505    fn from(value: [u16; 8]) -> Self {
506        let addr16 = [
508            value[0].to_be(),
509            value[1].to_be(),
510            value[2].to_be(),
511            value[3].to_be(),
512            value[4].to_be(),
513            value[5].to_be(),
514            value[6].to_be(),
515            value[7].to_be(),
516        ];
517        Self(
518            unsafe { mem::transmute::<[u16; 8], [u8; 16]>(addr16) },
521        )
522    }
523}
524
525#[cfg(feature = "std")]
526impl From<std::net::Ipv6Addr> for Ipv6Addr {
527    fn from(addr: std::net::Ipv6Addr) -> Self {
528        Self(addr.octets())
529    }
530}
531
532#[cfg(feature = "std")]
533impl From<Ipv6Addr> for std::net::Ipv6Addr {
534    fn from(value: Ipv6Addr) -> Self {
535        Self::from(value.0)
536    }
537}
538
539impl AsRef<[u8; 16]> for Ipv6Addr {
540    fn as_ref(&self) -> &[u8; 16] {
541        &self.0
542    }
543}
544
545mod parser {
549    use super::{AddrParseError, Ipv4Addr, Ipv6Addr};
550
551    pub(super) struct Parser<'a> {
552        state: &'a [u8],
554    }
555
556    impl<'a> Parser<'a> {
557        pub(super) const fn new(input: &'a [u8]) -> Self {
558            Parser { state: input }
559        }
560
561        fn read_atomically<T, F>(&mut self, inner: F) -> Option<T>
563        where
564            F: FnOnce(&mut Parser<'_>) -> Option<T>,
565        {
566            let state = self.state;
567            let result = inner(self);
568            if result.is_none() {
569                self.state = state;
570            }
571            result
572        }
573
574        pub(super) fn parse_with<T, F>(
577            &mut self,
578            inner: F,
579            kind: AddrKind,
580        ) -> Result<T, AddrParseError>
581        where
582            F: FnOnce(&mut Parser<'_>) -> Option<T>,
583        {
584            let result = inner(self);
585            if self.state.is_empty() { result } else { None }.ok_or(AddrParseError(kind))
586        }
587
588        fn peek_char(&self) -> Option<char> {
590            self.state.first().map(|&b| char::from(b))
591        }
592
593        fn read_char(&mut self) -> Option<char> {
595            self.state.split_first().map(|(&b, tail)| {
596                self.state = tail;
597                char::from(b)
598            })
599        }
600
601        #[must_use]
602        fn read_given_char(&mut self, target: char) -> Option<()> {
604            self.read_atomically(|p| {
605                p.read_char()
606                    .and_then(|c| if c == target { Some(()) } else { None })
607            })
608        }
609
610        fn read_separator<T, F>(&mut self, sep: char, index: usize, inner: F) -> Option<T>
615        where
616            F: FnOnce(&mut Parser<'_>) -> Option<T>,
617        {
618            self.read_atomically(move |p| {
619                if index > 0 {
620                    p.read_given_char(sep)?;
621                }
622                inner(p)
623            })
624        }
625
626        fn read_number<T: ReadNumberHelper>(
630            &mut self,
631            radix: u32,
632            max_digits: Option<usize>,
633            allow_zero_prefix: bool,
634        ) -> Option<T> {
635            self.read_atomically(move |p| {
636                let mut result = T::ZERO;
637                let mut digit_count = 0;
638                let has_leading_zero = p.peek_char() == Some('0');
639
640                while let Some(digit) = p.read_atomically(|p| p.read_char()?.to_digit(radix)) {
641                    result = result.checked_mul(radix)?;
642                    result = result.checked_add(digit)?;
643                    digit_count += 1;
644                    if let Some(max_digits) = max_digits {
645                        if digit_count > max_digits {
646                            return None;
647                        }
648                    }
649                }
650
651                if digit_count == 0 || (!allow_zero_prefix && has_leading_zero && digit_count > 1) {
652                    None
653                } else {
654                    Some(result)
655                }
656            })
657        }
658
659        pub(super) fn read_ipv4_addr(&mut self) -> Option<Ipv4Addr> {
661            self.read_atomically(|p| {
662                let mut groups = [0; 4];
663
664                for (i, slot) in groups.iter_mut().enumerate() {
665                    *slot = p.read_separator('.', i, |p| {
666                        p.read_number(10, Some(3), false)
669                    })?;
670                }
671
672                Some(Ipv4Addr(groups))
673            })
674        }
675
676        pub(super) fn read_ipv6_addr(&mut self) -> Option<Ipv6Addr> {
678            fn read_groups(p: &mut Parser<'_>, groups: &mut [u16]) -> (usize, bool) {
684                let limit = groups.len();
685
686                for (i, slot) in groups.iter_mut().enumerate() {
687                    if i < limit - 1 {
690                        let ipv4 = p.read_separator(':', i, |p| p.read_ipv4_addr());
691
692                        if let Some(v4_addr) = ipv4 {
693                            let [one, two, three, four] = v4_addr.0;
694                            groups[i] = u16::from_be_bytes([one, two]);
695                            groups[i + 1] = u16::from_be_bytes([three, four]);
696                            return (i + 2, true);
697                        }
698                    }
699
700                    let group = p.read_separator(':', i, |p| p.read_number(16, Some(4), true));
701
702                    match group {
703                        Some(g) => *slot = g,
704                        None => return (i, false),
705                    }
706                }
707                (groups.len(), false)
708            }
709
710            self.read_atomically(|p| {
711                let mut head = [0; 8];
714                let (head_size, head_ipv4) = read_groups(p, &mut head);
715
716                if head_size == 8 {
717                    return Some(head.into());
718                }
719
720                if head_ipv4 {
722                    return None;
723                }
724
725                p.read_given_char(':')?;
728                p.read_given_char(':')?;
729
730                let mut tail = [0; 7];
733                let limit = 8 - (head_size + 1);
734                let (tail_size, _) = read_groups(p, &mut tail[..limit]);
735
736                head[(8 - tail_size)..8].copy_from_slice(&tail[..tail_size]);
738
739                Some(head.into())
740            })
741        }
742    }
743
744    trait ReadNumberHelper: Sized {
745        const ZERO: Self;
746        fn checked_mul(&self, other: u32) -> Option<Self>;
747        fn checked_add(&self, other: u32) -> Option<Self>;
748    }
749
750    macro_rules! impl_helper {
751        ($($t:ty)*) => ($(impl ReadNumberHelper for $t {
752            const ZERO: Self = 0;
753            #[inline]
754            fn checked_mul(&self, other: u32) -> Option<Self> {
755                Self::checked_mul(*self, other.try_into().ok()?)
756            }
757            #[inline]
758            fn checked_add(&self, other: u32) -> Option<Self> {
759                Self::checked_add(*self, other.try_into().ok()?)
760            }
761        })*)
762    }
763
764    impl_helper! { u8 u16 u32 }
765
766    #[derive(Debug, Clone, Copy, Eq, PartialEq)]
767    pub(super) enum AddrKind {
768        Ipv4,
769        Ipv6,
770    }
771}
772
773use parser::{AddrKind, Parser};
774
775#[derive(Debug, Clone, Copy, Eq, PartialEq)]
777pub struct AddrParseError(AddrKind);
778
779impl core::fmt::Display for AddrParseError {
780    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
781        f.write_str(match self.0 {
782            AddrKind::Ipv4 => "invalid IPv4 address syntax",
783            AddrKind::Ipv6 => "invalid IPv6 address syntax",
784        })
785    }
786}
787
788#[cfg(feature = "std")]
789impl ::std::error::Error for AddrParseError {}
790
791#[cfg(test)]
792mod tests {
793    use super::*;
794    #[cfg(feature = "alloc")]
795    use alloc::format;
796
797    #[cfg(feature = "alloc")]
798    static TESTS: &[(&str, bool)] = &[
799        ("", false),
800        ("localhost", true),
801        ("LOCALHOST", true),
802        (".localhost", false),
803        ("..localhost", false),
804        ("1.2.3.4", false),
805        ("127.0.0.1", false),
806        ("absolute.", true),
807        ("absolute..", false),
808        ("multiple.labels.absolute.", true),
809        ("foo.bar.com", true),
810        ("infix-hyphen-allowed.com", true),
811        ("-prefixhypheninvalid.com", false),
812        ("suffixhypheninvalid--", false),
813        ("suffixhypheninvalid-.com", false),
814        ("foo.lastlabelendswithhyphen-", false),
815        ("infix_underscore_allowed.com", true),
816        ("_prefixunderscorevalid.com", true),
817        ("labelendswithnumber1.bar.com", true),
818        ("xn--bcher-kva.example", true),
819        (
820            "sixtythreesixtythreesixtythreesixtythreesixtythreesixtythreesix.com",
821            true,
822        ),
823        (
824            "sixtyfoursixtyfoursixtyfoursixtyfoursixtyfoursixtyfoursixtyfours.com",
825            false,
826        ),
827        (
828            "012345678901234567890123456789012345678901234567890123456789012.com",
829            true,
830        ),
831        (
832            "0123456789012345678901234567890123456789012345678901234567890123.com",
833            false,
834        ),
835        (
836            "01234567890123456789012345678901234567890123456789012345678901-.com",
837            false,
838        ),
839        (
840            "012345678901234567890123456789012345678901234567890123456789012-.com",
841            false,
842        ),
843        ("numeric-only-final-label.1", false),
844        ("numeric-only-final-label.absolute.1.", false),
845        ("1starts-with-number.com", true),
846        ("1Starts-with-number.com", true),
847        ("1.2.3.4.com", true),
848        ("123.numeric-only-first-label", true),
849        ("a123b.com", true),
850        ("numeric-only-middle-label.4.com", true),
851        ("1000-sans.badssl.com", true),
852        (
853            "twohundredandfiftythreecharacters.twohundredandfiftythreecharacters.twohundredandfiftythreecharacters.twohundredandfiftythreecharacters.twohundredandfiftythreecharacters.twohundredandfiftythreecharacters.twohundredandfiftythreecharacters.twohundredandfi",
854            true,
855        ),
856        (
857            "twohundredandfiftyfourcharacters.twohundredandfiftyfourcharacters.twohundredandfiftyfourcharacters.twohundredandfiftyfourcharacters.twohundredandfiftyfourcharacters.twohundredandfiftyfourcharacters.twohundredandfiftyfourcharacters.twohundredandfiftyfourc",
858            false,
859        ),
860    ];
861
862    #[cfg(feature = "alloc")]
863    #[test]
864    fn test_validation() {
865        for (input, expected) in TESTS {
866            #[cfg(feature = "std")]
867            println!("test: {input:?} expected valid? {expected:?}");
868            let name_ref = DnsName::try_from(*input);
869            assert_eq!(*expected, name_ref.is_ok());
870            let name = DnsName::try_from(input.to_string());
871            assert_eq!(*expected, name.is_ok());
872        }
873    }
874
875    #[cfg(feature = "alloc")]
876    #[test]
877    fn error_is_debug() {
878        assert_eq!(format!("{InvalidDnsNameError:?}"), "InvalidDnsNameError");
879    }
880
881    #[cfg(feature = "alloc")]
882    #[test]
883    fn error_is_display() {
884        assert_eq!(format!("{InvalidDnsNameError}"), "invalid dns name");
885    }
886
887    #[cfg(feature = "alloc")]
888    #[test]
889    fn dns_name_is_debug() {
890        let example = DnsName::try_from("example.com".to_string()).unwrap();
891        assert_eq!(format!("{example:?}"), "DnsName(\"example.com\")");
892    }
893
894    #[cfg(feature = "alloc")]
895    #[test]
896    fn dns_name_traits() {
897        let example = DnsName::try_from("example.com".to_string()).unwrap();
898        assert_eq!(example, example); #[cfg(feature = "std")]
901        {
902            use std::collections::HashSet;
903            let mut h = HashSet::<DnsName>::new();
904            h.insert(example);
905        }
906    }
907
908    #[cfg(feature = "alloc")]
909    #[test]
910    fn try_from_ascii_rejects_bad_utf8() {
911        assert_eq!(
912            format!("{:?}", DnsName::try_from(&b"\x80"[..])),
913            "Err(InvalidDnsNameError)"
914        );
915    }
916
917    const fn ipv4_address(
918        ip_address: &str,
919        octets: [u8; 4],
920    ) -> (&str, Result<Ipv4Addr, AddrParseError>) {
921        (ip_address, Ok(Ipv4Addr(octets)))
922    }
923
924    const IPV4_ADDRESSES: &[(&str, Result<Ipv4Addr, AddrParseError>)] = &[
925        ipv4_address("0.0.0.0", [0, 0, 0, 0]),
927        ipv4_address("1.1.1.1", [1, 1, 1, 1]),
928        ipv4_address("205.0.0.0", [205, 0, 0, 0]),
929        ipv4_address("0.205.0.0", [0, 205, 0, 0]),
930        ipv4_address("0.0.205.0", [0, 0, 205, 0]),
931        ipv4_address("0.0.0.205", [0, 0, 0, 205]),
932        ipv4_address("0.0.0.20", [0, 0, 0, 20]),
933        ("", Err(AddrParseError(AddrKind::Ipv4))),
935        ("...", Err(AddrParseError(AddrKind::Ipv4))),
936        (".0.0.0.0", Err(AddrParseError(AddrKind::Ipv4))),
937        ("0.0.0.0.", Err(AddrParseError(AddrKind::Ipv4))),
938        ("0.0.0", Err(AddrParseError(AddrKind::Ipv4))),
939        ("0.0.0.", Err(AddrParseError(AddrKind::Ipv4))),
940        ("256.0.0.0", Err(AddrParseError(AddrKind::Ipv4))),
941        ("0.256.0.0", Err(AddrParseError(AddrKind::Ipv4))),
942        ("0.0.256.0", Err(AddrParseError(AddrKind::Ipv4))),
943        ("0.0.0.256", Err(AddrParseError(AddrKind::Ipv4))),
944        ("1..1.1.1", Err(AddrParseError(AddrKind::Ipv4))),
945        ("1.1..1.1", Err(AddrParseError(AddrKind::Ipv4))),
946        ("1.1.1..1", Err(AddrParseError(AddrKind::Ipv4))),
947        ("025.0.0.0", Err(AddrParseError(AddrKind::Ipv4))),
948        ("0.025.0.0", Err(AddrParseError(AddrKind::Ipv4))),
949        ("0.0.025.0", Err(AddrParseError(AddrKind::Ipv4))),
950        ("0.0.0.025", Err(AddrParseError(AddrKind::Ipv4))),
951        ("1234.0.0.0", Err(AddrParseError(AddrKind::Ipv4))),
952        ("0.1234.0.0", Err(AddrParseError(AddrKind::Ipv4))),
953        ("0.0.1234.0", Err(AddrParseError(AddrKind::Ipv4))),
954        ("0.0.0.1234", Err(AddrParseError(AddrKind::Ipv4))),
955    ];
956
957    #[test]
958    fn parse_ipv4_address_test() {
959        for &(ip_address, expected_result) in IPV4_ADDRESSES {
960            assert_eq!(Ipv4Addr::try_from(ip_address), expected_result);
961        }
962    }
963
964    const fn ipv6_address(
965        ip_address: &str,
966        octets: [u8; 16],
967    ) -> (&str, Result<Ipv6Addr, AddrParseError>) {
968        (ip_address, Ok(Ipv6Addr(octets)))
969    }
970
971    const IPV6_ADDRESSES: &[(&str, Result<Ipv6Addr, AddrParseError>)] = &[
972        ipv6_address(
974            "2a05:d018:076c:b685:e8ab:afd3:af51:3aed",
975            [
976                0x2a, 0x05, 0xd0, 0x18, 0x07, 0x6c, 0xb6, 0x85, 0xe8, 0xab, 0xaf, 0xd3, 0xaf, 0x51,
977                0x3a, 0xed,
978            ],
979        ),
980        ipv6_address(
981            "2A05:D018:076C:B685:E8AB:AFD3:AF51:3AED",
982            [
983                0x2a, 0x05, 0xd0, 0x18, 0x07, 0x6c, 0xb6, 0x85, 0xe8, 0xab, 0xaf, 0xd3, 0xaf, 0x51,
984                0x3a, 0xed,
985            ],
986        ),
987        ipv6_address(
988            "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
989            [
990                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
991                0xff, 0xff,
992            ],
993        ),
994        ipv6_address(
995            "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF",
996            [
997                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
998                0xff, 0xff,
999            ],
1000        ),
1001        ipv6_address(
1002            "FFFF:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
1003            [
1004                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1005                0xff, 0xff,
1006            ],
1007        ),
1008        (
1010            "ffgf:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
1011            Err(AddrParseError(AddrKind::Ipv6)),
1012        ),
1013        (
1014            "ffff:gfff:ffff:ffff:ffff:ffff:ffff:ffff",
1015            Err(AddrParseError(AddrKind::Ipv6)),
1016        ),
1017        (
1018            "ffff:ffff:fffg:ffff:ffff:ffff:ffff:ffff",
1019            Err(AddrParseError(AddrKind::Ipv6)),
1020        ),
1021        (
1022            "ffff:ffff:ffff:ffgf:ffff:ffff:ffff:ffff",
1023            Err(AddrParseError(AddrKind::Ipv6)),
1024        ),
1025        (
1026            "ffff:ffff:ffff:ffff:gfff:ffff:ffff:ffff",
1027            Err(AddrParseError(AddrKind::Ipv6)),
1028        ),
1029        (
1030            "ffff:ffff:ffff:ffff:ffff:fgff:ffff:ffff",
1031            Err(AddrParseError(AddrKind::Ipv6)),
1032        ),
1033        (
1034            "ffff:ffff:ffff:ffff:ffff:ffff:ffgf:ffff",
1035            Err(AddrParseError(AddrKind::Ipv6)),
1036        ),
1037        (
1038            "ffff:ffff:ffff:ffff:ffff:ffff:ffgf:fffg",
1039            Err(AddrParseError(AddrKind::Ipv6)),
1040        ),
1041        (
1043            ":ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
1044            Err(AddrParseError(AddrKind::Ipv6)),
1045        ),
1046        (
1047            "ffff::ffff:ffff:ffff:ffff:ffff:ffff:ffff",
1048            Err(AddrParseError(AddrKind::Ipv6)),
1049        ),
1050        (
1051            "ffff:ffff::ffff:ffff:ffff:ffff:ffff:ffff",
1052            Err(AddrParseError(AddrKind::Ipv6)),
1053        ),
1054        (
1055            "ffff:ffff:ffff::ffff:ffff:ffff:ffff:ffff",
1056            Err(AddrParseError(AddrKind::Ipv6)),
1057        ),
1058        (
1059            "ffff:ffff:ffff:ffff::ffff:ffff:ffff:ffff",
1060            Err(AddrParseError(AddrKind::Ipv6)),
1061        ),
1062        (
1063            "ffff:ffff:ffff:ffff:ffff::ffff:ffff:ffff",
1064            Err(AddrParseError(AddrKind::Ipv6)),
1065        ),
1066        (
1067            "ffff:ffff:ffff:ffff:ffff:ffff::ffff:ffff",
1068            Err(AddrParseError(AddrKind::Ipv6)),
1069        ),
1070        (
1071            "ffff:ffff:ffff:ffff:ffff:ffff:ffff::ffff",
1072            Err(AddrParseError(AddrKind::Ipv6)),
1073        ),
1074        (
1076            "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:",
1077            Err(AddrParseError(AddrKind::Ipv6)),
1078        ),
1079        (
1080            "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
1081            Err(AddrParseError(AddrKind::Ipv6)),
1082        ),
1083        (
1085            "ga05:d018:076c:b685:e8ab:afd3:af51:3aed",
1086            Err(AddrParseError(AddrKind::Ipv6)),
1087        ),
1088        (
1090            ":a05:d018:076c:b685:e8ab:afd3:af51:3aed",
1091            Err(AddrParseError(AddrKind::Ipv6)),
1092        ),
1093        (
1095            "2a05:d018:076c:b685:e8ab:afd3:af51:3ae:",
1096            Err(AddrParseError(AddrKind::Ipv6)),
1097        ),
1098        (
1100            "2a05:d018:076c:b685:e8ab:afd3:af51:3a::",
1101            Err(AddrParseError(AddrKind::Ipv6)),
1102        ),
1103        (
1105            "2a05::018:076c:b685:e8ab:afd3:af51:3aed",
1106            Err(AddrParseError(AddrKind::Ipv6)),
1107        ),
1108        (
1110            "2a056:d018:076c:b685:e8ab:afd3:af51:3ae",
1111            Err(AddrParseError(AddrKind::Ipv6)),
1112        ),
1113        (
1115            "2a0:d018:076c:b685:e8ab:afd3:af51:3aed ",
1116            Err(AddrParseError(AddrKind::Ipv6)),
1117        ),
1118        (
1120            "d018:076c:b685:e8ab:afd3:af51:3aed",
1121            Err(AddrParseError(AddrKind::Ipv6)),
1122        ),
1123        (
1125            "2a05:d018:076c:b685:e8ab:afd3:af51:3aed3aed",
1126            Err(AddrParseError(AddrKind::Ipv6)),
1127        ),
1128    ];
1129
1130    #[test]
1131    fn parse_ipv6_address_test() {
1132        for &(ip_address, expected_result) in IPV6_ADDRESSES {
1133            assert_eq!(Ipv6Addr::try_from(ip_address), expected_result);
1134        }
1135    }
1136
1137    #[test]
1138    fn try_from_ascii_ip_address_test() {
1139        const IP_ADDRESSES: &[(&str, Result<IpAddr, AddrParseError>)] = &[
1140            ("127.0.0.1", Ok(IpAddr::V4(Ipv4Addr([127, 0, 0, 1])))),
1142            (
1144                "127.0.0.",
1146                Err(AddrParseError(AddrKind::Ipv6)),
1147            ),
1148            (
1150                "0000:0000:0000:0000:0000:0000:0000:0001",
1151                Ok(IpAddr::V6(Ipv6Addr([
1152                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
1153                ]))),
1154            ),
1155            (
1157                "example.com",
1159                Err(AddrParseError(AddrKind::Ipv6)),
1160            ),
1161        ];
1162        for &(ip_address, expected_result) in IP_ADDRESSES {
1163            assert_eq!(IpAddr::try_from(ip_address), expected_result)
1164        }
1165    }
1166
1167    #[test]
1168    fn try_from_ascii_str_ip_address_test() {
1169        const IP_ADDRESSES: &[(&str, Result<IpAddr, AddrParseError>)] = &[
1170            ("127.0.0.1", Ok(IpAddr::V4(Ipv4Addr([127, 0, 0, 1])))),
1172            (
1174                "127.0.0.",
1176                Err(AddrParseError(AddrKind::Ipv6)),
1177            ),
1178            (
1180                "0000:0000:0000:0000:0000:0000:0000:0001",
1181                Ok(IpAddr::V6(Ipv6Addr([
1182                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
1183                ]))),
1184            ),
1185            (
1187                "example.com",
1189                Err(AddrParseError(AddrKind::Ipv6)),
1190            ),
1191        ];
1192        for &(ip_address, expected_result) in IP_ADDRESSES {
1193            assert_eq!(IpAddr::try_from(ip_address), expected_result)
1194        }
1195    }
1196
1197    #[test]
1198    #[cfg(feature = "std")]
1199    fn to_str() {
1200        let domain_str = "example.com";
1201        let domain_servername = ServerName::try_from(domain_str).unwrap();
1202        assert_eq!(domain_str, domain_servername.to_str());
1203
1204        let ipv4_str = "127.0.0.1";
1205        let ipv4_servername = ServerName::try_from("127.0.0.1").unwrap();
1206        assert_eq!(ipv4_str, ipv4_servername.to_str());
1207
1208        let ipv6_str = "::1";
1209        let ipv6_servername = ServerName::try_from(ipv6_str).unwrap();
1210        assert_eq!("::1", ipv6_servername.to_str());
1211    }
1212}