rama_net/address/
authority.rs

1use super::{Domain, DomainAddress, Host, parse_utils};
2use rama_core::error::{ErrorContext, OpaqueError};
3use std::net::{Ipv4Addr, Ipv6Addr};
4use std::{
5    fmt,
6    net::{IpAddr, SocketAddr},
7};
8
9#[cfg(feature = "http")]
10use rama_http_types::HeaderValue;
11
12/// A [`Host`] with an associated port.
13#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
14pub struct Authority {
15    host: Host,
16    port: u16,
17}
18
19impl Authority {
20    /// Creates a new [`Authority`].
21    pub const fn new(host: Host, port: u16) -> Self {
22        Authority { host, port }
23    }
24
25    /// Gets the [`Host`] reference.
26    pub fn host(&self) -> &Host {
27        &self.host
28    }
29
30    /// Consumes the [`Authority`] and returns the [`Host`].
31    pub fn into_host(self) -> Host {
32        self.host
33    }
34
35    /// Gets the port
36    pub fn port(&self) -> u16 {
37        self.port
38    }
39
40    /// Consume self into its parts: `(host, port)`
41    pub fn into_parts(self) -> (Host, u16) {
42        (self.host, self.port)
43    }
44}
45
46impl From<(Domain, u16)> for Authority {
47    #[inline]
48    fn from((domain, port): (Domain, u16)) -> Self {
49        (Host::Name(domain), port).into()
50    }
51}
52
53impl From<(IpAddr, u16)> for Authority {
54    #[inline]
55    fn from((ip, port): (IpAddr, u16)) -> Self {
56        (Host::Address(ip), port).into()
57    }
58}
59
60impl From<(Ipv4Addr, u16)> for Authority {
61    #[inline]
62    fn from((ip, port): (Ipv4Addr, u16)) -> Self {
63        (Host::Address(IpAddr::V4(ip)), port).into()
64    }
65}
66
67impl From<([u8; 4], u16)> for Authority {
68    #[inline]
69    fn from((ip, port): ([u8; 4], u16)) -> Self {
70        (Host::Address(IpAddr::V4(ip.into())), port).into()
71    }
72}
73
74impl From<(Ipv6Addr, u16)> for Authority {
75    #[inline]
76    fn from((ip, port): (Ipv6Addr, u16)) -> Self {
77        (Host::Address(IpAddr::V6(ip)), port).into()
78    }
79}
80
81impl From<([u8; 16], u16)> for Authority {
82    #[inline]
83    fn from((ip, port): ([u8; 16], u16)) -> Self {
84        (Host::Address(IpAddr::V6(ip.into())), port).into()
85    }
86}
87
88impl From<(Host, u16)> for Authority {
89    fn from((host, port): (Host, u16)) -> Self {
90        Authority { host, port }
91    }
92}
93
94impl From<Authority> for Host {
95    fn from(authority: Authority) -> Host {
96        authority.host
97    }
98}
99
100impl From<SocketAddr> for Authority {
101    fn from(addr: SocketAddr) -> Self {
102        Authority {
103            host: Host::Address(addr.ip()),
104            port: addr.port(),
105        }
106    }
107}
108
109impl From<&SocketAddr> for Authority {
110    fn from(addr: &SocketAddr) -> Self {
111        Authority {
112            host: Host::Address(addr.ip()),
113            port: addr.port(),
114        }
115    }
116}
117
118impl From<DomainAddress> for Authority {
119    fn from(addr: DomainAddress) -> Self {
120        let (domain, port) = addr.into_parts();
121        Self::from((domain, port))
122    }
123}
124
125impl fmt::Display for Authority {
126    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127        match &self.host {
128            Host::Name(domain) => write!(f, "{}:{}", domain, self.port),
129            Host::Address(ip) => match ip {
130                IpAddr::V4(ip) => write!(f, "{}:{}", ip, self.port),
131                IpAddr::V6(ip) => write!(f, "[{}]:{}", ip, self.port),
132            },
133        }
134    }
135}
136
137impl std::str::FromStr for Authority {
138    type Err = OpaqueError;
139
140    fn from_str(s: &str) -> Result<Self, Self::Err> {
141        Authority::try_from(s)
142    }
143}
144
145impl TryFrom<String> for Authority {
146    type Error = OpaqueError;
147
148    fn try_from(s: String) -> Result<Self, Self::Error> {
149        s.as_str().try_into()
150    }
151}
152
153impl TryFrom<&str> for Authority {
154    type Error = OpaqueError;
155
156    fn try_from(s: &str) -> Result<Self, Self::Error> {
157        let (host, port) = parse_utils::split_port_from_str(s)?;
158        let host = Host::try_from(host).context("parse host from authority")?;
159        match host {
160            Host::Address(IpAddr::V6(_)) if !s.starts_with('[') => Err(OpaqueError::from_display(
161                "missing brackets for IPv6 address with port",
162            )),
163            _ => Ok(Authority { host, port }),
164        }
165    }
166}
167
168#[cfg(feature = "http")]
169impl TryFrom<HeaderValue> for Authority {
170    type Error = OpaqueError;
171
172    fn try_from(header: HeaderValue) -> Result<Self, Self::Error> {
173        Self::try_from(&header)
174    }
175}
176
177#[cfg(feature = "http")]
178impl TryFrom<&HeaderValue> for Authority {
179    type Error = OpaqueError;
180
181    fn try_from(header: &HeaderValue) -> Result<Self, Self::Error> {
182        header.to_str().context("convert header to str")?.try_into()
183    }
184}
185
186impl TryFrom<Vec<u8>> for Authority {
187    type Error = OpaqueError;
188
189    fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> {
190        let s = String::from_utf8(bytes).context("parse authority from bytes")?;
191        s.try_into()
192    }
193}
194
195impl TryFrom<&[u8]> for Authority {
196    type Error = OpaqueError;
197
198    fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
199        let s = std::str::from_utf8(bytes).context("parse authority from bytes")?;
200        s.try_into()
201    }
202}
203
204impl serde::Serialize for Authority {
205    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
206    where
207        S: serde::Serializer,
208    {
209        let address = self.to_string();
210        address.serialize(serializer)
211    }
212}
213
214impl<'de> serde::Deserialize<'de> for Authority {
215    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
216    where
217        D: serde::Deserializer<'de>,
218    {
219        let s = <std::borrow::Cow<'de, str>>::deserialize(deserializer)?;
220        s.parse().map_err(serde::de::Error::custom)
221    }
222}
223
224#[cfg(test)]
225mod tests {
226    use super::*;
227
228    fn assert_eq(s: &str, authority: Authority, host: &str, port: u16) {
229        assert_eq!(authority.host(), &host, "parsing: {}", s);
230        assert_eq!(authority.port(), port, "parsing: {}", s);
231    }
232
233    #[test]
234    fn test_parse_valid() {
235        for (s, (expected_host, expected_port)) in [
236            ("example.com:80", ("example.com", 80)),
237            ("[::1]:80", ("::1", 80)),
238            ("127.0.0.1:80", ("127.0.0.1", 80)),
239            (
240                "[2001:db8:3333:4444:5555:6666:7777:8888]:80",
241                ("2001:db8:3333:4444:5555:6666:7777:8888", 80),
242            ),
243        ] {
244            let msg = format!("parsing '{}'", s);
245
246            assert_eq(s, s.parse().expect(&msg), expected_host, expected_port);
247            assert_eq(s, s.try_into().expect(&msg), expected_host, expected_port);
248            assert_eq(
249                s,
250                s.to_owned().try_into().expect(&msg),
251                expected_host,
252                expected_port,
253            );
254            assert_eq(
255                s,
256                s.as_bytes().try_into().expect(&msg),
257                expected_host,
258                expected_port,
259            );
260            assert_eq(
261                s,
262                s.as_bytes().to_vec().try_into().expect(&msg),
263                expected_host,
264                expected_port,
265            );
266        }
267    }
268
269    #[test]
270    fn test_parse_invalid() {
271        for s in [
272            "",
273            "-",
274            ".",
275            ":",
276            ":80",
277            "-.",
278            ".-",
279            "::1",
280            "127.0.0.1",
281            "[::1]",
282            "2001:db8:3333:4444:5555:6666:7777:8888",
283            "[2001:db8:3333:4444:5555:6666:7777:8888]",
284            "example.com",
285            "example.com:",
286            "example.com:-1",
287            "example.com:999999",
288            "example:com",
289            "[127.0.0.1]:80",
290            "2001:db8:3333:4444:5555:6666:7777:8888:80",
291        ] {
292            let msg = format!("parsing '{}'", s);
293            assert!(s.parse::<Authority>().is_err(), "{}", msg);
294            assert!(Authority::try_from(s).is_err(), "{}", msg);
295            assert!(Authority::try_from(s.to_owned()).is_err(), "{}", msg);
296            assert!(Authority::try_from(s.as_bytes()).is_err(), "{}", msg);
297            assert!(
298                Authority::try_from(s.as_bytes().to_vec()).is_err(),
299                "{}",
300                msg
301            );
302        }
303    }
304
305    #[test]
306    fn test_parse_display() {
307        for (s, expected) in [
308            ("example.com:80", "example.com:80"),
309            ("[::1]:80", "[::1]:80"),
310            ("127.0.0.1:80", "127.0.0.1:80"),
311        ] {
312            let msg = format!("parsing '{}'", s);
313            let authority: Authority = s.parse().expect(&msg);
314            assert_eq!(authority.to_string(), expected, "{}", msg);
315        }
316    }
317}