diff --git a/static/client.html b/static/client.html
index 7382c44..01a6481 100644
--- a/static/client.html
+++ b/static/client.html
@@ -1491,6 +1491,9 @@
// ── File download handler (server-initiated file transfer) ──
client.onfile = function(stream, mimetype, filename) {
var reader = new Guacamole.BlobReader(stream, mimetype);
+ reader.onprogress = function(length) {
+ stream.sendAck('Received', Guacamole.Status.Code.SUCCESS);
+ };
reader.onend = function() {
var blob = reader.getBlob();
var a = document.createElement('a');
@@ -1502,6 +1505,7 @@
setTimeout(function() { URL.revokeObjectURL(a.href); }, 1000);
setFileStatus('Received file: ' + filename);
};
+ stream.sendAck('OK', Guacamole.Status.Code.SUCCESS);
};
function tracing_log(msg) {
diff --git a/tests/client-file-stream-ack.mjs b/tests/client-file-stream-ack.mjs
new file mode 100644
index 0000000..b3d125f
--- /dev/null
+++ b/tests/client-file-stream-ack.mjs
@@ -0,0 +1,41 @@
+import { readFile } from 'node:fs/promises';
+import { dirname, resolve, join } from 'node:path';
+import { fileURLToPath } from 'node:url';
+import vm from 'node:vm';
+import assert from 'node:assert/strict';
+
+const root = resolve(dirname(fileURLToPath(import.meta.url)), '..');
+const html = await readFile(join(root, 'static/client.html'), 'utf8');
+const marker = 'client.onfile = function(stream, mimetype, filename) {';
+const start = html.indexOf(marker);
+assert.notEqual(start, -1, 'client.onfile handler must exist');
+
+const end = html.indexOf('function tracing_log(msg) {', start);
+assert.ok(end > start, 'client onfile handler must be present');
+
+let reader;
+const acknowledgements = [];
+const client = {};
+const ctx = {
+ client,
+ Guacamole: {
+ BlobReader: class {
+ constructor() { reader = this; }
+ },
+ Status: { Code: { SUCCESS: 0 } }
+ }
+};
+vm.createContext(ctx);
+vm.runInContext(html.slice(start, end), ctx);
+
+const stream = {
+ sendAck(message, code) { acknowledgements.push({ message, code }); }
+};
+client.onfile(stream, 'text/plain', 'download.txt');
+assert.deepEqual(acknowledgements, [
+ { message: 'OK', code: 0 }
+], 'the stream should be accepted once the reader is ready');
+
+reader.onprogress();
+assert.deepEqual(acknowledgements.at(-1), { message: 'Received', code: 0 });
+console.log('client-file-stream-ack: ok');