#1886: reject orphan CONTINUATION and new TEXT/BINARY while reassembly is
pending (1002); validate TEXT UTF-8 on complete and assembled messages
(1007); clear fragOpcode when reassembly finishes. Mirrors engine #792.
#1887: gate every grpc-web RPC on ParseFromString success; return
INVALID_ARGUMENT (3) on truncated or malformed bodies instead of running
with default-valued requests.
proxy_regression covers fragmentation, UTF-8, and ParseFromString rejects.
- #1091: saveSession uses ON CONFLICT upsert so REPLACE cannot CASCADE-wipe scrollback
- #1092: loadFromDb keeps memoryBytes_ in lockstep with append() (no size_t underflow)
- #1093: reset lenBytesRead before MaskKey after extended length (no maskKey OOB)
- #1094: deliver WS CLOSE (and protocol errors) so session paths close the FD;
complete zero-length payloads after the mask key (empty CLOSE)
proxy_regression: ok (ext-len mask + CLOSE + unmasked teardown)
Moved base64 encode/decode from websocket.cpp and grpc_web.cpp into a
single shared implementation. Three overloads: raw bytes, std::string
encode, and std::string decode. Removed declarations from grpc_web.h.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Steps 2-4/7 of WebSocket GameSession transport:
- websocket.h/cpp: Parse Sec-WebSocket-Protocol during handshake,
set WsState::isGameSession when hydra-gamesession is requested,
echo the subprotocol in the 101 response
- hydra_types.h: Add WsGameSession to FrontDoorProto enum
- session_manager.h: Add subscriber fields to FrontDoorState
(wsGameSessionSubId, wsGameSessionQueue, wsGameSessionOQ,
wsGameSessionPersistId)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
RFC 6455 WebSocket codec with HTTP upgrade handshake, frame
encode/decode, masking, ping/pong/close, and fragmentation reassembly.
WebSocket listeners are configured alongside telnet listeners and
routed by tag in the event loop. Game output is wrapped in WS text
frames; client input is unwrapped and processed as lines.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>