#hostname #validation #punycode #idna #publicsuffix

adbyss_psl

A minimal Public Suffix List hostname validator

60 releases (12 breaking)

new 0.15.2 Jan 9, 2025
0.15.1 Nov 28, 2024
0.14.0 Oct 22, 2024
0.11.1 Jul 25, 2024
0.4.2 Jul 29, 2021

#312 in Web programming

WTFPL license

110KB
1K SLoC

Adbyss: Public Suffix

docs.rs changelog
crates.io ci deps.rs
license contributions welcome

This library contains a single public-facing struct — adbyss_psl::Domain — used for validating and normalizing Internet hostnames, like "www.domain.com".

It will:

  • Validate, normalize, and Puny-encode internationalized/Unicode labels (RFC 3492);
  • Validate and normalize the public suffix;
  • Ensure conformance with RFC 1123;
  • And locate the boundaries of the subdomain (if any), root (required), and suffix (required);

Examples

New instances of Domain can be initialized using either Domain::new or TryFrom<&str>.

use adbyss_psl::Domain;

// These are equivalent and fine:
assert!(Domain::new("www.MyDomain.com").is_some());
assert!(Domain::try_from("www.MyDomain.com").is_ok());

// The following is valid DNS, but invalid as an Internet hostname:
assert!(Domain::new("_acme-challenge.mydomain.com").is_none());

Valid Internet hostnames must be no longer than 253 characters, and contain both root and (valid) suffix components.

Their labels — the bits between the dots — must additionally:

  • Be no longer than 63 characters;
  • (Ultimately) contain only ASCII letters, digits, and -;
  • Start and end with an alphanumeric character;

Unicode/internationalized labels are allowed, but must be Puny-encodable and not contain any conflicting bidirectionality constraints. Domain will encode such labels using Punycode when it finds them, ensuring the resulting hostname will always be ASCII-only.

Post-parsing, Domain gives you access to each individual component, or the whole thing:

use adbyss_psl::Domain;

let dom = Domain::new("www.MyDomain.com").unwrap();

// Pull out the pieces if you're into that sort of thing.
assert_eq!(dom.host(), "www.mydomain.com");
assert_eq!(dom.subdomain(), Some("www"));
assert_eq!(dom.root(), "mydomain");
assert_eq!(dom.suffix(), "com");
assert_eq!(dom.tld(), "mydomain.com");

// If you just want the sanitized host back as an owned value, use
// `Domain::take` or `String::from`:
let owned = dom.take(); // "www.mydomain.com"

Optional Crate Features

  • serde: Enables serialization/deserialization support.

Dependencies

~2–3MB
~53K SLoC