Skip to content

fix(http): keep WebSocket control frames out of fragmented messages - #904

Merged
ithewei merged 1 commit into
masterfrom
fix/websocket-control-frame-between-fragments
Oct 12, 2026
Merged

ithewei merged 1 commit into
masterfrom
fix/websocket-control-frame-between-fragments

Conversation

@ithewei

@ithewei ithewei commented Oct 10, 2026

Copy link
Copy Markdown
Owner

Summary

  • A control frame (PING/PONG/CLOSE) arriving between the fragments of a TEXT/BINARY message replaced the parser's opcode and was appended to the partial message. The data message was never delivered to onmessage, and its contents were echoed back inside PONG frames. RFC 6455 §5.4 allows control frames in the middle of a fragmented message, so conforming peers can trigger this.
  • Control frames now go into a separate control_message buffer and are delivered when the frame ends, without touching the data message's opcode, message or state.
  • Fragmented control frames and control frames longer than 125 bytes are rejected (RFC 6455 §5.5). on_frame_header returns -1, so FeedRecvData returns a short count, and both HttpServer and WebSocketClient already close the connection in that case.
  • Add websocket_parser_test, wired into the Makefile, CMake and scripts/unittest.sh.

Scope

A CONTINUATION frame with no open message, and a new TEXT/BINARY frame while a fragmented message is open, behave as before. Other frame-header validation (masking direction, RSV bits, reserved opcodes) is not part of this change.

Verification

  • websocket_parser_test fails on master at the PING-between-fragments case and passes with this change
  • ./configure && make libhv unittest && make run-unittest on macOS
  • websocket_parser_test built with UBSan and run under Guard Malloc (libgmalloc)
  • WebSocketServer end to end with raw frames TEXT(FIN=0) "Hel" + PING "x" + CONT(FIN=1) "lo": replies PONG "x" and onmessage receives "Hello" (before: PONG "Helx" + PONG "lo", no onmessage); a fragmented PING now closes the connection
  • WebSocketClient end to end against a server sending the same frames: onmessage receives "Hello" and the client replies PONG "x"
  • git diff --check

Fixes #893

A control frame between the fragments of a data message overwrote the
parser's opcode and was appended to the partial message, so the data
message was echoed back inside PONG frames and never delivered.

Buffer control frames separately so they no longer touch the data
message state, and reject fragmented or oversized (>125 bytes) control
frames as required by RFC 6455 5.5.

Fixes #893
Copilot AI balanced review requested due to automatic review settings October 10, 2026 09:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The implementation addresses the reported parser corruption and includes focused coverage for valid and invalid control frames.

0 open findings

What changed in this PR

Separates WebSocket control frames from fragmented data messages and enforces RFC 6455 control-frame limits.

Changes:

  • Uses a dedicated control-frame buffer.
  • Rejects fragmented or oversized control frames.
  • Adds and registers parser tests.
File Description
http/​WebSocketParser.cpp Implements isolated control-frame parsing and validation.
http/​WebSocketParser.h Adds the control-frame buffer.
unittest/​websocket_parser_test.cpp Tests interleaving and invalid control frames.
unittest/​CMakeLists.txt Registers the CMake test target.
Makefile Builds the test with HTTP enabled.
scripts/​unittest.sh Runs the test when available.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@ithewei
ithewei merged commit 9afa2b8 into master Oct 12, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

WebSocket: a control frame between fragments of a data message corrupts that message

2 participants