GUAC-867: Add periodic keep-alive ping to ensure the session does not perish while a connection is active.

This commit is contained in:
Michael Jumper
2014-10-13 03:25:31 -07:00
parent 115f647f7a
commit 04ba001f15
4 changed files with 111 additions and 7 deletions

View File

@@ -0,0 +1,54 @@
/*
* Copyright (C) 2014 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.net.basic;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.glyptodon.guacamole.net.auth.UserContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Dummy servlet which provides an endpoint for arbitrary requests intended to
* simply keep the HTTP session from expiring.
*
* @author Michael Jumper
*/
public class SessionKeepAlive extends RestrictedHttpServlet {
/**
* Logger for this class.
*/
private final Logger logger = LoggerFactory.getLogger(SessionKeepAlive.class);
@Override
protected void restrictedService(
UserContext context,
HttpServletRequest request, HttpServletResponse response) {
// Do nothing
logger.trace("Keep-alive signal received.");
}
}

View File

@@ -86,6 +86,17 @@
<url-pattern>/logout</url-pattern> <url-pattern>/logout</url-pattern>
</servlet-mapping> </servlet-mapping>
<!-- Session Keep-Alive Servlet -->
<servlet>
<description>Session keep-alive servlet.</description>
<servlet-name>SessionKeepAlive</servlet-name>
<servlet-class>org.glyptodon.guacamole.net.basic.SessionKeepAlive</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SessionKeepAlive</servlet-name>
<url-pattern>/keep-alive</url-pattern>
</servlet-mapping>
<!-- Clipboard State Servlet --> <!-- Clipboard State Servlet -->
<servlet> <servlet>
<description>Clipboard state servlet.</description> <description>Clipboard state servlet.</description>

View File

@@ -195,10 +195,11 @@ GuacUI.Client = {
}, },
/* Constants */ /* Constants */
"KEYBOARD_AUTO_RESIZE_INTERVAL" : 30, /* milliseconds */ "KEEP_ALIVE_INTERVAL" : 60000, /* milliseconds */
"RECONNECT_PERIOD" : 15, /* seconds */ "KEYBOARD_AUTO_RESIZE_INTERVAL" : 30, /* milliseconds */
"TEXT_INPUT_PADDING" : 128, /* characters */ "RECONNECT_PERIOD" : 15, /* seconds */
"TEXT_INPUT_PADDING" : 128, /* characters */
"TEXT_INPUT_PADDING_CODEPOINT" : 0x200B, "TEXT_INPUT_PADDING_CODEPOINT" : 0x200B,
/* Main application area */ /* Main application area */
@@ -1014,6 +1015,11 @@ GuacUI.Client.connect = function() {
connect_string += "&video=" + encodeURIComponent(mimetype); connect_string += "&video=" + encodeURIComponent(mimetype);
}); });
// Ping server every 10 seconds
var session_keep_alive = window.setInterval(function _session_keep_alive() {
GuacamoleService.KeepAlive.ping();
}, GuacUI.Client.KEEP_ALIVE_INTERVAL);
// Show connection errors from tunnel // Show connection errors from tunnel
tunnel.onerror = function(status) { tunnel.onerror = function(status) {
var message = GuacUI.Client.tunnel_errors[status.code] || GuacUI.Client.tunnel_errors.DEFAULT; var message = GuacUI.Client.tunnel_errors[status.code] || GuacUI.Client.tunnel_errors.DEFAULT;
@@ -1021,10 +1027,20 @@ GuacUI.Client.connect = function() {
GuacUI.Client.tunnel_auto_reconnect[status.code] && GuacUI.Client.RECONNECT_PERIOD); GuacUI.Client.tunnel_auto_reconnect[status.code] && GuacUI.Client.RECONNECT_PERIOD);
}; };
// Notify of disconnections (if not already notified of something else)
tunnel.onstatechange = function(state) { tunnel.onstatechange = function(state) {
if (state === Guacamole.Tunnel.State.CLOSED && !GuacUI.Client.visibleStatus)
GuacUI.Client.showStatus("Disconnected", "You have been disconnected. Reload the page to reconnect."); // Handle disconnect
if (state === Guacamole.Tunnel.State.CLOSED) {
// No need for a keep-alive ping if the tunnel is closed
window.clearInterval(session_keep_alive);
// Notify of disconnections (if not already notified of something else)
if (!GuacUI.Client.visibleStatus)
GuacUI.Client.showStatus("Disconnected",
"You have been disconnected. Reload the page to reconnect.");
}
}; };
// Connect // Connect

View File

@@ -1438,3 +1438,26 @@ GuacamoleService.Clipboard = {
} }
}; };
/**
* Collection of service functions which deal with the session keep-alive. Each
* function makes an explicit HTTP query to the server. In the case of the
* keep-alive ping, no response is expected, and any received response is
* ignored.
*/
GuacamoleService.KeepAlive = {
"ping" : function(parameters) {
// Construct request URL
var ping_url = "keep-alive";
if (parameters) ping_url += "?" + parameters;
// Send keep-alive "ping"
var xhr = new XMLHttpRequest();
xhr.open("GET", ping_url, true);
xhr.send(null);
}
};