Fix CGI form/cookie data handling and CGI URL encode/decode

- CGIFormData: fix broken setSize()+read() double-length bug that
  corrupted every parsed body with a leading run of garbage bytes
  (setSize(contentLength) pre-set length before read()/write()
  appended on top of it); switch content-type checks from exact
  equality to startsWith() since a real multipart Content-Type
  always carries a boundary= parameter; implement the previously
  empty multipart/form-data branch (ordinary fields only, file
  uploads deferred to a separate upload mechanism per TODO.txt);
  restore operator[] real lookup logic (was hardcoded to echo the
  key back); default-initialize formdata to NULL; fix mismatched
  include guard (leftover from an IMFFormData.h copy-paste); drop
  the unused IMFHeader.h include that pulled in a broken,
  unrelated StreamReader.h dependency.
- CGIFormattedData: parameterize the split delimiter (was hardcoded
  to &, which silently broke cookie parsing since HTTP_COOKIE uses
  ; not &) and trim whitespace on each split token.
- MString::toCGI()/fromCGI(): were unimplemented stubs (always
  returned an empty string); implemented proper CGI percent-encode
  / percent-decode + space plus-encoding, and fixed the one caller
  that discarded fromCGIs return value instead of using it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Brad ArantandClaude Sonnet 5 committed 2026-08-22 21:37:10 -07:00
1 parent 28feaff3d7
commit 94d4a30e88
5 files changed
+121 -34

No files matched your search

+43 -13
View File
@@ -1,28 +1,58 @@
#include "CGIFormData.h"
#include "IMFHeader.h"
#include "malloc.h"
namespace coreutils {
CGIFormData::CGIFormData(int fd, ZString contentType, int contentLength, ZString boundary)
: contentType(contentType) {
if(contentType == "application/x-www-form-urlencoded") {
setSize(contentLength);
: contentType(contentType) {
if(contentType.startsWith("application/x-www-form-urlencoded")) {
read(fd, contentLength);
formdata = new CGIFormattedData(*this);
} else if(contentType == "multipart/form-data") {
} else if(contentType.startsWith("multipart/form-data")) {
read(fd, contentLength);
formdata = new CGIFormattedData();
MString delimiter;
delimiter << "--" << boundary;
ZString body(*this);
body.split(delimiter);
for(int ix = 0; ix < body.getList().size(); ++ix) {
ZString part = body[ix];
if(part.getLength() == 0 || part.startsWith("--"))
continue;
int headerEnd = part.find("\r\n\r\n");
if(headerEnd == -1)
continue;
ZString headers = part.substring(0, headerEnd);
if(headers.find("filename=\"") != -1)
// file uploads are out of scope here; handled via a separate upload mechanism.
continue;
int namePos = headers.find("name=\"");
if(namePos == -1)
continue;
ZString afterName = headers.substring(namePos + 6);
int nameEnd = afterName.find("\"");
if(nameEnd == -1)
continue;
ZString name = afterName.substring(0, nameEnd);
ZString value = part.substring(headerEnd + 4);
value.trimCRLF();
formdata->data[name] = value;
}
}
}
MString CGIFormData::operator[](ZString name) {
// if(contentType == "application/x-www-form-urlencoded")
// return formdata[name];
MString temp(name);
return temp;
if(formdata == NULL)
return MString();
return (*formdata).data[name];
}
}