diff --git a/src/NATS.Client.Core/Internal/NatsUri.cs b/src/NATS.Client.Core/Internal/NatsUri.cs index c3b033750..a988850dd 100644 --- a/src/NATS.Client.Core/Internal/NatsUri.cs +++ b/src/NATS.Client.Core/Internal/NatsUri.cs @@ -4,8 +4,6 @@ internal sealed record NatsUri { public const string DefaultScheme = "nats"; - private readonly string _redacted; - public NatsUri(string urlString, bool isSeed, string defaultScheme = DefaultScheme) { IsSeed = isSeed; @@ -40,6 +38,23 @@ public NatsUri(string urlString, bool isSeed, string defaultScheme = DefaultSche } Uri = uriBuilder.Uri; + } + + public Uri Uri { get; init; } + + public bool IsSeed { get; } + + public bool IsTls { get; } + + public bool IsWebSocket { get; } + + public string Host => Uri.Host; + + public int Port => Uri.Port; + + public override string ToString() + { + var uriBuilder = new UriBuilder(Uri); // Redact user/password or token from the URI string for logging if (uriBuilder.UserName is { Length: > 0 }) @@ -54,20 +69,6 @@ public NatsUri(string urlString, bool isSeed, string defaultScheme = DefaultSche } } - _redacted = IsWebSocket && Uri.AbsolutePath != "/" ? uriBuilder.Uri.ToString() : uriBuilder.Uri.ToString().Trim('/'); + return IsWebSocket && Uri.AbsolutePath != "/" ? uriBuilder.Uri.ToString() : uriBuilder.Uri.ToString().Trim('/'); } - - public Uri Uri { get; init; } - - public bool IsSeed { get; } - - public bool IsTls { get; } - - public bool IsWebSocket { get; } - - public string Host => Uri.Host; - - public int Port => Uri.Port; - - public override string ToString() => _redacted; } diff --git a/tests/NATS.Client.Core2.Tests/OnConnectingUriTest.cs b/tests/NATS.Client.Core2.Tests/OnConnectingUriTest.cs new file mode 100644 index 000000000..b538acdd3 --- /dev/null +++ b/tests/NATS.Client.Core2.Tests/OnConnectingUriTest.cs @@ -0,0 +1,32 @@ +using Microsoft.Extensions.Logging; +using NATS.Client.Platform.Windows.Tests; +using NATS.Client.TestUtilities; + +namespace NATS.Client.Core2.Tests; + +public class OnConnectingUriTest(ITestOutputHelper output) +{ + [Fact] + public async Task Logs_show_overridden_uri_when_OnConnectingAsync_changes_host_port() + { + await using var server = await NatsServerProcess.StartAsync(); + var serverPort = server.Port; + + var logger = new InMemoryTestLoggerFactory(LogLevel.Information, m => output.WriteLine($"LOG: {m.Message}")); + + await using var nats = new NatsConnection(new NatsOpts + { + Url = "nats://original-host:4222", + LoggerFactory = logger, + }); + + nats.OnConnectingAsync = _ => new ValueTask<(string Host, int Port)>(("127.0.0.1", serverPort)); + + await nats.ConnectAsync(); + + var connectLog = logger.Logs.FirstOrDefault(m => m.Message.Contains("Connect to NATS using")); + Assert.NotNull(connectLog); + Assert.Contains($"127.0.0.1:{serverPort}", connectLog.Message); + Assert.DoesNotContain("original-host", connectLog.Message); + } +} diff --git a/tests/NATS.Client.CoreUnit.Tests/OptsUrlTests.cs b/tests/NATS.Client.CoreUnit.Tests/OptsUrlTests.cs index e4144d179..452d577d5 100644 --- a/tests/NATS.Client.CoreUnit.Tests/OptsUrlTests.cs +++ b/tests/NATS.Client.CoreUnit.Tests/OptsUrlTests.cs @@ -117,5 +117,25 @@ public void Keep_URL_wss_path_and_query_string() Assert.Equal("t,", opts.AuthOpts.Token); } + [Fact] + public void ToString_reflects_uri_changed_via_with_expression() + { + var original = new NatsUri("host1:4222", true); + Assert.Equal("nats://host1:4222", original.ToString()); + + var modified = original with { Uri = new UriBuilder(original.Uri) { Host = "host2", Port = 5222 }.Uri }; + Assert.Equal("nats://host2:5222", modified.ToString()); + } + + [Fact] + public void ToString_reflects_uri_changed_via_with_expression_redacted() + { + var original = new NatsUri("u:p@host1:4222", true); + Assert.Equal("nats://u:***@host1:4222", original.ToString()); + + var modified = original with { Uri = new UriBuilder(original.Uri) { Host = "host2", Port = 5222 }.Uri }; + Assert.Equal("nats://u:***@host2:5222", modified.ToString()); + } + private static string GetUrisAsRedactedString(NatsOpts opts) => string.Join(",", opts.GetSeedUris(true).Select(u => u.ToString())); }