bare-ws 2.0.2 → 2.0.4
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/errors.d.ts +17 -22
- package/lib/errors.js +6 -13
- package/lib/frame.js +11 -14
- package/lib/server.d.ts +7 -13
- package/lib/server.js +9 -12
- package/lib/socket.d.ts +1 -2
- package/lib/socket.js +24 -35
- package/package.json +2 -2
package/lib/errors.d.ts
CHANGED
|
@@ -1,28 +1,23 @@
|
|
|
1
1
|
declare class WebSocketError extends Error {
|
|
2
|
-
constructor(
|
|
3
|
-
msg: string,
|
|
4
|
-
code: string,
|
|
5
|
-
status: number,
|
|
6
|
-
fn?: WebSocketError,
|
|
7
|
-
cause?: unknown
|
|
8
|
-
)
|
|
2
|
+
constructor(msg: string, code: string, status: number, fn?: WebSocketError, cause?: unknown)
|
|
9
3
|
|
|
10
4
|
static NETWORK_ERROR(msg: string, cause?: unknown): WebSocketError
|
|
11
|
-
static NOT_CONNECTED(msg?: string
|
|
12
|
-
static UNEXPECTED_RSV1(msg?: string
|
|
13
|
-
static UNEXPECTED_RSV2(msg?: string
|
|
14
|
-
static UNEXPECTED_RSV3(msg?: string
|
|
15
|
-
static EXPECTED_MASK(msg?: string
|
|
16
|
-
static EXPECTED_CONTINUATION(msg?: string
|
|
17
|
-
static UNEXPECTED_CONTINUATION(msg?: string
|
|
18
|
-
static UNEXPECTED_CONTROL(msg?: string
|
|
19
|
-
static INVALID_ENCODING(msg?: string
|
|
20
|
-
static INVALID_UPGRADE_HEADER(msg?: string
|
|
21
|
-
static INVALID_VERSION_HEADER(msg?: string
|
|
22
|
-
static INVALID_KEY_HEADER(msg?: string
|
|
23
|
-
static INVALID_ACCEPT_HEADER(msg?: string
|
|
24
|
-
static INVALID_OPCODE(msg?: string
|
|
25
|
-
static INVALID_PAYLOAD_LENGTH(msg?: string
|
|
5
|
+
static NOT_CONNECTED(msg?: string): WebSocketError
|
|
6
|
+
static UNEXPECTED_RSV1(msg?: string): WebSocketError
|
|
7
|
+
static UNEXPECTED_RSV2(msg?: string): WebSocketError
|
|
8
|
+
static UNEXPECTED_RSV3(msg?: string): WebSocketError
|
|
9
|
+
static EXPECTED_MASK(msg?: string): WebSocketError
|
|
10
|
+
static EXPECTED_CONTINUATION(msg?: string): WebSocketError
|
|
11
|
+
static UNEXPECTED_CONTINUATION(msg?: string): WebSocketError
|
|
12
|
+
static UNEXPECTED_CONTROL(msg?: string): WebSocketError
|
|
13
|
+
static INVALID_ENCODING(msg?: string): WebSocketError
|
|
14
|
+
static INVALID_UPGRADE_HEADER(msg?: string): WebSocketError
|
|
15
|
+
static INVALID_VERSION_HEADER(msg?: string): WebSocketError
|
|
16
|
+
static INVALID_KEY_HEADER(msg?: string): WebSocketError
|
|
17
|
+
static INVALID_ACCEPT_HEADER(msg?: string): WebSocketError
|
|
18
|
+
static INVALID_OPCODE(msg?: string): WebSocketError
|
|
19
|
+
static INVALID_PAYLOAD_LENGTH(msg?: string): WebSocketError
|
|
20
|
+
static INCOMPLETE_FRAME(msg?: string, length?: number): WebSocketError
|
|
26
21
|
}
|
|
27
22
|
|
|
28
23
|
export = WebSocketError
|
package/lib/errors.js
CHANGED
|
@@ -16,22 +16,11 @@ module.exports = class WebSocketError extends Error {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
static NETWORK_ERROR(msg, cause) {
|
|
19
|
-
return new WebSocketError(
|
|
20
|
-
msg,
|
|
21
|
-
'NETWORK_ERROR',
|
|
22
|
-
0,
|
|
23
|
-
WebSocketError.NETWORK_ERROR,
|
|
24
|
-
cause
|
|
25
|
-
)
|
|
19
|
+
return new WebSocketError(msg, 'NETWORK_ERROR', 0, WebSocketError.NETWORK_ERROR, cause)
|
|
26
20
|
}
|
|
27
21
|
|
|
28
22
|
static NOT_CONNECTED(msg = 'Socket is not connected') {
|
|
29
|
-
return new WebSocketError(
|
|
30
|
-
msg,
|
|
31
|
-
'NOT_CONNECTED',
|
|
32
|
-
0,
|
|
33
|
-
WebSocketError.NOT_CONNECTED
|
|
34
|
-
)
|
|
23
|
+
return new WebSocketError(msg, 'NOT_CONNECTED', 0, WebSocketError.NOT_CONNECTED)
|
|
35
24
|
}
|
|
36
25
|
|
|
37
26
|
static UNEXPECTED_RSV1(msg = 'RSV1 must be unset') {
|
|
@@ -168,4 +157,8 @@ module.exports = class WebSocketError extends Error {
|
|
|
168
157
|
WebSocketError.INVALID_PAYLOAD_LENGTH
|
|
169
158
|
)
|
|
170
159
|
}
|
|
160
|
+
|
|
161
|
+
static INCOMPLETE_FRAME(msg = 'Incomplete frame', length = -1) {
|
|
162
|
+
return new WebSocketError(msg, 'INCOMPLETE_FRAME', length, WebSocketError.INCOMPLETE_FRAME)
|
|
163
|
+
}
|
|
171
164
|
}
|
package/lib/frame.js
CHANGED
|
@@ -19,13 +19,7 @@ module.exports = exports = class Frame {
|
|
|
19
19
|
payload = EMPTY
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
const {
|
|
23
|
-
fin = true,
|
|
24
|
-
rsv1 = false,
|
|
25
|
-
rsv2 = false,
|
|
26
|
-
rsv3 = false,
|
|
27
|
-
mask = null
|
|
28
|
-
} = opts
|
|
22
|
+
const { fin = true, rsv1 = false, rsv2 = false, rsv3 = false, mask = null } = opts
|
|
29
23
|
|
|
30
24
|
this.fin = fin
|
|
31
25
|
this.rsv1 = rsv1
|
|
@@ -136,12 +130,13 @@ exports.encode = function encode(state, f) {
|
|
|
136
130
|
}
|
|
137
131
|
|
|
138
132
|
exports.decode = function decode(state) {
|
|
133
|
+
const s = state.start
|
|
139
134
|
const b = state.buffer
|
|
140
135
|
|
|
141
|
-
let i =
|
|
142
|
-
let n = b.
|
|
136
|
+
let i = s
|
|
137
|
+
let n = b.byteLength
|
|
143
138
|
|
|
144
|
-
if (n < 2)
|
|
139
|
+
if (n < 2) throw errors.INCOMPLETE_FRAME()
|
|
145
140
|
|
|
146
141
|
const view = new DataView(b.buffer, b.byteOffset, b.byteLength)
|
|
147
142
|
|
|
@@ -164,14 +159,14 @@ exports.decode = function decode(state) {
|
|
|
164
159
|
n--
|
|
165
160
|
|
|
166
161
|
if (length === 0x7e) {
|
|
167
|
-
if (n < 2)
|
|
162
|
+
if (n < 2) throw errors.INCOMPLETE_FRAME()
|
|
168
163
|
|
|
169
164
|
length = view.getUint16(i, false)
|
|
170
165
|
|
|
171
166
|
i += 2
|
|
172
167
|
n -= 2
|
|
173
168
|
} else if (length === 0x7f) {
|
|
174
|
-
if (n < 8)
|
|
169
|
+
if (n < 8) throw errors.INCOMPLETE_FRAME()
|
|
175
170
|
|
|
176
171
|
const high = view.getUint32(i, false)
|
|
177
172
|
|
|
@@ -191,7 +186,7 @@ exports.decode = function decode(state) {
|
|
|
191
186
|
let mask = null
|
|
192
187
|
|
|
193
188
|
if (masked) {
|
|
194
|
-
if (n < 4)
|
|
189
|
+
if (n < 4) throw errors.INCOMPLETE_FRAME()
|
|
195
190
|
|
|
196
191
|
mask = b.subarray(i, i + 4)
|
|
197
192
|
|
|
@@ -199,7 +194,9 @@ exports.decode = function decode(state) {
|
|
|
199
194
|
n -= 4
|
|
200
195
|
}
|
|
201
196
|
|
|
202
|
-
if (n < length)
|
|
197
|
+
if (n < length) {
|
|
198
|
+
throw errors.INCOMPLETE_FRAME('Incomplete frame', i - s + length)
|
|
199
|
+
}
|
|
203
200
|
|
|
204
201
|
const payload = b.subarray(i, i + length)
|
|
205
202
|
|
package/lib/server.d.ts
CHANGED
|
@@ -7,9 +7,7 @@ import Buffer from 'bare-buffer'
|
|
|
7
7
|
import WebSocket from './socket'
|
|
8
8
|
import WebSocketError from './errors'
|
|
9
9
|
|
|
10
|
-
interface WebSocketServerOptions
|
|
11
|
-
extends HTTPServerConnectionOptions,
|
|
12
|
-
HTTPSServerConnectionOptions {
|
|
10
|
+
interface WebSocketServerOptions extends HTTPServerConnectionOptions, HTTPSServerConnectionOptions {
|
|
13
11
|
secure?: boolean
|
|
14
12
|
}
|
|
15
13
|
|
|
@@ -18,15 +16,14 @@ interface WebSocketServerEvents extends DuplexEvents {
|
|
|
18
16
|
listening: []
|
|
19
17
|
}
|
|
20
18
|
|
|
21
|
-
interface WebSocketServer<
|
|
22
|
-
|
|
23
|
-
> extends EventEmitter<M> {
|
|
19
|
+
interface WebSocketServer<M extends WebSocketServerEvents = WebSocketServerEvents>
|
|
20
|
+
extends EventEmitter<M> {
|
|
24
21
|
readonly listening: boolean
|
|
25
22
|
|
|
26
23
|
address(): TCPSocketAddress
|
|
27
|
-
close(cb?: (err
|
|
28
|
-
ref():
|
|
29
|
-
unref():
|
|
24
|
+
close(cb?: (err?: Error | null) => void): this
|
|
25
|
+
ref(): this
|
|
26
|
+
unref(): this
|
|
30
27
|
}
|
|
31
28
|
|
|
32
29
|
declare class WebSocketServer {
|
|
@@ -41,10 +38,7 @@ declare class WebSocketServer {
|
|
|
41
38
|
declare namespace WebSocketServer {
|
|
42
39
|
export { type WebSocketServerOptions, type WebSocketServerEvents }
|
|
43
40
|
|
|
44
|
-
export function handshake(
|
|
45
|
-
req: HTTPClientRequest,
|
|
46
|
-
cb: (err: WebSocketError | null) => void
|
|
47
|
-
): void
|
|
41
|
+
export function handshake(req: HTTPClientRequest, cb: (err: WebSocketError | null) => void): void
|
|
48
42
|
|
|
49
43
|
export function handshake(
|
|
50
44
|
req: HTTPClientRequest,
|
package/lib/server.js
CHANGED
|
@@ -44,15 +44,21 @@ module.exports = exports = class WebSocketServer extends EventEmitter {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
close(cb) {
|
|
47
|
-
|
|
47
|
+
this._server.close(cb)
|
|
48
|
+
|
|
49
|
+
return this
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
ref() {
|
|
51
53
|
this._server.ref()
|
|
54
|
+
|
|
55
|
+
return this
|
|
52
56
|
}
|
|
53
57
|
|
|
54
58
|
unref() {
|
|
55
59
|
this._server.unref()
|
|
60
|
+
|
|
61
|
+
return this
|
|
56
62
|
}
|
|
57
63
|
|
|
58
64
|
_onlistening() {
|
|
@@ -80,12 +86,7 @@ module.exports = exports = class WebSocketServer extends EventEmitter {
|
|
|
80
86
|
}
|
|
81
87
|
|
|
82
88
|
// https://datatracker.ietf.org/doc/html/rfc6455#section-4.2
|
|
83
|
-
exports.handshake = function handshake(
|
|
84
|
-
req,
|
|
85
|
-
socket = req.socket,
|
|
86
|
-
head = EMPTY,
|
|
87
|
-
cb
|
|
88
|
-
) {
|
|
89
|
+
exports.handshake = function handshake(req, socket = req.socket, head = EMPTY, cb) {
|
|
89
90
|
if (typeof socket === 'function') {
|
|
90
91
|
cb = socket
|
|
91
92
|
socket = req.socket
|
|
@@ -111,11 +112,7 @@ exports.handshake = function handshake(
|
|
|
111
112
|
return cb(errors.INVALID_KEY_HEADER())
|
|
112
113
|
}
|
|
113
114
|
|
|
114
|
-
const digest = crypto
|
|
115
|
-
.createHash('sha1')
|
|
116
|
-
.update(key)
|
|
117
|
-
.update(GUID)
|
|
118
|
-
.digest('base64')
|
|
115
|
+
const digest = crypto.createHash('sha1').update(key).update(GUID).digest('base64')
|
|
119
116
|
|
|
120
117
|
socket.write(
|
|
121
118
|
'HTTP/1.1 101 Web Socket Protocol Handshake' +
|
package/lib/socket.d.ts
CHANGED
|
@@ -18,8 +18,7 @@ interface WebSocketEvents extends DuplexEvents {
|
|
|
18
18
|
pong: [payload: unknown]
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
interface WebSocket<M extends WebSocketEvents = WebSocketEvents>
|
|
22
|
-
extends Duplex<M> {
|
|
21
|
+
interface WebSocket<M extends WebSocketEvents = WebSocketEvents> extends Duplex<M> {
|
|
23
22
|
ping(data: unknown): void
|
|
24
23
|
pong(data: unknown): void
|
|
25
24
|
}
|
package/lib/socket.js
CHANGED
|
@@ -24,8 +24,7 @@ module.exports = exports = class WebSocket extends Duplex {
|
|
|
24
24
|
|
|
25
25
|
// For Node.js compatibility
|
|
26
26
|
opts.host = opts.hostname || opts.host
|
|
27
|
-
opts.port =
|
|
28
|
-
typeof opts.port === 'string' ? parseInt(opts.port, 10) : opts.port
|
|
27
|
+
opts.port = typeof opts.port === 'string' ? parseInt(opts.port, 10) : opts.port
|
|
29
28
|
}
|
|
30
29
|
|
|
31
30
|
const { isServer = false, socket = null } = opts
|
|
@@ -40,7 +39,9 @@ module.exports = exports = class WebSocket extends Duplex {
|
|
|
40
39
|
this._pendingOpen = null
|
|
41
40
|
this._pendingWrite = null
|
|
42
41
|
|
|
43
|
-
this._buffer =
|
|
42
|
+
this._buffer = []
|
|
43
|
+
this._buffered = 0
|
|
44
|
+
this._frame = -1
|
|
44
45
|
|
|
45
46
|
if (socket !== null) this._attach(socket)
|
|
46
47
|
else this._connect(opts)
|
|
@@ -51,9 +52,7 @@ module.exports = exports = class WebSocket extends Duplex {
|
|
|
51
52
|
|
|
52
53
|
if (typeof data === 'string') data = Buffer.from(data)
|
|
53
54
|
|
|
54
|
-
this._socket.write(
|
|
55
|
-
new Frame(opcode.PING, data, { mask: this._mask }).toBuffer()
|
|
56
|
-
)
|
|
55
|
+
this._socket.write(new Frame(opcode.PING, data, { mask: this._mask }).toBuffer())
|
|
57
56
|
}
|
|
58
57
|
|
|
59
58
|
pong(data) {
|
|
@@ -61,9 +60,7 @@ module.exports = exports = class WebSocket extends Duplex {
|
|
|
61
60
|
|
|
62
61
|
if (typeof data === 'string') data = Buffer.from(data)
|
|
63
62
|
|
|
64
|
-
this._socket.write(
|
|
65
|
-
new Frame(opcode.PONG, data, { mask: this._mask }).toBuffer()
|
|
66
|
-
)
|
|
63
|
+
this._socket.write(new Frame(opcode.PONG, data, { mask: this._mask }).toBuffer())
|
|
67
64
|
}
|
|
68
65
|
|
|
69
66
|
_attach(socket) {
|
|
@@ -101,29 +98,27 @@ module.exports = exports = class WebSocket extends Duplex {
|
|
|
101
98
|
}
|
|
102
99
|
|
|
103
100
|
_ondata(data) {
|
|
104
|
-
|
|
105
|
-
|
|
101
|
+
this._buffer.push(data)
|
|
102
|
+
this._buffered += data.byteLength
|
|
106
103
|
|
|
107
|
-
while (this.
|
|
108
|
-
const
|
|
104
|
+
while (this._frame === -1 || this._frame <= this._buffered) {
|
|
105
|
+
const buffer = this._buffer.length === 1 ? this._buffer[0] : Buffer.concat(this._buffer)
|
|
109
106
|
|
|
110
|
-
|
|
111
|
-
try {
|
|
112
|
-
frame = Frame.decode(state)
|
|
113
|
-
} catch (err) {
|
|
114
|
-
return this.destroy(err)
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
if (frame === null) return
|
|
107
|
+
this._buffer = [buffer]
|
|
118
108
|
|
|
119
|
-
|
|
120
|
-
state.start === state.end ? null : this._buffer.subarray(state.start)
|
|
109
|
+
const state = { start: 0, end: buffer.length, buffer }
|
|
121
110
|
|
|
122
111
|
try {
|
|
123
|
-
this._onframe(
|
|
112
|
+
this._onframe(Frame.decode(state))
|
|
124
113
|
} catch (err) {
|
|
125
|
-
|
|
114
|
+
if (err.code === 'INCOMPLETE_FRAME') this._frame = err.status
|
|
115
|
+
else this.destroy(err)
|
|
116
|
+
return
|
|
126
117
|
}
|
|
118
|
+
|
|
119
|
+
this._buffered -= state.start
|
|
120
|
+
this._buffer = this._buffered > 0 ? [buffer.subarray(state.start)] : []
|
|
121
|
+
this._frame = -1
|
|
127
122
|
}
|
|
128
123
|
}
|
|
129
124
|
|
|
@@ -222,11 +217,9 @@ module.exports = exports = class WebSocket extends Duplex {
|
|
|
222
217
|
return cb(errors.INVALID_ENCODING())
|
|
223
218
|
}
|
|
224
219
|
|
|
225
|
-
const frame = new Frame(
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
{ mask: this._mask }
|
|
229
|
-
)
|
|
220
|
+
const frame = new Frame(encoding === 'buffer' ? opcode.BINARY : opcode.TEXT, data, {
|
|
221
|
+
mask: this._mask
|
|
222
|
+
})
|
|
230
223
|
|
|
231
224
|
if (this._socket.write(frame.toBuffer())) cb(null)
|
|
232
225
|
else this._pendingWrite = cb
|
|
@@ -260,11 +253,7 @@ exports.handshake = function handshake(req, cb) {
|
|
|
260
253
|
return cb(errors.INVALID_UPGRADE_HEADER())
|
|
261
254
|
}
|
|
262
255
|
|
|
263
|
-
const digest = crypto
|
|
264
|
-
.createHash('sha1')
|
|
265
|
-
.update(key)
|
|
266
|
-
.update(GUID)
|
|
267
|
-
.digest('base64')
|
|
256
|
+
const digest = crypto.createHash('sha1').update(key).update(GUID).digest('base64')
|
|
268
257
|
|
|
269
258
|
if (res.headers['sec-websocket-accept'] !== digest) {
|
|
270
259
|
return cb(errors.INVALID_ACCEPT_HEADER())
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bare-ws",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.4",
|
|
4
4
|
"description": "WebSocket library for JavaScript",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"bare-url": "^2.1.3",
|
|
49
49
|
"brittle": "^3.3.0",
|
|
50
50
|
"prettier": "^3.4.1",
|
|
51
|
-
"prettier-config-
|
|
51
|
+
"prettier-config-holepunch": "^2.0.0"
|
|
52
52
|
},
|
|
53
53
|
"peerDependencies": {
|
|
54
54
|
"bare-buffer": "*",
|