Commit graph

4 commits

Author SHA1 Message Date
cjkas
a8bb377957 fix: track the JSON length instead of recounting it
Every append found the end of the buffer with strlen(), up to four
times per append and four appends per field, so building a response
cost the square of its size. /discovery fills a 4 KB buffer and spent
about 195 ms of its ~210 ms there (shades 126 ms, groups 69 ms), all on
the async_tcp task that serves every socket and web request.

Keep the length in the formatter and write every append at the end
through one helper. The web response and socket event subclasses and
ControllerChunker use the tracked length too. Output is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 16:04:13 +02:00
cjkas
8881289b1d fix: never write past a JSON buffer or send a broken socket event
When something didn't fit, the formatters skipped it silently, closing
brackets included, and clients got malformed JSON.  Two writes could
also go past the buffer:

- AsyncJsonResp flushed when full and then wrote the value without
  checking again, so a value bigger than the whole buffer overflowed.
  It is now streamed straight out instead.
- JsonSockEvent::closeEvent added the closing ] when only one byte was
  left, putting the terminator one byte past the buffer.

The formatters now set an overflowed() flag and log an error, and a
socket event that overflowed is logged and not sent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 13:31:48 +02:00
cjkas
b2294ced34 fix: escape control characters and count JSON string lengths correctly
calcEscapedLength looped from strlen(raw) down to 1, counting the
terminator instead of the first character.  A value starting with a
character that needs escaping was counted one byte short, so the fit
check could let it be written one byte past the buffer.  Control
characters other than \b\f\n\r\t were copied raw, which isn't valid
JSON.

Both now go through one escapeChar helper, which also escapes the
remaining control characters as \u00XX.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 13:30:42 +02:00
cjkas
d723c1024d refactor: move JsonFormatter into JsonFormatter.cpp
JsonFormatter and BufferedJsonFormatter move verbatim out of
WResp.cpp/WResp.h, which now include JsonFormatter.h.  They don't need
the web server, so on their own they can be unit tested on the PC; the
native env builds the new file.  AsyncJsonResp and JsonSockEvent stay
in WResp.  No behaviour change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 13:29:30 +02:00