def _handle_message(self, event, source_conn, other_conn, is_server):
        fb = self.server_frame_buffer if is_server else self.client_frame_buffer
        fb.append(event.data)

        if event.message_finished:
            original_chunk_sizes = [len(f) for f in fb]

            if isinstance(event, events.TextMessage):
                message_type = wsproto.frame_protocol.Opcode.TEXT
                payload = ''.join(fb)
            else:
                message_type = wsproto.frame_protocol.Opcode.BINARY
                payload = b''.join(fb)

            fb.clear()

            websocket_message = WebSocketMessage(message_type, not is_server,
                                                 payload)
            length = len(websocket_message.content)
            self.flow.messages.append(websocket_message)
            self.channel.ask("websocket_message", self.flow)

            if not self.flow.stream and not websocket_message.killed:

                def get_chunk(payload):
                    if len(payload) == length:
                        # message has the same length, we can reuse the same sizes
                        pos = 0
                        for s in original_chunk_sizes:
                            yield (payload[pos:pos + s],
                                   True if pos + s == length else False)
                            pos += s
                    else:
                        # just re-chunk everything into 4kB frames
                        # header len = 4 bytes without masking key and 8 bytes with masking key
                        chunk_size = 4092 if is_server else 4088
                        chunks = range(0, len(payload), chunk_size)
                        for i in chunks:
                            yield (payload[i:i + chunk_size], True if
                                   i + chunk_size >= len(payload) else False)

                for chunk, final in get_chunk(websocket_message.content):
                    data = self.connections[other_conn].send(
                        Message(data=chunk, message_finished=final))
                    other_conn.send(data)

        if self.flow.stream:
            data = self.connections[other_conn].send(
                Message(data=event.data,
                        message_finished=event.message_finished))
            other_conn.send(data)
        return True
Exemple #2
0
def handle_todo_post_save(sender, instance, created, **kwargs):
    if not hasattr(sender, 'APP_PORT'):
        return
    conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    conn.connect(('localhost', int(sender.APP_PORT)))

    ws = WSConnection(ConnectionType.CLIENT)
    print("hello")
    net_send(
        ws.send(Request(
            host=f"localhost:{sender.APP_PORT}",
            target=f"ws/todos")),
        conn
    )
    net_recv(ws, conn)
    handle_events(ws)

    net_send(ws.send(Message(data=str(instance.pk))), conn)
    net_recv(ws, conn)
    handle_events(ws)

    net_send(ws.send(CloseConnection(code=1000)), conn)
    net_recv(ws, conn)
    conn.shutdown(socket.SHUT_WR)
    net_recv(ws, conn)

    del sender.APP_PORT
Exemple #3
0
    def _send_data(self, data: AnyStr) -> None:
        if isinstance(data, str):
            io_object = io.StringIO(data)
        else:
            io_object = io.BytesIO(data)

        with io_object as f:
            chunk = f.read(self.buffer_size)
            while chunk:
                if len(chunk) < self.buffer_size:
                    self._client.sendall(
                        self._ws.send(Message(data, message_finished=True)))
                    break
                else:
                    self._client.sendall(
                        self._ws.send(Message(data, message_finished=False)))
                chunk = f.read(self.buffer_size)
Exemple #4
0
 def send(self, data):
     if not self.connected:
         raise ConnectionClosed()
     if isinstance(data, bytes):
         out_data = self.ws.send(Message(data=data))
     else:
         out_data = self.ws.send(TextMessage(data=str(data)))
     self.sock.send(out_data)
Exemple #5
0
 def _inject_messages(self, endpoint, message_queue):
     while True:
         try:
             payload = message_queue.get_nowait()
             data = self.connections[endpoint].send(Message(data=payload, message_finished=True))
             endpoint.send(data)
         except queue.Empty:
             break
Exemple #6
0
def websocket(request):
    # The underlying socket must be provided by the server. Gunicorn and
    # Werkzeug's dev server are known to support this.
    stream = request.environ.get("werkzeug.socket")

    if stream is None:
        stream = request.environ.get("gunicorn.socket")

    if stream is None:
        raise InternalServerError()

    # Initialize the wsproto connection. Need to recreate the request
    # data that was read by the WSGI server already.
    ws = WSConnection(ConnectionType.SERVER)
    in_data = b"GET %s HTTP/1.1\r\n" % request.path.encode("utf8")

    for header, value in request.headers.items():
        in_data += f"{header}: {value}\r\n".encode()

    in_data += b"\r\n"
    ws.receive_data(in_data)
    running = True

    while True:
        out_data = b""

        for event in ws.events():
            if isinstance(event, WSRequest):
                out_data += ws.send(AcceptConnection())
            elif isinstance(event, CloseConnection):
                out_data += ws.send(event.response())
                running = False
            elif isinstance(event, Ping):
                out_data += ws.send(event.response())
            elif isinstance(event, TextMessage):
                # echo the incoming message back to the client
                if event.data == "quit":
                    out_data += ws.send(
                        CloseConnection(CloseReason.NORMAL_CLOSURE, "bye")
                    )
                    running = False
                else:
                    out_data += ws.send(Message(data=event.data))

        if out_data:
            stream.send(out_data)

        if not running:
            break

        in_data = stream.recv(4096)
        ws.receive_data(in_data)

    # The connection will be closed at this point, but WSGI still
    # requires a response.
    return Response("", status=204)
def handle_connection(stream: socket.socket) -> None:
    """
    Handle a connection.

    The server operates a request/response cycle, so it performs a synchronous
    loop:

    1) Read data from network into wsproto
    2) Get new events and handle them
    3) Send data from wsproto to network

    :param stream: a socket stream
    """
    ws = WSConnection(ConnectionType.SERVER)
    running = True

    while running:
        # 1) Read data from network
        in_data = stream.recv(RECEIVE_BYTES)
        print("Received {} bytes".format(len(in_data)))
        ws.receive_data(in_data)

        # 2) Get new events and handle them
        out_data = b""
        for event in ws.events():
            if isinstance(event, Request):
                # Negotiate new WebSocket connection
                print("Accepting WebSocket upgrade")
                out_data += ws.send(AcceptConnection())
            elif isinstance(event, CloseConnection):
                # Print log message and break out
                print("Connection closed: code={} reason={}".format(
                    event.code, event.reason))
                out_data += ws.send(event.response())
                running = False
            elif isinstance(event, TextMessage):
                # Reverse text and send it back to wsproto
                print("Received request and sending response")
                out_data += ws.send(Message(data=event.data[::-1]))
            elif isinstance(event, Ping):
                # wsproto handles ping events for you by placing a pong frame in
                # the outgoing buffer. You should not call pong() unless you want to
                # send an unsolicited pong frame.
                print("Received ping and sending pong")
                out_data += ws.send(event.response())
            else:
                print(f"Unknown event: {event!r}")

        # 4) Send data from wsproto to network
        print("Sending {} bytes".format(len(out_data)))
        stream.send(out_data)
def wsproto_demo(host, port):
    '''
    Demonstrate wsproto:

    0) Open TCP connection
    1) Negotiate WebSocket opening handshake
    2) Send a message and display response
    3) Send ping and display pong
    4) Negotiate WebSocket closing handshake

    :param stream: a socket stream
    '''

    # 0) Open TCP connection
    print('Connecting to {}:{}'.format(host, port))
    conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    conn.connect((host, port))

    # 1) Negotiate WebSocket opening handshake
    print('Opening WebSocket')
    ws = WSConnection(ConnectionType.CLIENT)
    # Because this is a client WebSocket, we need to initiate the connection
    # handshake by sending a Request event.
    net_send(ws.send(Request(host=host, target='server')), conn)
    net_recv(ws, conn)
    handle_events(ws)

    # 2) Send a message and display response
    message = "wsproto is great"
    print('Sending message: {}'.format(message))
    net_send(ws.send(Message(data=message)), conn)
    net_recv(ws, conn)
    handle_events(ws)

    # 3) Send ping and display pong
    payload = b"table tennis"
    print('Sending ping: {}'.format(payload))
    net_send(ws.send(Ping(payload=payload)), conn)
    net_recv(ws, conn)
    handle_events(ws)

    # 4) Negotiate WebSocket closing handshake
    print('Closing WebSocket')
    net_send(ws.send(CloseConnection(code=1000, reason='sample reason')), conn)
    # After sending the closing frame, we won't get any more events. The server
    # should send a reply and then close the connection, so we need to receive
    # twice:
    net_recv(ws, conn)
    conn.shutdown(socket.SHUT_WR)
    net_recv(ws, conn)
def test_send_message(client_sends, final):
    client = Connection(CLIENT)
    server = Connection(SERVER)

    if client_sends:
        local = client
        remote = server
    else:
        local = server
        remote = client

    data = b"x" * 23
    remote.receive_data(local.send(Message(data=data, message_finished=final)))
    event = next(remote.events())
    assert isinstance(event, BytesMessage)
    assert event.data == data
    assert event.message_finished is final
Exemple #10
0
def new_conn(sock: socket.socket) -> None:
    global count
    print("test_server.py received connection {}".format(count))
    count += 1
    ws = WSConnection(SERVER)
    closed = False
    while not closed:
        try:
            data: Optional[bytes] = sock.recv(65535)
        except socket.error:
            data = None

        ws.receive_data(data or None)

        outgoing_data = b""
        for event in ws.events():
            if isinstance(event, Request):
                outgoing_data += ws.send(
                    AcceptConnection(extensions=[PerMessageDeflate()]))
            elif isinstance(event, Message):
                outgoing_data += ws.send(
                    Message(data=event.data,
                            message_finished=event.message_finished))
            elif isinstance(event, Ping):
                outgoing_data += ws.send(event.response())
            elif isinstance(event, CloseConnection):
                closed = True
                if ws.state is not ConnectionState.CLOSED:
                    outgoing_data += ws.send(event.response())

        if not data:
            closed = True

        try:
            sock.sendall(outgoing_data)
        except socket.error:
            closed = True

    sock.close()
def handle_connection(stream):
    '''
    Handle a connection.

    The server operates a request/response cycle, so it performs a synchronous
    loop:

    1) Read data from network into wsproto
    2) Get next wsproto event
    3) Handle event
    4) Send data from wsproto to network

    :param stream: a socket stream
    '''
    ws = WSConnection(ConnectionType.SERVER)

    # events is a generator that yields websocket event objects. Usually you
    # would say `for event in ws.events()`, but the synchronous nature of this
    # server requires us to use next(event) instead so that we can interleave
    # the network I/O.
    events = ws.events()
    running = True

    while running:
        # 1) Read data from network
        in_data = stream.recv(RECEIVE_BYTES)
        print('Received {} bytes'.format(len(in_data)))
        ws.receive_data(in_data)

        # 2) Get next wsproto event
        try:
            event = next(events)
        except StopIteration:
            print('Client connection dropped unexpectedly')
            return

        # 3) Handle event
        if isinstance(event, Request):
            # Negotiate new WebSocket connection
            print('Accepting WebSocket upgrade')
            out_data = ws.send(AcceptConnection())
        elif isinstance(event, CloseConnection):
            # Print log message and break out
            print('Connection closed: code={}/{} reason={}'.format(
                event.code.value, event.code.name, event.reason))
            out_data = ws.send(event.response())
            running = False
        elif isinstance(event, TextMessage):
            # Reverse text and send it back to wsproto
            print('Received request and sending response')
            out_data = ws.send(Message(data=event.data[::-1]))
        elif isinstance(event, Ping):
            # wsproto handles ping events for you by placing a pong frame in
            # the outgoing buffer. You should not call pong() unless you want to
            # send an unsolicited pong frame.
            print('Received ping and sending pong')
            out_data = ws.send(event.response())
        else:
            print('Unknown event: {!r}'.format(event))

        # 4) Send data from wsproto to network
        print('Sending {} bytes'.format(len(out_data)))
        stream.send(out_data)
Exemple #12
0
 async def send(self, data: AnyStr) -> None:
     self.server.data_received(self.connection.send(Message(data=data)))
     await asyncio.sleep(0)  # Allow the server to respond
Exemple #13
0
 async def send(self, data):
     if self.closed:
         raise WebsocketClosedError()
     await self.outgoing.put(Message(data=data))
Exemple #14
0
            host=uri.netloc, target='%s?%s' % (uri.path, uri.query),
            extensions=[PerMessageDeflate()],
        ))
    )
    closed = False

    while not closed:
        try:
            data = sock.recv(65535)
        except CONNECTION_EXCEPTIONS:
            data = None
        connection.receive_data(data or None)
        out_data = b""
        for event in connection.events():
            if isinstance(event, Message):
                out_data += connection.send(Message(data=event.data, message_finished=event.message_finished))
            elif isinstance(event, Ping):
                out_data += connection.send(event.response())
            elif isinstance(event, CloseConnection):
                closed = True
                out_data += connection.send(event.response())
            # else:
            #     print("??", event)
        if out_data is None:
            break
        try:
            sock.sendall(out_data)
        except CONNECTION_EXCEPTIONS:
            closed = True
            break
Exemple #15
0
 async def send(self, data: AnyStr) -> None:
     await self.client_stream.send_all(
         self.connection.send(Message(data=data)))
     await trio.sleep(0)  # Allow the server to respond
Exemple #16
0
                target='%s?%s' % (uri.path, uri.query),
                extensions=[PerMessageDeflate()],
            )))
    closed = False

    while not closed:
        try:
            data = sock.recv(65535)
        except CONNECTION_EXCEPTIONS:
            data = None
        connection.receive_data(data or None)
        out_data = b""
        for event in connection.events():
            if isinstance(event, Message):
                out_data += connection.send(
                    Message(data=event.data,
                            message_finished=event.message_finished))
            elif isinstance(event, Ping):
                out_data += connection.send(event.response())
            elif isinstance(event, CloseConnection):
                closed = True
                out_data += connection.send(event.response())
            # else:
            #     print("??", event)
        if out_data is None:
            break
        try:
            sock.sendall(out_data)
        except CONNECTION_EXCEPTIONS:
            closed = True
            break
def wsproto_demo(host, port):
    '''
    Demonstrate wsproto:

    0) Open TCP connection
    1) Negotiate WebSocket opening handshake
    2) Send a message and display response
    3) Send ping and display pong
    4) Negotiate WebSocket closing handshake

    :param stream: a socket stream
    '''

    # 0) Open TCP connection
    print('Connecting to {}:{}'.format(host, port))
    conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    conn.connect((host, port))

    # 1) Negotiate WebSocket opening handshake
    print('Opening WebSocket')
    ws = WSConnection(ConnectionType.CLIENT)
    net_send(ws.send(Request(host=host, target='server')), conn)
    net_recv(ws, conn)

    # events is a generator that yields websocket event objects. Usually you
    # would say `for event in ws.events()`, but the synchronous nature of this
    # client requires us to use next(event) instead so that we can interleave
    # the network I/O. It will raise StopIteration when it runs out of events
    # (i.e. needs more network data), but since this script is synchronous, we
    # will explicitly resume the generator whenever we have new network data.
    events = ws.events()

    # Because this is a client WebSocket, wsproto has automatically queued up
    # a handshake, and we need to send it and wait for a response.
    event = next(events)
    if isinstance(event, AcceptConnection):
        print('WebSocket negotiation complete')
    else:
        raise Exception('Expected AcceptConnection event!')

    # 2) Send a message and display response
    message = "wsproto is great"
    print('Sending message: {}'.format(message))
    net_send(ws.send(Message(data=message)), conn)
    net_recv(ws, conn)
    event = next(events)
    if isinstance(event, TextMessage):
        print('Received message: {}'.format(event.data))
    else:
        raise Exception('Expected TextMessage event!')

    # 3) Send ping and display pong
    payload = b"table tennis"
    print('Sending ping: {}'.format(payload))
    net_send(ws.send(Ping(payload=payload)), conn)
    net_recv(ws, conn)
    event = next(events)
    if isinstance(event, Pong):
        print('Received pong: {}'.format(event.payload))
    else:
        raise Exception('Expected Pong event!')

    # 4) Negotiate WebSocket closing handshake
    print('Closing WebSocket')
    net_send(ws.send(CloseConnection(code=1000, reason='sample reason')), conn)
    # After sending the closing frame, we won't get any more events. The server
    # should send a reply and then close the connection, so we need to receive
    # twice:
    net_recv(ws, conn)
    conn.shutdown(socket.SHUT_WR)
    net_recv(ws, conn)