Skip to content

Commit f69333d

Browse files
authored
[PR #10764/e0cc020 backport][3.11] Fix WebSocket reader with fragmented masked messages (#10765)
1 parent 83690e5 commit f69333d

File tree

3 files changed

+49
-2
lines changed

3 files changed

+49
-2
lines changed

CHANGES/10764.bugfix.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fixed reading fragmented WebSocket messages when the payload was masked -- by :user:`bdraco`.
2+
3+
The problem first appeared in 3.11.17

aiohttp/_websocket/reader_py.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -439,8 +439,7 @@ def _feed_data(self, data: bytes) -> None:
439439
self._payload_fragments.append(data_cstr[f_start_pos:f_end_pos])
440440
if self._has_mask:
441441
assert self._frame_mask is not None
442-
payload_bytearray = bytearray()
443-
payload_bytearray.join(self._payload_fragments)
442+
payload_bytearray = bytearray(b"".join(self._payload_fragments))
444443
websocket_mask(self._frame_mask, payload_bytearray)
445444
payload = payload_bytearray
446445
else:

tests/test_websocket_parser.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,51 @@ def test_fragmentation_header(
366366
assert res == (WSMessage(WSMsgType.TEXT, "a", ""), 1)
367367

368368

369+
def test_large_message(
370+
out: WebSocketDataQueue, parser: PatchableWebSocketReader
371+
) -> None:
372+
large_payload = b"b" * 131072
373+
data = build_frame(large_payload, WSMsgType.BINARY)
374+
parser._feed_data(data)
375+
376+
res = out._buffer[0]
377+
assert res == ((WSMsgType.BINARY, large_payload, ""), 131072)
378+
379+
380+
def test_large_masked_message(
381+
out: WebSocketDataQueue, parser: PatchableWebSocketReader
382+
) -> None:
383+
large_payload = b"b" * 131072
384+
data = build_frame(large_payload, WSMsgType.BINARY, use_mask=True)
385+
parser._feed_data(data)
386+
387+
res = out._buffer[0]
388+
assert res == ((WSMsgType.BINARY, large_payload, ""), 131072)
389+
390+
391+
def test_fragmented_masked_message(
392+
out: WebSocketDataQueue, parser: PatchableWebSocketReader
393+
) -> None:
394+
large_payload = b"b" * 100
395+
data = build_frame(large_payload, WSMsgType.BINARY, use_mask=True)
396+
for i in range(len(data)):
397+
parser._feed_data(data[i : i + 1])
398+
399+
res = out._buffer[0]
400+
assert res == ((WSMsgType.BINARY, large_payload, ""), 100)
401+
402+
403+
def test_large_fragmented_masked_message(
404+
out: WebSocketDataQueue, parser: PatchableWebSocketReader
405+
) -> None:
406+
large_payload = b"b" * 131072
407+
data = build_frame(large_payload, WSMsgType.BINARY, use_mask=True)
408+
for i in range(0, len(data), 16384):
409+
parser._feed_data(data[i : i + 16384])
410+
res = out._buffer[0]
411+
assert res == ((WSMsgType.BINARY, large_payload, ""), 131072)
412+
413+
369414
def test_continuation(
370415
out: WebSocketDataQueue, parser: PatchableWebSocketReader
371416
) -> None:

0 commit comments

Comments
 (0)