Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

848 ipv6 support in DestinationParser #849

Merged
merged 3 commits into from
Aug 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,11 @@ or this:
</appender>
```

Destinations are expressed using the following format: `host[:port]` where:
- `host` can be a hostname (eg. `localhost`) , an IPv4 address (eg. `192.168.1.1`) or an IPv6 address enclosed between brackets (eg. `[2001:db8::1]`).
- `port` is optional and, if specified, must be prefixed by a colon (`:`). It must be a valid integer value between `0` and `65535`.


The appender uses a `connectionStrategy` to determine:

* the order in which destination connections are attempted, and
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@
*/
public class DestinationParser {

private static final Pattern DESTINATION_PATTERN = Pattern.compile("^\\s*(\\S+?)\\s*(:\\s*(\\S+)\\s*)?$");
private static final Pattern DESTINATION_PATTERN = Pattern.compile("^([^:]+)(:(.+))?$");
private static final Pattern DESTINATION_IPV6_PATTERN = Pattern.compile("^\\[(.+)\\](:(.+))?$");

private static final int HOSTNAME_GROUP = 1;
private static final int PORT_GROUP = 3;

Expand All @@ -39,14 +41,20 @@ private DestinationParser() {
/**
* Constructs {@link InetSocketAddress}es by parsing the given {@link String} value.
* <p>
* The string is a comma separated list of destinations in the form of hostName[:portNumber].
* The string is a comma separated list of destinations in the form of hostName[:portNumber] where:
* <ul>
* <li>{@code hostName} can be a hostname (eg. <i>localhost</i>), an IPv4 (eg. <i>192.168.1.1</i>) or
* an IPv6 enclosed between brackets (eg. <i>[2001:db8::1]</i>)
*
* <li>{@code portNumber} is optional and, if specified, must be prefixed by a colon. Must be a valid
* integer between 0 and 65535. If {@code portNumber} is not provided, then the given {@code defaultPort}
* will be used.
* </ul>
* <p>
*
* For example, "host1.domain.com,host2.domain.com:5560"
* <p>
*
* If portNumber is not provided, then the given defaultPort will be used.
*
* @param destinations comma-separated list of destinations in the form of {@code hostName[:portNumber]}
* @param defaultPort the port number to use when a destination does not specify one explicitly
* @return ordered list of {@link InetSocketAddress} instances
Expand All @@ -56,8 +64,8 @@ public static List<InetSocketAddress> parse(String destinations, int defaultPort
/*
* Multiple destinations can be specified on one single line, separated by comma
*/
String[] destinationStrings = (destinations == null ? "" : destinations.trim()).split("\\s*,\\s*");

String[] destinationStrings = (destinations == null ? "" : destinations.replace(" ", "")).split(",");
List<InetSocketAddress> destinationList = new ArrayList<>(destinationStrings.length);

for (String entry: destinationStrings) {
Expand All @@ -70,7 +78,10 @@ public static List<InetSocketAddress> parse(String destinations, int defaultPort
throw new IllegalArgumentException("Invalid destination '" + entry + "': unparseable value (expected format 'host[:port]').");
}

Matcher matcher = DESTINATION_PATTERN.matcher(entry);
Matcher matcher = DESTINATION_IPV6_PATTERN.matcher(entry);
if (!matcher.matches()) {
matcher = DESTINATION_PATTERN.matcher(entry);
}
if (!matcher.matches()) {
throw new IllegalArgumentException("Invalid destination '" + entry + "': unparseable value (expected format 'host[:port]').");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,13 @@ public void testParse_Single_NegativePort() {
DestinationParser.parse("localhost:-1", 1);
});
}

@Test
public void testParse_Single_MissingPortAfterColon() {
assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> {
DestinationParser.parse(" localhost: ", 1);
});
}

@Test
public void testParse_Single_UndefinedProperty() {
Expand Down Expand Up @@ -105,4 +112,40 @@ public void testParse_Multiple_Empty() {
DestinationParser.parse("localhost:1000, , localhost:1001", 1);
});
}

@Test
public void testIPv4_WithPort() {
List<InetSocketAddress> destinations = DestinationParser.parse(" 192.168.1.1:8080 ", 1);

assertThat(destinations).containsExactly(
InetSocketAddress.createUnresolved("192.168.1.1", 8080)
);
}

@Test
public void testIPv4_DefaultPort() {
List<InetSocketAddress> destinations = DestinationParser.parse(" 192.168.1.1 ", 1);

assertThat(destinations).containsExactly(
InetSocketAddress.createUnresolved("192.168.1.1", 1)
);
}

@Test
public void testIPv6_WithPort() {
List<InetSocketAddress> destinations = DestinationParser.parse(" [2001:db8::1]:8080 ", 1);

assertThat(destinations).containsExactly(
InetSocketAddress.createUnresolved("2001:db8::1", 8080)
);
}

@Test
public void testIPv6_DefaultPort() {
List<InetSocketAddress> destinations = DestinationParser.parse(" [2001:db8::1] ", 1);

assertThat(destinations).containsExactly(
InetSocketAddress.createUnresolved("2001:db8::1", 1)
);
}
}