identifiers: Add host and is_ip_literal methods to ServerName

Co-authored-by: Timo Kösters <timo@koesters.xyz>
This commit is contained in:
Jonas Platte 2022-01-17 11:52:43 +01:00
parent 026c186b32
commit 4c2654c605
No known key found for this signature in database
GPG Key ID: 7D261D771D915378
2 changed files with 71 additions and 0 deletions

View File

@ -12,6 +12,10 @@ Breaking changes:
* Rename `RoomVersionId::Version{X}` variants to `RoomVersionId::V{X}` * Rename `RoomVersionId::Version{X}` variants to `RoomVersionId::V{X}`
* Rename `RoomIdOrAliasId` to `RoomOrAliasId` * Rename `RoomIdOrAliasId` to `RoomOrAliasId`
Improvements:
* Add `host` and `is_ip_literal` methods to `ServerName`
Bug fixes: Bug fixes:
* Properly validate localpart when building a `UserId` via `parse_with_server_name` (and its * Properly validate localpart when building a `UserId` via `parse_with_server_name` (and its

View File

@ -1,12 +1,37 @@
//! Matrix-spec compliant server names. //! Matrix-spec compliant server names.
use std::net::Ipv4Addr;
/// A Matrix-spec compliant server name. /// A Matrix-spec compliant server name.
///
/// It consists of a host and an optional port (separated by a colon if present).
#[repr(transparent)] #[repr(transparent)]
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ServerName(str); pub struct ServerName(str);
opaque_identifier_validated!(ServerName, ruma_identifiers_validation::server_name::validate); opaque_identifier_validated!(ServerName, ruma_identifiers_validation::server_name::validate);
impl ServerName {
/// Returns the host of the server name.
///
/// That is: Return the part of the server name before `:<port>` or the full server name if
/// there is no port.
pub fn host(&self) -> &str {
if let Some(end_of_ipv6) = self.0.find(']') {
&self.0[..=end_of_ipv6]
} else {
// It's not ipv6, so ':' means the port starts
let end_of_host = self.0.find(':').unwrap_or(self.0.len());
&self.0[..end_of_host]
}
}
/// Returns true if and only if the server name is an IPv4 or IPv6 address.
pub fn is_ip_literal(&self) -> bool {
self.host().parse::<Ipv4Addr>().is_ok() || self.0.starts_with('[')
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::convert::TryFrom; use std::convert::TryFrom;
@ -68,4 +93,46 @@ mod tests {
fn dns_name_with_invalid_port() { fn dns_name_with_invalid_port() {
assert!(<&ServerName>::try_from("matrix.org:hello").is_err()); assert!(<&ServerName>::try_from("matrix.org:hello").is_err());
} }
#[test]
fn parse_ipv4_host() {
let server_name = <&ServerName>::try_from("127.0.0.1").unwrap();
assert!(server_name.is_ip_literal());
assert_eq!(server_name.host(), "127.0.0.1");
}
#[test]
fn parse_ipv4_host_and_port() {
let server_name = <&ServerName>::try_from("1.1.1.1:12000").unwrap();
assert!(server_name.is_ip_literal());
assert_eq!(server_name.host(), "1.1.1.1");
}
#[test]
fn parse_ipv6() {
let server_name = <&ServerName>::try_from("[::1]").unwrap();
assert!(server_name.is_ip_literal());
assert_eq!(server_name.host(), "[::1]");
}
#[test]
fn parse_ipv6_with_port() {
let server_name = <&ServerName>::try_from("[1234:5678::abcd]:5678").unwrap();
assert!(server_name.is_ip_literal());
assert_eq!(server_name.host(), "[1234:5678::abcd]");
}
#[test]
fn parse_dns_name() {
let server_name = <&ServerName>::try_from("example.com").unwrap();
assert!(!server_name.is_ip_literal());
assert_eq!(server_name.host(), "example.com");
}
#[test]
fn parse_dns_name_with_port() {
let server_name = <&ServerName>::try_from("ruma.io:8080").unwrap();
assert!(!server_name.is_ip_literal());
assert_eq!(server_name.host(), "ruma.io");
}
} }