hostname_validator/
lib.rs

1// Copyright 2018-2022 System76 <info@system76.com>
2// SPDX-License-Identifier: MIT
3
4#![no_std]
5
6//! Validate a hostname according to the [IETF RFC 1123](https://tools.ietf.org/html/rfc1123).
7//!
8//! ```rust
9//! extern crate hostname_validator;
10//!
11//! let valid = "VaLiD-HoStNaMe";
12//! let invalid = "-invalid-name";
13//!
14//! assert!(hostname_validator::is_valid(valid));
15//! assert!(!hostname_validator::is_valid(invalid));
16//! ```
17
18/// Validate a hostname according to [IETF RFC 1123](https://tools.ietf.org/html/rfc1123).
19///
20/// A hostname is valid if the following condition are true:
21///
22/// - It does not start or end with `-` or `.`.
23/// - It does not contain any characters outside of the alphanumeric range, except for `-` and `.`.
24/// - It is not empty.
25/// - It is 253 or fewer characters.
26/// - Its labels (characters separated by `.`) are not empty.
27/// - Its labels are 63 or fewer characters.
28/// - Its lables do not start or end with '-' or '.'.
29pub fn is_valid(hostname: &str) -> bool {
30    fn is_valid_char(byte: u8) -> bool {
31        (b'a'..=b'z').contains(&byte)
32            || (b'A'..=b'Z').contains(&byte)
33            || (b'0'..=b'9').contains(&byte)
34            || byte == b'-'
35            || byte == b'.'
36    }
37
38    !(hostname.bytes().any(|byte| !is_valid_char(byte))
39        || hostname.split('.').any(|label| {
40            label.is_empty() || label.len() > 63 || label.starts_with('-') || label.ends_with('-')
41        })
42        || hostname.is_empty()
43        || hostname.len() > 253)
44}
45
46#[cfg(test)]
47mod tests {
48    use super::*;
49
50    #[test]
51    fn valid_hostnames() {
52        for hostname in &[
53            "VaLiD-HoStNaMe",
54            "50-name",
55            "235235",
56            "example.com",
57            "VaLid.HoStNaMe",
58            "123.456",
59        ] {
60            assert!(is_valid(hostname), "{} is not valid", hostname);
61        }
62    }
63
64    #[test]
65    fn invalid_hostnames() {
66        for hostname in &[
67            "-invalid-name",
68            "also-invalid-",
69            "asdf@fasd",
70            "@asdfl",
71            "asd f@",
72            ".invalid",
73            "invalid.name.",
74            "foo.label-is-way-to-longgggggggggggggggggggggggggggggggggggggggggggg.org",
75            "invalid.-starting.char",
76            "invalid.ending-.char",
77            "empty..label",
78        ] {
79            assert!(!is_valid(hostname), "{} should not be valid", hostname);
80        }
81    }
82}