Copilot commented on code in PR #1509:
URL: https://github.com/apache/ratis/pull/1509#discussion_r3539964917


##########
ratis-shell/src/main/java/org/apache/ratis/shell/cli/CliUtils.java:
##########
@@ -164,11 +165,7 @@ public static void checkReply(RaftClientReply reply, 
Supplier<String> message, P
   /** Parse the given string as a {@link InetSocketAddress}. */
   public static InetSocketAddress parseInetSocketAddress(String address) {
     try {
-      final String[] hostPortPair = address.split(":");
-      if (hostPortPair.length < 2) {
-        throw new IllegalArgumentException("Unexpected address format 
<HOST:PORT>.");
-      }
-      return new InetSocketAddress(hostPortPair[0], 
Integer.parseInt(hostPortPair[1]));
+      return NetUtils.createSocketAddr(address);
     } catch (Exception e) {
       throw new IllegalArgumentException("Failed to parse the server address 
parameter \"" + address + "\".", e);
     }

Review Comment:
   `parseInetSocketAddress` now delegates to `NetUtils.createSocketAddr`, which 
accepts URL-style inputs containing a scheme (e.g. `http://host:port`). Ratis 
shell options/messages describe addresses as `<HOST:PORT>`, so accepting 
schemes can silently mask invalid user input.
   
   Consider explicitly rejecting inputs containing `://` before parsing, while 
still using `NetUtils.createSocketAddr` for IPv6 bracket support.



##########
ratis-examples/src/main/java/org/apache/ratis/examples/common/SubCommandBase.java:
##########
@@ -41,26 +41,63 @@ public abstract class SubCommandBase {
   private String peers;
 
   public static RaftPeer[] parsePeers(String peers) {
-    return Stream.of(peers.split(",")).map(address -> {
-      String[] addressParts = address.split(":");
-      if (addressParts.length < 3) {
-        throw new IllegalArgumentException(
-            "Raft peer " + address + " is not a legitimate format. "
-                + "(format: 
name:host:port:dataStreamPort:clientPort:adminPort)");
+    return 
Stream.of(peers.split(",")).map(SubCommandBase::parsePeer).toArray(RaftPeer[]::new);
+  }
+
+  /**
+   * Parse a single peer definition in the format
+   * {@code name:host:port:dataStreamPort:clientPort:adminPort}, where the 
trailing
+   * ports are optional.  The host may be an IPv6 literal enclosed in brackets,
+   * e.g. {@code n0:[::1]:9000:9001:9002:9003}.
+   */
+  private static RaftPeer parsePeer(String address) {
+    final int idEnd = address.indexOf(':');
+    if (idEnd < 0) {
+      throw illegalFormat(address);
+    }
+    final String id = address.substring(0, idEnd);
+    final String hostAndPorts = address.substring(idEnd + 1);
+
+    // Separate the host from the port list, honoring IPv6 bracketed literals.
+    final String host;
+    final String portList;
+    if (hostAndPorts.startsWith("[")) {
+      final int bracketEnd = hostAndPorts.indexOf("]:");
+      if (bracketEnd < 0) {
+        throw illegalFormat(address);
       }
-      RaftPeer.Builder builder = RaftPeer.newBuilder();
-      builder.setId(addressParts[0]).setAddress(addressParts[1] + ":" + 
addressParts[2]);
-      if (addressParts.length >= 4) {
-        builder.setDataStreamAddress(addressParts[1] + ":" + addressParts[3]);
-        if (addressParts.length >= 5) {
-          builder.setClientAddress(addressParts[1] + ":" + addressParts[4]);
-          if (addressParts.length >= 6) {
-            builder.setAdminAddress(addressParts[1] + ":" + addressParts[5]);
-          }
-        }
+      host = hostAndPorts.substring(0, bracketEnd + 1); // include the closing 
']'
+      portList = hostAndPorts.substring(bracketEnd + 2);
+    } else {
+      final int hostEnd = hostAndPorts.indexOf(':');
+      if (hostEnd < 0) {
+        throw illegalFormat(address);
       }
-      return builder.build();
-    }).toArray(RaftPeer[]::new);
+      host = hostAndPorts.substring(0, hostEnd);
+      portList = hostAndPorts.substring(hostEnd + 1);
+    }
+
+    final String[] ports = portList.split(":");
+    if (ports[0].isEmpty()) {
+      throw illegalFormat(address);
+    }
+    final RaftPeer.Builder builder = RaftPeer.newBuilder();
+    builder.setId(id).setAddress(host + ":" + ports[0]);
+    if (ports.length >= 2) {
+      builder.setDataStreamAddress(host + ":" + ports[1]);
+    }
+    if (ports.length >= 3) {
+      builder.setClientAddress(host + ":" + ports[2]);
+    }
+    if (ports.length >= 4) {
+      builder.setAdminAddress(host + ":" + ports[3]);
+    }

Review Comment:
   `parsePeer` only checks that the first port is non-empty. If a user supplies 
an empty optional port (e.g. `n0:host:6000::6002` or `n0:[::1]:6000:`), the 
code will build invalid addresses like `host:` which will fail later and be 
harder to diagnose.
   
   Reject empty values for any provided port segment (up to the supported 4 
ports).



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to