Skip to content

Commit

Permalink
Rollup merge of rust-lang#94890 - marmeladema:ip-addr-try-from-bytes,…
Browse files Browse the repository at this point in the history
… r=joshtriplett

Support parsing IP addresses from a byte string

Fixes rust-lang#94821

The goal is to be able to parse addresses from a byte string without requiring to do any utf8 validation. Since internally the parser already works on byte strings, this should be possible and I personally already needed this in the past too.

~~I used the proposed approach from the issue by implementing `TryFrom<&'a [u8]>` for all 6 address types (3 ip address types and 3 socket address types). I believe implementing stable traits for stable types is insta-stable so this will probably need an FCP?~~

Switched to an unstable inherent method approach called `parse_ascii` as requested.

cc ``@jyn514``
  • Loading branch information
Dylan-DPC authored Aug 28, 2022
2 parents ee285ea + 8bb4b5f commit 0e8e3ce
Showing 1 changed file with 125 additions and 13 deletions.
138 changes: 125 additions & 13 deletions library/std/src/net/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ struct Parser<'a> {
}

impl<'a> Parser<'a> {
fn new(input: &'a str) -> Parser<'a> {
Parser { state: input.as_bytes() }
fn new(input: &'a [u8]) -> Parser<'a> {
Parser { state: input }
}

/// Run a parser, and restore the pre-parse state if it fails.
Expand Down Expand Up @@ -273,56 +273,168 @@ impl<'a> Parser<'a> {
}
}

impl IpAddr {
/// Parse an IP address from a slice of bytes.
///
/// ```
/// #![feature(addr_parse_ascii)]
///
/// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
///
/// let localhost_v4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
/// let localhost_v6 = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
///
/// assert_eq!(IpAddr::parse_ascii(b"127.0.0.1"), Ok(localhost_v4));
/// assert_eq!(IpAddr::parse_ascii(b"::1"), Ok(localhost_v6));
/// ```
#[unstable(feature = "addr_parse_ascii", issue = "101035")]
pub fn parse_ascii(b: &[u8]) -> Result<Self, AddrParseError> {
Parser::new(b).parse_with(|p| p.read_ip_addr(), AddrKind::Ip)
}
}

#[stable(feature = "ip_addr", since = "1.7.0")]
impl FromStr for IpAddr {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<IpAddr, AddrParseError> {
Parser::new(s).parse_with(|p| p.read_ip_addr(), AddrKind::Ip)
Self::parse_ascii(s.as_bytes())
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl FromStr for Ipv4Addr {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<Ipv4Addr, AddrParseError> {
impl Ipv4Addr {
/// Parse an IPv4 address from a slice of bytes.
///
/// ```
/// #![feature(addr_parse_ascii)]
///
/// use std::net::Ipv4Addr;
///
/// let localhost = Ipv4Addr::new(127, 0, 0, 1);
///
/// assert_eq!(Ipv4Addr::parse_ascii(b"127.0.0.1"), Ok(localhost));
/// ```
#[unstable(feature = "addr_parse_ascii", issue = "101035")]
pub fn parse_ascii(b: &[u8]) -> Result<Self, AddrParseError> {
// don't try to parse if too long
if s.len() > 15 {
if b.len() > 15 {
Err(AddrParseError(AddrKind::Ipv4))
} else {
Parser::new(s).parse_with(|p| p.read_ipv4_addr(), AddrKind::Ipv4)
Parser::new(b).parse_with(|p| p.read_ipv4_addr(), AddrKind::Ipv4)
}
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl FromStr for Ipv4Addr {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<Ipv4Addr, AddrParseError> {
Self::parse_ascii(s.as_bytes())
}
}

impl Ipv6Addr {
/// Parse an IPv6 address from a slice of bytes.
///
/// ```
/// #![feature(addr_parse_ascii)]
///
/// use std::net::Ipv6Addr;
///
/// let localhost = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
///
/// assert_eq!(Ipv6Addr::parse_ascii(b"::1"), Ok(localhost));
/// ```
#[unstable(feature = "addr_parse_ascii", issue = "101035")]
pub fn parse_ascii(b: &[u8]) -> Result<Self, AddrParseError> {
Parser::new(b).parse_with(|p| p.read_ipv6_addr(), AddrKind::Ipv6)
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl FromStr for Ipv6Addr {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<Ipv6Addr, AddrParseError> {
Parser::new(s).parse_with(|p| p.read_ipv6_addr(), AddrKind::Ipv6)
Self::parse_ascii(s.as_bytes())
}
}

impl SocketAddrV4 {
/// Parse an IPv4 socket address from a slice of bytes.
///
/// ```
/// #![feature(addr_parse_ascii)]
///
/// use std::net::{Ipv4Addr, SocketAddrV4};
///
/// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
///
/// assert_eq!(SocketAddrV4::parse_ascii(b"127.0.0.1:8080"), Ok(socket));
/// ```
#[unstable(feature = "addr_parse_ascii", issue = "101035")]
pub fn parse_ascii(b: &[u8]) -> Result<Self, AddrParseError> {
Parser::new(b).parse_with(|p| p.read_socket_addr_v4(), AddrKind::SocketV4)
}
}

#[stable(feature = "socket_addr_from_str", since = "1.5.0")]
impl FromStr for SocketAddrV4 {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<SocketAddrV4, AddrParseError> {
Parser::new(s).parse_with(|p| p.read_socket_addr_v4(), AddrKind::SocketV4)
Self::parse_ascii(s.as_bytes())
}
}

impl SocketAddrV6 {
/// Parse an IPv6 socket address from a slice of bytes.
///
/// ```
/// #![feature(addr_parse_ascii)]
///
/// use std::net::{Ipv6Addr, SocketAddrV6};
///
/// let socket = SocketAddrV6::new(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
///
/// assert_eq!(SocketAddrV6::parse_ascii(b"[2001:db8::1]:8080"), Ok(socket));
/// ```
#[unstable(feature = "addr_parse_ascii", issue = "101035")]
pub fn parse_ascii(b: &[u8]) -> Result<Self, AddrParseError> {
Parser::new(b).parse_with(|p| p.read_socket_addr_v6(), AddrKind::SocketV6)
}
}

#[stable(feature = "socket_addr_from_str", since = "1.5.0")]
impl FromStr for SocketAddrV6 {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<SocketAddrV6, AddrParseError> {
Parser::new(s).parse_with(|p| p.read_socket_addr_v6(), AddrKind::SocketV6)
Self::parse_ascii(s.as_bytes())
}
}

impl SocketAddr {
/// Parse a socket address from a slice of bytes.
///
/// ```
/// #![feature(addr_parse_ascii)]
///
/// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
///
/// let socket_v4 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
/// let socket_v6 = SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), 8080);
///
/// assert_eq!(SocketAddr::parse_ascii(b"127.0.0.1:8080"), Ok(socket_v4));
/// assert_eq!(SocketAddr::parse_ascii(b"[::1]:8080"), Ok(socket_v6));
/// ```
#[unstable(feature = "addr_parse_ascii", issue = "101035")]
pub fn parse_ascii(b: &[u8]) -> Result<Self, AddrParseError> {
Parser::new(b).parse_with(|p| p.read_socket_addr(), AddrKind::Socket)
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl FromStr for SocketAddr {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<SocketAddr, AddrParseError> {
Parser::new(s).parse_with(|p| p.read_socket_addr(), AddrKind::Socket)
Self::parse_ascii(s.as_bytes())
}
}

Expand Down

0 comments on commit 0e8e3ce

Please sign in to comment.