- MString::read() now gives up after repeated I/O errors instead of
looping forever and crashing via realloc() failure (root cause of a
recurring barant.com production crash).
- HTTPRequest::parse() no longer leaks lineParser/headerParser on a
malformed request.
- Log gained size-based rotation (config-driven) and a non-static-mutex
fix; a separate fix stopped rotation from destroying the logs symlink
on its first trigger.
- File.cpp: symlink-preserving rotation support.
- JString: fixed an array-index out-of-bounds and a setString issue.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Was an unchecked std::vector index (return list[index];). Any
malformed/short line - a port scanner, a bot probing the port, or any
client sending fewer colon-delimited fields than a given handler
indexes via request[N] - reached this with no length check anywhere
upstream, across every server built on this class. Depending on build
flags that was either undefined behavior or, confirmed live (a real
crash log from Zephora's game server), a hard process abort via
libstdc++'s own vector bounds assertion:
Assertion '__n < this->size()' failed.
Throwing instead lets this be caught: every caller that dispatches a
parsed request already wraps that dispatch in a try/catch (see
CommandList::processRequest()), so a single malformed line is now
cleanly rejected instead of taking down the entire server process for
every connected player.
Invisible until this session's ServerCore tls/master merge brought
Subscription/SubscriptionManager (which calls it) into the same
dependency chain as a real executable for the first time - a static
library archive (ar) never checks for unresolved symbols, only the
final link of a real binary does, so this went unnoticed for however
long it sat declared-only in MString.h. Stores the raw pointer value
as the string bytes (pointer-identity comparison, matching how void*
aliases are compared everywhere else in this codebase) rather than
dereferencing it, since some callers pass arbitrary non-string
pointers through this constructor.
File-upload parts (Content-Disposition with filename=) were
unconditionally flagged currentSkip and discarded at PART_BOUNDARY,
so every <field type="file"> upload site (track audio, presets,
project icons) only ever received an empty value via $[fieldname],
never the real uploaded bytes.
- File: stat() only after a successful open() (previously ran first with
its result ignored, feeding a missing file's garbage st_size into a
realloc - could crash the whole APIServer on a request for a
nonexistent static asset)
- JString::setString(): always quote+escape the value instead of going
through set()'s literal-value guess, which misclassified any string
starting with digits (e.g. a UUID) as a bare numeric literal and wrote
it unquoted, corrupting later edits to the same JSON document
- MString::remove() (both overloads): fixed an off-by-one that read one
byte past the buffer on a completely full string (found via ASan under
concurrent load)
- CGIFormData: added fields() so callers can iterate every parsed field
without knowing names in advance (used to merge POST body into
jet::Global::variables the same way query-string params already are)