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}