diff --git a/guacamole-common-js/src/main/resources/guacamole.js b/guacamole-common-js/src/main/resources/guacamole.js index 04aae5b50..e0fe0bf8f 100644 --- a/guacamole-common-js/src/main/resources/guacamole.js +++ b/guacamole-common-js/src/main/resources/guacamole.js @@ -364,6 +364,14 @@ Guacamole.OutputStream = function(client, index) { */ this.index = index; + /** + * Fired when the stream is being closed due to an error. + * + * @param {String} reason A human-readable reason describing the error. + * @param {Number} code The error code associated with the error. + */ + this.onerror = null; + /** * Writes the given base64-encoded data to this stream as a blob. * @@ -494,9 +502,12 @@ Guacamole.Client = function(tunnel) { // No initial streams var streams = []; - // Pool of available streams + // Pool of available stream indices var stream_indices = new Guacamole.IntegerPool(); + // Array of allocated output streams by index + var output_streams = []; + tunnel.onerror = function(message) { if (guac_client.onerror) guac_client.onerror(message); @@ -682,13 +693,14 @@ Guacamole.Client = function(tunnel) { // Create new stream guac_client.beginFileStream(index, mimetype, filename); - var stream = new Guacamole.OutputStream(guac_client, index); + var stream = output_streams[index] = new Guacamole.OutputStream(guac_client, index); // Override close() of stream to automatically free index var old_close = stream.close; stream.close = function() { old_close(); stream_indices.free(index); + delete output_streams[index]; }; // Return new, overridden stream @@ -717,7 +729,8 @@ Guacamole.Client = function(tunnel) { * is being closed. * * @event - * @param {String} error A human-readable description of the error. + * @param {String} reason A human-readable reason describing the error. + * @param {Number} code The error code associated with the error. */ this.onerror = null; @@ -862,6 +875,28 @@ Guacamole.Client = function(tunnel) { */ var instructionHandlers = { + "abort": function(parameters) { + + var stream_index = parseInt(parameters[0]); + var reason = parameters[1]; + var code = parameters[2]; + + // Get stream + var stream = output_streams[stream_index]; + + // Invalidate stream + if (stream) { + + // Signal error if handler defined + if (stream.onerror) + stream.onerror(reason, code); + + stream_indices.free(stream_index); + delete output_streams[stream_index]; + } + + }, + "arc": function(parameters) { var layer = getLayer(parseInt(parameters[0])); @@ -1085,8 +1120,16 @@ Guacamole.Client = function(tunnel) { }, "error": function(parameters) { - if (guac_client.onerror) guac_client.onerror(parameters[0]); + + var reason = parameters[0]; + var code = parameters[1]; + + // Call handler if defined + if (guac_client.onerror) + guac_client.onerror(reason, code); + guac_client.disconnect(); + }, "end": function(parameters) { diff --git a/guacamole/src/main/webapp/scripts/client-ui.js b/guacamole/src/main/webapp/scripts/client-ui.js index c6a5ec082..8904005f5 100644 --- a/guacamole/src/main/webapp/scripts/client-ui.js +++ b/guacamole/src/main/webapp/scripts/client-ui.js @@ -1104,12 +1104,21 @@ GuacUI.Client.attach = function(guac) { // Open file for writing var stream = GuacUI.Client.attachedClient.createFileStream(file.type, file.name); + var valid = true; var bytes = new Uint8Array(reader.result); var offset = 0; + + // Invalidate stream on all errors + stream.onerror = function() { + valid = false; + }; // Create upload callback function continueUpload() { + // Abort upload if stream is invalid + if (!valid) return false; + // Encode packet as base64 var slice = bytes.subarray(offset, offset+4096); var base64 = _get_base64(slice);