WebSocket-for-Python icon indicating copy to clipboard operation
WebSocket-for-Python copied to clipboard

WebSocket server responds incorrectly if connection is closed without a status code

Open robertknight opened this issue 5 years ago • 0 comments

If a client closes a connection without providing a status code, the WebSocket server will respond to the client with a close frame that has an invalid status code of 1005. This will cause some browsers, including Chrome and Safari, to display an error in the console.

Steps to reproduce:

I tested using Python 3.6.9 against commit 961c07ce16ce4eedc34ca1fdacd29442870feccc:

  1. Apply the following diff to examples/echo_gevent_server.py:
diff --git a/example/echo_gevent_server.py b/example/echo_gevent_server.py
index 100a536..3ed19f9 100644
--- a/example/echo_gevent_server.py
+++ b/example/echo_gevent_server.py
@@ -78,7 +78,7 @@ class EchoWebSocketApplication(object):
 
         start_response(status, headers)
 
-        return """<html>
+        response = """<html>
         <head>
         <script type='application/javascript' src='https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js'></script>
           <script type='application/javascript'>
@@ -120,6 +120,9 @@ class EchoWebSocketApplication(object):
                  $('#message').val("");
                  return false;
               });
+              $('#disconnect').click(function () {
+                ws.close();
+              });
             });
           </script>
         </head>
@@ -130,11 +133,13 @@ class EchoWebSocketApplication(object):
           <label for='message'>%(username)s: </label><input type='text' id='message' />
           <input id='send' type='submit' value='Send' />
           </form>
+          <button id='disconnect'>Disconnect</button>
         </body>
         </html>
         """ % {'username': "User%d" % random.randint(0, 100),
                'host': self.host,
                'port': self.port}
+        yield response.encode()
 
 if __name__ == '__main__':
     from ws4py import configure_logger

  1. Run python example/echo_gevent_server.py
  2. Open http://127.0.0.1:9000 in Chrome and click the "Disconnect" button
  3. The following error is displayed in the console:
Screenshot 2020-06-01 11 14 20

Notes:

It is correct for the server to internally synthesize the status code 1005 when it receives a close frame for the client with no status code, but this particular status code should never be sent back to the client. From the WebSocket RFC:

1005 is a reserved value and MUST NOT be set as a status code in a Close control frame by an endpoint. It is designated for use in applications expecting a status code to indicate that no status code was actually present.

In our application we worked around the issue on the client side by always setting a status code when closing the connection. See https://github.com/hypothesis/client/pull/1941 for details.

robertknight avatar Jun 01 '20 10:06 robertknight