From 74acd58c1e6a6057af483a10c1653bd8d11c08cf Mon Sep 17 00:00:00 2001 From: shaan1337 Date: Mon, 6 Jul 2020 16:35:55 +0400 Subject: [PATCH] Make the forward slash optional --- ...entStoreClientSettings.ConnectionString.cs | 24 +++++-- .../ConnectionStringTests.cs | 63 +++++++++++++++---- 2 files changed, 69 insertions(+), 18 deletions(-) diff --git a/src/EventStore.Client/EventStoreClientSettings.ConnectionString.cs b/src/EventStore.Client/EventStoreClientSettings.ConnectionString.cs index 0502e9bd9..d9f363db6 100644 --- a/src/EventStore.Client/EventStoreClientSettings.ConnectionString.cs +++ b/src/EventStore.Client/EventStoreClientSettings.ConnectionString.cs @@ -55,16 +55,28 @@ public static EventStoreClientSettings Parse(string connectionString) { currentIndex = userInfoIndex + UserInfoSeparator.Length; } + var slashIndex = connectionString.IndexOf(Slash, currentIndex, StringComparison.Ordinal); - if (slashIndex == -1) - throw new ConnectionStringParseException("The connection string must contain a / (forward slash) after specifying the hosts"); + var questionMarkIndex = connectionString.IndexOf(QuestionMark, Math.Max(currentIndex, slashIndex), StringComparison.Ordinal); + var endIndex = connectionString.Length; + + //for simpler substring operations: + if (slashIndex == -1) slashIndex = int.MaxValue; + if (questionMarkIndex == -1) questionMarkIndex = int.MaxValue; + + var hostSeparatorIndex = Math.Min(Math.Min(slashIndex, questionMarkIndex), endIndex); + var hosts = ParseHosts(connectionString.Substring(currentIndex,hostSeparatorIndex - currentIndex)); + currentIndex = hostSeparatorIndex; + + string path = ""; + if (slashIndex != int.MaxValue) + path = connectionString.Substring(currentIndex,Math.Min(questionMarkIndex, endIndex) - currentIndex); - var hosts = ParseHosts(connectionString.Substring(currentIndex, slashIndex - currentIndex)); - currentIndex = slashIndex + Slash.Length; + if (path != "" && path != "/") + throw new ConnectionStringParseException($"The specified path must be either an empty string or a forward slash (/) but instead found: {path}"); - var questionMarkIndex = connectionString.IndexOf(QuestionMark, currentIndex); var options = new Dictionary(); - if (questionMarkIndex != -1) { + if (questionMarkIndex != int.MaxValue) { currentIndex = questionMarkIndex + QuestionMark.Length; options = ParseKeyValuePairs(connectionString.Substring(currentIndex)); } diff --git a/test/EventStore.Client.Tests/ConnectionStringTests.cs b/test/EventStore.Client.Tests/ConnectionStringTests.cs index 27618f399..29a33ca4b 100644 --- a/test/EventStore.Client.Tests/ConnectionStringTests.cs +++ b/test/EventStore.Client.Tests/ConnectionStringTests.cs @@ -42,39 +42,78 @@ public void connection_string_with_invalid_userinfo_should_throw() { } [Fact] - public void connection_string_without_forward_slash_after_host_should_throw() { - Assert.Throws(() => { - EventStoreClientSettings.Create("esdb://user:pass@127.0.0.1"); + public void connection_string_with_invalid_host_should_throw() { + Assert.Throws(() => { + EventStoreClientSettings.Create("esdb://user:pass@127.0.0.1:abc"); }); - Assert.Throws(() => { - EventStoreClientSettings.Create("esdb://user:pass@127.0.0.1:1234"); + Assert.Throws(() => { + EventStoreClientSettings.Create("esdb://user:pass@127.0.0.1:abc/"); }); - } - [Fact] - public void connection_string_with_invalid_host_should_throw() { Assert.Throws(() => { - EventStoreClientSettings.Create("esdb://user:pass@127.0.0.1:abc/"); + EventStoreClientSettings.Create("esdb://user:pass@127.0.0.1:1234,127.0.0.2:abc,127.0.0.3:4321"); }); Assert.Throws(() => { EventStoreClientSettings.Create("esdb://user:pass@127.0.0.1:1234,127.0.0.2:abc,127.0.0.3:4321/"); }); + Assert.Throws(() => { + EventStoreClientSettings.Create("esdb://user:pass@127.0.0.1:abc:def"); + }); + Assert.Throws(() => { EventStoreClientSettings.Create("esdb://user:pass@127.0.0.1:abc:def/"); }); + Assert.Throws(() => { + EventStoreClientSettings.Create("esdb://user:pass@localhost:1234,127.0.0.2:abc:def,127.0.0.3:4321"); + }); + Assert.Throws(() => { EventStoreClientSettings.Create("esdb://user:pass@localhost:1234,127.0.0.2:abc:def,127.0.0.3:4321/"); }); + Assert.Throws(() => { + EventStoreClientSettings.Create("esdb://user:pass@localhost:1234,,127.0.0.3:4321"); + }); + Assert.Throws(() => { EventStoreClientSettings.Create("esdb://user:pass@localhost:1234,,127.0.0.3:4321/"); }); } + [Fact] + public void connection_string_with_empty_path_after_host_should_not_throw() { + EventStoreClientSettings.Create("esdb://user:pass@127.0.0.1"); + EventStoreClientSettings.Create("esdb://user:pass@127.0.0.1:1234"); + EventStoreClientSettings.Create("esdb://user:pass@127.0.0.1/"); + EventStoreClientSettings.Create("esdb://user:pass@127.0.0.1?maxDiscoverAttempts=10"); + EventStoreClientSettings.Create("esdb://user:pass@127.0.0.1/?maxDiscoverAttempts=10"); + } + + [Fact] + public void connection_string_with_non_empty_path_should_throw() { + Assert.Throws(() => { + EventStoreClientSettings.Create("esdb://user:pass@127.0.0.1/test"); + }); + + Assert.Throws(() => { + EventStoreClientSettings.Create("esdb://user:pass@127.0.0.1/maxDiscoverAttempts=10"); + }); + + Assert.Throws(() => { + EventStoreClientSettings.Create("esdb://user:pass@127.0.0.1/hello?maxDiscoverAttempts=10"); + }); + } + + [Fact] + public void connection_string_with_no_key_value_pairs_specified_should_not_throw() { + EventStoreClientSettings.Create("esdb://user:pass@127.0.0.1"); + EventStoreClientSettings.Create("esdb://user:pass@127.0.0.1/"); + } + [Fact] public void connection_string_with_invalid_key_value_pair_should_throw() { Assert.Throws(() => { @@ -157,7 +196,7 @@ public void with_valid_single_node_connection_string() { Assert.Equal(NodePreference.Follower, settings.ConnectivitySettings.NodePreference); Assert.NotNull(settings.CreateHttpMessageHandler); - settings = EventStoreClientSettings.Create("esdb://127.0.0.1/?connectionName=test&maxDiscoverAttempts=13&DiscoveryInterval=37&nOdEPrEfErence=FoLLoWer&tls=true&tlsVerifyCert=true&operationTimeout=330&throwOnAppendFailure=faLse"); + settings = EventStoreClientSettings.Create("esdb://127.0.0.1?connectionName=test&maxDiscoverAttempts=13&DiscoveryInterval=37&nOdEPrEfErence=FoLLoWer&tls=true&tlsVerifyCert=true&operationTimeout=330&throwOnAppendFailure=faLse"); Assert.Null(settings.DefaultCredentials); Assert.Equal("test", settings.ConnectionName); Assert.Equal("https://127.0.0.1:2113/",settings.ConnectivitySettings.Address.ToString()); @@ -252,7 +291,7 @@ public void with_different_tls_settings() { settings = EventStoreClientSettings.Create("esdb://127.0.0.1/"); Assert.Equal(Uri.UriSchemeHttps, settings.ConnectivitySettings.Address.Scheme); - settings = EventStoreClientSettings.Create("esdb://127.0.0.1/?tls=true"); + settings = EventStoreClientSettings.Create("esdb://127.0.0.1?tls=true"); Assert.Equal(Uri.UriSchemeHttps, settings.ConnectivitySettings.Address.Scheme); settings = EventStoreClientSettings.Create("esdb://127.0.0.1/?tls=FaLsE"); @@ -261,7 +300,7 @@ public void with_different_tls_settings() { settings = EventStoreClientSettings.Create("esdb://127.0.0.1,127.0.0.2:3321,127.0.0.3/"); Assert.True(settings.ConnectivitySettings.GossipOverHttps); - settings = EventStoreClientSettings.Create("esdb://127.0.0.1,127.0.0.2:3321,127.0.0.3/?tls=true"); + settings = EventStoreClientSettings.Create("esdb://127.0.0.1,127.0.0.2:3321,127.0.0.3?tls=true"); Assert.True(settings.ConnectivitySettings.GossipOverHttps); settings = EventStoreClientSettings.Create("esdb://127.0.0.1,127.0.0.2:3321,127.0.0.3/?tls=fAlSe");