/* * Implementation file for cgi.h. * * Note that C-style strings (o type char* ) are used internally. */ #include #include #include #include #include "cgi.h" struct fieldData { // Represents one name/value pair from query data sent to CGI program. // Generally, that means the name and value of an item in a HTML form. char *name; char *value; }; static char* cgiData[REMOTE_IDENT]; // Contains the valuse of CGI variables REQUEST_METHOD, REMOTE_ADDR, // HTTP_REFERER, etc. (NOTE: A "static" global variable or // function in C++ is one that can only be used in the file in // which it is defined -- this is not related to other meanings // of the overused word "static.") static fieldData *fields = NULL; // An array, to be created by the getFields() function, // containing all name/value pairs in the CGI data. // If there is no data, the value will be NULL after // calling getFields(). static int fieldCt = 0; // The number of name/value pairs stored in the array, fields. // The value is set by a call to the getFields() funtion. static bool dataReady = false; /********************************************************************************** * Function getFields() reads CGI data and decodes it into a set of name/value * * pairs. The number of pairs is stored in the global variable, fieldCt. * * The pairs themselves are stored in a global array, fields. * * (The function can read data submitted using either the GET or POST method. * * Data submitted through GET is retrieved from the environment variable * * QUERY_STRING. Data submitted with POST is read from standard input.) * **********************************************************************************/ static void getFields() { char* cgiVarName[] = { "REQUEST_METHOD", "REMOTE_ADDR", "HTTP_REFERER", "HTTP_USER_AGENT", "QUERY_STRING", "CONTENT_LENGTH", "CONTENT_TYPE", "HTTP_ACCEPT", "HTTP_HOST", "REMOTE_PORT", "SCRIPT_FILENAME", "GATEWAY_INTERFACE", "SERVER_PROTOCOL", "HTTP_ACCEPT_LANGUAGE", "REQUEST_URI", "SCRIPT_NAME", "SERVER_SOFTWARE", "SERVER_PORT", "PATH_INFO", "REMOTE_USER", "DOCUMENT_ROOT", "AUTH_TYPE", "REMOTE_IDENT" }; dataReady = true; for (int i = REQUEST_METHOD; i <= REMOTE_IDENT; i++) cgiData[i] = getenv(cgiVarName[i]); char *data = NULL; char *method = cgiData[REQUEST_METHOD]; if (method && strcmp(method, "GET") == 0) { char *query = cgiData[QUERY_STRING]; if (query == NULL || query[0] == 0) return; data = new char[strlen(query)+1]; if (data == NULL) return; strcpy(data,query); } else if (method && strcmp(method, "POST") == 0) { char *len = cgiData[CONTENT_LENGTH]; if (len == NULL || len[0] == 0) return; int datalength = atoi(len); if (datalength <= 0) return; data = new char[datalength+1]; if (data == NULL) return; cin.get(data,datalength+1,'\0'); if (!cin) { delete[] data; data = NULL; return; } } if (data == NULL) return; fieldCt = 1; for (int i = 0; data[i]; i++) if (data[i] == '&') fieldCt++; fields = new fieldData[fieldCt]; if (fields == NULL) { delete[] data; data = NULL; fieldCt = 0; return; } int inChar = 0; int outChar = 0; int ct = 0; int readingName = 1; fields[0].name = &data[0]; while (1) { if (data[inChar] == '+') data[outChar] = ' '; else if (data[inChar] == '%') { inChar++; if (data[inChar] == 0 || data[inChar+1] == 0) // shouldn't happen continue; int ch; if (data[inChar] >= '0' && data[inChar] <= '9') ch = data[inChar] - '0'; else if (data[inChar] >= 'a' && data[inChar] <= 'z') ch = data[inChar] - 'a' + 10; else ch = data[inChar] - 'A' + 10; inChar++; if (data[inChar] >= '0' && data[inChar] <= '9') ch = 16*ch + (data[inChar] - '0'); else if (data[inChar] >= 'a' && data[inChar] <= 'z') ch = 16*ch + (data[inChar] - 'a' + 10); else ch = 16*ch + (data[inChar] - 'A' + 10); data[outChar] = ch; } else if (data[inChar] == '=') { data[outChar] = 0; readingName = 0; fields[ct].value = &data[outChar+1]; } else if (data[inChar] == '&' || data[inChar] == 0) { int done = (data[inChar] == 0); data[outChar] = 0; if (readingName) // shouldn't be true fields[ct].value = fields[ct].name; if (done) { break; } ct++; readingName = 1; fields[ct].name = &data[outChar+1]; } else data[outChar] = data[inChar]; outChar++; inChar++; } if (readingName) // shouldn't be true fields[ct].value = fields[ct].name; fieldCt = ct+1; // have to already be equal, but let's be sure. } // end getFields(); /****************************************************** * Definitions of fucntions defined in cgi.h * ******************************************************/ string getCGIVariable(CGIVariable varName) { if (!dataReady) getFields(); if (cgiData[varName]) return cgiData[varName]; else return ""; } int formItemCount() { if (!dataReady) getFields(); return fieldCt; } string getFormItemValue(string itemName) { if (!dataReady) getFields(); for (int i = 0; i < fieldCt; i++) { if (itemName == fields[i].name) return fields[i].value; } return ""; } string getFormItemName(int itemNum) { if (!dataReady) getFields(); if (itemNum >= 0 && itemNum < fieldCt) return fields[itemNum].name; else return ""; } string getFormItemValue(int itemNum) { if (!dataReady) getFields(); if (itemNum >= 0 && itemNum < fieldCt) return fields[itemNum].value; else return ""; } bool string2int(string numString, int &num) { istringstream s(numString); num = 0; // value if an error occurs s >> num; if (!s) // Couldn't read a number. return false; int junk; // Shouldn't be anything else in the string -- // to make sure, try to read something. s >> junk; if (!s.eof()) return false; return true; } bool string2double(string numString, double &num) { istringstream s(numString); num = 0; // value if an error occurs s >> num; if (!s) // Couldn't read a number. return false; int junk; // Shouldn't be anything else in the string -- // to make sure, try to read something. s >> junk; if (!s.eof()) return false; return true; } string htmlEscape(string str) { int change = false; int len = str.length(); for (int i = 0; i < len; i++) { if (str[i] == '&' || str[i] == '<' || str[i] == '>' || str[i] == '"') { change = true; break; } } if (change) { string s; for (int i = 0; i < len; i++) { switch (str[i]) { case '&': s += "&"; break; case '"': s += """; break; case '<': s += "<"; break; case '>': s += ">"; break; default: s += str[i]; } } return s; } else { return str; } }