use std::borrow::Borrow;
use std::char;
use std::cmp::{Ordering, PartialEq};
use std::fmt::{self, Write};
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::ops::Index;
use std::slice::Iter;
use std::str::FromStr;
use error::*;
use rr::domain::label::{CaseInsensitive, CaseSensitive, IntoLabel, Label, LabelCmp};
use rr::domain::usage::LOCALHOST as LOCALHOST_usage;
#[cfg(feature = "serde-config")]
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use serialize::binary::*;
#[derive(Clone, Default, Debug, Eq, Hash)]
pub struct Name {
is_fqdn: bool,
labels: Vec<Label>,
}
impl Name {
pub fn new() -> Self {
Default::default()
}
pub fn root() -> Self {
let mut this = Self::new();
this.is_fqdn = true;
this
}
pub fn is_root(&self) -> bool {
self.labels.is_empty() && self.is_fqdn()
}
pub fn is_fqdn(&self) -> bool {
self.is_fqdn
}
pub fn set_fqdn(&mut self, val: bool) {
self.is_fqdn = val
}
pub fn iter(&self) -> LabelIter {
LabelIter(self.labels.iter())
}
pub fn append_label<L: IntoLabel>(mut self, label: L) -> ProtoResult<Self> {
self.labels.push(label.into_label()?);
if self.labels.len() > 255 {
return Err("labels exceed maximum length of 255".into());
};
Ok(self)
}
pub fn from_labels<I, L>(labels: I) -> ProtoResult<Self>
where
I: IntoIterator<Item = L>,
L: IntoLabel,
{
let (labels, errors): (Vec<_>, Vec<_>) = labels
.into_iter()
.map(IntoLabel::into_label)
.partition(Result::is_ok);
let labels: Vec<_> = labels.into_iter().map(Result::unwrap).collect();
let errors: Vec<_> = errors.into_iter().map(Result::unwrap_err).collect();
if labels.len() > 255 {
return Err("labels exceed maximum length of 255".into());
};
if !errors.is_empty() {
return Err(format!("error converting some labels: {:?}", errors).into());
};
Ok(Name {
is_fqdn: true,
labels: labels,
})
}
pub fn append_name(mut self, other: &Self) -> Self {
self.labels.reserve_exact(other.labels.len());
for label in &other.labels {
self.labels.push(label.clone());
}
self.is_fqdn = other.is_fqdn;
self
}
pub fn append_domain(self, domain: &Self) -> Self {
let mut this = self.append_name(domain);
this.set_fqdn(true);
this
}
pub fn to_lowercase(&self) -> Self {
let mut new_labels: Vec<Label> = Vec::with_capacity(self.labels.len());
for label in &self.labels {
new_labels.push(label.to_lowercase())
}
Name {
is_fqdn: self.is_fqdn,
labels: new_labels,
}
}
pub fn base_name(&self) -> Name {
let length = self.labels.len();
if length > 0 {
return self.trim_to(length - 1);
}
self.clone()
}
pub fn trim_to(&self, num_labels: usize) -> Name {
if self.labels.len() >= num_labels {
let trim = self.labels.len() - num_labels;
Name {
is_fqdn: self.is_fqdn,
labels: self.labels[trim..].to_vec(),
}
} else {
self.clone()
}
}
pub fn zone_of_case(&self, name: &Self) -> bool {
let self_len = self.labels.len();
let name_len = name.labels.len();
if self_len == 0 {
return true;
}
if name_len == 0 {
return false;
}
if self_len > name_len {
return false;
}
let self_iter = self.iter().rev();
let name_iter = name.iter().rev();
let zip_iter = self_iter.zip(name_iter);
for (self_label, name_label) in zip_iter {
if self_label != name_label {
return false;
}
}
return true;
}
pub fn zone_of(&self, name: &Self) -> bool {
let self_lower = self.to_lowercase();
let name_lower = name.to_lowercase();
self_lower.zone_of_case(&name_lower)
}
pub fn num_labels(&self) -> u8 {
let num = self.labels.len() as u8;
self.labels
.first()
.map(|l| if l.is_wildcard() { num - 1 } else { num })
.unwrap_or(num)
}
pub fn len(&self) -> usize {
let dots = if !self.labels.is_empty() {
self.labels.len()
} else {
1
};
self.labels.iter().fold(dots, |acc, item| acc + item.len())
}
pub fn is_empty(&self) -> bool {
false
}
pub fn parse(local: &str, origin: Option<&Self>) -> ProtoResult<Self> {
Self::from_encoded_str::<LabelEncUtf8>(local, origin)
}
pub fn from_ascii<S: AsRef<str>>(name: S) -> ProtoResult<Self> {
Self::from_encoded_str::<LabelEncAscii>(name.as_ref(), None)
}
pub fn from_utf8<S: AsRef<str>>(name: S) -> ProtoResult<Self> {
Self::from_encoded_str::<LabelEncUtf8>(name.as_ref(), None)
}
pub fn from_str_relaxed<S: AsRef<str>>(name: S) -> ProtoResult<Self> {
let name = name.as_ref();
Self::from_utf8(name).or_else(|_| Self::from_ascii(name))
}
fn from_encoded_str<E: LabelEnc>(local: &str, origin: Option<&Self>) -> ProtoResult<Self> {
let mut name = Name::new();
let mut label = String::new();
let mut state = ParseState::Label;
if local == "." {
name.set_fqdn(true);
return Ok(name);
}
for ch in local.chars() {
match state {
ParseState::Label => match ch {
'.' => {
name.labels.push(E::to_label(&label)?);
label.clear();
}
'\\' => state = ParseState::Escape1,
ch if !ch.is_control() && !ch.is_whitespace() => label.push(ch),
_ => return Err(format!("unrecognized char: {}", ch).into()),
},
ParseState::Escape1 => {
if ch.is_numeric() {
state =
ParseState::Escape2(ch.to_digit(8).ok_or_else(|| {
ProtoError::from(format!("illegal char: {}", ch))
})?);
} else {
label.push(ch);
state = ParseState::Label;
}
}
ParseState::Escape2(i) => {
if ch.is_numeric() {
state = ParseState::Escape3(
i,
ch.to_digit(8)
.ok_or_else(|| ProtoError::from(format!("illegal char: {}", ch)))?,
);
} else {
return Err(ProtoError::from(format!("unrecognized char: {}", ch)))?;
}
}
ParseState::Escape3(i, ii) => {
if ch.is_numeric() {
let val: u32 = (i * 8 * 8)
+ (ii * 8)
+ ch.to_digit(8)
.ok_or_else(|| ProtoError::from(format!("illegal char: {}", ch)))?;
let new: char = char::from_u32(val)
.ok_or_else(|| ProtoError::from(format!("illegal char: {}", ch)))?;
label.push(new);
state = ParseState::Label;
} else {
return Err(format!("unrecognized char: {}", ch))?;
}
}
}
}
if !label.is_empty() {
name.labels.push(E::to_label(&label)?);
}
if local.ends_with('.') {
name.set_fqdn(true);
} else if let Some(other) = origin {
return Ok(name.append_domain(other));
}
Ok(name)
}
pub fn emit_as_canonical(&self, encoder: &mut BinEncoder, canonical: bool) -> ProtoResult<()> {
let buf_len = encoder.len();
let labels: &[Label] = &self.labels;
let mut labels_written: Vec<usize> = Vec::with_capacity(labels.len());
if canonical {
for label in labels {
encoder.emit_character_data(label)?;
}
} else {
for label in labels {
if label.len() > 63 {
return Err(ProtoErrorKind::LabelBytesTooLong(label.len()).into());
}
labels_written.push(encoder.offset());
encoder.emit_character_data(label)?;
}
let last_index = encoder.offset();
for label_idx in &labels_written {
let label_ptr: Option<u16> = encoder.get_label_pointer(*label_idx, last_index);
if let Some(loc) = label_ptr {
encoder.set_offset(*label_idx);
encoder.trim();
encoder.emit_u16(0xC000u16 | (loc & 0x3FFFu16))?;
return Ok(());
} else {
encoder.store_label_pointer(*label_idx, last_index);
}
}
}
encoder.emit(0)?;
let length = encoder.len() - buf_len;
if length > 255 {
return Err(ProtoErrorKind::DomainNameTooLong(length).into());
}
Ok(())
}
pub fn emit_with_lowercase(
&self,
encoder: &mut BinEncoder,
lowercase: bool,
) -> ProtoResult<()> {
let is_canonical_names = encoder.is_canonical_names();
if lowercase {
self.to_lowercase()
.emit_as_canonical(encoder, is_canonical_names)
} else {
self.emit_as_canonical(encoder, is_canonical_names)
}
}
fn cmp_with_f<F: LabelCmp>(&self, other: &Self) -> Ordering {
if self.labels.is_empty() && other.labels.is_empty() {
return Ordering::Equal;
}
let self_labels = self.labels.iter().rev();
let other_labels = other.labels.iter().rev();
for (l, r) in self_labels.zip(other_labels) {
match l.cmp_with_f::<F>(r) {
Ordering::Equal => continue,
not_eq => return not_eq,
}
}
self.labels.len().cmp(&other.labels.len())
}
pub fn cmp_case(&self, other: &Self) -> Ordering {
self.cmp_with_f::<CaseSensitive>(other)
}
pub fn eq_case(&self, other: &Self) -> bool {
self.cmp_with_f::<CaseSensitive>(other) == Ordering::Equal
}
pub fn to_ascii(&self) -> String {
let mut s = String::with_capacity(self.len());
self.write_labels::<String, LabelEncAscii>(&mut s)
.expect("string conversion of name should not fail");
s
}
pub fn to_utf8(&self) -> String {
format!("{}", self)
}
fn write_labels<W: Write, E: LabelEnc>(&self, f: &mut W) -> Result<(), fmt::Error> {
let mut iter = self.labels.iter();
if let Some(label) = iter.next() {
E::write_label(f, label)?;
}
for label in iter {
write!(f, ".")?;
E::write_label(f, label)?;
}
if self.is_root() || self.is_fqdn() {
write!(f, ".")?;
}
Ok(())
}
pub fn is_localhost(&self) -> bool {
LOCALHOST_usage.zone_of(self)
}
}
trait LabelEnc {
fn to_label(name: &str) -> ProtoResult<Label>;
fn write_label<W: Write>(f: &mut W, label: &Label) -> Result<(), fmt::Error>;
}
struct LabelEncAscii;
impl LabelEnc for LabelEncAscii {
fn to_label(name: &str) -> ProtoResult<Label> {
Label::from_ascii(name)
}
fn write_label<W: Write>(f: &mut W, label: &Label) -> Result<(), fmt::Error> {
label.write_ascii(f)
}
}
struct LabelEncUtf8;
impl LabelEnc for LabelEncUtf8 {
fn to_label(name: &str) -> ProtoResult<Label> {
Label::from_utf8(name)
}
fn write_label<W: Write>(f: &mut W, label: &Label) -> Result<(), fmt::Error> {
write!(f, "{}", label)
}
}
pub struct LabelIter<'a>(Iter<'a, Label>);
impl<'a> Iterator for LabelIter<'a> {
type Item = &'a [u8];
fn next(&mut self) -> Option<Self::Item> {
self.0.next().map(|s| s.borrow())
}
}
impl<'a> ExactSizeIterator for LabelIter<'a> {}
impl<'a> DoubleEndedIterator for LabelIter<'a> {
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back().map(|s| s.borrow())
}
}
impl<'a> IntoIterator for &'a Name {
type Item = &'a [u8];
type IntoIter = LabelIter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl From<IpAddr> for Name {
fn from(addr: IpAddr) -> Name {
match addr {
IpAddr::V4(ip) => ip.into(),
IpAddr::V6(ip) => ip.into(),
}
}
}
impl From<Ipv4Addr> for Name {
fn from(addr: Ipv4Addr) -> Name {
let octets = addr.octets();
let mut labels =
octets
.iter()
.rev()
.fold(Vec::<Label>::with_capacity(6), |mut labels, o| {
let label: Label = format!("{}", o)
.as_bytes()
.into_label()
.expect("IP octet to label should never fail");
labels.push(label);
labels
});
labels.push(
"in-addr"
.as_bytes()
.into_label()
.expect("simple name should never fail"),
);
labels.push(
"arpa"
.as_bytes()
.into_label()
.expect("simple name should never fail"),
);
Self::from_labels(labels).expect("a translation of Ipv4Addr should never fail")
}
}
impl From<Ipv6Addr> for Name {
fn from(addr: Ipv6Addr) -> Name {
let segments = addr.segments();
let mut labels =
segments
.iter()
.rev()
.fold(Vec::<Label>::with_capacity(34), |mut labels, o| {
labels.push(
format!("{:x}", (*o & 0x000F) as u8)
.as_bytes()
.into_label()
.expect("IP octet to label should never fail"),
);
labels.push(
format!("{:x}", (*o >> 4 & 0x000F) as u8)
.as_bytes()
.into_label()
.expect("IP octet to label should never fail"),
);
labels.push(
format!("{:x}", (*o >> 8 & 0x000F) as u8)
.as_bytes()
.into_label()
.expect("IP octet to label should never fail"),
);
labels.push(
format!("{:x}", (*o >> 12 & 0x000F) as u8)
.as_bytes()
.into_label()
.expect("IP octet to label should never fail"),
);
labels
});
labels.push(
"ip6"
.as_bytes()
.into_label()
.expect("simple name should never fail"),
);
labels.push(
"arpa"
.as_bytes()
.into_label()
.expect("simple name should never fail"),
);
Self::from_labels(labels).expect("a translation of Ipv6Addr should never fail")
}
}
impl PartialEq<Name> for Name {
fn eq(&self, other: &Self) -> bool {
self.cmp_with_f::<CaseInsensitive>(other) == Ordering::Equal
}
}
enum ParseState {
Label,
Escape1,
Escape2(u32),
Escape3(u32, u32),
}
impl BinEncodable for Name {
fn emit(&self, encoder: &mut BinEncoder) -> ProtoResult<()> {
let is_canonical_names = encoder.is_canonical_names();
self.emit_as_canonical(encoder, is_canonical_names)
}
}
impl<'r> BinDecodable<'r> for Name {
fn read(decoder: &mut BinDecoder<'r>) -> ProtoResult<Name> {
read_inner(decoder, None)
}
}
fn read_inner<'r>(decoder: &mut BinDecoder<'r>, max_idx: Option<usize>) -> ProtoResult<Name> {
let mut state: LabelParseState = LabelParseState::LabelLengthOrPointer;
let mut labels: Vec<Label> = Vec::with_capacity(3);
let name_start = decoder.index();
let mut run_len = 0_usize;
loop {
if let Some(max_idx) = max_idx {
if decoder.index() >= max_idx {
return Err(ProtoErrorKind::LabelOverlapsWithOther {
label: name_start,
other: max_idx,
}
.into());
}
}
let cur_len = run_len + labels.len();
if cur_len > 255 {
return Err(ProtoErrorKind::DomainNameTooLong(cur_len).into());
}
state = match state {
LabelParseState::LabelLengthOrPointer => {
match decoder.peek().map(Restrict::unverified) {
Some(0) | None => LabelParseState::Root,
Some(byte) if byte & 0b1100_0000 == 0b1100_0000 => LabelParseState::Pointer,
Some(byte) if byte & 0b1100_0000 == 0b0000_0000 => LabelParseState::Label,
Some(byte) => return Err(ProtoErrorKind::UnrecognizedLabelCode(byte).into()),
}
}
LabelParseState::Label => {
let label = decoder
.read_character_data_max(Some(63))?
.verify_unwrap(|l| l.len() <= 63)
.map_err(|_| ProtoError::from("label exceeds maximum length of 63"))?;
run_len += label.len();
labels.push(label.into_label()?);
LabelParseState::LabelLengthOrPointer
}
LabelParseState::Pointer => {
let pointer_location = decoder.index();
let location = decoder
.read_u16()?
.map(|u| {
u & 0x3FFF
})
.verify_unwrap(|ptr| {
(*ptr as usize) < name_start
})
.map_err(|e| {
ProtoError::from(ProtoErrorKind::PointerNotPriorToLabel {
idx: pointer_location,
ptr: e,
})
})?;
let mut pointer = decoder.clone(location);
let pointed = read_inner(&mut pointer, Some(name_start))?;
for l in &*pointed.labels {
if l.len() > 0 {
run_len += l.len();
}
labels.push(l.clone());
}
break;
}
LabelParseState::Root => {
decoder.pop()?;
break;
}
}
}
run_len += if labels.is_empty() { 1 } else { labels.len() };
let name = Name {
is_fqdn: true,
labels: labels,
};
debug_assert_eq!(run_len, name.len());
Ok(name)
}
impl fmt::Display for Name {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.write_labels::<fmt::Formatter, LabelEncUtf8>(f)
}
}
impl Index<usize> for Name {
type Output = Label;
fn index(&self, _index: usize) -> &Label {
&self.labels[_index]
}
}
impl PartialOrd<Name> for Name {
fn partial_cmp(&self, other: &Name) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Name {
fn cmp(&self, other: &Self) -> Ordering {
self.cmp_with_f::<CaseInsensitive>(other)
}
}
enum LabelParseState {
LabelLengthOrPointer,
Label,
Pointer,
Root,
}
impl FromStr for Name {
type Err = ProtoError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Name::from_str_relaxed(s)
}
}
pub trait IntoName: Sized {
fn into_name(self) -> ProtoResult<Name>;
}
impl<'a> IntoName for &'a Name {
fn into_name(self) -> ProtoResult<Name> {
Ok(self.clone())
}
}
impl IntoName for Name {
fn into_name(self) -> ProtoResult<Name> {
Ok(self.clone())
}
}
impl<'a> IntoName for &'a str {
fn into_name(self) -> ProtoResult<Name> {
Name::from_utf8(self)
}
}
impl IntoName for String {
fn into_name(self) -> ProtoResult<Name> {
Name::from_utf8(self)
}
}
#[cfg(feature = "serde-config")]
impl Serialize for Name {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.to_string())
}
}
#[cfg(feature = "serde-config")]
impl<'de> Deserialize<'de> for Name {
fn deserialize<D>(deserializer: D) -> Result<Name, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
FromStr::from_str(&s).map_err(de::Error::custom)
}
}
#[cfg(test)]
mod tests {
use std::cmp::Ordering;
use std::str::FromStr;
use super::*;
use serialize::binary::bin_tests::{test_emit_data_set, test_read_data_set};
#[allow(unused)]
use serialize::binary::*;
fn get_data() -> Vec<(Name, Vec<u8>)> {
vec![
(Name::new(), vec![0]),
(Name::from_str("a").unwrap(), vec![1, b'a', 0]),
(
Name::from_str("a.bc").unwrap(),
vec![1, b'a', 2, b'b', b'c', 0],
),
(
Name::from_str("a.♥").unwrap(),
vec![1, b'a', 7, b'x', b'n', b'-', b'-', b'g', b'6', b'h', 0],
),
]
}
#[test]
fn test_num_labels() {
assert_eq!(Name::from_str("*").unwrap().num_labels(), 0);
assert_eq!(Name::from_str("a").unwrap().num_labels(), 1);
assert_eq!(Name::from_str("*.b").unwrap().num_labels(), 1);
assert_eq!(Name::from_str("a.b").unwrap().num_labels(), 2);
assert_eq!(Name::from_str("*.b.c").unwrap().num_labels(), 2);
assert_eq!(Name::from_str("a.b.c").unwrap().num_labels(), 3);
}
#[test]
fn test_read() {
test_read_data_set(get_data(), |ref mut d| Name::read(d));
}
#[test]
fn test_write_to() {
test_emit_data_set(get_data(), |e, n| n.emit(e));
}
#[test]
fn test_pointer() {
let mut bytes: Vec<u8> = Vec::with_capacity(512);
let first = Name::from_str("ra.rb.rc").unwrap();
let second = Name::from_str("rb.rc").unwrap();
let third = Name::from_str("rc").unwrap();
let fourth = Name::from_str("z.ra.rb.rc").unwrap();
{
let mut e = BinEncoder::new(&mut bytes);
first.emit(&mut e).unwrap();
assert_eq!(e.len(), 10);
second.emit(&mut e).unwrap();
assert_eq!(e.len(), 12);
third.emit(&mut e).unwrap();
assert_eq!(e.len(), 14);
fourth.emit(&mut e).unwrap();
assert_eq!(e.len(), 18);
}
let mut d = BinDecoder::new(&bytes);
let r_test = Name::read(&mut d).unwrap();
assert_eq!(first, r_test);
let r_test = Name::read(&mut d).unwrap();
assert_eq!(second, r_test);
let r_test = Name::read(&mut d).unwrap();
assert_eq!(third, r_test);
let r_test = Name::read(&mut d).unwrap();
assert_eq!(fourth, r_test);
}
#[test]
fn test_recursive_pointer() {
let bytes = vec![0xC0, 0x01];
let mut d = BinDecoder::new(&bytes);
assert!(Name::read(&mut d).is_err());
let bytes = vec![0xC0, 0x00];
let mut d = BinDecoder::new(&bytes);
assert!(Name::read(&mut d).is_err());
let bytes = vec![0x01, 0x41, 0xC0, 0x00];
let mut d = BinDecoder::new(&bytes);
assert!(Name::read(&mut d).is_err());
let bytes = vec![0xC0, 0x02, 0xC0, 0x00];
let mut d = BinDecoder::new(&bytes);
assert!(Name::read(&mut d).is_err());
}
#[test]
fn test_bin_overlap_enforced() {
let mut bytes = Vec::with_capacity(512);
let n = 31;
for _ in 0..=5 {
for _ in 0..=n {
bytes.push(n);
}
}
bytes.push(n + 1);
for b in (0..n).into_iter() {
bytes.push(1 + n + b);
}
bytes.extend_from_slice(&[1, 0]);
for b in 0..n {
bytes.extend_from_slice(&[0xC0, b]);
}
let mut d = BinDecoder::new(&bytes);
d.read_slice(n as usize).unwrap();
assert!(Name::read(&mut d).is_err());
}
#[test]
fn test_bin_max_octets() {
let mut bytes = Vec::with_capacity(512);
for _ in 0..256 {
bytes.extend_from_slice(&[1, b'a']);
}
bytes.push(0);
let mut d = BinDecoder::new(&bytes);
assert!(Name::read(&mut d).is_err());
}
#[test]
fn test_base_name() {
let zone = Name::from_str("example.com.").unwrap();
assert_eq!(zone.base_name(), Name::from_str("com").unwrap());
assert!(zone.base_name().base_name().is_root());
assert!(zone.base_name().base_name().base_name().is_root());
}
#[test]
fn test_zone_of() {
let zone = Name::from_str("example.com").unwrap();
let www = Name::from_str("www.example.com").unwrap();
let none = Name::from_str("none.com").unwrap();
let root = Name::root();
assert!(zone.zone_of(&zone));
assert!(zone.zone_of(&www));
assert!(!zone.zone_of(&none));
assert!(root.zone_of(&zone));
assert!(!zone.zone_of(&root));
}
#[test]
fn test_zone_of_case() {
let zone = Name::from_ascii("examplE.cOm").unwrap();
let www = Name::from_str("www.example.com").unwrap();
let none = Name::from_str("none.com").unwrap();
assert!(zone.zone_of(&zone));
assert!(zone.zone_of(&www));
assert!(!zone.zone_of(&none))
}
#[test]
fn test_partial_cmp_eq() {
let root = Some(Name::from_labels(Vec::<&str>::new()).unwrap());
let comparisons: Vec<(Name, Name)> = vec![
(root.clone().unwrap(), root.clone().unwrap()),
(
Name::parse("example.", root.as_ref()).unwrap(),
Name::parse("example", root.as_ref()).unwrap(),
),
];
for (left, right) in comparisons {
println!("left: {}, right: {}", left, right);
assert_eq!(left.partial_cmp(&right), Some(Ordering::Equal));
}
}
#[test]
fn test_partial_cmp() {
let comparisons: Vec<(Name, Name)> = vec![
(
Name::from_str("example.").unwrap(),
Name::from_str("a.example.").unwrap(),
),
(
Name::from_str("a.example.").unwrap(),
Name::from_str("yljkjljk.a.example.").unwrap(),
),
(
Name::from_str("yljkjljk.a.example.").unwrap(),
Name::from_ascii("Z.a.example.").unwrap(),
),
(
Name::from_ascii("Z.a.example.").unwrap(),
Name::from_ascii("zABC.a.EXAMPLE").unwrap(),
),
(
Name::from_ascii("zABC.a.EXAMPLE.").unwrap(),
Name::from_str("z.example.").unwrap(),
),
(
Name::from_str("z.example.").unwrap(),
Name::from_labels(vec![
&[001u8] as &[u8],
"z".as_bytes(),
"example".as_bytes(),
]).unwrap(),
),
(
Name::from_labels(vec![
&[001u8] as &[u8],
"z".as_bytes(),
"example".as_bytes(),
]).unwrap(),
Name::from_str("*.z.example.").unwrap(),
),
(
Name::from_str("*.z.example.").unwrap(),
Name::from_labels(vec![
&[200u8] as &[u8],
"z".as_bytes(),
"example".as_bytes(),
]).unwrap(),
),
];
for (left, right) in comparisons {
println!("left: {}, right: {}", left, right);
assert_eq!(left.cmp(&right), Ordering::Less);
}
}
#[test]
fn test_cmp_ignore_case() {
let comparisons: Vec<(Name, Name)> = vec![
(
Name::from_ascii("ExAmPle.").unwrap(),
Name::from_ascii("example.").unwrap(),
),
(
Name::from_ascii("A.example.").unwrap(),
Name::from_ascii("a.example.").unwrap(),
),
];
for (left, right) in comparisons {
println!("left: {}, right: {}", left, right);
assert_eq!(left, right);
}
}
#[test]
fn test_from_ipv4() {
let ip = IpAddr::V4(Ipv4Addr::new(26, 3, 0, 103));
let name = Name::from_str("103.0.3.26.in-addr.arpa").unwrap();
assert_eq!(Into::<Name>::into(ip), name);
}
#[test]
fn test_from_ipv6() {
let ip = IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0x1));
let name = Name::from_str(
"1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa",
)
.unwrap();
assert_eq!(Into::<Name>::into(ip), name);
}
#[test]
fn test_from_str() {
assert_eq!(
Name::from_str("www.example.com.").unwrap(),
Name::from_labels(vec![
"www".as_bytes(),
"example".as_bytes(),
"com".as_bytes()
]).unwrap()
);
assert_eq!(
Name::from_str(".").unwrap(),
Name::from_labels(Vec::<&str>::new()).unwrap()
);
}
#[test]
fn test_fqdn() {
assert!(Name::root().is_fqdn());
assert!(Name::from_str(".").unwrap().is_fqdn());
assert!(Name::from_str("www.example.com.").unwrap().is_fqdn());
assert!(Name::from_labels(vec![b"www" as &[u8], b"example", b"com"])
.unwrap()
.is_fqdn());
assert!(!Name::new().is_fqdn());
assert!(!Name::from_str("www.example.com").unwrap().is_fqdn());
assert!(!Name::from_str("www.example").unwrap().is_fqdn());
assert!(!Name::from_str("www").unwrap().is_fqdn());
}
#[test]
fn test_to_string() {
assert_eq!(
Name::from_str("www.example.com.").unwrap().to_string(),
"www.example.com."
);
assert_eq!(
Name::from_str("www.example.com").unwrap().to_string(),
"www.example.com"
);
}
#[test]
fn test_from_ascii() {
let bytes_name = Name::from_labels(vec![
"WWW".as_bytes(),
"example".as_bytes(),
"COM".as_bytes(),
]).unwrap();
let ascii_name = Name::from_ascii("WWW.example.COM.").unwrap();
let lower_name = Name::from_ascii("www.example.com.").unwrap();
assert!(bytes_name.eq_case(&ascii_name));
assert!(!lower_name.eq_case(&ascii_name));
}
#[test]
fn test_from_utf8() {
let bytes_name = Name::from_labels(vec![
"WWW".as_bytes(),
"example".as_bytes(),
"COM".as_bytes(),
]).unwrap();
let utf8_name = Name::from_utf8("WWW.example.COM.").unwrap();
let lower_name = Name::from_utf8("www.example.com.").unwrap();
assert!(!bytes_name.eq_case(&utf8_name));
assert!(lower_name.eq_case(&utf8_name));
}
#[test]
fn test_into_name() {
let name = Name::from_utf8("www.example.com").unwrap();
assert_eq!(
Name::from_utf8("www.example.com").unwrap(),
(&name).into_name().unwrap()
);
assert_eq!(
Name::from_utf8("www.example.com").unwrap(),
Name::from_utf8("www.example.com")
.unwrap()
.into_name()
.unwrap()
);
assert_eq!(
Name::from_utf8("www.example.com").unwrap(),
"www.example.com".into_name().unwrap()
);
assert_eq!(
Name::from_utf8("www.example.com").unwrap(),
"www.example.com".to_string().into_name().unwrap()
);
}
#[test]
fn test_encoding() {
assert_eq!(
Name::from_ascii("WWW.example.COM.").unwrap().to_ascii(),
"WWW.example.COM."
);
assert_eq!(
Name::from_utf8("WWW.example.COM.").unwrap().to_ascii(),
"www.example.com."
);
assert_eq!(
Name::from_ascii("WWW.example.COM.").unwrap().to_utf8(),
"WWW.example.COM."
);
}
#[test]
fn test_excessive_encoding_len() {
use error::ProtoErrorKind;
let mut buf = Vec::with_capacity(u16::max_value() as usize);
let mut encoder = BinEncoder::new(&mut buf);
let mut result = Ok(());
for i in 0..10000 {
let name = Name::from_ascii(format!("name{}.example.com.", i)).unwrap();
result = name.emit(&mut encoder);
if let Err(..) = result {
break;
}
}
assert!(result.is_err());
match *result.unwrap_err().kind() {
ProtoErrorKind::MaxBufferSizeExceeded(_) => (),
_ => assert!(false),
}
}
#[test]
fn test_underscore() {
Name::from_str("_begin.example.com").expect("failed at beginning");
Name::from_str_relaxed("mid_dle.example.com").expect("failed in the middle");
Name::from_str_relaxed("end_.example.com").expect("failed at the end");
}
}