bare-ws 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/constants.js CHANGED
@@ -9,7 +9,9 @@ exports.opcode = {
9
9
  CONTINUATION: 0x0,
10
10
  TEXT: 0x1,
11
11
  BINARY: 0x2,
12
- CLOSE: 0x8
12
+ CLOSE: 0x8,
13
+ PING: 0x9,
14
+ PONG: 0xa
13
15
  }
14
16
 
15
17
  // https://datatracker.ietf.org/doc/html/rfc6455#section-7.4.1
package/lib/errors.js CHANGED
@@ -15,6 +15,22 @@ module.exports = class WebSocketError extends Error {
15
15
  return 'WebSocketError'
16
16
  }
17
17
 
18
+ static NOT_CONNECTED (msg = 'Socket is not connected') {
19
+ return new WebSocketError(msg, 'NOT_CONNECTED', 0, WebSocketError.NOT_CONNECTED)
20
+ }
21
+
22
+ static UNEXPECTED_RSV1 (msg = 'RSV1 must be unset') {
23
+ return new WebSocketError(msg, 'UNEXPECTED_RSV1', status.PROTOCOL_ERROR, WebSocketError.UNEXPECTED_RSV1)
24
+ }
25
+
26
+ static UNEXPECTED_RSV2 (msg = 'RSV2 must be unset') {
27
+ return new WebSocketError(msg, 'UNEXPECTED_RSV2', status.PROTOCOL_ERROR, WebSocketError.UNEXPECTED_RSV2)
28
+ }
29
+
30
+ static UNEXPECTED_RSV3 (msg = 'RSV3 must be unset') {
31
+ return new WebSocketError(msg, 'UNEXPECTED_RSV3', status.PROTOCOL_ERROR, WebSocketError.UNEXPECTED_RSV3)
32
+ }
33
+
18
34
  static EXPECTED_MASK (msg = 'MASK must be set') {
19
35
  return new WebSocketError(msg, 'EXPECTED_MASK', status.PROTOCOL_ERROR, WebSocketError.EXPECTED_MASK)
20
36
  }
package/lib/frame.js CHANGED
@@ -58,7 +58,7 @@ exports.preencode = function preencode (state, f) {
58
58
 
59
59
  if (length <= 0x7d) i++
60
60
  else {
61
- if (length < 2 ** 16) i += 3
61
+ if (length <= 0xffff) i += 3
62
62
  else i += 9
63
63
  }
64
64
 
@@ -91,7 +91,7 @@ exports.encode = function encode (state, f) {
91
91
 
92
92
  if (length <= 0x7d) b[i++] |= length
93
93
  else {
94
- if (length < 2 ** 16) {
94
+ if (length <= 0xffff) {
95
95
  b[i++] |= 0x7e
96
96
 
97
97
  v.setUint16(i, length, false)
package/lib/socket.js CHANGED
@@ -28,7 +28,7 @@ module.exports = exports = class WebSocket extends Duplex {
28
28
  socket = null
29
29
  } = opts
30
30
 
31
- super()
31
+ super({ eagerOpen: true })
32
32
 
33
33
  this._socket = null
34
34
  this._isServer = isServer
@@ -44,6 +44,22 @@ module.exports = exports = class WebSocket extends Duplex {
44
44
  else this._connect(opts)
45
45
  }
46
46
 
47
+ ping (data) {
48
+ if (this._socket === null) throw errors.NOT_CONNECTED()
49
+
50
+ if (typeof data === 'string') data = Buffer.from(data)
51
+
52
+ this._socket.write(new Frame(opcode.PING, data, { mask: this._mask }).toBuffer())
53
+ }
54
+
55
+ pong (data) {
56
+ if (this._socket === null) throw errors.NOT_CONNECTED()
57
+
58
+ if (typeof data === 'string') data = Buffer.from(data)
59
+
60
+ this._socket.write(new Frame(opcode.PONG, data, { mask: this._mask }).toBuffer())
61
+ }
62
+
47
63
  _attach (socket) {
48
64
  this._socket = socket
49
65
 
@@ -85,31 +101,46 @@ module.exports = exports = class WebSocket extends Duplex {
85
101
  while (this._buffer !== null) {
86
102
  const state = { start: 0, end: this._buffer.length, buffer: this._buffer }
87
103
 
88
- const frame = Frame.decode(state)
104
+ let frame
105
+ try {
106
+ frame = Frame.decode(state)
107
+ } catch (err) {
108
+ return this.destroy(err)
109
+ }
89
110
 
90
111
  if (frame === null) return
91
112
 
92
113
  this._buffer = state.start === state.end ? null : this._buffer.subarray(state.start)
93
114
 
94
- this._onframe(frame)
115
+ try {
116
+ this._onframe(frame)
117
+ } catch (err) {
118
+ return this.destroy(err)
119
+ }
95
120
  }
96
121
  }
97
122
 
98
123
  _onframe (frame) {
124
+ if (frame.rsv1) throw errors.UNEXPECTED_RSV1()
125
+
126
+ if (frame.rsv2) throw errors.UNEXPECTED_RSV2()
127
+
128
+ if (frame.rsv3) throw errors.UNEXPECTED_RSV3()
129
+
99
130
  if (frame.payload.length > 0 && !frame.mask === this._isServer) {
100
- return this.destroy(this._isServer ? errors.EXPECTED_MASK() : errors.UNEXPECTED_MASK())
131
+ throw this._isServer ? errors.EXPECTED_MASK() : errors.UNEXPECTED_MASK()
101
132
  }
102
133
 
103
134
  if (frame.fin === false) {
104
135
  if (this._fragments.push(frame) === 1) { // First frame
105
- if (frame.opcode === opcode.CONTINUATION) return this.destroy(errors.UNEXPECTED_CONTINUATION())
136
+ if (frame.opcode === opcode.CONTINUATION) throw errors.UNEXPECTED_CONTINUATION()
106
137
 
107
- if (frame.opcode >= opcode.CLOSE) return this.destroy(errors.UNEXPECTED_CONTROL())
138
+ if (frame.opcode >= opcode.CLOSE) throw errors.UNEXPECTED_CONTROL()
108
139
 
109
140
  return
110
141
  }
111
142
 
112
- if (frame.opcode !== opcode.CONTINUATION) return this.destroy(errors.EXPECTED_CONTINUATION())
143
+ if (frame.opcode !== opcode.CONTINUATION) throw errors.EXPECTED_CONTINUATION()
113
144
 
114
145
  return
115
146
  }
@@ -120,8 +151,17 @@ module.exports = exports = class WebSocket extends Duplex {
120
151
  this.end()
121
152
  return
122
153
 
154
+ case opcode.PING:
155
+ this.pong(frame.payload)
156
+ this.emit('ping', frame.payload)
157
+ return
158
+
159
+ case opcode.PONG:
160
+ this.emit('pong', frame.payload)
161
+ return
162
+
123
163
  case opcode.CONTINUATION: {
124
- if (this._fragments.length === 0) return this.destroy(errors.UNEXPECTED_CONTINUATION())
164
+ if (this._fragments.length === 0) throw errors.UNEXPECTED_CONTINUATION()
125
165
 
126
166
  frame.opcode = this._fragments[0].opcode
127
167
 
@@ -137,7 +177,7 @@ module.exports = exports = class WebSocket extends Duplex {
137
177
  }
138
178
 
139
179
  default:
140
- if (this._fragments.length > 0) return this.destroy(errors.EXPECTED_CONTINUATION())
180
+ if (this._fragments.length > 0) throw errors.EXPECTED_CONTINUATION()
141
181
  }
142
182
 
143
183
  switch (frame.opcode) {
@@ -147,7 +187,7 @@ module.exports = exports = class WebSocket extends Duplex {
147
187
  break
148
188
 
149
189
  default:
150
- this.destroy(errors.INVALID_OPCODE())
190
+ throw errors.INVALID_OPCODE()
151
191
  }
152
192
  }
153
193
 
@@ -222,10 +262,10 @@ const handshake = exports.handshake = function handshake (req, cb) {
222
262
  function defaultPort (url) {
223
263
  switch (url.protocol) {
224
264
  case 'ftp:': return 21
225
- case 'http':
226
- case 'ws': return 80
227
- case 'https':
228
- case 'wss': return 443
265
+ case 'http:':
266
+ case 'ws:': return 80
267
+ case 'https:':
268
+ case 'wss:': return 443
229
269
  }
230
270
 
231
271
  return null
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bare-ws",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "WebSocket library for JavaScript",
5
5
  "exports": {
6
6
  ".": "./index.js",