Back $[@name] session variables with a JSON file via JFile, reusing the @ sigil

The @ sigil previously read through global.getSession(global.sessionId),
a MySQL-session binding that was already confirmed dead this session -
Global::sessionId is never assigned anywhere in the codebase, so any
$[@name] read would always throw. The design goal: persist session state
as a JSON file at sessiondir/<sessionId>.json, using CoreUtils's existing
JFile (an MFile+JString combination with load-on-construct/save-on-
destruct RAII semantics), reusing @ rather than introducing a new sigil
since the old @ usage was unreachable in practice anyway.

Global.h/.cpp: added Global::sessionFile (a JFile*, NULL unless a request
is in cgi mode with sessiondir set). Its destructor now explicitly
deletes sessionFile - JFile's actual disk write happens in MFile's
destructor via update(), so this has to run for persistence to happen at
all (a raw `new`'d pointer that's never deleted, as cgiData still is,
would never save anything back to disk).

__jet.cpp: the sessiondir block now builds the session file path from the
sessiondir keyword and the active session id (existing cookie or newly
issued) and constructs global.sessionFile there, for both branches. The
"pull sessionfile from sessiondir" comment is now implemented - JFile's
own constructor already handles "file doesn't exist yet" by loading as
empty, so one construction point serves both a resumed and a brand-new
session.

Tag.cpp: getVariable's "@" branch now reads via (*global.sessionFile)[name]
with a clear error if no session is active, instead of the dead MySQL
lookup. Added Tag::assignVariable (declared in Tag.h), a single write
path both storeVariable overloads now funnel through, so a "@name"-
prefixed target (e.g. <set name="@x" value="y"/>) is routed to the
session file instead of the normal global/local/parent variables maps -
without this, the read side would have been read-only, which isn't a
very useful session mechanism.

This surfaced two real, pre-existing CoreUtils bugs, both fixed
separately (see CoreUtils commit 3e6e410): JFile's virtual-base diamond
skipping JString's own empty-object seed, and MString's ZString-source
copy paths pairing an absolute data pointer with a cursor-relative
length - both were silently corrupting any cursor-advanced ZString
(exactly what assignVariable produces when it strips the "@" prefix via
ifNext() before storing).

Verified live: two genuinely separate jet-2.0 process invocations
sharing one session cookie, where the first writes two session
variables and the second - a fresh process with no shared memory - reads
both back correctly from the JSON file on disk. Also re-ran
tests/posttest.sh (unchanged output, no regression) and the full
CoreUtils test suite (no regressions).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Brad ArantandClaude Sonnet 5 committed 2026-08-23 18:45:21 -07:00
1 parent 6f2f3d7339
commit fc849c44a4
5 files changed
+72 -23

No files matched your search

+11
View File
@@ -5,6 +5,7 @@
# include "CGIFormattedData.h"
# include "CGIFormData.h"
# include "StreamReader.h"
# include "JFile.h"
# include <map>
namespace jet {
@@ -40,6 +41,16 @@ namespace jet {
coreutils::StreamReader cgiReader;
coreutils::CGIFormData *cgiData = NULL;
///
/// sessionFile backs $[@name] (read) and <set name="@name" .../>
/// (write) - a JSON file at sessiondir/<sessionId>.json, loaded when
/// opened and saved automatically when destroyed (JFile/MFile's own
/// RAII behavior - see MFile.cpp). NULL unless cgi mode and the
/// sessiondir keyword are both active for this request.
///
coreutils::JFile *sessionFile = NULL;
std::map<coreutils::MString, coreutils::MString> variables;
std::map<coreutils::MString, __mysql *> sessions;
std::map<coreutils::MString, coreutils::MString> headers;