#![allow(clippy::needless_maybe_sized)]
#[cfg(feature = "std")]
use std::collections::BTreeMap;
#[cfg(feature = "std")]
use std::string::String;
use super::value::AllValues;
use crate::base::cmp::CanonicalOrd;
use crate::base::iana::SvcParamKey;
use crate::base::scan::{Scanner, ScannerError, Symbol};
use crate::base::wire::{Compose, Parse, ParseError};
use crate::base::zonefile_fmt::{self, Formatter, ZonefileFmt};
use core::cmp::Ordering;
use core::marker::PhantomData;
#[cfg(feature = "std")]
use core::str::FromStr;
use core::{cmp, fmt, hash, mem};
use octseq::builder::{EmptyBuilder, FromBuilder, OctetsBuilder, ShortBuf};
use octseq::octets::{Octets, OctetsFrom, OctetsInto};
use octseq::parse::{Parser, ShortInput};
use octseq::FreezeBuilder;
#[derive(Clone, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(transparent)]
pub struct SvcParams<Octs: ?Sized> {
#[cfg_attr(
feature = "serde",
serde(
serialize_with = "octseq::serde::SerializeOctets::serialize_octets",
deserialize_with = "octseq::serde::DeserializeOctets::deserialize_octets",
bound(
serialize = "Octs: octseq::serde::SerializeOctets",
deserialize = "Octs: octseq::serde::DeserializeOctets<'de> + Sized",
)
)
)]
octets: Octs,
}
impl<Octs> SvcParams<Octs> {
pub fn from_octets(octets: Octs) -> Result<Self, SvcParamsError>
where
Octs: AsRef<[u8]>,
{
SvcParams::check_slice(octets.as_ref())?;
Ok(unsafe { Self::from_octets_unchecked(octets) })
}
pub unsafe fn from_octets_unchecked(octets: Octs) -> Self {
SvcParams { octets }
}
}
impl SvcParams<[u8]> {
pub fn from_slice(slice: &[u8]) -> Result<&Self, SvcParamsError> {
SvcParams::check_slice(slice)?;
Ok(unsafe { Self::from_slice_unchecked(slice) })
}
#[must_use]
pub unsafe fn from_slice_unchecked(slice: &[u8]) -> &Self {
mem::transmute(slice)
}
fn check_slice(slice: &[u8]) -> Result<(), SvcParamsError> {
let mut parser = Parser::from_ref(slice);
let mut last_key = None;
while parser.remaining() > 0 {
let key = u16::parse(&mut parser)?;
if let Some(last_key) = last_key {
if key <= last_key {
Err(ParseError::form_error("unordered SVCB params"))?;
}
}
last_key = Some(key);
let len = u16::parse(&mut parser)?;
parser.advance(len.into())?;
}
Ok(())
}
}
impl<Octs> SvcParams<Octs> {
pub fn from_values<F>(op: F) -> Result<Self, PushError>
where
Octs: FromBuilder,
<Octs as FromBuilder>::Builder:
AsRef<[u8]> + OctetsBuilder + EmptyBuilder,
F: FnOnce(
&mut SvcParamsBuilder<<Octs as FromBuilder>::Builder>,
) -> Result<(), PushError>,
{
let mut res = SvcParamsBuilder::empty();
op(&mut res)?;
res.freeze().map_err(Into::into)
}
}
impl<Octs: AsRef<[u8]>> SvcParams<Octs> {
pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized + 'a>(
parser: &mut Parser<'a, Src>,
) -> Result<Self, ParseError> {
Self::from_octets(parser.parse_octets(parser.remaining())?)
.map_err(Into::into)
}
}
#[cfg(feature = "std")]
impl<Octs: AsRef<[u8]>> SvcParams<Octs> {
pub fn scan<S: Scanner<Octets = Octs>>(
scanner: &mut S,
) -> Result<Self, S::Error> {
fn allowed_key_charset(ch: u8) -> bool {
(0x61..0x7A).contains(&ch)
|| (0x30..0x39).contains(&ch)
|| 0x2D == ch
}
let mut builder = scanner.octets_builder()?;
let mut key_map = BTreeMap::<SvcParamKey, AllValues<Octs>>::new();
while scanner.continues() {
let mut is_key = true;
let mut key_end = None;
let mut value_start = None;
let octs = scanner.scan_svcb_octets()?;
if octs.as_ref().is_empty() {
return Err(S::Error::custom("SvcParams cannot be empty"));
}
for (i, &ch) in octs.as_ref().iter().enumerate() {
if is_key {
if !allowed_key_charset(ch) {
if ch == b'=' {
key_end = Some(i);
is_key = false;
} else {
return Err(ScannerError::custom(
"invalid SvcParamKey",
));
}
}
} else if value_start.is_none() {
value_start = Some(i);
}
}
let param_key = if let Some(key_end) = key_end {
SvcParamKey::from_str(&String::from_utf8_lossy(
&octs.as_ref()[0..key_end],
))
} else {
SvcParamKey::from_str(&String::from_utf8_lossy(octs.as_ref()))
}
.map_err(|_| ScannerError::custom("unknown SvcParamKey"))?;
let param_value = if let Some(value_start) = value_start {
let value = &octs.as_ref()[value_start..];
AllValues::<Octs>::value_from_scan_octets(
scanner, param_key, value,
)?
.ok_or(S::Error::custom("could not parse SvcParamValue"))?
} else {
AllValues::<Octs>::value_from_scan_octets(
scanner,
param_key,
&[],
)?
.ok_or(S::Error::custom(
"could not parse SvcParamValue from empty value",
))?
};
if key_map.insert(param_key, param_value).is_some() {
return Err(S::Error::custom("duplicate SvcParamKey"));
}
}
for (param_key, param_value) in &key_map {
param_key
.compose(&mut builder)
.map_err(|_| S::Error::short_buf())?;
let value_len = param_value.compose_len();
value_len
.compose(&mut builder)
.map_err(|_| S::Error::short_buf())?;
param_value
.compose_value(&mut builder)
.map_err(|_| S::Error::short_buf())?;
if let AllValues::Mandatory(m) = ¶m_value {
for req in m.iter() {
if !key_map.contains_key(&req) {
return Err(S::Error::custom("all SvcParamKeys listed in mandatory MUST appear in SvcParams"));
}
}
}
}
SvcParams::from_octets(builder.freeze()).map_err(|e| {
println!("error in params::from_octets = {}", &e.0);
S::Error::custom("invalid SvcParams")
})
}
}
impl<Octs: ?Sized> SvcParams<Octs> {
pub fn as_octets(&self) -> &Octs {
&self.octets
}
}
impl<Octs: AsRef<[u8]> + ?Sized> SvcParams<Octs> {
pub fn as_slice(&self) -> &[u8] {
self.octets.as_ref()
}
pub fn for_slice(&self) -> &SvcParams<[u8]> {
unsafe { SvcParams::from_slice_unchecked(self.octets.as_ref()) }
}
pub fn len(&self) -> usize {
self.octets.as_ref().len()
}
pub fn is_empty(&self) -> bool {
self.octets.as_ref().is_empty()
}
pub fn first<'s, Value>(&'s self) -> Option<Value>
where
Octs: Octets,
Value: ParseSvcParamValue<'s, Octs>,
{
self.iter::<Value>().next().and_then(Result::ok)
}
pub fn iter<Value>(&self) -> ValueIter<'_, Octs, Value> {
ValueIter::new(self.as_octets())
}
pub fn iter_all(&self) -> ValueIter<'_, Octs, AllValues<Octs>>
where
Octs: Sized,
{
self.iter()
}
pub fn iter_raw(
&self,
) -> impl Iterator<Item = UnknownSvcParam<Octs::Range<'_>>>
where
Octs: Octets + Sized,
{
self.iter()
.map(|item| item.expect("parsing cannot have failed"))
}
pub fn compose<Target: OctetsBuilder + ?Sized>(
&self,
target: &mut Target,
) -> Result<(), Target::AppendError> {
target.append_slice(self.octets.as_ref())
}
}
impl<SrcOcts, Octs> OctetsFrom<SvcParams<SrcOcts>> for SvcParams<Octs>
where
Octs: OctetsFrom<SrcOcts>,
{
type Error = Octs::Error;
fn try_octets_from(src: SvcParams<SrcOcts>) -> Result<Self, Self::Error> {
Ok(unsafe {
SvcParams::from_octets_unchecked(src.octets.try_octets_into()?)
})
}
}
impl<Octs, OtherOcts> PartialEq<SvcParams<OtherOcts>> for SvcParams<Octs>
where
Octs: AsRef<[u8]> + ?Sized,
OtherOcts: AsRef<[u8]> + ?Sized,
{
fn eq(&self, other: &SvcParams<OtherOcts>) -> bool {
self.as_slice().eq(other.as_slice())
}
}
impl<Octs: AsRef<[u8]> + ?Sized> Eq for SvcParams<Octs> {}
impl<Octs: AsRef<[u8]> + ?Sized> hash::Hash for SvcParams<Octs> {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.as_slice().hash(state)
}
}
impl<Octs, OtherOcts> PartialOrd<SvcParams<OtherOcts>> for SvcParams<Octs>
where
Octs: AsRef<[u8]> + ?Sized,
OtherOcts: AsRef<[u8]> + ?Sized,
{
fn partial_cmp(
&self,
other: &SvcParams<OtherOcts>,
) -> Option<cmp::Ordering> {
self.as_slice().partial_cmp(other.as_slice())
}
}
impl<Octs: AsRef<[u8]> + ?Sized> Ord for SvcParams<Octs> {
fn cmp(&self, other: &Self) -> cmp::Ordering {
self.as_slice().cmp(other.as_slice())
}
}
impl<Octs, OtherOcts> CanonicalOrd<SvcParams<OtherOcts>> for SvcParams<Octs>
where
Octs: AsRef<[u8]> + ?Sized,
OtherOcts: AsRef<[u8]> + ?Sized,
{
fn canonical_cmp(&self, other: &SvcParams<OtherOcts>) -> cmp::Ordering {
self.as_slice().cmp(other.as_slice())
}
}
impl<Octs: AsRef<[u8]> + ?Sized> fmt::Display for SvcParams<Octs> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut parser = Parser::from_ref(self.as_slice());
let mut first = true;
while parser.remaining() > 0 {
let key =
SvcParamKey::parse(&mut parser).expect("invalid SvcbParam");
let len = usize::from(
u16::parse(&mut parser).expect("invalid SvcParam"),
);
let mut parser =
parser.parse_parser(len).expect("invalid SvcParam");
if first {
first = false;
} else {
f.write_str(" ")?;
}
write!(
f,
"{}",
super::value::AllValues::parse_any(key, &mut parser)
)?;
}
Ok(())
}
}
impl<Octs: AsRef<[u8]> + ?Sized> fmt::Debug for SvcParams<Octs> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("SvcParams")
.field(&format_args!("{}", self))
.finish()
}
}
impl<Octs: AsRef<[u8]> + ?Sized> ZonefileFmt for SvcParams<Octs> {
fn fmt(&self, p: &mut impl Formatter) -> zonefile_fmt::Result {
p.block(|p| {
let mut parser = Parser::from_ref(self.as_slice());
while parser.remaining() > 0 {
let key = SvcParamKey::parse(&mut parser)
.expect("invalid SvcbParam");
let len = usize::from(
u16::parse(&mut parser).expect("invalid SvcParam"),
);
let mut parser =
parser.parse_parser(len).expect("invalid SvcParam");
p.write_token(super::value::AllValues::parse_any(
key,
&mut parser,
))?;
}
Ok(())
})
}
}
#[derive(Clone, Debug)]
pub struct ValueIter<'a, Octs: ?Sized, Value> {
parser: Parser<'a, Octs>,
marker: PhantomData<Value>,
}
impl<'a, Octs: AsRef<[u8]> + ?Sized, Value> ValueIter<'a, Octs, Value> {
fn new(octets: &'a Octs) -> Self {
ValueIter {
parser: Parser::from_ref(octets),
marker: PhantomData,
}
}
fn next_step(&mut self) -> Result<Option<Value>, ParseError>
where
Octs: Octets,
Value: ParseSvcParamValue<'a, Octs>,
{
let key = SvcParamKey::parse(&mut self.parser)?;
let len = usize::from(u16::parse(&mut self.parser)?);
let mut parser = self.parser.parse_parser(len)?;
let res = Value::parse_value(key, &mut parser)?;
if res.is_some() && parser.remaining() > 0 {
return Err(ParseError::form_error(
"trailing data in SVCB parameter",
));
}
Ok(res)
}
}
impl<'a, Octs, Value> Iterator for ValueIter<'a, Octs, Value>
where
Octs: Octets + ?Sized,
Value: ParseSvcParamValue<'a, Octs>,
{
type Item = Result<Value, ParseError>;
fn next(&mut self) -> Option<Self::Item> {
while self.parser.remaining() > 0 {
match self.next_step() {
Ok(Some(res)) => return Some(Ok(res)),
Ok(None) => {}
Err(err) => {
self.parser.advance_to_end();
return Some(Err(err));
}
}
}
None
}
}
pub trait SvcParamValue {
fn key(&self) -> SvcParamKey;
}
pub trait ParseSvcParamValue<'a, Octs: ?Sized>:
SvcParamValue + Sized
{
fn parse_value(
key: SvcParamKey,
parser: &mut Parser<'a, Octs>,
) -> Result<Option<Self>, ParseError>;
}
pub trait ScanSvcParamValue<
SrcOcts: AsRef<[u8]> + ?Sized,
Octs: AsRef<[u8]> + ?Sized,
>: SvcParamValue + Sized
{
fn value_from_scan_octets<S: Scanner<Octets = Octs>>(
scanner: &mut S,
key: SvcParamKey,
octs: &SrcOcts,
) -> Result<Option<Self>, S::Error>;
}
pub trait ComposeSvcParamValue: SvcParamValue {
fn compose_len(&self) -> u16;
fn compose_value<Target: OctetsBuilder + ?Sized>(
&self,
target: &mut Target,
) -> Result<(), Target::AppendError>;
}
#[derive(Clone, Debug)]
pub struct UnknownSvcParam<Octs> {
key: SvcParamKey,
value: Octs,
}
impl<Octs> UnknownSvcParam<Octs> {
pub fn new(key: SvcParamKey, value: Octs) -> Result<Self, LongSvcParam>
where
Octs: AsRef<[u8]>,
{
LongSvcParam::check_len(value.as_ref().len())?;
Ok(unsafe { Self::new_unchecked(key, value) })
}
pub unsafe fn new_unchecked(key: SvcParamKey, value: Octs) -> Self {
Self { key, value }
}
}
impl<Octs: AsRef<[u8]>> UnknownSvcParam<Octs> {
pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
key: SvcParamKey,
parser: &mut Parser<'a, Src>,
) -> Result<Self, ParseError> {
Self::new(key, parser.parse_octets(parser.remaining())?)
.map_err(Into::into)
}
pub fn parse_param<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
parser: &mut Parser<'a, Src>,
) -> Result<Self, ParseError> {
let key = SvcParamKey::parse(parser)?;
let len = usize::from(u16::parse(parser)?);
let value = parser.parse_octets(len)?;
Ok(unsafe { Self::new_unchecked(key, value) })
}
pub fn compose_param<Target: OctetsBuilder + ?Sized>(
&self,
target: &mut Target,
) -> Result<(), Target::AppendError> {
self.key.compose(target)?;
self.compose_len().compose(target)?;
self.compose_value(target)
}
}
impl<Octs> UnknownSvcParam<Octs> {
pub fn key(&self) -> SvcParamKey {
self.key
}
pub fn value(&self) -> &Octs {
&self.value
}
pub fn as_slice(&self) -> &[u8]
where
Octs: AsRef<[u8]>,
{
self.value.as_ref()
}
pub fn as_slice_mut(&mut self) -> &mut [u8]
where
Octs: AsMut<[u8]>,
{
self.value.as_mut()
}
}
impl<Octs> AsRef<Octs> for UnknownSvcParam<Octs> {
fn as_ref(&self) -> &Octs {
self.value()
}
}
impl<Octs: AsRef<[u8]>> AsRef<[u8]> for UnknownSvcParam<Octs> {
fn as_ref(&self) -> &[u8] {
self.as_slice()
}
}
impl<Octs: AsMut<[u8]>> AsMut<[u8]> for UnknownSvcParam<Octs> {
fn as_mut(&mut self) -> &mut [u8] {
self.as_slice_mut()
}
}
impl<Octs, OtherOcts> PartialEq<UnknownSvcParam<OtherOcts>>
for UnknownSvcParam<Octs>
where
Octs: AsRef<[u8]>,
OtherOcts: AsRef<[u8]>,
{
fn eq(&self, other: &UnknownSvcParam<OtherOcts>) -> bool {
self.as_slice().eq(other.as_slice())
}
}
impl<Octs: AsRef<[u8]>> Eq for UnknownSvcParam<Octs> {}
impl<Octs: AsRef<[u8]>> hash::Hash for UnknownSvcParam<Octs> {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.as_slice().hash(state)
}
}
impl<Octs> SvcParamValue for UnknownSvcParam<Octs> {
fn key(&self) -> SvcParamKey {
self.key
}
}
impl<'a, Octs: Octets + ?Sized> ParseSvcParamValue<'a, Octs>
for UnknownSvcParam<Octs::Range<'a>>
{
fn parse_value(
key: SvcParamKey,
parser: &mut Parser<'a, Octs>,
) -> Result<Option<Self>, ParseError> {
Self::new(key, parser.parse_octets(parser.remaining())?)
.map(Some)
.map_err(Into::into)
}
}
impl<SrcOcts, Octs> ScanSvcParamValue<SrcOcts, Octs> for UnknownSvcParam<Octs>
where
Octs: AsRef<[u8]>,
SrcOcts: AsRef<[u8]> + ?Sized,
{
fn value_from_scan_octets<S: Scanner<Octets = Octs>>(
scanner: &mut S,
key: SvcParamKey,
octs: &SrcOcts,
) -> Result<Option<Self>, S::Error> {
let mut tmp = scanner.octets_builder()?;
tmp.append_slice(octs.as_ref())
.map_err(|_| S::Error::short_buf())?;
Self::new(key, tmp.freeze()).map(Some).map_err(|_| {
S::Error::custom("SvcParamValue for unknown param too long")
})
}
}
impl<Octs: AsRef<[u8]>> ComposeSvcParamValue for UnknownSvcParam<Octs> {
fn compose_len(&self) -> u16 {
u16::try_from(self.as_slice().len()).expect("long value")
}
fn compose_value<Target: OctetsBuilder + ?Sized>(
&self,
target: &mut Target,
) -> Result<(), Target::AppendError> {
target.append_slice(self.as_slice())
}
}
impl<Octs: AsRef<[u8]>> fmt::Display for UnknownSvcParam<Octs> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.key)?;
let slice = self.value.as_ref();
if !slice.is_empty() {
f.write_str("=")?;
for &ch in slice {
Symbol::from_octet(ch).fmt(f)?;
}
}
Ok(())
}
}
#[derive(Clone, Debug)]
pub struct SvcParamsBuilder<Octs> {
octets: Octs,
}
impl<Octs> SvcParamsBuilder<Octs> {
#[must_use]
pub fn empty() -> Self
where
Octs: EmptyBuilder,
{
Self {
octets: Octs::empty(),
}
}
pub fn from_params<Src: Octets + ?Sized>(
params: &SvcParams<Src>,
) -> Result<Self, ShortBuf>
where
Octs: AsRef<[u8]> + OctetsBuilder + EmptyBuilder,
{
let mut octets = Octs::empty();
for item in params.iter::<UnknownSvcParam<_>>() {
let item = item.expect("invalid SvcParams");
let start = u32::try_from(octets.as_ref().len())
.map_err(|_| ShortBuf)?
.checked_add(u32::from(u32::COMPOSE_LEN))
.ok_or(ShortBuf)?;
octets
.append_slice(start.to_ne_bytes().as_ref())
.map_err(Into::into)?;
item.compose_param(&mut octets).map_err(Into::into)?;
}
octets
.append_slice(u32::MAX.to_be_bytes().as_ref())
.map_err(Into::into)?;
Ok(Self { octets })
}
pub fn push<Value: ComposeSvcParamValue + ?Sized>(
&mut self,
value: &Value,
) -> Result<(), PushError>
where
Octs: OctetsBuilder + AsRef<[u8]> + AsMut<[u8]>,
{
self.push_raw(value.key(), value.compose_len(), |octs| {
value.compose_value(octs)
})
}
pub(super) fn push_raw(
&mut self,
key: SvcParamKey,
value_len: u16,
value: impl FnOnce(&mut Octs) -> Result<(), Octs::AppendError>,
) -> Result<(), PushError>
where
Octs: OctetsBuilder + AsRef<[u8]> + AsMut<[u8]>,
{
if self.octets.as_ref().is_empty() {
self.octets
.append_slice(&u32::from(u32::COMPOSE_LEN).to_ne_bytes())?;
key.compose(&mut self.octets)?;
value_len.compose(&mut self.octets)?;
(value)(&mut self.octets)?;
u32::MAX.compose(&mut self.octets)?;
return Ok(());
}
let start = u32::try_from(self.octets.as_ref().len())
.map_err(|_| PushError::ShortBuf)?;
let mut pre = None;
let mut next = None;
let mut parser = Parser::from_ref(self.octets.as_ref());
parser.advance(u32::COMPOSE_LEN.into()).unwrap();
while parser.remaining() > 0 {
let tmp_start = u32::try_from(parser.pos()).unwrap();
let tmp = UnknownSvcParam::parse_param(&mut parser).unwrap();
let tmp_end = u32::try_from(parser.pos()).unwrap();
let tmp_key = tmp.key();
match tmp_key.cmp(&key) {
Ordering::Equal => return Err(PushError::DuplicateKey),
Ordering::Less => match pre {
Some((key, _)) => {
if tmp_key > key {
pre = Some((tmp_key, tmp_end));
}
}
None => pre = Some((tmp_key, tmp_end)),
},
Ordering::Greater => match next {
Some((key, _)) => {
if tmp_key < key {
next = Some((tmp_key, tmp_start));
}
}
None => next = Some((tmp_key, tmp_start)),
},
}
parser.advance(u32::COMPOSE_LEN.into()).unwrap();
}
key.compose(&mut self.octets)?;
value_len.compose(&mut self.octets)?;
(value)(&mut self.octets)?;
self.octets.append_slice(
&next.map(|(_, pos)| pos).unwrap_or(u32::MAX).to_ne_bytes(),
)?;
let pos = pre
.map(|(_, pos)| {
usize::try_from(pos).unwrap()
})
.unwrap_or(0);
self.octets.as_mut()[pos..pos + usize::from(u32::COMPOSE_LEN)]
.copy_from_slice(&start.to_ne_bytes());
Ok(())
}
pub fn freeze<Target>(
&self,
) -> Result<
SvcParams<Target>,
<<Target as FromBuilder>::Builder as OctetsBuilder>::AppendError,
>
where
Octs: AsRef<[u8]>,
Target: FromBuilder,
<Target as FromBuilder>::Builder: OctetsBuilder + EmptyBuilder,
{
let mut target = <Target as FromBuilder>::Builder::empty();
if !self.octets.as_ref().is_empty() {
let mut parser = Parser::from_ref(self.octets.as_ref());
loop {
let pos =
u32::from_ne_bytes(Parse::parse(&mut parser).unwrap());
if pos == u32::MAX {
break;
}
let pos = usize::try_from(pos).unwrap();
parser.seek(pos).unwrap();
let param =
UnknownSvcParam::parse_param(&mut parser).unwrap();
param.compose_param(&mut target)?;
}
}
Ok(unsafe {
SvcParams::from_octets_unchecked(Target::from_builder(target))
})
}
}
pub struct SvcParamsError(ParseError);
impl From<ShortInput> for SvcParamsError {
fn from(err: ShortInput) -> Self {
ParseError::from(err).into()
}
}
impl From<ParseError> for SvcParamsError {
fn from(err: ParseError) -> Self {
SvcParamsError(err)
}
}
impl From<SvcParamsError> for ParseError {
fn from(err: SvcParamsError) -> Self {
err.0
}
}
#[derive(Clone, Copy, Debug)]
pub struct LongSvcParam(());
impl LongSvcParam {
#[must_use]
pub fn as_str(self) -> &'static str {
"service parameter too long"
}
pub fn check_len(len: usize) -> Result<(), Self> {
if len > usize::from(u16::MAX) {
Err(LongSvcParam(()))
} else {
Ok(())
}
}
}
impl From<LongSvcParam> for ParseError {
fn from(src: LongSvcParam) -> Self {
ParseError::form_error(src.as_str())
}
}
impl fmt::Display for LongSvcParam {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
#[cfg(feature = "std")]
impl std::error::Error for LongSvcParam {}
#[derive(Clone, Copy, Debug)]
#[non_exhaustive]
pub enum PushError {
DuplicateKey,
ShortBuf,
}
impl<T: Into<ShortBuf>> From<T> for PushError {
fn from(_: T) -> Self {
PushError::ShortBuf
}
}
impl fmt::Display for PushError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
PushError::DuplicateKey => f.write_str("duplicate key"),
PushError::ShortBuf => ShortBuf.fmt(f),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for PushError {}
#[cfg(test)]
mod test {
use super::super::value;
use super::*;
use octseq::array::Array;
type Octets512 = Array<512>;
type Params512 = SvcParams<Array<512>>;
type Builder512 = SvcParamsBuilder<Array<512>>;
fn octets512(slice: impl AsRef<[u8]>) -> Octets512 {
Octets512::try_from(slice.as_ref()).unwrap()
}
macro_rules! parse_compose {
( $rdata:expr, [ $( $value:expr )* ] ) => {
let mut parser = Parser::from_ref($rdata.as_ref());
let params = SvcParams::parse(&mut parser).unwrap();
let mut param_iter = params.iter_all();
$(
assert_eq!(
param_iter.next().unwrap().unwrap(),
AllValues::<Octets512>::from($value)
);
)*
assert_eq!(None, param_iter.next());
let built = Params512::from_values(|_builder| {
$(
_builder.push(&$value).unwrap();
)*
Ok(())
}).unwrap();
let mut buf = Octets512::new();
built.compose(&mut buf).unwrap();
assert_eq!($rdata.as_ref(), buf.as_ref());
}
}
#[test]
fn test_vectors_alias() {
parse_compose!(b"", []);
}
#[test]
fn test_vectors_port_only() {
parse_compose!(
b"\x00\x03\
\x00\x02\
\x00\x35",
[value::Port::new(53)]
);
}
#[test]
fn test_vectors_unknown_param() {
parse_compose!(
b"\x02\x9b\
\x00\x05\
\x68\x65\x6c\x6c\x6f",
[UnknownSvcParam::new(0x029b.into(), octets512(b"hello"))
.unwrap()]
);
}
#[test]
fn test_vectors_unknown_param_quote() {
parse_compose!(
b"\x02\x9b\
\x00\x09\
\x68\x65\x6c\x6c\x6f\xd2\x71\x6f\x6f",
[UnknownSvcParam::new(
0x029b.into(),
octets512(b"\x68\x65\x6c\x6c\x6f\xd2\x71\x6f\x6f"),
)
.unwrap()]
);
}
#[test]
fn test_vectors_ipv6hint() {
use crate::base::net::Ipv6Addr;
use core::str::FromStr;
parse_compose!(
b"\x00\x06\
\x00\x20\
\x20\x01\x0d\xb8\x00\x00\x00\x00\
\x00\x00\x00\x00\x00\x00\x00\x01\
\x20\x01\x0d\xb8\x00\x00\x00\x00\
\x00\x00\x00\x00\x00\x53\x00\x01",
[value::Ipv6Hint::<Octets512>::from_addrs([
Ipv6Addr::from_str("2001:db8::1").unwrap(),
Ipv6Addr::from_str("2001:db8::53:1").unwrap(),
])
.unwrap()]
);
}
#[test]
fn test_vectors_ipv6hint_v4mapped() {
use crate::base::net::Ipv6Addr;
use core::str::FromStr;
parse_compose!(
b"\x00\x06\
\x00\x10\
\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\xff\xff\xc6\x33\x64\x64",
[
value::Ipv6Hint::<Octets512>::from_addrs([
Ipv6Addr::from_str("::ffff:198.51.100.100").unwrap(),
])
.unwrap()
]
);
}
#[cfg(feature = "std")]
#[test]
fn test_representation() {
let mandatory = value::Mandatory::<Octets512>::from_keys(
[
SvcParamKey::ALPN,
SvcParamKey::IPV4HINT,
SvcParamKey::PRIVATE_RANGE_BEGIN.into(),
]
.into_iter(),
)
.unwrap();
assert_eq!(
"mandatory=alpn,ipv4hint,key65280",
format!("{}", mandatory)
);
let mut alpn_builder = value::AlpnBuilder::<Octets512>::empty();
alpn_builder.push("h2").unwrap();
alpn_builder.push("h3-19").unwrap();
assert_eq!("alpn=h2,h3-19", format!("{}", alpn_builder.freeze()));
assert_eq!("nodefaultalpn", format!("{}", value::NoDefaultAlpn));
assert_eq!(
"ech",
format!("{}", value::Ech::from_octets(Octets512::new()).unwrap())
);
assert_eq!(
"ipv4hint=192.0.2.1,192.0.2.2",
format!(
"{}",
value::Ipv4Hint::<Octets512>::from_addrs([
[192, 0, 2, 1].into(),
[192, 0, 2, 2].into()
])
.unwrap()
)
);
}
#[test]
fn empty_builder() {
assert_eq!(
Builder512::empty()
.freeze::<Octets512>()
.unwrap()
.as_slice(),
b""
);
}
#[test]
fn one_value() {
let mut builder = Builder512::empty();
builder.push(&value::Port::new(53)).unwrap();
assert_eq!(
builder.freeze::<Octets512>().unwrap().as_slice(),
b"\x00\x03\x00\x02\x00\x35"
);
}
#[test]
fn three_values_in_order() {
let mut builder = Builder512::empty();
builder
.push(&UnknownSvcParam::new(1.into(), b"223").unwrap())
.unwrap();
builder
.push(&UnknownSvcParam::new(2.into(), b"224").unwrap())
.unwrap();
builder
.push(&UnknownSvcParam::new(8.into(), b"225").unwrap())
.unwrap();
assert_eq!(
builder.freeze::<Octets512>().unwrap().as_slice(),
b"\x00\x01\x00\x03223\
\x00\x02\x00\x03224\
\x00\x08\x00\x03225"
);
}
#[test]
fn three_values_out_of_order() {
let mut builder = Builder512::empty();
builder
.push(&UnknownSvcParam::new(1.into(), b"223").unwrap())
.unwrap();
builder
.push(&UnknownSvcParam::new(8.into(), b"225").unwrap())
.unwrap();
builder
.push(&UnknownSvcParam::new(2.into(), b"224").unwrap())
.unwrap();
assert_eq!(
builder.freeze::<Octets512>().unwrap().as_slice(),
b"\x00\x01\x00\x03223\
\x00\x02\x00\x03224\
\x00\x08\x00\x03225"
);
}
#[test]
fn three_values_with_collision() {
let mut builder = Builder512::empty();
builder
.push(&UnknownSvcParam::new(1.into(), b"223").unwrap())
.unwrap();
builder
.push(&UnknownSvcParam::new(8.into(), b"225").unwrap())
.unwrap();
assert!(builder
.push(&UnknownSvcParam::new(8.into(), b"224").unwrap())
.is_err());
}
}