1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
//! A fully qualified domain name representation
//!
//! Notice that a fully qualified domain name (FQDN) is case-insensitive.
//! So the implementation of traits like `Hash` or `PartialEq` do the same.
//!
//! # Crate features
//! These features control how the parsing of a String should be done.
//! Violation of one of these activated limitations raises an error (see [`Error`]).
//!
//! Some limitations are set by the Internet RFC but, by default, some of them are relaxed to fit
//! with more applicative contexts. The following features are available in order to activate or not these
//! limitations, depending on applicative purposes.
//!
//!
//! ### `domain-label-length-limited-to-63`
//! The internet standards specifies that each label of a FQDN is limited to 63 characters.
//! By default, this crate allows up to 256 characters but the 63 limitation could be set
//! through the activation of this feature.
//!
//! ### `domain-name-length-limited-to-255`
//! The internet standards specifies that the total length of a FQDN is limited to 255 characters.
//! By default, the only limit is the available memory but the 255 limitation could be set
//! through the activation of this feature.
//!
//! ### `domain-name-without-special-chars`
//! The internet standards specifies that a FQDN should only contains digits, letters and hyphens (`-`).
//! But, many network equipment accept also `_` (underscore) without any problem. If this crate is used to design
//! something like a firewall, it could be necessary to deal with this, so do this feature.
//! At the contrary, the activation of this feature refuses these special characters.
//!
//! ### `domain-label-should-start-with-letter`
//! The internet standards specifies that FQDN should always start with a letter (nor a digit, nor a hyphen).
//! By default, this crate accept any of theses characters event at the first position.
//! The activation of this feature forces the use of a letter at the beginning of FQDN.
//!
//! ### `domain-label-should-have-trailing-dot`
//! The internet standards specifies that the human readable representation of FQDN should always end with a dot.
//! If this feature is activated, then parsing or printing a FQDN strictly apply this rule. By default,
//! the parsing behavior is more lenient (i.e. the trailing dot could miss).
//!
//! # RFC 1035
//! The RFC 1035 has some restrictions that are not activated by default.
//! The feature `strict-rfc-1035` activates all of them:
//! * `domain-label-length-limited-to-63`
//! * `domain-name-length-limited-to-255`
//! * `domain-name-without-special-chars`
//! * `domain-label-should-start-with-letter`
//! * `domain-label-should-have-trailing-dot`
//!
//! See above for more details.
//!
mod fqdnref;
mod fqdn;
mod check;
/// Parses a list of strings and creates an new
/// FQDN by concatenating them.
///
/// If the trailing dot is missing, it is automatically added.
///
/// # Examples
/// ```
/// use fqdn::fqdn;
///
/// let fqdn = fqdn!("rust-lang", "github.io");
/// ```
/// # Panics
/// If one of the elements is not a valid symbol, the macro panics.
/// ```should_panic
/// use fqdn::fqdn;
///
/// let s = fqdn!("w@w","fr"); // panics !!
/// ```
#[macro_export]
macro_rules! fqdn {
($($args:expr),*) => {{
#[allow(unused_mut)]
let mut str = std::string::String::new();
$( str += "."; str += $args; )*
match str.as_str().as_bytes().last() {
None => $crate::FQDN::default(),
Some(b'.') => str[1..].parse::<$crate::FQDN>().unwrap(),
_ => (str + ".")[1..].parse::<$crate::FQDN>().unwrap(),
}
}}
}
pub use crate::fqdn::FQDN;
pub use fqdnref::Fqdn;
pub use check::Error;
#[cfg(test)]
mod tests {
use crate as fqdn;
use fqdn::*;
#[test]
fn parsing_string()
{
assert!(FQDN::default().is_root());
assert!("github.com.".parse::<FQDN>().is_ok());
#[cfg(feature="domain-name-should-have-trailing-dot")]
assert_eq!("crates.io".parse::<FQDN>(), Err(fqdn::Error::TrailingDotMissing));
#[cfg(not(feature="domain-name-should-have-trailing-dot"))]
assert_eq!("crates.io".parse::<FQDN>().map(|fqdn| fqdn.to_string()), Ok("crates.io.".to_string()));
assert_eq!("github..com.".parse::<FQDN>(), Err(fqdn::Error::EmptyLabel));
assert_eq!(".github.com.".parse::<FQDN>(), Err(fqdn::Error::EmptyLabel));
assert_eq!("git@ub.com.".parse::<FQDN>(), Err(fqdn::Error::InvalidLabelChar));
}
#[test]
fn parsing_bytes()
{
assert!(Fqdn::from_bytes(b"\x06github\x03com\x00").is_ok());
assert_eq!(Fqdn::from_bytes(b"\x06github\x03com"), Err(fqdn::Error::TrailingNulCharMissing));
assert_eq!(Fqdn::from_bytes(b"\x06g|thub\x03com\x00"), Err(fqdn::Error::InvalidLabelChar));
#[cfg(feature="domain-label-should-start-with-letter")]
assert_eq!(Fqdn::from_bytes(b"\x04yeah\x0512345\x03com\x00"), Err(fqdn::Error::LabelDoesNotStartWithLetter));
}
#[test]
fn depth()
{
assert_eq!(".".parse::<FQDN>().map(|f| f.is_root()), Ok(true));
assert_eq!(".".parse::<FQDN>().map(|f| f.depth()), Ok(0));
assert_eq!("github.com.".parse::<FQDN>().map(|f| f.depth()), Ok(2));
assert_eq!("rust-lang.github.com.".parse::<FQDN>().map(|f| f.depth()), Ok(3));
}
#[test]
fn subdomains()
{
let a = "rust-lang.github.com.".parse::<FQDN>().unwrap();
let b = "GitHub.com.".parse::<FQDN>().unwrap();
assert!( a.is_subdomain_of(&a));
assert!( a.is_subdomain_of(&b));
assert!( !b.is_subdomain_of(&a));
assert!( fqdn!("com").is_tld() );
assert_eq!( a, fqdn!("rust-lang","github","com") );
}
}