/* Cfour (C++ Common Console Classes) CgiParser
* Copyright (C)2001, (C)2002 Jeffrey Bakker
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Author: Jeffrey Bakker <jefskey@yahoo.com>
* Filename: cgiparser.cpp
* File version: 1.0.0
*
* REMARK ====================================================================
* ===========================================================================
*
* This is the definition file for the CgiParser class.
* CgiParser is a Cgi parser library written in C++, which
* can be used as a stream class, thanks to operator
* overloading. The documentation below will show
* how to use the methods.
*
* CHANGELOG =================================================================
* ===========================================================================
*
* Created on: October 10th, 2002
*
* Last Modified on: November 14th, 2002
*
* - This parser is now complete.
* - Added method documentation.
*
*
* METHOD DOCUMENTATION ======================================================
* ===========================================================================
*
* CgiParser& operator<<(string name):
*
* Description: Prints the value of name from form data. If no value exists,
* just print the string.
*
* ===========================================================================
*
* CgiParser& operator>>(string &name):
*
* Description: Replace name with the value from the paired form data.
*
* ===========================================================================
*
* CgiParser():
*
* Description: Default constructor. This automatically calls methods that
* decodes the data. It also checks validity for REQUEST_METHOD
* environment variable.
*
* ===========================================================================
*
* bool is_empty():
*
* Description: Checks to see is there was any form data submitted.
*
*
* Output:
* - returns true if any form data is present, false otherwise.
*
* ===========================================================================
*
* string get_value(string name):
*
* Description: Returns the value of the name from the paired form data.
*
* Input:
*
* Parameter 1
* - Name: name
* - Type: string
* - Description: the name of the value
*
* Output:
* - returns the value of the name
*
* ===========================================================================
*
* void print_error(string error, string message):
*
* Description: Prints an error message to the browser.
*
* Input:
*
* Parameter 1
* - Name: error
* - Type: string
* - Description: the error code, or the title
*
* Parameter 2
* - Name: message
* - Type: string
* - Description: a more detailed description of the error
*
* ===========================================================================
*
* The following methods shall *never* be called by the programmer. They are
* all automatically called the moment the constructor is called. The methods
* are for URL decoding. Using these methods manually may cause undesired
* results, therefore there will be no ducumentation on how to use them.
*
* bool InitData() // top level, calls the others
* void get_query() // get data from GET method
* void get_stdin() // get data from POST method
* void parse_spaces() // convert '+' into ' '
* void split_data() // split form data into pairs
* void decode_hex(string&) // do URL decoding
* inline char asmhex(char) // convert hexadecimal
*
* END METHOD DOCUMENTATION ==================================================
* ===========================================================================
* _______. ..
*/
#include "cgiparser.h"
// construction ---------------------------------------------------------------
CgiParser::CgiParser() {
if(DEBUG_CGI_TRACE)
cout << "Content-type: text/plain\n\nIn Constructor\n";
first_print = true;
QStr = "";
// Automatically decode form data
// when CgiParser object is created
if(!InitData()) {
print_error("Invalid Request Method","");
}
}
// initialize form data to be decoded -----------------------------------------
bool CgiParser::InitData() {
if(DEBUG_CGI_TRACE)
cout << "In InitData()\n";
string Method;
// get the request method: GET or POST ?
Method = getenv("REQUEST_METHOD");
if(Method == "GET") {get_query();}
else
if(Method == "POST") {get_stdin();}
else return false;
parse_spaces(); // convert '+' to ' '
split_data(); // split name=value&name=value into data pairs
if(DEBUG_CGI_TRACE)
cout << "In InitData()\n";
return true;
}
// get url-friendly query from GET --------------------------------------------
void CgiParser::get_query() {
QStr = getenv("QUERY_STRING");
}
// get url-friendly stdin from POST -------------------------------------------
void CgiParser::get_stdin() {
if(DEBUG_CGI_TRACE) cout << "in get_stdin() point 1\n";
int Length;
string chars_long;
// know how much bytes are to be read from STDIN
chars_long = getenv("CONTENT_LENGTH");
Length = atoi(chars_long.data());
// char StdIn[Length+1]; // create a buffer for the incoming post data
char* StdIn = new char[Length+1];
if(DEBUG_CGI_TRACE)
cout << "in get_stdin() point 2 Length: " << Length << "\n";
// read the post data from STDIN for Length + 1 amount of bytes
cin.get(StdIn,Length+1);
QStr = StdIn;
if(DEBUG_CGI_TRACE) cout << "Post data is: " << QStr << endl;
if(DEBUG_CGI_TRACE) cout << "leaving get_stdin()\n";
delete [] StdIn;
}
// convert all instances of '+' into a space ----------------------------------
void CgiParser::parse_spaces() {
if(DEBUG_CGI_TRACE) cout << "in parse_spaces()\n";
for(int i = 0; i < QStr.size(); i++)
{
if(QStr[i] == '+') {QStr[i] = ' ';}
}
if(DEBUG_CGI_TRACE) cout << QStr << endl;
}
// decode the hex escapes in the url encoded string ---------------------------
void CgiParser::decode_hex(string &data) {
if(DEBUG_CGI_TRACE) cout << "in decode_hex()\n";
char one,two;
int index = 0;
bool finished = false;
index = data.find("%",index);
while(!finished || index < string::npos) {
if(index != -1) {
one = asmhex(data[index+1]);
two = asmhex(data[index+2]);
one *= 0x10;
data.erase(index,2);
data[index] = (char)one+two;
index++;
index = data.find("%",index);
}
else finished = true;
}
if(DEBUG_CGI_TRACE) cout << data << endl;
}
// translate single hex char to hex digit (using inline assembly) -------------
inline char CgiParser::asmhex(char hex) {
/*
if( hex >= (char) 0x41 ) {
asm( "AND $0xdf,%0" : "=r" (hex) );
asm( "SUB $0x41,%0" : "=r" (hex) );
asm( "ADD $0x0a,%0" : "=r" (hex) );
} else {
asm( "SUB $0x30,%0" : "=r" (hex) );
}
return hex;
*/
if(hex >= 0x41) {return ((hex & 0xdf) -0x41) + 0x0a;}
else {return hex - 0x30;}
}
// split up everything between the &'s and ='s -------------------------------
void CgiParser::split_data() {
if(DEBUG_CGI_TRACE) cout << "in split_data()\n";
string nm,vl; // temporary
DataPair Pair; // data store
int nidx,vidx; // name = value indexes
bool finished = false;
bool last = false;
nidx = 0;
vidx = QStr.find("=",nidx);
if(vidx == -1) {return;}
while (!finished) {
nm = QStr.substr(nidx,vidx - nidx);
if(nm[0] == '&') {
nm.erase(0,1);
}
decode_hex(nm); // decode the url encoded escapes
if(DEBUG_CGI_TRACE) cout << "found name:\t" << nm << endl;
nidx = QStr.find("&",vidx);
if(nidx == -1) {
nidx = QStr.size() -1;
last = true;
}
vl = QStr.substr(vidx+1,nidx - ( (!last)? vidx : vidx-1 ) );
if(vl[vl.size() -1] == '&') {
vl.erase(vl.size() -1,1);
}
decode_hex(vl); // decode the url encoded escapes
if(DEBUG_CGI_TRACE) cout << "found value:\t" << vl << endl;
Pair.Name = nm;
Pair.Value = vl;
CgiData.push_back(Pair);
vidx = QStr.find("=",vidx+1);
if(vidx == -1) {
finished = true;
}
}
}
// return the paired value of the give name -----------------------------------
string CgiParser::get_value(string Name) {
for(int i=0;i < CgiData.size();i++) {
if(CgiData[i].Name == Name) {
return CgiData[i].Value;
}
}
return "\0"; // if the pair doesn't exist
}
// check to see if there was any form data submitted --------------------------
bool CgiParser::is_empty() {
return (CgiData.size() == 0) ? true : false; // is there any form data?
}
// print given error message --------------------------------------------------
void CgiParser::print_error(string error, string msg) {
cout << "Content-type: text/html\n\n"
<< "<html>\n<head>\n<title>Error</title>\n</head>\n"
<< "<body>\n\n<H1>Error: " + error + "</H1>\n<br><br>\n";
if(msg != "") cout << msg << endl;
cout << "\n\n</body>\n</html>";
exit(0);
}
// print cgi variables by using their names, if !found print the string -------
CgiParser& CgiParser::operator<<(string name) {
if(first_print) {
cout << "Content-type: text/html\n\n";
first_print = false;
}
string value;
value = get_value(name);
if (value != "\0") {
cout << value;
} else {
cout << name;
}
return *this;
}
// swap the value into the string that matches the given name -----------------
CgiParser& CgiParser::operator>>(string &name) {
name = get_value(name);
return *this;
}
// end of class implementation ------------------------------------------------
| w | e | b | c | p | p |
|
| |||||