GUACAMOLE-44: Expose tunnel UUID to JavaScript. Document allowed internal use of the empty opcode.

This commit is contained in:
Michael Jumper
2016-04-13 18:09:34 -07:00
parent 12d35d4feb
commit d398509660
7 changed files with 77 additions and 16 deletions

View File

@@ -70,6 +70,14 @@ Guacamole.Tunnel = function() {
*/ */
this.receiveTimeout = 15000; this.receiveTimeout = 15000;
/**
* The UUID uniquely identifying this tunnel. If not yet known, this will
* be null.
*
* @type {String}
*/
this.uuid = null;
/** /**
* Fired whenever an error is encountered by the tunnel. * Fired whenever an error is encountered by the tunnel.
* *
@@ -99,6 +107,18 @@ Guacamole.Tunnel = function() {
}; };
/**
* The Guacamole protocol instruction opcode reserved for arbitrary internal
* use by tunnel implementations. The value of this opcode is guaranteed to be
* the empty string (""). Tunnel implementations may use this opcode for any
* purpose. It is currently used by the HTTP tunnel to mark the end of the HTTP
* response, and by the WebSocket tunnel to transmit the tunnel UUID.
*
* @constant
* @type {String}
*/
Guacamole.Tunnel.INTERNAL_DATA_OPCODE = '';
/** /**
* All possible tunnel states. * All possible tunnel states.
*/ */
@@ -152,8 +172,6 @@ Guacamole.HTTPTunnel = function(tunnelURL, crossDomain) {
*/ */
var tunnel = this; var tunnel = this;
var tunnel_uuid;
var TUNNEL_CONNECT = tunnelURL + "?connect"; var TUNNEL_CONNECT = tunnelURL + "?connect";
var TUNNEL_READ = tunnelURL + "?read:"; var TUNNEL_READ = tunnelURL + "?read:";
var TUNNEL_WRITE = tunnelURL + "?write:"; var TUNNEL_WRITE = tunnelURL + "?write:";
@@ -286,7 +304,7 @@ Guacamole.HTTPTunnel = function(tunnelURL, crossDomain) {
sendingMessages = true; sendingMessages = true;
var message_xmlhttprequest = new XMLHttpRequest(); var message_xmlhttprequest = new XMLHttpRequest();
message_xmlhttprequest.open("POST", TUNNEL_WRITE + tunnel_uuid); message_xmlhttprequest.open("POST", TUNNEL_WRITE + tunnel.uuid);
message_xmlhttprequest.withCredentials = withCredentials; message_xmlhttprequest.withCredentials = withCredentials;
message_xmlhttprequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=UTF-8"); message_xmlhttprequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=UTF-8");
@@ -517,7 +535,7 @@ Guacamole.HTTPTunnel = function(tunnelURL, crossDomain) {
// Make request, increment request ID // Make request, increment request ID
var xmlhttprequest = new XMLHttpRequest(); var xmlhttprequest = new XMLHttpRequest();
xmlhttprequest.open("GET", TUNNEL_READ + tunnel_uuid + ":" + (request_id++)); xmlhttprequest.open("GET", TUNNEL_READ + tunnel.uuid + ":" + (request_id++));
xmlhttprequest.withCredentials = withCredentials; xmlhttprequest.withCredentials = withCredentials;
xmlhttprequest.send(null); xmlhttprequest.send(null);
@@ -546,7 +564,7 @@ Guacamole.HTTPTunnel = function(tunnelURL, crossDomain) {
reset_timeout(); reset_timeout();
// Get UUID from response // Get UUID from response
tunnel_uuid = connect_xmlhttprequest.responseText; tunnel.uuid = connect_xmlhttprequest.responseText;
tunnel.state = Guacamole.Tunnel.State.OPEN; tunnel.state = Guacamole.Tunnel.State.OPEN;
if (tunnel.onstatechange) if (tunnel.onstatechange)
@@ -733,13 +751,7 @@ Guacamole.WebSocketTunnel = function(tunnelURL) {
socket = new WebSocket(tunnelURL + "?" + data, "guacamole"); socket = new WebSocket(tunnelURL + "?" + data, "guacamole");
socket.onopen = function(event) { socket.onopen = function(event) {
reset_timeout(); reset_timeout();
tunnel.state = Guacamole.Tunnel.State.OPEN;
if (tunnel.onstatechange)
tunnel.onstatechange(tunnel.state);
}; };
socket.onclose = function(event) { socket.onclose = function(event) {
@@ -794,8 +806,22 @@ Guacamole.WebSocketTunnel = function(tunnelURL) {
// Get opcode // Get opcode
var opcode = elements.shift(); var opcode = elements.shift();
// Update state and UUID when first instruction received
if (tunnel.state !== Guacamole.Tunnel.State.OPEN) {
// Associate tunnel UUID if received
if (opcode === Guacamole.Tunnel.INTERNAL_DATA_OPCODE)
tunnel.uuid = elements[0];
// Tunnel is now open and UUID is available
tunnel.state = Guacamole.Tunnel.State.OPEN;
if (tunnel.onstatechange)
tunnel.onstatechange(tunnel.state);
}
// Call instruction handler. // Call instruction handler.
if (tunnel.oninstruction) if (opcode !== Guacamole.Tunnel.INTERNAL_DATA_OPCODE && tunnel.oninstruction)
tunnel.oninstruction(opcode, elements); tunnel.oninstruction(opcode, elements);
// Clear elements // Clear elements
@@ -926,6 +952,7 @@ Guacamole.ChainedTunnel = function(tunnelChain) {
tunnel.onstatechange = chained_tunnel.onstatechange; tunnel.onstatechange = chained_tunnel.onstatechange;
tunnel.oninstruction = chained_tunnel.oninstruction; tunnel.oninstruction = chained_tunnel.oninstruction;
tunnel.onerror = chained_tunnel.onerror; tunnel.onerror = chained_tunnel.onerror;
chained_tunnel.uuid = tunnel.uuid;
committedTunnel = tunnel; committedTunnel = tunnel;
} }

View File

@@ -33,6 +33,16 @@ import org.apache.guacamole.io.GuacamoleWriter;
*/ */
public interface GuacamoleTunnel { public interface GuacamoleTunnel {
/**
* The Guacamole protocol instruction opcode reserved for arbitrary
* internal use by tunnel implementations. The value of this opcode is
* guaranteed to be the empty string (""). Tunnel implementations may use
* this opcode for any purpose. It is currently used by the HTTP tunnel to
* mark the end of the HTTP response, and by the WebSocket tunnel to
* transmit the tunnel UUID.
*/
static final String INTERNAL_DATA_OPCODE = "";
/** /**
* Acquires exclusive read access to the Guacamole instruction stream * Acquires exclusive read access to the Guacamole instruction stream
* and returns a GuacamoleReader for reading from that stream. * and returns a GuacamoleReader for reading from that stream.

View File

@@ -36,6 +36,7 @@ import org.apache.guacamole.io.GuacamoleWriter;
import org.apache.guacamole.net.GuacamoleTunnel; import org.apache.guacamole.net.GuacamoleTunnel;
import org.apache.guacamole.GuacamoleClientException; import org.apache.guacamole.GuacamoleClientException;
import org.apache.guacamole.GuacamoleConnectionClosedException; import org.apache.guacamole.GuacamoleConnectionClosedException;
import org.apache.guacamole.protocol.GuacamoleInstruction;
import org.apache.guacamole.protocol.GuacamoleStatus; import org.apache.guacamole.protocol.GuacamoleStatus;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -149,6 +150,12 @@ public abstract class GuacamoleWebSocketTunnelEndpoint extends Endpoint {
try { try {
// Send tunnel UUID
remote.sendText(new GuacamoleInstruction(
GuacamoleTunnel.INTERNAL_DATA_OPCODE,
tunnel.getUUID().toString()
).toString());
try { try {
// Attempt to read // Attempt to read

View File

@@ -124,10 +124,6 @@ public class TunnelRESTService {
GuacamoleSession session = authenticationService.getGuacamoleSession(authToken); GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
Map<String, StreamInterceptingTunnel> tunnels = session.getTunnels(); Map<String, StreamInterceptingTunnel> tunnels = session.getTunnels();
// STUB: For sake of testing, if only one tunnel exists, use that
if (tunnels.size() == 1)
tunnelUUID = tunnels.keySet().iterator().next();
// Pull tunnel with given UUID // Pull tunnel with given UUID
final StreamInterceptingTunnel tunnel = tunnels.get(tunnelUUID); final StreamInterceptingTunnel tunnel = tunnels.get(tunnelUUID);
if (tunnel == null) if (tunnel == null)

View File

@@ -30,6 +30,7 @@ import org.eclipse.jetty.websocket.WebSocket.Connection;
import org.eclipse.jetty.websocket.WebSocketServlet; import org.eclipse.jetty.websocket.WebSocketServlet;
import org.apache.guacamole.GuacamoleClientException; import org.apache.guacamole.GuacamoleClientException;
import org.apache.guacamole.GuacamoleConnectionClosedException; import org.apache.guacamole.GuacamoleConnectionClosedException;
import org.apache.guacamole.protocol.GuacamoleInstruction;
import org.apache.guacamole.tunnel.http.HTTPTunnelRequest; import org.apache.guacamole.tunnel.http.HTTPTunnelRequest;
import org.apache.guacamole.tunnel.TunnelRequest; import org.apache.guacamole.tunnel.TunnelRequest;
import org.apache.guacamole.protocol.GuacamoleStatus; import org.apache.guacamole.protocol.GuacamoleStatus;
@@ -136,6 +137,12 @@ public abstract class GuacamoleWebSocketTunnelServlet extends WebSocketServlet {
try { try {
// Send tunnel UUID
connection.sendMessage(new GuacamoleInstruction(
GuacamoleTunnel.INTERNAL_DATA_OPCODE,
tunnel.getUUID().toString()
).toString());
try { try {
// Attempt to read // Attempt to read

View File

@@ -30,6 +30,7 @@ import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.io.GuacamoleReader; import org.apache.guacamole.io.GuacamoleReader;
import org.apache.guacamole.io.GuacamoleWriter; import org.apache.guacamole.io.GuacamoleWriter;
import org.apache.guacamole.net.GuacamoleTunnel; import org.apache.guacamole.net.GuacamoleTunnel;
import org.apache.guacamole.protocol.GuacamoleInstruction;
import org.apache.guacamole.protocol.GuacamoleStatus; import org.apache.guacamole.protocol.GuacamoleStatus;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -127,6 +128,12 @@ public abstract class GuacamoleWebSocketTunnelListener implements WebSocketListe
try { try {
// Send tunnel UUID
remote.sendString(new GuacamoleInstruction(
GuacamoleTunnel.INTERNAL_DATA_OPCODE,
tunnel.getUUID().toString()
).toString());
try { try {
// Attempt to read // Attempt to read

View File

@@ -35,6 +35,7 @@ import org.apache.catalina.websocket.WebSocketServlet;
import org.apache.catalina.websocket.WsOutbound; import org.apache.catalina.websocket.WsOutbound;
import org.apache.guacamole.GuacamoleClientException; import org.apache.guacamole.GuacamoleClientException;
import org.apache.guacamole.GuacamoleConnectionClosedException; import org.apache.guacamole.GuacamoleConnectionClosedException;
import org.apache.guacamole.protocol.GuacamoleInstruction;
import org.apache.guacamole.tunnel.http.HTTPTunnelRequest; import org.apache.guacamole.tunnel.http.HTTPTunnelRequest;
import org.apache.guacamole.tunnel.TunnelRequest; import org.apache.guacamole.tunnel.TunnelRequest;
import org.apache.guacamole.protocol.GuacamoleStatus; import org.apache.guacamole.protocol.GuacamoleStatus;
@@ -164,6 +165,12 @@ public abstract class GuacamoleWebSocketTunnelServlet extends WebSocketServlet {
try { try {
// Send tunnel UUID
outbound.writeTextMessage(CharBuffer.wrap(new GuacamoleInstruction(
GuacamoleTunnel.INTERNAL_DATA_OPCODE,
tunnel.getUUID().toString()
).toString()));
try { try {
// Attempt to read // Attempt to read