|
CGIparse
/*******************************************
Downloaded from: http://www.mike95.com
Copyright (c)1997 Michael Olivero
All Rights Reserved
********************************************/
#include <stdlib.h>
#include <string>
#include <iostream>
#include <stdio.h>
#include <iomanip>
#include "CGIparse.h"
bool CGIparse::mime_sent = false;
CGIparse::node::node( const char* aKey, const char* aValue, node* aNode ) : link(aNode)
{
key = new char[ strlen( aKey ) + 1 ];
value = new char[ strlen( aValue ) + 1 ];
strcpy( key, aKey );
strcpy( value, aValue );
}
CGIparse::node::~node()
{
delete [] key;
delete [] value;
}
CGIparse::CGIparse() : m_head( NULL ), m_tail( NULL ), m_method( NULL )
{
//stop execution if not executed by browser
if ( HTTP_USER_AGENT == NULL )
endMessage(NULL, errorString(300) );
//check and set request method enviornment
const char* RM = REQUEST_METHOD;
if ( RM == NULL )
endMessage(NULL, errorString(103));
m_method = new char[ strlen( RM ) + 1 ];
strcpy( m_method, RM );
char* temp = NULL; //will contain value of QUERY for either POST/GET
if ( strcmp(m_method, "GET") == 0 )
{
//===========================================
// Get posting info from environment variable
//===========================================
const char* QS = QUERY_STRING;
if ( QS == NULL )
endMessage("ERROR", errorString(101));
temp = new char[ strlen(QS) + 1 ];
strcpy( temp, QS );
}
else if ( strcmp(m_method, "POST") == 0 )
{
//===========================================
// Get posting info from stdin
//===========================================
char *temp2;
const char* CL = CONTENT_LENGTH;
if ( CL == NULL )
endMessage( "ERROR", errorString(102));
UINT size = atoi( CL );
if ( size > 0 )
{
temp2 = new char[ size + 1 ];
cin.getline( temp2, size + 1 );
temp = temp2;
}
}
//process the CGI encoded string
//==============================
char* front = temp; //for memory release since temp becomes NULL
char* key = temp, * value;
while( key != NULL )
{
if ( (temp = strchr(temp, '=')) != NULL )
*(temp++) = '\0';
else
endMessage("ERROR", errorString(201));
value = temp;
if ( (temp = strchr( temp, '&' )) != NULL )
*(temp++) = '\0';
addKey( parseHex( key ), parseHex( value ) );
key = temp;
}
delete [] front;
}
void
CGIparse::endMessage( const char* title, const char* message )
{
//non-browser messages
if ( title == NULL )
{
cerr << message << "\n\n";
exit(0);
}
//prints web error message and terminates application
//===================================================
printMime(); //send mime-type if not sent yet
cout
<< "<table border=\"1\" width=\"415\">\n"
<< " <tr bgcolor=\"000088\">\n"
<< " <td><font face=\"Arial\" size=\"2\" color=\"ffffff\">"
<< "<b>" << title << "</b></font></td>\n"
<< " </tr>\n"
<< " <tr>\n"
<< " <td>\n"
<< " <font face=Arial><i>" << message << "</i></font>\n"
<< " <hr noshade>\n"
<< " <font face=Arial size=1>CGIparse library by Michael Olivero"
<< " (<a href=\"mailto:mike95@mediaone.net\">mike95@mediaone.net</a>)</font>\n"
<< " </td>\n"
<< " </tr>\n"
<< "</table>" << endl;
exit( 0 );
}
const char*
CGIparse::parseHex( char* hexstr ) const
{
//======================
//Return an empty string
//======================
if ( hexstr == NULL || strlen( hexstr ) == 0 )
return "";
register UINT x,y;
for ( x = 0, y = 0; hexstr[y]; x++, y++ )
{
if( (hexstr[x] = hexstr[y]) == '+' )
{
hexstr[x] = ' ';
continue;
}
else if ( hexstr[x] == '%' )
{
hexstr[x] = convertHex(&hexstr[y+1]);
y+=2;
}
}
hexstr[x] = '\0';
return hexstr;
}
const UINT
CGIparse::convertHex( const char* what ) const
{
//0x4f == 01001111 mask
register char digit;
digit = (what[0] >= 'A' ? ((what[0] & 0x4F) - 'A')+10 : (what[0] - '0'));
digit *= 16;
digit += (what[1] >='A' ? ((what[1] & 0x4F) - 'A')+10 : (what[1] - '0'));
return digit;
}
CGIparse::~CGIparse()
{
node* itr = NULL;
while( m_head )
{
itr = m_head;
m_head = m_head->link;
delete itr;
}
delete [] m_method;
}
void
CGIparse::addKey( const char* aKey, const char* aValue )
{
if ( m_tail != NULL )
m_tail = m_tail->link = new node( aKey, aValue );
else
m_head = m_tail = new node( aKey, aValue );
m_size++;
}
void
CGIparse::replaceKey( const char* aKey, const char* aValue )
{
node* itr = m_head;
while( itr != NULL )
{
if ( strcmp( itr->key, aKey ) == 0 )
{
const UINT length = strlen( aValue );
if ( length > strlen(itr->value) )
{
delete [] itr->value;
itr->value = new char[ length + 1 ];
}
strcpy( itr->value, aValue );
break;
}
itr = itr->link;
}
}
void
CGIparse::removeKey( const char* aKey )
{
node* itr = m_head;
//check for null pointer
if ( itr == NULL )
return;
//first check the head
if ( strcmp( itr->key, aKey ) == 0 )
{
m_head = itr->link;
if ( m_head == NULL )
m_tail = NULL;
delete itr;
m_size--;
return;
}
//loop through all the other values
//=================================
while( itr->link != NULL )
{
if ( strcmp( itr->link->key, aKey ) == 0 )
{
node* toDelete = itr->link; //for deletion
itr->link = itr->link->link;
if ( itr->link == NULL )
m_tail = itr;
delete toDelete;
m_size--;
break;
}
itr = itr->link;
}
}
//properly formats a neat HTML table of key/value pairs stored in the object
//==========================================================================
void
CGIparse::formDump()
{
printMime();
const node* itr = m_head;
if ( itr != NULL )
{
cout << "<table border=1 width=100%>\n"
<< " <tr valign=top>\n"
<< " <th bgcolor=000000 colspan=2><font color=ffffff>Method: <i>"
<< m_method << "</i> " << "Browser: <i>" << HTTP_USER_AGENT << "</i></font></th>"
<< " </tr>\n"
<< " <tr valign=top>\n"
<< " <th bgcolor=ff0000><b>Keys</b></th><th bgcolor=ff0000><b>Values</b></th>\n"
<< " </tr>\n";
while( itr != NULL )
{
cout << " <tr valign=top>\n"
<< " <td bgcolor=00aaff>" << itr->key << "</td>\n"
<< " <td>" << itr->value << "</td>\n"
<< " </tr>" << endl;
itr = itr->link;
}
cout << "</table>" << endl;
}
}
const char*
CGIparse::valueOf( const char* aKey )
{
node* itr = m_head;
while( itr != NULL )
{
if ( strcmp( itr->key, aKey ) == 0 )
{
m_marker = itr;
return itr->value;
}
itr = itr->link;
}
m_marker = NULL;
return NULL;
}
const char*
CGIparse::getNextValue( )
{
//getNextValue() must be called after a valueOf() function call.
//This provides support for mutilple values for a single key as
//in multiple selection boxes
//=============================================================
if ( m_marker != NULL )
{
const char* curKey = m_marker->key;
const node* nextLink = m_marker->getLink();
if ( nextLink != NULL )
{
if ( strcmp(nextLink->key, curKey) == 0 )
{
m_marker = m_marker->getLink();
return m_marker->value;
}
else
m_marker = NULL;
}
else
m_marker = NULL;
}
return NULL;
}
//check if a particualar key exists
//=================================
bool
CGIparse::defined( const char* aKey ) const
{
const node* itr = m_head;
while( itr != NULL )
{
if ( strcmp( itr->key, aKey ) == 0 )
return true;
itr = itr->link;
}
return false;
}
void
CGIparse::envDump( )
{
const char* user_agent = HTTP_USER_AGENT;
if ( user_agent != NULL )
{
printMime();
cout
<< "<table border=\"1\" width=\"100%\">\n"
<< " <tr valign=\"top\">\n"
<< " <th bgcolor=\"000000\" colspan=\"2\">"
<< "<font color=\"ffffff\">CGI Enviroment Variable Dump</font></th>\n"
<< " </tr>\n"
<< " <tr valign=\"top\">\n"
<< " <th bgcolor=\"ff0000\"><b>Variable<b></th>"
<< "<th bgcolor=\"ff0000\"><b>Value</b></th>\n"
<< " </tr>\n" << endl;
}
else
{
cout << setw(25) << ios::left << "Environment Variable"
<< setw(55) << "Value\n"
<< setw(25) << "===================="
<< setw(55) << "====================" << endl;
}
#ifdef _WIN32
//Environment traversal for Windows95/NT
//======================================
char** search = _environ;
char* temp = NULL;
UINT cur_length, max_length = 0;
while( *search )
{
cur_length = strlen( *search );
if ( cur_length > max_length )
{
max_length = cur_length;
delete [] temp;
temp = new char[ cur_length + 1 ];
}
strcpy( temp, *search );
*strrchr( temp, '=' ) = '\0';
if ( user_agent != NULL )
cout << " <tr><td bgcolor=\"00aaff\"><b>" << temp
<< "</b></td><td>" << (temp + strlen(temp) + 1) << "</td></tr>\n";
else
printf("%-40s%-40s\n", temp, temp + strlen(temp) + 1);
search++;
}
delete [] temp;
#else
//Standard ENV vars returned for others
//=====================================
char* temp[] = { "AUTH_TYPE", "GATEWAY_INTERFACE", "LOGON_USER",
"REQUEST_METHOD", "QUERY_STRING", "CONTENT_LENGTH",
"CONTENT_TYPE", "DOCUMENT", "DOCUMENT_URI",
"DOCUMENT_ROOT", "HTTP_ACCEPT", "HTTP_ACCEPT_LANGUAGE",
"HTTP_CONNECTION", "HTTP_HOST", "HTTP_REFERER",
"HTTP_USER_AGENT", "HTTP_COOKIE", "REMOTE_ADDR",
"REMOTE_HOST", "REMOTE_USER", "REMOTE_IDENT",
"SCRIPT_FILENAME", "SCRIPT_NAME", "SERVER_ADMIN",
"SERVER_PORT", "SERVER_PROTOCOL", "SERVER_SOFTWARE",
"SERVER_NAME", "PATH", "PATH_INFO",
"PATH_TRANSLATED" };
const UINT size = sizeof(temp) / sizeof(char*);
for( UINT i = 0; i < size; i++ )
{
const char* value = getenv(temp[i]);
if ( value != NULL )
{
if ( user_agent != NULL )
cout << " <tr><td bgcolor=\"00aaff\"><b>" << temp[i]
<< "</b></td><td>" << value << "</td></tr>" << endl;
else
printf("%-40s%-40s\n", temp[i], value);
}
}
#endif
if ( user_agent != NULL )
cout << "</table>" << endl;
}
//sends mime type to client, default mime type is "text/html"
//to terminate the mime heading for the client, either one of
//of the following forms of printMime must be called:
// printMime();
// printMime( "text/html" ); //same as previous
// printMime( "other mime", true ); //true signals mime is complete
//=====================================================================
void CGIparse::printMime( const char* mime, bool isLast )
{
if ( !mime_sent )
{
cout << "Content-type: " << mime << endl;
if ( isLast || strcmp(mime, "text/html") == 0 )
{
cout << endl; //terminate mime header
mime_sent = true;
}
}
}
//custom error messages for CGIparse class
//========================================
const char*
CGIparse::errorString( const UINT number ) const
{
switch( number )
{
case 100:
return "QUERY_STRING is formated incorrectly";
case 101:
return "QUERY_STRING enviornment is 'NULL'";
case 102:
return "CONTENT_LENGTH enviornment is 'NULL'";
case 103:
return "REQUEST_METHOD enviornment is 'NULL'";
case 201:
return "Value string is missing in a [key=value] pair";
case 300:
return "Must be executed by a browser with a QUERY or FORM";
default:
return "No Message Specified";
}
}
|
|
|