Fix jet cgi=yes CGI variable loading and related bugs

- __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>
This commit is contained in:
Brad ArantandClaude Sonnet 5 committed 2026-08-22 21:37:51 -07:00
1 parent d0f2551e89
commit 2d9505cd33
4 files changed
+23 -7

No files matched your search

+2 -2
View File
@@ -7,7 +7,7 @@
namespace jet {
Global::Global(char **envp) : envp(envp) {
cookies.setDelimiter(";");
}
Global::~Global() {
@@ -25,7 +25,7 @@ namespace jet {
void Global::addSession(coreutils::MString sessionId, __mysql *mysql) {
if(sessionExists(sessionId))
coreutils::Exception("sessionid already exists.");
throw coreutils::Exception("sessionid already exists.");
sessions[sessionId] = mysql;
}
+1 -1
View File
@@ -28,7 +28,7 @@ namespace jet {
char *errorCursor = NULL;
coreutils::CGIFormattedData cookies;
coreutils::CGIFormData *cgiData;
coreutils::CGIFormData *cgiData = NULL;
std::map<coreutils::MString, coreutils::MString> variables;
std::map<coreutils::MString, __mysql *> sessions;
std::map<coreutils::MString, coreutils::MString> headers;
+14 -2
View File
@@ -412,12 +412,24 @@ namespace jet {
if(name.find(":") == -1) {
name << ":0";
}
return processModifier(global.cgiData[name], modifier);
if(global.cgiData == NULL)
throw coreutils::Exception("cgi variable requested but no request body was available (not a POST, or an unrecognized Content-Type).");
coreutils::MString cgiValue = (*global.cgiData)[name];
return processModifier(cgiValue, modifier);
} else
throw coreutils::Exception("cgi variable only allowed in cgi mode.");
} else if(variable.ifNext("@")) {
// TODO: should only allow session variables. Allow substitution.
renderVariableName(variable, name, modifier);
coreutils::MString sessionValue = global.getSession(global.sessionId)->getColumnValue(name);
return processModifier(sessionValue, modifier);
} else if(variable.ifNext("%")) {
// NOTE: unreachable - '%' is already claimed by the keyword-lookup branch
// above (variable.ifNext("%") at the top of this chain), so this branch
// can never be entered. This looks like a copy-paste where the intended
// sigil character for environment-variable access was meant to be
// something else. Left as-is rather than guessing a new template-syntax
// character unilaterally - confirm the intended sigil before wiring this
// branch up to a reachable condition.
renderVariableName(variable, name, modifier);
return getenv(name.c_str());
} else if(variable.ifNext("^")) {
+6 -2
View File
@@ -10,7 +10,7 @@ namespace jet {
__jet::__jet(coreutils::ZString &in, coreutils::MString &parentOut, Global &global, Tag *parent, Tag *local) : Tag(in, parentOut, global, parent, this) {
char *cookies;
if(keywordDefined("cgi") && (resolveKeyword("cgi") == "true")) {
if(keywordDefined("cgi") && (resolveKeyword("cgi") == "yes")) {
global.cgi = true;
if(keywordDefined("sessiondir")) {
@@ -35,7 +35,11 @@ namespace jet {
if(requestMethod == "POST") {
coreutils::ZString contentLength(getenv("CONTENT_LENGTH"));
coreutils::ZString contentType(getenv("CONTENT_TYPE"));
ZString boundary = "xxxx";
coreutils::ZString boundary;
int boundaryPos = contentType.find("boundary=");
if(boundaryPos != -1) {
boundary = contentType.substring(boundaryPos + 9);
}
global.cgiData = new coreutils::CGIFormData(0, contentType, contentLength.asInteger(), boundary);
}