python-hyper / wsproto

Sans-IO WebSocket protocol implementation
https://wsproto.readthedocs.io/
MIT License
261 stars 38 forks source link

should Connection.send() raise a LocalProtocolError after the connection.state == CLOSED? #168

Closed haolian9 closed 2 years ago

haolian9 commented 2 years ago

reproduce:

from wsproto.connection import Connection, ConnectionState, ConnectionType
from wsproto.events import CloseConnection, TextMessage
from wsproto.frame_protocol import CloseReason
from wsproto.utilities import LocalProtocolError

def test_send_after_close():
    client = Connection(ConnectionType.CLIENT)
    server = Connection(ConnectionType.SERVER)

    OPEN = ConnectionState.OPEN
    LOCAL_CLOSING = ConnectionState.LOCAL_CLOSING
    REMOTE_CLOSING = ConnectionState.REMOTE_CLOSING
    CLOSED = ConnectionState.CLOSED

    assert client.state == OPEN and server.state == OPEN

    client.receive_data(server.send(CloseConnection(CloseReason.NORMAL_CLOSURE)))
    close = next(client.events())
    assert client.state == REMOTE_CLOSING and server.state == LOCAL_CLOSING

    server.receive_data(client.send(close.response()))
    next(server.events())
    assert client.state == CLOSED and server.state == CLOSED

    try:
        server.send(TextMessage(data="hello and welcome"))
    except LocalProtocolError:
        pass
    else:
        raise AssertionError(
            "The application MUST NOT send any more data frames after sending a Close frame."
        )

if __name__ == "__main__":
    test_send_after_close()

according to the rfc:

The application MUST NOT send any more data frames after sending a Close frame.

if i did not misunderstand, i think server.send() should raise an LocalProtocolError after it sent the CloseConnection.

haolian9 commented 2 years ago

by the way, i did not mention LocalProtocolError randomly, i got it's name from

    try:
        packed_text = server.send(TextMessage(data="hello and welcome"))
    except LocalProtocolError:
        pass
    else:
        # raise AssertionError(
        #     "The application MUST NOT send any more data frames after sending a Close frame."
        # )
        pass

    try:
        client.receive_data(packed_text)
    except LocalProtocolError:
        pass
    else:
        raise AssertionError("there should be an exception")
pgjones commented 2 years ago

Thanks, fixed in b0efe554cca8ac24dcf82940137d04c90351c9c1