feature/Refactored-server-url-parsing-logic (#7496)

* HostPort now properly returns -1 when no port was specified

* refactored the URL parsing to now attempt a DNS lookup in cases where URI parsing fails
This now allows local computer names and localhost etc
This commit is contained in:
matthias8422
2025-05-05 10:10:37 -07:00
committed by GitHub
parent 3c7993d640
commit a76f23fc25

View File

@@ -1,28 +1,14 @@
package forge.util; package forge.util;
import java.net.InetAddress;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.util.regex.Pattern; import java.net.UnknownHostException;
public class URLValidator { public class URLValidator {
private static final Pattern DOMAIN_NAME_PATTERN = Pattern.compile("^(?!-)[A-Za-z0-9-]{1,63}(?<!-)(\\.[A-Za-z]{2,})+$"); //no more need for URL regex as we are now passing any non conforming url to the inetAddressLookup function
//Removed manual ip parsing as the URI parsing will also take care of validating ip addresses as well
public static HostPort parseIP(String ip) {
String[] parts = ip.split("\\.");
if (parts.length != 4) return null;
for (String part : parts) {
try {
int num = Integer.parseInt(part);
if (num < 0 || num > 255) return null;
} catch (NumberFormatException e) {
return null;
}
}
return new HostPort(ip, null); // No port for raw IP
}
public static HostPort parseURL(String url) { public static HostPort parseURL(String url) {
try { try {
//prepend http:// if a protocol is missing so URI parsing does not fail //prepend http:// if a protocol is missing so URI parsing does not fail
@@ -30,21 +16,33 @@ public class URLValidator {
URI uri = new URI(formattedUrl); URI uri = new URI(formattedUrl);
String host = uri.getHost(); String host = uri.getHost();
int port = uri.getPort(); // Returns -1 if port is not specified int port = uri.getPort(); // Returns -1 if port is not specified
if (host == null) return null; if (host == null) {
HostPort hostPort; return inetAddressLookup(url);
if (parseIP(host) != null) {
hostPort = new HostPort(host, port == -1 ? null : port);
} else if (DOMAIN_NAME_PATTERN.matcher(host).matches()) {
hostPort = new HostPort(host, port == -1 ? null : port);
} else {
return null;
} }
return hostPort; return new HostPort(host, port);
} catch (URISyntaxException e) { } catch (URISyntaxException e) {
return null; return inetAddressLookup(url);
} }
} }
// Attempt to resolve as hostname
private static HostPort inetAddressLookup(String url) {
try {
// Split input to handle cases like "localhost:36743"
String[] parts = url.split(":");
String host = parts[0];
// if no port exists, default to -1 just like URI parsing
// invalid port number will throw NumberFormatException caught below
int port = parts.length > 1 ? Integer.parseInt(parts[1]) : -1;
// address isn't needed but its presence suppresses an intelij warning
InetAddress address = InetAddress.getByName(host);
return new HostPort(host, port);
} catch (NumberFormatException | UnknownHostException ex) {
return null; // Invalid port or hostname does not resolve
}
}
//This is fine, Records were introduced in Java 16, its essentially a DTO class with implicit getters and constructors //This is fine, Records were introduced in Java 16, its essentially a DTO class with implicit getters and constructors
public record HostPort(String host, Integer port) { public record HostPort(String host, Integer port) {
} }