@@ -24,6 +24,7 @@ const { PerMessageDeflate } = require('./permessage-deflate')
24
24
25
25
class ByteParser extends Writable {
26
26
#buffers = [ ]
27
+ #fragmentsBytes = 0
27
28
#byteOffset = 0
28
29
#loop = false
29
30
@@ -208,16 +209,14 @@ class ByteParser extends Writable {
208
209
this . #state = parserStates . INFO
209
210
} else {
210
211
if ( ! this . #info. compressed ) {
211
- this . #fragments . push ( body )
212
+ this . writeFragments ( body )
212
213
213
214
// If the frame is not fragmented, a message has been received.
214
215
// If the frame is fragmented, it will terminate with a fin bit set
215
216
// and an opcode of 0 (continuation), therefore we handle that when
216
217
// parsing continuation frames, not here.
217
218
if ( ! this . #info. fragmented && this . #info. fin ) {
218
- const fullMessage = Buffer . concat ( this . #fragments)
219
- websocketMessageReceived ( this . #handler, this . #info. binaryType , fullMessage )
220
- this . #fragments. length = 0
219
+ websocketMessageReceived ( this . #handler, this . #info. binaryType , this . consumeFragments ( ) )
221
220
}
222
221
223
222
this . #state = parserStates . INFO
@@ -228,7 +227,7 @@ class ByteParser extends Writable {
228
227
return
229
228
}
230
229
231
- this . #fragments . push ( data )
230
+ this . writeFragments ( data )
232
231
233
232
if ( ! this . #info. fin ) {
234
233
this . #state = parserStates . INFO
@@ -237,11 +236,10 @@ class ByteParser extends Writable {
237
236
return
238
237
}
239
238
240
- websocketMessageReceived ( this . #handler, this . #info. binaryType , Buffer . concat ( this . #fragments ) )
239
+ websocketMessageReceived ( this . #handler, this . #info. binaryType , this . consumeFragments ( ) )
241
240
242
241
this . #loop = true
243
242
this . #state = parserStates . INFO
244
- this . #fragments. length = 0
245
243
this . run ( callback )
246
244
} )
247
245
@@ -265,34 +263,70 @@ class ByteParser extends Writable {
265
263
return emptyBuffer
266
264
}
267
265
268
- if ( this . #buffers[ 0 ] . length === n ) {
269
- this . #byteOffset -= this . #buffers[ 0 ] . length
266
+ this . #byteOffset -= n
267
+
268
+ const first = this . #buffers[ 0 ]
269
+
270
+ if ( first . length > n ) {
271
+ // replace with remaining buffer
272
+ this . #buffers[ 0 ] = first . subarray ( n , first . length )
273
+ return first . subarray ( 0 , n )
274
+ } else if ( first . length === n ) {
275
+ // prefect match
270
276
return this . #buffers. shift ( )
277
+ } else {
278
+ let offset = 0
279
+ // If Buffer.allocUnsafe is used, extra copies will be made because the offset is non-zero.
280
+ const buffer = Buffer . allocUnsafeSlow ( n )
281
+ while ( offset !== n ) {
282
+ const next = this . #buffers[ 0 ]
283
+ const length = next . length
284
+
285
+ if ( length + offset === n ) {
286
+ buffer . set ( this . #buffers. shift ( ) , offset )
287
+ break
288
+ } else if ( length + offset > n ) {
289
+ buffer . set ( next . subarray ( 0 , n - offset ) , offset )
290
+ this . #buffers[ 0 ] = next . subarray ( n - offset )
291
+ break
292
+ } else {
293
+ buffer . set ( this . #buffers. shift ( ) , offset )
294
+ offset += length
295
+ }
296
+ }
297
+
298
+ return buffer
299
+ }
300
+ }
301
+
302
+ writeFragments ( fragment ) {
303
+ this . #fragmentsBytes += fragment . length
304
+ this . #fragments. push ( fragment )
305
+ }
306
+
307
+ consumeFragments ( ) {
308
+ const fragments = this . #fragments
309
+
310
+ if ( fragments . length === 1 ) {
311
+ // single fragment
312
+ this . #fragmentsBytes = 0
313
+ return fragments . shift ( )
271
314
}
272
315
273
- const buffer = Buffer . allocUnsafe ( n )
274
316
let offset = 0
317
+ // If Buffer.allocUnsafe is used, extra copies will be made because the offset is non-zero.
318
+ const output = Buffer . allocUnsafeSlow ( this . #fragmentsBytes)
275
319
276
- while ( offset !== n ) {
277
- const next = this . #buffers[ 0 ]
278
- const { length } = next
279
-
280
- if ( length + offset === n ) {
281
- buffer . set ( this . #buffers. shift ( ) , offset )
282
- break
283
- } else if ( length + offset > n ) {
284
- buffer . set ( next . subarray ( 0 , n - offset ) , offset )
285
- this . #buffers[ 0 ] = next . subarray ( n - offset )
286
- break
287
- } else {
288
- buffer . set ( this . #buffers. shift ( ) , offset )
289
- offset += next . length
290
- }
320
+ for ( let i = 0 ; i < fragments . length ; ++ i ) {
321
+ const buffer = fragments [ i ]
322
+ output . set ( buffer , offset )
323
+ offset += buffer . length
291
324
}
292
325
293
- this . #byteOffset -= n
326
+ this . #fragments = [ ]
327
+ this . #fragmentsBytes = 0
294
328
295
- return buffer
329
+ return output
296
330
}
297
331
298
332
parseCloseBody ( data ) {
0 commit comments