From 312656c368d213d8e14f683928afa4dc8c6ee87b Mon Sep 17 00:00:00 2001 From: GulliblePsychologist Date: Tue, 14 Jan 2020 21:07:23 +0000 Subject: [PATCH] Fix for WebSocket failing when the page is refreshed --- evennia/server/portal/webclient.py | 29 +++++++++++++++---- evennia/web/utils/middleware.py | 7 +++++ .../static/webclient/js/webclient_gui.js | 1 - 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/evennia/server/portal/webclient.py b/evennia/server/portal/webclient.py index b501a3df2e..5584884819 100644 --- a/evennia/server/portal/webclient.py +++ b/evennia/server/portal/webclient.py @@ -30,15 +30,24 @@ _RE_SCREENREADER_REGEX = re.compile( ) _CLIENT_SESSIONS = mod_import(settings.SESSION_ENGINE).SessionStore - +# Status Code 1000: Normal Closure +# called when the connection was closed through JavaScript CLOSE_NORMAL = WebSocketServerProtocol.CLOSE_STATUS_CODE_NORMAL +# Status Code 1001: Going Away +# called when the browser is navigating away from the page +GOING_AWAY = WebSocketServerProtocol.CLOSE_STATUS_CODE_GOING_AWAY + class WebSocketClient(WebSocketServerProtocol, Session): """ Implements the server-side of the Websocket connection. """ + # nonce value, used to prevent the webclient from erasing the + # webclient_authenticated_uid value of csession on disconnect + nonce = None + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.protocol_key = "webclient/websocket" @@ -80,9 +89,11 @@ class WebSocketClient(WebSocketServerProtocol, Session): csession = self.get_client_session() # this sets self.csessid csessid = self.csessid uid = csession and csession.get("webclient_authenticated_uid", None) + nonce = csession and csession.get("webclient_authenticated_nonce", 0) if uid: # the client session is already logged in. self.uid = uid + self.nonce = nonce self.logged_in = True for old_session in self.sessionhandler.sessions_from_csessid(csessid): @@ -111,12 +122,20 @@ class WebSocketClient(WebSocketServerProtocol, Session): csession = self.get_client_session() if csession: - csession["webclient_authenticated_uid"] = None - csession.save() + # if the nonce is different, webclient_authenticated_uid has been + # set *before* this disconnect (disconnect called after a new client + # connects, which occurs in some 'fast' browsers like Google Chrome + # and Mobile Safari) + if csession.get("webclient_authenticated_nonce", None) == self.nonce: + csession["webclient_authenticated_uid"] = None + csession["webclient_authenticated_nonce"] = 0 + csession.save() self.logged_in = False self.sessionhandler.disconnect(self) - # autobahn-python: 1000 for a normal close, 3000-4999 for app. specific, + # autobahn-python: + # 1000 for a normal close, 1001 if the browser window is closed, + # 3000-4999 for app. specific, # in case anyone wants to expose this functionality later. # # sendClose() under autobahn/websocket/interfaces.py @@ -134,7 +153,7 @@ class WebSocketClient(WebSocketServerProtocol, Session): reason (str or None): Close reason as sent by the WebSocket peer. """ - if code == CLOSE_NORMAL: + if code == CLOSE_NORMAL or code == GOING_AWAY: self.disconnect(reason) else: self.websocket_close_code = code diff --git a/evennia/web/utils/middleware.py b/evennia/web/utils/middleware.py index d9e58256fe..aace1263f7 100644 --- a/evennia/web/utils/middleware.py +++ b/evennia/web/utils/middleware.py @@ -61,3 +61,10 @@ class SharedLoginMiddleware(object): login(request, account) except AttributeError: logger.log_trace() + + if csession.get("webclient_authenticated_uid", None): + # set a nonce to prevent the webclient from erasing the webclient_authenticated_uid value + csession["webclient_authenticated_nonce"] = csession.get("webclient_authenticated_nonce", 0) + 1 + # wrap around to prevent integer overflows + if csession["webclient_authenticated_nonce"] > 32: + csession["webclient_authenticated_nonce"] = 0 diff --git a/evennia/web/webclient/static/webclient/js/webclient_gui.js b/evennia/web/webclient/static/webclient/js/webclient_gui.js index 412827f153..d358c04c7c 100644 --- a/evennia/web/webclient/static/webclient/js/webclient_gui.js +++ b/evennia/web/webclient/static/webclient/js/webclient_gui.js @@ -284,7 +284,6 @@ $(document).ready(function() { // Event when closing window (have to have Evennia initialized) $(window).bind("beforeunload", plugin_handler.onBeforeUnload); - $(window).bind("unload", Evennia.connection.close); // Event when any key is pressed $(document).keydown(plugin_handler.onKeydown)