Skip to content

Commit a466ba5

Browse files
authored
Add a FromStr for dns::Name (#746)
We use `TryFrom<&[u8]>` in many cases we can use `FromStr`. This is a minor cleanup of these type coersions.
1 parent 5c7db67 commit a466ba5

File tree

14 files changed

+93
-83
lines changed

14 files changed

+93
-83
lines changed

linkerd/addr/src/lib.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22

33
use http;
44
use linkerd2_dns_name::Name;
5-
use std::convert::TryFrom;
6-
use std::fmt;
7-
use std::net::{IpAddr, SocketAddr};
8-
use std::str::FromStr;
5+
use std::{
6+
fmt,
7+
net::{IpAddr, SocketAddr},
8+
str::FromStr,
9+
};
910

1011
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
1112
pub enum Addr {
@@ -165,7 +166,7 @@ impl NameAddr {
165166
return Err(Error::InvalidHost);
166167
}
167168

168-
Name::try_from(host.as_bytes())
169+
Name::from_str(host)
169170
.map(|name| NameAddr { name, port })
170171
.map_err(|_| Error::InvalidHost)
171172
}

linkerd/app/gateway/src/lib.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ mod test {
1919
Error, NameAddr, NameMatch, Never,
2020
};
2121
use linkerd2_app_inbound::endpoint as inbound;
22-
use std::{convert::TryFrom, net::SocketAddr};
22+
use std::{net::SocketAddr, str::FromStr};
2323
use tower::util::{service_fn, ServiceExt};
2424
use tower_test::mock;
2525

@@ -111,7 +111,7 @@ mod test {
111111
suffix: "test.example.com",
112112
dst_name: Some("dst.test.example.com:4321"),
113113
peer_id: tls::PeerIdentity::Some(identity::Name::from(
114-
dns::Name::try_from("client.id.test".as_bytes()).unwrap(),
114+
dns::Name::from_str("client.id.test").unwrap(),
115115
)),
116116
orig_fwd: None,
117117
}
@@ -140,12 +140,12 @@ mod test {
140140
tokio::spawn(async move { tx.closed().await });
141141
Ok::<_, Never>(Some(rx))
142142
});
143-
let allow_discovery = NameMatch::new(Some(dns::Suffix::try_from(suffix).unwrap()));
143+
let allow_discovery = NameMatch::new(Some(dns::Suffix::from_str(suffix).unwrap()));
144144
Config { allow_discovery }.build(
145145
move |_: _| outbound.clone(),
146146
profiles,
147147
tls::PeerIdentity::Some(identity::Name::from(
148-
dns::Name::try_from("gateway.id.test".as_bytes()).unwrap(),
148+
dns::Name::from_str("gateway.id.test").unwrap(),
149149
)),
150150
)
151151
};

linkerd/app/outbound/src/tcp/tests.rs

Lines changed: 24 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -103,10 +103,9 @@ async fn tls_when_hinted() {
103103
};
104104

105105
let cfg = default_config(plain_addr);
106-
let id_name = linkerd2_identity::Name::from_hostname(
107-
b"foo.ns1.serviceaccount.identity.linkerd.cluster.local",
108-
)
109-
.expect("hostname is valid");
106+
let id_name =
107+
linkerd2_identity::Name::from_str("foo.ns1.serviceaccount.identity.linkerd.cluster.local")
108+
.expect("hostname is valid");
110109
let mut srv_io = support::io();
111110
srv_io.write(b"hello").read(b"world");
112111
let id_name2 = id_name.clone();
@@ -173,10 +172,9 @@ async fn resolutions_are_reused() {
173172

174173
let addr = SocketAddr::new([0, 0, 0, 0].into(), 5550);
175174
let cfg = default_config(addr);
176-
let id_name = linkerd2_identity::Name::from_hostname(
177-
b"foo.ns1.serviceaccount.identity.linkerd.cluster.local",
178-
)
179-
.expect("hostname is valid");
175+
let id_name =
176+
linkerd2_identity::Name::from_str("foo.ns1.serviceaccount.identity.linkerd.cluster.local")
177+
.expect("hostname is valid");
180178

181179
// Build a mock "connector" that returns the upstream "server" IO.
182180
let connect = support::connect().endpoint(
@@ -254,10 +252,9 @@ async fn load_balances() {
254252
];
255253

256254
let cfg = default_config(svc_addr);
257-
let id_name = linkerd2_identity::Name::from_hostname(
258-
b"foo.ns1.serviceaccount.identity.linkerd.cluster.local",
259-
)
260-
.expect("hostname is valid");
255+
let id_name =
256+
linkerd2_identity::Name::from_str("foo.ns1.serviceaccount.identity.linkerd.cluster.local")
257+
.expect("hostname is valid");
261258

262259
// Build a mock "connector" that returns the upstream "server" IO
263260
let mut connect = support::connect();
@@ -345,10 +342,9 @@ async fn load_balancer_add_endpoints() {
345342
];
346343

347344
let cfg = default_config(svc_addr);
348-
let id_name = linkerd2_identity::Name::from_hostname(
349-
b"foo.ns1.serviceaccount.identity.linkerd.cluster.local",
350-
)
351-
.expect("hostname is valid");
345+
let id_name =
346+
linkerd2_identity::Name::from_str("foo.ns1.serviceaccount.identity.linkerd.cluster.local")
347+
.expect("hostname is valid");
352348

353349
let mut connect = support::connect();
354350
for &(addr, ref conns) in endpoints {
@@ -454,10 +450,9 @@ async fn load_balancer_remove_endpoints() {
454450
];
455451

456452
let cfg = default_config(svc_addr);
457-
let id_name = linkerd2_identity::Name::from_hostname(
458-
b"foo.ns1.serviceaccount.identity.linkerd.cluster.local",
459-
)
460-
.expect("hostname is valid");
453+
let id_name =
454+
linkerd2_identity::Name::from_str("foo.ns1.serviceaccount.identity.linkerd.cluster.local")
455+
.expect("hostname is valid");
461456

462457
let mut connect = support::connect();
463458
for &(addr, ref enabled) in endpoints {
@@ -544,10 +539,9 @@ async fn no_profiles_when_outside_search_nets() {
544539
allow_discovery: IpMatch::new(Some(IpNet::from_str("10.0.0.0/8").unwrap())).into(),
545540
..default_config(profile_addr)
546541
};
547-
let id_name = linkerd2_identity::Name::from_hostname(
548-
b"foo.ns1.serviceaccount.identity.linkerd.cluster.local",
549-
)
550-
.expect("hostname is invalid");
542+
let id_name =
543+
linkerd2_identity::Name::from_str("foo.ns1.serviceaccount.identity.linkerd.cluster.local")
544+
.expect("hostname is invalid");
551545
let id_name2 = id_name.clone();
552546

553547
// Build a mock "connector" that returns the upstream "server" IO.
@@ -617,10 +611,9 @@ async fn no_discovery_when_profile_has_an_endpoint() {
617611

618612
let ep = SocketAddr::new([10, 0, 0, 41].into(), 5550);
619613
let cfg = default_config(ep);
620-
let id_name = linkerd2_identity::Name::from_hostname(
621-
b"foo.ns1.serviceaccount.identity.linkerd.cluster.local",
622-
)
623-
.expect("hostname is invalid");
614+
let id_name =
615+
linkerd2_identity::Name::from_str("foo.ns1.serviceaccount.identity.linkerd.cluster.local")
616+
.expect("hostname is invalid");
624617
let meta = support::resolver::Metadata::new(
625618
Default::default(),
626619
support::resolver::ProtocolHint::Unknown,
@@ -672,10 +665,9 @@ async fn profile_endpoint_propagates_conn_errors() {
672665
let ep2 = SocketAddr::new([10, 0, 0, 42].into(), 5550);
673666

674667
let cfg = default_config(ep1);
675-
let id_name = linkerd2_identity::Name::from_hostname(
676-
b"foo.ns1.serviceaccount.identity.linkerd.cluster.local",
677-
)
678-
.expect("hostname is invalid");
668+
let id_name =
669+
linkerd2_identity::Name::from_str("foo.ns1.serviceaccount.identity.linkerd.cluster.local")
670+
.expect("hostname is invalid");
679671
let meta = support::resolver::Metadata::new(
680672
Default::default(),
681673
support::resolver::ProtocolHint::Unknown,

linkerd/app/src/env.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@ use crate::core::{
99
use crate::{dns, gateway, identity, inbound, oc_collector, outbound};
1010
use indexmap::IndexSet;
1111
use std::{
12-
collections::HashMap, convert::TryFrom, fmt, fs, net::SocketAddr, path::PathBuf, str::FromStr,
13-
time::Duration,
12+
collections::HashMap, fmt, fs, net::SocketAddr, path::PathBuf, str::FromStr, time::Duration,
1413
};
1514
use tracing::{error, warn};
1615

@@ -768,7 +767,7 @@ fn parse_port_set(s: &str) -> Result<IndexSet<u16>, ParseError> {
768767
}
769768

770769
pub(super) fn parse_identity(s: &str) -> Result<identity::Name, ParseError> {
771-
identity::Name::from_hostname(s.as_bytes()).map_err(|identity::InvalidName| {
770+
identity::Name::from_str(s).map_err(|identity::InvalidName| {
772771
error!("Not a valid identity name: {}", s);
773772
ParseError::NameError
774773
})
@@ -835,9 +834,7 @@ fn parse_dns_suffix(s: &str) -> Result<dns::Suffix, ParseError> {
835834
return Ok(dns::Suffix::Root);
836835
}
837836

838-
dns::Name::try_from(s.as_bytes())
839-
.map(dns::Suffix::Name)
840-
.map_err(|_| ParseError::NotADomainSuffix)
837+
dns::Suffix::from_str(s).map_err(|_| ParseError::NotADomainSuffix)
841838
}
842839

843840
fn parse_networks(list: &str) -> Result<IndexSet<ipnet::IpNet>, ParseError> {

linkerd/app/test/src/profile.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ where
88
}
99

1010
pub fn with_name(name: &str) -> Profile {
11-
use std::convert::TryFrom;
12-
let name = dns::Name::try_from(name.as_bytes()).expect("non-ascii characters in DNS name! 😢");
11+
use std::str::FromStr;
12+
let name = dns::Name::from_str(name).expect("non-ascii characters in DNS name! 😢");
1313
Profile {
1414
name: Some(name),
1515
..Default::default()

linkerd/dns/name/src/name.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,13 @@ impl<'a> TryFrom<&'a [u8]> for Name {
5353
}
5454
}
5555

56+
impl<'a> std::str::FromStr for Name {
57+
type Err = InvalidName;
58+
fn from_str(s: &str) -> Result<Self, Self::Err> {
59+
Self::try_from(s.as_bytes())
60+
}
61+
}
62+
5663
impl Into<webpki::DNSName> for Name {
5764
fn into(self) -> webpki::DNSName {
5865
self.0

linkerd/dns/name/src/suffix.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use crate::Name;
2-
use std::convert::TryFrom;
3-
use std::fmt;
2+
use std::{fmt, str::FromStr};
43

54
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
65
pub enum Suffix {
@@ -23,14 +22,14 @@ impl From<Name> for Suffix {
2322
}
2423
}
2524

26-
impl<'s> TryFrom<&'s str> for Suffix {
27-
type Error = <Name as TryFrom<&'s [u8]>>::Error;
25+
impl FromStr for Suffix {
26+
type Err = <Name as FromStr>::Err;
2827

29-
fn try_from(s: &str) -> Result<Self, Self::Error> {
28+
fn from_str(s: &str) -> Result<Self, Self::Err> {
3029
if s == "." {
3130
Ok(Suffix::Root)
3231
} else {
33-
Name::try_from(s.as_bytes()).map(|n| n.into())
32+
Name::from_str(s).map(Suffix::Name)
3433
}
3534
}
3635
}

linkerd/dns/src/lib.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ impl std::error::Error for InvalidSrv {}
173173
#[cfg(test)]
174174
mod tests {
175175
use super::{Name, Suffix};
176-
use std::convert::TryFrom;
176+
use std::str::FromStr;
177177

178178
#[test]
179179
fn test_dns_name_parsing() {
@@ -225,7 +225,7 @@ mod tests {
225225
];
226226

227227
for case in VALID {
228-
let name = Name::try_from(case.input.as_bytes());
228+
let name = Name::from_str(&case.input);
229229
assert_eq!(name.as_ref().map(|x| x.as_ref()), Ok(case.output));
230230
}
231231

@@ -237,7 +237,7 @@ mod tests {
237237
];
238238

239239
for case in INVALID {
240-
assert!(Name::try_from(case.as_bytes()).is_err());
240+
assert!(Name::from_str(case).is_err());
241241
}
242242
}
243243

@@ -255,8 +255,8 @@ mod tests {
255255
("a.b.c.", "b.c"),
256256
("hacker.example.com", "example.com"),
257257
] {
258-
let n = Name::try_from((*name).as_bytes()).unwrap();
259-
let s = Suffix::try_from(*suffix).unwrap();
258+
let n = Name::from_str(name).unwrap();
259+
let s = Suffix::from_str(suffix).unwrap();
260260
assert!(
261261
s.contains(&n),
262262
format!("{} should contain {}", suffix, name)
@@ -272,14 +272,14 @@ mod tests {
272272
("b.a", "b"),
273273
("hackerexample.com", "example.com"),
274274
] {
275-
let n = Name::try_from((*name).as_bytes()).unwrap();
276-
let s = Suffix::try_from(*suffix).unwrap();
275+
let n = Name::from_str(name).unwrap();
276+
let s = Suffix::from_str(suffix).unwrap();
277277
assert!(
278278
!s.contains(&n),
279279
format!("{} should not contain {}", suffix, name)
280280
);
281281
}
282282

283-
assert!(Suffix::try_from("").is_err(), "suffix must not be empty");
283+
assert!(Suffix::from_str("").is_err(), "suffix must not be empty");
284284
}
285285
}

linkerd/identity/src/lib.rs

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,7 @@ use linkerd2_dns_name;
44
pub use ring::error::KeyRejected;
55
use ring::rand;
66
use ring::signature::EcdsaKeyPair;
7-
use std::convert::TryFrom;
8-
use std::error::Error;
9-
use std::sync::Arc;
10-
use std::time::SystemTime;
11-
use std::{fmt, fs, io};
7+
use std::{convert::TryFrom, error::Error, fmt, fs, io, str::FromStr, sync::Arc, time::SystemTime};
128
use tracing::{debug, warn};
139

1410
#[cfg(any(test, feature = "test-util"))]
@@ -132,16 +128,32 @@ impl From<linkerd2_dns_name::Name> for Name {
132128
}
133129

134130
impl Name {
135-
pub fn from_hostname(hostname: &[u8]) -> Result<Self, InvalidName> {
136-
if hostname.last() == Some(&b'.') {
131+
pub fn as_dns_name_ref(&self) -> webpki::DNSNameRef<'_> {
132+
self.0.as_dns_name_ref()
133+
}
134+
}
135+
136+
impl FromStr for Name {
137+
type Err = InvalidName;
138+
139+
fn from_str(s: &str) -> Result<Self, Self::Err> {
140+
if s.as_bytes().last() == Some(&b'.') {
137141
return Err(InvalidName); // SNI hostnames are implicitly absolute.
138142
}
139143

140-
linkerd2_dns_name::Name::try_from(hostname).map(|n| Name(Arc::new(n)))
144+
linkerd2_dns_name::Name::from_str(s).map(|n| Name(Arc::new(n)))
141145
}
146+
}
142147

143-
pub fn as_dns_name_ref(&self) -> webpki::DNSNameRef<'_> {
144-
self.0.as_dns_name_ref()
148+
impl TryFrom<&[u8]> for Name {
149+
type Error = InvalidName;
150+
151+
fn try_from(s: &[u8]) -> Result<Self, Self::Error> {
152+
if s.last() == Some(&b'.') {
153+
return Err(InvalidName); // SNI hostnames are implicitly absolute.
154+
}
155+
156+
linkerd2_dns_name::Name::try_from(s).map(|n| Name(Arc::new(n)))
145157
}
146158
}
147159

linkerd/identity/src/test_util.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ impl Identity {
3535
pub fn crt(&self) -> Crt {
3636
const HOUR: Duration = Duration::from_secs(60 * 60);
3737

38-
let n = Name::from_hostname(self.name.as_bytes()).expect("name must be valid");
38+
let n = Name::from_str(&self.name).expect("name must be valid");
3939
let der = self.crt.iter().map(|b| *b).collect();
4040
Crt::new(n, der, vec![], SystemTime::now() + HOUR)
4141
}

0 commit comments

Comments
 (0)