python-websockets/websockets

Inconsistent raw frames when sending a custom text frame with an empty body

edw4rb opened this issue · 3 comments

Description:

I'm experiencing an issue where sending a custom frame with an empty body using the python-websockets library results in inconsistent raw frames. Each time I send an empty text frame, the raw frame data differs. I expected the raw frame data to be consistent since the payload is empty.

Steps to Reproduce:

  1. Connect to the WebSocket server at wss://echo.websocket.org.
  2. Send an empty text frame every x seconds.
  3. Observe the differences in the raw frames each time a new frame is sent.

Code to Reproduce:

import websocket
import threading
import time
from websocket import WebSocketApp

def on_message(ws: WebSocketApp, message):
    pass

def on_error(ws: WebSocketApp, error):
    pass

def on_close(ws: WebSocketApp, close_status_code, close_msg):
    pass

def on_open(ws: WebSocketApp):
    def run(*args):
        while True:
            ws.send('')  # Send an empty text frame
            time.sleep(5)

    # Start the sending thread
    threading.Thread(target=run).start()

if __name__ == "__main__":
    websocket.enableTrace(True)
    ws = WebSocketApp("wss://echo.websocket.org",
                      on_message=on_message,
                      on_error=on_error,
                      on_close=on_close,
                      on_open=on_open)

    ws.run_forever()

Actual Result:

Here is the output I'm observing when running the above code:

++Sent raw: b'\x81\x80(\xc1\xc0\xd3'
++Rcv raw: b'\x81\x01o'
++Sent decoded: fin=1 opcode=1 data=b''
++Rcv decoded: fin=1 opcode=1 data=b'o'
++Sent raw: b'\x81\x807\xa60\xb9'
++Sent decoded: fin=1 opcode=1 data=b''
++Sent raw: b'\x88\x82\xf1\xc3\x8bY\xf2+'
++Sent decoded: fin=1 opcode=8 data=b'\x03\xe8'
++Sent raw: b'\x81\x800Dy\xe1'
++Sent decoded: fin=1 opcode=1 data=b''

Expected Result:

The raw frames should be identical each time, as the payload is empty. However, the raw frames appear to differ with each frame sent.

I'm not sure if this behavior is intended or if there's something I'm missing. Any guidance or explanation would be appreciated.

Your code is for websocket-client, a project unrelated to websockets.

That being said, you'd see the same behavior with websockets.

I expected the raw frame data to be consistent since the payload is empty.

That's an incorrect expectation. The protocol requires some randomness.

Per https://datatracker.ietf.org/doc/html/rfc6455#section-5.3:

The masking key is a 32-bit value chosen at random by the client.
When preparing a masked frame, the client MUST pick a fresh masking
key from the set of allowed 32-bit values. The masking key needs to
be unpredictable.

I apologize, that was embarrassing. Thank you

No worries!