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:
1 parent
28feaff3d7
commit
94d4a30e88
5 files changed
+121
-34
No files matched your search
+43
-13
@@ -1,28 +1,58 @@
|
|||||||
#include "CGIFormData.h"
|
#include "CGIFormData.h"
|
||||||
#include "IMFHeader.h"
|
|
||||||
#include "malloc.h"
|
#include "malloc.h"
|
||||||
|
|
||||||
namespace coreutils {
|
namespace coreutils {
|
||||||
|
|
||||||
CGIFormData::CGIFormData(int fd, ZString contentType, int contentLength, ZString boundary)
|
CGIFormData::CGIFormData(int fd, ZString contentType, int contentLength, ZString boundary)
|
||||||
: contentType(contentType) {
|
: contentType(contentType) {
|
||||||
if(contentType == "application/x-www-form-urlencoded") {
|
if(contentType.startsWith("application/x-www-form-urlencoded")) {
|
||||||
setSize(contentLength);
|
|
||||||
read(fd, contentLength);
|
read(fd, contentLength);
|
||||||
formdata = new CGIFormattedData(*this);
|
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) {
|
MString CGIFormData::operator[](ZString name) {
|
||||||
// if(contentType == "application/x-www-form-urlencoded")
|
if(formdata == NULL)
|
||||||
// return formdata[name];
|
return MString();
|
||||||
MString temp(name);
|
return (*formdata).data[name];
|
||||||
return temp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
#ifndef __CGIFormData_h__
|
#ifndef __CGIFormData_h__
|
||||||
# define __IMFFormData_h__
|
# define __CGIFormData_h__
|
||||||
|
|
||||||
#include "MString.h"
|
#include "MString.h"
|
||||||
#include "ZString.h"
|
#include "ZString.h"
|
||||||
@@ -15,7 +15,7 @@ namespace coreutils {
|
|||||||
MString operator[](ZString name);
|
MString operator[](ZString name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CGIFormattedData *formdata;
|
CGIFormattedData *formdata = NULL;
|
||||||
MString contentType;
|
MString contentType;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
+22
-16
@@ -4,27 +4,33 @@
|
|||||||
namespace coreutils {
|
namespace coreutils {
|
||||||
|
|
||||||
CGIFormattedData::CGIFormattedData() {}
|
CGIFormattedData::CGIFormattedData() {}
|
||||||
|
|
||||||
CGIFormattedData::CGIFormattedData(ZString cgiData) {
|
CGIFormattedData::CGIFormattedData(ZString cgiData) {
|
||||||
if(cgiData != "") {
|
parse(cgiData);
|
||||||
cgiData.split("&");
|
}
|
||||||
|
|
||||||
|
CGIFormattedData::CGIFormattedData(ZString cgiData, ZString delimiter) : delimiter(delimiter) {
|
||||||
|
parse(cgiData);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGIFormattedData::setDelimiter(ZString delimiter) {
|
||||||
|
this->delimiter = delimiter;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGIFormattedData::parse(ZString cgiData) {
|
||||||
|
if(cgiData != "") {
|
||||||
|
cgiData.split(delimiter);
|
||||||
for(int ix = 0; ix < cgiData.getList().size(); ++ix) {
|
for(int ix = 0; ix < cgiData.getList().size(); ++ix) {
|
||||||
cgiData[ix].split("=");
|
ZString pair = cgiData[ix].trim();
|
||||||
data[cgiData[ix][0]] = cgiData[ix][1];
|
pair.split("=");
|
||||||
data[cgiData[ix][0]].fromCGI();
|
data[pair[0]] = pair[1];
|
||||||
|
data[pair[0]] = data[pair[0]].fromCGI();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ZString CGIFormattedData::operator=(ZString cgiData) {
|
ZString CGIFormattedData::operator=(ZString cgiData) {
|
||||||
if(cgiData != "") {
|
parse(cgiData);
|
||||||
cgiData.split("&");
|
|
||||||
for(int ix = 0; ix < cgiData.getList().size(); ++ix) {
|
|
||||||
cgiData[ix].split("=");
|
|
||||||
data[cgiData[ix][0]] = cgiData[ix][1];
|
|
||||||
data[cgiData[ix][0]].fromCGI();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cgiData;
|
return cgiData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+8
-1
@@ -17,11 +17,18 @@ namespace coreutils {
|
|||||||
public:
|
public:
|
||||||
CGIFormattedData();
|
CGIFormattedData();
|
||||||
CGIFormattedData(ZString cgiData);
|
CGIFormattedData(ZString cgiData);
|
||||||
|
CGIFormattedData(ZString cgiData, ZString delimiter);
|
||||||
|
|
||||||
ZString operator=(ZString cgiData);
|
ZString operator=(ZString cgiData);
|
||||||
|
void setDelimiter(ZString delimiter);
|
||||||
|
|
||||||
std::map<MString, MString> data;
|
std::map<MString, MString> data;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void parse(ZString cgiData);
|
||||||
|
|
||||||
|
ZString delimiter = "&";
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+46
-2
@@ -432,13 +432,57 @@ namespace coreutils {
|
|||||||
|
|
||||||
|
|
||||||
MString MString::toCGI() {
|
MString MString::toCGI() {
|
||||||
|
push();
|
||||||
|
reset();
|
||||||
MString target;
|
MString target;
|
||||||
|
while(!eod()) {
|
||||||
|
char ch = nextChar();
|
||||||
|
if(ch == ' ') {
|
||||||
|
target.write('+');
|
||||||
|
} else if(isalnum((unsigned char)ch) || ch == '-' || ch == '_' || ch == '.' || ch == '~') {
|
||||||
|
target.write(ch);
|
||||||
|
} else {
|
||||||
|
target.write('%');
|
||||||
|
target.write(hexChar((ch >> 4) & 15));
|
||||||
|
target.write(hexChar(ch & 15));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pop();
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
MString MString::fromCGI() {
|
MString MString::fromCGI() {
|
||||||
|
push();
|
||||||
|
reset();
|
||||||
MString target;
|
MString target;
|
||||||
|
while(!eod()) {
|
||||||
|
char ch = nextChar();
|
||||||
|
if(ch == '+') {
|
||||||
|
target.write(' ');
|
||||||
|
} else if(ch == '%' && !eod()) {
|
||||||
|
char ch1 = nextChar();
|
||||||
|
ch1 -= 48;
|
||||||
|
if(ch1 > 9)
|
||||||
|
ch1 -= 7;
|
||||||
|
ch1 <<= 4;
|
||||||
|
ch1 &= 240;
|
||||||
|
if(!eod()) {
|
||||||
|
char ch2 = nextChar();
|
||||||
|
ch2 -= 48;
|
||||||
|
if(ch2 > 9)
|
||||||
|
ch2 -= 7;
|
||||||
|
ch2 &= 15;
|
||||||
|
ch1 |= ch2;
|
||||||
|
target.write(ch1);
|
||||||
|
} else {
|
||||||
|
target.write(ch1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
target.write(ch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pop();
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user