Skip to content

Commit 34b1032

Browse files
committed
Add DnsNameInput to make constructing DnsName more convenient.
1 parent 417afdb commit 34b1032

File tree

2 files changed

+68
-33
lines changed

2 files changed

+68
-33
lines changed

src/name.rs

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -56,32 +56,70 @@ impl core::fmt::Display for InvalidDnsNameError {
5656
#[cfg(feature = "std")]
5757
impl ::std::error::Error for InvalidDnsNameError {}
5858

59+
pub trait DnsNameInput: AsRef<[u8]> + Sized {
60+
type Storage: AsRef<[u8]>;
61+
fn into_storage(self) -> Self::Storage;
62+
}
63+
64+
#[cfg(feature = "std")]
65+
impl DnsNameInput for String {
66+
type Storage = Box<[u8]>;
67+
fn into_storage(self) -> Self::Storage {
68+
self.into_boxed_str().into()
69+
}
70+
}
71+
72+
#[cfg(feature = "std")]
73+
impl DnsNameInput for Box<[u8]> {
74+
type Storage = Box<[u8]>;
75+
fn into_storage(self) -> Self::Storage {
76+
self
77+
}
78+
}
79+
80+
#[cfg(feature = "std")]
81+
impl DnsNameInput for Vec<u8> {
82+
type Storage = Box<[u8]>;
83+
fn into_storage(self) -> Self::Storage {
84+
self.into()
85+
}
86+
}
87+
88+
impl<'a> DnsNameInput for &'a str {
89+
type Storage = &'a [u8];
90+
fn into_storage(self) -> Self::Storage {
91+
self.as_ref()
92+
}
93+
}
94+
95+
impl<'a> DnsNameInput for &'a [u8] {
96+
type Storage = &'a [u8];
97+
fn into_storage(self) -> Self::Storage {
98+
self.as_ref()
99+
}
100+
}
101+
59102
impl<B> DnsName<B>
60103
where
61104
B: AsRef<[u8]>,
62105
{
63-
/// TODO: docs
64-
pub fn try_from_punycode_str<'a>(dns_name: &'a str) -> Result<Self, InvalidDnsNameError>
65-
where
66-
B: From<&'a [u8]>,
67-
{
68-
Self::try_from_punycode(dns_name.as_ref())
69-
}
70-
71106
/// Constructs a `DnsName` from the given input if the input is a
72107
/// syntactically-valid DNS name.
73-
pub fn try_from_punycode<A>(dns_name: A) -> Result<Self, InvalidDnsNameError>
74-
where
75-
A: AsRef<[u8]>,
76-
A: Into<B>,
77-
{
78-
if !is_valid_reference_dns_id(untrusted::Input::from(dns_name.as_ref())) {
108+
pub fn try_from_punycode(
109+
input: impl DnsNameInput<Storage = B>,
110+
) -> Result<Self, InvalidDnsNameError> {
111+
if !is_valid_reference_dns_id(untrusted::Input::from(input.as_ref())) {
79112
return Err(InvalidDnsNameError);
80113
}
81114

82-
Ok(Self(dns_name.into()))
115+
Ok(Self(input.into_storage()))
83116
}
117+
}
84118

119+
impl<B> DnsName<B>
120+
where
121+
B: AsRef<[u8]>,
122+
{
85123
/// Borrows any `DnsName` as a `DnsName<&[u8]>`.
86124
///
87125
/// Use `DnsName<&[u8]>` when you don't *need* to be generic over the
@@ -93,7 +131,7 @@ where
93131

94132
/// TODO:
95133
#[cfg(feature = "std")]
96-
pub fn to_owned(&self) -> DnsName<Box<[u8]>> {
134+
pub fn into_owned(self) -> DnsName<Box<[u8]>> {
97135
DnsName(Box::from(self.0.as_ref()))
98136
}
99137

tests/dns_name_tests.rs

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Copyright 2014-2017 Brian Smith.
22

3-
use webpki::DnsName;
3+
use webpki::{DnsName, DnsNameRef};
44

55
// (name, is_valid)
66
static DNS_NAME_VALIDITY: &[(&[u8], bool)] = &[
@@ -422,7 +422,7 @@ const DNS_NAME_LOWERCASE_TEST_CASES: &[(&str, &str)] = &[
422422
#[test]
423423
fn test_dns_name_ascii_lowercase_chars() {
424424
for (expected_lowercase, input) in DNS_NAME_LOWERCASE_TEST_CASES {
425-
let dns_name: DnsName<&str> = DnsName::try_from_punycode(*input).unwrap();
425+
let dns_name: DnsNameRef = DnsName::try_from_punycode(*input).unwrap();
426426
let actual_lowercase = dns_name.punycode_lowercase_bytes();
427427

428428
assert_eq!(expected_lowercase.len(), actual_lowercase.len());
@@ -438,7 +438,7 @@ fn test_dns_name_ascii_lowercase_chars() {
438438
#[test]
439439
fn test_dns_name_fmt() {
440440
for (expected_lowercase, input) in DNS_NAME_LOWERCASE_TEST_CASES {
441-
let dns_name: DnsName<&str> = DnsName::try_from_punycode(*input).unwrap();
441+
let dns_name: DnsNameRef = DnsName::try_from_punycode(*input).unwrap();
442442

443443
// Test `Display` implementation.
444444
assert_eq!(*expected_lowercase, format!("{}", dns_name));
@@ -464,8 +464,8 @@ fn test_dns_name_eq_different_len() {
464464
];
465465

466466
for (a, b) in NOT_EQUAL {
467-
let a: DnsName<&str> = DnsName::try_from_punycode(*a).unwrap();
468-
let b: DnsName<&str> = DnsName::try_from_punycode(*b).unwrap();
467+
let a: DnsNameRef = DnsName::try_from_punycode(*a).unwrap();
468+
let b: DnsNameRef = DnsName::try_from_punycode(*b).unwrap();
469469
assert_ne!(a, b)
470470
}
471471
}
@@ -474,8 +474,8 @@ fn test_dns_name_eq_different_len() {
474474
#[test]
475475
fn test_dns_name_eq_case() {
476476
for (expected_lowercase, input) in DNS_NAME_LOWERCASE_TEST_CASES {
477-
let a: DnsName<&str> = DnsName::try_from_punycode(*expected_lowercase).unwrap();
478-
let b: DnsName<&str> = DnsName::try_from_punycode(*input).unwrap();
477+
let a: DnsNameRef = DnsName::try_from_punycode(*expected_lowercase).unwrap();
478+
let b: DnsNameRef = DnsName::try_from_punycode(*input).unwrap();
479479
assert_eq!(a, b);
480480
}
481481
}
@@ -484,22 +484,19 @@ fn test_dns_name_eq_case() {
484484
#[cfg(feature = "std")]
485485
#[test]
486486
fn test_dns_name_eq_various_types() {
487-
for (expected_lowercase, input) in DNS_NAME_LOWERCASE_TEST_CASES {
488-
let a: DnsName<&str> = DnsName::try_from_punycode(*expected_lowercase).unwrap();
489-
let b: DnsName<String> = DnsName::try_from_punycode(*input).unwrap();
490-
assert_eq!(a, b);
491-
}
487+
use webpki::DnsNameBox;
492488

493489
for (expected_lowercase, input) in DNS_NAME_LOWERCASE_TEST_CASES {
494-
let a: DnsName<String> = DnsName::try_from_punycode(*expected_lowercase).unwrap();
495-
let b: DnsName<&[u8]> = DnsName::try_from_punycode(input.as_ref()).unwrap();
490+
let a: DnsNameRef = DnsName::try_from_punycode(*expected_lowercase).unwrap();
491+
let b: DnsNameBox = DnsName::try_from_punycode(*input).unwrap().into_owned();
496492
assert_eq!(a, b);
497493
}
498494

499495
for (expected_lowercase, input) in DNS_NAME_LOWERCASE_TEST_CASES {
500-
let a: DnsName<Box<[u8]>> =
501-
DnsName::try_from_punycode(expected_lowercase.as_ref()).unwrap();
502-
let b: DnsName<&str> = DnsName::try_from_punycode(*input).unwrap();
496+
let a: DnsNameBox = DnsName::try_from_punycode(*expected_lowercase)
497+
.unwrap()
498+
.into_owned();
499+
let b: DnsNameRef = DnsName::try_from_punycode(*input).unwrap();
503500
assert_eq!(a, b);
504501
}
505502
}

0 commit comments

Comments
 (0)