22
33const { createInflateRaw, Z_DEFAULT_WINDOWBITS } = require ( 'node:zlib' )
44const { isValidClientWindowBits } = require ( './util' )
5+ const { MessageSizeExceededError } = require ( '../../core/errors' )
56
67const tail = Buffer . from ( [ 0x00 , 0x00 , 0xff , 0xff ] )
78const kBuffer = Symbol ( 'kBuffer' )
89const kLength = Symbol ( 'kLength' )
910
11+ // Default maximum decompressed message size: 4 MB
12+ const kDefaultMaxDecompressedSize = 4 * 1024 * 1024
13+
1014class PerMessageDeflate {
1115 /** @type {import('node:zlib').InflateRaw } */
1216 #inflate
1317
1418 #options = { }
1519
20+ /** @type {boolean } */
21+ #aborted = false
22+
23+ /** @type {Function|null } */
24+ #currentCallback = null
25+
26+ /**
27+ * @param {Map<string, string> } extensions
28+ */
1629 constructor ( extensions ) {
1730 this . #options. serverNoContextTakeover = extensions . has ( 'server_no_context_takeover' )
1831 this . #options. serverMaxWindowBits = extensions . get ( 'server_max_window_bits' )
@@ -24,6 +37,11 @@ class PerMessageDeflate {
2437 // payload of the message.
2538 // 2. Decompress the resulting data using DEFLATE.
2639
40+ if ( this . #aborted) {
41+ callback ( new MessageSizeExceededError ( ) )
42+ return
43+ }
44+
2745 if ( ! this . #inflate) {
2846 let windowBits = Z_DEFAULT_WINDOWBITS
2947
@@ -36,13 +54,37 @@ class PerMessageDeflate {
3654 windowBits = Number . parseInt ( this . #options. serverMaxWindowBits )
3755 }
3856
39- this . #inflate = createInflateRaw ( { windowBits } )
57+ try {
58+ this . #inflate = createInflateRaw ( { windowBits } )
59+ } catch ( err ) {
60+ callback ( err )
61+ return
62+ }
4063 this . #inflate[ kBuffer ] = [ ]
4164 this . #inflate[ kLength ] = 0
4265
4366 this . #inflate. on ( 'data' , ( data ) => {
44- this . #inflate[ kBuffer ] . push ( data )
67+ if ( this . #aborted) {
68+ return
69+ }
70+
4571 this . #inflate[ kLength ] += data . length
72+
73+ if ( this . #inflate[ kLength ] > kDefaultMaxDecompressedSize ) {
74+ this . #aborted = true
75+ this . #inflate. removeAllListeners ( )
76+ this . #inflate. destroy ( )
77+ this . #inflate = null
78+
79+ if ( this . #currentCallback) {
80+ const cb = this . #currentCallback
81+ this . #currentCallback = null
82+ cb ( new MessageSizeExceededError ( ) )
83+ }
84+ return
85+ }
86+
87+ this . #inflate[ kBuffer ] . push ( data )
4688 } )
4789
4890 this . #inflate. on ( 'error' , ( err ) => {
@@ -51,16 +93,22 @@ class PerMessageDeflate {
5193 } )
5294 }
5395
96+ this . #currentCallback = callback
5497 this . #inflate. write ( chunk )
5598 if ( fin ) {
5699 this . #inflate. write ( tail )
57100 }
58101
59102 this . #inflate. flush ( ( ) => {
103+ if ( this . #aborted || ! this . #inflate) {
104+ return
105+ }
106+
60107 const full = Buffer . concat ( this . #inflate[ kBuffer ] , this . #inflate[ kLength ] )
61108
62109 this . #inflate[ kBuffer ] . length = 0
63110 this . #inflate[ kLength ] = 0
111+ this . #currentCallback = null
64112
65113 callback ( null , full )
66114 } )
0 commit comments