@@ -5,7 +5,16 @@ const assert = require('node:assert')
5
5
const { parserStates, opcodes, states, emptyBuffer, sentCloseFrameState } = require ( './constants' )
6
6
const { kReadyState, kSentClose, kResponse, kReceivedClose } = require ( './symbols' )
7
7
const { channels } = require ( '../../core/diagnostics' )
8
- const { isValidStatusCode, failWebsocketConnection, websocketMessageReceived, utf8Decode, isControlFrame, isContinuationFrame } = require ( './util' )
8
+ const {
9
+ isValidStatusCode,
10
+ isValidOpcode,
11
+ failWebsocketConnection,
12
+ websocketMessageReceived,
13
+ utf8Decode,
14
+ isControlFrame,
15
+ isContinuationFrame,
16
+ isTextBinaryFrame
17
+ } = require ( './util' )
9
18
const { WebsocketFrameSend } = require ( './frame' )
10
19
const { CloseEvent } = require ( './events' )
11
20
@@ -58,19 +67,45 @@ class ByteParser extends Writable {
58
67
const opcode = buffer [ 0 ] & 0x0F
59
68
const masked = ( buffer [ 1 ] & 0x80 ) === 0x80
60
69
70
+ if ( ! isValidOpcode ( opcode ) ) {
71
+ failWebsocketConnection ( this . ws , 'Invalid opcode received' )
72
+ return callback ( )
73
+ }
74
+
61
75
if ( masked ) {
62
76
failWebsocketConnection ( this . ws , 'Frame cannot be masked' )
63
77
return callback ( )
64
78
}
65
79
80
+ const rsv1 = ( buffer [ 0 ] & 0x40 ) !== 0
81
+ const rsv2 = ( buffer [ 0 ] & 0x20 ) !== 0
82
+ const rsv3 = ( buffer [ 0 ] & 0x10 ) !== 0
83
+
84
+ // MUST be 0 unless an extension is negotiated that defines meanings
85
+ // for non-zero values. If a nonzero value is received and none of
86
+ // the negotiated extensions defines the meaning of such a nonzero
87
+ // value, the receiving endpoint MUST _Fail the WebSocket
88
+ // Connection_.
89
+ if ( rsv1 || rsv2 || rsv3 ) {
90
+ failWebsocketConnection ( this . ws , 'RSV1, RSV2, RSV3 must be clear' )
91
+ return
92
+ }
93
+
66
94
const fragmented = ! fin && opcode !== opcodes . CONTINUATION
67
95
68
- if ( fragmented && opcode !== opcodes . BINARY && opcode !== opcodes . TEXT ) {
96
+ if ( fragmented && ! isTextBinaryFrame ( opcode ) ) {
69
97
// Only text and binary frames can be fragmented
70
98
failWebsocketConnection ( this . ws , 'Invalid frame type was fragmented.' )
71
99
return
72
100
}
73
101
102
+ // If we are already parsing a text/binary frame and do not receive either
103
+ // a continuation frame or close frame, fail the connection.
104
+ if ( isTextBinaryFrame ( opcode ) && this . #info. opcode !== undefined ) {
105
+ failWebsocketConnection ( this . ws , 'Expected continuation frame' )
106
+ return
107
+ }
108
+
74
109
const payloadLength = buffer [ 1 ] & 0x7F
75
110
76
111
if ( isControlFrame ( opcode ) ) {
@@ -269,7 +304,7 @@ class ByteParser extends Writable {
269
304
270
305
if ( info . payloadLength > 125 ) {
271
306
// Control frames can have a payload length of 125 bytes MAX
272
- callback ( new Error ( 'Payload length for control frame exceeded 125 bytes.' ) )
307
+ failWebsocketConnection ( this . ws , 'Payload length for control frame exceeded 125 bytes.' )
273
308
return false
274
309
} else if ( this . #byteOffset < info . payloadLength ) {
275
310
callback ( )
@@ -375,7 +410,7 @@ class ByteParser extends Writable {
375
410
parseContinuationFrame ( callback , info ) {
376
411
// If we received a continuation frame before we started parsing another frame.
377
412
if ( this . #info. opcode === undefined ) {
378
- callback ( new Error ( 'Received unexpected continuation frame.' ) )
413
+ failWebsocketConnection ( this . ws , 'Received unexpected continuation frame.' )
379
414
return false
380
415
} else if ( this . #byteOffset < info . payloadLength ) {
381
416
callback ( )
0 commit comments