diff --git a/test/test.ml b/test/test.ml index 0377c075..d26cb7ee 100644 --- a/test/test.ml +++ b/test/test.ml @@ -741,6 +741,22 @@ let test_late_bootstrap ~net = so we wait too, to ensure it's done. *) Fiber.yield () +let test_listen_address () = + let location = Alcotest.of_pp Capnp_rpc_unix.Network.Location.pp in + let result = Alcotest.result location Alcotest.string in + let test expected s = + let x = Capnp_rpc_unix.Network.Location.of_string s |> Result.map_error (fun (`Msg m) -> m) in + Alcotest.check result s expected x + in + test (Ok (`TCP ("127.0.0.1", 7000))) "tcp:127.0.0.1:7000"; + test (Ok (`TCP ("::1", 7000))) "tcp:[::1]:7000"; + test (Ok (`TCP ("example.org", 7000))) "tcp:example.org:7000"; + test (Ok (`Unix "/run/socket")) "unix:/run/socket"; + test (Error {|Missing port in IPv6 address "[::1]"|}) "tcp:[::1]"; + test (Error {|Invalid port ":1:7000" in listen address "::1:7000"|}) "tcp:::1:7000"; + test (Error {|Missing :PORT in listen address "127.0.0.1"|}) "tcp:127.0.0.1"; + test (Error {|Only tcp:HOST:PORT and unix:PATH addresses are currently supported|}) "http://localhost" + let run name fn = Alcotest.test_case name `Quick fn let rpc_tests ~net ~dir = @@ -775,6 +791,7 @@ let rpc_tests ~net ~dir = run_eio "File store" (test_file_store ~dir); run_eio "Await settled" test_await_settled; run_eio "Late bootstrap" test_late_bootstrap; + run "Listen address" test_listen_address; ] let () = diff --git a/unix/network.ml b/unix/network.ml index 777c6ce1..b148998f 100644 --- a/unix/network.ml +++ b/unix/network.ml @@ -4,8 +4,6 @@ module Log = Capnp_rpc.Debug.Log module Tls_wrapper = Capnp_rpc_net.Tls_wrapper module Location = struct - open Astring - include Capnp_rpc_net.Capnp_address.Location let abs_path p = @@ -21,16 +19,25 @@ module Location = struct let tcp ~host ~port = `TCP (host, port) let parse_tcp s = - match String.cut ~sep:":" s with - | None -> Error (`Msg "Missing :PORT in listen address") - | Some (host, port) -> - match String.to_int port with - | None -> Error (`Msg "PORT must be an integer") - | Some port -> + if String.starts_with ~prefix:"[" s then ( + match Ipaddr.with_port_of_string ~default:(-1) s with + | Ok (_, -1) -> Fmt.error_msg "Missing port in IPv6 address %S" s + | Ok (host, port) -> + let host = Ipaddr.to_string host in Ok (tcp ~host ~port) + | Error (`Msg m) -> Fmt.error_msg "Invalid IPv6 address %S: %s" s m + ) else ( + match Astring.String.cut ~sep:":" s with + | None -> Fmt.error_msg "Missing :PORT in listen address %S" s + | Some (host, port) -> + match int_of_string_opt port with + | None -> Fmt.error_msg "Invalid port %S in listen address %S" port s + | Some port -> + Ok (tcp ~host ~port) + ) let of_string s = - match String.cut ~sep:":" s with + match Astring.String.cut ~sep:":" s with | Some ("unix", path) -> Ok (unix path) | Some ("tcp", tcp) -> parse_tcp tcp | None -> Error (`Msg "Missing ':'")