]>
Commit | Line | Data |
---|---|---|
85aaf69f SL |
1 | //! A private parser implementation of IPv4, IPv6, and socket addresses. |
2 | //! | |
3 | //! This module is "publicly exported" through the `FromStr` implementations | |
4 | //! below. | |
5 | ||
1b1a35ee XL |
6 | #[cfg(test)] |
7 | mod tests; | |
8 | ||
29967ef6 | 9 | use crate::convert::TryInto as _; |
532ac7d7 XL |
10 | use crate::error::Error; |
11 | use crate::fmt; | |
12 | use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; | |
13 | use crate::str::FromStr; | |
85aaf69f | 14 | |
29967ef6 XL |
15 | trait ReadNumberHelper: crate::marker::Sized { |
16 | const ZERO: Self; | |
17 | fn checked_mul(&self, other: u32) -> Option<Self>; | |
18 | fn checked_add(&self, other: u32) -> Option<Self>; | |
19 | } | |
20 | ||
21 | macro_rules! impl_helper { | |
22 | ($($t:ty)*) => ($(impl ReadNumberHelper for $t { | |
23 | const ZERO: Self = 0; | |
24 | #[inline] | |
25 | fn checked_mul(&self, other: u32) -> Option<Self> { | |
26 | Self::checked_mul(*self, other.try_into().ok()?) | |
27 | } | |
28 | #[inline] | |
29 | fn checked_add(&self, other: u32) -> Option<Self> { | |
30 | Self::checked_add(*self, other.try_into().ok()?) | |
31 | } | |
32 | })*) | |
33 | } | |
34 | ||
35 | impl_helper! { u8 u16 u32 } | |
36 | ||
85aaf69f | 37 | struct Parser<'a> { |
6a06907d | 38 | // Parsing as ASCII, so can use byte array. |
f035d41b | 39 | state: &'a [u8], |
85aaf69f SL |
40 | } |
41 | ||
42 | impl<'a> Parser<'a> { | |
f035d41b XL |
43 | fn new(input: &'a str) -> Parser<'a> { |
44 | Parser { state: input.as_bytes() } | |
85aaf69f SL |
45 | } |
46 | ||
6a06907d | 47 | /// Run a parser, and restore the pre-parse state if it fails. |
f035d41b | 48 | fn read_atomically<T, F>(&mut self, inner: F) -> Option<T> |
60c5eb7d | 49 | where |
532ac7d7 | 50 | F: FnOnce(&mut Parser<'_>) -> Option<T>, |
85aaf69f | 51 | { |
f035d41b XL |
52 | let state = self.state; |
53 | let result = inner(self); | |
54 | if result.is_none() { | |
55 | self.state = state; | |
85aaf69f | 56 | } |
f035d41b | 57 | result |
85aaf69f SL |
58 | } |
59 | ||
f035d41b XL |
60 | /// Run a parser, but fail if the entire input wasn't consumed. |
61 | /// Doesn't run atomically. | |
f035d41b | 62 | fn parse_with<T, F>(&mut self, inner: F) -> Result<T, AddrParseError> |
60c5eb7d | 63 | where |
f035d41b | 64 | F: FnOnce(&mut Parser<'_>) -> Option<T>, |
85aaf69f | 65 | { |
29967ef6 XL |
66 | let result = inner(self); |
67 | if self.state.is_empty() { result } else { None }.ok_or(AddrParseError(())) | |
85aaf69f SL |
68 | } |
69 | ||
f035d41b | 70 | /// Read the next character from the input |
85aaf69f | 71 | fn read_char(&mut self) -> Option<char> { |
f035d41b XL |
72 | self.state.split_first().map(|(&b, tail)| { |
73 | self.state = tail; | |
29967ef6 | 74 | char::from(b) |
85aaf69f SL |
75 | }) |
76 | } | |
77 | ||
29967ef6 XL |
78 | #[must_use] |
79 | /// Read the next character from the input if it matches the target. | |
80 | fn read_given_char(&mut self, target: char) -> Option<()> { | |
81 | self.read_atomically(|p| { | |
82 | p.read_char().and_then(|c| if c == target { Some(()) } else { None }) | |
83 | }) | |
85aaf69f SL |
84 | } |
85 | ||
f035d41b XL |
86 | /// Helper for reading separators in an indexed loop. Reads the separator |
87 | /// character iff index > 0, then runs the parser. When used in a loop, | |
88 | /// the separator character will only be read on index > 0 (see | |
89 | /// read_ipv4_addr for an example) | |
90 | fn read_separator<T, F>(&mut self, sep: char, index: usize, inner: F) -> Option<T> | |
91 | where | |
92 | F: FnOnce(&mut Parser<'_>) -> Option<T>, | |
93 | { | |
94 | self.read_atomically(move |p| { | |
95 | if index > 0 { | |
29967ef6 | 96 | p.read_given_char(sep)?; |
f035d41b XL |
97 | } |
98 | inner(p) | |
99 | }) | |
85aaf69f SL |
100 | } |
101 | ||
f035d41b XL |
102 | // Read a number off the front of the input in the given radix, stopping |
103 | // at the first non-digit character or eof. Fails if the number has more | |
29967ef6 XL |
104 | // digits than max_digits or if there is no number. |
105 | fn read_number<T: ReadNumberHelper>( | |
106 | &mut self, | |
107 | radix: u32, | |
108 | max_digits: Option<usize>, | |
109 | ) -> Option<T> { | |
f035d41b | 110 | self.read_atomically(move |p| { |
29967ef6 | 111 | let mut result = T::ZERO; |
f035d41b XL |
112 | let mut digit_count = 0; |
113 | ||
29967ef6 XL |
114 | while let Some(digit) = p.read_atomically(|p| p.read_char()?.to_digit(radix)) { |
115 | result = result.checked_mul(radix)?; | |
116 | result = result.checked_add(digit)?; | |
f035d41b | 117 | digit_count += 1; |
29967ef6 XL |
118 | if let Some(max_digits) = max_digits { |
119 | if digit_count > max_digits { | |
120 | return None; | |
121 | } | |
f035d41b | 122 | } |
85aaf69f SL |
123 | } |
124 | ||
f035d41b XL |
125 | if digit_count == 0 { None } else { Some(result) } |
126 | }) | |
85aaf69f SL |
127 | } |
128 | ||
6a06907d | 129 | /// Read an IPv4 address. |
85aaf69f | 130 | fn read_ipv4_addr(&mut self) -> Option<Ipv4Addr> { |
f035d41b XL |
131 | self.read_atomically(|p| { |
132 | let mut groups = [0; 4]; | |
85aaf69f | 133 | |
f035d41b | 134 | for (i, slot) in groups.iter_mut().enumerate() { |
29967ef6 | 135 | *slot = p.read_separator('.', i, |p| p.read_number(10, None))?; |
f035d41b XL |
136 | } |
137 | ||
138 | Some(groups.into()) | |
139 | }) | |
140 | } | |
85aaf69f | 141 | |
6a06907d | 142 | /// Read an IPv6 Address. |
f035d41b | 143 | fn read_ipv6_addr(&mut self) -> Option<Ipv6Addr> { |
6a06907d | 144 | /// Read a chunk of an IPv6 address into `groups`. Returns the number |
f035d41b | 145 | /// of groups read, along with a bool indicating if an embedded |
6a06907d XL |
146 | /// trailing IPv4 address was read. Specifically, read a series of |
147 | /// colon-separated IPv6 groups (0x0000 - 0xFFFF), with an optional | |
148 | /// trailing embedded IPv4 address. | |
f035d41b XL |
149 | fn read_groups(p: &mut Parser<'_>, groups: &mut [u16]) -> (usize, bool) { |
150 | let limit = groups.len(); | |
151 | ||
152 | for (i, slot) in groups.iter_mut().enumerate() { | |
6a06907d | 153 | // Try to read a trailing embedded IPv4 address. There must be |
f035d41b | 154 | // at least two groups left. |
85aaf69f | 155 | if i < limit - 1 { |
f035d41b XL |
156 | let ipv4 = p.read_separator(':', i, |p| p.read_ipv4_addr()); |
157 | ||
85aaf69f | 158 | if let Some(v4_addr) = ipv4 { |
29967ef6 XL |
159 | let [one, two, three, four] = v4_addr.octets(); |
160 | groups[i + 0] = u16::from_be_bytes([one, two]); | |
161 | groups[i + 1] = u16::from_be_bytes([three, four]); | |
85aaf69f SL |
162 | return (i + 2, true); |
163 | } | |
164 | } | |
165 | ||
29967ef6 | 166 | let group = p.read_separator(':', i, |p| p.read_number(16, Some(4))); |
f035d41b | 167 | |
85aaf69f | 168 | match group { |
29967ef6 | 169 | Some(g) => *slot = g, |
60c5eb7d | 170 | None => return (i, false), |
85aaf69f | 171 | } |
85aaf69f | 172 | } |
f035d41b | 173 | (groups.len(), false) |
85aaf69f SL |
174 | } |
175 | ||
f035d41b XL |
176 | self.read_atomically(|p| { |
177 | // Read the front part of the address; either the whole thing, or up | |
178 | // to the first :: | |
179 | let mut head = [0; 8]; | |
180 | let (head_size, head_ipv4) = read_groups(p, &mut head); | |
85aaf69f | 181 | |
f035d41b XL |
182 | if head_size == 8 { |
183 | return Some(head.into()); | |
184 | } | |
85aaf69f | 185 | |
f035d41b XL |
186 | // IPv4 part is not allowed before `::` |
187 | if head_ipv4 { | |
188 | return None; | |
189 | } | |
85aaf69f | 190 | |
6a06907d XL |
191 | // Read `::` if previous code parsed less than 8 groups. |
192 | // `::` indicates one or more groups of 16 bits of zeros. | |
29967ef6 XL |
193 | p.read_given_char(':')?; |
194 | p.read_given_char(':')?; | |
85aaf69f | 195 | |
f035d41b XL |
196 | // Read the back part of the address. The :: must contain at least one |
197 | // set of zeroes, so our max length is 7. | |
198 | let mut tail = [0; 7]; | |
199 | let limit = 8 - (head_size + 1); | |
200 | let (tail_size, _) = read_groups(p, &mut tail[..limit]); | |
85aaf69f | 201 | |
f035d41b XL |
202 | // Concat the head and tail of the IP address |
203 | head[(8 - tail_size)..8].copy_from_slice(&tail[..tail_size]); | |
204 | ||
205 | Some(head.into()) | |
206 | }) | |
85aaf69f SL |
207 | } |
208 | ||
6a06907d | 209 | /// Read an IP Address, either IPv4 or IPv6. |
85aaf69f | 210 | fn read_ip_addr(&mut self) -> Option<IpAddr> { |
f035d41b | 211 | self.read_ipv4_addr().map(IpAddr::V4).or_else(move || self.read_ipv6_addr().map(IpAddr::V6)) |
85aaf69f SL |
212 | } |
213 | ||
6a06907d | 214 | /// Read a `:` followed by a port in base 10. |
f035d41b XL |
215 | fn read_port(&mut self) -> Option<u16> { |
216 | self.read_atomically(|p| { | |
29967ef6 XL |
217 | p.read_given_char(':')?; |
218 | p.read_number(10, None) | |
219 | }) | |
220 | } | |
221 | ||
6a06907d | 222 | /// Read a `%` followed by a scope ID in base 10. |
29967ef6 XL |
223 | fn read_scope_id(&mut self) -> Option<u32> { |
224 | self.read_atomically(|p| { | |
225 | p.read_given_char('%')?; | |
226 | p.read_number(10, None) | |
f035d41b XL |
227 | }) |
228 | } | |
b039eaaf | 229 | |
6a06907d | 230 | /// Read an IPv4 address with a port. |
f035d41b XL |
231 | fn read_socket_addr_v4(&mut self) -> Option<SocketAddrV4> { |
232 | self.read_atomically(|p| { | |
233 | let ip = p.read_ipv4_addr()?; | |
234 | let port = p.read_port()?; | |
235 | Some(SocketAddrV4::new(ip, port)) | |
b039eaaf SL |
236 | }) |
237 | } | |
238 | ||
6a06907d | 239 | /// Read an IPv6 address with a port. |
b039eaaf | 240 | fn read_socket_addr_v6(&mut self) -> Option<SocketAddrV6> { |
f035d41b | 241 | self.read_atomically(|p| { |
29967ef6 | 242 | p.read_given_char('[')?; |
f035d41b | 243 | let ip = p.read_ipv6_addr()?; |
29967ef6 XL |
244 | let scope_id = p.read_scope_id().unwrap_or(0); |
245 | p.read_given_char(']')?; | |
f035d41b XL |
246 | |
247 | let port = p.read_port()?; | |
29967ef6 | 248 | Some(SocketAddrV6::new(ip, port, 0, scope_id)) |
c34b1796 | 249 | }) |
85aaf69f | 250 | } |
b039eaaf | 251 | |
f035d41b | 252 | /// Read an IP address with a port |
b039eaaf | 253 | fn read_socket_addr(&mut self) -> Option<SocketAddr> { |
dfeec247 XL |
254 | self.read_socket_addr_v4() |
255 | .map(SocketAddr::V4) | |
60c5eb7d | 256 | .or_else(|| self.read_socket_addr_v6().map(SocketAddr::V6)) |
b039eaaf | 257 | } |
85aaf69f SL |
258 | } |
259 | ||
c30ab7b3 | 260 | #[stable(feature = "ip_addr", since = "1.7.0")] |
85aaf69f | 261 | impl FromStr for IpAddr { |
c34b1796 AL |
262 | type Err = AddrParseError; |
263 | fn from_str(s: &str) -> Result<IpAddr, AddrParseError> { | |
f035d41b | 264 | Parser::new(s).parse_with(|p| p.read_ip_addr()) |
85aaf69f SL |
265 | } |
266 | } | |
267 | ||
c34b1796 | 268 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f | 269 | impl FromStr for Ipv4Addr { |
c34b1796 AL |
270 | type Err = AddrParseError; |
271 | fn from_str(s: &str) -> Result<Ipv4Addr, AddrParseError> { | |
f035d41b | 272 | Parser::new(s).parse_with(|p| p.read_ipv4_addr()) |
85aaf69f SL |
273 | } |
274 | } | |
275 | ||
c34b1796 | 276 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f | 277 | impl FromStr for Ipv6Addr { |
c34b1796 AL |
278 | type Err = AddrParseError; |
279 | fn from_str(s: &str) -> Result<Ipv6Addr, AddrParseError> { | |
f035d41b | 280 | Parser::new(s).parse_with(|p| p.read_ipv6_addr()) |
85aaf69f SL |
281 | } |
282 | } | |
283 | ||
b039eaaf SL |
284 | #[stable(feature = "socket_addr_from_str", since = "1.5.0")] |
285 | impl FromStr for SocketAddrV4 { | |
286 | type Err = AddrParseError; | |
287 | fn from_str(s: &str) -> Result<SocketAddrV4, AddrParseError> { | |
f035d41b | 288 | Parser::new(s).parse_with(|p| p.read_socket_addr_v4()) |
b039eaaf SL |
289 | } |
290 | } | |
291 | ||
292 | #[stable(feature = "socket_addr_from_str", since = "1.5.0")] | |
293 | impl FromStr for SocketAddrV6 { | |
294 | type Err = AddrParseError; | |
295 | fn from_str(s: &str) -> Result<SocketAddrV6, AddrParseError> { | |
f035d41b | 296 | Parser::new(s).parse_with(|p| p.read_socket_addr_v6()) |
b039eaaf SL |
297 | } |
298 | } | |
299 | ||
c34b1796 | 300 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f | 301 | impl FromStr for SocketAddr { |
c34b1796 AL |
302 | type Err = AddrParseError; |
303 | fn from_str(s: &str) -> Result<SocketAddr, AddrParseError> { | |
f035d41b | 304 | Parser::new(s).parse_with(|p| p.read_socket_addr()) |
85aaf69f SL |
305 | } |
306 | } | |
307 | ||
cc61c64b XL |
308 | /// An error which can be returned when parsing an IP address or a socket address. |
309 | /// | |
310 | /// This error is used as the error type for the [`FromStr`] implementation for | |
311 | /// [`IpAddr`], [`Ipv4Addr`], [`Ipv6Addr`], [`SocketAddr`], [`SocketAddrV4`], and | |
312 | /// [`SocketAddrV6`]. | |
313 | /// | |
0531ce1d XL |
314 | /// # Potential causes |
315 | /// | |
316 | /// `AddrParseError` may be thrown because the provided string does not parse as the given type, | |
317 | /// often because it includes information only handled by a different address type. | |
318 | /// | |
319 | /// ```should_panic | |
320 | /// use std::net::IpAddr; | |
321 | /// let _foo: IpAddr = "127.0.0.1:8080".parse().expect("Cannot handle the socket port"); | |
322 | /// ``` | |
323 | /// | |
324 | /// [`IpAddr`] doesn't handle the port. Use [`SocketAddr`] instead. | |
325 | /// | |
326 | /// ``` | |
327 | /// use std::net::SocketAddr; | |
328 | /// | |
329 | /// // No problem, the `panic!` message has disappeared. | |
330 | /// let _foo: SocketAddr = "127.0.0.1:8080".parse().expect("unreachable panic"); | |
331 | /// ``` | |
c34b1796 | 332 | #[stable(feature = "rust1", since = "1.0.0")] |
9e0c209e | 333 | #[derive(Debug, Clone, PartialEq, Eq)] |
c34b1796 | 334 | pub struct AddrParseError(()); |
e9174d1e SL |
335 | |
336 | #[stable(feature = "addr_parse_error_error", since = "1.4.0")] | |
337 | impl fmt::Display for AddrParseError { | |
dfeec247 | 338 | #[allow(deprecated, deprecated_in_future)] |
532ac7d7 | 339 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
e9174d1e SL |
340 | fmt.write_str(self.description()) |
341 | } | |
342 | } | |
343 | ||
344 | #[stable(feature = "addr_parse_error_error", since = "1.4.0")] | |
345 | impl Error for AddrParseError { | |
dfeec247 | 346 | #[allow(deprecated)] |
e9174d1e SL |
347 | fn description(&self) -> &str { |
348 | "invalid IP address syntax" | |
349 | } | |
350 | } |