mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 05:07:41 +00:00
GUACAMOLE-956: Decouple tunnel UUID from HTTP tunnel session identification.
This commit is contained in:
@@ -309,6 +309,25 @@ Guacamole.HTTPTunnel = function(tunnelURL, crossDomain, extraTunnelHeaders) {
|
|||||||
*/
|
*/
|
||||||
var extraHeaders = extraTunnelHeaders || {};
|
var extraHeaders = extraTunnelHeaders || {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the HTTP header containing the session token specific to the
|
||||||
|
* HTTP tunnel implementation.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @constant
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
var TUNNEL_TOKEN_HEADER = 'Guacamole-Tunnel-Token';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The session token currently assigned to this HTTP tunnel. All distinct
|
||||||
|
* HTTP tunnel connections will have their own dedicated session token.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
var tunnelSessionToken = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the configured additional headers to the given request.
|
* Adds the configured additional headers to the given request.
|
||||||
*
|
*
|
||||||
@@ -453,6 +472,7 @@ Guacamole.HTTPTunnel = function(tunnelURL, crossDomain, extraTunnelHeaders) {
|
|||||||
message_xmlhttprequest.withCredentials = withCredentials;
|
message_xmlhttprequest.withCredentials = withCredentials;
|
||||||
addExtraHeaders(message_xmlhttprequest, extraHeaders);
|
addExtraHeaders(message_xmlhttprequest, extraHeaders);
|
||||||
message_xmlhttprequest.setRequestHeader("Content-type", "application/octet-stream");
|
message_xmlhttprequest.setRequestHeader("Content-type", "application/octet-stream");
|
||||||
|
message_xmlhttprequest.setRequestHeader(TUNNEL_TOKEN_HEADER, tunnelSessionToken);
|
||||||
|
|
||||||
// Once response received, send next queued event.
|
// Once response received, send next queued event.
|
||||||
message_xmlhttprequest.onreadystatechange = function() {
|
message_xmlhttprequest.onreadystatechange = function() {
|
||||||
@@ -697,6 +717,7 @@ Guacamole.HTTPTunnel = function(tunnelURL, crossDomain, extraTunnelHeaders) {
|
|||||||
// 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.setRequestHeader(TUNNEL_TOKEN_HEADER, tunnelSessionToken);
|
||||||
xmlhttprequest.withCredentials = withCredentials;
|
xmlhttprequest.withCredentials = withCredentials;
|
||||||
addExtraHeaders(xmlhttprequest, extraHeaders);
|
addExtraHeaders(xmlhttprequest, extraHeaders);
|
||||||
xmlhttprequest.send(null);
|
xmlhttprequest.send(null);
|
||||||
@@ -728,8 +749,15 @@ Guacamole.HTTPTunnel = function(tunnelURL, crossDomain, extraTunnelHeaders) {
|
|||||||
|
|
||||||
reset_timeout();
|
reset_timeout();
|
||||||
|
|
||||||
// Get UUID from response
|
// Get UUID and HTTP-specific tunnel session token from response
|
||||||
tunnel.setUUID(connect_xmlhttprequest.responseText);
|
tunnel.setUUID(connect_xmlhttprequest.responseText);
|
||||||
|
tunnelSessionToken = connect_xmlhttprequest.getResponseHeader(TUNNEL_TOKEN_HEADER);
|
||||||
|
|
||||||
|
// Fail connect attempt if token is not successfully assigned
|
||||||
|
if (!tunnelSessionToken) {
|
||||||
|
close_tunnel(new Guacamole.Status(Guacamole.Status.Code.UPSTREAM_NOT_FOUND));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Mark as open
|
// Mark as open
|
||||||
tunnel.setState(Guacamole.Tunnel.State.OPEN);
|
tunnel.setState(Guacamole.Tunnel.State.OPEN);
|
||||||
|
@@ -58,7 +58,8 @@ class GuacamoleHTTPTunnelMap {
|
|||||||
private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
|
private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map of all tunnels that are using HTTP, indexed by tunnel UUID.
|
* Map of all tunnels that are using HTTP, indexed by their tunnel-specific
|
||||||
|
* session tokens.
|
||||||
*/
|
*/
|
||||||
private final ConcurrentMap<String, GuacamoleHTTPTunnel> tunnelMap =
|
private final ConcurrentMap<String, GuacamoleHTTPTunnel> tunnelMap =
|
||||||
new ConcurrentHashMap<String, GuacamoleHTTPTunnel>();
|
new ConcurrentHashMap<String, GuacamoleHTTPTunnel>();
|
||||||
@@ -141,22 +142,22 @@ class GuacamoleHTTPTunnelMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the GuacamoleTunnel having the given UUID, wrapped within a
|
* Returns the GuacamoleTunnel associated with the given tunnel-specific
|
||||||
* GuacamoleHTTPTunnel. If the no tunnel having the given UUID is
|
* session token, wrapped within a GuacamoleHTTPTunnel. If the no tunnel
|
||||||
* available, null is returned.
|
* is associated with the given token, null is returned.
|
||||||
*
|
*
|
||||||
* @param uuid
|
* @param tunnelSessionToken
|
||||||
* The UUID of the tunnel to retrieve.
|
* The tunnel-specific session token of the HTTP tunnel to retrieve.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* The GuacamoleTunnel having the given UUID, wrapped within a
|
* The GuacamoleTunnel associated with the given tunnel-specific
|
||||||
* GuacamoleHTTPTunnel, if such a tunnel exists, or null if there is no
|
* session token, wrapped within a GuacamoleHTTPTunnel, if such a
|
||||||
* such tunnel.
|
* tunnel exists, or null if there is no such tunnel.
|
||||||
*/
|
*/
|
||||||
public GuacamoleHTTPTunnel get(String uuid) {
|
public GuacamoleHTTPTunnel get(String tunnelSessionToken) {
|
||||||
|
|
||||||
// Update the last access time
|
// Update the last access time
|
||||||
GuacamoleHTTPTunnel tunnel = tunnelMap.get(uuid);
|
GuacamoleHTTPTunnel tunnel = tunnelMap.get(tunnelSessionToken);
|
||||||
if (tunnel != null)
|
if (tunnel != null)
|
||||||
tunnel.access();
|
tunnel.access();
|
||||||
|
|
||||||
@@ -169,32 +170,34 @@ class GuacamoleHTTPTunnelMap {
|
|||||||
* Registers that a new connection has been established using HTTP via the
|
* Registers that a new connection has been established using HTTP via the
|
||||||
* given GuacamoleTunnel.
|
* given GuacamoleTunnel.
|
||||||
*
|
*
|
||||||
* @param uuid
|
* @param tunnelSessionToken
|
||||||
* The UUID of the tunnel being added (registered).
|
* The tunnel-specific session token of the HTTP tunnel being added
|
||||||
|
* (registered).
|
||||||
*
|
*
|
||||||
* @param tunnel
|
* @param tunnel
|
||||||
* The GuacamoleTunnel being registered, its associated connection
|
* The GuacamoleTunnel being registered, its associated connection
|
||||||
* having just been established via HTTP.
|
* having just been established via HTTP.
|
||||||
*/
|
*/
|
||||||
public void put(String uuid, GuacamoleTunnel tunnel) {
|
public void put(String tunnelSessionToken, GuacamoleTunnel tunnel) {
|
||||||
tunnelMap.put(uuid, new GuacamoleHTTPTunnel(tunnel));
|
tunnelMap.put(tunnelSessionToken, new GuacamoleHTTPTunnel(tunnel));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the GuacamoleTunnel having the given UUID, if such a tunnel
|
* Removes the GuacamoleTunnel associated with the given tunnel-specific
|
||||||
* exists. The original tunnel is returned wrapped within a
|
* session token, if such a tunnel exists. The original tunnel is returned
|
||||||
* GuacamoleHTTPTunnel.
|
* wrapped within a GuacamoleHTTPTunnel.
|
||||||
*
|
*
|
||||||
* @param uuid
|
* @param tunnelSessionToken
|
||||||
* The UUID of the tunnel to remove (deregister).
|
* The tunnel-specific session token of the HTTP tunnel to remove
|
||||||
|
* (deregister).
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* The GuacamoleTunnel having the given UUID, if such a tunnel exists,
|
* The GuacamoleTunnel having the given tunnel-specific session token,
|
||||||
* wrapped within a GuacamoleHTTPTunnel, or null if no such tunnel
|
* if such a tunnel exists, wrapped within a GuacamoleHTTPTunnel, or
|
||||||
* exists and no removal was performed.
|
* null if no such tunnel exists and no removal was performed.
|
||||||
*/
|
*/
|
||||||
public GuacamoleHTTPTunnel remove(String uuid) {
|
public GuacamoleHTTPTunnel remove(String tunnelSessionToken) {
|
||||||
return tunnelMap.remove(uuid);
|
return tunnelMap.remove(tunnelSessionToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -25,6 +25,8 @@ import java.io.InputStreamReader;
|
|||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.util.Base64;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServlet;
|
import javax.servlet.http.HttpServlet;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
@@ -37,7 +39,6 @@ import org.apache.guacamole.GuacamoleServerException;
|
|||||||
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.GuacamoleStatus;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -53,10 +54,17 @@ public abstract class GuacamoleHTTPTunnelServlet extends HttpServlet {
|
|||||||
private final Logger logger = LoggerFactory.getLogger(GuacamoleHTTPTunnelServlet.class);
|
private final Logger logger = LoggerFactory.getLogger(GuacamoleHTTPTunnelServlet.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map of absolutely all active tunnels using HTTP, indexed by tunnel UUID.
|
* Map of absolutely all active tunnels using HTTP, indexed by tunnel
|
||||||
|
* session token.
|
||||||
*/
|
*/
|
||||||
private final GuacamoleHTTPTunnelMap tunnels = new GuacamoleHTTPTunnelMap();
|
private final GuacamoleHTTPTunnelMap tunnels = new GuacamoleHTTPTunnelMap();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the HTTP header that contains the tunnel-specific session
|
||||||
|
* token identifying each active and distinct HTTP tunnel connection.
|
||||||
|
*/
|
||||||
|
private static final String TUNNEL_TOKEN_HEADER_NAME = "Guacamole-Tunnel-Token";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The prefix of the query string which denotes a tunnel read operation.
|
* The prefix of the query string which denotes a tunnel read operation.
|
||||||
*/
|
*/
|
||||||
@@ -68,29 +76,64 @@ public abstract class GuacamoleHTTPTunnelServlet extends HttpServlet {
|
|||||||
private static final String WRITE_PREFIX = "write:";
|
private static final String WRITE_PREFIX = "write:";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The length of the read prefix, in characters.
|
* Instance of SecureRandom for generating the session token specific to
|
||||||
|
* each distinct HTTP tunnel connection.
|
||||||
*/
|
*/
|
||||||
private static final int READ_PREFIX_LENGTH = READ_PREFIX.length();
|
private final SecureRandom secureRandom = new SecureRandom();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The length of the write prefix, in characters.
|
* Instance of Base64.Encoder for encoding random session tokens as
|
||||||
|
* strings.
|
||||||
*/
|
*/
|
||||||
private static final int WRITE_PREFIX_LENGTH = WRITE_PREFIX.length();
|
private final Base64.Encoder encoder = Base64.getEncoder();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The length of every tunnel UUID, in characters.
|
* Generates a new, securely-random session token that may be used to
|
||||||
|
* represent the ongoing communication session of a distinct HTTP tunnel
|
||||||
|
* connection.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* A new, securely-random session token.
|
||||||
*/
|
*/
|
||||||
private static final int UUID_LENGTH = 36;
|
protected String generateToken() {
|
||||||
|
byte[] bytes = new byte[33];
|
||||||
|
secureRandom.nextBytes(bytes);
|
||||||
|
return encoder.encodeToString(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers the given tunnel such that future read/write requests to that
|
* Registers the given tunnel such that future read/write requests to that
|
||||||
* tunnel will be properly directed.
|
* tunnel will be properly directed.
|
||||||
*
|
*
|
||||||
|
* @deprecated
|
||||||
|
* This function has been deprecated in favor of {@link #registerTunnel(java.lang.String, org.apache.guacamole.net.GuacamoleTunnel)},
|
||||||
|
* which decouples identification of HTTP tunnel sessions from the
|
||||||
|
* tunnel UUID.
|
||||||
|
*
|
||||||
* @param tunnel
|
* @param tunnel
|
||||||
* The tunnel to register.
|
* The tunnel to register.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
protected void registerTunnel(GuacamoleTunnel tunnel) {
|
protected void registerTunnel(GuacamoleTunnel tunnel) {
|
||||||
tunnels.put(tunnel.getUUID().toString(), tunnel);
|
registerTunnel(tunnel.getUUID().toString(), tunnel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers the given HTTP tunnel such that future read/write requests
|
||||||
|
* including the given tunnel-specific session token will be properly
|
||||||
|
* directed. The session token must be unpredictable (securely-random) and
|
||||||
|
* unique across all active HTTP tunnels. It is recommended that each HTTP
|
||||||
|
* tunnel session token be obtained through calling {@link #generateToken()}.
|
||||||
|
*
|
||||||
|
* @param tunnelSessionToken
|
||||||
|
* The tunnel-specific session token to associate with the HTTP tunnel
|
||||||
|
* being registered.
|
||||||
|
*
|
||||||
|
* @param tunnel
|
||||||
|
* The tunnel to register.
|
||||||
|
*/
|
||||||
|
protected void registerTunnel(String tunnelSessionToken, GuacamoleTunnel tunnel) {
|
||||||
|
tunnels.put(tunnelSessionToken, tunnel);
|
||||||
logger.debug("Registered tunnel \"{}\".", tunnel.getUUID());
|
logger.debug("Registered tunnel \"{}\".", tunnel.getUUID());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,33 +141,56 @@ public abstract class GuacamoleHTTPTunnelServlet extends HttpServlet {
|
|||||||
* Deregisters the given tunnel such that future read/write requests to
|
* Deregisters the given tunnel such that future read/write requests to
|
||||||
* that tunnel will be rejected.
|
* that tunnel will be rejected.
|
||||||
*
|
*
|
||||||
|
* @deprecated
|
||||||
|
* This function has been deprecated in favor of {@link #deregisterTunnel(java.lang.String)},
|
||||||
|
* which decouples identification of HTTP tunnel sessions from the
|
||||||
|
* tunnel UUID.
|
||||||
|
*
|
||||||
* @param tunnel
|
* @param tunnel
|
||||||
* The tunnel to deregister.
|
* The tunnel to deregister.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
protected void deregisterTunnel(GuacamoleTunnel tunnel) {
|
protected void deregisterTunnel(GuacamoleTunnel tunnel) {
|
||||||
tunnels.remove(tunnel.getUUID().toString());
|
deregisterTunnel(tunnel.getUUID().toString());
|
||||||
logger.debug("Deregistered tunnel \"{}\".", tunnel.getUUID());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the tunnel with the given UUID, if it has been registered with
|
* Deregisters the HTTP tunnel associated with the given tunnel-specific
|
||||||
* registerTunnel() and not yet deregistered with deregisterTunnel().
|
* session token such that future read/write requests to that tunnel will
|
||||||
|
* be rejected. Each HTTP tunnel must be associated with a session token
|
||||||
|
* unique to that tunnel via a call {@link #registerTunnel(java.lang.String, org.apache.guacamole.net.GuacamoleTunnel)}.
|
||||||
*
|
*
|
||||||
* @param tunnelUUID
|
* @param tunnelSessionToken
|
||||||
* The UUID of registered tunnel.
|
* The tunnel-specific session token associated with the HTTP tunnel
|
||||||
|
* being deregistered.
|
||||||
|
*/
|
||||||
|
protected void deregisterTunnel(String tunnelSessionToken) {
|
||||||
|
GuacamoleTunnel tunnel = tunnels.remove(tunnelSessionToken);
|
||||||
|
if (tunnel != null)
|
||||||
|
logger.debug("Deregistered tunnel \"{}\".", tunnel.getUUID());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the tunnel associated with the given tunnel-specific session
|
||||||
|
* token, if it has been registered with {@link #registerTunnel(java.lang.String, org.apache.guacamole.net.GuacamoleTunnel)}
|
||||||
|
* and not yet deregistered with {@link #deregisterTunnel(java.lang.String)}.
|
||||||
|
*
|
||||||
|
* @param tunnelSessionToken
|
||||||
|
* The tunnel-specific session token associated with the HTTP tunnel to
|
||||||
|
* be retrieved.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* The tunnel corresponding to the given UUID.
|
* The tunnel corresponding to the given session token.
|
||||||
*
|
*
|
||||||
* @throws GuacamoleException
|
* @throws GuacamoleException
|
||||||
* If the requested tunnel does not exist because it has not yet been
|
* If the requested tunnel does not exist because it has not yet been
|
||||||
* registered or it has been deregistered.
|
* registered or it has been deregistered.
|
||||||
*/
|
*/
|
||||||
protected GuacamoleTunnel getTunnel(String tunnelUUID)
|
protected GuacamoleTunnel getTunnel(String tunnelSessionToken)
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
|
||||||
// Pull tunnel from map
|
// Pull tunnel from map
|
||||||
GuacamoleTunnel tunnel = tunnels.get(tunnelUUID);
|
GuacamoleTunnel tunnel = tunnels.get(tunnelSessionToken);
|
||||||
if (tunnel == null)
|
if (tunnel == null)
|
||||||
throw new GuacamoleResourceNotFoundException("No such tunnel.");
|
throw new GuacamoleResourceNotFoundException("No such tunnel.");
|
||||||
|
|
||||||
@@ -209,52 +275,54 @@ public abstract class GuacamoleHTTPTunnelServlet extends HttpServlet {
|
|||||||
if (query == null)
|
if (query == null)
|
||||||
throw new GuacamoleClientException("No query string provided.");
|
throw new GuacamoleClientException("No query string provided.");
|
||||||
|
|
||||||
// If connect operation, call doConnect() and return tunnel UUID
|
// If connect operation, call doConnect() and return tunnel
|
||||||
// in response.
|
// session token and UUID in response
|
||||||
if (query.equals("connect")) {
|
if (query.equals("connect")) {
|
||||||
|
|
||||||
GuacamoleTunnel tunnel = doConnect(request);
|
GuacamoleTunnel tunnel = doConnect(request);
|
||||||
if (tunnel != null) {
|
if (tunnel == null)
|
||||||
|
throw new GuacamoleResourceNotFoundException("No tunnel created.");
|
||||||
|
|
||||||
// Register newly-created tunnel
|
// Register newly-created tunnel
|
||||||
registerTunnel(tunnel);
|
String tunnelSessionToken = generateToken();
|
||||||
|
registerTunnel(tunnelSessionToken, tunnel);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Ensure buggy browsers do not cache response
|
// Ensure buggy browsers do not cache response
|
||||||
response.setHeader("Cache-Control", "no-cache");
|
response.setHeader("Cache-Control", "no-cache");
|
||||||
|
|
||||||
// Send UUID to client
|
// Include tunnel session token for future requests
|
||||||
response.getWriter().print(tunnel.getUUID().toString());
|
response.setHeader(TUNNEL_TOKEN_HEADER_NAME, tunnelSessionToken);
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
throw new GuacamoleServerException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Send UUID to client
|
||||||
|
response.getWriter().print(tunnel.getUUID().toString());
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
throw new GuacamoleServerException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Failed to connect
|
// Connection successful
|
||||||
else
|
return;
|
||||||
throw new GuacamoleResourceNotFoundException("No tunnel created.");
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If read operation, call doRead() with tunnel UUID, ignoring any
|
// Pull tunnel-specific session token from request
|
||||||
// characters following the tunnel UUID.
|
String tunnelSessionToken = request.getHeader(TUNNEL_TOKEN_HEADER_NAME);
|
||||||
else if (query.startsWith(READ_PREFIX))
|
if (tunnelSessionToken == null)
|
||||||
doRead(request, response, query.substring(
|
throw new GuacamoleClientException("The HTTP tunnel session "
|
||||||
READ_PREFIX_LENGTH,
|
+ "token is required for all requests after "
|
||||||
READ_PREFIX_LENGTH + UUID_LENGTH));
|
+ "connecting.");
|
||||||
|
|
||||||
// If write operation, call doWrite() with tunnel UUID, ignoring any
|
// Dispatch valid tunnel read/write operations
|
||||||
// characters following the tunnel UUID.
|
if (query.startsWith(READ_PREFIX))
|
||||||
|
doRead(request, response, tunnelSessionToken);
|
||||||
else if (query.startsWith(WRITE_PREFIX))
|
else if (query.startsWith(WRITE_PREFIX))
|
||||||
doWrite(request, response, query.substring(
|
doWrite(request, response, tunnelSessionToken);
|
||||||
WRITE_PREFIX_LENGTH,
|
|
||||||
WRITE_PREFIX_LENGTH + UUID_LENGTH));
|
|
||||||
|
|
||||||
// Otherwise, invalid operation
|
// Otherwise, invalid operation
|
||||||
else
|
else
|
||||||
throw new GuacamoleClientException("Invalid tunnel operation: " + query);
|
throw new GuacamoleClientException("Invalid tunnel operation: " + query);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Catch any thrown guacamole exception and attempt to pass within the
|
// Catch any thrown guacamole exception and attempt to pass within the
|
||||||
@@ -308,20 +376,20 @@ public abstract class GuacamoleHTTPTunnelServlet extends HttpServlet {
|
|||||||
* Any data to be sent to the client in response to the write request
|
* Any data to be sent to the client in response to the write request
|
||||||
* should be written to the response body of this HttpServletResponse.
|
* should be written to the response body of this HttpServletResponse.
|
||||||
*
|
*
|
||||||
* @param tunnelUUID
|
* @param tunnelSessionToken
|
||||||
* The UUID of the tunnel to read from, as specified in the write
|
* The tunnel-specific session token of the HTTP tunnel to read from,
|
||||||
* request. This tunnel must have been created by a previous call to
|
* as specified in the read request. This tunnel must have been created
|
||||||
* doConnect().
|
* by a previous call to doConnect().
|
||||||
*
|
*
|
||||||
* @throws GuacamoleException
|
* @throws GuacamoleException
|
||||||
* If an error occurs while handling the read request.
|
* If an error occurs while handling the read request.
|
||||||
*/
|
*/
|
||||||
protected void doRead(HttpServletRequest request,
|
protected void doRead(HttpServletRequest request,
|
||||||
HttpServletResponse response, String tunnelUUID)
|
HttpServletResponse response, String tunnelSessionToken)
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
|
||||||
// Get tunnel, ensure tunnel exists
|
// Get tunnel, ensure tunnel exists
|
||||||
GuacamoleTunnel tunnel = getTunnel(tunnelUUID);
|
GuacamoleTunnel tunnel = getTunnel(tunnelSessionToken);
|
||||||
|
|
||||||
// Ensure tunnel is open
|
// Ensure tunnel is open
|
||||||
if (!tunnel.isOpen())
|
if (!tunnel.isOpen())
|
||||||
@@ -371,7 +439,7 @@ public abstract class GuacamoleHTTPTunnelServlet extends HttpServlet {
|
|||||||
|
|
||||||
// Close tunnel immediately upon EOF
|
// Close tunnel immediately upon EOF
|
||||||
if (message == null) {
|
if (message == null) {
|
||||||
deregisterTunnel(tunnel);
|
deregisterTunnel(tunnelSessionToken);
|
||||||
tunnel.close();
|
tunnel.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -385,7 +453,7 @@ public abstract class GuacamoleHTTPTunnelServlet extends HttpServlet {
|
|||||||
catch (GuacamoleConnectionClosedException e) {
|
catch (GuacamoleConnectionClosedException e) {
|
||||||
|
|
||||||
// Deregister and close
|
// Deregister and close
|
||||||
deregisterTunnel(tunnel);
|
deregisterTunnel(tunnelSessionToken);
|
||||||
tunnel.close();
|
tunnel.close();
|
||||||
|
|
||||||
// End-of-instructions marker
|
// End-of-instructions marker
|
||||||
@@ -398,7 +466,7 @@ public abstract class GuacamoleHTTPTunnelServlet extends HttpServlet {
|
|||||||
catch (GuacamoleException e) {
|
catch (GuacamoleException e) {
|
||||||
|
|
||||||
// Deregister and close
|
// Deregister and close
|
||||||
deregisterTunnel(tunnel);
|
deregisterTunnel(tunnelSessionToken);
|
||||||
tunnel.close();
|
tunnel.close();
|
||||||
|
|
||||||
throw e;
|
throw e;
|
||||||
@@ -416,7 +484,7 @@ public abstract class GuacamoleHTTPTunnelServlet extends HttpServlet {
|
|||||||
logger.debug("Error writing to servlet output stream", e);
|
logger.debug("Error writing to servlet output stream", e);
|
||||||
|
|
||||||
// Deregister and close
|
// Deregister and close
|
||||||
deregisterTunnel(tunnel);
|
deregisterTunnel(tunnelSessionToken);
|
||||||
tunnel.close();
|
tunnel.close();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -439,19 +507,19 @@ public abstract class GuacamoleHTTPTunnelServlet extends HttpServlet {
|
|||||||
* @param response
|
* @param response
|
||||||
* The HttpServletResponse associated with the write request received.
|
* The HttpServletResponse associated with the write request received.
|
||||||
*
|
*
|
||||||
* @param tunnelUUID
|
* @param tunnelSessionToken
|
||||||
* The UUID of the tunnel to write to, as specified in the write
|
* The tunnel-specific session token of the HTTP tunnel to write to,
|
||||||
* request. This tunnel must have been created by a previous call to
|
* as specified in the write request. This tunnel must have been created
|
||||||
* doConnect().
|
* by a previous call to doConnect().
|
||||||
*
|
*
|
||||||
* @throws GuacamoleException
|
* @throws GuacamoleException
|
||||||
* If an error occurs while handling the write request.
|
* If an error occurs while handling the write request.
|
||||||
*/
|
*/
|
||||||
protected void doWrite(HttpServletRequest request,
|
protected void doWrite(HttpServletRequest request,
|
||||||
HttpServletResponse response, String tunnelUUID)
|
HttpServletResponse response, String tunnelSessionToken)
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
|
||||||
GuacamoleTunnel tunnel = getTunnel(tunnelUUID);
|
GuacamoleTunnel tunnel = getTunnel(tunnelSessionToken);
|
||||||
|
|
||||||
// We still need to set the content type to avoid the default of
|
// We still need to set the content type to avoid the default of
|
||||||
// text/html, as such a content type would cause some browsers to
|
// text/html, as such a content type would cause some browsers to
|
||||||
@@ -498,7 +566,7 @@ public abstract class GuacamoleHTTPTunnelServlet extends HttpServlet {
|
|||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
|
|
||||||
// Deregister and close
|
// Deregister and close
|
||||||
deregisterTunnel(tunnel);
|
deregisterTunnel(tunnelSessionToken);
|
||||||
tunnel.close();
|
tunnel.close();
|
||||||
|
|
||||||
throw new GuacamoleServerException("I/O Error sending data to server: " + e.getMessage(), e);
|
throw new GuacamoleServerException("I/O Error sending data to server: " + e.getMessage(), e);
|
||||||
|
Reference in New Issue
Block a user