]> Piment Noir Git Repositories - e-mobility-charging-stations-simulator.git/commit
fix(ui-server): reject reused in-flight WebSocket request ids (#2029) (#2033)
authorJérôme Benoit <jerome.benoit@piment-noir.org>
Sun, 19 Jul 2026 11:33:19 +0000 (13:33 +0200)
committerGitHub <noreply@github.com>
Sun, 19 Jul 2026 11:33:19 +0000 (13:33 +0200)
commitde0e86f47426fd8a53f122d5f7f427042a4edfb3
treedfc2310a2718f01ebddb9704dba844f18ae95934
parentee3db961367b32afab340ca3a8706fddca19e3ca
fix(ui-server): reject reused in-flight WebSocket request ids (#2029) (#2033)

* fix(ui-server): reject reused in-flight WebSocket request ids (#2029)

Client-supplied WebSocket UI request ids were validated for format only.
A second request reusing a still-in-flight id overwrote the prior request's
response handler (cross-delivered reply, dropped second response) and its
broadcast tracking (leaked safety-net timer firing against the wrong context).

Guard the transport ingest: when responseHandlers already holds the request id,
reject the duplicate with a typed BaseError failure on its own socket instead of
overwriting the in-flight request. A completed request releases its handler, so a
legitimate sequential reuse of the same id is still accepted. HTTP and MCP mint
server-side UUIDs and are unaffected.

Closes #2029

Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
* fix(ui-server): harden in-flight duplicate rejection send

Wrap the ws.send in rejectInFlightRequestId() in try/catch, matching the
sendResponse() send discipline. The helper runs in the synchronous 'message'
listener, so an uncaught send throw would escape unhandled; log and swallow it
instead. No behavior change to the in-flight guard.

Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
* test(ui-server): fail parseSentResponse with a descriptive assertion

When no message is captured at the requested index, fail with an explicit
assertion naming the index and sentMessages length instead of letting
JSON.parse throw an opaque SyntaxError. Use a length check rather than a
nullish guard, since MockWebSocket.sentMessages is typed string[] (indexed
access is not nullable under the project's tsconfig).

Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
* test(ui-server): reuse shared UI-server test helpers and constants

Hoist emitWorkerResponse into UIServerTestUtils as the single source of truth
and consume it from both AbstractUIService and UIWebSocketServer tests, removing
the duplicated worker-response injection helper (with divergent argument order).
In the WebSocket test, build the protocol request via createProtocolRequest
instead of an inline tuple, and drop the redundant explicit 'ui0.0.1' argument
(it is createMockUIWebSocket's default).

Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
---------

Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
src/charging-station/ui-server/UIWebSocketServer.ts
tests/charging-station/ui-server/UIServerTestUtils.ts
tests/charging-station/ui-server/UIWebSocketServer.test.ts
tests/charging-station/ui-server/ui-services/AbstractUIService.test.ts