Skip to content

Commit 2f93af7

Browse files
committed
tiny performance improvements
Signed-off-by: MTRNord <MTRNord@users.noreply.github.com>
1 parent df7f508 commit 2f93af7

1 file changed

Lines changed: 44 additions & 13 deletions

File tree

crates/federation/src/validation/server_name.rs

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ pub fn parse_and_validate_server_name(data: &mut Root, server_name: &str) {
1010
return;
1111
}
1212

13+
let is_bracketed = server_name.starts_with('[');
14+
1315
// Split hostname and port, handling IPv6 literals in brackets: [addr] or [addr]:port
14-
let (hostname, port_str): (&str, &str) = if server_name.starts_with('[') {
16+
let (hostname, port_str): (&str, &str) = if is_bracketed {
1517
match server_name.find(']') {
1618
Some(end) => {
1719
let inner = &server_name[1..end];
@@ -50,7 +52,19 @@ pub fn parse_and_validate_server_name(data: &mut Root, server_name: &str) {
5052
return;
5153
}
5254

53-
if hostname.parse::<std::net::IpAddr>().is_ok() {
55+
// Pre-filter before the expensive IpAddr::from_str (which attempts both IPv4 and IPv6):
56+
// - Bracketed form: inner could be IPv4 or IPv6 → hex digits, ':', '.'
57+
// - Non-bracketed: only IPv4 is valid per Matrix spec (IPv6 requires brackets) → digits, '.'
58+
// Anything outside these sets can't be a valid IP, so skip the parse entirely.
59+
let might_be_ip = if is_bracketed {
60+
hostname
61+
.bytes()
62+
.all(|b| b.is_ascii_hexdigit() || matches!(b, b':' | b'.'))
63+
} else {
64+
hostname.bytes().all(|b| b.is_ascii_digit() || b == b'.')
65+
};
66+
67+
if might_be_ip && hostname.parse::<std::net::IpAddr>().is_ok() {
5468
// Valid IP literal; validate port if present
5569
if !port_str.is_empty() && port_str.parse::<u16>().is_err() {
5670
data.error = Some(Error {
@@ -64,24 +78,41 @@ pub fn parse_and_validate_server_name(data: &mut Root, server_name: &str) {
6478
}
6579

6680
// Not an IP literal — validate as DNS name
67-
if !hostname.is_ascii() || hostname.len() > 255 || hostname.contains("..") {
81+
if !hostname.is_ascii() || hostname.len() > 255 {
6882
data.error = Some(Error {
6983
error: format!("Invalid server name: {server_name} (Not a valid DNS name)",),
7084
error_code: ErrorCode::InvalidServerName(InvalidServerNameErrorCode::NotValidDNS),
7185
});
7286
return;
7387
}
7488

75-
// Check for invalid characters in the hostname
76-
for c in hostname.chars() {
77-
if !c.is_ascii_alphanumeric() && c != '-' && c != '.' {
78-
data.error = Some(Error {
79-
error: format!("Invalid server name: {server_name} (Invalid character '{c}')",),
80-
error_code: ErrorCode::InvalidServerName(
81-
InvalidServerNameErrorCode::InvalidCharacter,
82-
),
83-
});
84-
return;
89+
// Single-pass over bytes: detect invalid characters and ".." simultaneously.
90+
// Since is_ascii() passed above, iterating bytes is equivalent to iterating chars.
91+
let mut prev_was_dot = false;
92+
for b in hostname.bytes() {
93+
if b == b'.' {
94+
if prev_was_dot {
95+
data.error = Some(Error {
96+
error: format!("Invalid server name: {server_name} (Not a valid DNS name)",),
97+
error_code: ErrorCode::InvalidServerName(
98+
InvalidServerNameErrorCode::NotValidDNS,
99+
),
100+
});
101+
return;
102+
}
103+
prev_was_dot = true;
104+
} else {
105+
prev_was_dot = false;
106+
if !b.is_ascii_alphanumeric() && b != b'-' {
107+
let c = b as char;
108+
data.error = Some(Error {
109+
error: format!("Invalid server name: {server_name} (Invalid character '{c}')",),
110+
error_code: ErrorCode::InvalidServerName(
111+
InvalidServerNameErrorCode::InvalidCharacter,
112+
),
113+
});
114+
return;
115+
}
85116
}
86117
}
87118
}

0 commit comments

Comments
 (0)