Replace hand-rolled JSON protocol parsing with real JSON

Daemon: parse requests with kotlinx.serialization and read fields from
the params object instead of scanning the whole line for key markers,
which picked up decoy keys ("path", "version", "id") occurring inside
buffer text. Build all responses and events with JsonObject builders,
which also fixes unescaped control characters in output and \uXXXX
escapes in input. Malformed lines now get a BAD_REQUEST reply instead
of corrupting field extraction.

Client: quote outgoing JSON strings with a strict json_quote helper
instead of Odin's %q verb, whose \x/\e escapes are not valid JSON.

Verified end to end: adversarial payloads (decoy protocol keys,
unicode, control chars, malformed lines) against the daemon, and the
full client smoke flow (ids 1-10) against a real Gradle workspace.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
pavel 2026-07-03 09:04:50 +02:00
commit 8b1723ce31
5 changed files with 245 additions and 256 deletions

View file

@ -298,12 +298,12 @@ ui_state_save :: proc(view: ^SDL_View) {
append(&open_files_json, '[')
for file, index in view.saved_open_files {
if index > 0 do append(&open_files_json, ',')
item := fmt.tprintf("{\"path\":%q,\"cursor\":%d}", file.path, file.cursor)
item := fmt.tprintf("{\"path\":%s,\"cursor\":%d}", json_quote(file.path), file.cursor)
for b in transmute([]u8)item do append(&open_files_json, b)
}
append(&open_files_json, ']')
text := fmt.tprintf("{\n \"windowWidth\": %d,\n \"windowHeight\": %d,\n \"sidebarWidth\": %d,\n \"rightSidebarWidth\": %d,\n \"explorerVisible\": %v,\n \"gradleSidebarVisible\": %v,\n \"workspace\": %q,\n \"activeFile\": %d,\n \"openFiles\": %s\n}\n", view.window_width, view.window_height, view.sidebar_width, view.right_sidebar_width, view.explorer_visible, view.gradle_sidebar_visible, view.cached_workspace, view.saved_active_file, string(open_files_json[:]))
text := fmt.tprintf("{\n \"windowWidth\": %d,\n \"windowHeight\": %d,\n \"sidebarWidth\": %d,\n \"rightSidebarWidth\": %d,\n \"explorerVisible\": %v,\n \"gradleSidebarVisible\": %v,\n \"workspace\": %s,\n \"activeFile\": %d,\n \"openFiles\": %s\n}\n", view.window_width, view.window_height, view.sidebar_width, view.right_sidebar_width, view.explorer_visible, view.gradle_sidebar_visible, json_quote(view.cached_workspace), view.saved_active_file, string(open_files_json[:]))
_ = os.write_entire_file(path, transmute([]byte)text)
}