protected void handleTunnelRequest(HttpServletRequest request,
            HttpServletResponse response) throws ServletException {

        try {

            String query = request.getQueryString();
            if (query == null)
                throw new GuacamoleClientException("No query string provided.");

            // If connect operation, call doConnect() and return tunnel
            // session token and UUID in response
            if (query.equals("connect")) {

                GuacamoleTunnel tunnel = doConnect(request);
                if (tunnel == null)
                    throw new GuacamoleResourceNotFoundException("No tunnel created.");

                // Register newly-created tunnel
                String tunnelSessionToken = generateToken();
                registerTunnel(tunnelSessionToken, tunnel);

                try {
                    // Ensure buggy browsers do not cache response
                    response.setHeader("Cache-Control", "no-cache");

                    // Include tunnel session token for future requests
                    response.setHeader(TUNNEL_TOKEN_HEADER_NAME, tunnelSessionToken);
                    
                    // Send UUID to client
                    response.getWriter().print(tunnel.getUUID().toString());
                }
                catch (IOException e) {
                    throw new GuacamoleServerException(e);
                }

                // Connection successful
                return;

            }

            // Pull tunnel-specific session token from request
            String tunnelSessionToken = request.getHeader(TUNNEL_TOKEN_HEADER_NAME);
            if (tunnelSessionToken == null)
                throw new GuacamoleClientException("The HTTP tunnel session "
                        + "token is required for all requests after "
                        + "connecting.");

            // Dispatch valid tunnel read/write operations
            if (query.startsWith(READ_PREFIX))
                doRead(request, response, tunnelSessionToken);
            else if (query.startsWith(WRITE_PREFIX))
                doWrite(request, response, tunnelSessionToken);

            // Otherwise, invalid operation
            else
                throw new GuacamoleClientException("Invalid tunnel operation: " + query);

        }

        // Catch any thrown guacamole exception and attempt to pass within the
        // HTTP response, logging each error appropriately.
        catch (GuacamoleClientException e) {
            logger.warn("HTTP tunnel request rejected: {}", e.getMessage());
            sendError(response, e.getStatus().getGuacamoleStatusCode(),
                    e.getStatus().getHttpStatusCode(), e.getMessage());
        }
        catch (GuacamoleException e) {
            logger.error("HTTP tunnel request failed: {}", e.getMessage());
            logger.debug("Internal error in HTTP tunnel.", e);
            sendError(response, e.getStatus().getGuacamoleStatusCode(),
                    e.getStatus().getHttpStatusCode(), "Internal server error.");
        }

    }
Dispatches every HTTP GET and POST request to the appropriate handler
function based on the query string.

@param request
    The HttpServletRequest associated with the GET or POST request
    received.

@param response
    The HttpServletResponse associated with the GET or POST request
    received.

@throws ServletException
    If an error occurs while servicing the request.
guacamole-common/src/main/java/org/apache/guacamole/servlet/GuacamoleHTTPTunnelServlet.java