#include #include /* getenv */ #include /* vfprintf */ #include /* str... */ #include /* is... */ #include "cgi.h" /* Local global variables ******************************************************************************/ static int cgiHeaderFlag = 0; static int cgiHtmlFlag = 0; static int cgiArgc = 0; static char **cgiArgv = NULL; static char *cgiStdin = NULL; typedef struct { char *var; char *val; } pair_t; typedef struct { int size; pair_t *pair; } form_t; form_t form; /* Local function declaration ******************************************************************************/ static char *cgiStrdup(char *s); static char *cgiDecodeUrl(char *data); static int cgiFormAdd(char *var, char *val); static char *cgiGetEnv(char *var); static char *cgiGetStdin(int len); static char cgiHexAsc(char x1, char x2); static int cgiHexInt(char x); static int cgiParseArgs(char **argv, int argc); static int cgiParseInput(char *input, int len); /* Library functions ******************************************************************************/ /****************************************************************************** ** ** Function cgiFormGetVal ** ** Purpose Return the value of the given variable ** ** History Date Author Modification ** 04-03-96 JEM First Draft ** ******************************************************************************/ char *cgiFormGetVal(char *var) { int cnt; for(cnt=0; cnt "); cgiPrintf(""); cgiPrintf("%s", title); cgiPrintf(""); cgiPrintf(""); } /****************************************************************************** ** ** Function cgiHtmlTail ** ** Purpose Finalises a HTML document ** ** History Date Author Modification ** 29-03-96 JEM First Draft ** ******************************************************************************/ void cgiHtmlTail() { cgiPrintf(""); cgiPrintf(""); } /****************************************************************************** ** ** Function cgiPrintf ** ** Purpose Same as printf, but suffixes a NL char to help keep script tidy, ** and flushes output. ** ** History Date Author Modification ** 04-03-96 JEM First Draft ** ******************************************************************************/ void cgiPrintf(char *fmt, ...) { va_list argp; va_start(argp, fmt); vfprintf(stdout, fmt, argp); va_end(argp); fprintf(stdout, "\n"); fflush(stdout); } /****************************************************************************** ** Local functions ******************************************************************************/ /****************************************************************************** ** ** Function cgiStrdup ** ** Purpose Equivalent to non_ANSI C function strdup(). ** ** History Date Author Modification ** 11-02-97 JEM First Draft ** ******************************************************************************/ static char *cgiStrdup(char *s) { char *m; if (!s) return NULL; if (!(m = (char*)malloc(strlen(s)+1))) return NULL; return strcpy(m, s); } /****************************************************************************** ** ** Function cgiDecodeUrl ** ** Purpose Decode a URL-envoded string (plus to space, hex to ascii) ** ** History Date Author Modification ** 08-03-96 JEM First Draft ** 06-12-96 JEM Bug fix. Due to differing compiler precedence ** rules, *++i had to be changed. ** ******************************************************************************/ static char *cgiDecodeUrl(char *data) { char *i, *j; for (j=i=data; *i!='\0'; i++, j++) { if (*i == '%') { *j = cgiHexAsc(*(i+1), *(i+2)); i += 2; } else if (*i == '+') *j = ' '; else *j = *i; } *j = '\0'; return data; } /****************************************************************************** ** ** Function cgiFormAdd ** ** Purpose Add a form pair to the internal linked list ** ** History Date Author Modification ** 15-03-96 JEM First Draft ** ******************************************************************************/ static int cgiFormAdd(char *var, char *val) { if (!(form.pair)) form.pair = (pair_t*)malloc((form.size+1)*sizeof(pair_t)); else form.pair = (pair_t*)realloc(form.pair, (form.size+1)*sizeof(pair_t)); if (!(form.pair)) return 0; if (!(form.pair[form.size].var = cgiStrdup(var)) || !(form.pair[form.size].val = cgiStrdup(val))) return 0; ++form.size; return 1; } /****************************************************************************** ** ** Function cgiGetEnv ** ** Purpose ** ** History Date Author Modification ** 06-03-96 JEM First Draft ** ******************************************************************************/ static char *cgiGetEnv(char *var) { char *val = getenv(var); return (val) ? (val) : ""; } /****************************************************************************** ** ** Function cgiGetStdin ** ** Purpose Get CGI data from stdin ** ** History Date Author Modification ** 06-03-96 JEM First Draft ** ******************************************************************************/ static char *cgiGetStdin(int len) { char *data; if (!(data = (char*)malloc(len+1))) return ""; len = fread(data, 1, len, stdin); data[len]='\0'; return data; } /****************************************************************************** ** ** Function cgiHexAsc ** ** Purpose Convert two hex values to an ascii character ** ** History Date Author Modification ** 08-03-96 JEM First Draft ** ******************************************************************************/ static char cgiHexAsc(char x1, char x2) { return (isxdigit(x1)&&isxdigit(x2))?((cgiHexInt(x1)<<4)+cgiHexInt(x2)):' '; } /****************************************************************************** ** ** Function cgiHexInt ** ** Purpose Convert a hex value to an integer value ** ** History Date Author Modification ** 08-03-96 JEM First Draft ** ******************************************************************************/ static int cgiHexInt(char x) { return (x>='0' && x<='9') ? (x-'0') : (x>='a' && x<='f') ? (x-'a'+10) : (x>='A' && x<='F') ? (x-'A'+10) : 0; } /****************************************************************************** ** ** Function cgiParseArgs ** ** Purpose Get CGI data from commandline arguments ** ** History Date Author Modification ** 06-03-96 JEM First Draft ** ******************************************************************************/ static int cgiParseArgs(char **argv, int argc) { int cnt; for (cnt=1; cnt "); cgiPrintf(""); cgiPrintf("%i %s", statusCode, statusReason); cgiPrintf(""); cgiPrintf(""); cgiPrintf("

%i %s

", statusCode, statusReason); cgiPrintf("

%s

", statusMesg); cgiPrintf(""); cgiPrintf(""); return 1; } /****************************************************************************** ** ** Function cgiParseInput ** ** Purpose Parse CGI data, URL-decode and add pairs to linked list ** ** History Date Author Modification ** 06-03-96 JEM First Draft ** ******************************************************************************/ static int cgiParseInput(char *input, int len) { char *var, *val; int cnt, stPnt=0, eqPnt=0, eqCnt=0, amPnt=0, amCnt=0; if (!len) return 1; for (cnt=0; cnt<=len; cnt++) { if (input[cnt] == '=') { eqCnt++; eqPnt = cnt; } else if (input[cnt] == '&' || cnt==len) { amCnt++; amPnt = cnt; } if (!eqCnt && amCnt) /* no equal in equal/ampersand pair */ return 0; else if (eqCnt>1 || amCnt>1) /* equal/ampersand followed by same */ return 0; else if (eqCnt && amCnt) { if (stPnt == eqPnt) /* not allowed to have a NULL variable */ return 0; if (!(var = (char*)calloc(eqPnt-stPnt+1, 1))) return 0; memcpy(var, input+stPnt, eqPnt-stPnt); var = cgiDecodeUrl(var); if(!(val = (char*)calloc(amPnt-eqPnt, 1))) return 0; memcpy(val, input+eqPnt+1, amPnt-eqPnt-1); val = cgiDecodeUrl(val); if (!cgiFormAdd(var, val)) return 0; free(var); free(val); eqCnt = amCnt = 0; stPnt = amPnt+1; } } return 1; } /****************************************************************************** ** ** Function main ** ** Purpose Main ** ** History Date Author Modification ** 06-03-96 JEM First Draft ** 29-07-96 JEM Fixed error messages, residue from testing ** ******************************************************************************/ void main(int argc, char **argv) { cgiArgc = argc; cgiArgv = argv; cgiStdin = ""; cgiEnv.contentLength = atoi(cgiGetEnv("CONTENT_LENGTH")); cgiEnv.contentType = cgiGetEnv("CONTENT_TYPE"); cgiEnv.requestMethod = cgiGetEnv("REQUEST_METHOD"); cgiEnv.httpReferer = cgiGetEnv("HTTP_REFERER"); cgiEnv.httpUserAgent = cgiGetEnv("HTTP_USER_AGENT"); cgiEnv.remoteAddr = cgiGetEnv("REMOTE_ADDR"); cgiEnv.remoteHost = cgiGetEnv("REMOTE_HOST"); cgiStdin = cgiGetStdin(cgiEnv.contentLength); if (!strcmp(cgiEnv.requestMethod, "POST")) { if (!strcmp(cgiEnv.contentType, "application/x-www-form-urlencoded")) { if (!cgiParseInput(cgiStdin, cgiEnv.contentLength)) { cgiHeaderStatus(405, "Input Not Valid", "Data sent to the CGI program was not valid"); } } else { cgiHeaderStatus(406, "Input Not Encoded", "Data send to the CGI program was not URL encoded"); } } else { cgiHeaderStatus(407, "Unknown Request Method", "Only POST request method is supported"); } cgiMain(); }