@@ -430,6 +430,8 @@ describe('WebSocket', () => {
430
430
describe ( 'Events' , ( ) => {
431
431
it ( "emits an 'error' event if an error occurs" , ( done ) => {
432
432
let clientCloseEventEmitted = false ;
433
+ let serverClientCloseEventEmitted = false ;
434
+
433
435
const wss = new WebSocket . Server ( { port : 0 } , ( ) => {
434
436
const ws = new WebSocket ( `ws://localhost:${ wss . address ( ) . port } ` ) ;
435
437
@@ -442,19 +444,22 @@ describe('WebSocket', () => {
442
444
) ;
443
445
444
446
ws . on ( 'close' , ( code , reason ) => {
445
- clientCloseEventEmitted = true ;
446
447
assert . strictEqual ( code , 1006 ) ;
447
448
assert . strictEqual ( reason , '' ) ;
449
+
450
+ clientCloseEventEmitted = true ;
451
+ if ( serverClientCloseEventEmitted ) wss . close ( done ) ;
448
452
} ) ;
449
453
} ) ;
450
454
} ) ;
451
455
452
456
wss . on ( 'connection' , ( ws ) => {
453
457
ws . on ( 'close' , ( code , reason ) => {
454
- assert . ok ( clientCloseEventEmitted ) ;
455
458
assert . strictEqual ( code , 1002 ) ;
456
459
assert . strictEqual ( reason , '' ) ;
457
- wss . close ( done ) ;
460
+
461
+ serverClientCloseEventEmitted = true ;
462
+ if ( clientCloseEventEmitted ) wss . close ( done ) ;
458
463
} ) ;
459
464
460
465
ws . _socket . write ( Buffer . from ( [ 0x85 , 0x00 ] ) ) ;
@@ -1419,16 +1424,19 @@ describe('WebSocket', () => {
1419
1424
} ) ;
1420
1425
1421
1426
it ( 'honors the `mask` option' , ( done ) => {
1427
+ let clientCloseEventEmitted = false ;
1422
1428
let serverClientCloseEventEmitted = false ;
1429
+
1423
1430
const wss = new WebSocket . Server ( { port : 0 } , ( ) => {
1424
1431
const ws = new WebSocket ( `ws://localhost:${ wss . address ( ) . port } ` ) ;
1425
1432
1426
1433
ws . on ( 'open' , ( ) => ws . send ( 'hi' , { mask : false } ) ) ;
1427
1434
ws . on ( 'close' , ( code , reason ) => {
1428
- assert . ok ( serverClientCloseEventEmitted ) ;
1429
1435
assert . strictEqual ( code , 1002 ) ;
1430
1436
assert . strictEqual ( reason , '' ) ;
1431
- wss . close ( done ) ;
1437
+
1438
+ clientCloseEventEmitted = true ;
1439
+ if ( serverClientCloseEventEmitted ) wss . close ( done ) ;
1432
1440
} ) ;
1433
1441
} ) ;
1434
1442
@@ -1450,9 +1458,11 @@ describe('WebSocket', () => {
1450
1458
) ;
1451
1459
1452
1460
ws . on ( 'close' , ( code , reason ) => {
1453
- serverClientCloseEventEmitted = true ;
1454
1461
assert . strictEqual ( code , 1006 ) ;
1455
1462
assert . strictEqual ( reason , '' ) ;
1463
+
1464
+ serverClientCloseEventEmitted = true ;
1465
+ if ( clientCloseEventEmitted ) wss . close ( done ) ;
1456
1466
} ) ;
1457
1467
} ) ;
1458
1468
} ) ;
@@ -2760,4 +2770,118 @@ describe('WebSocket', () => {
2760
2770
} ) ;
2761
2771
} ) ;
2762
2772
} ) ;
2773
+
2774
+ describe ( 'Connection close edge cases' , ( ) => {
2775
+ it ( 'closes cleanly after simultaneous errors (1/2)' , ( done ) => {
2776
+ let clientCloseEventEmitted = false ;
2777
+ let serverClientCloseEventEmitted = false ;
2778
+
2779
+ const wss = new WebSocket . Server ( { port : 0 } , ( ) => {
2780
+ const ws = new WebSocket ( `ws://localhost:${ wss . address ( ) . port } ` ) ;
2781
+
2782
+ ws . on ( 'error' , ( err ) => {
2783
+ assert . ok ( err instanceof RangeError ) ;
2784
+ assert . strictEqual ( err . code , 'WS_ERR_INVALID_OPCODE' ) ;
2785
+ assert . strictEqual (
2786
+ err . message ,
2787
+ 'Invalid WebSocket frame: invalid opcode 5'
2788
+ ) ;
2789
+
2790
+ ws . on ( 'close' , ( code , reason ) => {
2791
+ assert . strictEqual ( code , 1006 ) ;
2792
+ assert . strictEqual ( reason , '' ) ;
2793
+
2794
+ clientCloseEventEmitted = true ;
2795
+ if ( serverClientCloseEventEmitted ) wss . close ( done ) ;
2796
+ } ) ;
2797
+ } ) ;
2798
+
2799
+ ws . on ( 'open' , ( ) => {
2800
+ // Write an invalid frame in both directions to trigger simultaneous
2801
+ // failure.
2802
+ const chunk = Buffer . from ( [ 0x85 , 0x00 ] ) ;
2803
+
2804
+ wss . clients . values ( ) . next ( ) . value . _socket . write ( chunk ) ;
2805
+ ws . _socket . write ( chunk ) ;
2806
+ } ) ;
2807
+ } ) ;
2808
+
2809
+ wss . on ( 'connection' , ( ws ) => {
2810
+ ws . on ( 'error' , ( err ) => {
2811
+ assert . ok ( err instanceof RangeError ) ;
2812
+ assert . strictEqual ( err . code , 'WS_ERR_INVALID_OPCODE' ) ;
2813
+ assert . strictEqual (
2814
+ err . message ,
2815
+ 'Invalid WebSocket frame: invalid opcode 5'
2816
+ ) ;
2817
+
2818
+ ws . on ( 'close' , ( code , reason ) => {
2819
+ assert . strictEqual ( code , 1006 ) ;
2820
+ assert . strictEqual ( reason , '' ) ;
2821
+
2822
+ serverClientCloseEventEmitted = true ;
2823
+ if ( clientCloseEventEmitted ) wss . close ( done ) ;
2824
+ } ) ;
2825
+ } ) ;
2826
+ } ) ;
2827
+ } ) ;
2828
+
2829
+ it ( 'closes cleanly after simultaneous errors (2/2)' , ( done ) => {
2830
+ let clientCloseEventEmitted = false ;
2831
+ let serverClientCloseEventEmitted = false ;
2832
+
2833
+ const wss = new WebSocket . Server ( { port : 0 } , ( ) => {
2834
+ const ws = new WebSocket ( `ws://localhost:${ wss . address ( ) . port } ` ) ;
2835
+
2836
+ ws . on ( 'error' , ( err ) => {
2837
+ assert . ok ( err instanceof RangeError ) ;
2838
+ assert . strictEqual ( err . code , 'WS_ERR_INVALID_OPCODE' ) ;
2839
+ assert . strictEqual (
2840
+ err . message ,
2841
+ 'Invalid WebSocket frame: invalid opcode 5'
2842
+ ) ;
2843
+
2844
+ ws . on ( 'close' , ( code , reason ) => {
2845
+ assert . strictEqual ( code , 1006 ) ;
2846
+ assert . strictEqual ( reason , '' ) ;
2847
+
2848
+ clientCloseEventEmitted = true ;
2849
+ if ( serverClientCloseEventEmitted ) wss . close ( done ) ;
2850
+ } ) ;
2851
+ } ) ;
2852
+
2853
+ ws . on ( 'open' , ( ) => {
2854
+ // Write an invalid frame in both directions and change the
2855
+ // `readyState` to `WebSocket.CLOSING`.
2856
+ const chunk = Buffer . from ( [ 0x85 , 0x00 ] ) ;
2857
+ const serverWs = wss . clients . values ( ) . next ( ) . value ;
2858
+
2859
+ serverWs . _socket . write ( chunk ) ;
2860
+ serverWs . close ( ) ;
2861
+
2862
+ ws . _socket . write ( chunk ) ;
2863
+ ws . close ( ) ;
2864
+ } ) ;
2865
+ } ) ;
2866
+
2867
+ wss . on ( 'connection' , ( ws ) => {
2868
+ ws . on ( 'error' , ( err ) => {
2869
+ assert . ok ( err instanceof RangeError ) ;
2870
+ assert . strictEqual ( err . code , 'WS_ERR_INVALID_OPCODE' ) ;
2871
+ assert . strictEqual (
2872
+ err . message ,
2873
+ 'Invalid WebSocket frame: invalid opcode 5'
2874
+ ) ;
2875
+
2876
+ ws . on ( 'close' , ( code , reason ) => {
2877
+ assert . strictEqual ( code , 1006 ) ;
2878
+ assert . strictEqual ( reason , '' ) ;
2879
+
2880
+ serverClientCloseEventEmitted = true ;
2881
+ if ( clientCloseEventEmitted ) wss . close ( done ) ;
2882
+ } ) ;
2883
+ } ) ;
2884
+ } ) ;
2885
+ } ) ;
2886
+ } ) ;
2763
2887
} ) ;
0 commit comments