def do_handshake(method, headers, transport): """Prepare WebSocket handshake. It return http response code, response headers, websocket parser, websocket writer. It does not perform any IO.""" # WebSocket accepts only GET if method.upper() != 'GET': raise errors.HttpErrorException(405, headers=(('Allow', 'GET'),)) headers = dict(((hdr, val) for hdr, val in headers if hdr in WS_HDRS)) if 'websocket' != headers.get('UPGRADE', '').lower().strip(): raise errors.HttpBadRequest( 'No WebSocket UPGRADE hdr: {}\n' 'Can "Upgrade" only to "WebSocket".'.format( headers.get('UPGRADE'))) if 'upgrade' not in headers.get('CONNECTION', '').lower(): raise errors.HttpBadRequest( 'No CONNECTION upgrade hdr: {}'.format( headers.get('CONNECTION'))) # check supported version version = headers.get('SEC-WEBSOCKET-VERSION') if version not in ('13', '8', '7'): raise errors.HttpBadRequest( 'Unsupported version: {}'.format(version)) # check client handshake for validity key = headers.get('SEC-WEBSOCKET-KEY') try: if not key or len(base64.b64decode(key)) != 16: raise errors.HttpBadRequest( 'Handshake error: {!r}'.format(key)) except binascii.Error: raise errors.HttpBadRequest( 'Handshake error: {!r}'.format(key)) from None # response code, headers, parser, writer return (101, (('UPGRADE', 'websocket'), ('CONNECTION', 'upgrade'), ('TRANSFER-ENCODING', 'chunked'), ('SEC-WEBSOCKET-ACCEPT', base64.b64encode( hashlib.sha1(key.encode() + WS_KEY).digest()).decode())), WebSocketParser, WebSocketWriter(transport))
def test_http_error_exception(self): exc = errors.HttpErrorException(500, message='Internal error') self.assertEqual(exc.code, 500) self.assertEqual(exc.message, 'Internal error')
def do_handshake(method, headers, transport, protocols=()): """Prepare WebSocket handshake. It return http response code, response headers, websocket parser, websocket writer. It does not perform any IO. `protocols` is a sequence of known protocols. On successful handshake, the returned response headers contain the first protocol in this list which the server also knows.""" # WebSocket accepts only GET if method.upper() != 'GET': raise errors.HttpErrorException(405, headers=(('Allow', 'GET'), )) if 'websocket' != headers.get('UPGRADE', '').lower().strip(): raise errors.HttpBadRequest( 'No WebSocket UPGRADE hdr: {}\n' 'Can "Upgrade" only to "WebSocket".'.format( headers.get('UPGRADE'))) if 'upgrade' not in headers.get('CONNECTION', '').lower(): raise errors.HttpBadRequest('No CONNECTION upgrade hdr: {}'.format( headers.get('CONNECTION'))) # find common sub-protocol between client and server protocol = None if 'SEC-WEBSOCKET-PROTOCOL' in headers: req_protocols = { str(proto.strip()) for proto in headers['SEC-WEBSOCKET-PROTOCOL'].split(',') } for proto in protocols: if proto in req_protocols: protocol = proto break else: raise errors.HttpBadRequest( 'Client protocols {!r} don’t overlap server-known ones {!r}'. format(protocols, req_protocols)) # check supported version version = headers.get('SEC-WEBSOCKET-VERSION') if version not in ('13', '8', '7'): raise errors.HttpBadRequest('Unsupported version: {}'.format(version)) # check client handshake for validity key = headers.get('SEC-WEBSOCKET-KEY') try: if not key or len(base64.b64decode(key)) != 16: raise errors.HttpBadRequest('Handshake error: {!r}'.format(key)) except binascii.Error: raise errors.HttpBadRequest( 'Handshake error: {!r}'.format(key)) from None response_headers = [ ('UPGRADE', 'websocket'), ('CONNECTION', 'upgrade'), ('TRANSFER-ENCODING', 'chunked'), ('SEC-WEBSOCKET-ACCEPT', base64.b64encode(hashlib.sha1(key.encode() + WS_KEY).digest()).decode()) ] if protocol: response_headers.append(('SEC-WEBSOCKET-PROTOCOL', protocol)) # response code, headers, parser, writer, protocol return (101, response_headers, WebSocketParser, WebSocketWriter(transport), protocol)