Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

Commit

Permalink
Change the behavior of ReceiveAsync cancellation to throw OperationCa…
Browse files Browse the repository at this point in the history
…nceledException (#17444)

* fix the behavior of ReceiveAsync cancellation throws WebSocketException
  • Loading branch information
Caesar Chen authored and stephentoub committed Mar 25, 2017
1 parent 37d1a01 commit d6b1125
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 27 deletions.
8 changes: 5 additions & 3 deletions src/Common/src/System/Net/WebSockets/ManagedWebSocket.cs
Original file line number Diff line number Diff line change
Expand Up @@ -732,9 +732,11 @@ private async Task<WebSocketReceiveResult> ReceiveAsyncPrivate(ArraySegment<byte
}
catch (Exception exc)
{
throw _state == WebSocketState.Aborted ?
new WebSocketException(WebSocketError.InvalidState, SR.Format(SR.net_WebSockets_InvalidState_ClosedOrAborted, "System.Net.WebSockets.InternalClientWebSocket", "Aborted"), exc) :
new WebSocketException(WebSocketError.ConnectionClosedPrematurely, exc);
if (_state == WebSocketState.Aborted)
{
throw new OperationCanceledException(nameof(WebSocketState.Aborted), exc);
}
throw new WebSocketException(WebSocketError.ConnectionClosedPrematurely, exc);
}
finally
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -795,14 +795,7 @@ private void CancelAllOperations()

if (_operation.TcsReceive != null)
{
var exception = new WebSocketException(
WebSocketError.InvalidState,
SR.Format(
SR.net_WebSockets_InvalidState_ClosedOrAborted,
"System.Net.WebSockets.InternalClientWebSocket",
"Aborted"));

_operation.TcsReceive.TrySetException(exception);
_operation.TcsReceive.TrySetCanceled();
}

if (_operation.TcsSend != null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -315,24 +315,16 @@ private static void OnWebSocketError(

if (asyncResult.AsyncResult.dwError == Interop.WinHttp.ERROR_WINHTTP_OPERATION_CANCELLED)
{
var exception = new WebSocketException(
WebSocketError.InvalidState,
SR.Format(
SR.net_WebSockets_InvalidState_ClosedOrAborted,
"System.Net.WebSockets.InternalClientWebSocket",
"Aborted"),
innerException);

state.UpdateState(WebSocketState.Aborted);

if (state.TcsReceive != null)
{
state.TcsReceive.TrySetException(exception);
state.TcsReceive.TrySetCanceled();
}

if (state.TcsSend != null)
{
state.TcsSend.TrySetException(exception);
state.TcsSend.TrySetCanceled();
}

return;
Expand Down
39 changes: 34 additions & 5 deletions src/System.Net.WebSockets.Client/tests/CancelTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,23 +117,52 @@ await cws.SendAsync(
await cws.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "CancelShutdown", cts.Token);
}, server);
}

[OuterLoop] // TODO: Issue #11345
[ConditionalTheory(nameof(WebSocketsSupported)), MemberData(nameof(EchoServers))]
public async Task ReceiveAsync_CancelThenReceive_ThrowsOperationCanceledException(Uri server)
{
using (ClientWebSocket cws = await WebSocketHelper.GetConnectedWebSocket(server, TimeOutMilliseconds, _output))
{
var recvBuffer = new byte[100];
var segment = new ArraySegment<byte>(recvBuffer);
var cts = new CancellationTokenSource();

cts.Cancel();
Task receive = cws.ReceiveAsync(segment, cts.Token);
await Assert.ThrowsAnyAsync<OperationCanceledException>(() => receive);
}
}

[OuterLoop] // TODO: Issue #11345
[ConditionalTheory(nameof(WebSocketsSupported)), MemberData(nameof(EchoServers))]
public async Task ReceiveAsync_CancelAndReceive_ThrowsWebSocketExceptionWithMessage(Uri server)
public async Task ReceiveAsync_ReceiveThenCancel_ThrowsOperationCanceledException(Uri server)
{
using (ClientWebSocket cws = await WebSocketHelper.GetConnectedWebSocket(server, TimeOutMilliseconds, _output))
{
var recvBuffer = new byte[100];
var segment = new ArraySegment<byte>(recvBuffer);
var cts = new CancellationTokenSource();

Task receive = cws.ReceiveAsync(segment, cts.Token);
cts.Cancel();
await Assert.ThrowsAnyAsync<OperationCanceledException>(() => receive);
}
}

[OuterLoop] // TODO: Issue #11345
[ConditionalTheory(nameof(WebSocketsSupported)), MemberData(nameof(EchoServers))]
public async Task ReceiveAsync_AfterCancellationDoReceiveAsync_ThrowsWebSocketException(Uri server)
{
using (ClientWebSocket cws = await WebSocketHelper.GetConnectedWebSocket(server, TimeOutMilliseconds, _output))
{
var recvBuffer = new byte[100];
var segment = new ArraySegment<byte>(recvBuffer);
var cts = new CancellationTokenSource();
// OperationCancelledException is thrown only if the token is canceled before calling ReceiveAsync
// Once it returns (with a Task<>), any cancellation that occurs is treated as a WebSocketException

Task recieve = cws.ReceiveAsync(segment, cts.Token);
cts.Cancel();
WebSocketException wse = await Assert.ThrowsAnyAsync<WebSocketException>(() => recieve);


WebSocketException ex = await Assert.ThrowsAsync<WebSocketException>(() =>
cws.ReceiveAsync(segment, CancellationToken.None));
Assert.Equal(
Expand Down
2 changes: 1 addition & 1 deletion src/System.Net.WebSockets.Client/tests/CloseTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ public async Task CloseAsync_DuringConcurrentReceiveAsync_ExpectedStates(Uri ser
await t;
Assert.Equal(WebSocketState.Closed, cws.State);
}
catch (WebSocketException)
catch (OperationCanceledException)
{
Assert.Equal(WebSocketState.Aborted, cws.State);
}
Expand Down
4 changes: 4 additions & 0 deletions src/System.Net.WebSockets.Client/tests/SendReceiveTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,10 @@ await cws.SendAsync(
(errCode == WebSocketError.InvalidState) || (errCode == WebSocketError.Success),
"WebSocketErrorCode");
}
else if (ex is OperationCanceledException)
{
Assert.Equal(WebSocketState.Aborted, cws.State);
}
else
{
Assert.True(false, "Unexpected exception: " + ex.Message);
Expand Down

0 comments on commit d6b1125

Please sign in to comment.