@@ -63,9 +63,40 @@ class XzContext {
6363 }
6464}
6565
66+ // Simple mutex to serialize context creation and prevent resource exhaustion
67+ class ContextMutex {
68+ constructor ( ) {
69+ this . locked = false ;
70+ this . waitQueue = [ ] ;
71+ }
72+
73+ async acquire ( ) {
74+ if ( ! this . locked ) {
75+ this . locked = true ;
76+ return ;
77+ }
78+
79+ // Wait in queue
80+ return new Promise ( ( resolve ) => {
81+ this . waitQueue . push ( resolve ) ;
82+ } ) ;
83+ }
84+
85+ release ( ) {
86+ if ( this . waitQueue . length > 0 ) {
87+ const next = this . waitQueue . shift ( ) ;
88+ next ( ) ;
89+ } else {
90+ this . locked = false ;
91+ }
92+ }
93+ }
94+
6695export class XzReadableStream extends ReadableStream {
6796 static _moduleInstancePromise ;
6897 static _moduleInstance ;
98+ static _contextMutex = new ContextMutex ( ) ;
99+
69100 static async _getModuleInstance ( ) {
70101 const base64Wasm = xzwasmBytes . replace ( 'data:application/wasm;base64,' , '' ) ;
71102 const wasmBytes = Uint8Array . from ( atob ( base64Wasm ) , c => c . charCodeAt ( 0 ) ) . buffer ;
@@ -81,6 +112,8 @@ export class XzReadableStream extends ReadableStream {
81112
82113 super ( {
83114 async start ( controller ) {
115+ await XzReadableStream . _contextMutex . acquire ( ) ;
116+
84117 if ( ! XzReadableStream . _moduleInstance ) {
85118 await ( XzReadableStream . _moduleInstancePromise || ( XzReadableStream . _moduleInstancePromise = XzReadableStream . _getModuleInstance ( ) ) ) ;
86119 }
@@ -105,12 +138,14 @@ export class XzReadableStream extends ReadableStream {
105138 xzContext . resetOutputBuffer ( ) ;
106139
107140 if ( nextOutputResult . finished ) {
108- xzContext . dispose ( ) ; // Not sure if this always happens
141+ xzContext . dispose ( ) ;
142+ XzReadableStream . _contextMutex . release ( ) ;
109143 controller . close ( ) ;
110144 }
111145 } ,
112146 cancel ( ) {
113- xzContext . dispose ( ) ; // Not sure if this always happens
147+ xzContext . dispose ( ) ;
148+ XzReadableStream . _contextMutex . release ( ) ;
114149 return compressedReader . cancel ( ) ;
115150 }
116151 } ) ;
0 commit comments