diff --git a/dotnet/Trinsic.Tests/Tests.cs b/dotnet/Trinsic.Tests/Tests.cs index 324923d82..5efe9d786 100644 --- a/dotnet/Trinsic.Tests/Tests.cs +++ b/dotnet/Trinsic.Tests/Tests.cs @@ -30,17 +30,21 @@ public Tests(ITestOutputHelper testOutputHelper) private string VaccinationCertificateFrame => Path.GetFullPath(Path.Join(TestDataPath, "vaccination-certificate-frame.jsonld")); - [Fact] - public void TestParseURL() + [Theory] + [InlineData("localhost", false)] + [InlineData("localhost:5000", false)] + [InlineData("http://localhost", false)] + [InlineData("http://20.75.134.127", false)] + [InlineData("https://localhost:5000", true)] + [InlineData("http://localhost:5000", true)] + [InlineData("http://localhost:80", true)] + [InlineData("http://20.75.134.127:80", true)] + public void TestParseURL(string url, bool isValid) { - Assert.Throws(() => ServiceBase.CreateChannelIfNeeded("localhost")); - Assert.Throws(() => ServiceBase.CreateChannelIfNeeded("localhost:5000")); - // Assert.Throws(() => ServiceBase.CreateChannelIfNeeded("http://localhost")); - // Throws because HTTPS is not yet supported. - // Assert.Throws(() => ServiceBase.CreateChannelIfNeeded("https://localhost:5000")); - - Assert.NotNull(ServiceBase.CreateChannelIfNeeded("http://localhost:5000")); - + if (!isValid) + Assert.Throws(() => ServiceBase.CreateChannelIfNeeded(url)); + else + Assert.NotNull(ServiceBase.CreateChannelIfNeeded(url)); } [Fact] diff --git a/dotnet/Trinsic/ServiceBase.cs b/dotnet/Trinsic/ServiceBase.cs index f17cd9e71..a37305857 100644 --- a/dotnet/Trinsic/ServiceBase.cs +++ b/dotnet/Trinsic/ServiceBase.cs @@ -64,10 +64,25 @@ public void SetProfile(WalletProfile profile) public static GrpcChannel CreateChannelIfNeeded(string serviceAddress) { - var url = new Uri(serviceAddress); - //if (url.IsDefaultPort) throw new ArgumentException("GRPC Port and scheme required"); - if ("https".Equals(url.Scheme)) throw new ArgumentException("HTTPS not yet supported"); - return GrpcChannel.ForAddress(serviceAddress, new GrpcChannelOptions()); + try + { + var url = new Uri(serviceAddress); + AssertPortIsProvided(serviceAddress, url); + return GrpcChannel.ForAddress(serviceAddress, new GrpcChannelOptions()); + } + catch (UriFormatException ufe) + { + throw new ArgumentException("Invalid service address", ufe); + } + } + + private static void AssertPortIsProvided(string serviceAddress, Uri url) + { + // If port not provided, it will mismatch as a string + var rebuiltUri = new UriBuilder(url.Scheme, url.Host, url.Port, url.AbsolutePath); + // Remove trailing '/' + if (!serviceAddress.TrimEnd('/').StartsWith(rebuiltUri.ToString().TrimEnd('/'))) + throw new ArgumentException("GRPC Port and scheme required"); } } } diff --git a/go/services/services_test.go b/go/services/services_test.go index 601276562..b47cdeb6e 100644 --- a/go/services/services_test.go +++ b/go/services/services_test.go @@ -60,13 +60,15 @@ func TestServiceBase_SetProfile(t *testing.T) { } func TestCreateChannelIfNeeded(t *testing.T) { - var validHttpAddress = "http://localhost:5000" - var validHttpsAddress = "https://localhost:5000" // Currently, fails due to lack of HTTPS support. - var missingPortAddress = "http://localhost" - var missingProtocolAddress = "localhost:5000" - var blankAddress = "" - testAddresses := []string{validHttpAddress, validHttpsAddress, missingPortAddress, missingProtocolAddress, blankAddress} - throwsException := []bool{false, true, true, true, true} + const validHttpAddress = "http://localhost:5000" + const validHttpsAddress = "https://localhost:5000" // Currently, fails due to lack of HTTPS support. + const validIpAddress = "http://20.75.134.127:80" + const missingPortIpAddress = "http://20.75.134.127" + const missingPortAddress = "http://localhost" + const missingProtocolAddress = "localhost:5000" + const blankAddress = "" + testAddresses := []string{validHttpAddress, validHttpsAddress, validIpAddress, missingPortIpAddress, missingPortAddress, missingProtocolAddress, blankAddress} + throwsException := []bool{false, true, false, true, true, true, true} for ij := 0; ij < len(testAddresses); ij++ { channel, err := CreateChannelIfNeeded(testAddresses[ij], nil, false) diff --git a/python/tests/test_trinsic_services.py b/python/tests/test_trinsic_services.py index 50419cf41..b9cd364f2 100644 --- a/python/tests/test_trinsic_services.py +++ b/python/tests/test_trinsic_services.py @@ -43,16 +43,19 @@ async def test_providerservice_inviteparticipant(self): def test_url_parse(self): valid_http_address = "http://localhost:5000" valid_https_address = "https://localhost:5000" + valid_ip_address = "http://20.75.134.127:80" + missing_port_ip_address = "http://20.75.134.127" missing_port_address = "http://localhost" missing_protocol_address = "localhost:5000" blank_address = "" - addresses = [valid_http_address, valid_https_address, missing_port_address, missing_protocol_address, + addresses = [valid_http_address, valid_https_address, valid_ip_address, missing_port_ip_address, + missing_port_address, missing_protocol_address, blank_address] - throws_exception = [False, False, True, True, True] + throws_exception = [False, False, False, True, True, True, True] for ij in range(len(addresses)): try: - channel = create_channel_if_needed(None, addresses[ij]) + create_channel_if_needed(service_address=addresses[ij]) if throws_exception[ij]: self.fail(f"URL={addresses[ij]} should throw") except: diff --git a/python/trinsic/services.py b/python/trinsic/services.py index 1dc8c33af..aca83fa6e 100644 --- a/python/trinsic/services.py +++ b/python/trinsic/services.py @@ -18,7 +18,7 @@ from trinsic.proto.services.verifiablecredentials.v1 import CredentialStub -def create_channel_if_needed(channel: Channel, service_address: str) -> Channel: +def create_channel_if_needed(channel: Channel = None, service_address: str = '') -> Channel: if not channel: service_url = urllib.parse.urlsplit(service_address) is_https = service_url.scheme == "https"