@@ -24,6 +24,8 @@ internal sealed class BrowserWebSocket : WebSocket
2424 private WebSocketState _state ;
2525 private bool _disposed ;
2626 private bool _aborted ;
27+ private bool _closeReceived ;
28+ private bool _closeSent ;
2729 private int [ ] responseStatus = new int [ 3 ] ;
2830 private MemoryHandle ? responseStatusHandle ;
2931
@@ -37,7 +39,7 @@ public override WebSocketState State
3739 lock ( _thisLock )
3840 {
3941#endif
40- if ( _innerWebSocket == null || _disposed || ( _state != WebSocketState . Connecting && _state ! = WebSocketState . Open && _state != WebSocketState . CloseSent ) )
42+ if ( _innerWebSocket == null || _disposed || _state = = WebSocketState . Aborted || _state == WebSocketState . Closed )
4143 {
4244 return _state ;
4345 }
@@ -46,15 +48,9 @@ public override WebSocketState State
4648#endif
4749
4850#if FEATURE_WASM_THREADS
49- return FastState = _innerWebSocket ! . SynchronizationContext . Send ( static ( BrowserWebSocket self ) =>
50- {
51- lock ( self . _thisLock )
52- {
53- return GetReadyState ( self . _innerWebSocket ! ) ;
54- } //lock
55- } , this ) ;
51+ return _innerWebSocket ! . SynchronizationContext . Send ( GetReadyState , this ) ;
5652#else
57- return FastState = GetReadyState ( _innerWebSocket ! ) ;
53+ return GetReadyState ( this ) ;
5854#endif
5955 }
6056 }
@@ -148,7 +144,7 @@ public override Task SendAsync(ArraySegment<byte> buffer, WebSocketMessageType m
148144 ThrowIfDisposed ( ) ;
149145
150146 // fast check of previous _state instead of GetReadyState(), the readyState would be validated on JS side
151- if ( FastState != WebSocketState . Open )
147+ if ( FastState != WebSocketState . Open && FastState != WebSocketState . CloseReceived )
152148 {
153149 throw new InvalidOperationException ( SR . net_WebSockets_NotConnected ) ;
154150 }
@@ -240,7 +236,7 @@ public override Task CloseOutputAsync(WebSocketCloseStatus closeStatus, string?
240236 {
241237 throw new WebSocketException ( WebSocketError . InvalidState , SR . Format ( SR . net_WebSockets_InvalidState , state , "Connecting, Open, CloseSent, Aborted" ) ) ;
242238 }
243- if ( state != WebSocketState . Open && state ! = WebSocketState . Connecting && state != WebSocketState . Aborted )
239+ if ( state = = WebSocketState . CloseSent )
244240 {
245241 return Task . CompletedTask ;
246242 }
@@ -280,10 +276,6 @@ public override Task CloseAsync(WebSocketCloseStatus closeStatus, string? status
280276 {
281277 throw new WebSocketException ( WebSocketError . InvalidState , SR . Format ( SR . net_WebSockets_InvalidState , state , "Connecting, Open, CloseSent, Aborted" ) ) ;
282278 }
283- if ( state != WebSocketState . Open && state != WebSocketState . Connecting && state != WebSocketState . Aborted && state != WebSocketState . CloseSent )
284- {
285- return Task . CompletedTask ;
286- }
287279
288280#if FEATURE_WASM_THREADS
289281 promise = CloseAsyncCore ( closeStatus , statusDescription , state != WebSocketState . Aborted , cancellationToken ) ;
@@ -387,12 +379,13 @@ private void CreateCore(Uri uri, List<string>? requestedSubProtocols)
387379 string [ ] ? subProtocols = requestedSubProtocols ? . ToArray ( ) ;
388380 var onClose = ( int code , string reason ) =>
389381 {
390- _closeStatus = ( WebSocketCloseStatus ) code ;
391- _closeStatusDescription = reason ;
392382#if FEATURE_WASM_THREADS
393383 lock ( _thisLock )
394384 {
395385#endif
386+ _closeStatus = ( WebSocketCloseStatus ) code ;
387+ _closeStatusDescription = reason ;
388+ _closeReceived = true ;
396389 WebSocketState state = State ;
397390 if ( state == WebSocketState . Connecting || state == WebSocketState . Open || state == WebSocketState . CloseSent )
398391 {
@@ -545,15 +538,21 @@ private static WebSocketReceiveResult ConvertResponse(BrowserWebSocket self)
545538 WebSocketMessageType messageType = ( WebSocketMessageType ) self . responseStatus [ typeIndex ] ;
546539 if ( messageType == WebSocketMessageType . Close )
547540 {
541+ self . _closeReceived = true ;
542+ self . FastState = self . _closeSent ? WebSocketState . Closed : WebSocketState . CloseReceived ;
548543 return new WebSocketReceiveResult ( self . responseStatus [ countIndex ] , messageType , self . responseStatus [ endIndex ] != 0 , self . CloseStatus , self . CloseStatusDescription ) ;
549544 }
550545 return new WebSocketReceiveResult ( self . responseStatus [ countIndex ] , messageType , self . responseStatus [ endIndex ] != 0 ) ;
551546 }
552547
553548 private async Task CloseAsyncCore ( WebSocketCloseStatus closeStatus , string ? statusDescription , bool waitForCloseReceived , CancellationToken cancellationToken )
554549 {
555- _closeStatus = closeStatus ;
556- _closeStatusDescription = statusDescription ;
550+ if ( ! _closeReceived )
551+ {
552+ _closeStatus = closeStatus ;
553+ _closeStatusDescription = statusDescription ;
554+ }
555+ _closeSent = true ;
557556
558557 var closeTask = BrowserInterop . WebSocketClose ( _innerWebSocket ! , ( int ) closeStatus , statusDescription , waitForCloseReceived ) ?? Task . CompletedTask ;
559558 await CancelationHelper ( closeTask , cancellationToken , FastState ) . ConfigureAwait ( true ) ;
@@ -562,6 +561,10 @@ private async Task CloseAsyncCore(WebSocketCloseStatus closeStatus, string? stat
562561 lock ( _thisLock )
563562 {
564563#endif
564+ if ( waitForCloseReceived )
565+ {
566+ _closeReceived = true ;
567+ }
565568 var state = State ;
566569 if ( state == WebSocketState . Open || state == WebSocketState . Connecting || state == WebSocketState . CloseSent )
567570 {
@@ -614,18 +617,42 @@ private async Task CancelationHelper(Task jsTask, CancellationToken cancellation
614617 }
615618 }
616619
617- private static WebSocketState GetReadyState ( JSObject innerWebSocket )
620+ private static WebSocketState GetReadyState ( BrowserWebSocket self )
618621 {
619- var readyState = BrowserInterop . GetReadyState ( innerWebSocket ) ;
620- // https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/readyState
621- return readyState switch
622- {
623- 0 => WebSocketState . Connecting , // 0 (CONNECTING)
624- 1 => WebSocketState . Open , // 1 (OPEN)
625- 2 => WebSocketState . CloseSent , // 2 (CLOSING)
626- 3 => WebSocketState . Closed , // 3 (CLOSED)
627- _ => WebSocketState . None
628- } ;
622+ #if FEATURE_WASM_THREADS
623+ lock ( self . _thisLock )
624+ {
625+ #endif
626+ var readyState = BrowserInterop . GetReadyState ( self . _innerWebSocket ) ;
627+ // https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/readyState
628+ var st = readyState switch
629+ {
630+ 0 => WebSocketState . Connecting , // 0 (CONNECTING)
631+ 1 => WebSocketState . Open , // 1 (OPEN)
632+ 2 => WebSocketState . CloseSent , // 2 (CLOSING)
633+ 3 => WebSocketState . Closed , // 3 (CLOSED)
634+ _ => WebSocketState . None
635+ } ;
636+ if ( st == WebSocketState . Closed || st == WebSocketState . CloseSent )
637+ {
638+ if ( self . _closeReceived && self . _closeSent )
639+ {
640+ st = WebSocketState . Closed ;
641+ }
642+ else if ( self . _closeReceived && ! self . _closeSent )
643+ {
644+ st = WebSocketState . CloseReceived ;
645+ }
646+ else if ( ! self . _closeReceived && self . _closeSent )
647+ {
648+ st = WebSocketState . CloseSent ;
649+ }
650+ }
651+ self . FastState = st ;
652+ return st ;
653+ #if FEATURE_WASM_THREADS
654+ } //lock
655+ #endif
629656 }
630657
631658 #endregion
0 commit comments