Example #1
0
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))
Example #2
0
 def test_http_error_exception(self):
     exc = errors.HttpErrorException(500, message='Internal error')
     self.assertEqual(exc.code, 500)
     self.assertEqual(exc.message, 'Internal error')
Example #3
0
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)