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#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
14pub struct Authority {
15 host: Host,
16 port: u16,
17}
18
19impl Authority {
20 pub const fn new(host: Host, port: u16) -> Self {
22 Authority { host, port }
23 }
24
25 pub fn host(&self) -> &Host {
27 &self.host
28 }
29
30 pub fn into_host(self) -> Host {
32 self.host
33 }
34
35 pub fn port(&self) -> u16 {
37 self.port
38 }
39
40 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}