📄 cgi.c
字号:
} else if (outf) {
n->value = (char *) malloc(1);
if (!n->value) {
goto outOfMemory;
}
n->value[0] = '\0';
fclose(outf);
}
n->valueLength = bodyLength;
n->next = 0;
if (!l) {
cgiFormEntryFirst = n;
} else {
l->next = n;
}
n->fileName = (char *) malloc(strlen(ffileName) + 1);
if (!n->fileName) {
goto outOfMemory;
}
strcpy(n->fileName, ffileName);
n->contentType = (char *) malloc(strlen(fcontentType) + 1);
if (!n->contentType) {
goto outOfMemory;
}
strcpy(n->contentType, fcontentType);
n->tfileName = (char *) malloc(strlen(tfileName) + 1);
if (!n->tfileName) {
goto outOfMemory;
}
strcpy(n->tfileName, tfileName);
l = n;
}
return cgiParseSuccess;
outOfMemory:
if (n) {
if (n->attr) {
free(n->attr);
}
if (n->value) {
free(n->value);
}
if (n->fileName) {
free(n->fileName);
}
if (n->tfileName) {
free(n->tfileName);
}
if (n->contentType) {
free(n->contentType);
}
free(n);
}
if (out) {
free(out);
}
if (outf) {
fclose(outf);
unlink(tfileName);
}
return cgiParseMemory;
}
static cgiParseResultType getTempFileName(char *tfileName)
{
#ifndef WIN32
/* Unix. Use the robust 'mkstemp' function to create
a temporary file that is truly unique, with
permissions that are truly safe. The
fopen-for-write destroys any bogus information
written by potential hackers during the brief
window between the file's creation and the
chmod call (glibc 2.0.6 and lower might
otherwise have allowed this). */
int outfd;
strcpy(tfileName, cgicTempDir "/cgicXXXXXX");
outfd = mkstemp(tfileName);
if (outfd == -1) {
return cgiParseIO;
}
close(outfd);
/* Fix the permissions */
if (chmod(tfileName, 0600) != 0) {
unlink(tfileName);
return cgiParseIO;
}
#else
/* Non-Unix. Do what we can. */
if (!tmpnam(tfileName)) {
return cgiParseIO;
}
#endif
return cgiParseSuccess;
}
#define APPEND(string, char) \
{ \
if ((string##Len + 1) < string##Space) { \
string[string##Len++] = (char); \
} \
}
#define RAPPEND(string, ch) \
{ \
if ((string##Len + 1) == string##Space) { \
char *sold = string; \
string##Space *= 2; \
string = (char *) realloc(string, string##Space); \
if (!string) { \
string = sold; \
goto outOfMemory; \
} \
} \
string[string##Len++] = (ch); \
}
#define BAPPEND(ch) \
{ \
if (outf) { \
putc(ch, outf); \
outLen++; \
} else if (out) { \
RAPPEND(out, ch); \
} \
}
cgiParseResultType afterNextBoundary(mpStreamPtr mpp, FILE *outf, char **outP,
int *bodyLengthP, int first)
{
int outLen = 0;
int outSpace = 256;
char *out = 0;
cgiParseResultType result;
int boffset;
int got;
char d[2];
/* This is large enough, because the buffer into which the
original boundary string is fetched is shorter by more
than four characters due to the space required for
the attribute name */
char workingBoundaryData[1024];
char *workingBoundary = workingBoundaryData;
int workingBoundaryLength;
if ((!outf) && (outP)) {
out = (char *) malloc(outSpace);
if (!out) {
goto outOfMemory;
}
}
boffset = 0;
sprintf(workingBoundaryData, "\r\n--%s", cgiMultipartBoundary);
if (first) {
workingBoundary = workingBoundaryData + 2;
}
workingBoundaryLength = strlen(workingBoundary);
while (1) {
got = mpRead(mpp, d, 1);
if (got != 1) {
/* 2.01: cgiParseIO, not cgiFormIO */
result = cgiParseIO;
goto error;
}
if (d[0] == workingBoundary[boffset]) {
/* We matched the next byte of the boundary.
Keep track of our progress into the
boundary and don't emit anything. */
boffset++;
if (boffset == workingBoundaryLength) {
break;
}
} else if (boffset > 0) {
/* We matched part, but not all, of the
boundary. Now we have to be careful:
put back all except the first
character and try again. The
real boundary could begin in the
middle of a false match. We can
emit the first character only so far. */
BAPPEND(workingBoundary[0]);
mpPutBack(mpp,
workingBoundary + 1, boffset - 1);
mpPutBack(mpp, d, 1);
boffset = 0;
} else {
/* Not presently in the middle of a boundary
match; just emit the character. */
BAPPEND(d[0]);
}
}
/* Read trailing newline or -- EOF marker. A literal EOF here
would be an error in the input stream. */
got = mpRead(mpp, d, 2);
if (got != 2) {
result = cgiParseIO;
goto error;
}
if ((d[0] == '\r') && (d[1] == '\n')) {
/* OK, EOL */
} else if (d[0] == '-') {
/* Probably EOF, but we check for
that later */
mpPutBack(mpp, d, 2);
}
if (out && outSpace) {
char *oout = out;
out[outLen] = '\0';
out = (char *) realloc(out, outLen + 1);
if (!out) {
/* Surprising if it happens; and not fatal! We were
just trying to give some space back. We can
keep it if we have to. */
out = oout;
}
*outP = out;
}
if (bodyLengthP) {
*bodyLengthP = outLen;
}
return cgiParseSuccess;
outOfMemory:
result = cgiParseMemory;
if (outP) {
if (out) {
free(out);
}
*outP = '\0';
}
error:
if (bodyLengthP) {
*bodyLengthP = 0;
}
if (out) {
free(out);
}
if (outP) {
*outP = 0;
}
return result;
}
static void decomposeValue(char *value,
char *mvalue, int mvalueSpace,
char **argNames,
char **argValues,
int argValueSpace)
{
char argName[1024];
int argNameSpace = sizeof(argName);
int argNameLen = 0;
int mvalueLen = 0;
char *argValue;
int argNum = 0;
while (argNames[argNum]) {
if (argValueSpace) {
argValues[argNum][0] = '\0';
}
argNum++;
}
while (isspace(*value)) {
value++;
}
/* Quoted mvalue */
if (*value == '\"') {
value++;
while ((*value) && (*value != '\"')) {
APPEND(mvalue, *value);
value++;
}
while ((*value) && (*value != ';')) {
value++;
}
} else {
/* Unquoted mvalue */
while ((*value) && (*value != ';')) {
APPEND(mvalue, *value);
value++;
}
}
if (mvalueSpace) {
mvalue[mvalueLen] = '\0';
}
while (*value == ';') {
int argNum;
int argValueLen = 0;
/* Skip the ; between parameters */
value++;
/* Now skip leading whitespace */
while ((*value) && (isspace(*value))) {
value++;
}
/* Now read the parameter name */
argNameLen = 0;
while ((*value) && (isalnum(*value))) {
APPEND(argName, *value);
value++;
}
if (argNameSpace) {
argName[argNameLen] = '\0';
}
while ((*value) && isspace(*value)) {
value++;
}
if (*value != '=') {
/* Malformed line */
return;
}
value++;
while ((*value) && isspace(*value)) {
value++;
}
/* Find the parameter in the argument list, if present */
argNum = 0;
argValue = 0;
while (argNames[argNum]) {
if (cgiStrEqNc(argName, argNames[argNum])) {
argValue = argValues[argNum];
break;
}
argNum++;
}
/* Finally, read the parameter value */
if (*value == '\"') {
value++;
while ((*value) && (*value != '\"')) {
if (argValue) {
APPEND(argValue, *value);
}
value++;
}
while ((*value) && (*value != ';')) {
value++;
}
} else {
/* Unquoted value */
while ((*value) && (*value != ';')) {
if (argNames[argNum]) {
APPEND(argValue, *value);
}
value++;
}
}
if (argValueSpace) {
argValue[argValueLen] = '\0';
}
}
}
static int readHeaderLine(
mpStreamPtr mpp,
char *attr,
int attrSpace,
char *value,
int valueSpace)
{
int attrLen = 0;
int valueLen = 0;
int valueFound = 0;
while (1) {
char d[1];
int got = mpRead(mpp, d, 1);
if (got != 1) {
return 0;
}
if (d[0] == '\r') {
got = mpRead(mpp, d, 1);
if (got == 1) {
if (d[0] == '\n') {
/* OK */
} else {
mpPutBack(mpp, d, 1);
}
}
break;
} else if (d[0] == '\n') {
break;
} else if ((d[0] == ':') && attrLen) {
valueFound = 1;
while (mpRead(mpp, d, 1) == 1) {
if (!isspace(d[0])) {
mpPutBack(mpp, d, 1);
break;
}
}
} else if (!valueFound) {
if (!isspace(*d)) {
if (attrLen < (attrSpace - 1)) {
attr[attrLen++] = *d;
}
}
} else if (valueFound) {
if (valueLen < (valueSpace - 1)) {
value[valueLen++] = *d;
}
}
}
if (attrSpace) {
attr[attrLen] = '\0';
}
if (valueSpace) {
value[valueLen] = '\0';
}
if (attrLen && valueLen) {
return 1;
} else {
return 0;
}
}
static cgiParseResultType cgiParseGetFormInput() {
return cgiParseFormInput(cgiQueryString, cgiContentLength);
}
typedef enum {
cgiEscapeRest,
cgiEscapeFirst,
cgiEscapeSecond
} cgiEscapeState;
typedef enum {
cgiUnescapeSuccess,
cgiUnescapeMemory
} cgiUnescapeResultType;
static cgiUnescapeResultType cgiUnescapeChars(char **sp, char *cp, int len);
static cgiParseResultType cgiParseFormInput(char *data, int length) {
/* Scan for pairs, unescaping and storing them as they are found. */
int pos = 0;
cgiFormEntry *n;
cgiFormEntry *l = 0;
while (pos != length) {
int foundEq = 0;
int foundAmp = 0;
int start = pos;
int len = 0;
char *attr;
char *value;
while (pos != length) {
if (data[pos] == '=') {
foundEq = 1;
pos++;
break;
}
pos++;
len++;
}
if (!foundEq) {
break;
}
if (cgiUnescapeChars(&attr, data+start, len)
!= cgiUnescapeSuccess) {
return cgiParseMemory;
}
start = pos;
len = 0;
while (pos != length) {
if (data[pos] == '&') {
foundAmp = 1;
pos++;
break;
}
pos++;
len++;
}
/* The last pair probably won't be followed by a &, but
that's fine, so check for that after accepting it */
if (cgiUnescapeChars(&value, data+start, len)
!= cgiUnescapeSuccess) {
free(attr);
return cgiParseMemory;
}
/* OK, we have a new pair, add it to the list. */
n = (cgiFormEntry *) malloc(sizeof(cgiFormEntry));
if (!n) {
free(attr);
free(value);
return cgiParseMemory;
}
n->attr = attr;
n->value = value;
n->valueLength = strlen(n->value);
n->fileName = (char *) malloc(1);
if (!n->fileName) {
free(attr);
free(value);
free(n);
return cgiParseMemory;
}
n->fileName[0] = '\0';
n->contentType = (char *) malloc(1);
if (!n->contentType) {
free(attr);
free(value);
free(n->fileName);
free(n);
return cgiParseMemory;
}
n->contentType[0] = '\0';
n->tfileName = (char *) malloc(1);
if (!n->tfileName) {
free(attr);
free(value);
free(n->fileName);
free(n->contentType);
free(n);
return cgiParseMemory;
}
n->tfileName[0] = '\0';
n->next = 0;
if (!l) {
cgiFormEntryFirst = n;
} else {
l->next = n;
}
l = n;
if (!foundAmp) {
break;
}
}
return cgiParseSuccess;
}
static int cgiHexValue[256];
cgiUnescapeResultType cgiUnescapeChars(char **sp, char *cp, int len) {
char *s;
cgiEscapeState escapeState = cgiEscapeRest;
int escapedValue = 0;
int srcPos = 0;
int dstPos = 0;
s = (char *) malloc(len + 1);
if (!s) {
return cgiUnescapeMemory;
}
while (srcPos < len) {
int ch = cp[srcPos];
switch (escapeState) {
case cgiEscapeRest:
if (ch == '%') {
escapeState = cgiEscapeFirst;
} else if (ch == '+') {
s[dstPos++] = ' ';
} else {
s[dstPos++] = ch;
}
break;
case cgiEscapeFirst:
escapedValue = cgiHexValue[ch] << 4;
escapeState = cgiEscapeSecond;
break;
case cgiEscapeSecond:
escapedValue += cgiHexValue[ch];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -