Skip to content

Commit 695de5f

Browse files
committed
Throw early when Config Server URL(s) is/are invalid
1 parent 33882da commit 695de5f

7 files changed

+67
-42
lines changed

src/Configuration/src/ConfigServer/ConfigServerClientOptions.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,18 @@ public bool ValidateCertificatesAlt
143143
/// </summary>
144144
public IDictionary<string, string> Headers { get; } = new Dictionary<string, string>();
145145

146-
internal IList<string> GetUris()
146+
internal List<Uri> GetUris()
147147
{
148-
return !string.IsNullOrEmpty(Uri) ? Uri.Split(CommaDelimiter, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) : [];
148+
return Uri == null ? [] : Uri.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries).Select(ParseSingleUri).ToList();
149+
}
150+
151+
private static Uri ParseSingleUri(string uri)
152+
{
153+
if (!System.Uri.TryCreate(uri, UriKind.Absolute, out Uri? result))
154+
{
155+
throw new ConfigServerException("One or more Config Server URIs in configuration are invalid.");
156+
}
157+
158+
return result;
149159
}
150160
}

src/Configuration/src/ConfigServer/ConfigServerConfigurationProvider.cs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -223,24 +223,22 @@ public override void Load()
223223
// Adds client settings (e.g. spring:cloud:config:uri, etc.) to the Data dictionary
224224
AddConfigServerClientOptions();
225225

226-
string logUri = string.Join(',', ClientOptions.GetUris().Select(uri => new Uri(uri).ToMaskedString()));
227-
228226
if (ClientOptions is { Retry.Enabled: true, FailFast: true })
229227
{
230228
int attempts = 0;
231229
int backOff = ClientOptions.Retry.InitialInterval;
232230

233231
do
234232
{
235-
_logger.LogDebug("Fetching configuration from server at: {Uri}", logUri);
233+
_logger.LogDebug("Fetching configuration from server(s).");
236234

237235
try
238236
{
239237
return await DoLoadAsync(updateDictionary, cancellationToken);
240238
}
241239
catch (ConfigServerException exception)
242240
{
243-
_logger.LogWarning(exception, "Failed fetching configuration from server at: {Uri}.", logUri);
241+
_logger.LogWarning(exception, "Failed fetching configuration from server(s).");
244242
attempts++;
245243

246244
if (attempts < ClientOptions.Retry.MaxAttempts)
@@ -258,16 +256,16 @@ public override void Load()
258256
while (true);
259257
}
260258

261-
_logger.LogDebug("Fetching configuration from server at: {Uri}", logUri);
259+
_logger.LogDebug("Fetching configuration from server(s).");
262260
return await DoLoadAsync(updateDictionary, cancellationToken);
263261
}
264262

265263
internal async Task<ConfigEnvironment?> DoLoadAsync(bool updateDictionary, CancellationToken cancellationToken)
266264
{
267265
Exception? error = null;
268266

269-
// Get arrays of Config Server uris to check
270-
IList<string> uris = ClientOptions.GetUris();
267+
// Get list of Config Server uris to check
268+
List<Uri> uris = ClientOptions.GetUris();
271269

272270
try
273271
{
@@ -543,7 +541,7 @@ private void AddConfigServerClientOptions(Dictionary<string, string?> data)
543541
}
544542
}
545543

546-
internal async Task<ConfigEnvironment?> RemoteLoadAsync(IEnumerable<string> requestUris, string? label, CancellationToken cancellationToken)
544+
internal async Task<ConfigEnvironment?> RemoteLoadAsync(List<Uri> requestUris, string? label, CancellationToken cancellationToken)
547545
{
548546
_logger.LogTrace("Entered {Method}", nameof(RemoteLoadAsync));
549547

@@ -552,11 +550,13 @@ private void AddConfigServerClientOptions(Dictionary<string, string?> data)
552550

553551
Exception? error = null;
554552

555-
foreach (string requestUri in requestUris)
553+
foreach (Uri requestUri in requestUris)
556554
{
557555
// Make Config Server URI from settings
558556
Uri uri = BuildConfigServerUri(requestUri, label);
559557

558+
_logger.LogDebug("Trying to connect to Config Server at {RequestUri}", uri.ToMaskedString());
559+
560560
// Get the request message
561561
_logger.LogTrace("Building HTTP request message");
562562
HttpRequestMessage request = await GetRequestMessageAsync(uri, cancellationToken);
@@ -622,11 +622,11 @@ private void AddConfigServerClientOptions(Dictionary<string, string?> data)
622622
/// <returns>
623623
/// The request URI for the Configuration Server.
624624
/// </returns>
625-
internal Uri BuildConfigServerUri(string serverUri, string? label)
625+
internal Uri BuildConfigServerUri(Uri serverUri, string? label)
626626
{
627-
ArgumentException.ThrowIfNullOrWhiteSpace(serverUri);
627+
ArgumentNullException.ThrowIfNull(serverUri);
628628

629-
var uriBuilder = new UriBuilder(new Uri(serverUri));
629+
var uriBuilder = new UriBuilder(serverUri);
630630

631631
if (!string.IsNullOrEmpty(ClientOptions.Username))
632632
{

src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationBuilderExtensionsCoreTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public void AddConfigServer_WithLoggerFactorySucceeds()
4444
IList<string> logMessages = loggerProvider.GetAll();
4545

4646
logMessages.Should().Contain(
47-
"DBUG Steeltoe.Configuration.ConfigServer.ConfigServerConfigurationProvider: Fetching configuration from server at: http://localhost:8888/");
47+
"DBUG Steeltoe.Configuration.ConfigServer.ConfigServerConfigurationProvider: Fetching configuration from server(s).");
4848
}
4949

5050
[Fact]

src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationBuilderExtensionsTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ public void AddConfigServer_WithLoggerFactorySucceeds()
185185
IList<string> logMessages = loggerProvider.GetAll();
186186

187187
logMessages.Should().Contain(
188-
"DBUG Steeltoe.Configuration.ConfigServer.ConfigServerConfigurationProvider: Fetching configuration from server at: http://localhost:8888/");
188+
"DBUG Steeltoe.Configuration.ConfigServer.ConfigServerConfigurationProvider: Fetching configuration from server(s).");
189189
}
190190

191191
[Theory]

src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationProviderTest.Loading.cs

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,6 @@ namespace Steeltoe.Configuration.ConfigServer.Test;
1313

1414
public sealed partial class ConfigServerConfigurationProviderTest
1515
{
16-
[Fact]
17-
public async Task RemoteLoadAsync_InvalidUri()
18-
{
19-
var options = new ConfigServerClientOptions();
20-
using var provider = new ConfigServerConfigurationProvider(options, null, null, NullLoggerFactory.Instance);
21-
22-
// ReSharper disable once AccessToDisposedClosure
23-
Func<Task> action = async () => await provider.RemoteLoadAsync([@"foobar\foobar\"], null, TestContext.Current.CancellationToken);
24-
25-
await action.Should().ThrowExactlyAsync<UriFormatException>();
26-
}
27-
2816
[Fact]
2917
public async Task RemoteLoadAsync_HostTimesOut()
3018
{
@@ -35,9 +23,10 @@ public async Task RemoteLoadAsync_HostTimesOut()
3523

3624
var httpClientHandler = new SlowHttpClientHandler(1.Seconds(), new HttpResponseMessage());
3725
using var provider = new ConfigServerConfigurationProvider(options, null, httpClientHandler, NullLoggerFactory.Instance);
26+
List<Uri> requestUris = [new("http://localhost:9999/app/profile")];
3827

3928
// ReSharper disable once AccessToDisposedClosure
40-
Func<Task> action = async () => await provider.RemoteLoadAsync(["http://localhost:9999/app/profile"], null, TestContext.Current.CancellationToken);
29+
Func<Task> action = async () => await provider.RemoteLoadAsync(requestUris, null, TestContext.Current.CancellationToken);
4130

4231
(await action.Should().ThrowExactlyAsync<TaskCanceledException>()).WithInnerExceptionExactly<TimeoutException>();
4332
}
@@ -506,6 +495,32 @@ public async Task Load_MultipleConfigServers_ReturnsNotFoundStatus__DoesNotConti
506495
startup.RequestCount.Should().Be(1);
507496
}
508497

498+
[Fact]
499+
public async Task Load_UriInvalid_FailFastEnabled()
500+
{
501+
using var startup = new TestConfigServerStartup();
502+
startup.ReturnStatus = [500];
503+
504+
await using WebApplication app = TestWebApplicationBuilderFactory.Create().Build();
505+
startup.Configure(app);
506+
await app.StartAsync(TestContext.Current.CancellationToken);
507+
508+
using TestServer server = app.GetTestServer();
509+
server.BaseAddress = new Uri("http://localhost:8888");
510+
511+
ConfigServerClientOptions options = GetCommonOptions();
512+
options.Uri = "http://username:p@ssword@localhost:8888";
513+
options.FailFast = true;
514+
515+
using var httpClientHandler = new ForwardingHttpClientHandler(server.CreateHandler());
516+
using var provider = new ConfigServerConfigurationProvider(options, null, httpClientHandler, NullLoggerFactory.Instance);
517+
518+
// ReSharper disable once AccessToDisposedClosure
519+
Func<Task> action = async () => await provider.LoadInternalAsync(true, TestContext.Current.CancellationToken);
520+
521+
await action.Should().ThrowExactlyAsync<ConfigServerException>().WithMessage("One or more Config Server URIs in configuration are invalid.");
522+
}
523+
509524
[Fact]
510525
public async Task Load_ConfigServerReturnsBadStatus_FailFastEnabled()
511526
{

src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationProviderTest.Settings.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public void GetConfigServerUri_NoLabel()
7979
};
8080

8181
using var provider = new ConfigServerConfigurationProvider(options, null, null, NullLoggerFactory.Instance);
82-
string uri = provider.BuildConfigServerUri(options.Uri!, null).ToString();
82+
string uri = provider.BuildConfigServerUri(new Uri(options.Uri!), null).ToString();
8383

8484
uri.Should().Be($"{options.Uri}/{options.Name}/{options.Environment}");
8585
}
@@ -95,7 +95,7 @@ public void GetConfigServerUri_WithLabel()
9595
};
9696

9797
using var provider = new ConfigServerConfigurationProvider(options, null, null, NullLoggerFactory.Instance);
98-
string uri = provider.BuildConfigServerUri(options.Uri!, options.Label).ToString();
98+
string uri = provider.BuildConfigServerUri(new Uri(options.Uri!), options.Label).ToString();
9999

100100
uri.Should().Be($"{options.Uri}/{options.Name}/{options.Environment}/{options.Label}");
101101
}
@@ -111,7 +111,7 @@ public void GetConfigServerUri_WithLabelContainingSlash()
111111
};
112112

113113
using var provider = new ConfigServerConfigurationProvider(options, null, null, NullLoggerFactory.Instance);
114-
string uri = provider.BuildConfigServerUri(options.Uri!, options.Label).ToString();
114+
string uri = provider.BuildConfigServerUri(new Uri(options.Uri!), options.Label).ToString();
115115

116116
uri.Should().Be($"{options.Uri}/{options.Name}/{options.Environment}/myLabel(_)version");
117117
}
@@ -127,7 +127,7 @@ public void GetConfigServerUri_WithExtraPathInfo()
127127
};
128128

129129
using var provider = new ConfigServerConfigurationProvider(options, null, null, NullLoggerFactory.Instance);
130-
string uri = provider.BuildConfigServerUri(options.Uri, null).ToString();
130+
string uri = provider.BuildConfigServerUri(new Uri(options.Uri), null).ToString();
131131

132132
uri.Should().Be($"http://localhost:9999/myPath/path/{options.Name}/{options.Environment}");
133133
}
@@ -143,7 +143,7 @@ public void GetConfigServerUri_WithExtraPathInfo_NoEndingSlash()
143143
};
144144

145145
using var provider = new ConfigServerConfigurationProvider(options, null, null, NullLoggerFactory.Instance);
146-
string uri = provider.BuildConfigServerUri(options.Uri, null).ToString();
146+
string uri = provider.BuildConfigServerUri(new Uri(options.Uri), null).ToString();
147147

148148
uri.Should().Be($"http://localhost:9999/myPath/path/{options.Name}/{options.Environment}");
149149
}
@@ -159,7 +159,7 @@ public void GetConfigServerUri_NoEndingSlash()
159159
};
160160

161161
using var provider = new ConfigServerConfigurationProvider(options, null, null, NullLoggerFactory.Instance);
162-
string uri = provider.BuildConfigServerUri(options.Uri, null).ToString();
162+
string uri = provider.BuildConfigServerUri(new Uri(options.Uri), null).ToString();
163163

164164
uri.Should().Be($"http://localhost:9999/{options.Name}/{options.Environment}");
165165
}
@@ -175,7 +175,7 @@ public void GetConfigServerUri_WithEndingSlash()
175175
};
176176

177177
using var provider = new ConfigServerConfigurationProvider(options, null, null, NullLoggerFactory.Instance);
178-
string uri = provider.BuildConfigServerUri(options.Uri, null).ToString();
178+
string uri = provider.BuildConfigServerUri(new Uri(options.Uri), null).ToString();
179179

180180
uri.Should().Be($"http://localhost:9999/{options.Name}/{options.Environment}");
181181
}
@@ -191,7 +191,7 @@ public void GetConfigServerUri_MultipleEnvironments_EncodesComma()
191191
};
192192

193193
using var provider = new ConfigServerConfigurationProvider(options, null, null, NullLoggerFactory.Instance);
194-
string uri = provider.BuildConfigServerUri(options.Uri!, options.Label).ToString();
194+
string uri = provider.BuildConfigServerUri(new Uri(options.Uri!), options.Label).ToString();
195195

196196
uri.Should().Be("http://localhost:8888/myName/one%2Ctwo/demo");
197197
}
@@ -209,7 +209,7 @@ public void GetConfigServerUri_EncodesSpecialCharacters()
209209
};
210210

211211
using var provider = new ConfigServerConfigurationProvider(options, null, null, NullLoggerFactory.Instance);
212-
string uri = provider.BuildConfigServerUri(options.Uri!, options.Label).ToString();
212+
string uri = provider.BuildConfigServerUri(new Uri(options.Uri!), options.Label).ToString();
213213

214214
uri.Should().Be(
215215
"http://a%22%3A%3F%27*%2Cb%2F%5C%26:%23%26%3A%24%3C%3E%27%2Fso%2C%22me@localhost:8888/my%24<>%3A%2C\"%27Name/%40%2F%26%3F%3A\"%27/^%26%24%40%23*<>%2B");

src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationProviderTest.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ public async Task GetRequestMessage_AddsBasicAuthIfUserNameAndPasswordInURL()
145145

146146
using var provider = new ConfigServerConfigurationProvider(options, null, null, NullLoggerFactory.Instance);
147147

148-
Uri requestUri = provider.BuildConfigServerUri(options.Uri, null);
148+
Uri requestUri = provider.BuildConfigServerUri(new Uri(options.Uri), null);
149149
HttpRequestMessage request = await provider.GetRequestMessageAsync(requestUri, TestContext.Current.CancellationToken);
150150

151151
request.Method.Should().Be(HttpMethod.Get);
@@ -169,7 +169,7 @@ public async Task GetRequestMessage_AddsBasicAuthIfUserNameAndPasswordInSettings
169169

170170
using var provider = new ConfigServerConfigurationProvider(options, null, null, NullLoggerFactory.Instance);
171171

172-
Uri requestUri = provider.BuildConfigServerUri(options.Uri, null);
172+
Uri requestUri = provider.BuildConfigServerUri(new Uri(options.Uri), null);
173173
HttpRequestMessage request = await provider.GetRequestMessageAsync(requestUri, TestContext.Current.CancellationToken);
174174

175175
request.Method.Should().Be(HttpMethod.Get);
@@ -193,7 +193,7 @@ public async Task GetRequestMessage_BasicAuthInSettingsOverridesUserNameAndPassw
193193

194194
using var provider = new ConfigServerConfigurationProvider(options, null, null, NullLoggerFactory.Instance);
195195

196-
Uri requestUri = provider.BuildConfigServerUri(options.Uri, null);
196+
Uri requestUri = provider.BuildConfigServerUri(new Uri(options.Uri), null);
197197
HttpRequestMessage request = await provider.GetRequestMessageAsync(requestUri, TestContext.Current.CancellationToken);
198198

199199
request.Method.Should().Be(HttpMethod.Get);
@@ -215,7 +215,7 @@ public async Task GetRequestMessage_AddsVaultToken_IfNeeded()
215215

216216
using var provider = new ConfigServerConfigurationProvider(options, null, null, NullLoggerFactory.Instance);
217217

218-
Uri requestUri = provider.BuildConfigServerUri(options.Uri!, null);
218+
Uri requestUri = provider.BuildConfigServerUri(new Uri(options.Uri!), null);
219219
HttpRequestMessage request = await provider.GetRequestMessageAsync(requestUri, TestContext.Current.CancellationToken);
220220

221221
request.Method.Should().Be(HttpMethod.Get);

0 commit comments

Comments
 (0)