CitadelCore.Windows
CitadelCore.Windows copied to clipboard
Handling of websocket connections close event
On websocket termination (triggered by browser tab closure), a number of catch blocks catch an exception. The relevant code and stack trace is appended. I normally just ignore these errors and I haven't noticed any problems because the thing you are doing is already done after the connection is closed. So apart from cluttering the error logs, they appear to be benign. But I wonder.. Do they cause any side effects and should they be prevented? The code is from FilterWebsocketHandler.cs and FilterHttpResponseHandler.cs .The below stack is generated by tab close event. Thank you.
//FilterWebsocketHandler.cs
0+249 // Spawn an async task that will poll the remote server for data in a loop, and then
1+249 // write any data it gets to the client websocket.
2+249 var serverTask = Task.Run(async () =>
3+249 {
4+249 System.Net.WebSockets.WebSocketReceiveResult serverResult = null;
5+249 var serverBuffer = new byte[1024 * 4];
6+249 try
7+249 {
8+249 bool looping = true;
9+249
10+249 serverResult = await wsServer.ReceiveAsync(new ArraySegment<byte>(serverBuffer), context.RequestAborted);
11+249
12+249 while (looping && !serverResult.CloseStatus.HasValue && !context.RequestAborted.IsCancellationRequested)
13+249 {
14+249
15+249 if (inspect)
16+249 {
17+249 serverMessageInfo.Body = new Memory<byte>(serverBuffer, 0, serverResult.Count);
18+249
19+249 switch (serverResult.MessageType)
20+249 {
21+249 case System.Net.WebSockets.WebSocketMessageType.Binary:
22+249 {
23+249 serverMessageInfo.BodyContentType = s_octetStreamContentType;
24+249 }
25+249 break;
26+249
27+249 case System.Net.WebSockets.WebSocketMessageType.Text:
28+249 {
29+249 serverMessageInfo.BodyContentType = s_plainTextContentType;
30+249 }
31+249 break;
32+249 }
33+249
34+249 _configuration.HttpMessageWholeBodyInspectionHandler?.Invoke(serverMessageInfo, null);
35+249 }
36+249
37+249 switch (serverMessageInfo.ProxyNextAction)
38+249 {
39+249 case ProxyNextAction.DropConnection:
40+249 {
41+249 looping = false;
42+249 }
43+249 break;
44+249
45+249 default:
46+249 {
47+249 await wsClient.SendAsync(new ArraySegment<byte>(serverBuffer, 0, serverResult.Count), serverResult.MessageType, serverResult.EndOfMessage, context.RequestAborted);
48+249
49+249 if (!wsClient.CloseStatus.HasValue)
50+249 {
51+249 serverResult = await wsServer.ReceiveAsync(new ArraySegment<byte>(serverBuffer), context.RequestAborted); // this triggers an exception #0
52+249 continue;
53+249 }
54+249 }
55+249 break;
56+249 }
57+249
58+249 looping = false;
59+249 }
60+249
61+249 await wsClient.CloseAsync(serverResult.CloseStatus.Value, serverResult.CloseStatusDescription, context.RequestAborted);// this triggers an exception #1
62+249 }
63+249 catch (Exception e)
64+249 {
65+249 LoggerProxy.Default.Error(e.ToString());
66+249 try{
67+249 var closeStatus = serverResult?.CloseStatus ??
68+249 System.Net.WebSockets.WebSocketCloseStatus.NormalClosure;
69+249 var closeMessage = serverResult?.CloseStatusDescription ?? string.Empty;
70+249
71+249 await wsClient.CloseAsync(closeStatus, closeMessage, context.RequestAborted);// this triggers an exception #2
72+249 }
73+249 catch (Exception e2){
74+249 LoggerProxy.Default.Error(e2.ToString());
75+249
76+249 }
77+249 }
78+249 });
79+249
80+249 // Spawn an async task that will poll the local client websocket, in a loop, and then
81+249 // write any data it gets to the remote server websocket.
82+249 var clientTask = Task.Run(async () =>
83+249 {
84+249 System.Net.WebSockets.WebSocketReceiveResult clientResult = null;
85+249 var clientBuffer = new byte[1024 * 4];
86+249 try
87+249 {
88+249 bool looping = true;
89+249
90+249 clientResult = await wsClient.ReceiveAsync(new ArraySegment<byte>(clientBuffer), context.RequestAborted);
91+249
92+249 while (looping && !clientResult.CloseStatus.HasValue && !context.RequestAborted.IsCancellationRequested)
93+249 {
94+249 if (inspect)
95+249 {
96+249 clientMessageInfo.Body = new Memory<byte>(clientBuffer, 0, clientResult.Count);
97+249
98+249 switch (clientResult.MessageType)
99+249 {
100+249 case System.Net.WebSockets.WebSocketMessageType.Binary:
101+249 {
102+249 clientMessageInfo.BodyContentType = s_octetStreamContentType;
103+249 }
104+249 break;
105+249
106+249 case System.Net.WebSockets.WebSocketMessageType.Text:
107+249 {
108+249 clientMessageInfo.BodyContentType = s_plainTextContentType;
109+249 }
110+249 break;
111+249 }
112+249
113+249 _configuration.HttpMessageWholeBodyInspectionHandler?.Invoke(clientMessageInfo, null);
114+249 }
115+249
116+249 switch (clientMessageInfo.ProxyNextAction)
117+249 {
118+249 case ProxyNextAction.DropConnection:
119+249 {
120+249 looping = false;
121+249 }
122+249 break;
123+249
124+249 default:
125+249 {
126+249 await wsServer.SendAsync(new ArraySegment<byte>(clientBuffer, 0, clientResult.Count), clientResult.MessageType, clientResult.EndOfMessage, context.RequestAborted);
127+249
128+249 if (!wsServer.CloseStatus.HasValue)
129+249 {
130+249 clientResult = await wsClient.ReceiveAsync(new ArraySegment<byte>(clientBuffer), context.RequestAborted);
131+249 continue;
132+249 }
133+249 }
134+249 break;
135+249 }
136+249
137+249 looping = false;
138+249 }
139+249
140+249 await wsServer.CloseAsync(clientResult.CloseStatus.Value, clientResult.CloseStatusDescription, context.RequestAborted);// this triggers an exception #3
141+249 }
142+249 catch(Exception e)
143+249 {
144+249
145+249 LoggerProxy.Default.Error(e.ToString());
146+249 try{
147+249 var closeStatus = clientResult?.CloseStatus ??
148+249 System.Net.WebSockets.WebSocketCloseStatus.NormalClosure;
149+249 var closeMessage = clientResult?.CloseStatusDescription ?? string.Empty;
150+249
151+249 await wsServer.CloseAsync(closeStatus, closeMessage, context.RequestAborted);// this triggers an exception #4
152+249 }
153+249 catch (Exception e2){
154+249 LoggerProxy.Default.Error(e2.ToString());
155+249 }
156+249 }
157+249 });
158+249
159+249 // Above, we have created a bridge between the local and remote websocket. Wait for
160+249 // both associated tasks to complete.
161+249 await Task.WhenAll(serverTask, clientTask);
// FilterHttpResponseHandler.cs
0+386 try
1+386 {
2+386 if (false){
3+386
4+386 }
5+386 response = await upstreamClient.SendAsync(requestMsg, HttpCompletionOption.ResponseHeadersRead, context.RequestAborted);
6+386 }
7+386 catch (Exception e)
8+386 {
Exceptions:
ERRO: System.OperationCanceledException: Aborted ---> System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'SslStream'.
at System.Net.Security.SslState.CheckThrow(Boolean authSuccessCheck, Boolean shutdownCheck)
at System.Net.Security.SslState.get_SecureStream()
at System.Net.Security.SslStream.EndRead(IAsyncResult asyncResult)
at System.IO.Stream.<>c.<BeginEndReadAsync>b__43_1(Stream stream, IAsyncResult asyncResult)
at System.Threading.Tasks.TaskFactory`1.FromAsyncTrimPromise`1.Complete(TInstance thisRef, Func`3 endMethod, IAsyncResult asyncResult, Boolean requiresSynchronization)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
at Relay.Websockets.Managed.ManagedWebSocket.<EnsureBufferContainsAsync>d__70.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
at Relay.Websockets.Managed.ManagedWebSocket.<ReceiveAsyncPrivate>d__61.MoveNext()
--- End of inner exception stack trace ---
at Relay.Websockets.Managed.ManagedWebSocket.<ReceiveAsyncPrivate>d__61.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at Relay.Net.Handlers.FilterWebsocketHandler.<>c__DisplayClass4_1.<<Handle>b__0>d.MoveNext() in C:\Users\pathtoproject\Net\Handlers\FilterWebsocketHandler.cs:line 300
ERRO: System.Threading.Tasks.TaskCanceledException: A task was canceled.
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Net.Http.HttpClient.<FinishSendAsyncUnbuffered>d__59.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at Relay.Net.Handlers.FilterHttpResponseHandler.<Handle>d__7.MoveNext() in C:\Users\pathtoproject\Net\Handlers\FilterHttpResponseHandler.cs:line 391
ERRO: System.OperationCanceledException: Aborted ---> System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'SslStream'.
at System.Net.Security.SslState.CheckThrow(Boolean authSuccessCheck, Boolean shutdownCheck)
at System.Net.Security.SslState.get_SecureStream()
at System.Net.Security.SslStream.EndRead(IAsyncResult asyncResult)
at System.IO.Stream.<>c.<BeginEndReadAsync>b__43_1(Stream stream, IAsyncResult asyncResult)
at System.Threading.Tasks.TaskFactory`1.FromAsyncTrimPromise`1.Complete(TInstance thisRef, Func`3 endMethod, IAsyncResult asyncResult, Boolean requiresSynchronization)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
at Relay.Websockets.Managed.ManagedWebSocket.<EnsureBufferContainsAsync>d__70.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
at Relay.Websockets.Managed.ManagedWebSocket.<ReceiveAsyncPrivate>d__61.MoveNext()
--- End of inner exception stack trace ---
at Relay.Websockets.Managed.ManagedWebSocket.<ReceiveAsyncPrivate>d__61.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at Relay.Net.Handlers.FilterWebsocketHandler.<>c__DisplayClass4_1.<<Handle>b__0>d.MoveNext() in C:\Users\pathtoproject\Net\Handlers\FilterWebsocketHandler.cs:line 0
ERRO: System.Threading.Tasks.TaskCanceledException: A task was canceled.
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.WebSockets.Protocol.CommonWebSocket.<CloseOutputAsync>d__42.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.WebSockets.Protocol.CommonWebSocket.<CloseAsync>d__41.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at Relay.Net.Handlers.FilterWebsocketHandler.<>c__DisplayClass4_1.<<Handle>b__0>d.MoveNext() in C:\Users\pathtoproject\Net\Handlers\FilterWebsocketHandler.cs:line 320
ERRO: System.OperationCanceledException: Aborted ---> System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'SslStream'.
at System.Net.Security.SslState.CheckThrow(Boolean authSuccessCheck, Boolean shutdownCheck)
at System.Net.Security.SslState.get_SecureStream()
at System.Net.Security.SslStream.EndRead(IAsyncResult asyncResult)
at System.IO.Stream.<>c.<BeginEndReadAsync>b__43_1(Stream stream, IAsyncResult asyncResult)
at System.Threading.Tasks.TaskFactory`1.FromAsyncTrimPromise`1.Complete(TInstance thisRef, Func`3 endMethod, IAsyncResult asyncResult, Boolean requiresSynchronization)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
at Relay.Websockets.Managed.ManagedWebSocket.<EnsureBufferContainsAsync>d__70.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
at Relay.Websockets.Managed.ManagedWebSocket.<ReceiveAsyncPrivate>d__61.MoveNext()
--- End of inner exception stack trace ---
at Relay.Websockets.Managed.ManagedWebSocket.<ReceiveAsyncPrivate>d__61.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
at Relay.Websockets.Managed.ManagedWebSocket.<CloseAsyncPrivate>d__67.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at Relay.Net.Handlers.FilterWebsocketHandler.<>c__DisplayClass4_1.<<Handle>b__1>d.MoveNext() in C:\Users\pathtoproject\Net\Handlers\FilterWebsocketHandler.cs:line 389
ERRO: System.TypeInitializationException: The type initializer for 'System.SR' threw an exception. ---> System.Resources.MissingManifestResourceException: Could not find any resources appropriate for the specified culture or the neutral culture. Make sure
"Relay.Websockets.Client.Managed.Strings.resources" was correctly embedded or linked into assembly "ProjectSockets" at compile time, or that all the satellite assemblies required are loadable and fully signed.
at System.Resources.ManifestBasedResourceGroveler.HandleResourceStreamMissing(String fileName)
at System.Resources.ManifestBasedResourceGroveler.GrovelForResourceSet(CultureInfo culture, Dictionary`2 localResourceSets, Boolean tryParents, Boolean createIfNotExists, StackCrawlMark& stackMark)
at System.Resources.ResourceManager.InternalGetResourceSet(CultureInfo requestedCulture, Boolean createIfNotExists, Boolean tryParents, StackCrawlMark& stackMark)
at System.Resources.ResourceManager.InternalGetResourceSet(CultureInfo culture, Boolean createIfNotExists, Boolean tryParents)
at System.Resources.ResourceManager.GetString(String name, CultureInfo culture)
at Relay.Websockets.Client.Managed.Strings.get_net_WebSockets_InvalidCloseStatusDescription()
at System.SR..cctor()
--- End of inner exception stack trace ---
at Relay.Websockets.Managed.WebSocketValidate.ThrowIfInvalidState(WebSocketState currentState, Boolean isDisposed, WebSocketState[] validStates)
at Relay.Websockets.Managed.ManagedWebSocket.CloseAsync(WebSocketCloseStatus closeStatus, String statusDescription, CancellationToken cancellationToken)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at Relay.Net.Handlers.FilterWebsocketHandler.<>c__DisplayClass4_1.<<Handle>b__1>d.MoveNext() in C:\Users\pathtoproject\Net\Handlers\FilterWebsocketHandler.cs:line 400