@@ -24,6 +24,7 @@ const { PerMessageDeflate } = require('./permessage-deflate')
2424
2525class ByteParser extends Writable {
2626 #buffers = [ ]
27+ #fragmentsBytes = 0
2728 #byteOffset = 0
2829 #loop = false
2930
@@ -208,16 +209,14 @@ class ByteParser extends Writable {
208209 this . #state = parserStates . INFO
209210 } else {
210211 if ( ! this . #info. compressed ) {
211- this . #fragments . push ( body )
212+ this . writeFragments ( body )
212213
213214 // If the frame is not fragmented, a message has been received.
214215 // If the frame is fragmented, it will terminate with a fin bit set
215216 // and an opcode of 0 (continuation), therefore we handle that when
216217 // parsing continuation frames, not here.
217218 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 ( ) )
221220 }
222221
223222 this . #state = parserStates . INFO
@@ -228,7 +227,7 @@ class ByteParser extends Writable {
228227 return
229228 }
230229
231- this . #fragments . push ( data )
230+ this . writeFragments ( data )
232231
233232 if ( ! this . #info. fin ) {
234233 this . #state = parserStates . INFO
@@ -237,11 +236,10 @@ class ByteParser extends Writable {
237236 return
238237 }
239238
240- websocketMessageReceived ( this . #handler, this . #info. binaryType , Buffer . concat ( this . #fragments ) )
239+ websocketMessageReceived ( this . #handler, this . #info. binaryType , this . consumeFragments ( ) )
241240
242241 this . #loop = true
243242 this . #state = parserStates . INFO
244- this . #fragments. length = 0
245243 this . run ( callback )
246244 } )
247245
@@ -265,34 +263,70 @@ class ByteParser extends Writable {
265263 return emptyBuffer
266264 }
267265
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
270276 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 ( )
271314 }
272315
273- const buffer = Buffer . allocUnsafe ( n )
274316 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)
275319
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
291324 }
292325
293- this . #byteOffset -= n
326+ this . #fragments = [ ]
327+ this . #fragmentsBytes = 0
294328
295- return buffer
329+ return output
296330 }
297331
298332 parseCloseBody ( data ) {
0 commit comments