From 250dce3faa1d07c6376fde5b6d7a2245dcebebc3 Mon Sep 17 00:00:00 2001 From: tenox7 Date: Sat, 14 Jul 2018 02:43:18 -0700 Subject: merged new cgic version, disabled upload status --- cgic.c | 4313 ++++++++++++++++++++++++++++++++-------------------------------- cgic.h | 17 +- dir.c | 12 +- wfm.c | 6 +- wfm.h | 2 +- 5 files changed, 2182 insertions(+), 2168 deletions(-) diff --git a/cgic.c b/cgic.c index bcb2690..8b32b11 100644 --- a/cgic.c +++ b/cgic.c @@ -1,22 +1,22 @@ /* cgicTempDir is the only setting you are likely to need - to change in this file. */ + to change in this file. */ /* Used only in Unix environments, in conjunction with mkstemp(). - Elsewhere (Windows), temporary files go where the tmpnam() - function suggests. If this behavior does not work for you, - modify the getTempFileName() function to suit your needs. */ + Elsewhere (Windows), temporary files go where the tmpnam() + function suggests. If this behavior does not work for you, + modify the getTempFileName() function to suit your needs. */ #define cgicTempDir "/tmp" #if CGICDEBUG #define CGICDEBUGSTART \ - { \ - FILE *dout; \ - dout = fopen("/home/boutell/public_html/debug", "a"); \ - + { \ + FILE *dout; \ + dout = fopen("/home/boutell/public_html/debug", "a"); \ + #define CGICDEBUGEND \ - fclose(dout); \ - } + fclose(dout); \ + } #else /* CGICDEBUG */ #define CGICDEBUGSTART #define CGICDEBUGEND @@ -29,8 +29,6 @@ #include #include #include -#include -#include #ifdef WIN32 #include @@ -69,12 +67,6 @@ char *cgiAccept; char *cgiUserAgent; char *cgiReferrer; -char *shm_val=NULL; -int shm_key=-1; -int shm_id=-1; -#define SHM_SIZE 16 - - FILE *cgiIn; FILE *cgiOut; @@ -84,34 +76,34 @@ static int cgiRestored = 0; static void cgiGetenv(char **s, char *var); typedef enum { - cgiParseSuccess, - cgiParseMemory, - cgiParseIO + cgiParseSuccess, + cgiParseMemory, + cgiParseIO } cgiParseResultType; /* One form entry, consisting of an attribute-value pair, - and an optional filename and content type. All of - these are guaranteed to be valid null-terminated strings, - which will be of length zero in the event that the - field is not present, with the exception of tfileName - which will be null when 'in' is null. DO NOT MODIFY THESE - VALUES. Make local copies if modifications are desired. */ + and an optional filename and content type. All of + these are guaranteed to be valid null-terminated strings, + which will be of length zero in the event that the + field is not present, with the exception of tfileName + which will be null when 'in' is null. DO NOT MODIFY THESE + VALUES. Make local copies if modifications are desired. */ typedef struct cgiFormEntryStruct { - char *attr; - /* value is populated for regular form fields only. - For file uploads, it points to an empty string, and file - upload data should be read from the file tfileName. */ - char *value; - /* When fileName is not an empty string, tfileName is not null, - and 'value' points to an empty string. */ - /* Valid for both files and regular fields; does not include - terminating null of regular fields. */ - int valueLength; - char *fileName; - char *contentType; - /* Temporary file name for working storage of file uploads. */ - char *tfileName; + char *attr; + /* value is populated for regular form fields only. + For file uploads, it points to an empty string, and file + upload data should be read from the file tfileName. */ + char *value; + /* When fileName is not an empty string, tfileName is not null, + and 'value' points to an empty string. */ + /* Valid for both files and regular fields; does not include + terminating null of regular fields. */ + int valueLength; + char *fileName; + char *contentType; + /* Temporary file descriptor for working storage of file uploads. */ + FILE *tFile; struct cgiFormEntryStruct *next; } cgiFormEntry; @@ -127,1776 +119,1765 @@ static void cgiFreeResources(); static int cgiStrEqNc(char *s1, char *s2); static int cgiStrBeginsNc(char *s1, char *s2); -/* Dirty little hack to get file upload progress - Part 4: SHM Cleanup */ -void shmcleanup(void) { - if(shm_id>=0) - shmctl(shm_id, IPC_RMID, NULL); -} +#ifdef UNIT_TEST +static int unitTest(); +#endif int main(int argc, char *argv[]) { - int result; - char *cgiContentLengthString; - char *e; - cgiSetupConstants(); - cgiGetenv(&cgiServerSoftware, "SERVER_SOFTWARE"); - cgiGetenv(&cgiServerName, "SERVER_NAME"); - cgiGetenv(&cgiGatewayInterface, "GATEWAY_INTERFACE"); - cgiGetenv(&cgiServerProtocol, "SERVER_PROTOCOL"); - cgiGetenv(&cgiServerPort, "SERVER_PORT"); - cgiGetenv(&cgiRequestMethod, "REQUEST_METHOD"); - cgiGetenv(&cgiPathInfo, "PATH_INFO"); - cgiGetenv(&cgiPathTranslated, "PATH_TRANSLATED"); - cgiGetenv(&cgiScriptName, "SCRIPT_NAME"); - cgiGetenv(&cgiQueryString, "QUERY_STRING"); - cgiGetenv(&cgiRemoteHost, "REMOTE_HOST"); - cgiGetenv(&cgiRemoteAddr, "REMOTE_ADDR"); - cgiGetenv(&cgiAuthType, "AUTH_TYPE"); - cgiGetenv(&cgiRemoteUser, "REMOTE_USER"); - cgiGetenv(&cgiRemoteIdent, "REMOTE_IDENT"); - /* 2.0: the content type string needs to be parsed and modified, so - copy it to a buffer. */ - e = getenv("CONTENT_TYPE"); - if (e) { - if (strlen(e) < sizeof(cgiContentTypeData)) { - strcpy(cgiContentType, e); - } else { - /* Truncate safely in the event of what is almost certainly - a hack attempt */ - strncpy(cgiContentType, e, sizeof(cgiContentTypeData)); - cgiContentType[sizeof(cgiContentTypeData) - 1] = '\0'; - } - } else { - cgiContentType[0] = '\0'; - } - /* Never null */ - cgiMultipartBoundary = ""; - /* 2.0: parse semicolon-separated additional parameters of the - content type. The one we're interested in is 'boundary'. - We discard the rest to make cgiContentType more useful - to the typical programmer. */ - if (strchr(cgiContentType, ';')) { - char *sat = strchr(cgiContentType, ';'); - while (sat) { - *sat = '\0'; - sat++; - while (isspace((int)*sat)) { - sat++; - } - if (cgiStrBeginsNc(sat, "boundary=")) { - char *s; - cgiMultipartBoundary = sat + strlen("boundary="); - s = cgiMultipartBoundary; - while ((*s) && (!isspace((int)*s))) { - s++; - } - *s = '\0'; - break; - } else { - sat = strchr(sat, ';'); - } - } - } - cgiGetenv(&cgiContentLengthString, "CONTENT_LENGTH"); - cgiContentLength = atoi(cgiContentLengthString); - cgiGetenv(&cgiAccept, "HTTP_ACCEPT"); - cgiGetenv(&cgiUserAgent, "HTTP_USER_AGENT"); - cgiGetenv(&cgiReferrer, "HTTP_REFERER"); - cgiGetenv(&cgiCookie, "HTTP_COOKIE"); + int result; + char *cgiContentLengthString; + char *e; + cgiSetupConstants(); + cgiGetenv(&cgiServerSoftware, "SERVER_SOFTWARE"); + cgiGetenv(&cgiServerName, "SERVER_NAME"); + cgiGetenv(&cgiGatewayInterface, "GATEWAY_INTERFACE"); + cgiGetenv(&cgiServerProtocol, "SERVER_PROTOCOL"); + cgiGetenv(&cgiServerPort, "SERVER_PORT"); + cgiGetenv(&cgiRequestMethod, "REQUEST_METHOD"); + cgiGetenv(&cgiPathInfo, "PATH_INFO"); + cgiGetenv(&cgiPathTranslated, "PATH_TRANSLATED"); + cgiGetenv(&cgiScriptName, "SCRIPT_NAME"); + cgiGetenv(&cgiQueryString, "QUERY_STRING"); + cgiGetenv(&cgiRemoteHost, "REMOTE_HOST"); + cgiGetenv(&cgiRemoteAddr, "REMOTE_ADDR"); + cgiGetenv(&cgiAuthType, "AUTH_TYPE"); + cgiGetenv(&cgiRemoteUser, "REMOTE_USER"); + cgiGetenv(&cgiRemoteIdent, "REMOTE_IDENT"); + /* 2.0: the content type string needs to be parsed and modified, so + copy it to a buffer. */ + e = getenv("CONTENT_TYPE"); + if (e) { + if (strlen(e) < sizeof(cgiContentTypeData)) { + strcpy(cgiContentType, e); + } else { + /* Truncate safely in the event of what is almost certainly + a hack attempt */ + strncpy(cgiContentType, e, sizeof(cgiContentTypeData)); + cgiContentType[sizeof(cgiContentTypeData) - 1] = '\0'; + } + } else { + cgiContentType[0] = '\0'; + } + /* Never null */ + cgiMultipartBoundary = ""; + /* 2.0: parse semicolon-separated additional parameters of the + content type. The one we're interested in is 'boundary'. + We discard the rest to make cgiContentType more useful + to the typical programmer. */ + if (strchr(cgiContentType, ';')) { + char *sat = strchr(cgiContentType, ';'); + while (sat) { + *sat = '\0'; + sat++; + while (isspace(*sat)) { + sat++; + } + if (cgiStrBeginsNc(sat, "boundary=")) { + char *s; + cgiMultipartBoundary = sat + strlen("boundary="); + s = cgiMultipartBoundary; + while ((*s) && (!isspace(*s))) { + s++; + } + *s = '\0'; + break; + } else { + sat = strchr(sat, ';'); + } + } + } + cgiGetenv(&cgiContentLengthString, "CONTENT_LENGTH"); + cgiContentLength = atoi(cgiContentLengthString); + cgiGetenv(&cgiAccept, "HTTP_ACCEPT"); + cgiGetenv(&cgiUserAgent, "HTTP_USER_AGENT"); + cgiGetenv(&cgiReferrer, "HTTP_REFERER"); + cgiGetenv(&cgiCookie, "HTTP_COOKIE"); #ifdef CGICDEBUG - CGICDEBUGSTART - fprintf(dout, "%d\n", cgiContentLength); - fprintf(dout, "%s\n", cgiRequestMethod); - fprintf(dout, "%s\n", cgiContentType); - CGICDEBUGEND + CGICDEBUGSTART + fprintf(dout, "%d\n", cgiContentLength); + fprintf(dout, "%s\n", cgiRequestMethod); + fprintf(dout, "%s\n", cgiContentType); + CGICDEBUGEND #endif /* CGICDEBUG */ #ifdef WIN32 - /* 1.07: Must set stdin and stdout to binary mode */ - /* 2.0: this is particularly crucial now and must not be removed */ - _setmode( _fileno( stdin ), _O_BINARY ); - _setmode( _fileno( stdout ), _O_BINARY ); + /* 1.07: Must set stdin and stdout to binary mode */ + /* 2.0: this is particularly crucial now and must not be removed */ + _setmode( _fileno( stdin ), _O_BINARY ); + _setmode( _fileno( stdout ), _O_BINARY ); #endif /* WIN32 */ - cgiFormEntryFirst = 0; - cgiIn = stdin; - cgiOut = stdout; - cgiRestored = 0; + cgiFormEntryFirst = 0; + cgiIn = stdin; + cgiOut = stdout; + cgiRestored = 0; - /* These five lines keep compilers from - producing warnings that argc and argv - are unused. They have no actual function. */ - if (argc) { - if (argv[0]) { - cgiRestored = 0; - } - } + /* These five lines keep compilers from + producing warnings that argc and argv + are unused. They have no actual function. */ + if (argc) { + if (argv[0]) { + cgiRestored = 0; + } + } - if (cgiStrEqNc(cgiRequestMethod, "post")) { + if (cgiStrEqNc(cgiRequestMethod, "post")) { #ifdef CGICDEBUG - CGICDEBUGSTART - fprintf(dout, "POST recognized\n"); - CGICDEBUGEND + CGICDEBUGSTART + fprintf(dout, "POST recognized\n"); + CGICDEBUGEND #endif /* CGICDEBUG */ - if (cgiStrEqNc(cgiContentType, "application/x-www-form-urlencoded")) { + if (cgiStrEqNc(cgiContentType, "application/x-www-form-urlencoded")) { #ifdef CGICDEBUG - CGICDEBUGSTART - fprintf(dout, "Calling PostFormInput\n"); - CGICDEBUGEND + CGICDEBUGSTART + fprintf(dout, "Calling PostFormInput\n"); + CGICDEBUGEND #endif /* CGICDEBUG */ - if (cgiParsePostFormInput() != cgiParseSuccess) { + if (cgiParsePostFormInput() != cgiParseSuccess) { #ifdef CGICDEBUG - CGICDEBUGSTART - fprintf(dout, "PostFormInput failed\n"); - CGICDEBUGEND + CGICDEBUGSTART + fprintf(dout, "PostFormInput failed\n"); + CGICDEBUGEND #endif /* CGICDEBUG */ - cgiFreeResources(); - return -1; - } + cgiHeaderStatus(500, "Error reading form data"); + cgiFreeResources(); + return -1; + } #ifdef CGICDEBUG - CGICDEBUGSTART - fprintf(dout, "PostFormInput succeeded\n"); - CGICDEBUGEND + CGICDEBUGSTART + fprintf(dout, "PostFormInput succeeded\n"); + CGICDEBUGEND #endif /* CGICDEBUG */ - } else if (cgiStrEqNc(cgiContentType, "multipart/form-data")) { + } else if (cgiStrEqNc(cgiContentType, "multipart/form-data")) { #ifdef CGICDEBUG - CGICDEBUGSTART - fprintf(dout, "Calling PostMultipartInput\n"); - CGICDEBUGEND + CGICDEBUGSTART + fprintf(dout, "Calling PostMultipartInput\n"); + CGICDEBUGEND #endif /* CGICDEBUG */ - if (cgiParsePostMultipartInput() != cgiParseSuccess) { + if (cgiParsePostMultipartInput() != cgiParseSuccess) { #ifdef CGICDEBUG - CGICDEBUGSTART - fprintf(dout, "PostMultipartInput failed\n"); - CGICDEBUGEND + CGICDEBUGSTART + fprintf(dout, "PostMultipartInput failed\n"); + CGICDEBUGEND #endif /* CGICDEBUG */ - cgiFreeResources(); - return -1; - } + cgiHeaderStatus(500, "Error reading form data"); + cgiFreeResources(); + return -1; + } #ifdef CGICDEBUG - CGICDEBUGSTART - fprintf(dout, "PostMultipartInput succeeded\n"); - CGICDEBUGEND + CGICDEBUGSTART + fprintf(dout, "PostMultipartInput succeeded\n"); + CGICDEBUGEND #endif /* CGICDEBUG */ - } - } else if (cgiStrEqNc(cgiRequestMethod, "get")) { - /* The spec says this should be taken care of by - the server, but... it isn't */ - cgiContentLength = strlen(cgiQueryString); - if (cgiParseGetFormInput() != cgiParseSuccess) { + } + } else if (cgiStrEqNc(cgiRequestMethod, "get")) { + /* The spec says this should be taken care of by + the server, but... it isn't */ + cgiContentLength = strlen(cgiQueryString); + if (cgiParseGetFormInput() != cgiParseSuccess) { #ifdef CGICDEBUG - CGICDEBUGSTART - fprintf(dout, "GetFormInput failed\n"); - CGICDEBUGEND + CGICDEBUGSTART + fprintf(dout, "GetFormInput failed\n"); + CGICDEBUGEND #endif /* CGICDEBUG */ - cgiFreeResources(); - return -1; - } else { + cgiHeaderStatus(500, "Error reading form data"); + cgiFreeResources(); + return -1; + } else { #ifdef CGICDEBUG - CGICDEBUGSTART - fprintf(dout, "GetFormInput succeeded\n"); - CGICDEBUGEND + CGICDEBUGSTART + fprintf(dout, "GetFormInput succeeded\n"); + CGICDEBUGEND #endif /* CGICDEBUG */ - } - } - result = cgiMain(); - cgiFreeResources(); - return result; + } + } +#ifdef UNIT_TEST + unitTest(); + cgiFreeResources(); + return 0; +#else + result = cgiMain(); + return result; +#endif } static void cgiGetenv(char **s, char *var){ - *s = getenv(var); - if (!(*s)) { - *s = ""; - } + *s = getenv(var); + if (!(*s)) { + *s = ""; + } } static cgiParseResultType cgiParsePostFormInput() { - char *input; - cgiParseResultType result; - if (!cgiContentLength) { - return cgiParseSuccess; - } - input = (char *) malloc(cgiContentLength); - if (!input) { - return cgiParseMemory; - } - if (((int) fread(input, 1, cgiContentLength, cgiIn)) - != cgiContentLength) - { - return cgiParseIO; - } - result = cgiParseFormInput(input, cgiContentLength); - free(input); - return result; + char *input; + cgiParseResultType result; + if (!cgiContentLength) { + return cgiParseSuccess; + } + input = (char *) malloc(cgiContentLength); + if (!input) { + return cgiParseMemory; + } + if (((int) fread(input, 1, cgiContentLength, cgiIn)) + != cgiContentLength) + { + return cgiParseIO; + } + result = cgiParseFormInput(input, cgiContentLength); + free(input); + return result; } /* 2.0: A virtual datastream supporting putback of - enough characters to handle multipart boundaries easily. - A simple memset(&mp, 0, sizeof(mp)) is suitable initialization. */ + enough characters to handle multipart boundaries easily. + A simple memset(&mp, 0, sizeof(mp)) is suitable initialization. */ typedef struct { - /* Buffer for putting characters back */ - char putback[1024]; - /* Position in putback from which next character will be read. - If readPos == writePos, then next character should - come from cgiIn. */ - int readPos; - /* Position in putback to which next character will be put back. - If writePos catches up to readPos, as opposed to the other - way around, the stream no longer functions properly. - Calling code must guarantee that no more than - sizeof(putback) bytes are put back at any given time. */ - int writePos; - /* Offset in the virtual datastream; can be compared - to cgiContentLength */ - int offset; + /* Buffer for putting characters back */ + char putback[1024]; + /* Position in putback from which next character will be read. + If readPos == writePos, then next character should + come from cgiIn. */ + int readPos; + /* Position in putback to which next character will be put back. + If writePos catches up to readPos, as opposed to the other + way around, the stream no longer functions properly. + Calling code must guarantee that no more than + sizeof(putback) bytes are put back at any given time. */ + int writePos; + /* Offset in the virtual datastream; can be compared + to cgiContentLength */ + int offset; } mpStream, *mpStreamPtr; int mpRead(mpStreamPtr mpp, char *buffer, int len) { - int ilen = len; - int got = 0; - while (len) { - if (mpp->readPos != mpp->writePos) { - *buffer++ = mpp->putback[mpp->readPos++]; - mpp->readPos %= sizeof(mpp->putback); - got++; - len--; - } else { - break; - } - } - /* Refuse to read past the declared length in order to - avoid deadlock */ - if (len > (cgiContentLength - mpp->offset)) { - len = cgiContentLength - mpp->offset; - } - if (len) { - int fgot = fread(buffer, 1, len, cgiIn); - if (fgot >= 0) { - mpp->offset += (got + fgot); - return got + fgot; - } else if (got > 0) { - mpp->offset += got; - return got; - } else { - /* EOF or error */ - return fgot; - } - } else if (got) { - return got; - } else if (ilen) { - return EOF; - } else { - /* 2.01 */ - return 0; - } + int ilen = len; + int got = 0; + /* Refuse to read past the declared length in order to + avoid deadlock */ + if (len > (cgiContentLength - mpp->offset)) { + len = cgiContentLength - mpp->offset; + } + while (len) { + if (mpp->readPos != mpp->writePos) { + *buffer++ = mpp->putback[mpp->readPos++]; + mpp->readPos %= sizeof(mpp->putback); + got++; + len--; + } else { + break; + } + } + if (len) { + int fgot = fread(buffer, 1, len, cgiIn); + if (fgot >= 0) { + mpp->offset += (got + fgot); + return got + fgot; + } else if (got > 0) { + mpp->offset += got; + return got; + } else { + /* EOF or error */ + return fgot; + } + } else if (got) { + mpp->offset += got; + return got; + } else if (ilen) { + return EOF; + } else { + /* 2.01 */ + return 0; + } } void mpPutBack(mpStreamPtr mpp, char *data, int len) { - mpp->offset -= len; - while (len) { - mpp->putback[mpp->writePos++] = *data++; - mpp->writePos %= sizeof(mpp->putback); - len--; - } + mpp->offset -= len; + while (len) { + mpp->putback[mpp->writePos++] = *data++; + mpp->writePos %= sizeof(mpp->putback); + len--; + } } /* This function copies the body to outf if it is not null, otherwise to - a newly allocated character buffer at *outP, which will be null - terminated; if both outf and outP are null the body is not stored. - If bodyLengthP is not null, the size of the body in bytes is stored - to *bodyLengthP, not including any terminating null added to *outP. - If 'first' is nonzero, a preceding newline is not expected before - the boundary. If 'first' is zero, a preceding newline is expected. - Upon return mpp is positioned after the boundary and its trailing - newline, if any; if the boundary is followed by -- the next two - characters read after this function returns will be --. Upon error, - if outP is not null, *outP is a null pointer; *bodyLengthP - is set to zero. Returns cgiParseSuccess, cgiParseMemory - or cgiParseIO. */ + a newly allocated character buffer at *outP, which will be null + terminated; if both outf and outP are null the body is not stored. + If bodyLengthP is not null, the size of the body in bytes is stored + to *bodyLengthP, not including any terminating null added to *outP. + If 'first' is nonzero, a preceding newline is not expected before + the boundary. If 'first' is zero, a preceding newline is expected. + Upon return mpp is positioned after the boundary and its trailing + newline, if any; if the boundary is followed by -- the next two + characters read after this function returns will be --. Upon error, + if outP is not null, *outP is a null pointer; *bodyLengthP + is set to zero. Returns cgiParseSuccess, cgiParseMemory + or cgiParseIO. */ static cgiParseResultType afterNextBoundary(mpStreamPtr mpp, - FILE *outf, - char **outP, - int *bodyLengthP, - int first - ); + FILE *outf, + char **outP, + int *bodyLengthP, + int first + ); static int readHeaderLine( - mpStreamPtr mpp, - char *attr, - int attrSpace, - char *value, - int valueSpace); + mpStreamPtr mpp, + char *attr, + int attrSpace, + char *value, + int valueSpace); static void decomposeValue(char *value, - char *mvalue, int mvalueSpace, - char **argNames, - char **argValues, - int argValueSpace); - -/* tfileName must be 1024 bytes to ensure adequacy on - win32 (1024 exceeds the maximum path length and - certainly exceeds observed behavior of _tmpnam). - May as well also be 1024 bytes on Unix, although actual - length is strlen(cgiTempDir) + a short unique pattern. */ - -static cgiParseResultType getTempFileName(char *tfileName); + char *mvalue, int mvalueSpace, + char **argNames, + char **argValues, + int argValueSpace); + +static cgiParseResultType getTempFileName(FILE **tFile); static cgiParseResultType cgiParsePostMultipartInput() { - cgiParseResultType result; - cgiFormEntry *n = 0, *l = 0; - int got; - int sig; - FILE *outf = 0; - char *out = 0; - char tfileName[1024]; - mpStream mp; - mpStreamPtr mpp = ∓ - memset(&mp, 0, sizeof(mp)); - if (!cgiContentLength) { - return cgiParseSuccess; - } - /* Read first boundary, including trailing newline */ - result = afterNextBoundary(mpp, 0, 0, 0, 1); - if (result == cgiParseIO) { - /* An empty submission is not necessarily an error */ - return cgiParseSuccess; - } else if (result != cgiParseSuccess) { - return result; - } - while (1) { - char d[1024]; - char fvalue[1024]; - char fname[1024]; - int bodyLength = 0; - char ffileName[1024]; - char fcontentType[1024]; - char attr[1024]; - char value[1024]; - fvalue[0] = 0; - fname[0] = 0; - ffileName[0] = 0; - fcontentType[0] = 0; - out = 0; - outf = 0; - /* Check for EOF */ - got = mpRead(mpp, d, 2); - if (got < 2) { - /* Crude EOF */ - break; - } - if ((d[0] == '-') && (d[1] == '-')) { - /* Graceful EOF */ - break; - } - mpPutBack(mpp, d, 2); - /* Read header lines until end of header */ - while (readHeaderLine( - mpp, attr, sizeof(attr), value, sizeof(value))) - { - char *argNames[3]; - char *argValues[2]; - /* Content-Disposition: form-data; - name="test"; filename="googley.gif" */ - if (cgiStrEqNc(attr, "Content-Disposition")) { - argNames[0] = "name"; - argNames[1] = "filename"; - argNames[2] = 0; - argValues[0] = fname; - argValues[1] = ffileName; - decomposeValue(value, - fvalue, sizeof(fvalue), - argNames, - argValues, - 1024); - } else if (cgiStrEqNc(attr, "Content-Type")) { - argNames[0] = 0; - decomposeValue(value, - fcontentType, sizeof(fcontentType), - argNames, - 0, - 0); - } - } - if (!cgiStrEqNc(fvalue, "form-data")) { - /* Not form data */ - continue; - } - /* Body is everything from here until the next - boundary. So, set it aside and move past boundary. - If a filename was submitted as part of the - disposition header, store to a temporary file. - Otherwise, store to a memory buffer (it is - presumably a regular form field). */ - if (strlen(ffileName)) { - if (getTempFileName(tfileName) != cgiParseSuccess) { - return cgiParseIO; - } - outf = fopen(tfileName, "w+b"); - /* Dirty little hack to get file upload progress - Part 1: Initialize */ - if (cgiFormInteger("upload_id", &shm_key, -1) == cgiFormSuccess && shm_key) { - if ((shm_id = shmget(shm_key, 16, IPC_CREAT | 0666)) >= 0) { - for(sig=1; sig<=31; sig++) - signal(sig, (void*)shmcleanup); - shm_val = shmat(shm_id, NULL, 0); - } - } - } else { - outf = 0; - tfileName[0] = '\0'; - } - result = afterNextBoundary(mpp, outf, &out, &bodyLength, 0); - /* Dirty little hack to get file upload progress - Part 2: Clean up */ - if(shm_val) - shmdt(shm_val); - if(shm_id>=0) - shmctl(shm_id, IPC_RMID, NULL); - if (result != cgiParseSuccess) { - /* Lack of a boundary here is an error. */ - if (outf) { - fclose(outf); - unlink(tfileName); - } - if (out) { - free(out); - } - return result; - } - /* OK, we have a new pair, add it to the list. */ - n = (cgiFormEntry *) malloc(sizeof(cgiFormEntry)); - if (!n) { - goto outOfMemory; - } - memset(n, 0, sizeof(cgiFormEntry)); - /* 2.01: one of numerous new casts required - to please C++ compilers */ - n->attr = (char *) malloc(strlen(fname) + 1); - if (!n->attr) { - goto outOfMemory; - } - strcpy(n->attr, fname); - if (out) { - n->value = out; - out = 0; - } 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; + cgiParseResultType result; + cgiFormEntry *n = 0, *l = 0; + int got; + FILE *outf = 0; + char *out = 0; + mpStream mp; + mpStreamPtr mpp = ∓ + memset(&mp, 0, sizeof(mp)); + if (!cgiContentLength) { + return cgiParseSuccess; + } + /* Read first boundary, including trailing newline */ + result = afterNextBoundary(mpp, 0, 0, 0, 1); + if (result == cgiParseIO) { + /* An empty submission is not necessarily an error */ + return cgiParseSuccess; + } else if (result != cgiParseSuccess) { + return result; + } + while (1) { + char d[1024]; + char fvalue[1024]; + char fname[1024]; + int bodyLength = 0; + char ffileName[1024]; + char fcontentType[1024]; + char attr[1024]; + char value[1024]; + fvalue[0] = 0; + fname[0] = 0; + ffileName[0] = 0; + fcontentType[0] = 0; + out = 0; + outf = 0; + /* Check for EOF */ + got = mpRead(mpp, d, 2); + if (got < 2) { + /* Crude EOF */ + break; + } + if ((d[0] == '-') && (d[1] == '-')) { + /* Graceful EOF */ + break; + } + mpPutBack(mpp, d, 2); + /* Read header lines until end of header */ + while (readHeaderLine( + mpp, attr, sizeof(attr), value, sizeof(value))) + { + char *argNames[3]; + char *argValues[2]; + /* Content-Disposition: form-data; + name="test"; filename="googley.gif" */ + if (cgiStrEqNc(attr, "Content-Disposition")) { + argNames[0] = "name"; + argNames[1] = "filename"; + argNames[2] = 0; + argValues[0] = fname; + argValues[1] = ffileName; + decomposeValue(value, + fvalue, sizeof(fvalue), + argNames, + argValues, + 1024); + } else if (cgiStrEqNc(attr, "Content-Type")) { + argNames[0] = 0; + decomposeValue(value, + fcontentType, sizeof(fcontentType), + argNames, + 0, + 0); + } + } + if (!cgiStrEqNc(fvalue, "form-data")) { + /* Not form data */ + result = afterNextBoundary(mpp, 0, 0, 0, 0); + if (result != cgiParseSuccess) { + /* Lack of a boundary here is an error. */ + return result; + } + continue; + } + /* Body is everything from here until the next + boundary. So, set it aside and move past boundary. + If a filename was submitted as part of the + disposition header, store to a temporary file. + Otherwise, store to a memory buffer (it is + presumably a regular form field). */ + if (strlen(ffileName)) { + if (getTempFileName(&outf) != cgiParseSuccess) { + return cgiParseIO; + } + } else { + outf = 0; + } + result = afterNextBoundary(mpp, outf, &out, &bodyLength, 0); + if (result != cgiParseSuccess) { + /* Lack of a boundary here is an error. */ + if (outf) { + fclose(outf); + } + if (out) { + free(out); + } + return result; + } + /* OK, we have a new pair, add it to the list. */ + n = (cgiFormEntry *) malloc(sizeof(cgiFormEntry)); + if (!n) { + goto outOfMemory; + } + memset(n, 0, sizeof(cgiFormEntry)); + /* 2.01: one of numerous new casts required + to please C++ compilers */ + n->attr = (char *) malloc(strlen(fname) + 1); + if (!n->attr) { + goto outOfMemory; + } + strcpy(n->attr, fname); + if (out) { + n->value = out; + out = 0; + } else if (outf) { + n->value = (char *) malloc(1); + if (!n->value) { + goto outOfMemory; + } + n->value[0] = '\0'; + } + 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); + + if(outf) + { + n->tFile = fdopen (dup (fileno (outf)), "w+b"); + fclose(outf); + } + + 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; + if (n) { + if (n->attr) { + free(n->attr); + } + if (n->value) { + free(n->value); + } + if (n->fileName) { + free(n->fileName); + } + if (n->tFile) { + fclose(n->tFile); + } + if (n->contentType) { + free(n->contentType); + } + free(n); + } + if (out) { + free(out); + } + if (outf) { + fclose(outf); + } + +return cgiParseMemory; } -static cgiParseResultType getTempFileName(char *tfileName) +static cgiParseResultType getTempFileName(FILE **tFile) { + /* tfileName must be 1024 bytes to ensure adequacy on + win32 (1024 exceeds the maximum path length and + certainly exceeds observed behavior of _tmpnam). + May as well also be 1024 bytes on Unix, although actual + length is strlen(cgiTempDir) + a short unique pattern. */ + char tfileName[1024]; + #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; - } + /* 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; - } + /* Non-Unix. Do what we can. */ + if (!tmpnam(tfileName)) { + return cgiParseIO; + } #endif - return cgiParseSuccess; + *tFile = fopen(tfileName, "w+b"); + unlink(tfileName); + return cgiParseSuccess; } #define APPEND(string, char) \ - { \ - if ((string##Len + 1) < string##Space) { \ - string[string##Len++] = (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); \ - } - + { \ + 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); \ - } \ - } + { \ + 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 *bodyLengthP, int first) { - int outLen = 0; - int outSpace = 256; - char *out = 0; - cgiParseResultType result; - int boffset; - int got; - off_t tot=0; - 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); - /* Dirty little hack to get file upload progress - Part 3: Set value */ - if(outf && shm_val) - snprintf(shm_val, SHM_SIZE, "%.1f M", (float)(tot+=got)/1024/1024); - 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; + 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'; - } + 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; + 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 *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((int)*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((int)*value))) { - value++; - } - /* Now read the parameter name */ - argNameLen = 0; - while ((*value) && (isalnum((int)*value))) { - APPEND(argName, *value); - value++; - } - if (argNameSpace) { - argName[argNameLen] = '\0'; - } - while ((*value) && isspace((int)*value)) { - value++; - } - if (*value != '=') { - /* Malformed line */ - return; - } - value++; - while ((*value) && isspace((int)*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'; - } - } + 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) { + if (argValue) { + 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((int)d[0])) { - mpPutBack(mpp, d, 1); - break; - } - } - } else if (!valueFound) { - if (!isspace((int)*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; - } + 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); + return cgiParseFormInput(cgiQueryString, cgiContentLength); } typedef enum { - cgiEscapeRest, - cgiEscapeFirst, - cgiEscapeSecond + cgiEscapeRest, + cgiEscapeFirst, + cgiEscapeSecond } cgiEscapeState; typedef enum { - cgiUnescapeSuccess, - cgiUnescapeMemory + 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; + /* Scan for pairs, unescaping and storing them as they are found. */ + int pos = 0; + cgiFormEntry *n; + cgiFormEntry *l = 0; + while (pos != length) { + int foundAmp = 0; + int start = pos; + int len = 0; + char *attr; + char *value; + while (pos != length) { + if (data[pos] == '&') { + /* Tolerate attr name without a value. This will fall through + and give us an empty value */ + break; + } + if (data[pos] == '=') { + pos++; + break; + } + pos++; + len++; + } + if (!len) { + 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->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]; - s[dstPos++] = escapedValue; - escapeState = cgiEscapeRest; - break; - } - srcPos++; - } - s[dstPos] = '\0'; - *sp = s; - return cgiUnescapeSuccess; -} - + 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]; + s[dstPos++] = escapedValue; + escapeState = cgiEscapeRest; + break; + } + srcPos++; + } + s[dstPos] = '\0'; + *sp = s; + return cgiUnescapeSuccess; +} + static void cgiSetupConstants() { - int i; - for (i=0; (i < 256); i++) { - cgiHexValue[i] = 0; - } - cgiHexValue['0'] = 0; - cgiHexValue['1'] = 1; - cgiHexValue['2'] = 2; - cgiHexValue['3'] = 3; - cgiHexValue['4'] = 4; - cgiHexValue['5'] = 5; - cgiHexValue['6'] = 6; - cgiHexValue['7'] = 7; - cgiHexValue['8'] = 8; - cgiHexValue['9'] = 9; - cgiHexValue['A'] = 10; - cgiHexValue['B'] = 11; - cgiHexValue['C'] = 12; - cgiHexValue['D'] = 13; - cgiHexValue['E'] = 14; - cgiHexValue['F'] = 15; - cgiHexValue['a'] = 10; - cgiHexValue['b'] = 11; - cgiHexValue['c'] = 12; - cgiHexValue['d'] = 13; - cgiHexValue['e'] = 14; - cgiHexValue['f'] = 15; + int i; + for (i=0; (i < 256); i++) { + cgiHexValue[i] = 0; + } + cgiHexValue['0'] = 0; + cgiHexValue['1'] = 1; + cgiHexValue['2'] = 2; + cgiHexValue['3'] = 3; + cgiHexValue['4'] = 4; + cgiHexValue['5'] = 5; + cgiHexValue['6'] = 6; + cgiHexValue['7'] = 7; + cgiHexValue['8'] = 8; + cgiHexValue['9'] = 9; + cgiHexValue['A'] = 10; + cgiHexValue['B'] = 11; + cgiHexValue['C'] = 12; + cgiHexValue['D'] = 13; + cgiHexValue['E'] = 14; + cgiHexValue['F'] = 15; + cgiHexValue['a'] = 10; + cgiHexValue['b'] = 11; + cgiHexValue['c'] = 12; + cgiHexValue['d'] = 13; + cgiHexValue['e'] = 14; + cgiHexValue['f'] = 15; } static void cgiFreeResources() { - cgiFormEntry *c = cgiFormEntryFirst; - cgiFormEntry *n; - while (c) { - n = c->next; - free(c->attr); - free(c->value); - free(c->fileName); - free(c->contentType); - if (strlen(c->tfileName)) { - unlink(c->tfileName); - } - free(c->tfileName); - free(c); - c = n; - } - /* If the cgi environment was restored from a saved environment, - then these are in allocated space and must also be freed */ - if (cgiRestored) { - free(cgiServerSoftware); - free(cgiServerName); - free(cgiGatewayInterface); - free(cgiServerProtocol); - free(cgiServerPort); - free(cgiRequestMethod); - free(cgiPathInfo); - free(cgiPathTranslated); - free(cgiScriptName); - free(cgiQueryString); - free(cgiRemoteHost); - free(cgiRemoteAddr); - free(cgiAuthType); - free(cgiRemoteUser); - free(cgiRemoteIdent); - free(cgiContentType); - free(cgiAccept); - free(cgiUserAgent); - free(cgiReferrer); - } - /* 2.0: to clean up the environment for cgiReadEnvironment, - we must set these correctly */ - cgiFormEntryFirst = 0; - cgiRestored = 0; + cgiFormEntry *c = cgiFormEntryFirst; + cgiFormEntry *n; + while (c) { + n = c->next; + free(c->attr); + free(c->value); + free(c->fileName); + free(c->contentType); + if (c->tFile) { + fclose(c->tFile); + } + free(c); + c = n; + } + /* If the cgi environment was restored from a saved environment, + then these are in allocated space and must also be freed */ + if (cgiRestored) { + free(cgiServerSoftware); + free(cgiServerName); + free(cgiGatewayInterface); + free(cgiServerProtocol); + free(cgiServerPort); + free(cgiRequestMethod); + free(cgiPathInfo); + free(cgiPathTranslated); + free(cgiScriptName); + free(cgiQueryString); + free(cgiRemoteHost); + free(cgiRemoteAddr); + free(cgiAuthType); + free(cgiRemoteUser); + free(cgiRemoteIdent); + free(cgiContentType); + free(cgiAccept); + free(cgiUserAgent); + free(cgiReferrer); + } + /* 2.0: to clean up the environment for cgiReadEnvironment, + we must set these correctly */ + cgiFormEntryFirst = 0; + cgiRestored = 0; } static cgiFormResultType cgiFormEntryString( - cgiFormEntry *e, char *result, int max, int newlines); + cgiFormEntry *e, char *result, int max, int newlines); static cgiFormEntry *cgiFormEntryFindFirst(char *name); static cgiFormEntry *cgiFormEntryFindNext(); cgiFormResultType cgiFormString( char *name, char *result, int max) { - cgiFormEntry *e; - e = cgiFormEntryFindFirst(name); - if (!e) { - strcpy(result, ""); - return cgiFormNotFound; - } - return cgiFormEntryString(e, result, max, 1); + cgiFormEntry *e; + e = cgiFormEntryFindFirst(name); + if (!e) { + strcpy(result, ""); + return cgiFormNotFound; + } + return cgiFormEntryString(e, result, max, 1); } cgiFormResultType cgiFormFileName( - char *name, char *result, int resultSpace) + char *name, char *result, int resultSpace) { - cgiFormEntry *e; - int resultLen = 0; - char *s; - e = cgiFormEntryFindFirst(name); - if (!e) { - strcpy(result, ""); - return cgiFormNotFound; - } - s = e->fileName; - while (*s) { - APPEND(result, *s); - s++; - } - if (resultSpace) { - result[resultLen] = '\0'; - } - if (!strlen(e->fileName)) { - return cgiFormNoFileName; - } else if (((int) strlen(e->fileName)) > (resultSpace - 1)) { - return cgiFormTruncated; - } else { - return cgiFormSuccess; - } + cgiFormEntry *e; + int resultLen = 0; + char *s; + e = cgiFormEntryFindFirst(name); + if (!e) { + strcpy(result, ""); + return cgiFormNotFound; + } + s = e->fileName; + while (*s) { + APPEND(result, *s); + s++; + } + if (resultSpace) { + result[resultLen] = '\0'; + } + if (!strlen(e->fileName)) { + return cgiFormNoFileName; + } else if (((int) strlen(e->fileName)) > (resultSpace - 1)) { + return cgiFormTruncated; + } else { + return cgiFormSuccess; + } } cgiFormResultType cgiFormFileContentType( - char *name, char *result, int resultSpace) + char *name, char *result, int resultSpace) { - cgiFormEntry *e; - int resultLen = 0; - char *s; - e = cgiFormEntryFindFirst(name); - if (!e) { - if (resultSpace) { - result[0] = '\0'; - } - return cgiFormNotFound; - } - s = e->contentType; - while (*s) { - APPEND(result, *s); - s++; - } - if (resultSpace) { - result[resultLen] = '\0'; - } - if (!strlen(e->contentType)) { - return cgiFormNoContentType; - } else if (((int) strlen(e->contentType)) > (resultSpace - 1)) { - return cgiFormTruncated; - } else { - return cgiFormSuccess; - } + cgiFormEntry *e; + int resultLen = 0; + char *s; + e = cgiFormEntryFindFirst(name); + if (!e) { + if (resultSpace) { + result[0] = '\0'; + } + return cgiFormNotFound; + } + s = e->contentType; + while (*s) { + APPEND(result, *s); + s++; + } + if (resultSpace) { + result[resultLen] = '\0'; + } + if (!strlen(e->contentType)) { + return cgiFormNoContentType; + } else if (((int) strlen(e->contentType)) > (resultSpace - 1)) { + return cgiFormTruncated; + } else { + return cgiFormSuccess; + } } cgiFormResultType cgiFormFileSize( - char *name, int *sizeP) + char *name, int *sizeP) { - cgiFormEntry *e; - e = cgiFormEntryFindFirst(name); - if (!e) { - if (sizeP) { - *sizeP = 0; - } - return cgiFormNotFound; - } else if (!strlen(e->tfileName)) { - if (sizeP) { - *sizeP = 0; - } - return cgiFormNotAFile; - } else { - if (sizeP) { - *sizeP = e->valueLength; - } - return cgiFormSuccess; - } + cgiFormEntry *e; + e = cgiFormEntryFindFirst(name); + if (!e) { + if (sizeP) { + *sizeP = 0; + } + return cgiFormNotFound; + } else if (!e->tFile) { + if (sizeP) { + *sizeP = 0; + } + return cgiFormNotAFile; + } else { + if (sizeP) { + *sizeP = e->valueLength; + } + return cgiFormSuccess; + } } typedef struct cgiFileStruct { - FILE *in; + FILE *in; } cgiFile; cgiFormResultType cgiFormFileOpen( - char *name, cgiFilePtr *cfpp) + char *name, cgiFilePtr *cfpp) { - cgiFormEntry *e; - cgiFilePtr cfp; - e = cgiFormEntryFindFirst(name); - if (!e) { - *cfpp = 0; - return cgiFormNotFound; - } - if (!strlen(e->tfileName)) { - *cfpp = 0; - return cgiFormNotAFile; - } - cfp = (cgiFilePtr) malloc(sizeof(cgiFile)); - if (!cfp) { - *cfpp = 0; - return cgiFormMemory; - } - cfp->in = fopen(e->tfileName, "rb"); - if (!cfp->in) { - free(cfp); - return cgiFormIO; - } - *cfpp = cfp; - return cgiFormSuccess; + cgiFormEntry *e; + cgiFilePtr cfp; + e = cgiFormEntryFindFirst(name); + if (!e) { + *cfpp = 0; + return cgiFormNotFound; + } + if (!e->tFile) { + *cfpp = 0; + return cgiFormNotAFile; + } + cfp = (cgiFilePtr) malloc(sizeof(cgiFile)); + if (!cfp) { + *cfpp = 0; + return cgiFormMemory; + } + cfp->in = fdopen(dup(fileno(e->tFile)), "rb"); + rewind(cfp->in); + if (!cfp->in) { + free(cfp); + return cgiFormIO; + } + *cfpp = cfp; + return cgiFormSuccess; } cgiFormResultType cgiFormFileRead( - cgiFilePtr cfp, char *buffer, - int bufferSize, int *gotP) + cgiFilePtr cfp, char *buffer, + int bufferSize, int *gotP) { - int got = 0; - if (!cfp) { - return cgiFormOpenFailed; - } - got = fread(buffer, 1, bufferSize, cfp->in); - if (got <= 0) { - return cgiFormEOF; - } - *gotP = got; - return cgiFormSuccess; + int got = 0; + if (!cfp) { + return cgiFormOpenFailed; + } + got = fread(buffer, 1, bufferSize, cfp->in); + if (got <= 0) { + return cgiFormEOF; + } + *gotP = got; + return cgiFormSuccess; } cgiFormResultType cgiFormFileClose(cgiFilePtr cfp) { - if (!cfp) { - return cgiFormOpenFailed; - } - fclose(cfp->in); - free(cfp); - return cgiFormSuccess; + if (!cfp) { + return cgiFormOpenFailed; + } + fclose(cfp->in); + free(cfp); + return cgiFormSuccess; } cgiFormResultType cgiFormStringNoNewlines( char *name, char *result, int max) { - cgiFormEntry *e; - e = cgiFormEntryFindFirst(name); - if (!e) { - strcpy(result, ""); - return cgiFormNotFound; - } - return cgiFormEntryString(e, result, max, 0); + cgiFormEntry *e; + e = cgiFormEntryFindFirst(name); + if (!e) { + strcpy(result, ""); + return cgiFormNotFound; + } + return cgiFormEntryString(e, result, max, 0); } cgiFormResultType cgiFormStringMultiple( char *name, char ***result) { - char **stringArray; - cgiFormEntry *e; - int i; - int total = 0; - /* Make two passes. One would be more efficient, but this - function is not commonly used. The select menu and - radio box functions are faster. */ - e = cgiFormEntryFindFirst(name); - if (e != 0) { - do { - total++; - } while ((e = cgiFormEntryFindNext()) != 0); - } - stringArray = (char **) malloc(sizeof(char *) * (total + 1)); - if (!stringArray) { - *result = 0; - return cgiFormMemory; - } - /* initialize all entries to null; the last will stay that way */ - for (i=0; (i <= total); i++) { - stringArray[i] = 0; - } - /* Now go get the entries */ - e = cgiFormEntryFindFirst(name); + char **stringArray; + cgiFormEntry *e; + int i; + int total = 0; + /* Make two passes. One would be more efficient, but this + function is not commonly used. The select menu and + radio box functions are faster. */ + e = cgiFormEntryFindFirst(name); + if (e != 0) { + do { + total++; + } while ((e = cgiFormEntryFindNext()) != 0); + } + stringArray = (char **) malloc(sizeof(char *) * (total + 1)); + if (!stringArray) { + *result = 0; + return cgiFormMemory; + } + /* initialize all entries to null; the last will stay that way */ + for (i=0; (i <= total); i++) { + stringArray[i] = 0; + } + /* Now go get the entries */ + e = cgiFormEntryFindFirst(name); #ifdef CGICDEBUG - CGICDEBUGSTART - fprintf(dout, "StringMultiple Beginning\n"); - CGICDEBUGEND + CGICDEBUGSTART + fprintf(dout, "StringMultiple Beginning\n"); + CGICDEBUGEND #endif /* CGICDEBUG */ - if (e) { - i = 0; - do { - int max = (int) (strlen(e->value) + 1); - stringArray[i] = (char *) malloc(max); - if (stringArray[i] == 0) { - /* Memory problems */ - cgiStringArrayFree(stringArray); - *result = 0; - return cgiFormMemory; - } - strcpy(stringArray[i], e->value); - cgiFormEntryString(e, stringArray[i], max, 1); - i++; - } while ((e = cgiFormEntryFindNext()) != 0); - *result = stringArray; + if (e) { + i = 0; + do { + int max = (int) (strlen(e->value) + 1); + stringArray[i] = (char *) malloc(max); + if (stringArray[i] == 0) { + /* Memory problems */ + cgiStringArrayFree(stringArray); + *result = 0; + return cgiFormMemory; + } + strcpy(stringArray[i], e->value); + cgiFormEntryString(e, stringArray[i], max, 1); + i++; + } while ((e = cgiFormEntryFindNext()) != 0); + *result = stringArray; #ifdef CGICDEBUG - CGICDEBUGSTART - fprintf(dout, "StringMultiple Succeeding\n"); - CGICDEBUGEND + CGICDEBUGSTART + fprintf(dout, "StringMultiple Succeeding\n"); + CGICDEBUGEND #endif /* CGICDEBUG */ - return cgiFormSuccess; - } else { - *result = stringArray; + return cgiFormSuccess; + } else { + *result = stringArray; #ifdef CGICDEBUG - CGICDEBUGSTART - fprintf(dout, "StringMultiple found nothing\n"); - CGICDEBUGEND + CGICDEBUGSTART + fprintf(dout, "StringMultiple found nothing\n"); + CGICDEBUGEND #endif /* CGICDEBUG */ - return cgiFormNotFound; - } + return cgiFormNotFound; + } } cgiFormResultType cgiFormStringSpaceNeeded( char *name, int *result) { - cgiFormEntry *e; - e = cgiFormEntryFindFirst(name); - if (!e) { - *result = 1; - return cgiFormNotFound; - } - *result = ((int) strlen(e->value)) + 1; - return cgiFormSuccess; + cgiFormEntry *e; + e = cgiFormEntryFindFirst(name); + if (!e) { + *result = 1; + return cgiFormNotFound; + } + *result = ((int) strlen(e->value)) + 1; + return cgiFormSuccess; } static cgiFormResultType cgiFormEntryString( - cgiFormEntry *e, char *result, int max, int newlines) { - char *dp, *sp; - int truncated = 0; - int len = 0; - int avail = max-1; - int crCount = 0; - int lfCount = 0; - dp = result; - sp = e->value; - while (1) { - int ch; - /* 1.07: don't check for available space now. - We check for it immediately before adding - an actual character. 1.06 handled the - trailing null of the source string improperly, - resulting in a cgiFormTruncated error. */ - ch = *sp; - /* Fix the CR/LF, LF, CR nightmare: watch for - consecutive bursts of CRs and LFs in whatever - pattern, then actually output the larger number - of LFs. Consistently sane, yet it still allows - consecutive blank lines when the user - actually intends them. */ - if ((ch == 13) || (ch == 10)) { - if (ch == 13) { - crCount++; - } else { - lfCount++; - } - } else { - if (crCount || lfCount) { - int lfsAdd = crCount; - if (lfCount > crCount) { - lfsAdd = lfCount; - } - /* Stomp all newlines if desired */ - if (!newlines) { - lfsAdd = 0; - } - while (lfsAdd) { - if (len >= avail) { - truncated = 1; - break; - } - *dp = 10; - dp++; - lfsAdd--; - len++; - } - crCount = 0; - lfCount = 0; - } - if (ch == '\0') { - /* The end of the source string */ - break; - } - /* 1.06: check available space before adding - the character, because a previously added - LF may have brought us to the limit */ - if (len >= avail) { - truncated = 1; - break; - } - *dp = ch; - dp++; - len++; - } - sp++; - } - *dp = '\0'; - if (truncated) { - return cgiFormTruncated; - } else if (!len) { - return cgiFormEmpty; - } else { - return cgiFormSuccess; - } + cgiFormEntry *e, char *result, int max, int newlines) { + char *dp, *sp; + int truncated = 0; + int len = 0; + int avail = max-1; + int crCount = 0; + int lfCount = 0; + dp = result; + sp = e->value; + while (1) { + int ch; + /* 1.07: don't check for available space now. + We check for it immediately before adding + an actual character. 1.06 handled the + trailing null of the source string improperly, + resulting in a cgiFormTruncated error. */ + ch = *sp; + /* Fix the CR/LF, LF, CR nightmare: watch for + consecutive bursts of CRs and LFs in whatever + pattern, then actually output the larger number + of LFs. Consistently sane, yet it still allows + consecutive blank lines when the user + actually intends them. */ + if ((ch == 13) || (ch == 10)) { + if (ch == 13) { + crCount++; + } else { + lfCount++; + } + } else { + if (crCount || lfCount) { + int lfsAdd = crCount; + if (lfCount > crCount) { + lfsAdd = lfCount; + } + /* Stomp all newlines if desired */ + if (!newlines) { + lfsAdd = 0; + } + while (lfsAdd) { + if (len >= avail) { + truncated = 1; + break; + } + *dp = 10; + dp++; + lfsAdd--; + len++; + } + crCount = 0; + lfCount = 0; + } + if (ch == '\0') { + /* The end of the source string */ + break; + } + /* 1.06: check available space before adding + the character, because a previously added + LF may have brought us to the limit */ + if (len >= avail) { + truncated = 1; + break; + } + *dp = ch; + dp++; + len++; + } + sp++; + } + *dp = '\0'; + if (truncated) { + return cgiFormTruncated; + } else if (!len) { + return cgiFormEmpty; + } else { + return cgiFormSuccess; + } } static int cgiFirstNonspaceChar(char *s); cgiFormResultType cgiFormInteger( char *name, int *result, int defaultV) { - cgiFormEntry *e; - int ch; - e = cgiFormEntryFindFirst(name); - if (!e) { - *result = defaultV; - return cgiFormNotFound; - } - if (!strlen(e->value)) { - *result = defaultV; - return cgiFormEmpty; - } - ch = cgiFirstNonspaceChar(e->value); - if (!(isdigit(ch)) && (ch != '-') && (ch != '+')) { - *result = defaultV; - return cgiFormBadType; - } else { - *result = atoi(e->value); - return cgiFormSuccess; - } + cgiFormEntry *e; + int ch; + e = cgiFormEntryFindFirst(name); + if (!e) { + *result = defaultV; + return cgiFormNotFound; + } + if (!strlen(e->value)) { + *result = defaultV; + return cgiFormEmpty; + } + ch = cgiFirstNonspaceChar(e->value); + if (!(isdigit(ch)) && (ch != '-') && (ch != '+')) { + *result = defaultV; + return cgiFormBadType; + } else { + *result = atoi(e->value); + return cgiFormSuccess; + } } cgiFormResultType cgiFormIntegerBounded( char *name, int *result, int min, int max, int defaultV) { - cgiFormResultType error = cgiFormInteger(name, result, defaultV); - if (error != cgiFormSuccess) { - return error; - } - if (*result < min) { - *result = min; - return cgiFormConstrained; - } - if (*result > max) { - *result = max; - return cgiFormConstrained; - } - return cgiFormSuccess; + cgiFormResultType error = cgiFormInteger(name, result, defaultV); + if (error != cgiFormSuccess) { + return error; + } + if (*result < min) { + *result = min; + return cgiFormConstrained; + } + if (*result > max) { + *result = max; + return cgiFormConstrained; + } + return cgiFormSuccess; } cgiFormResultType cgiFormDouble( char *name, double *result, double defaultV) { - cgiFormEntry *e; - int ch; - e = cgiFormEntryFindFirst(name); - if (!e) { - *result = defaultV; - return cgiFormNotFound; - } - if (!strlen(e->value)) { - *result = defaultV; - return cgiFormEmpty; - } - ch = cgiFirstNonspaceChar(e->value); - if (!(isdigit(ch)) && (ch != '.') && (ch != '-') && (ch != '+')) { - *result = defaultV; - return cgiFormBadType; - } else { - *result = atof(e->value); - return cgiFormSuccess; - } + cgiFormEntry *e; + int ch; + e = cgiFormEntryFindFirst(name); + if (!e) { + *result = defaultV; + return cgiFormNotFound; + } + if (!strlen(e->value)) { + *result = defaultV; + return cgiFormEmpty; + } + ch = cgiFirstNonspaceChar(e->value); + if (!(isdigit(ch)) && (ch != '.') && (ch != '-') && (ch != '+')) { + *result = defaultV; + return cgiFormBadType; + } else { + *result = atof(e->value); + return cgiFormSuccess; + } } cgiFormResultType cgiFormDoubleBounded( char *name, double *result, double min, double max, double defaultV) { - cgiFormResultType error = cgiFormDouble(name, result, defaultV); - if (error != cgiFormSuccess) { - return error; - } - if (*result < min) { - *result = min; - return cgiFormConstrained; - } - if (*result > max) { - *result = max; - return cgiFormConstrained; - } - return cgiFormSuccess; + cgiFormResultType error = cgiFormDouble(name, result, defaultV); + if (error != cgiFormSuccess) { + return error; + } + if (*result < min) { + *result = min; + return cgiFormConstrained; + } + if (*result > max) { + *result = max; + return cgiFormConstrained; + } + return cgiFormSuccess; } cgiFormResultType cgiFormSelectSingle( - char *name, char **choicesText, int choicesTotal, - int *result, int defaultV) + char *name, char **choicesText, int choicesTotal, + int *result, int defaultV) { - cgiFormEntry *e; - int i; - e = cgiFormEntryFindFirst(name); + cgiFormEntry *e; + int i; + e = cgiFormEntryFindFirst(name); #ifdef CGICDEBUG - CGICDEBUGSTART - fprintf(dout, "%d\n", (int) e); - CGICDEBUGEND + CGICDEBUGSTART + fprintf(dout, "%d\n", (int) e); + CGICDEBUGEND #endif /* CGICDEBUG */ - if (!e) { - *result = defaultV; - return cgiFormNotFound; - } - for (i=0; (i < choicesTotal); i++) { + if (!e) { + *result = defaultV; + return cgiFormNotFound; + } + for (i=0; (i < choicesTotal); i++) { #ifdef CGICDEBUG - CGICDEBUGSTART - fprintf(dout, "%s %s\n", choicesText[i], e->value); - CGICDEBUGEND + CGICDEBUGSTART + fprintf(dout, "%s %s\n", choicesText[i], e->value); + CGICDEBUGEND #endif /* CGICDEBUG */ - if (cgiStrEq(choicesText[i], e->value)) { + if (cgiStrEq(choicesText[i], e->value)) { #ifdef CGICDEBUG - CGICDEBUGSTART - fprintf(dout, "MATCH\n"); - CGICDEBUGEND + CGICDEBUGSTART + fprintf(dout, "MATCH\n"); + CGICDEBUGEND #endif /* CGICDEBUG */ - *result = i; - return cgiFormSuccess; - } - } - *result = defaultV; - return cgiFormNoSuchChoice; + *result = i; + return cgiFormSuccess; + } + } + *result = defaultV; + return cgiFormNoSuchChoice; } cgiFormResultType cgiFormSelectMultiple( - char *name, char **choicesText, int choicesTotal, - int *result, int *invalid) + char *name, char **choicesText, int choicesTotal, + int *result, int *invalid) { - cgiFormEntry *e; - int i; - int hits = 0; - int invalidE = 0; - for (i=0; (i < choicesTotal); i++) { - result[i] = 0; - } - e = cgiFormEntryFindFirst(name); - if (!e) { - *invalid = invalidE; - return cgiFormNotFound; - } - do { - int hit = 0; - for (i=0; (i < choicesTotal); i++) { - if (cgiStrEq(choicesText[i], e->value)) { - result[i] = 1; - hits++; - hit = 1; - break; - } - } - if (!(hit)) { - invalidE++; - } - } while ((e = cgiFormEntryFindNext()) != 0); - - *invalid = invalidE; - - if (hits) { - return cgiFormSuccess; - } else { - return cgiFormNotFound; - } + cgiFormEntry *e; + int i; + int hits = 0; + int invalidE = 0; + for (i=0; (i < choicesTotal); i++) { + result[i] = 0; + } + e = cgiFormEntryFindFirst(name); + if (!e) { + *invalid = invalidE; + return cgiFormNotFound; + } + do { + int hit = 0; + for (i=0; (i < choicesTotal); i++) { + if (cgiStrEq(choicesText[i], e->value)) { + result[i] = 1; + hits++; + hit = 1; + break; + } + } + if (!(hit)) { + invalidE++; + } + } while ((e = cgiFormEntryFindNext()) != 0); + + *invalid = invalidE; + + if (hits) { + return cgiFormSuccess; + } else { + return cgiFormNotFound; + } } cgiFormResultType cgiFormCheckboxSingle( - char *name) + char *name) { - cgiFormEntry *e; - e = cgiFormEntryFindFirst(name); - if (!e) { - return cgiFormNotFound; - } - return cgiFormSuccess; + cgiFormEntry *e; + e = cgiFormEntryFindFirst(name); + if (!e) { + return cgiFormNotFound; + } + return cgiFormSuccess; } extern cgiFormResultType cgiFormCheckboxMultiple( - char *name, char **valuesText, int valuesTotal, - int *result, int *invalid) + char *name, char **valuesText, int valuesTotal, + int *result, int *invalid) { - /* Implementation is identical to cgiFormSelectMultiple. */ - return cgiFormSelectMultiple(name, valuesText, - valuesTotal, result, invalid); + /* Implementation is identical to cgiFormSelectMultiple. */ + return cgiFormSelectMultiple(name, valuesText, + valuesTotal, result, invalid); } cgiFormResultType cgiFormRadio( - char *name, - char **valuesText, int valuesTotal, int *result, int defaultV) + char *name, + char **valuesText, int valuesTotal, int *result, int defaultV) { - /* Implementation is identical to cgiFormSelectSingle. */ - return cgiFormSelectSingle(name, valuesText, valuesTotal, - result, defaultV); + /* Implementation is identical to cgiFormSelectSingle. */ + return cgiFormSelectSingle(name, valuesText, valuesTotal, + result, defaultV); } cgiFormResultType cgiCookieString( - char *name, - char *value, - int space) + char *name, + char *value, + int space) { - char *p = cgiCookie; - while (*p) { - char *n = name; - /* 2.02: if cgiCookie is exactly equal to name, this - can cause an overrun. The server probably wouldn't - allow it, since a name without values makes no sense - -- but then again it might not check, so this is a - genuine security concern. Thanks to Nicolas - Tomadakis. */ - while (*p == *n) { - if ((p == '\0') && (n == '\0')) { - /* Malformed cookie header from client */ - return cgiFormNotFound; - } - p++; - n++; - } - if ((!*n) && (*p == '=')) { - p++; - while ((*p != ';') && (*p != '\0') && - (space > 1)) - { - *value = *p; - value++; - p++; - space--; - } - if (space > 0) { - *value = '\0'; - } - /* Correct parens: 2.02. Thanks to - Mathieu Villeneuve-Belair. */ - if (!(((*p) == ';') || ((*p) == '\0'))) - { - return cgiFormTruncated; - } else { - return cgiFormSuccess; - } - } else { - /* Skip to next cookie */ - while (*p) { - if (*p == ';') { - break; - } - p++; - } - if (!*p) { - /* 2.01: default to empty */ - if (space) { - *value = '\0'; - } - return cgiFormNotFound; - } - p++; - /* Allow whitespace after semicolon */ - while ((*p) && isspace((int)*p)) { - p++; - } - } - } - /* 2.01: actually the above loop never terminates except - with a return, but do this to placate gcc */ - if (space) { - *value = '\0'; - } - return cgiFormNotFound; + char *p = cgiCookie; + while (*p) { + char *n = name; + /* 2.02: if cgiCookie is exactly equal to name, this + can cause an overrun. The server probably wouldn't + allow it, since a name without values makes no sense + -- but then again it might not check, so this is a + genuine security concern. Thanks to Nicolas + Tomadakis. */ + while (*p == *n) { + if ((*p == '\0') && (*n == '\0')) { + /* Malformed cookie header from client */ + return cgiFormNotFound; + } + p++; + n++; + } + if ((!*n) && (*p == '=')) { + p++; + while ((*p != ';') && (*p != '\0') && + (space > 1)) + { + *value = *p; + value++; + p++; + space--; + } + if (space > 0) { + *value = '\0'; + } + /* Correct parens: 2.02. Thanks to + Mathieu Villeneuve-Belair. */ + if (!(((*p) == ';') || ((*p) == '\0'))) + { + return cgiFormTruncated; + } else { + return cgiFormSuccess; + } + } else { + /* Skip to next cookie */ + while (*p) { + if (*p == ';') { + break; + } + p++; + } + if (!*p) { + /* 2.01: default to empty */ + if (space) { + *value = '\0'; + } + return cgiFormNotFound; + } + p++; + /* Allow whitespace after semicolon */ + while ((*p) && isspace(*p)) { + p++; + } + } + } + /* 2.01: actually the above loop never terminates except + with a return, but do this to placate gcc */ + /* Actually, it can, so this is real. */ + if (space) { + *value = '\0'; + } + return cgiFormNotFound; } cgiFormResultType cgiCookieInteger( - char *name, - int *result, - int defaultV) + char *name, + int *result, + int defaultV) { - char buffer[256]; - cgiFormResultType r = - cgiCookieString(name, buffer, sizeof(buffer)); - if (r != cgiFormSuccess) { - *result = defaultV; - } else { - *result = atoi(buffer); - } - return r; + char buffer[256]; + cgiFormResultType r = + cgiCookieString(name, buffer, sizeof(buffer)); + if (r != cgiFormSuccess) { + *result = defaultV; + } else { + *result = atoi(buffer); + } + return r; } void cgiHeaderCookieSetInteger(char *name, int value, int secondsToLive, - char *path, char *domain) + char *path, char *domain) { - char svalue[256]; - sprintf(svalue, "%d", value); - cgiHeaderCookieSetString(name, svalue, secondsToLive, path, domain); + char svalue[256]; + sprintf(svalue, "%d", value); + cgiHeaderCookieSetString(name, svalue, secondsToLive, path, domain); } -char *days[] = { - "Sun", - "Mon", - "Tue", - "Wed", - "Thu", - "Fri", - "Sat" +static char *days[] = { + "Sun", + "Mon", + "Tue", + "Wed", + "Thu", + "Fri", + "Sat" }; -char *months[] = { - "Jan", - "Feb", - "Mar", - "Apr", - "May", - "Jun", - "Jul", - "Aug", - "Sep", - "Oct", - "Nov", - "Dec" +static char *months[] = { + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec" }; void cgiHeaderCookieSetString(char *name, char *value, int secondsToLive, - char *path, char *domain) + char *path, char *domain) { - /* cgic 2.02: simpler and more widely compatible implementation. - Thanks to Chunfu Lai. - cgic 2.03: yes, but it didn't work. Reimplemented by - Thomas Boutell. ; after last element was a bug. - Examples of real world cookies that really work: - Set-Cookie: MSNADS=UM=; domain=.slate.com; + /* cgic 2.02: simpler and more widely compatible implementation. + Thanks to Chunfu Lai. + cgic 2.03: yes, but it didn't work. Reimplemented by + Thomas Boutell. ; after last element was a bug. + Examples of real world cookies that really work: + Set-Cookie: MSNADS=UM=; domain=.slate.com; expires=Tue, 26-Apr-2022 19:00:00 GMT; path=/ - Set-Cookie: MC1=V=3&ID=b5bc08af2b8a43ff85fcb5efd8b238f0; + Set-Cookie: MC1=V=3&ID=b5bc08af2b8a43ff85fcb5efd8b238f0; domain=.slate.com; expires=Mon, 04-Oct-2021 19:00:00 GMT; path=/ - */ - time_t now; - time_t then; - struct tm *gt; - time(&now); - then = now + secondsToLive; - gt = gmtime(&then); - fprintf(cgiOut, - "Set-Cookie: %s=%s; domain=%s; expires=%s, %02d-%s-%04d %02d:%02d:%02d GMT; path=%s\r\n", - name, value, domain, - days[gt->tm_wday], - gt->tm_mday, - months[gt->tm_mon], - gt->tm_year + 1900, - gt->tm_hour, - gt->tm_min, - gt->tm_sec, - path); + */ + time_t now; + time_t then; + struct tm *gt; + time(&now); + then = now + secondsToLive; + gt = gmtime(&then); + fprintf(cgiOut, + "Set-Cookie: %s=%s; domain=%s; expires=%s, %02d-%s-%04d %02d:%02d:%02d GMT; path=%s\r\n", + name, value, domain, + days[gt->tm_wday], + gt->tm_mday, + months[gt->tm_mon], + gt->tm_year + 1900, + gt->tm_hour, + gt->tm_min, + gt->tm_sec, + path); } void cgiHeaderLocation(char *redirectUrl) { - fprintf(cgiOut, "Location: %s\r\n\r\n", redirectUrl); + fprintf(cgiOut, "Location: %s\r\n\r\n", redirectUrl); } void cgiHeaderStatus(int status, char *statusMessage) { - fprintf(cgiOut, "Status: %d %s\r\n\r\n", status, statusMessage); + fprintf(cgiOut, "Status: %d %s\r\n\r\n", status, statusMessage); } void cgiHeaderContentType(char *mimeType) { - fprintf(cgiOut, "Content-type: %s\r\n\r\n", mimeType); + fprintf(cgiOut, "Content-type: %s\r\n\r\n", mimeType); } static int cgiWriteString(FILE *out, char *s); @@ -1906,149 +1887,149 @@ static int cgiWriteInt(FILE *out, int i); #define CGIC_VERSION "2.0" cgiEnvironmentResultType cgiWriteEnvironment(char *filename) { - FILE *out; - cgiFormEntry *e; - /* Be sure to open in binary mode */ - out = fopen(filename, "wb"); - if (!out) { - /* Can't create file */ - return cgiEnvironmentIO; - } - if (!cgiWriteString(out, "CGIC2.0")) { - goto error; - } - if (!cgiWriteString(out, cgiServerSoftware)) { - goto error; - } - if (!cgiWriteString(out, cgiServerName)) { - goto error; - } - if (!cgiWriteString(out, cgiGatewayInterface)) { - goto error; - } - if (!cgiWriteString(out, cgiServerProtocol)) { - goto error; - } - if (!cgiWriteString(out, cgiServerPort)) { - goto error; - } - if (!cgiWriteString(out, cgiRequestMethod)) { - goto error; - } - if (!cgiWriteString(out, cgiPathInfo)) { - goto error; - } - if (!cgiWriteString(out, cgiPathTranslated)) { - goto error; - } - if (!cgiWriteString(out, cgiScriptName)) { - goto error; - } - if (!cgiWriteString(out, cgiQueryString)) { - goto error; - } - if (!cgiWriteString(out, cgiRemoteHost)) { - goto error; - } - if (!cgiWriteString(out, cgiRemoteAddr)) { - goto error; - } - if (!cgiWriteString(out, cgiAuthType)) { - goto error; - } - if (!cgiWriteString(out, cgiRemoteUser)) { - goto error; - } - if (!cgiWriteString(out, cgiRemoteIdent)) { - goto error; - } - if (!cgiWriteString(out, cgiContentType)) { - goto error; - } - if (!cgiWriteString(out, cgiAccept)) { - goto error; - } - if (!cgiWriteString(out, cgiUserAgent)) { - goto error; - } - if (!cgiWriteString(out, cgiReferrer)) { - goto error; - } - if (!cgiWriteString(out, cgiCookie)) { - goto error; - } - if (!cgiWriteInt(out, cgiContentLength)) { - goto error; - } - e = cgiFormEntryFirst; - while (e) { - cgiFilePtr fp; - if (!cgiWriteString(out, e->attr)) { - goto error; - } - if (!cgiWriteString(out, e->value)) { - goto error; - } - /* New 2.0 fields and file uploads */ - if (!cgiWriteString(out, e->fileName)) { - goto error; - } - if (!cgiWriteString(out, e->contentType)) { - goto error; - } - if (!cgiWriteInt(out, e->valueLength)) { - goto error; - } - if (cgiFormFileOpen(e->attr, &fp) == cgiFormSuccess) { - char buffer[1024]; - int got; - if (!cgiWriteInt(out, 1)) { - cgiFormFileClose(fp); - goto error; - } - while (cgiFormFileRead(fp, buffer, - sizeof(buffer), &got) == cgiFormSuccess) - { - if (((int) fwrite(buffer, 1, got, out)) != got) { - cgiFormFileClose(fp); - goto error; - } - } - if (cgiFormFileClose(fp) != cgiFormSuccess) { - goto error; - } - } else { - if (!cgiWriteInt(out, 0)) { - goto error; - } - } - e = e->next; - } - fclose(out); - return cgiEnvironmentSuccess; + FILE *out; + cgiFormEntry *e; + /* Be sure to open in binary mode */ + out = fopen(filename, "wb"); + if (!out) { + /* Can't create file */ + return cgiEnvironmentIO; + } + if (!cgiWriteString(out, "CGIC2.0")) { + goto error; + } + if (!cgiWriteString(out, cgiServerSoftware)) { + goto error; + } + if (!cgiWriteString(out, cgiServerName)) { + goto error; + } + if (!cgiWriteString(out, cgiGatewayInterface)) { + goto error; + } + if (!cgiWriteString(out, cgiServerProtocol)) { + goto error; + } + if (!cgiWriteString(out, cgiServerPort)) { + goto error; + } + if (!cgiWriteString(out, cgiRequestMethod)) { + goto error; + } + if (!cgiWriteString(out, cgiPathInfo)) { + goto error; + } + if (!cgiWriteString(out, cgiPathTranslated)) { + goto error; + } + if (!cgiWriteString(out, cgiScriptName)) { + goto error; + } + if (!cgiWriteString(out, cgiQueryString)) { + goto error; + } + if (!cgiWriteString(out, cgiRemoteHost)) { + goto error; + } + if (!cgiWriteString(out, cgiRemoteAddr)) { + goto error; + } + if (!cgiWriteString(out, cgiAuthType)) { + goto error; + } + if (!cgiWriteString(out, cgiRemoteUser)) { + goto error; + } + if (!cgiWriteString(out, cgiRemoteIdent)) { + goto error; + } + if (!cgiWriteString(out, cgiContentType)) { + goto error; + } + if (!cgiWriteString(out, cgiAccept)) { + goto error; + } + if (!cgiWriteString(out, cgiUserAgent)) { + goto error; + } + if (!cgiWriteString(out, cgiReferrer)) { + goto error; + } + if (!cgiWriteString(out, cgiCookie)) { + goto error; + } + if (!cgiWriteInt(out, cgiContentLength)) { + goto error; + } + e = cgiFormEntryFirst; + while (e) { + cgiFilePtr fp; + if (!cgiWriteString(out, e->attr)) { + goto error; + } + if (!cgiWriteString(out, e->value)) { + goto error; + } + /* New 2.0 fields and file uploads */ + if (!cgiWriteString(out, e->fileName)) { + goto error; + } + if (!cgiWriteString(out, e->contentType)) { + goto error; + } + if (!cgiWriteInt(out, e->valueLength)) { + goto error; + } + if (cgiFormFileOpen(e->attr, &fp) == cgiFormSuccess) { + char buffer[1024]; + int got; + if (!cgiWriteInt(out, 1)) { + cgiFormFileClose(fp); + goto error; + } + while (cgiFormFileRead(fp, buffer, + sizeof(buffer), &got) == cgiFormSuccess) + { + if (((int) fwrite(buffer, 1, got, out)) != got) { + cgiFormFileClose(fp); + goto error; + } + } + if (cgiFormFileClose(fp) != cgiFormSuccess) { + goto error; + } + } else { + if (!cgiWriteInt(out, 0)) { + goto error; + } + } + e = e->next; + } + fclose(out); + return cgiEnvironmentSuccess; error: - fclose(out); - /* If this function is not defined in your system, - you must substitute the appropriate - file-deletion function. */ - unlink(filename); - return cgiEnvironmentIO; + fclose(out); + /* If this function is not defined in your system, + you must substitute the appropriate + file-deletion function. */ + unlink(filename); + return cgiEnvironmentIO; } static int cgiWriteString(FILE *out, char *s) { - int len = (int) strlen(s); - cgiWriteInt(out, len); - if (((int) fwrite(s, 1, len, out)) != len) { - return 0; - } - return 1; + int len = (int) strlen(s); + cgiWriteInt(out, len); + if (((int) fwrite(s, 1, len, out)) != len) { + return 0; + } + return 1; } static int cgiWriteInt(FILE *out, int i) { - if (!fwrite(&i, sizeof(int), 1, out)) { - return 0; - } - return 1; + if (!fwrite(&i, sizeof(int), 1, out)) { + return 0; + } + return 1; } static int cgiReadString(FILE *out, char **s); @@ -2056,503 +2037,527 @@ static int cgiReadString(FILE *out, char **s); static int cgiReadInt(FILE *out, int *i); cgiEnvironmentResultType cgiReadEnvironment(char *filename) { - FILE *in; - cgiFormEntry *e = 0, *p; - char *version; - /* Prevent compiler warnings */ - cgiEnvironmentResultType result = cgiEnvironmentIO; - /* Free any existing data first */ - cgiFreeResources(); - /* Be sure to open in binary mode */ - in = fopen(filename, "rb"); - if (!in) { - /* Can't access file */ - return cgiEnvironmentIO; - } - if (!cgiReadString(in, &version)) { - goto error; - } - if (strcmp(version, "CGIC" CGIC_VERSION)) { - /* 2.02: Merezko Oleg */ - free(version); - return cgiEnvironmentWrongVersion; - } - /* 2.02: Merezko Oleg */ - free(version); - if (!cgiReadString(in, &cgiServerSoftware)) { - goto error; - } - if (!cgiReadString(in, &cgiServerName)) { - goto error; - } - if (!cgiReadString(in, &cgiGatewayInterface)) { - goto error; - } - if (!cgiReadString(in, &cgiServerProtocol)) { - goto error; - } - if (!cgiReadString(in, &cgiServerPort)) { - goto error; - } - if (!cgiReadString(in, &cgiRequestMethod)) { - goto error; - } - if (!cgiReadString(in, &cgiPathInfo)) { - goto error; - } - if (!cgiReadString(in, &cgiPathTranslated)) { - goto error; - } - if (!cgiReadString(in, &cgiScriptName)) { - goto error; - } - if (!cgiReadString(in, &cgiQueryString)) { - goto error; - } - if (!cgiReadString(in, &cgiRemoteHost)) { - goto error; - } - if (!cgiReadString(in, &cgiRemoteAddr)) { - goto error; - } - if (!cgiReadString(in, &cgiAuthType)) { - goto error; - } - if (!cgiReadString(in, &cgiRemoteUser)) { - goto error; - } - if (!cgiReadString(in, &cgiRemoteIdent)) { - goto error; - } - if (!cgiReadString(in, &cgiContentType)) { - goto error; - } - if (!cgiReadString(in, &cgiAccept)) { - goto error; - } - if (!cgiReadString(in, &cgiUserAgent)) { - goto error; - } - if (!cgiReadString(in, &cgiReferrer)) { - goto error; - } - /* 2.0 */ - if (!cgiReadString(in, &cgiCookie)) { - goto error; - } - if (!cgiReadInt(in, &cgiContentLength)) { - goto error; - } - p = 0; - while (1) { - int fileFlag; - e = (cgiFormEntry *) calloc(1, sizeof(cgiFormEntry)); - if (!e) { - cgiFreeResources(); - fclose(in); - return cgiEnvironmentMemory; - } - memset(e, 0, sizeof(cgiFormEntry)); - if (!cgiReadString(in, &e->attr)) { - /* This means we've reached the end of the list. */ - /* 2.02: thanks to Merezko Oleg */ - free(e); - break; - } - if (!cgiReadString(in, &e->value)) { - goto outOfMemory; - } - if (!cgiReadString(in, &e->fileName)) { - goto outOfMemory; - } - if (!cgiReadString(in, &e->contentType)) { - goto outOfMemory; - } - if (!cgiReadInt(in, &e->valueLength)) { - goto outOfMemory; - } - if (!cgiReadInt(in, &fileFlag)) { - goto outOfMemory; - } - if (fileFlag) { - char buffer[1024]; - FILE *out; - char tfileName[1024]; - int got; - int len = e->valueLength; - if (getTempFileName(tfileName) - != cgiParseSuccess) - { - result = cgiEnvironmentIO; - goto error; - } - out = fopen(tfileName, "w+b"); - if (!out) { - result = cgiEnvironmentIO; - goto error; - } - while (len > 0) { - /* 2.01: try is a bad variable name in - C++, and it wasn't being used - properly either */ - int tryr = len; - if (tryr > ((int) sizeof(buffer))) { - tryr = sizeof(buffer); - } - got = fread(buffer, 1, tryr, in); - if (got <= 0) { - result = cgiEnvironmentIO; - fclose(out); - unlink(tfileName); - goto error; - } - if (((int) fwrite(buffer, 1, got, out)) != got) { - result = cgiEnvironmentIO; - fclose(out); - unlink(tfileName); - goto error; - } - len -= got; - } - /* cgic 2.05: should be fclose not rewind */ - fclose(out); - e->tfileName = (char *) malloc((int) strlen(tfileName) + 1); - if (!e->tfileName) { - result = cgiEnvironmentMemory; - unlink(tfileName); - goto error; - } - strcpy(e->tfileName, tfileName); - } else { - e->tfileName = (char *) malloc(1); - if (!e->tfileName) { - result = cgiEnvironmentMemory; - goto error; - } - } - e->next = 0; - if (p) { - p->next = e; - } else { - cgiFormEntryFirst = e; - } - p = e; - } - fclose(in); - cgiRestored = 1; - return cgiEnvironmentSuccess; + FILE *in; + cgiFormEntry *e = 0, *p; + char *version; + /* Prevent compiler warnings */ + cgiEnvironmentResultType result = cgiEnvironmentIO; + /* Free any existing data first */ + cgiFreeResources(); + /* Be sure to open in binary mode */ + in = fopen(filename, "rb"); + if (!in) { + /* Can't access file */ + return cgiEnvironmentIO; + } + if (!cgiReadString(in, &version)) { + goto error; + } + if (strcmp(version, "CGIC" CGIC_VERSION)) { + /* 2.02: Merezko Oleg */ + free(version); + return cgiEnvironmentWrongVersion; + } + /* 2.02: Merezko Oleg */ + free(version); + if (!cgiReadString(in, &cgiServerSoftware)) { + goto error; + } + if (!cgiReadString(in, &cgiServerName)) { + goto error; + } + if (!cgiReadString(in, &cgiGatewayInterface)) { + goto error; + } + if (!cgiReadString(in, &cgiServerProtocol)) { + goto error; + } + if (!cgiReadString(in, &cgiServerPort)) { + goto error; + } + if (!cgiReadString(in, &cgiRequestMethod)) { + goto error; + } + if (!cgiReadString(in, &cgiPathInfo)) { + goto error; + } + if (!cgiReadString(in, &cgiPathTranslated)) { + goto error; + } + if (!cgiReadString(in, &cgiScriptName)) { + goto error; + } + if (!cgiReadString(in, &cgiQueryString)) { + goto error; + } + if (!cgiReadString(in, &cgiRemoteHost)) { + goto error; + } + if (!cgiReadString(in, &cgiRemoteAddr)) { + goto error; + } + if (!cgiReadString(in, &cgiAuthType)) { + goto error; + } + if (!cgiReadString(in, &cgiRemoteUser)) { + goto error; + } + if (!cgiReadString(in, &cgiRemoteIdent)) { + goto error; + } + if (!cgiReadString(in, &cgiContentType)) { + goto error; + } + if (!cgiReadString(in, &cgiAccept)) { + goto error; + } + if (!cgiReadString(in, &cgiUserAgent)) { + goto error; + } + if (!cgiReadString(in, &cgiReferrer)) { + goto error; + } + /* 2.0 */ + if (!cgiReadString(in, &cgiCookie)) { + goto error; + } + if (!cgiReadInt(in, &cgiContentLength)) { + goto error; + } + p = 0; + while (1) { + int fileFlag; + e = (cgiFormEntry *) calloc(1, sizeof(cgiFormEntry)); + if (!e) { + cgiFreeResources(); + fclose(in); + return cgiEnvironmentMemory; + } + memset(e, 0, sizeof(cgiFormEntry)); + if (!cgiReadString(in, &e->attr)) { + /* This means we've reached the end of the list. */ + /* 2.02: thanks to Merezko Oleg */ + free(e); + break; + } + if (!cgiReadString(in, &e->value)) { + goto outOfMemory; + } + if (!cgiReadString(in, &e->fileName)) { + goto outOfMemory; + } + if (!cgiReadString(in, &e->contentType)) { + goto outOfMemory; + } + if (!cgiReadInt(in, &e->valueLength)) { + goto outOfMemory; + } + if (!cgiReadInt(in, &fileFlag)) { + goto outOfMemory; + } + if (fileFlag) { + char buffer[1024]; + FILE *out = NULL; + int got; + int len = e->valueLength; + if (getTempFileName(&out) + != cgiParseSuccess || !out) + { + result = cgiEnvironmentIO; + goto error; + } + while (len > 0) { + /* 2.01: try is a bad variable name in + C++, and it wasn't being used + properly either */ + int tryr = len; + if (tryr > ((int) sizeof(buffer))) { + tryr = sizeof(buffer); + } + got = fread(buffer, 1, tryr, in); + if (got <= 0) { + result = cgiEnvironmentIO; + fclose(out); + goto error; + } + if (((int) fwrite(buffer, 1, got, out)) != got) { + result = cgiEnvironmentIO; + fclose(out); + goto error; + } + len -= got; + } + /* cgic 2.05: should be fclose not rewind */ + e->tFile = out; + } else { + e->tFile = NULL; + } + e->next = 0; + if (p) { + p->next = e; + } else { + cgiFormEntryFirst = e; + } + p = e; + } + fclose(in); + cgiRestored = 1; + return cgiEnvironmentSuccess; outOfMemory: - result = cgiEnvironmentMemory; + result = cgiEnvironmentMemory; error: - cgiFreeResources(); - fclose(in); - if (e) { - if (e->attr) { - free(e->attr); - } - if (e->value) { - free(e->value); - } - if (e->fileName) { - free(e->fileName); - } - if (e->contentType) { - free(e->contentType); - } - if (e->tfileName) { - free(e->tfileName); - } - free(e); - } - return result; + cgiFreeResources(); + fclose(in); + if (e) { + if (e->attr) { + free(e->attr); + } + if (e->value) { + free(e->value); + } + if (e->fileName) { + free(e->fileName); + } + if (e->contentType) { + free(e->contentType); + } + if (e->tFile) { + fclose(e->tFile); + } + free(e); + } + return result; } static int cgiReadString(FILE *in, char **s) { - int len; - /* 2.0 fix: test cgiReadInt for failure! */ - if (!cgiReadInt(in, &len)) { - return 0; - } - *s = (char *) malloc(len + 1); - if (!(*s)) { - return 0; - } - if (((int) fread(*s, 1, len, in)) != len) { - return 0; - } - (*s)[len] = '\0'; - return 1; + int len; + /* 2.0 fix: test cgiReadInt for failure! */ + if (!cgiReadInt(in, &len)) { + return 0; + } + *s = (char *) malloc(len + 1); + if (!(*s)) { + return 0; + } + if (((int) fread(*s, 1, len, in)) != len) { + return 0; + } + (*s)[len] = '\0'; + return 1; } static int cgiReadInt(FILE *out, int *i) { - if (!fread(i, sizeof(int), 1, out)) { - return 0; - } - return 1; + if (!fread(i, sizeof(int), 1, out)) { + return 0; + } + return 1; } static int cgiStrEqNc(char *s1, char *s2) { - while(1) { - if (!(*s1)) { - if (!(*s2)) { - return 1; - } else { - return 0; - } - } else if (!(*s2)) { - return 0; - } - if (isalpha((int)*s1)) { - if (tolower(*s1) != tolower(*s2)) { - return 0; - } - } else if ((*s1) != (*s2)) { - return 0; - } - s1++; - s2++; - } + while(1) { + if (!(*s1)) { + if (!(*s2)) { + return 1; + } else { + return 0; + } + } else if (!(*s2)) { + return 0; + } + if (isalpha(*s1)) { + if (tolower(*s1) != tolower(*s2)) { + return 0; + } + } else if ((*s1) != (*s2)) { + return 0; + } + s1++; + s2++; + } } static int cgiStrBeginsNc(char *s1, char *s2) { - while(1) { - if (!(*s2)) { - return 1; - } else if (!(*s1)) { - return 0; - } - if (isalpha((int)*s1)) { - if (tolower(*s1) != tolower(*s2)) { - return 0; - } - } else if ((*s1) != (*s2)) { - return 0; - } - s1++; - s2++; - } + while(1) { + if (!(*s2)) { + return 1; + } else if (!(*s1)) { + return 0; + } + if (isalpha(*s1)) { + if (tolower(*s1) != tolower(*s2)) { + return 0; + } + } else if ((*s1) != (*s2)) { + return 0; + } + s1++; + s2++; + } } static char *cgiFindTarget = 0; static cgiFormEntry *cgiFindPos = 0; static cgiFormEntry *cgiFormEntryFindFirst(char *name) { - cgiFindTarget = name; - cgiFindPos = cgiFormEntryFirst; - return cgiFormEntryFindNext(); + cgiFindTarget = name; + cgiFindPos = cgiFormEntryFirst; + return cgiFormEntryFindNext(); } static cgiFormEntry *cgiFormEntryFindNext() { - while (cgiFindPos) { - cgiFormEntry *c = cgiFindPos; - cgiFindPos = c->next; - if (!strcmp(c -> attr, cgiFindTarget)) { - return c; - } - } - return 0; + while (cgiFindPos) { + cgiFormEntry *c = cgiFindPos; + cgiFindPos = c->next; + if (!strcmp(c -> attr, cgiFindTarget)) { + return c; + } + } + return 0; } static int cgiFirstNonspaceChar(char *s) { - int len = strspn(s, " \n\r\t"); - return s[len]; + int len = strspn(s, " \n\r\t"); + return s[len]; } void cgiStringArrayFree(char **stringArray) { - char *p; - char **arrayItself = stringArray; - p = *stringArray; - while (p) { - free(p); - stringArray++; - p = *stringArray; - } - /* 2.0: free the array itself! */ - free(arrayItself); -} + char *p; + char **arrayItself = stringArray; + p = *stringArray; + while (p) { + free(p); + stringArray++; + p = *stringArray; + } + /* 2.0: free the array itself! */ + free(arrayItself); +} cgiFormResultType cgiCookies(char ***result) { - char **stringArray; - int i; - int total = 0; - char *p; - char *n; - p = cgiCookie; - while (*p) { - if (*p == '=') { - total++; - } - p++; - } - stringArray = (char **) malloc(sizeof(char *) * (total + 1)); - if (!stringArray) { - *result = 0; - return cgiFormMemory; - } - /* initialize all entries to null; the last will stay that way */ - for (i=0; (i <= total); i++) { - stringArray[i] = 0; - } - i = 0; - p = cgiCookie; - while (*p) { - while (*p && isspace((int)*p)) { - p++; - } - n = p; - while (*p && (*p != '=')) { - p++; - } - if (p != n) { - stringArray[i] = (char *) malloc((p - n) + 1); - if (!stringArray[i]) { - cgiStringArrayFree(stringArray); - *result = 0; - return cgiFormMemory; - } - memcpy(stringArray[i], n, p - n); - stringArray[i][p - n] = '\0'; - i++; - } - while (*p && (*p != ';')) { - p++; - } - if (!*p) { - break; - } - if (*p == ';') { - p++; - } - } - *result = stringArray; - return cgiFormSuccess; + char **stringArray; + int i; + int total = 0; + char *p; + char *n; + p = cgiCookie; + while (*p) { + if (*p == '=') { + total++; + } + p++; + } + stringArray = (char **) malloc(sizeof(char *) * (total + 1)); + if (!stringArray) { + *result = 0; + return cgiFormMemory; + } + /* initialize all entries to null; the last will stay that way */ + for (i=0; (i <= total); i++) { + stringArray[i] = 0; + } + i = 0; + p = cgiCookie; + while (*p) { + while (*p && isspace(*p)) { + p++; + } + n = p; + while (*p && (*p != '=')) { + p++; + } + if (p != n) { + stringArray[i] = (char *) malloc((p - n) + 1); + if (!stringArray[i]) { + cgiStringArrayFree(stringArray); + *result = 0; + return cgiFormMemory; + } + memcpy(stringArray[i], n, p - n); + stringArray[i][p - n] = '\0'; + i++; + } + while (*p && (*p != ';')) { + p++; + } + if (!*p) { + break; + } + if (*p == ';') { + p++; + } + } + *result = stringArray; + return cgiFormSuccess; } cgiFormResultType cgiFormEntries(char ***result) { - char **stringArray; - cgiFormEntry *e, *pe; - int i; - int total = 0; - e = cgiFormEntryFirst; - while (e) { - /* Don't count a field name more than once if - multiple values happen to be present for it */ - pe = cgiFormEntryFirst; - while (pe != e) { - if (!strcmp(e->attr, pe->attr)) { - goto skipSecondValue; - } - pe = pe->next; - } - total++; + char **stringArray; + cgiFormEntry *e, *pe; + int i; + int total = 0; + e = cgiFormEntryFirst; + while (e) { + /* Don't count a field name more than once if + multiple values happen to be present for it */ + pe = cgiFormEntryFirst; + while (pe != e) { + if (!strcmp(e->attr, pe->attr)) { + goto skipSecondValue; + } + pe = pe->next; + } + total++; skipSecondValue: - e = e->next; - } - stringArray = (char **) malloc(sizeof(char *) * (total + 1)); - if (!stringArray) { - *result = 0; - return cgiFormMemory; - } - /* initialize all entries to null; the last will stay that way */ - for (i=0; (i <= total); i++) { - stringArray[i] = 0; - } - /* Now go get the entries */ - e = cgiFormEntryFirst; - i = 0; - while (e) { - int space; - /* Don't return a field name more than once if - multiple values happen to be present for it */ - pe = cgiFormEntryFirst; - while (pe != e) { - if (!strcmp(e->attr, pe->attr)) { - goto skipSecondValue2; - } - pe = pe->next; - } - space = (int) strlen(e->attr) + 1; - stringArray[i] = (char *) malloc(space); - if (stringArray[i] == 0) { - /* Memory problems */ - cgiStringArrayFree(stringArray); - *result = 0; - return cgiFormMemory; - } - strcpy(stringArray[i], e->attr); - i++; + e = e->next; + } + stringArray = (char **) malloc(sizeof(char *) * (total + 1)); + if (!stringArray) { + *result = 0; + return cgiFormMemory; + } + /* initialize all entries to null; the last will stay that way */ + for (i=0; (i <= total); i++) { + stringArray[i] = 0; + } + /* Now go get the entries */ + e = cgiFormEntryFirst; + i = 0; + while (e) { + size_t space; + /* Don't return a field name more than once if + multiple values happen to be present for it */ + pe = cgiFormEntryFirst; + while (pe != e) { + if (!strcmp(e->attr, pe->attr)) { + goto skipSecondValue2; + } + pe = pe->next; + } + space = strlen(e->attr) + 1; + stringArray[i] = (char *) malloc(space); + if (stringArray[i] == 0) { + /* Memory problems */ + cgiStringArrayFree(stringArray); + *result = 0; + return cgiFormMemory; + } + strcpy(stringArray[i], e->attr); + i++; skipSecondValue2: - e = e->next; - } - *result = stringArray; - return cgiFormSuccess; + e = e->next; + } + *result = stringArray; + return cgiFormSuccess; } #define TRYPUTC(ch) \ - { \ - if (putc((ch), cgiOut) == EOF) { \ - return cgiFormIO; \ - } \ - } + { \ + if (putc((ch), cgiOut) == EOF) { \ + return cgiFormIO; \ + } \ + } -cgiFormResultType cgiHtmlEscapeData(char *data, int len) +cgiFormResultType cgiHtmlEscapeData(const char *data, int len) { - while (len--) { - if (*data == '<') { - TRYPUTC('&'); - TRYPUTC('l'); - TRYPUTC('t'); - TRYPUTC(';'); - } else if (*data == '&') { - TRYPUTC('&'); - TRYPUTC('a'); - TRYPUTC('m'); - TRYPUTC('p'); - TRYPUTC(';'); - } else if (*data == '>') { - TRYPUTC('&'); - TRYPUTC('g'); - TRYPUTC('t'); - TRYPUTC(';'); - } else { - TRYPUTC(*data); - } - data++; - } - return cgiFormSuccess; + while (len--) { + if (*data == '<') { + TRYPUTC('&'); + TRYPUTC('l'); + TRYPUTC('t'); + TRYPUTC(';'); + } else if (*data == '&') { + TRYPUTC('&'); + TRYPUTC('a'); + TRYPUTC('m'); + TRYPUTC('p'); + TRYPUTC(';'); + } else if (*data == '>') { + TRYPUTC('&'); + TRYPUTC('g'); + TRYPUTC('t'); + TRYPUTC(';'); + } else { + TRYPUTC(*data); + } + data++; + } + return cgiFormSuccess; } -cgiFormResultType cgiHtmlEscape(char *s) +cgiFormResultType cgiHtmlEscape(const char *s) { - return cgiHtmlEscapeData(s, (int) strlen(s)); + return cgiHtmlEscapeData(s, (int) strlen(s)); } /* Output data with the " character HTML-escaped, and no - other characters escaped. This is useful when outputting - the contents of a tag attribute such as 'href' or 'src'. - 'data' is not null-terminated; 'len' is the number of - bytes in 'data'. Returns cgiFormIO in the event - of error, cgiFormSuccess otherwise. */ -cgiFormResultType cgiValueEscapeData(char *data, int len) + other characters escaped. This is useful when outputting + the contents of a tag attribute such as 'href' or 'src'. + 'data' is not null-terminated; 'len' is the number of + bytes in 'data'. Returns cgiFormIO in the event + of error, cgiFormSuccess otherwise. */ +cgiFormResultType cgiValueEscapeData(const char *data, int len) { - while (len--) { - if (*data == '\"') { - TRYPUTC('&'); - TRYPUTC('#'); - TRYPUTC('3'); - TRYPUTC('4'); - TRYPUTC(';'); - } else { - TRYPUTC(*data); - } - data++; - } - return cgiFormSuccess; + while (len--) { + if (*data == '\"') { + TRYPUTC('&'); + TRYPUTC('#'); + TRYPUTC('3'); + TRYPUTC('4'); + TRYPUTC(';'); + } else { + TRYPUTC(*data); + } + data++; + } + return cgiFormSuccess; } -cgiFormResultType cgiValueEscape(char *s) +cgiFormResultType cgiValueEscape(const char *s) { - return cgiValueEscapeData(s, (int) strlen(s)); + return cgiValueEscapeData(s, (int) strlen(s)); } +#ifdef UNIT_TEST + +static void unitTestAssert(const int value, const char *message); + +static int unitTest() { + char *input = "one=1&two=2&empty1&four=4&empty2"; + cgiFormEntry *e; + cgiParseResultType result = cgiParseFormInput(input, strlen(input)); + unitTestAssert(result == cgiParseSuccess, "cgiParseFormInput did not return cgiParseSuccess"); + e = cgiFormEntryFirst; + unitTestAssert(!!e, "first entry missing"); + unitTestAssert(!strcmp(e->attr, "one"), "first entry name is not one"); + unitTestAssert(!strcmp(e->value, "1"), "first entry value is not 1"); + e = e->next; + unitTestAssert(!!e, "Test failed: second entry missing"); + unitTestAssert(!strcmp(e->attr, "two"), "second entry name is not two"); + unitTestAssert(!strcmp(e->value, "2"), "second entry value is not 2"); + e = e->next; + unitTestAssert(!!e, "Test failed: third entry missing"); + unitTestAssert(!strcmp(e->attr, "empty1"), "third entry name is not empty1"); + unitTestAssert(!strcmp(e->value, ""), "third entry value is not empty string"); + e = e->next; + unitTestAssert(!!e, "Test failed: fourth entry missing"); + unitTestAssert(!strcmp(e->attr, "four"), "fourth entry name is not four"); + unitTestAssert(!strcmp(e->value, "4"), "fourth entry value is not 4"); + e = e->next; + unitTestAssert(!!e, "Test failed: fifth entry missing"); + unitTestAssert(!strcmp(e->attr, "empty2"), "fifth entry name is not empty2"); + unitTestAssert(!strcmp(e->value, ""), "fifth entry value is not empty string"); + unitTestAssert(!e->next, "unexpected entry at end of list"); + return 0; +} + +static void unitTestAssert(const int value, const char *message) +{ + if (value) { + return; + } + fprintf(stderr, "Test failed: %s\n", message); + exit(1); +} + +#endif diff --git a/cgic.h b/cgic.h index 54270db..45cd9cb 100644 --- a/cgic.h +++ b/cgic.h @@ -6,6 +6,11 @@ #ifndef CGI_C #define CGI_C 1 +/* Ensure proper linkage to c++ programs. */ +#ifdef __cplusplus +extern "C" { +#endif + /* Bring in standard I/O since some of the functions refer to types defined by it, such as FILE *. */ @@ -205,20 +210,20 @@ extern cgiFormResultType cgiFormEntries( /* Output string with the <, &, and > characters HTML-escaped. 's' is null-terminated. Returns cgiFormIO in the event of error, cgiFormSuccess otherwise. */ -cgiFormResultType cgiHtmlEscape(char *s); +cgiFormResultType cgiHtmlEscape(const char *s); /* Output data with the <, &, and > characters HTML-escaped. 'data' is not null-terminated; 'len' is the number of bytes in 'data'. Returns cgiFormIO in the event of error, cgiFormSuccess otherwise. */ -cgiFormResultType cgiHtmlEscapeData(char *data, int len); +cgiFormResultType cgiHtmlEscapeData(const char *data, int len); /* Output string with the " character HTML-escaped, and no other characters escaped. This is useful when outputting the contents of a tag attribute such as 'href' or 'src'. 's' is null-terminated. Returns cgiFormIO in the event of error, cgiFormSuccess otherwise. */ -cgiFormResultType cgiValueEscape(char *s); +cgiFormResultType cgiValueEscape(const char *s); /* Output data with the " character HTML-escaped, and no other characters escaped. This is useful when outputting @@ -226,7 +231,11 @@ cgiFormResultType cgiValueEscape(char *s); 'data' is not null-terminated; 'len' is the number of bytes in 'data'. Returns cgiFormIO in the event of error, cgiFormSuccess otherwise. */ -cgiFormResultType cgiValueEscapeData(char *data, int len); +cgiFormResultType cgiValueEscapeData(const char *data, int len); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ #endif /* CGI_C */ diff --git a/dir.c b/dir.c index 039630a..fed0ae9 100644 --- a/dir.c +++ b/dir.c @@ -70,9 +70,9 @@ void dirlist(void) { time_t now; time(&now); - upload_id=ftok(getenv("SCRIPT_FILENAME"), getpid()); - if(upload_id<1) - upload_id=now; // holy shit +// upload_id=ftok(getenv("SCRIPT_FILENAME"), getpid()); +// if(upload_id<1) +// upload_id=now; // holy shit cgiFormStringNoNewlines("highlight", highlight, sizeof(wp.virt_filename)-1); //TODO: urlencode ? cgiFormStringNoNewlines("sortby", sortby, 63); @@ -119,7 +119,7 @@ void dirlist(void) { " }\n" "}\n"); - if(rt.js>=2) fprintf(cgiOut, +/* if(rt.js>=2) fprintf(cgiOut, "function xmlhttpPost(strURL) {\n" " var xmlHttpReq = false;\n" " var self = this;\n" @@ -146,7 +146,7 @@ void dirlist(void) { "function start() {\n" " setInterval('xmlhttpPost(\"%s?ea=upstat&upload_id=%d\");', 250);\n" "}\n", - cgiScriptName, upload_id); + cgiScriptName, upload_id);*/ if(rt.js) fprintf(cgiOut, "//-->\n" @@ -177,7 +177,7 @@ void dirlist(void) { "\n" "\n" "
\n", - FONT_SIZE, FONT_SIZE, rt.iconsurl, cfg.favicon, cgiScriptName, (rt.js>=2) ? "onsubmit=\"start()\"" : ""); + FONT_SIZE, FONT_SIZE, rt.iconsurl, cfg.favicon, cgiScriptName, /*(rt.js>=2) ? "onsubmit=\"start()\"" :*/ ""); diff --git a/wfm.c b/wfm.c index a72f261..87b3c0d 100644 --- a/wfm.c +++ b/wfm.c @@ -35,7 +35,7 @@ int icon(void) { // Display upload status in SHM via key_id // Called by early action=upstat // -void upload_status(void) { +/*void upload_status(void) { int shm_key=-1; int shm_id=-1; char *shm_val=NULL; @@ -61,7 +61,7 @@ void upload_status(void) { shmdt(shm_val); exit(0); -} +}*/ // @@ -566,7 +566,7 @@ int cgiMain(void) { // early action - simple actions before cfg is read or access check performed (no authentication!) cgiFormStringNoNewlines("ea", ea, sizeof(ea)); if(strcmp(ea, "icon")==0) icon(); - if(strcmp(ea, "upstat")==0) upload_status(); +// if(strcmp(ea, "upstat")==0) upload_status(); // normal initialization tstart(); diff --git a/wfm.h b/wfm.h index 0e86090..346a670 100644 --- a/wfm.h +++ b/wfm.h @@ -64,7 +64,7 @@ #define VALIDCHRS "an ()[]{}-_.,!@#$%^&=+;" #define VALIDCHRS_DIR VALIDCHRS "/" -#define SHM_SIZE 16 +//#define SHM_SIZE 16 struct wfm_paths { char virt_dirname[NAME_MAX]; -- cgit v1.2.3