Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions RELEASE-NOTES.txt
Original file line number Diff line number Diff line change
@@ -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
Expand Down
46 changes: 45 additions & 1 deletion WhoisClient.NET.Test/IrregularCaseTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Net.Sockets;
using System;
using System.Net.Sockets;
using System.Text;
using NUnit.Framework;
using Whois.NET;
Expand Down Expand Up @@ -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<IOException>(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<TimeoutException>(new AsyncTestDelegate(action));

cts.Token.IsCancellationRequested.IsFalse();
}

[Test]
public async Task Default_RetryCount_Test()
{
Expand Down
2 changes: 1 addition & 1 deletion WhoisClient.NET/WhoisClient.NET.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<AssemblyName>WhoisClient</AssemblyName>
<Product>WhoisClient.NET</Product>
<Authors>J.Sakamoto, Keith J. Jones, Martijn Storck, Makaopior</Authors>
<Version>6.0.0</Version>
<Version>6.1.0</Version>
<Copyright>Copyright 2012-2025 J.Sakamoto; 2016 Keith J. Jones; 2023 Martijn Storck; 2025 Makaopior; Ms-PL License.</Copyright>
<PackageLicenseExpression>MS-PL</PackageLicenseExpression>
<PackageProjectUrl>https://github.com/jsakamoto/WhoisClient.NET/</PackageProjectUrl>
Expand Down
11 changes: 9 additions & 2 deletions WhoisClient.NET/WhoisClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -468,15 +468,22 @@ private static async Task InvokeAsync(Func<CancellationToken, Task> 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");
Comment on lines +475 to +477
Copy link

Copilot AI Apr 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Consider including the original OperationCanceledException as the inner exception when throwing the TimeoutException to preserve additional context for debugging.

Suggested change
catch (OperationCanceledException) when (!token.IsCancellationRequested)
{
throw new TimeoutException("Socket operation timeout");
catch (OperationCanceledException ex) when (!token.IsCancellationRequested)
{
throw new TimeoutException("Socket operation timeout", ex);

Copilot uses AI. Check for mistakes.

}
#else
var mainTask = action(linked.Token);
var timeoutTask = Task.Delay(Timeout.Infinite, timeoutCancellation.Token);
var cancellationTask = Task.Delay(Timeout.Infinite, token);

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
}
Expand Down