mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 13:17:41 +00:00
GUACAMOLE-250: Add tunnel implementation which reads static files via HTTP.
This commit is contained in:
@@ -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();
|
||||
|
Reference in New Issue
Block a user