Repository: incubator-guacamole-client Updated Branches: refs/heads/master 5a9ad1119 -> bb0d79661
GUACAMOLE-250: Add tunnel implementation which reads static files via HTTP. Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/commit/f915862f Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/tree/f915862f Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/diff/f915862f Branch: refs/heads/master Commit: f915862f3b9472bd42a70b21e4be672be4dbee02 Parents: 5a9ad11 Author: Michael Jumper <mjum...@apache.org> Authored: Wed Jan 18 19:53:46 2017 -0800 Committer: Michael Jumper <mjum...@apache.org> Committed: Tue Apr 11 16:33:18 2017 -0700 ---------------------------------------------------------------------- .../src/main/webapp/modules/Tunnel.js | 181 +++++++++++++++++++ 1 file changed, 181 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/f915862f/guacamole-common-js/src/main/webapp/modules/Tunnel.js ---------------------------------------------------------------------- diff --git a/guacamole-common-js/src/main/webapp/modules/Tunnel.js b/guacamole-common-js/src/main/webapp/modules/Tunnel.js index 44013e8..e520177 100644 --- a/guacamole-common-js/src/main/webapp/modules/Tunnel.js +++ b/guacamole-common-js/src/main/webapp/modules/Tunnel.js @@ -1025,3 +1025,184 @@ Guacamole.ChainedTunnel = function(tunnelChain) { }; Guacamole.ChainedTunnel.prototype = new Guacamole.Tunnel(); + +/** + * Guacamole Tunnel which replays a Guacamole protocol dump from a static file + * received via HTTP. Instructions within the file are parsed and handled as + * quickly as possible, while the file is being downloaded. + * + * @constructor + * @augments Guacamole.Tunnel + * @param {String} url + * The URL of a Guacamole protocol dump. + * + * @param {Boolean} [crossDomain=false] + * Whether tunnel requests will be cross-domain, and thus must use CORS + * mechanisms and headers. By default, it is assumed that tunnel requests + * will be made to the same domain. + */ +Guacamole.StaticHTTPTunnel = function StaticHTTPTunnel(url, crossDomain) { + + /** + * Reference to this Guacamole.StaticHTTPTunnel. + * + * @private + */ + var tunnel = this; + + /** + * The current, in-progress HTTP request. If no request is currently in + * progress, this will be null. + * + * @private + * @type {XMLHttpRequest} + */ + var xhr = null; + + /** + * Changes the stored numeric state of this tunnel, firing the onstatechange + * event if the new state is different and a handler has been defined. + * + * @private + * @param {Number} state + * The new state of this tunnel. + */ + var setState = function setState(state) { + + // Notify only if state changes + if (state !== tunnel.state) { + tunnel.state = state; + if (tunnel.onstatechange) + tunnel.onstatechange(state); + } + + }; + + /** + * Returns the Guacamole protocol status code which most closely + * represents the given HTTP status code. + * + * @private + * @param {Number} httpStatus + * The HTTP status code to translate into a Guacamole protocol status + * code. + * + * @returns {Number} + * The Guacamole protocol status code which most closely represents the + * given HTTP status code. + */ + var getGuacamoleStatusCode = function getGuacamoleStatusCode(httpStatus) { + + // Translate status codes with known equivalents + switch (httpStatus) { + + // HTTP 400 - Bad request + case 400: + return Guacamole.Status.Code.CLIENT_BAD_REQUEST; + + // HTTP 403 - Forbidden + case 403: + return Guacamole.Status.Code.CLIENT_FORBIDDEN; + + // HTTP 404 - Resource not found + case 404: + return Guacamole.Status.Code.RESOURCE_NOT_FOUND; + + // HTTP 429 - Too many requests + case 429: + return Guacamole.Status.Code.CLIENT_TOO_MANY; + + // HTTP 503 - Server unavailable + case 503: + return Guacamole.Status.Code.SERVER_BUSY; + + } + + // Default all other codes to generic internal error + return Guacamole.Status.Code.SERVER_ERROR; + + }; + + this.sendMessage = function sendMessage(elements) { + // Do nothing + }; + + this.connect = function connect(data) { + + // Ensure any existing connection is killed + tunnel.disconnect(); + + // Connection is now starting + setState(Guacamole.Tunnel.State.CONNECTING); + + // Start a new connection + xhr = new XMLHttpRequest(); + xhr.open('GET', url); + xhr.withCredentials = !!crossDomain; + xhr.send(null); + + var offset = 0; + + // Create Guacamole protocol parser specifically for this connection + var parser = new Guacamole.Parser(); + + // Invoke tunnel's oninstruction handler for each parsed instruction + parser.oninstruction = function instructionReceived(opcode, args) { + if (tunnel.oninstruction) + tunnel.oninstruction(opcode, args); + }; + + // Continuously parse received data + xhr.onreadystatechange = function readyStateChanged() { + + // Parse while data is being received + if (xhr.readyState === 3 || xhr.readyState === 4) { + + // Connection is open + setState(Guacamole.Tunnel.State.OPEN); + + var buffer = xhr.responseText; + var length = buffer.length; + + // Parse only the portion of data which is newly received + if (offset < length) { + parser.receive(buffer.substring(offset)); + offset = length; + } + + } + + // Clean up and close when done + if (xhr.readyState === 4) + tunnel.disconnect(); + + }; + + // Reset state and close upon error + xhr.onerror = function httpError() { + + // Fail if file could not be downloaded via HTTP + if (tunnel.onerror) + tunnel.onerror(new Guacamole.Status(getGuacamoleStatusCode(xhr.status), xhr.statusText)); + + tunnel.disconnect(); + }; + + }; + + this.disconnect = function disconnect() { + + // Abort and dispose of XHR if a request is in progress + if (xhr) { + xhr.abort(); + xhr = null; + } + + // Connection is now closed + setState(Guacamole.Tunnel.State.CLOSED); + + }; + +}; + +Guacamole.StaticHTTPTunnel.prototype = new Guacamole.Tunnel();