class WebSocketResponse(HttpResponse): """Upgrade from a WSGI connection with the WebSocket handshake.""" status_code = 101 def __init__(self, environ, reader, writer, hdlr, hdlr_args, hdlr_kwargs): super().__init__() try: key = self.check_request(environ) except Exception: self.status_code = 400 self.content = "Invalid WebSocket handshake." else: self.create_headers(key) self.ws = WebSocket(reader, writer) self.ws_handler = hdlr(self.ws, *hdlr_args, **hdlr_kwargs) def check_request(self, environ): # Host and Origin checking isn't handled at this level. # RFC6455 - 4.2.1. Reading the Client's Opening Handshake assert environ['SERVER_PROTOCOL'] == 'HTTP/1.1' assert environ['HTTP_HOST'] # the server's authority isn't known assert environ['HTTP_UPGRADE'].lower() == 'websocket' assert any(token.strip() == 'upgrade' for token in environ['HTTP_CONNECTION'].lower().split(',')) assert len(base64.b64decode(environ['HTTP_SEC_WEBSOCKET_KEY'])) == 16 assert environ['HTTP_SEC_WEBSOCKET_VERSION'] == '13' return environ['HTTP_SEC_WEBSOCKET_KEY'] def create_headers(self, key): # Reset headers (private API!) self._headers = {} # RFC6455 - 4.2.2. Sending the Server's Opening Handshake guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" sha1 = hashlib.sha1((key + guid).encode()).digest() self['Upgrade'] = 'WebSocket' self['Connection'] = 'Upgrade' self['Sec-WebSocket-Accept'] = base64.b64encode(sha1) @tulip.coroutine def close(self): # This is where the magic happens. yield from self.ws_handler self.ws.close() super().close()
def __init__(self, environ, reader, writer, hdlr, hdlr_args, hdlr_kwargs): super().__init__() try: key = self.check_request(environ) except Exception: self.status_code = 400 self.content = "Invalid WebSocket handshake." else: self.create_headers(key) self.ws = WebSocket(reader, writer) self.ws_handler = hdlr(self.ws, *hdlr_args, **hdlr_kwargs)