Skip to content

fix(websocket): replace invalid UTF-8 instead of dropping the session - #646

Open
rawsun007 wants to merge 1 commit into
GoMudEngine:masterfrom
rawsun007:fix/websocket-invalid-utf8
Open

fix(websocket): replace invalid UTF-8 instead of dropping the session#646
rawsun007 wants to merge 1 commit into
GoMudEngine:masterfrom
rawsun007:fix/websocket-invalid-utf8

Conversation

@rawsun007

Copy link
Copy Markdown

Follow-up to #631, and the belt-and-braces half I offered there rather than assumed.

A websocket text frame has to be valid UTF-8. ConnectionDetails.Write already guards one source of an invalid frame - the p[0] == term.TELNET_IAC check - and the comment above it names the consequence: "Websocket client complains, disconnects, error is raised: close 1002 (protocol error): Invalid UTF-8 in text frame."

Anything else that cuts a multi-byte rune hits the same wall, and the player loses the session rather than seeing a glitch. #631 is exactly that: ansitags.SplitStringOnSpaces measures in bytes, so the blocks in the quests progress bar get split and the browser closes with 1007.

This replaces invalid bytes with U+FFFD and logs the payload, so the frame is deliverable and the cause shows up in the log. Write still reports len(p) to the caller, since the write consumed all of it.

Deliberately not a fix for the wrap - that belongs upstream in GoMudEngine/ansitags#14, and I have not touched it here. This only stops that class of bug from being fatal, and does nothing at all when the payload is already valid (the common path returns the original slice, no allocation).

validUTF8Payload is split out so it is testable without a live socket. The test covers ASCII, a 25-rune bar, a bar cut after the first byte of a rune (the #631 shape), orphaned continuation bytes, and a lone 0xff; it also asserts a valid payload comes back byte-identical.

Verified: make validate clean, go test ./... green, and the new test fails to compile against main without the helper.

Assisted-by: Claude Code (Claude Opus 5) - disclosed here and in the commit trailer.

A websocket text frame must be valid UTF-8, so a payload that splits a rune
makes the client close with 1007 and the player loses the session. The
existing first-byte TELNET_IAC check guards one source of that; the comment
beside it already names the failure ('Invalid UTF-8 in text frame').

Anything that cuts a multi-byte rune hits the same wall - see GoMudEngine#631, where a
byte-counting wrap splits the U+2591 blocks in the quests progress bar. Sanitize
the payload and log it, so the frame is deliverable and the cause is visible
rather than the connection disappearing.

This does not fix the wrap itself, which is upstream in ansitags
(GoMudEngine/ansitags#14). It stops that class of bug from being fatal.

Assisted-by: Claude Code (Claude Opus 5)
@rawsun007
rawsun007 requested a review from Volte6 as a code owner September 4, 2026 14:16
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.

1 participant