#[cfg(feature = "std")]
use std::collections::BTreeSet;
#[cfg(feature = "std")]
use std::collections::HashSet;
use super::{
ComposeSvcParamValue, LongSvcParam, ParseSvcParamValue, PushError,
ScanSvcParamValue, SvcParamValue, SvcParams, SvcParamsBuilder,
UnknownSvcParam,
};
use crate::base::iana::SvcParamKey;
use crate::base::net::{Ipv4Addr, Ipv6Addr};
use crate::base::scan::{
ConvertSymbols, EntrySymbol, Scanner, ScannerError, Symbol,
};
use crate::base::wire::{Compose, Parse, ParseError};
use crate::utils::base64;
use core::fmt::Write as _;
use core::str::FromStr;
use core::{fmt, hash, mem, str};
use octseq::builder::{
EmptyBuilder, FreezeBuilder, FromBuilder, OctetsBuilder, ShortBuf,
};
use octseq::octets::{Octets, OctetsFrom};
use octseq::parse::Parser;
use octseq::str::Str;
macro_rules! values_enum {
(
$( $type:ident $( < $( $type_arg:ident ),* > )?, )+
) => {
#[derive(Debug, Clone)]
pub enum AllValues<Octs> {
$(
$type($type $( < $( $type_arg ),* > )? ),
)+
Unknown(UnknownSvcParam<Octs>),
}
impl<Octs: AsRef<[u8]>> AllValues<Octs> {
pub(super) fn parse_any<'a, Src>(
key: SvcParamKey,
parser: &mut Parser<'a, Src>,
) -> Self
where Src: Octets<Range<'a> = Octs> + ?Sized {
let pos = parser.pos();
let res = match key {
$(
$type::KEY => {
$type::parse(
parser
).map(Self::$type)
}
)+
_ => {
UnknownSvcParam::parse(
key, parser
).map(Self::Unknown)
}
};
if let Ok(res) = res {
return res
}
parser.seek(pos).expect("invalid SvcParams");
let octets = parser.parse_octets(
parser.remaining()
).expect("invalid SvcParams");
Self::Unknown(unsafe {
UnknownSvcParam::new_unchecked(key, octets)
})
}
}
$(
impl<Octs> From<$type $( < $( $type_arg ),* > )*>
for AllValues<Octs> {
fn from(p: $type $( < $( $type_arg ),* > )*) -> Self {
Self::$type(p)
}
}
)+
impl<Octs> From<UnknownSvcParam<Octs>> for AllValues<Octs> {
fn from(p: UnknownSvcParam<Octs>) -> Self {
Self::Unknown(p)
}
}
impl<Octs> SvcParamValue for AllValues<Octs> {
fn key(&self) -> SvcParamKey {
match self {
$(
Self::$type(v) => v.key(),
)+
Self::Unknown(v) => v.key(),
}
}
}
impl<'a, Octs> ParseSvcParamValue<'a, Octs>
for AllValues<Octs::Range<'a>>
where Octs: Octets + ?Sized {
fn parse_value(
key: SvcParamKey,
parser: &mut Parser<'a, Octs>,
) -> Result<Option<Self>, ParseError> {
match key {
$(
$type::KEY => {
$type::parse(
parser
).map(|res| Some(Self::$type(res)))
}
)+
_ => {
UnknownSvcParam::parse_value(
key, parser
).map(|res| res.map(Self::Unknown))
}
}
}
}
#[cfg(feature = "std")]
impl<SrcOcts, Octs> ScanSvcParamValue<SrcOcts, Octs>
for AllValues<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> {
match key {
$(
$type::KEY => {
$type::value_from_scan_octets(
scanner,
key,
octs
).map(|res| Some(Self::$type(res.unwrap())))
}
)+
_ => {
UnknownSvcParam::value_from_scan_octets(
scanner, key, octs
).map(|res| res.map(Self::Unknown))
}
}
}
}
impl<Octs: AsRef<[u8]>> ComposeSvcParamValue for AllValues<Octs> {
fn compose_len(&self) -> u16 {
match self {
$(
Self::$type(v) => v.compose_len(),
)*
Self::Unknown(v) => v.compose_len(),
}
}
fn compose_value<Target: OctetsBuilder + ?Sized>(
&self, target: &mut Target,
) -> Result<(), Target::AppendError> {
match self {
$(
Self::$type(v) => v.compose_value(target),
)*
Self::Unknown(v) => v.compose_value(target),
}
}
}
impl<Octs, OtherOcts> PartialEq<AllValues<OtherOcts>>
for AllValues<Octs>
where
Octs: AsRef<[u8]>,
OtherOcts: AsRef<[u8]>,
{
fn eq(&self, other: &AllValues<OtherOcts>) -> bool {
match (self, other) {
$(
(AllValues::$type(left), AllValues::$type(right)) => {
left.eq(right)
}
)*
(AllValues::Unknown(left), AllValues::Unknown(right)) => {
left.eq(right)
}
_ => false
}
}
}
impl<Octs: AsRef<[u8]>> Eq for AllValues<Octs> { }
impl<Octs: AsRef<[u8]>> hash::Hash for AllValues<Octs> {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
match self {
$(
Self::$type(value) => value.hash(state),
)*
Self::Unknown(value) => value.hash(state)
}
}
}
impl<Octs: Octets> fmt::Display for AllValues<Octs> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
$(
Self::$type(v) => v.fmt(f),
)*
Self::Unknown(v) => v.fmt(f),
}
}
}
}
}
values_enum! {
Mandatory<Octs>,
Alpn<Octs>,
NoDefaultAlpn,
Port,
Ech<Octs>,
Ipv4Hint<Octs>,
Ipv6Hint<Octs>,
DohPath<Octs>,
Ohttp,
TlsSupportedGroups<Octs>,
}
macro_rules! octets_wrapper {
( $(#[$attr:meta])* $name:ident => $key:ident) => {
$(#[$attr])*
#[derive(Debug, Clone)]
#[repr(transparent)]
pub struct $name<Octs: ?Sized>(Octs);
impl $name<()> {
const KEY: SvcParamKey = SvcParamKey::$key;
}
impl<Octs> $name<Octs> {
pub unsafe fn from_octets_unchecked(octets: Octs) -> Self {
$name(octets)
}
}
impl $name<[u8]> {
#[must_use]
pub unsafe fn from_slice_unchecked(slice: &[u8]) -> &Self {
mem::transmute(slice)
}
}
impl<Octs: ?Sized> $name<Octs> {
pub fn as_octets(&self) -> &Octs {
&self.0
}
pub fn as_slice(&self) -> &[u8]
where Octs: AsRef<[u8]> {
self.0.as_ref()
}
}
impl<O, OO> OctetsFrom<$name<O>> for $name<OO>
where
OO: OctetsFrom<O>,
{
type Error = OO::Error;
fn try_octets_from(
source: $name<O>,
) -> Result<Self, Self::Error> {
Ok(unsafe {
$name::from_octets_unchecked(
OO::try_octets_from(source.0)?
)
})
}
}
impl<Octs> AsRef<Octs> for $name<Octs> {
fn as_ref(&self) -> &Octs {
self.as_octets()
}
}
impl<Octs: AsRef<[u8]> + ?Sized> AsRef<[u8]> for $name<Octs> {
fn as_ref(&self) -> &[u8] {
self.as_slice()
}
}
impl<Octs, OtherOcts> PartialEq<$name<OtherOcts>> for $name<Octs>
where
Octs: AsRef<[u8]>,
OtherOcts: AsRef<[u8]>,
{
fn eq(&self, other: &$name<OtherOcts>) -> bool {
self.as_slice().eq(other.as_slice())
}
}
impl<Octs: AsRef<[u8]>> Eq for $name<Octs> { }
impl<Octs: AsRef<[u8]>> hash::Hash for $name<Octs> {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.as_slice().hash(state)
}
}
impl<Octs: ?Sized> SvcParamValue for $name<Octs> {
fn key(&self) -> SvcParamKey {
$name::KEY
}
}
impl<'a, Octs> ParseSvcParamValue<'a, Octs> for $name<Octs::Range<'a>>
where Octs: Octets + ?Sized {
fn parse_value(
key: SvcParamKey,
parser: &mut Parser<'a, Octs>,
) -> Result<Option<Self>, ParseError> {
if key == $name::KEY {
Self::parse(parser).map(Some)
}
else {
Ok(None)
}
}
}
impl<Octs: AsRef<[u8]> + ?Sized> ComposeSvcParamValue for $name<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())
}
}
};
($(#[$attr:meta])* $name:ident => $key:ident, $iter:ident) => {
octets_wrapper!( $(#[$attr])* $name => $key);
impl<Octs: AsRef<[u8]> + ?Sized> $name<Octs> {
pub fn iter(&self) -> $iter<'_, Octs> {
$iter {
parser: Parser::from_ref(&self.0),
}
}
}
pub struct $iter<'a, Octs: ?Sized> {
parser: Parser<'a, Octs>,
}
};
}
octets_wrapper!(
Mandatory => MANDATORY,
MandatoryIter
);
impl<Octs: AsRef<[u8]>> Mandatory<Octs> {
pub fn from_octets(octets: Octs) -> Result<Self, ParseError> {
Mandatory::check_slice(octets.as_ref())?;
Ok(unsafe { Self::from_octets_unchecked(octets) })
}
}
impl Mandatory<[u8]> {
pub fn from_slice(slice: &[u8]) -> Result<&Self, ParseError> {
Self::check_slice(slice)?;
Ok(unsafe { Self::from_slice_unchecked(slice) })
}
fn check_slice(slice: &[u8]) -> Result<(), ParseError> {
LongSvcParam::check_len(slice.len())?;
if !slice
.len()
.is_multiple_of(usize::from(SvcParamKey::COMPOSE_LEN))
{
return Err(ParseError::form_error(
"invalid mandatory parameter",
));
}
Ok(())
}
}
impl<Octs: AsRef<[u8]>> Mandatory<Octs> {
pub fn from_keys(
keys: impl Iterator<Item = SvcParamKey>,
) -> Result<Self, BuildValueError>
where
Octs: FromBuilder,
<Octs as FromBuilder>::Builder: EmptyBuilder,
{
let mut octets = EmptyBuilder::empty();
for item in keys {
item.compose(&mut octets)?;
}
let octets = Octs::from_builder(octets);
if LongSvcParam::check_len(octets.as_ref().len()).is_err() {
return Err(BuildValueError::LongSvcParam);
}
Ok(unsafe { Self::from_octets_unchecked(octets) })
}
}
impl<Octs: AsRef<[u8]>> Mandatory<Octs> {
pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
parser: &mut Parser<'a, Src>,
) -> Result<Self, ParseError> {
Self::from_octets(parser.parse_octets(parser.remaining())?)
}
}
#[cfg(feature = "std")]
impl<SrcOcts, Octs> ScanSvcParamValue<SrcOcts, Octs> for Mandatory<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> {
if key == Mandatory::KEY {
let mut tmp = scanner.octets_builder()?;
let mut iter = SvcParamValueScanIter::from_slice(octs.as_ref());
let mut keys = BTreeSet::<SvcParamKey>::new();
while let Some(item) = iter.next_no_escapes().map_err(|_| {
S::Error::custom("no escape sequences allowed in mandatory")
})? {
let k =
SvcParamKey::from_bytes(item).ok_or(S::Error::custom(
"invalid key listed in SvcParamKey mandatory",
))?;
if k == SvcParamKey::MANDATORY {
return Err(S::Error::custom(
"the key 'mandatory' MUST NOT appear in the mandatory keys list",
));
}
if !keys.insert(k) {
return Err(S::Error::custom(
"mandatory contains duplicate keys",
));
}
}
if keys.is_empty() {
return Err(S::Error::custom(
"mandatory requires at least one value",
));
}
for k in keys {
k.compose(&mut tmp).map_err(|_| S::Error::short_buf())?;
}
Ok(Some(Self::from_octets(tmp.freeze()).map_err(|_| {
S::Error::custom("invalid svc param value for mandatory")
})?))
} else {
Ok(None)
}
}
}
impl<Octs: AsRef<[u8]> + ?Sized> Iterator for MandatoryIter<'_, Octs> {
type Item = SvcParamKey;
fn next(&mut self) -> Option<Self::Item> {
if self.parser.remaining() == 0 {
return None;
}
Some(
SvcParamKey::parse(&mut self.parser)
.expect("invalid mandatory parameter"),
)
}
}
impl<Octs: Octets + ?Sized> fmt::Display for Mandatory<Octs> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for (i, v) in self.iter().enumerate() {
if i == 0 {
write!(f, "mandatory={}", v)?;
} else {
write!(f, ",{}", v)?;
}
}
Ok(())
}
}
impl<Octs: Octets + ?Sized> SvcParams<Octs> {
pub fn mandatory(&self) -> Option<Mandatory<Octs::Range<'_>>> {
self.first()
}
}
impl<Octs: OctetsBuilder + AsRef<[u8]> + AsMut<[u8]>> SvcParamsBuilder<Octs> {
pub fn mandatory(
&mut self,
keys: impl AsRef<[SvcParamKey]>,
) -> Result<(), PushValueError> {
self.push_raw(
Mandatory::KEY,
u16::try_from(
keys.as_ref().len() * usize::from(SvcParamKey::COMPOSE_LEN),
)
.map_err(|_| PushValueError::LongSvcParam)?,
|octs| {
keys.as_ref().iter().try_for_each(|item| item.compose(octs))
},
)
.map_err(Into::into)
}
}
octets_wrapper!(
Alpn => ALPN,
AlpnIter
);
impl<Octs: AsRef<[u8]>> Alpn<Octs> {
pub fn from_octets(octets: Octs) -> Result<Self, ParseError> {
Alpn::check_slice(octets.as_ref())?;
Ok(unsafe { Self::from_octets_unchecked(octets) })
}
}
impl Alpn<[u8]> {
pub fn from_slice(slice: &[u8]) -> Result<&Self, ParseError> {
Self::check_slice(slice)?;
Ok(unsafe { Self::from_slice_unchecked(slice) })
}
fn check_slice(slice: &[u8]) -> Result<(), ParseError> {
LongSvcParam::check_len(slice.len())?;
let mut parser = Parser::from_ref(slice);
while parser.remaining() > 0 {
let len = usize::from(u8::parse(&mut parser)?);
parser.advance(len)?;
}
Ok(())
}
}
impl<Octs: AsRef<[u8]>> Alpn<Octs> {
pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
parser: &mut Parser<'a, Src>,
) -> Result<Self, ParseError> {
Self::from_octets(parser.parse_octets(parser.remaining())?)
}
}
impl<SrcOcts, Octs> ScanSvcParamValue<SrcOcts, Octs> for Alpn<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> {
if key == Alpn::KEY {
let mut tmp = scanner.octets_builder()?;
let mut iter = SvcParamValueScanIter::from_slice(octs.as_ref());
let mut at_least_one = false;
while let Some(item) = iter.next_no_escapes().map_err(|_| {
S::Error::custom("this implementation does not allow escape sequences in alpn")
})? {
at_least_one = true;
let len: u8 = item.len().try_into().map_err(|_| {
S::Error::custom("SvcParamValue is too long")
})?;
tmp.append_slice(&[len])
.map_err(|_| S::Error::short_buf())?;
tmp.append_slice(item).map_err(|_| S::Error::short_buf())?;
}
if !at_least_one {
return Err(S::Error::custom(
"expected at least one alpn-id value",
));
}
Ok(Some(Self::from_octets(tmp.freeze()).map_err(|_| {
S::Error::custom("invalid svc param value for alpn")
})?))
} else {
Ok(None)
}
}
}
impl<'a, Octs: Octets + ?Sized> Iterator for AlpnIter<'a, Octs> {
type Item = Octs::Range<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.parser.remaining() == 0 {
return None;
}
let len = usize::from(
u8::parse(&mut self.parser).expect("invalid alpn parameter"),
);
Some(
self.parser
.parse_octets(len)
.expect("invalid alpn parameter"),
)
}
}
impl<Octs: Octets + ?Sized> fmt::Display for Alpn<Octs> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for (i, v) in self.iter().enumerate() {
if i == 0 {
f.write_str("alpn=")?;
} else {
f.write_str(",")?;
}
for ch in v.as_ref() {
f.write_char(*ch as char)?;
}
}
Ok(())
}
}
impl<Octs: Octets + ?Sized> SvcParams<Octs> {
pub fn alpn(&self) -> Option<Alpn<Octs::Range<'_>>> {
self.first()
}
}
impl<Octs: OctetsBuilder + AsRef<[u8]> + AsMut<[u8]>> SvcParamsBuilder<Octs> {
pub fn alpn(&mut self, protocols: &[&[u8]]) -> Result<(), PushAlpnError> {
let mut len = 0u16;
for proto in protocols.iter() {
let proto_len = u8::try_from(proto.len())
.map_err(|_| PushAlpnError::InvalidProtocol)?;
len = len
.checked_add(u16::from(proto_len) + u8::COMPOSE_LEN)
.ok_or(PushAlpnError::LongSvcParam)?;
}
self.push_raw(Alpn::KEY, len, |octs| {
protocols.iter().try_for_each(|proto| {
u8::try_from(proto.len())
.expect("long protocol")
.compose(octs)?;
octs.append_slice(proto)
})
})
.map_err(Into::into)
}
}
#[derive(Clone, Debug)]
pub struct AlpnBuilder<Target> {
target: Target,
}
impl<Target> AlpnBuilder<Target> {
#[must_use]
pub fn empty() -> Self
where
Target: EmptyBuilder,
{
AlpnBuilder {
target: Target::empty(),
}
}
pub fn push(
&mut self,
protocol: impl AsRef<[u8]>,
) -> Result<(), BuildAlpnError>
where
Target: OctetsBuilder + AsRef<[u8]>,
{
let protocol = protocol.as_ref();
if protocol.is_empty() {
return Err(BuildAlpnError::InvalidProtocol);
}
let len = u8::try_from(protocol.len())
.map_err(|_| BuildAlpnError::InvalidProtocol)?;
LongSvcParam::check_len(
self.target
.as_ref()
.len()
.checked_add(protocol.len() + 1)
.expect("long Alpn value"),
)
.map_err(|_| BuildAlpnError::LongSvcParam)?;
len.compose(&mut self.target)?;
self.target
.append_slice(protocol)
.map_err(|_| BuildAlpnError::ShortBuf)
}
pub fn freeze(self) -> Alpn<Target::Octets>
where
Target: FreezeBuilder,
{
unsafe { Alpn::from_octets_unchecked(self.target.freeze()) }
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct NoDefaultAlpn;
impl NoDefaultAlpn {
const KEY: SvcParamKey = SvcParamKey::NO_DEFAULT_ALPN;
}
impl NoDefaultAlpn {
pub fn parse<Src: Octets + ?Sized>(
_parser: &mut Parser<'_, Src>,
) -> Result<Self, ParseError> {
Ok(Self)
}
}
impl SvcParamValue for NoDefaultAlpn {
fn key(&self) -> SvcParamKey {
Self::KEY
}
}
impl<'a, Octs: Octets + ?Sized> ParseSvcParamValue<'a, Octs>
for NoDefaultAlpn
{
fn parse_value(
key: SvcParamKey,
parser: &mut Parser<'a, Octs>,
) -> Result<Option<Self>, ParseError> {
if key == Self::KEY {
Self::parse(parser).map(Some)
} else {
Ok(None)
}
}
}
impl<SrcOcts, Octs> ScanSvcParamValue<SrcOcts, Octs> for NoDefaultAlpn
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> {
if key == Self::KEY {
if !octs.as_ref().is_empty() {
return Err(S::Error::custom(
"no-default-alpn takes no values",
));
}
Ok(Some(Self))
} else {
Ok(None)
}
}
}
impl ComposeSvcParamValue for NoDefaultAlpn {
fn compose_len(&self) -> u16 {
0
}
fn compose_value<Target: OctetsBuilder + ?Sized>(
&self,
_target: &mut Target,
) -> Result<(), Target::AppendError> {
Ok(())
}
}
impl fmt::Display for NoDefaultAlpn {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("nodefaultalpn")
}
}
impl<Octs: Octets + ?Sized> SvcParams<Octs> {
pub fn no_default_alpn(&self) -> bool {
self.first::<NoDefaultAlpn>().is_some()
}
}
impl<Octs: OctetsBuilder + AsRef<[u8]> + AsMut<[u8]>> SvcParamsBuilder<Octs> {
pub fn no_default_alpn(&mut self) -> Result<(), PushError> {
self.push(&NoDefaultAlpn)
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Port(u16);
impl Port {
const KEY: SvcParamKey = SvcParamKey::PORT;
}
impl Port {
#[must_use]
pub fn new(port: u16) -> Self {
Port(port)
}
pub fn parse<Src: Octets + ?Sized>(
parser: &mut Parser<'_, Src>,
) -> Result<Self, ParseError> {
u16::parse(parser).map(Port::new)
}
#[must_use]
pub fn port(self) -> u16 {
self.0
}
}
impl SvcParamValue for Port {
fn key(&self) -> SvcParamKey {
Self::KEY
}
}
impl<'a, Octs: Octets + ?Sized> ParseSvcParamValue<'a, Octs> for Port {
fn parse_value(
key: SvcParamKey,
parser: &mut Parser<'a, Octs>,
) -> Result<Option<Self>, ParseError> {
if key == Self::KEY {
Self::parse(parser).map(Some)
} else {
Ok(None)
}
}
}
impl<SrcOcts, Octs> ScanSvcParamValue<SrcOcts, Octs> for Port
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> {
if key == Self::KEY {
if octs.as_ref().is_empty() {
return Err(S::Error::custom("port requires a value"));
}
let s = str::from_utf8(octs.as_ref()).map_err(|_| {
S::Error::custom("port value must be valid utf-8")
})?;
let port = s.parse::<u16>().map_err(|_| {
S::Error::custom(
"port value must be a 16-bit unsigned decimal number",
)
})?;
Ok(Some(Self::new(port)))
} else {
Ok(None)
}
}
}
impl ComposeSvcParamValue for Port {
fn compose_len(&self) -> u16 {
u16::COMPOSE_LEN
}
fn compose_value<Target: OctetsBuilder + ?Sized>(
&self,
target: &mut Target,
) -> Result<(), Target::AppendError> {
self.0.compose(target)
}
}
impl fmt::Display for Port {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "port={}", self.0)
}
}
impl<Octs: Octets + ?Sized> SvcParams<Octs> {
pub fn port(&self) -> Option<Port> {
self.first()
}
}
impl<Octs: OctetsBuilder + AsRef<[u8]> + AsMut<[u8]>> SvcParamsBuilder<Octs> {
pub fn port(&mut self, port: u16) -> Result<(), PushError> {
self.push(&Port::new(port))
}
}
octets_wrapper!(
Ech => ECH
);
impl<Octs: AsRef<[u8]>> Ech<Octs> {
pub fn from_octets(octets: Octs) -> Result<Self, LongSvcParam> {
Ech::check_slice(octets.as_ref())?;
Ok(unsafe { Self::from_octets_unchecked(octets) })
}
}
impl Ech<[u8]> {
pub fn from_slice(slice: &[u8]) -> Result<&Self, LongSvcParam> {
Self::check_slice(slice)?;
Ok(unsafe { Self::from_slice_unchecked(slice) })
}
fn check_slice(slice: &[u8]) -> Result<(), LongSvcParam> {
LongSvcParam::check_len(slice.len())?;
Ok(())
}
}
impl<Octs: AsRef<[u8]>> Ech<Octs> {
pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
parser: &mut Parser<'a, Src>,
) -> Result<Self, ParseError> {
Self::from_octets(parser.parse_octets(parser.remaining())?)
.map_err(Into::into)
}
}
impl<SrcOcts, Octs> ScanSvcParamValue<SrcOcts, Octs> for Ech<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> {
if key == Ech::KEY {
if octs.as_ref().is_empty() {
return Err(S::Error::custom("ech requires as value"));
}
let mut builder = scanner.octets_builder()?;
let mut convert = base64::SymbolConverter::new();
for ch in octs.as_ref() {
if let Some(data) = convert.process_symbol(
EntrySymbol::from(Symbol::from_octet(*ch)),
)? {
builder
.append_slice(data)
.map_err(|_| S::Error::short_buf())?;
}
}
if let Some(data) = <base64::SymbolConverter as ConvertSymbols<
EntrySymbol,
<S as Scanner>::Error,
>>::process_tail(&mut convert)?
{
builder
.append_slice(data)
.map_err(|_| S::Error::short_buf())?;
}
let dec = builder.freeze();
Ok(Some(Self::from_octets(dec).map_err(|_| {
S::Error::custom("invalid ech param value")
})?))
} else {
Ok(None)
}
}
}
impl<Octs: AsRef<[u8]> + ?Sized> fmt::Display for Ech<Octs> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.as_slice().is_empty() {
f.write_str("ech")
} else {
f.write_str("ech=")?;
base64::display(self.as_slice(), f)
}
}
}
impl<Octs: Octets + ?Sized> SvcParams<Octs> {
pub fn ech(&self) -> Option<Ech<Octs::Range<'_>>> {
self.first()
}
}
impl<Octs: OctetsBuilder + AsRef<[u8]> + AsMut<[u8]>> SvcParamsBuilder<Octs> {
pub fn ech<Source: AsRef<[u8]> + ?Sized>(
&mut self,
ech: &Source,
) -> Result<(), PushValueError> {
self.push(Ech::from_slice(ech.as_ref())?)
.map_err(Into::into)
}
}
octets_wrapper!(
Ipv4Hint => IPV4HINT,
Ipv4HintIter
);
impl<Octs: AsRef<[u8]>> Ipv4Hint<Octs> {
pub fn from_octets(octets: Octs) -> Result<Self, ParseError> {
Ipv4Hint::check_slice(octets.as_ref())?;
Ok(unsafe { Self::from_octets_unchecked(octets) })
}
pub fn from_addrs(
addrs: impl IntoIterator<Item = Ipv4Addr>,
) -> Result<Self, BuildValueError>
where
Octs: FromBuilder,
<Octs as FromBuilder>::Builder: EmptyBuilder,
{
let mut octets = EmptyBuilder::empty();
for item in addrs {
item.compose(&mut octets)?;
}
let octets = Octs::from_builder(octets);
if LongSvcParam::check_len(octets.as_ref().len()).is_err() {
return Err(BuildValueError::LongSvcParam);
}
Ok(unsafe { Self::from_octets_unchecked(octets) })
}
}
impl Ipv4Hint<[u8]> {
pub fn from_slice(slice: &[u8]) -> Result<&Self, ParseError> {
Self::check_slice(slice)?;
Ok(unsafe { Self::from_slice_unchecked(slice) })
}
fn check_slice(slice: &[u8]) -> Result<(), ParseError> {
LongSvcParam::check_len(slice.len())?;
if !slice
.len()
.is_multiple_of(usize::from(Ipv4Addr::COMPOSE_LEN))
{
return Err(ParseError::form_error("invalid ipv4hint parameter"));
}
Ok(())
}
}
impl<Octs: AsRef<[u8]>> Ipv4Hint<Octs> {
pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
parser: &mut Parser<'a, Src>,
) -> Result<Self, ParseError> {
Self::from_octets(parser.parse_octets(parser.remaining())?)
}
}
impl<SrcOcts, Octs> ScanSvcParamValue<SrcOcts, Octs> for Ipv4Hint<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> {
if key == Ipv4Hint::KEY {
let mut tmp = scanner.octets_builder()?;
let mut iter = SvcParamValueScanIter::from_slice(octs.as_ref());
while let Some(item) = iter.next_no_escapes().map_err(|_| {
S::Error::custom("no escape sequences allowed in ipv4hint")
})? {
let ip = Ipv4Addr::from_str(str::from_utf8(item).map_err(
|_| S::Error::custom("invalid utf-8 in ipv4hint param"),
)?)
.map_err(|_| {
S::Error::custom("invalid ipv4 in ipv4hint param")
})?;
tmp.append_slice(&ip.octets())
.map_err(|_| S::Error::short_buf())?;
}
let ipv4hint = Self::from_octets(tmp.freeze()).map_err(|_| {
S::Error::custom("invalid svc param value for ipv4hint")
})?;
if ipv4hint.as_slice().is_empty() {
return Err(S::Error::custom(
"ipv4hint requires at least one value",
));
}
Ok(Some(ipv4hint))
} else {
Ok(None)
}
}
}
impl<Octs: Octets + ?Sized> Iterator for Ipv4HintIter<'_, Octs> {
type Item = Ipv4Addr;
fn next(&mut self) -> Option<Self::Item> {
if self.parser.remaining() == 0 {
return None;
}
Some(
Ipv4Addr::parse(&mut self.parser)
.expect("invalid ipv4hint parameter"),
)
}
}
impl<Octs: Octets + ?Sized> fmt::Display for Ipv4Hint<Octs> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for (i, v) in self.iter().enumerate() {
if i == 0 {
write!(f, "ipv4hint={}", v)?;
} else {
write!(f, ",{}", v)?;
}
}
Ok(())
}
}
impl<Octs: Octets + ?Sized> SvcParams<Octs> {
pub fn ipv4hint(&self) -> Option<Ipv4Hint<Octs::Range<'_>>> {
self.first()
}
}
impl<Octs: OctetsBuilder + AsRef<[u8]> + AsMut<[u8]>> SvcParamsBuilder<Octs> {
pub fn ipv4hint(
&mut self,
addrs: impl AsRef<[Ipv4Addr]>,
) -> Result<(), PushValueError> {
self.push_raw(
Ipv4Hint::KEY,
u16::try_from(
addrs.as_ref().len() * usize::from(Ipv4Addr::COMPOSE_LEN),
)
.map_err(|_| PushValueError::LongSvcParam)?,
|octs| {
addrs
.as_ref()
.iter()
.try_for_each(|item| item.compose(octs))
},
)
.map_err(Into::into)
}
}
octets_wrapper!(
Ipv6Hint => IPV6HINT,
Ipv6HintIter
);
impl<Octs: AsRef<[u8]>> Ipv6Hint<Octs> {
pub fn from_octets(octets: Octs) -> Result<Self, ParseError> {
Ipv6Hint::check_slice(octets.as_ref())?;
Ok(unsafe { Self::from_octets_unchecked(octets) })
}
pub fn from_addrs(
addrs: impl IntoIterator<Item = Ipv6Addr>,
) -> Result<Self, BuildValueError>
where
Octs: FromBuilder,
<Octs as FromBuilder>::Builder: EmptyBuilder,
{
let mut octets = EmptyBuilder::empty();
for item in addrs {
item.compose(&mut octets)?;
}
let octets = Octs::from_builder(octets);
if LongSvcParam::check_len(octets.as_ref().len()).is_err() {
return Err(BuildValueError::LongSvcParam);
}
Ok(unsafe { Self::from_octets_unchecked(octets) })
}
}
impl Ipv6Hint<[u8]> {
pub fn from_slice(slice: &[u8]) -> Result<&Self, ParseError> {
Self::check_slice(slice)?;
Ok(unsafe { Self::from_slice_unchecked(slice) })
}
fn check_slice(slice: &[u8]) -> Result<(), ParseError> {
LongSvcParam::check_len(slice.len())?;
if !slice
.len()
.is_multiple_of(usize::from(Ipv6Addr::COMPOSE_LEN))
{
return Err(ParseError::form_error("invalid ipv6hint parameter"));
}
Ok(())
}
}
impl<Octs: AsRef<[u8]>> Ipv6Hint<Octs> {
pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
parser: &mut Parser<'a, Src>,
) -> Result<Self, ParseError> {
Self::from_octets(parser.parse_octets(parser.remaining())?)
}
}
impl<SrcOcts, Octs> ScanSvcParamValue<SrcOcts, Octs> for Ipv6Hint<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> {
if key == Ipv6Hint::KEY {
let mut tmp = scanner.octets_builder()?;
let mut iter = SvcParamValueScanIter::from_slice(octs.as_ref());
while let Some(item) = iter.next_no_escapes().map_err(|_| {
S::Error::custom("no escape sequences allowed in ipv6hint")
})? {
let ip = Ipv6Addr::from_str(str::from_utf8(item).map_err(
|_| S::Error::custom("invalid utf-8 in ipv6hint param"),
)?)
.map_err(|_| {
S::Error::custom("invalid ipv6 in ipv6hint param")
})?;
tmp.append_slice(&ip.octets())
.map_err(|_| S::Error::short_buf())?;
}
let ipv6hint = Self::from_octets(tmp.freeze()).map_err(|_| {
S::Error::custom("invalid svc param value for ipv6hint")
})?;
if ipv6hint.as_slice().is_empty() {
return Err(S::Error::custom(
"ipv6hint requires at least one value",
));
}
Ok(Some(ipv6hint))
} else {
Ok(None)
}
}
}
impl<Octs: Octets + ?Sized> Iterator for Ipv6HintIter<'_, Octs> {
type Item = Ipv6Addr;
fn next(&mut self) -> Option<Self::Item> {
if self.parser.remaining() == 0 {
return None;
}
Some(
Ipv6Addr::parse(&mut self.parser)
.expect("invalid ipv6hint parameter"),
)
}
}
impl<Octs: Octets + ?Sized> fmt::Display for Ipv6Hint<Octs> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for (i, v) in self.iter().enumerate() {
if i == 0 {
write!(f, "ipv6hint={}", v)?;
} else {
write!(f, ",{}", v)?;
}
}
Ok(())
}
}
impl<Octs: Octets + ?Sized> SvcParams<Octs> {
pub fn ipv6hint(&self) -> Option<Ipv6Hint<Octs::Range<'_>>> {
self.first()
}
}
impl<Octs: OctetsBuilder + AsRef<[u8]> + AsMut<[u8]>> SvcParamsBuilder<Octs> {
pub fn ipv6hint(
&mut self,
addrs: impl AsRef<[Ipv6Addr]>,
) -> Result<(), PushValueError> {
self.push_raw(
Ipv6Hint::KEY,
u16::try_from(
addrs.as_ref().len() * usize::from(Ipv6Addr::COMPOSE_LEN),
)
.map_err(|_| PushValueError::LongSvcParam)?,
|octs| {
addrs
.as_ref()
.iter()
.try_for_each(|item| item.compose(octs))
},
)
.map_err(Into::into)
}
}
octets_wrapper!(
DohPath => DOHPATH
);
impl<Octs: AsRef<[u8]>> DohPath<Octs> {
pub fn from_octets(octets: Octs) -> Result<Self, LongSvcParam> {
DohPath::check_slice(octets.as_ref())?;
Ok(unsafe { Self::from_octets_unchecked(octets) })
}
}
impl DohPath<[u8]> {
pub fn from_slice(slice: &[u8]) -> Result<&Self, LongSvcParam> {
Self::check_slice(slice)?;
Ok(unsafe { Self::from_slice_unchecked(slice) })
}
fn check_slice(slice: &[u8]) -> Result<(), LongSvcParam> {
LongSvcParam::check_len(slice.len())?;
Ok(())
}
}
impl<Octs: AsRef<[u8]>> DohPath<Octs> {
pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
parser: &mut Parser<'a, Src>,
) -> Result<Self, ParseError> {
Self::from_octets(parser.parse_octets(parser.remaining())?)
.map_err(Into::into)
}
}
impl<SrcOcts, Octs> ScanSvcParamValue<SrcOcts, Octs> for DohPath<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> {
if key == DohPath::KEY {
let _ = str::from_utf8(octs.as_ref()).map_err(|_| {
S::Error::custom("dohpath must be valid UTF-8")
})?;
let mut tmp = scanner.octets_builder()?;
tmp.append_slice(octs.as_ref())
.map_err(|_| S::Error::short_buf())?;
Ok(Some(Self::from_octets(tmp.freeze()).map_err(|_| {
S::Error::custom("invalid svc param value for dohpath")
})?))
} else {
Ok(None)
}
}
}
impl<Octs: AsRef<[u8]>> TryFrom<Str<Octs>> for DohPath<Octs> {
type Error = LongSvcParam;
fn try_from(src: Str<Octs>) -> Result<Self, Self::Error> {
Self::from_octets(src.into_octets())
}
}
impl<Octs> FromStr for DohPath<Octs>
where
Octs: FromBuilder,
<Octs as FromBuilder>::Builder:
EmptyBuilder + FreezeBuilder<Octets = Octs>,
{
type Err = BuildValueError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
DohPath::check_slice(s.as_bytes())?;
let mut res: <Octs as FromBuilder>::Builder = EmptyBuilder::empty();
res.append_slice(s.as_bytes()).map_err(Into::into)?;
Ok(unsafe { Self::from_octets_unchecked(res.freeze()) })
}
}
impl<Octs: AsRef<[u8]> + ?Sized> fmt::Display for DohPath<Octs> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.as_slice().is_empty() {
f.write_str("dohpath")
} else {
f.write_str("dohpath=")?;
let mut s = self.as_slice();
while !s.is_empty() {
match str::from_utf8(s) {
Ok(s) => return f.write_str(s),
Err(err) => {
let end = err.valid_up_to();
if end > 0 {
f.write_str(unsafe {
str::from_utf8_unchecked(&s[..end])
})?;
}
f.write_str("\u{FFFD}")?;
match err.error_len() {
Some(len) => {
s = &s[end + len..];
}
None => break,
}
}
}
}
Ok(())
}
}
}
impl<Octs: Octets + ?Sized> SvcParams<Octs> {
pub fn dohpath(&self) -> Option<DohPath<Octs::Range<'_>>> {
self.first()
}
}
impl<Octs: OctetsBuilder + AsRef<[u8]> + AsMut<[u8]>> SvcParamsBuilder<Octs> {
pub fn dohpath(&mut self, template: &str) -> Result<(), PushValueError> {
self.push_raw(
DohPath::KEY,
u16::try_from(template.len())
.map_err(|_| PushValueError::LongSvcParam)?,
|octs| octs.append_slice(template.as_bytes()),
)
.map_err(Into::into)
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct Ohttp;
impl Ohttp {
const KEY: SvcParamKey = SvcParamKey::OHTTP;
}
impl Ohttp {
pub fn parse<Src: Octets + ?Sized>(
_parser: &mut Parser<'_, Src>,
) -> Result<Self, ParseError> {
Ok(Self)
}
}
impl SvcParamValue for Ohttp {
fn key(&self) -> SvcParamKey {
Self::KEY
}
}
impl<'a, Octs: Octets + ?Sized> ParseSvcParamValue<'a, Octs> for Ohttp {
fn parse_value(
key: SvcParamKey,
parser: &mut Parser<'a, Octs>,
) -> Result<Option<Self>, ParseError> {
if key == Self::KEY {
Self::parse(parser).map(Some)
} else {
Ok(None)
}
}
}
impl<SrcOcts, Octs> ScanSvcParamValue<SrcOcts, Octs> for Ohttp
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> {
if key == Self::KEY {
if !octs.as_ref().is_empty() {
return Err(S::Error::custom("ohttp takes no values"));
}
Ok(Some(Self))
} else {
Ok(None)
}
}
}
impl ComposeSvcParamValue for Ohttp {
fn compose_len(&self) -> u16 {
0
}
fn compose_value<Target: OctetsBuilder + ?Sized>(
&self,
_target: &mut Target,
) -> Result<(), Target::AppendError> {
Ok(())
}
}
impl fmt::Display for Ohttp {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("ohttp")
}
}
impl<Octs: Octets + ?Sized> SvcParams<Octs> {
pub fn ohttp(&self) -> bool {
self.first::<Ohttp>().is_some()
}
}
impl<Octs: OctetsBuilder + AsRef<[u8]> + AsMut<[u8]>> SvcParamsBuilder<Octs> {
pub fn ohttp(&mut self) -> Result<(), PushError> {
self.push(&Ohttp)
}
}
octets_wrapper!(
TlsSupportedGroups => TLS_SUPPORTED_GROUPS,
TlsSupportedGroupsIter
);
impl<Octs: AsRef<[u8]>> TlsSupportedGroups<Octs> {
pub fn from_octets(octets: Octs) -> Result<Self, ParseError> {
TlsSupportedGroups::check_slice(octets.as_ref())?;
Ok(unsafe { Self::from_octets_unchecked(octets) })
}
}
impl TlsSupportedGroups<[u8]> {
pub fn from_slice(slice: &[u8]) -> Result<&Self, ParseError> {
Self::check_slice(slice)?;
Ok(unsafe { Self::from_slice_unchecked(slice) })
}
fn check_slice(slice: &[u8]) -> Result<(), ParseError> {
LongSvcParam::check_len(slice.len())?;
if slice.is_empty()
|| !slice.len().is_multiple_of(usize::from(u16::COMPOSE_LEN))
{
return Err(ParseError::form_error(
"invalid tls-supported-groups parameter",
));
}
Ok(())
}
}
impl<Octs: AsRef<[u8]>> TlsSupportedGroups<Octs> {
pub fn from_keys(
keys: impl Iterator<Item = u16>,
) -> Result<Self, BuildValueError>
where
Octs: FromBuilder,
<Octs as FromBuilder>::Builder: EmptyBuilder,
{
let mut octets = EmptyBuilder::empty();
for item in keys {
item.compose(&mut octets)?;
}
let octets = Octs::from_builder(octets);
if LongSvcParam::check_len(octets.as_ref().len()).is_err() {
return Err(BuildValueError::LongSvcParam);
}
Ok(unsafe { Self::from_octets_unchecked(octets) })
}
}
impl<Octs: AsRef<[u8]>> TlsSupportedGroups<Octs> {
pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
parser: &mut Parser<'a, Src>,
) -> Result<Self, ParseError> {
Self::from_octets(parser.parse_octets(parser.remaining())?)
}
}
#[cfg(feature = "std")]
impl<SrcOcts, Octs> ScanSvcParamValue<SrcOcts, Octs>
for TlsSupportedGroups<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> {
if key == TlsSupportedGroups::KEY {
let mut tmp = scanner.octets_builder()?;
let mut iter = SvcParamValueScanIter::from_slice(octs.as_ref());
let mut keys = HashSet::<u16>::new();
while let Some(item) = iter.next_no_escapes().map_err(|_| {
S::Error::custom(
"no escape sequences allowed in tls-supported-groups",
)
})? {
let k = str::from_utf8(item)
.map_err(|_| {
S::Error::custom(
"invalid key listed in SvcParamKey tls-supported-groups, must contain UTF-8 encoded numbers",
)
})?
.parse::<u16>()
.map_err(|_| {
S::Error::custom(
"invalid key listed in SvcParamKey tls-supported-groups, must contain positive 16-bit integers",
)
})?;
if !keys.insert(k) {
return Err(S::Error::custom(
"tls-supported-groups contains duplicate values",
));
}
k.compose(&mut tmp).map_err(|_| S::Error::short_buf())?;
}
Ok(Some(Self::from_octets(tmp.freeze()).map_err(|_| {
S::Error::custom(
"invalid svc param value for tls-supported-groups",
)
})?))
} else {
Ok(None)
}
}
}
impl<Octs: AsRef<[u8]> + ?Sized> Iterator
for TlsSupportedGroupsIter<'_, Octs>
{
type Item = u16;
fn next(&mut self) -> Option<Self::Item> {
if self.parser.remaining() == 0 {
return None;
}
Some(
u16::parse(&mut self.parser)
.expect("invalid tls-supported-groups parameter"),
)
}
}
impl<Octs: Octets + ?Sized> fmt::Display for TlsSupportedGroups<Octs> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for (i, v) in self.iter().enumerate() {
if i == 0 {
write!(f, "tls-supported-groups={}", v)?;
} else {
write!(f, ",{}", v)?;
}
}
Ok(())
}
}
impl<Octs: Octets + ?Sized> SvcParams<Octs> {
pub fn tls_supported_groups(
&self,
) -> Option<TlsSupportedGroups<Octs::Range<'_>>> {
self.first()
}
}
impl<Octs: OctetsBuilder + AsRef<[u8]> + AsMut<[u8]>> SvcParamsBuilder<Octs> {
pub fn tls_supported_groups(
&mut self,
keys: impl AsRef<[SvcParamKey]>,
) -> Result<(), PushValueError> {
self.push_raw(
TlsSupportedGroups::KEY,
u16::try_from(
keys.as_ref().len() * usize::from(SvcParamKey::COMPOSE_LEN),
)
.map_err(|_| PushValueError::LongSvcParam)?,
|octs| {
keys.as_ref().iter().try_for_each(|item| item.compose(octs))
},
)
.map_err(Into::into)
}
}
struct SvcParamValueScanIter<'a> {
data: &'a [u8],
start_next: usize,
end: usize,
}
impl<'a> SvcParamValueScanIter<'a> {
pub fn from_slice(octs: &'a [u8]) -> Self {
Self {
data: octs,
start_next: 0,
end: 0,
}
}
pub fn next_no_escapes(&mut self) -> Result<Option<&[u8]>, ()> {
if self.start_next >= self.data.len() {
Ok(None)
} else {
let start = self.start_next;
self.end = self.start_next;
loop {
if self.end < self.data.len() {
if self.data[self.end] == b',' {
break;
} else {
if self.data[self.end] == b'\\' {
return Err(());
}
self.end += 1;
}
} else {
break;
}
}
self.start_next = self.end + 1;
Ok(Some(&self.data[start..self.end]))
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum BuildValueError {
LongSvcParam,
ShortBuf,
}
impl From<LongSvcParam> for BuildValueError {
fn from(_: LongSvcParam) -> Self {
Self::LongSvcParam
}
}
impl<T: Into<ShortBuf>> From<T> for BuildValueError {
fn from(_: T) -> Self {
Self::ShortBuf
}
}
impl fmt::Display for BuildValueError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::LongSvcParam => f.write_str("long SVCB value"),
Self::ShortBuf => ShortBuf.fmt(f),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for BuildValueError {}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum PushValueError {
DuplicateKey,
LongSvcParam,
ShortBuf,
}
impl From<LongSvcParam> for PushValueError {
fn from(_: LongSvcParam) -> Self {
Self::LongSvcParam
}
}
impl From<PushError> for PushValueError {
fn from(src: PushError) -> Self {
match src {
PushError::DuplicateKey => Self::DuplicateKey,
PushError::ShortBuf => Self::ShortBuf,
}
}
}
impl From<BuildValueError> for PushValueError {
fn from(src: BuildValueError) -> Self {
match src {
BuildValueError::LongSvcParam => Self::LongSvcParam,
BuildValueError::ShortBuf => Self::ShortBuf,
}
}
}
impl<T: Into<ShortBuf>> From<T> for PushValueError {
fn from(_: T) -> Self {
Self::ShortBuf
}
}
impl fmt::Display for PushValueError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::DuplicateKey => f.write_str("duplicate key"),
Self::LongSvcParam => f.write_str("long SVCB value"),
Self::ShortBuf => ShortBuf.fmt(f),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for PushValueError {}
#[derive(Clone, Copy, Debug)]
pub enum BuildAlpnError {
InvalidProtocol,
LongSvcParam,
ShortBuf,
}
impl<T: Into<ShortBuf>> From<T> for BuildAlpnError {
fn from(_: T) -> Self {
Self::ShortBuf
}
}
impl fmt::Display for BuildAlpnError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidProtocol => f.write_str("invalid ALPN protocol"),
Self::LongSvcParam => f.write_str("long SVCB value"),
Self::ShortBuf => ShortBuf.fmt(f),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for BuildAlpnError {}
#[derive(Clone, Copy, Debug)]
pub enum PushAlpnError {
DuplicateKey,
InvalidProtocol,
LongSvcParam,
ShortBuf,
}
impl From<PushError> for PushAlpnError {
fn from(src: PushError) -> Self {
match src {
PushError::DuplicateKey => Self::DuplicateKey,
PushError::ShortBuf => Self::ShortBuf,
}
}
}
impl From<BuildValueError> for PushAlpnError {
fn from(src: BuildValueError) -> Self {
match src {
BuildValueError::LongSvcParam => Self::LongSvcParam,
BuildValueError::ShortBuf => Self::ShortBuf,
}
}
}
impl<T: Into<ShortBuf>> From<T> for PushAlpnError {
fn from(_: T) -> Self {
Self::ShortBuf
}
}
impl fmt::Display for PushAlpnError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::DuplicateKey => f.write_str("duplicate key"),
Self::InvalidProtocol => f.write_str("invalid ALPN protocol"),
Self::LongSvcParam => f.write_str("long SVCB value"),
Self::ShortBuf => ShortBuf.fmt(f),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for PushAlpnError {}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_vectors_alpn_escape() {
let mut parser = Parser::from_ref(
b"\
\x08\
\x66\x5c\x6f\x6f\x2c\x62\x61\x72\
\x02\
\x68\x32\
"
.as_ref(),
);
let alpn = Alpn::parse(&mut parser).unwrap();
assert_eq!(parser.remaining(), 0);
assert!(alpn.iter().eq([br"f\oo,bar".as_ref(), b"h2".as_ref(),]));
}
}