@@ -109,6 +109,8 @@ Guacamole.BlobWriter = function BlobWriter(stream) {
109109
110110 var offset = 0 ;
111111 var reader = new FileReader ( ) ;
112+ var inFlight = false ;
113+ var ackHandled = false ;
112114
113115 /**
114116 * Reads the next chunk of the blob provided to
@@ -120,6 +122,10 @@ Guacamole.BlobWriter = function BlobWriter(stream) {
120122 */
121123 var readNextChunk = function readNextChunk ( ) {
122124
125+ // Prevent concurrent chunk operations
126+ if ( inFlight )
127+ return ;
128+
123129 // If no further chunks remain, inform of completion and stop
124130 if ( offset >= blob . size ) {
125131
@@ -132,6 +138,10 @@ Guacamole.BlobWriter = function BlobWriter(stream) {
132138
133139 }
134140
141+ // Mark that a chunk operation is now in progress
142+ inFlight = true ;
143+ ackHandled = false ;
144+
135145 // Obtain reference to next chunk as a new blob
136146 var chunk = slice ( blob , offset , offset + arrayBufferWriter . blobLength ) ;
137147 offset += arrayBufferWriter . blobLength ;
@@ -145,16 +155,20 @@ Guacamole.BlobWriter = function BlobWriter(stream) {
145155 // Send each chunk over the stream, continue reading the next chunk
146156 reader . onload = function chunkLoadComplete ( ) {
147157
148- // Send the successfully-read chunk
149- arrayBufferWriter . sendData ( reader . result ) ;
150-
151- // Continue sending more chunks after the latest chunk is
152- // acknowledged
158+ // Register ACK handler BEFORE sending data to prevent race condition
153159 arrayBufferWriter . onack = function sendMoreChunks ( status ) {
154160
161+ // Prevent duplicate ACK handling
162+ if ( ackHandled )
163+ return ;
164+ ackHandled = true ;
165+
155166 if ( guacWriter . onack )
156167 guacWriter . onack ( status ) ;
157168
169+ // Clear in-flight flag now that ACK is received
170+ inFlight = false ;
171+
158172 // Abort transfer if an error occurs
159173 if ( status . isError ( ) )
160174 return ;
@@ -163,16 +177,24 @@ Guacamole.BlobWriter = function BlobWriter(stream) {
163177 if ( guacWriter . onprogress )
164178 guacWriter . onprogress ( blob , offset - arrayBufferWriter . blobLength ) ;
165179
166- // Queue the next chunk for reading
167- readNextChunk ( ) ;
180+ // Schedule the next chunk for reading (avoid deep recursion)
181+ setTimeout ( function ( ) {
182+ readNextChunk ( ) ;
183+ } , 0 ) ;
168184
169185 } ;
170186
187+ // Send the successfully-read chunk
188+ arrayBufferWriter . sendData ( reader . result ) ;
189+
171190 } ;
172191
173192 // If an error prevents further reading, inform of error and stop
174193 reader . onerror = function chunkLoadFailed ( ) {
175194
195+ // Clear in-flight flag on error
196+ inFlight = false ;
197+
176198 // Fire error event, including the context of the error
177199 if ( guacWriter . onerror )
178200 guacWriter . onerror ( blob , offset , reader . error ) ;
0 commit comments