$[^session] (a cookie lookup, global.cookies.data[name]) was always
empty because __jet.cpp's cgi keyword check compares against "yes" (a
deliberate choice from an earlier session, not the codebase-wide
true/false convention used by filterblanklines/trimlines/eval etc.) -
testpost.jet had cgi="true", a stale mismatch that predates that
decision, so the entire cgi block (including reading HTTP_COOKIE into
global.cookies) never ran at all. Fixed the test fixture to say
cgi="yes" to match.
Verified live via tests/posttest.sh against the current build:
$[^session] now correctly prints 18fd56a83f (posttest.sh's simulated
HTTP_COOKIE session id), and dump.txt's *** COOKIES *** section shows
session=[18fd56a83f] instead of empty. dump.txt committed with this
fresh, correct output.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Global now owns a long-lived StreamReader (cgiReader) that CGIFormData
(a Parser) holds a reference to - declared before cgiData so it's
constructed first and destroyed last. __jet.cpp's POST handling
constructs CGIFormData against it and feeds the request body off stdin
in 4KB chunks, driving doParse() after each feed rather than blocking to
read the whole body up front - the same feed()/doParse() pattern a
socket-fed StreamReader would use, keeping memory bounded for large
multipart uploads.
Also fixes two real, pre-existing bugs surfaced while getting an actual
end-to-end CGI request working through jet-2.0 (not just compiling):
- Tag::Tag's opening-tag parser was gated on "parent && in.ifNext(\"<\")",
but jet-2.0.cpp's main() constructs the top-level __jet with
parent=NULL - meaning the outer <jet ...> tag's own attributes
(cgi="yes" and everything else) were never actually parsed at all, just
echoed as literal passthrough content. parent=NULL is used at exactly
one call site in the whole codebase, so dropping the "parent &&"
requirement only changes behavior for that one top-level case - every
nested tag construction already passes a real parent.
- __jet.cpp's boundary-extraction code calls contentType.find("boundary=")
to locate the multipart boundary parameter, but find() repositions
contentType's own cursor to the match as a side effect. That same
cursor-shifted contentType then got passed into CGIFormData's
constructor, whose startsWith("multipart/form-data")/
startsWith("application/x-www-form-urlencoded") checks are
cursor-relative and so silently matched neither, falling through to an
unrecognized content type that parsed nothing (reported COMPLETE
immediately, no error, just empty results). Fixed with
contentType.reset() before the CGIFormData construction.
Verified with a real end-to-end run: jet-2.0 invoked with simulated CGI
environment variables (REQUEST_METHOD=POST, CONTENT_TYPE with a
boundary=, CONTENT_LENGTH) and a genuine multipart/form-data body
(including a file-upload part) piped over stdin, using $[:name] in a
.jet script - correctly returns each field's value and correctly leaves
the skipped upload field empty.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- __jet.cpp: the cgi keyword check compared against "true" but the
documented/intended value is "yes", so <jet cgi="yes" ...> never
actually turned CGI mode on; fixed. Also replaced the hardcoded
fake multipart boundary ("xxxx") with real extraction from the
Content-Type header's boundary= parameter.
- Global.h: default-initialize cgiData to NULL (a GET request with
cgi="yes" never allocates it, so it was previously left
dangling); Global.cpp now sets the cookie jar's delimiter to ";"
to match RFC 6265, since it defaulted to CGIFormattedData's
&-based form-data delimiter.
- Global.cpp: fix addSession()'s missing throw that let it silently
continue past a duplicate session id.
- Tag.cpp: fix the CGI-variable lookup branch, which failed to
compile (cgiData is a pointer; needed to dereference it before
indexing) and added a null check so a CGI request that never
populated cgiData (bad Content-Type, or the null-safety gap
above) throws a clear error instead of crashing; implemented the
previously-empty session-variable lookup branch; left the
unreachable duplicate environment-variable branch as-is with a
comment, since fixing its sigil is a user-facing template-syntax
decision, not a bug fix.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>