Example #1
0
async def wrap_server_stream(nursery,
                             stream,
                             message_queue_size=MESSAGE_QUEUE_SIZE,
                             max_message_size=MAX_MESSAGE_SIZE):
    '''
    Wrap an arbitrary stream in a server-side WebSocket.

    This is a low-level function only needed in rare cases. In most cases, you
    should use :func:`serve_websocket`.

    :param nursery: A nursery to run background tasks in.
    :param stream: A stream to be wrapped.
    :param int message_queue_size: The maximum number of messages that will be
        buffered in the library's internal message queue.
    :param int max_message_size: The maximum message size as measured by
        ``len()``. If a message is received that is larger than this size,
        then the connection is closed with code 1009 (Message Too Big).
    :type stream: trio.abc.Stream
    :rtype: WebSocketConnection
    '''
    wsproto = wsconnection.WSConnection(wsconnection.SERVER)
    connection = WebSocketConnection(stream,
                                     wsproto,
                                     message_queue_size=message_queue_size,
                                     max_message_size=max_message_size)
    nursery.start_soon(connection._reader_task)
    request = await connection._get_request()
    return request
Example #2
0
async def wrap_client_stream(nursery, stream, host, resource, *,
    subprotocols=None, message_queue_size=MESSAGE_QUEUE_SIZE,
    max_message_size=MAX_MESSAGE_SIZE):
    '''
    Wrap an arbitrary stream in a WebSocket connection.

    This is a low-level function only needed in rare cases. In most cases, you
    should use :func:`open_websocket` or :func:`open_websocket_url`.

    :param nursery: A Trio nursery to run background tasks in.
    :param stream: A Trio stream to be wrapped.
    :type stream: trio.abc.Stream
    :param str host: A host string that will be sent in the ``Host:`` header.
    :param str resource: A resource string, i.e. the path component to be
        accessed on the server.
    :param subprotocols: An iterable of strings representing preferred
        subprotocols.
    :param int message_queue_size: The maximum number of messages that will be
        buffered in the library's internal message queue.
    :param int max_message_size: The maximum message size as measured by
        ``len()``. If a message is received that is larger than this size,
        then the connection is closed with code 1009 (Message Too Big).
    :rtype: WebSocketConnection
    '''
    wsproto = wsconnection.WSConnection(wsconnection.CLIENT, host=host,
        resource=resource, subprotocols=subprotocols)
    connection = WebSocketConnection(stream, wsproto, path=resource,
        message_queue_size=message_queue_size,
        max_message_size=max_message_size)
    nursery.start_soon(connection._reader_task)
    await connection._open_handshake.wait()
    return connection
Example #3
0
    async def _handle_connection(self, stream):
        '''
        Handle an incoming connection by spawning a connection background task
        and a handler task inside a new nursery.

        :param stream:
        :type stream: trio.abc.Stream
        '''
        async with trio.open_nursery() as nursery:
            wsproto = wsconnection.WSConnection(wsconnection.SERVER)
            connection = WebSocketConnection(
                stream,
                wsproto,
                message_queue_size=self._message_queue_size,
                max_message_size=self._max_message_size)
            nursery.start_soon(connection._reader_task)
            with trio.move_on_after(self._connect_timeout) as connect_scope:
                request = await connection._get_request()
            if connect_scope.cancelled_caught:
                nursery.cancel_scope.cancel()
                await stream.aclose()
                return
            try:
                await self._handler(request)
            finally:
                with trio.move_on_after(self._disconnect_timeout):
                    # aclose() will shut down the reader task even if its
                    # cancelled:
                    await connection.aclose()
Example #4
0
    async def connect(self, nursery):
        '''
        Connect to WebSocket server.

        :param nursery: a Trio nursery to run background connection tasks in
        :raises: OSError if connection attempt fails
        '''
        logger.info('Connecting to http%s://%s:%d/%s',
                    '' if self._ssl is None else 's', self._host, self._port,
                    self._resource)
        if self._ssl is None:
            stream = await trio.open_tcp_stream(self._host, self._port)
        else:
            stream = await trio.open_ssl_over_tcp_stream(self._host,
                                                         self._port,
                                                         ssl_context=self._ssl,
                                                         https_compatible=True)
        if self._port in (80, 443):
            host_header = self._host
        else:
            host_header = '{}:{}'.format(self._host, self._port)
        wsproto = wsconnection.WSConnection(wsconnection.CLIENT,
                                            host=host_header,
                                            resource=self._resource)
        connection = WebSocketConnection(stream, wsproto)
        nursery.start_soon(connection._reader_task)
        return connection
Example #5
0
 async def _handle_connection(self, stream):
     ''' Handle an incoming connection. '''
     async with trio.open_nursery() as nursery:
         wsproto = wsconnection.WSConnection(wsconnection.SERVER)
         connection = WebSocketConnection(stream, wsproto)
         nursery.start_soon(connection._reader_task)
         nursery.start_soon(self._handler, connection)
Example #6
0
async def connect_websocket(nursery, host, port, resource, *, use_ssl,
    subprotocols=None, message_queue_size=MESSAGE_QUEUE_SIZE,
    max_message_size=MAX_MESSAGE_SIZE):
    '''
    Return an open WebSocket client connection to a host.

    This function is used to specify a custom nursery to run connection
    background tasks in. The caller is responsible for closing the connection.

    If you don't need a custom nursery, you should probably use
    :func:`open_websocket` instead.

    :param nursery: A Trio nursery to run background tasks in.
    :param str host: The host to connect to.
    :param int port: The port to connect to.
    :param str resource: The resource, i.e. URL path.
    :type use_ssl: bool or ssl.SSLContext
    :param subprotocols: An iterable of strings representing preferred
        subprotocols.
    :param int message_queue_size: The maximum number of messages that will be
        buffered in the library's internal message queue.
    :param int max_message_size: The maximum message size as measured by
        ``len()``. If a message is received that is larger than this size,
        then the connection is closed with code 1009 (Message Too Big).
    :rtype: WebSocketConnection
    '''
    if use_ssl == True:
        ssl_context = ssl.create_default_context()
    elif use_ssl == False:
        ssl_context = None
    elif isinstance(use_ssl, ssl.SSLContext):
        ssl_context = use_ssl
    else:
        raise TypeError('`use_ssl` argument must be bool or ssl.SSLContext')

    logger.debug('Connecting to ws%s://%s:%d%s',
        '' if ssl_context is None else 's', host, port, resource)
    if ssl_context is None:
        stream = await trio.open_tcp_stream(host, port)
    else:
        stream = await trio.open_ssl_over_tcp_stream(host, port,
            ssl_context=ssl_context, https_compatible=True)
    if port in (80, 443):
        host_header = host
    else:
        host_header = '{}:{}'.format(host, port)
    wsproto = wsconnection.WSConnection(wsconnection.CLIENT,
        host=host_header, resource=resource, subprotocols=subprotocols)
    connection = WebSocketConnection(stream, wsproto, path=resource,
        message_queue_size=message_queue_size,
        max_message_size=max_message_size)
    nursery.start_soon(connection._reader_task)
    await connection._open_handshake.wait()
    return connection
Example #7
0
    async def _handle_connection(self, stream):
        '''
        Handle an incoming connection by spawning a connection background task
        and a handler task inside a new nursery.

        :param stream:
        :type stream: trio.abc.Stream
        '''
        async with trio.open_nursery() as nursery:
            wsproto = wsconnection.WSConnection(wsconnection.SERVER)
            connection = WebSocketConnection(stream, wsproto)
            nursery.start_soon(connection._reader_task)
            await connection._open_handshake.wait()
            nursery.start_soon(self._handler, connection)
Example #8
0
async def wrap_server_stream(nursery, stream):
    '''
    Wrap an arbitrary stream in a server-side ``WebSocketConnection``.

    This is a low-level function only needed in rare cases. Most users should
    call ``serve_websocket()`.

    :param nursery: A Trio nursery to run background tasks in.
    :param stream: A Trio stream to be wrapped.
    :param task_status: part of Trio nursery start protocol
    :rtype: WebSocketConnection
    '''
    wsproto = wsconnection.WSConnection(wsconnection.SERVER)
    connection = WebSocketConnection(stream, wsproto)
    nursery.start_soon(connection._reader_task)
    await connection._open_handshake.wait()
    return connection
Example #9
0
async def connect_websocket(nursery, host, port, resource, use_ssl):
    '''
    Return a WebSocket client connection to a host.

    Most users should use ``open_websocket(…)`` instead of this function. This
    function is not an async context manager, and it requires a nursery argument
    for the connection's background task[s]. The caller is responsible for
    closing the connection.

    :param nursery: a Trio nursery to run background tasks in
    :param str host: the host to connect to
    :param int port: the port to connect to
    :param str resource: the resource a.k.a. path
    :param use_ssl: a bool or SSLContext
    :rtype: WebSocketConnection
    '''
    if use_ssl == True:
        ssl_context = ssl.create_default_context()
    elif use_ssl == False:
        ssl_context = None
    elif isinstance(use_ssl, ssl.SSLContext):
        ssl_context = use_ssl
    else:
        raise TypeError('`use_ssl` argument must be bool or ssl.SSLContext')

    logger.debug('Connecting to ws%s://%s:%d%s',
        '' if ssl_context is None else 's', host, port, resource)
    if ssl_context is None:
        stream = await trio.open_tcp_stream(host, port)
    else:
        stream = await trio.open_ssl_over_tcp_stream(host, port,
            ssl_context=ssl_context, https_compatible=True)
    if port in (80, 443):
        host_header = host
    else:
        host_header = '{}:{}'.format(host, port)
    wsproto = wsconnection.WSConnection(wsconnection.CLIENT,
        host=host_header, resource=resource)
    connection = WebSocketConnection(stream, wsproto, path=resource)
    nursery.start_soon(connection._reader_task)
    await connection._open_handshake.wait()
    return connection
Example #10
0
async def wrap_client_stream(nursery, stream, host, resource):
    '''
    Wrap an arbitrary stream in a client-side ``WebSocketConnection``.

    This is a low-level function only needed in rare cases. Most users should
    call ``open_websocket()`` or ``open_websocket_url()``.

    :param nursery: A Trio nursery to run background tasks in.
    :param stream: A Trio stream to be wrapped.
    :param str host: A host string that will be sent in the ``Host:`` header.
    :param str resource: A resource string, i.e. the path component to be
        accessed on the server.
    :rtype: WebSocketConnection
    '''
    wsproto = wsconnection.WSConnection(wsconnection.CLIENT, host=host,
        resource=resource)
    connection = WebSocketConnection(stream, wsproto, path=resource)
    nursery.start_soon(connection._reader_task)
    await connection._open_handshake.wait()
    return connection