use super::super::scan::Scanner;
use super::super::wire::ParseError;
use super::absolute::Name;
use super::builder::{FromStrError, NameBuilder, PushError};
use super::chain::{Chain, LongChainError};
use super::label::{Label, LabelTypeError, SplitLabelError};
use super::relative::{NameIter, RelativeName};
use super::traits::ToLabelIter;
#[cfg(feature = "bytes")]
use bytes::Bytes;
use core::{fmt, hash, str};
use octseq::builder::{
EmptyBuilder, FreezeBuilder, FromBuilder, IntoBuilder,
};
#[cfg(feature = "serde")]
use octseq::serde::{DeserializeOctets, SerializeOctets};
#[cfg(feature = "std")]
use std::vec::Vec;
#[derive(Clone)]
pub enum UncertainName<Octets> {
Absolute(Name<Octets>),
Relative(RelativeName<Octets>),
}
impl<Octets> UncertainName<Octets> {
pub fn absolute(name: Name<Octets>) -> Self {
UncertainName::Absolute(name)
}
pub fn relative(name: RelativeName<Octets>) -> Self {
UncertainName::Relative(name)
}
#[must_use]
pub fn root() -> Self
where
Octets: From<&'static [u8]>,
{
UncertainName::Absolute(Name::root())
}
#[must_use]
pub fn empty() -> Self
where
Octets: From<&'static [u8]>,
{
UncertainName::Relative(RelativeName::empty())
}
pub fn from_octets(octets: Octets) -> Result<Self, UncertainDnameError>
where
Octets: AsRef<[u8]>,
{
if Self::is_slice_absolute(octets.as_ref())? {
Ok(UncertainName::Absolute(unsafe {
Name::from_octets_unchecked(octets)
}))
} else {
Ok(UncertainName::Relative(unsafe {
RelativeName::from_octets_unchecked(octets)
}))
}
}
fn is_slice_absolute(
mut slice: &[u8],
) -> Result<bool, UncertainDnameError> {
if slice.len() > Name::MAX_LEN {
return Err(UncertainDnameErrorEnum::LongName.into());
}
loop {
let (label, tail) = Label::split_from(slice)?;
if label.is_root() {
if tail.is_empty() {
return Ok(true);
} else {
return Err(UncertainDnameErrorEnum::TrailingData.into());
}
}
if tail.is_empty() {
return Ok(false);
}
slice = tail;
}
}
pub fn from_chars<C>(chars: C) -> Result<Self, FromStrError>
where
Octets: FromBuilder,
<Octets as FromBuilder>::Builder: FreezeBuilder<Octets = Octets>
+ EmptyBuilder
+ AsRef<[u8]>
+ AsMut<[u8]>,
C: IntoIterator<Item = char>,
{
let mut builder =
NameBuilder::<<Octets as FromBuilder>::Builder>::new();
builder.append_chars(chars)?;
if builder.in_label() || builder.is_empty() {
Ok(builder.finish().into())
} else {
Ok(builder.into_name()?.into())
}
}
pub fn scan<S: Scanner<Name = Name<Octets>>>(
scanner: &mut S,
) -> Result<Self, S::Error> {
scanner.scan_name().map(UncertainName::Absolute)
}
}
impl UncertainName<&'static [u8]> {
#[must_use]
pub fn empty_ref() -> Self {
Self::empty()
}
#[must_use]
pub fn root_ref() -> Self {
Self::root()
}
}
#[cfg(feature = "std")]
impl UncertainName<Vec<u8>> {
#[must_use]
pub fn empty_vec() -> Self {
Self::empty()
}
#[must_use]
pub fn root_vec() -> Self {
Self::root()
}
}
#[cfg(feature = "bytes")]
impl UncertainName<Bytes> {
pub fn empty_bytes() -> Self {
Self::empty()
}
pub fn root_bytes() -> Self {
Self::root()
}
}
impl<Octets> UncertainName<Octets> {
pub fn is_absolute(&self) -> bool {
match *self {
UncertainName::Absolute(_) => true,
UncertainName::Relative(_) => false,
}
}
pub fn is_relative(&self) -> bool {
!self.is_absolute()
}
pub fn as_absolute(&self) -> Option<&Name<Octets>> {
match *self {
UncertainName::Absolute(ref name) => Some(name),
_ => None,
}
}
pub fn as_relative(&self) -> Option<&RelativeName<Octets>> {
match *self {
UncertainName::Relative(ref name) => Some(name),
_ => None,
}
}
pub fn into_absolute(self) -> Result<Name<Octets>, PushError>
where
Octets: AsRef<[u8]> + IntoBuilder,
<Octets as IntoBuilder>::Builder:
FreezeBuilder<Octets = Octets> + AsRef<[u8]> + AsMut<[u8]>,
{
match self {
UncertainName::Absolute(name) => Ok(name),
UncertainName::Relative(name) => name.into_absolute(),
}
}
pub fn try_into_absolute(self) -> Result<Name<Octets>, Self> {
if let UncertainName::Absolute(name) = self {
Ok(name)
} else {
Err(self)
}
}
pub fn try_into_relative(self) -> Result<RelativeName<Octets>, Self> {
if let UncertainName::Relative(name) = self {
Ok(name)
} else {
Err(self)
}
}
pub fn as_octets(&self) -> &Octets {
match *self {
UncertainName::Absolute(ref name) => name.as_octets(),
UncertainName::Relative(ref name) => name.as_octets(),
}
}
pub fn as_slice(&self) -> &[u8]
where
Octets: AsRef<[u8]>,
{
match *self {
UncertainName::Absolute(ref name) => name.as_slice(),
UncertainName::Relative(ref name) => name.as_slice(),
}
}
pub fn chain<S: ToLabelIter>(
self,
suffix: S,
) -> Result<Chain<Self, S>, LongChainError>
where
Octets: AsRef<[u8]>,
{
Chain::new_uncertain(self, suffix)
}
}
impl<Octets> From<Name<Octets>> for UncertainName<Octets> {
fn from(src: Name<Octets>) -> Self {
UncertainName::Absolute(src)
}
}
impl<Octets> From<RelativeName<Octets>> for UncertainName<Octets> {
fn from(src: RelativeName<Octets>) -> Self {
UncertainName::Relative(src)
}
}
impl<Octets> str::FromStr for UncertainName<Octets>
where
Octets: FromBuilder,
<Octets as FromBuilder>::Builder: EmptyBuilder
+ FreezeBuilder<Octets = Octets>
+ AsRef<[u8]>
+ AsMut<[u8]>,
{
type Err = FromStrError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::from_chars(s.chars())
}
}
impl<Octs> AsRef<Octs> for UncertainName<Octs> {
fn as_ref(&self) -> &Octs {
match *self {
UncertainName::Absolute(ref name) => name.as_ref(),
UncertainName::Relative(ref name) => name.as_ref(),
}
}
}
impl<Octs: AsRef<[u8]>> AsRef<[u8]> for UncertainName<Octs> {
fn as_ref(&self) -> &[u8] {
match *self {
UncertainName::Absolute(ref name) => name.as_ref(),
UncertainName::Relative(ref name) => name.as_ref(),
}
}
}
impl<Octets, Other> PartialEq<UncertainName<Other>> for UncertainName<Octets>
where
Octets: AsRef<[u8]>,
Other: AsRef<[u8]>,
{
fn eq(&self, other: &UncertainName<Other>) -> bool {
use UncertainName::*;
match (self, other) {
(Absolute(l), Absolute(r)) => l.eq(r),
(Relative(l), Relative(r)) => l.eq(r),
_ => false,
}
}
}
impl<Octets: AsRef<[u8]>> Eq for UncertainName<Octets> {}
impl<Octets: AsRef<[u8]>> hash::Hash for UncertainName<Octets> {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
for item in self.iter_labels() {
item.hash(state)
}
}
}
impl<Octs: AsRef<[u8]>> ToLabelIter for UncertainName<Octs> {
type LabelIter<'a> = NameIter<'a> where Octs: 'a;
fn iter_labels(&self) -> Self::LabelIter<'_> {
match *self {
UncertainName::Absolute(ref name) => name.iter_labels(),
UncertainName::Relative(ref name) => name.iter_labels(),
}
}
fn compose_len(&self) -> u16 {
match *self {
UncertainName::Absolute(ref name) => name.compose_len(),
UncertainName::Relative(ref name) => name.compose_len(),
}
}
}
impl<'a, Octets: AsRef<[u8]>> IntoIterator for &'a UncertainName<Octets> {
type Item = &'a Label;
type IntoIter = NameIter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter_labels()
}
}
impl<Octets: AsRef<[u8]>> fmt::Display for UncertainName<Octets> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
UncertainName::Absolute(ref name) => {
write!(f, "{}.", name)
}
UncertainName::Relative(ref name) => name.fmt(f),
}
}
}
impl<Octets: AsRef<[u8]>> fmt::Debug for UncertainName<Octets> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
UncertainName::Absolute(ref name) => {
write!(f, "UncertainName::Absolute({})", name)
}
UncertainName::Relative(ref name) => {
write!(f, "UncertainName::Relative({})", name)
}
}
}
}
#[cfg(feature = "serde")]
impl<Octets> serde::Serialize for UncertainName<Octets>
where
Octets: AsRef<[u8]> + SerializeOctets,
{
fn serialize<S: serde::Serializer>(
&self,
serializer: S,
) -> Result<S::Ok, S::Error> {
if serializer.is_human_readable() {
serializer.serialize_newtype_struct(
"UncertainName",
&format_args!("{}", self),
)
} else {
serializer.serialize_newtype_struct(
"UncertainName",
&self.as_octets().as_serialized_octets(),
)
}
}
}
#[cfg(feature = "serde")]
impl<'de, Octets> serde::Deserialize<'de> for UncertainName<Octets>
where
Octets: FromBuilder + DeserializeOctets<'de>,
<Octets as FromBuilder>::Builder: EmptyBuilder
+ FreezeBuilder<Octets = Octets>
+ AsRef<[u8]>
+ AsMut<[u8]>,
{
fn deserialize<D: serde::Deserializer<'de>>(
deserializer: D,
) -> Result<Self, D::Error> {
use core::marker::PhantomData;
struct InnerVisitor<'de, T: DeserializeOctets<'de>>(T::Visitor);
impl<'de, Octets> serde::de::Visitor<'de> for InnerVisitor<'de, Octets>
where
Octets: FromBuilder + DeserializeOctets<'de>,
<Octets as FromBuilder>::Builder: EmptyBuilder
+ FreezeBuilder<Octets = Octets>
+ AsRef<[u8]>
+ AsMut<[u8]>,
{
type Value = UncertainName<Octets>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("a domain name")
}
fn visit_str<E: serde::de::Error>(
self,
v: &str,
) -> Result<Self::Value, E> {
use core::str::FromStr;
UncertainName::from_str(v).map_err(E::custom)
}
fn visit_borrowed_bytes<E: serde::de::Error>(
self,
value: &'de [u8],
) -> Result<Self::Value, E> {
self.0.visit_borrowed_bytes(value).and_then(|octets| {
UncertainName::from_octets(octets).map_err(E::custom)
})
}
#[cfg(feature = "std")]
fn visit_byte_buf<E: serde::de::Error>(
self,
value: std::vec::Vec<u8>,
) -> Result<Self::Value, E> {
self.0.visit_byte_buf(value).and_then(|octets| {
UncertainName::from_octets(octets).map_err(E::custom)
})
}
}
struct NewtypeVisitor<T>(PhantomData<T>);
impl<'de, Octets> serde::de::Visitor<'de> for NewtypeVisitor<Octets>
where
Octets: FromBuilder + DeserializeOctets<'de>,
<Octets as FromBuilder>::Builder: EmptyBuilder
+ FreezeBuilder<Octets = Octets>
+ AsRef<[u8]>
+ AsMut<[u8]>,
{
type Value = UncertainName<Octets>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("a domain name")
}
fn visit_newtype_struct<D: serde::Deserializer<'de>>(
self,
deserializer: D,
) -> Result<Self::Value, D::Error> {
if deserializer.is_human_readable() {
deserializer
.deserialize_str(InnerVisitor(Octets::visitor()))
} else {
Octets::deserialize_with_visitor(
deserializer,
InnerVisitor(Octets::visitor()),
)
}
}
}
deserializer.deserialize_newtype_struct(
"UncertainName",
NewtypeVisitor(PhantomData),
)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct UncertainDnameError(UncertainDnameErrorEnum);
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum UncertainDnameErrorEnum {
BadLabel(LabelTypeError),
CompressedName,
LongName,
TrailingData,
ShortInput,
}
impl From<LabelTypeError> for UncertainDnameError {
fn from(err: LabelTypeError) -> Self {
Self(UncertainDnameErrorEnum::BadLabel(err))
}
}
impl From<SplitLabelError> for UncertainDnameError {
fn from(err: SplitLabelError) -> UncertainDnameError {
Self(match err {
SplitLabelError::Pointer(_) => {
UncertainDnameErrorEnum::CompressedName
}
SplitLabelError::BadType(t) => {
UncertainDnameErrorEnum::BadLabel(t)
}
SplitLabelError::ShortInput => {
UncertainDnameErrorEnum::ShortInput
}
})
}
}
impl From<UncertainDnameErrorEnum> for UncertainDnameError {
fn from(err: UncertainDnameErrorEnum) -> Self {
Self(err)
}
}
impl fmt::Display for UncertainDnameError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.0 {
UncertainDnameErrorEnum::BadLabel(ref err) => err.fmt(f),
UncertainDnameErrorEnum::CompressedName => {
f.write_str("compressed domain name")
}
UncertainDnameErrorEnum::LongName => {
f.write_str("long domain name")
}
UncertainDnameErrorEnum::TrailingData => {
f.write_str("trailing data")
}
UncertainDnameErrorEnum::ShortInput => {
ParseError::ShortInput.fmt(f)
}
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for UncertainDnameError {}
#[cfg(test)]
#[cfg(feature = "std")]
mod test {
use super::*;
use std::str::FromStr;
use std::string::String;
#[test]
fn from_str() {
type U = UncertainName<Vec<u8>>;
fn name(s: &str) -> U {
U::from_str(s).unwrap()
}
assert_eq!(
name("www.example.com").as_relative().unwrap().as_slice(),
b"\x03www\x07example\x03com"
);
assert_eq!(
name("www.example.com.").as_absolute().unwrap().as_slice(),
b"\x03www\x07example\x03com\0"
);
assert_eq!(
name(r"www\.example.com").as_slice(),
b"\x0bwww.example\x03com"
);
assert_eq!(
name(r"w\119w.example.com").as_slice(),
b"\x03www\x07example\x03com"
);
assert_eq!(
name(r"w\000w.example.com").as_slice(),
b"\x03w\0w\x07example\x03com"
);
U::from_str(r"w\01").unwrap_err();
U::from_str(r"w\").unwrap_err();
U::from_str(r"www..example.com").unwrap_err();
U::from_str(r"www.example.com..").unwrap_err();
U::from_str(r".www.example.com").unwrap_err();
U::from_str(r"www.\[322].example.com").unwrap_err();
U::from_str(r"www.\2example.com").unwrap_err();
U::from_str(r"www.\29example.com").unwrap_err();
U::from_str(r"www.\299example.com").unwrap_err();
U::from_str(r"www.\892example.com").unwrap_err();
U::from_str("www.e\0ample.com").unwrap_err();
U::from_str("www.eüample.com").unwrap_err();
let mut s = String::from("www.");
for _ in 0..Label::MAX_LEN {
s.push('x');
}
s.push_str(".com");
assert!(U::from_str(&s).is_ok());
let mut s = String::from("www.");
for _ in 0..64 {
s.push('x');
}
s.push_str(".com");
U::from_str(&s).unwrap_err();
let mut s = String::new();
for _ in 0..50 {
s.push_str("four.");
}
let mut s1 = s.clone();
s1.push_str("com.");
assert_eq!(name(&s1).as_slice().len(), 255);
let mut s1 = s.clone();
s1.push_str("com");
assert_eq!(name(&s1).as_slice().len(), 254);
let mut s1 = s.clone();
s1.push_str("coma.");
U::from_str(&s1).unwrap_err();
let mut s1 = s.clone();
s1.push_str("coma");
U::from_str(&s1).unwrap_err();
}
#[cfg(feature = "serde")]
#[test]
fn ser_de() {
use serde_test::{assert_tokens, Configure, Token};
let abs_name =
UncertainName::<Vec<u8>>::from_str("www.example.com.").unwrap();
assert!(abs_name.is_absolute());
assert_tokens(
&abs_name.clone().compact(),
&[
Token::NewtypeStruct {
name: "UncertainName",
},
Token::ByteBuf(b"\x03www\x07example\x03com\0"),
],
);
assert_tokens(
&abs_name.readable(),
&[
Token::NewtypeStruct {
name: "UncertainName",
},
Token::Str("www.example.com."),
],
);
let rel_name =
UncertainName::<Vec<u8>>::from_str("www.example.com").unwrap();
assert!(rel_name.is_relative());
assert_tokens(
&rel_name.clone().compact(),
&[
Token::NewtypeStruct {
name: "UncertainName",
},
Token::ByteBuf(b"\x03www\x07example\x03com"),
],
);
assert_tokens(
&rel_name.readable(),
&[
Token::NewtypeStruct {
name: "UncertainName",
},
Token::Str("www.example.com"),
],
);
}
}