From 2d9505cd336c85029da3ac5dbb88cc026080ab63 Mon Sep 17 00:00:00 2001 From: Brad Arant Date: Sat, 22 Aug 2026 21:37:51 -0700 Subject: [PATCH] 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 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 --- Global.cpp | 4 ++-- Global.h | 2 +- Tag.cpp | 18 +++++++++++++++--- __jet.cpp | 14 +++++++++----- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/Global.cpp b/Global.cpp index c36636f..f6bb3c0 100644 --- a/Global.cpp +++ b/Global.cpp @@ -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; } diff --git a/Global.h b/Global.h index 381d54a..f325c14 100644 --- a/Global.h +++ b/Global.h @@ -28,7 +28,7 @@ namespace jet { char *errorCursor = NULL; coreutils::CGIFormattedData cookies; - coreutils::CGIFormData *cgiData; + coreutils::CGIFormData *cgiData = NULL; std::map variables; std::map sessions; std::map headers; diff --git a/Tag.cpp b/Tag.cpp index 45d0315..962b1ef 100644 --- a/Tag.cpp +++ b/Tag.cpp @@ -412,12 +412,24 @@ namespace jet { if(name.find(":") == -1) { name << ":0"; } - return processModifier(global.cgiData[name], modifier); - } else + 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("^")) { diff --git a/__jet.cpp b/__jet.cpp index 066e51f..ea2b07e 100644 --- a/__jet.cpp +++ b/__jet.cpp @@ -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,10 +35,14 @@ namespace jet { if(requestMethod == "POST") { coreutils::ZString contentLength(getenv("CONTENT_LENGTH")); coreutils::ZString contentType(getenv("CONTENT_TYPE")); - ZString boundary = "xxxx"; - - global.cgiData = new coreutils::CGIFormData(0, contentType, contentLength.asInteger(), boundary); - } + 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); + } } processContainer(container, NULL, true); }