#include "cgi.h"
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <ctime>
#include <stdexcept>
#include <algorithm>
using namespace std;
#include "HTMLstream.h"
string get_cgi_string (const string & allowed_method)
{
string method = request_method ();
if (allowed_method == any || method == allowed_method)
{
if (method == get)
{
return getenv ("QUERY_STRING");
}
else if (method == post)
{
string query;
getline (cin, query);
return query;
}
else
{
throw runtime_error
("Unable to handle request method `" +
method + "'");
}
}
else
{
throw runtime_error ("Method " + method + " not allowed");
}
}
string request_method ()
{
const char * method = getenv ("REQUEST_METHOD");
if (method != NULL)
{
return method;
}
else
{
return "";
}
}
string content_length ()
{
const char * len = getenv ("CONTENT_LENGTH");
if (len != NULL)
{
return len;
}
else
{
return "";
}
}
const string & decode_cgi_string (string & s)
{
for (int i = 0; i < s.length(); i++)
{
if (s[i] == '+') s[i] = ' ';
if (s.substr (i, 6) == "%0D%0A")
{
s.replace (i, 6, "\n");
}
else if (s[i] == '%')
{
string hex_code = s.substr (i+1,2);
int code;
sscanf (hex_code.c_str(), "%X", &code);
// Don't process the CR character
// (replace it by a newline)
if (code == '\r')
{
code = '\n';
}
string str_code = "";
str_code += static_cast<char>(code);
s.replace (i, 3, str_code);
}
}
return s;
}
string encode_cgi_string (const string & s)
{
string result = "";
for (int i = 0; i < s.length(); i++)
{
switch (s[i])
{
case ' ':
result += '+';
break;
case '\n':
case '\r':
result += "%0D";
break;
default:
if (isalnum (s[i]))
{
result += s[i];
}
else // special character -- replace with %
{ // followed by the ASCII value in HEX
char hex_code[20];
sprintf (hex_code, "%%%02X", s[i]);
result += hex_code;
}
break;
}
}
return result;
}
map<string, string> cgi_parameters (const string & allowed_method)
{
string cgi_string = get_cgi_string (allowed_method);
vector<string> cgi_tokens = tokens (cgi_string, "&");
map<string, string> result;
for (int i = 0; i < cgi_tokens.size(); i++)
{
vector<string> cgi_parameter = tokens (cgi_tokens[i], "=");
for_each (cgi_parameter.begin(), cgi_parameter.end(),
decode_cgi_string);
switch (cgi_parameter.size())
{
case 2:
result[cgi_parameter[0]] = cgi_parameter[1];
break;
case 1:
result[cgi_parameter[0]] = "";
break;
default:
throw invalid_argument
("Incorrect CGI parameter: `" +
cgi_tokens[i] + "'");
}
}
return result;
}
vector<string>
tokens (const string & s, const string & separators)
{
vector<string> result;
int pos_start, pos_end;
pos_start = s.find_first_not_of (separators);
if (pos_start == string::npos)
{
return result;
}
pos_end = s.find_first_of (separators, pos_start);
if (pos_end == string::npos)
{
result.push_back (s);
return result;
}
result.push_back (s.substr (pos_start, pos_end - pos_start));
while ((pos_start =
s.find_first_not_of (separators, pos_end)) !=
string::npos)
{
pos_end = s.find_first_of (separators, pos_start);
if (pos_end == string::npos)
{
result.push_back (s.substr (pos_start));
return result;
}
result.push_back
(s.substr (pos_start, pos_end - pos_start));
}
return result;
}
void send_error_page (const string & error_message)
{
HTMLstream error_page;
error_page << "The application reported a critical error "
<< "with message: <br><b>"
<< error_message << ".</b><p>"
<< "Please take note of the above message and "
<< "contact this site's administrator.\n";
error_page.send();
}
string lcase (const string & s)
{
string result = s;
transform (result.begin(), result.end(),
result.begin(), tolower);
return result;
}
string removed_separators (const string & s)
{
string result;
for (string::const_iterator i = s.begin(); i != s.end(); ++i)
{
if (!isspace(*i))
{
result += *i;
}
}
return result;
}