diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index af19a6d..c35ea71 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -1,3 +1,6 @@ +v.6.1.0 +- Throw TimeoutException instead of OperationCanceledException when RawQueryAsync method times out + v.6.0.0 - [BREAKING CHANGE] The Default timeout for communication with servers was changed to 2 seconds, and the default retry count was changed to 3 times (Issue #10 by Makaopior) - Improved resolving an organization name from a raw response text from a WHOIS server diff --git a/WhoisClient.NET.Test/IrregularCaseTests.cs b/WhoisClient.NET.Test/IrregularCaseTests.cs index 1013126..18238d1 100644 --- a/WhoisClient.NET.Test/IrregularCaseTests.cs +++ b/WhoisClient.NET.Test/IrregularCaseTests.cs @@ -1,4 +1,5 @@ -using System.Net.Sockets; +using System; +using System.Net.Sockets; using System.Text; using NUnit.Framework; using Whois.NET; @@ -110,6 +111,49 @@ public async Task Default_Timeout_Async_Test() cts.Token.IsCancellationRequested.IsFalse(); } + [Test] + public void Default_Timeout_WithExceptionRethrow_Test() + { + // Given: a server that never shuts down + using var server = new MockServer((client, token) => Task.Delay(int.MaxValue, token)); + + // When: a query is made to the server + using var cts = new CancellationTokenSource(millisecondsDelay: 5000); + var action = () => Task.Run(() => + WhoisClient.RawQuery("example.jp", options: new() + { + Server = "localhost", + Port = server.Port, + RethrowExceptions = true + }), cts.Token); + + // Then: IOException should be thrown + Assert.ThrowsAsync(new AsyncTestDelegate(action)); + + cts.Token.IsCancellationRequested.IsFalse(); + } + + [Test] + public void Default_Timeout_WithExceptionRethrow_Async_Test() + { + // Given: a server that never shuts down + using var server = new MockServer((client, token) => Task.Delay(int.MaxValue, token)); + + // When: a query is made to the server + using var cts = new CancellationTokenSource(millisecondsDelay: 5000); + var action = () => WhoisClient.RawQueryAsync("example.jp", options: new() + { + Server = "localhost", + Port = server.Port, + RethrowExceptions = true + }, cts.Token); + + // Then: TimeoutException should be thrown + Assert.ThrowsAsync(new AsyncTestDelegate(action)); + + cts.Token.IsCancellationRequested.IsFalse(); + } + [Test] public async Task Default_RetryCount_Test() { diff --git a/WhoisClient.NET/WhoisClient.NET.csproj b/WhoisClient.NET/WhoisClient.NET.csproj index 437d577..21c55c4 100644 --- a/WhoisClient.NET/WhoisClient.NET.csproj +++ b/WhoisClient.NET/WhoisClient.NET.csproj @@ -9,7 +9,7 @@ WhoisClient WhoisClient.NET J.Sakamoto, Keith J. Jones, Martijn Storck, Makaopior - 6.0.0 + 6.1.0 Copyright 2012-2025 J.Sakamoto; 2016 Keith J. Jones; 2023 Martijn Storck; 2025 Makaopior; Ms-PL License. MS-PL https://github.com/jsakamoto/WhoisClient.NET/ diff --git a/WhoisClient.NET/WhoisClient.cs b/WhoisClient.NET/WhoisClient.cs index d0275d2..29f3a8a 100644 --- a/WhoisClient.NET/WhoisClient.cs +++ b/WhoisClient.NET/WhoisClient.cs @@ -468,7 +468,14 @@ private static async Task InvokeAsync(Func action, int using (var linked = CancellationTokenSource.CreateLinkedTokenSource(token, timeoutCancellation.Token)) { #if NETCOREAPP - await action(linked.Token); + try + { + await action(linked.Token); + } + catch (OperationCanceledException) when (!token.IsCancellationRequested) + { + throw new TimeoutException("Socket operation timeout"); + } #else var mainTask = action(linked.Token); var timeoutTask = Task.Delay(Timeout.Infinite, timeoutCancellation.Token); @@ -476,7 +483,7 @@ private static async Task InvokeAsync(Func action, int var firstCompletedTask = await Task.WhenAny(mainTask, timeoutTask, cancellationTask); - if (firstCompletedTask == timeoutTask) throw new TimeoutException(); + if (firstCompletedTask == timeoutTask) throw new TimeoutException("Socket operation timeout"); if (firstCompletedTask == cancellationTask) token.ThrowIfCancellationRequested(); #endif }