]>
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 | ||
532ac7d7 XL |
6 | use crate::error::Error; |
7 | use crate::fmt; | |
8 | use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; | |
9 | use crate::str::FromStr; | |
85aaf69f SL |
10 | |
11 | struct Parser<'a> { | |
12 | // parsing as ASCII, so can use byte array | |
13 | s: &'a [u8], | |
14 | pos: usize, | |
15 | } | |
16 | ||
17 | impl<'a> Parser<'a> { | |
18 | fn new(s: &'a str) -> Parser<'a> { | |
60c5eb7d | 19 | Parser { s: s.as_bytes(), pos: 0 } |
85aaf69f SL |
20 | } |
21 | ||
22 | fn is_eof(&self) -> bool { | |
23 | self.pos == self.s.len() | |
24 | } | |
25 | ||
26 | // Commit only if parser returns Some | |
60c5eb7d XL |
27 | fn read_atomically<T, F>(&mut self, cb: F) -> Option<T> |
28 | where | |
532ac7d7 | 29 | F: FnOnce(&mut Parser<'_>) -> Option<T>, |
85aaf69f SL |
30 | { |
31 | let pos = self.pos; | |
32 | let r = cb(self); | |
33 | if r.is_none() { | |
34 | self.pos = pos; | |
35 | } | |
36 | r | |
37 | } | |
38 | ||
39 | // Commit only if parser read till EOF | |
60c5eb7d XL |
40 | fn read_till_eof<T, F>(&mut self, cb: F) -> Option<T> |
41 | where | |
532ac7d7 | 42 | F: FnOnce(&mut Parser<'_>) -> Option<T>, |
85aaf69f | 43 | { |
60c5eb7d | 44 | self.read_atomically(move |p| cb(p).filter(|_| p.is_eof())) |
85aaf69f SL |
45 | } |
46 | ||
47 | // Apply 3 parsers sequentially | |
60c5eb7d XL |
48 | fn read_seq_3<A, B, C, PA, PB, PC>(&mut self, pa: PA, pb: PB, pc: PC) -> Option<(A, B, C)> |
49 | where | |
532ac7d7 XL |
50 | PA: FnOnce(&mut Parser<'_>) -> Option<A>, |
51 | PB: FnOnce(&mut Parser<'_>) -> Option<B>, | |
52 | PC: FnOnce(&mut Parser<'_>) -> Option<C>, | |
85aaf69f SL |
53 | { |
54 | self.read_atomically(move |p| { | |
55 | let a = pa(p); | |
56 | let b = if a.is_some() { pb(p) } else { None }; | |
57 | let c = if b.is_some() { pc(p) } else { None }; | |
58 | match (a, b, c) { | |
59 | (Some(a), Some(b), Some(c)) => Some((a, b, c)), | |
60c5eb7d | 60 | _ => None, |
85aaf69f SL |
61 | } |
62 | }) | |
63 | } | |
64 | ||
65 | // Read next char | |
66 | fn read_char(&mut self) -> Option<char> { | |
67 | if self.is_eof() { | |
68 | None | |
69 | } else { | |
70 | let r = self.s[self.pos] as char; | |
71 | self.pos += 1; | |
72 | Some(r) | |
73 | } | |
74 | } | |
75 | ||
76 | // Return char and advance iff next char is equal to requested | |
77 | fn read_given_char(&mut self, c: char) -> Option<char> { | |
60c5eb7d XL |
78 | self.read_atomically(|p| match p.read_char() { |
79 | Some(next) if next == c => Some(next), | |
80 | _ => None, | |
85aaf69f SL |
81 | }) |
82 | } | |
83 | ||
84 | // Read digit | |
85 | fn read_digit(&mut self, radix: u8) -> Option<u8> { | |
86 | fn parse_digit(c: char, radix: u8) -> Option<u8> { | |
87 | let c = c as u8; | |
88 | // assuming radix is either 10 or 16 | |
89 | if c >= b'0' && c <= b'9' { | |
90 | Some(c - b'0') | |
91 | } else if radix > 10 && c >= b'a' && c < b'a' + (radix - 10) { | |
92 | Some(c - b'a' + 10) | |
93 | } else if radix > 10 && c >= b'A' && c < b'A' + (radix - 10) { | |
94 | Some(c - b'A' + 10) | |
95 | } else { | |
96 | None | |
97 | } | |
98 | } | |
99 | ||
60c5eb7d | 100 | self.read_atomically(|p| p.read_char().and_then(|c| parse_digit(c, radix))) |
85aaf69f SL |
101 | } |
102 | ||
103 | fn read_number_impl(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option<u32> { | |
c34b1796 | 104 | let mut r = 0; |
85aaf69f SL |
105 | let mut digit_count = 0; |
106 | loop { | |
107 | match self.read_digit(radix) { | |
108 | Some(d) => { | |
109 | r = r * (radix as u32) + (d as u32); | |
110 | digit_count += 1; | |
111 | if digit_count > max_digits || r >= upto { | |
60c5eb7d | 112 | return None; |
85aaf69f SL |
113 | } |
114 | } | |
115 | None => { | |
116 | if digit_count == 0 { | |
60c5eb7d | 117 | return None; |
85aaf69f | 118 | } else { |
60c5eb7d | 119 | return Some(r); |
85aaf69f SL |
120 | } |
121 | } | |
122 | }; | |
123 | } | |
124 | } | |
125 | ||
126 | // Read number, failing if max_digits of number value exceeded | |
127 | fn read_number(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option<u32> { | |
128 | self.read_atomically(|p| p.read_number_impl(radix, max_digits, upto)) | |
129 | } | |
130 | ||
131 | fn read_ipv4_addr_impl(&mut self) -> Option<Ipv4Addr> { | |
c34b1796 | 132 | let mut bs = [0; 4]; |
85aaf69f SL |
133 | let mut i = 0; |
134 | while i < 4 { | |
135 | if i != 0 && self.read_given_char('.').is_none() { | |
136 | return None; | |
137 | } | |
138 | ||
ff7c6d11 | 139 | bs[i] = self.read_number(10, 3, 0x100).map(|n| n as u8)?; |
85aaf69f SL |
140 | i += 1; |
141 | } | |
142 | Some(Ipv4Addr::new(bs[0], bs[1], bs[2], bs[3])) | |
143 | } | |
144 | ||
145 | // Read IPv4 address | |
146 | fn read_ipv4_addr(&mut self) -> Option<Ipv4Addr> { | |
147 | self.read_atomically(|p| p.read_ipv4_addr_impl()) | |
148 | } | |
149 | ||
150 | fn read_ipv6_addr_impl(&mut self) -> Option<Ipv6Addr> { | |
151 | fn ipv6_addr_from_head_tail(head: &[u16], tail: &[u16]) -> Ipv6Addr { | |
152 | assert!(head.len() + tail.len() <= 8); | |
c34b1796 | 153 | let mut gs = [0; 8]; |
7453a54e | 154 | gs[..head.len()].copy_from_slice(head); |
60c5eb7d | 155 | gs[(8 - tail.len())..8].copy_from_slice(tail); |
85aaf69f SL |
156 | Ipv6Addr::new(gs[0], gs[1], gs[2], gs[3], gs[4], gs[5], gs[6], gs[7]) |
157 | } | |
158 | ||
60c5eb7d | 159 | fn read_groups(p: &mut Parser<'_>, groups: &mut [u16; 8], limit: usize) -> (usize, bool) { |
85aaf69f SL |
160 | let mut i = 0; |
161 | while i < limit { | |
162 | if i < limit - 1 { | |
163 | let ipv4 = p.read_atomically(|p| { | |
164 | if i == 0 || p.read_given_char(':').is_some() { | |
165 | p.read_ipv4_addr() | |
166 | } else { | |
167 | None | |
168 | } | |
169 | }); | |
170 | if let Some(v4_addr) = ipv4 { | |
171 | let octets = v4_addr.octets(); | |
172 | groups[i + 0] = ((octets[0] as u16) << 8) | (octets[1] as u16); | |
173 | groups[i + 1] = ((octets[2] as u16) << 8) | (octets[3] as u16); | |
174 | return (i + 2, true); | |
175 | } | |
176 | } | |
177 | ||
178 | let group = p.read_atomically(|p| { | |
179 | if i == 0 || p.read_given_char(':').is_some() { | |
180 | p.read_number(16, 4, 0x10000).map(|n| n as u16) | |
181 | } else { | |
182 | None | |
183 | } | |
184 | }); | |
185 | match group { | |
186 | Some(g) => groups[i] = g, | |
60c5eb7d | 187 | None => return (i, false), |
85aaf69f SL |
188 | } |
189 | i += 1; | |
190 | } | |
191 | (i, false) | |
192 | } | |
193 | ||
c34b1796 | 194 | let mut head = [0; 8]; |
85aaf69f SL |
195 | let (head_size, head_ipv4) = read_groups(self, &mut head, 8); |
196 | ||
197 | if head_size == 8 { | |
198 | return Some(Ipv6Addr::new( | |
60c5eb7d XL |
199 | head[0], head[1], head[2], head[3], head[4], head[5], head[6], head[7], |
200 | )); | |
85aaf69f SL |
201 | } |
202 | ||
203 | // IPv4 part is not allowed before `::` | |
204 | if head_ipv4 { | |
60c5eb7d | 205 | return None; |
85aaf69f SL |
206 | } |
207 | ||
208 | // read `::` if previous code parsed less than 8 groups | |
209 | if !self.read_given_char(':').is_some() || !self.read_given_char(':').is_some() { | |
210 | return None; | |
211 | } | |
212 | ||
c34b1796 | 213 | let mut tail = [0; 8]; |
ff7c6d11 XL |
214 | // `::` indicates one or more groups of 16 bits of zeros |
215 | let limit = 8 - (head_size + 1); | |
216 | let (tail_size, _) = read_groups(self, &mut tail, limit); | |
85aaf69f SL |
217 | Some(ipv6_addr_from_head_tail(&head[..head_size], &tail[..tail_size])) |
218 | } | |
219 | ||
220 | fn read_ipv6_addr(&mut self) -> Option<Ipv6Addr> { | |
221 | self.read_atomically(|p| p.read_ipv6_addr_impl()) | |
222 | } | |
223 | ||
224 | fn read_ip_addr(&mut self) -> Option<IpAddr> { | |
60c5eb7d XL |
225 | self.read_ipv4_addr().map(IpAddr::V4) |
226 | .or_else(|| self.read_ipv6_addr().map(IpAddr::V6)) | |
85aaf69f SL |
227 | } |
228 | ||
b039eaaf | 229 | fn read_socket_addr_v4(&mut self) -> Option<SocketAddrV4> { |
532ac7d7 XL |
230 | let ip_addr = |p: &mut Parser<'_>| p.read_ipv4_addr(); |
231 | let colon = |p: &mut Parser<'_>| p.read_given_char(':'); | |
60c5eb7d | 232 | let port = |p: &mut Parser<'_>| p.read_number(10, 5, 0x10000).map(|n| n as u16); |
b039eaaf SL |
233 | |
234 | self.read_seq_3(ip_addr, colon, port).map(|t| { | |
235 | let (ip, _, port): (Ipv4Addr, char, u16) = t; | |
236 | SocketAddrV4::new(ip, port) | |
237 | }) | |
238 | } | |
239 | ||
240 | fn read_socket_addr_v6(&mut self) -> Option<SocketAddrV6> { | |
532ac7d7 XL |
241 | let ip_addr = |p: &mut Parser<'_>| { |
242 | let open_br = |p: &mut Parser<'_>| p.read_given_char('['); | |
243 | let ip_addr = |p: &mut Parser<'_>| p.read_ipv6_addr(); | |
244 | let clos_br = |p: &mut Parser<'_>| p.read_given_char(']'); | |
b039eaaf | 245 | p.read_seq_3(open_br, ip_addr, clos_br).map(|t| t.1) |
85aaf69f | 246 | }; |
532ac7d7 | 247 | let colon = |p: &mut Parser<'_>| p.read_given_char(':'); |
60c5eb7d | 248 | let port = |p: &mut Parser<'_>| p.read_number(10, 5, 0x10000).map(|n| n as u16); |
85aaf69f | 249 | |
c34b1796 | 250 | self.read_seq_3(ip_addr, colon, port).map(|t| { |
b039eaaf SL |
251 | let (ip, _, port): (Ipv6Addr, char, u16) = t; |
252 | SocketAddrV6::new(ip, port, 0, 0) | |
c34b1796 | 253 | }) |
85aaf69f | 254 | } |
b039eaaf SL |
255 | |
256 | fn read_socket_addr(&mut self) -> Option<SocketAddr> { | |
60c5eb7d XL |
257 | self.read_socket_addr_v4().map(SocketAddr::V4) |
258 | .or_else(|| self.read_socket_addr_v6().map(SocketAddr::V6)) | |
b039eaaf | 259 | } |
85aaf69f SL |
260 | } |
261 | ||
c30ab7b3 | 262 | #[stable(feature = "ip_addr", since = "1.7.0")] |
85aaf69f | 263 | impl FromStr for IpAddr { |
c34b1796 AL |
264 | type Err = AddrParseError; |
265 | fn from_str(s: &str) -> Result<IpAddr, AddrParseError> { | |
85aaf69f SL |
266 | match Parser::new(s).read_till_eof(|p| p.read_ip_addr()) { |
267 | Some(s) => Ok(s), | |
60c5eb7d | 268 | None => Err(AddrParseError(())), |
85aaf69f SL |
269 | } |
270 | } | |
271 | } | |
272 | ||
c34b1796 | 273 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f | 274 | impl FromStr for Ipv4Addr { |
c34b1796 AL |
275 | type Err = AddrParseError; |
276 | fn from_str(s: &str) -> Result<Ipv4Addr, AddrParseError> { | |
85aaf69f SL |
277 | match Parser::new(s).read_till_eof(|p| p.read_ipv4_addr()) { |
278 | Some(s) => Ok(s), | |
60c5eb7d | 279 | None => Err(AddrParseError(())), |
85aaf69f SL |
280 | } |
281 | } | |
282 | } | |
283 | ||
c34b1796 | 284 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f | 285 | impl FromStr for Ipv6Addr { |
c34b1796 AL |
286 | type Err = AddrParseError; |
287 | fn from_str(s: &str) -> Result<Ipv6Addr, AddrParseError> { | |
85aaf69f SL |
288 | match Parser::new(s).read_till_eof(|p| p.read_ipv6_addr()) { |
289 | Some(s) => Ok(s), | |
60c5eb7d | 290 | None => Err(AddrParseError(())), |
85aaf69f SL |
291 | } |
292 | } | |
293 | } | |
294 | ||
b039eaaf SL |
295 | #[stable(feature = "socket_addr_from_str", since = "1.5.0")] |
296 | impl FromStr for SocketAddrV4 { | |
297 | type Err = AddrParseError; | |
298 | fn from_str(s: &str) -> Result<SocketAddrV4, AddrParseError> { | |
299 | match Parser::new(s).read_till_eof(|p| p.read_socket_addr_v4()) { | |
300 | Some(s) => Ok(s), | |
301 | None => Err(AddrParseError(())), | |
302 | } | |
303 | } | |
304 | } | |
305 | ||
306 | #[stable(feature = "socket_addr_from_str", since = "1.5.0")] | |
307 | impl FromStr for SocketAddrV6 { | |
308 | type Err = AddrParseError; | |
309 | fn from_str(s: &str) -> Result<SocketAddrV6, AddrParseError> { | |
310 | match Parser::new(s).read_till_eof(|p| p.read_socket_addr_v6()) { | |
311 | Some(s) => Ok(s), | |
312 | None => Err(AddrParseError(())), | |
313 | } | |
314 | } | |
315 | } | |
316 | ||
c34b1796 | 317 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f | 318 | impl FromStr for SocketAddr { |
c34b1796 AL |
319 | type Err = AddrParseError; |
320 | fn from_str(s: &str) -> Result<SocketAddr, AddrParseError> { | |
85aaf69f SL |
321 | match Parser::new(s).read_till_eof(|p| p.read_socket_addr()) { |
322 | Some(s) => Ok(s), | |
c34b1796 | 323 | None => Err(AddrParseError(())), |
85aaf69f SL |
324 | } |
325 | } | |
326 | } | |
327 | ||
cc61c64b XL |
328 | /// An error which can be returned when parsing an IP address or a socket address. |
329 | /// | |
330 | /// This error is used as the error type for the [`FromStr`] implementation for | |
331 | /// [`IpAddr`], [`Ipv4Addr`], [`Ipv6Addr`], [`SocketAddr`], [`SocketAddrV4`], and | |
332 | /// [`SocketAddrV6`]. | |
333 | /// | |
0531ce1d XL |
334 | /// # Potential causes |
335 | /// | |
336 | /// `AddrParseError` may be thrown because the provided string does not parse as the given type, | |
337 | /// often because it includes information only handled by a different address type. | |
338 | /// | |
339 | /// ```should_panic | |
340 | /// use std::net::IpAddr; | |
341 | /// let _foo: IpAddr = "127.0.0.1:8080".parse().expect("Cannot handle the socket port"); | |
342 | /// ``` | |
343 | /// | |
344 | /// [`IpAddr`] doesn't handle the port. Use [`SocketAddr`] instead. | |
345 | /// | |
346 | /// ``` | |
347 | /// use std::net::SocketAddr; | |
348 | /// | |
349 | /// // No problem, the `panic!` message has disappeared. | |
350 | /// let _foo: SocketAddr = "127.0.0.1:8080".parse().expect("unreachable panic"); | |
351 | /// ``` | |
352 | /// | |
cc61c64b XL |
353 | /// [`FromStr`]: ../../std/str/trait.FromStr.html |
354 | /// [`IpAddr`]: ../../std/net/enum.IpAddr.html | |
355 | /// [`Ipv4Addr`]: ../../std/net/struct.Ipv4Addr.html | |
356 | /// [`Ipv6Addr`]: ../../std/net/struct.Ipv6Addr.html | |
357 | /// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html | |
358 | /// [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html | |
359 | /// [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html | |
c34b1796 | 360 | #[stable(feature = "rust1", since = "1.0.0")] |
9e0c209e | 361 | #[derive(Debug, Clone, PartialEq, Eq)] |
c34b1796 | 362 | pub struct AddrParseError(()); |
e9174d1e SL |
363 | |
364 | #[stable(feature = "addr_parse_error_error", since = "1.4.0")] | |
365 | impl fmt::Display for AddrParseError { | |
532ac7d7 | 366 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
e9174d1e SL |
367 | fmt.write_str(self.description()) |
368 | } | |
369 | } | |
370 | ||
371 | #[stable(feature = "addr_parse_error_error", since = "1.4.0")] | |
372 | impl Error for AddrParseError { | |
373 | fn description(&self) -> &str { | |
374 | "invalid IP address syntax" | |
375 | } | |
376 | } |