Logo
~Sockets~
~Examples~
~Contact~


HttpdForm Class Reference
[Webserver framework]

Parse/store a http query_string/form-data body. More...

#include <HttpdForm.h>

List of all members.


Public Member Functions

 HttpdForm (IFile *, const std::string &content_type, size_t content_length)
 Default constructor (used in POST operations).
 HttpdForm (const std::string &query_string, size_t length)
 Another constructor (used in GET operations).
 ~HttpdForm ()
void EnableRaw (bool)
void strcpyval (std::string &, const char *) const
 Encode characters '<' '>' '&' as < > &.
bool getfirst (std::string &n) const
bool getnext (std::string &n) const
bool getfirst (std::string &n, std::string &v) const
bool getnext (std::string &n, std::string &v) const
int getvalue (const std::string &, std::string &) const
std::string getvalue (const std::string &) const
size_t getlength (const std::string &) const
cgi_vgetbase ()
const std::string & GetBoundary () const

Private Types

typedef std::list< CGI * > cgi_v
 list of key/value pairs.

Private Member Functions

 HttpdForm (const HttpdForm &)
HttpdFormoperator= (const HttpdForm &)

Private Attributes

cgi_v m_cgi
cgi_v::const_iterator m_current
std::string m_strBoundary
bool raw

Classes

struct  CGI
 Store the name/value pairs from a GET/POST operation. More...

Detailed Description

Parse/store a http query_string/form-data body.

Definition at line 48 of file HttpdForm.h.


Member Typedef Documentation

typedef std::list<CGI *> HttpdForm::cgi_v [private]

list of key/value pairs.

Definition at line 64 of file HttpdForm.h.


Constructor & Destructor Documentation

HttpdForm::HttpdForm ( IFile infil,
const std::string &  content_type,
size_t  content_length 
)

Default constructor (used in POST operations).

Input is read from stdin. Number of characters to read can be found in the environment variable CONTENT_LENGTH.

Definition at line 52 of file HttpdForm.cpp.

References DEB, Parse::EnableQuote(), Parse::getrest(), Parse::getword(), m_cgi, m_current, m_strBoundary, and TMPSIZE.

00052                                                                                        : raw(false)
00053 {
00054 DEB(    Debug deb("HttpdForm");)
00055         CGI *cgi = NULL;
00056         size_t extra = 2;
00057 
00058         m_current = m_cgi.end();
00059 DEB(    deb << "Content-Type: " << content_type << Debug::endl();)
00060 
00061         if (content_type.size() >= 19 && content_type.substr(0, 19) == "multipart/form-data")
00062         {
00063                 Parse pa(content_type,";=");
00064                 char *tempcmp = NULL;
00065                 size_t tc = 0;
00066                 size_t l = 0;
00067                 std::string str = pa.getword();
00068                 m_strBoundary = "";
00069                 while (!str.empty())
00070                 {
00071                         if (!strcmp(str.c_str(),"boundary"))
00072                         {
00073                                 m_strBoundary = pa.getword();
00074                                 l = m_strBoundary.size();
00075                                 tempcmp = new char[l + extra];
00076                         }
00077                         //
00078                         str = pa.getword();
00079                 }
00080                 if (!m_strBoundary.empty())
00081                 {
00082 DEB(                    Debug deb("HttpdForm; parsing, boundary = " + m_strBoundary);)
00083                         std::string content_type;
00084                         std::string current_name;
00085                         std::string current_filename;
00086                         char *slask = new char[TMPSIZE];
00087                         infil -> fgets(slask, TMPSIZE);
00088                         while (!infil -> eof())
00089                         {
00090                                 while (strlen(slask) && (slask[strlen(slask) - 1] == 13 || slask[strlen(slask) - 1] == 10))
00091                                 {
00092                                         slask[strlen(slask) - 1] = 0;
00093                                 }
00094                                 content_type = "";
00095                                 current_name = "";
00096                                 current_filename = "";
00097                                 if ((strstr(slask,m_strBoundary.c_str()) || strstr(m_strBoundary.c_str(),slask)) && strcmp(slask, m_strBoundary.c_str()))
00098                                 {
00099                                         m_strBoundary = slask;
00100                                         l = m_strBoundary.size();
00101                                         delete[] tempcmp;
00102                                         tempcmp = new char[l + extra];
00103                                 }
00104                                 if (!strcmp(slask, m_strBoundary.c_str()))
00105                                 {
00106                                         // Get headers until empty line
00107                                         infil -> fgets(slask, TMPSIZE);
00108                                         while (strlen(slask) && (slask[strlen(slask) - 1] == 13 || slask[strlen(slask) - 1] == 10))
00109                                         {
00110                                                 slask[strlen(slask) - 1] = 0;
00111                                         }
00112 DEB(                                    deb << "Parsing header, line = " << slask << Debug::endl();)
00113                                         while (!infil -> eof() && *slask)
00114                                         {
00115                                                 Parse pa(slask,":");
00116                                                 std::string h = pa.getword();
00117                                                 std::string h2 = pa.getrest();
00118 DEB(                                            deb << "KEY:" << h << "  REST:" << h2 << Debug::endl();)
00119                                                 if (!strcasecmp(h.c_str(),"Content-type"))
00120                                                 {
00121                                                         Parse pa(h2, ";");
00122                                                         content_type = pa.getword();
00123 DEB(                                                    deb << "Found Content-Type: " << content_type << Debug::endl();)
00124                                                 }
00125                                                 else
00126                                                 if (!strcasecmp(h.c_str(),"Content-Disposition"))
00127                                                 {
00128                                                         Parse pa(h2, ";");
00129                                                         h = pa.getword();
00130                                                         if (!strcmp(h.c_str(),"form-data"))
00131                                                         {
00132 DEB(                                                            deb << "Found Content-Disposition: form-data, parsing" << Debug::endl();)
00133                                                                 pa.EnableQuote(true);
00134                                                                 h = pa.getword();
00135                                                                 while (!h.empty())
00136                                                                 {
00137                                                                         Parse pa2(h,"=");
00138                                                                         std::string name = pa2.getword();
00139                                                                         h = pa2.getrest();
00140                                                                         if (!strcmp(name.c_str(),"name"))
00141                                                                         {
00142                                                                                 if (!h.empty() && h[0] == '"')
00143                                                                                 {
00144                                                                                         current_name = h.substr(1, h.size() - 2);
00145                                                                                 }
00146                                                                                 else
00147                                                                                 {
00148                                                                                         current_name = h;
00149                                                                                 }
00150 DEB(                                                                            deb << "  Found name = " << current_name << Debug::endl();)
00151                                                                         }
00152                                                                         else
00153                                                                         if (!strcmp(name.c_str(),"filename"))
00154                                                                         {
00155                                                                                 if (!h.empty() && h[0] == '"')
00156                                                                                 {
00157                                                                                         current_filename = h.substr(1, h.size() - 2);
00158                                                                                 }
00159                                                                                 else
00160                                                                                 {
00161                                                                                         current_filename = h;
00162                                                                                 }
00163                                                                                 size_t x = 0;
00164                                                                                 for (size_t i = 0; i < current_filename.size(); i++)
00165                                                                                 {
00166                                                                                         if (current_filename[i] == '/' || current_filename[i] == '\\')
00167                                                                                                 x = i + 1;
00168                                                                                 }
00169                                                                                 if (x)
00170                                                                                 {
00171                                                                                         current_filename = current_filename.substr(x);
00172                                                                                 }
00173 DEB(                                                                            deb << "  Found filename = " << current_filename << Debug::endl();)
00174                                                                         }
00175                                                                         h = pa.getword();
00176                                                                 }
00177                                                         }
00178                                                 }
00179                                                 // get next header value
00180                                                 infil -> fgets(slask, TMPSIZE);
00181                                                 while (strlen(slask) && (slask[strlen(slask) - 1] == 13 || slask[strlen(slask) - 1] == 10))
00182                                                 {
00183                                                         slask[strlen(slask) - 1] = 0;
00184                                                 }
00185                                         }
00186                                         // Read content, save...?
00187                                         if (current_filename.empty()) // not a file
00188                                         {
00189                                                 std::string val;
00190                                                 infil -> fgets(slask, TMPSIZE);
00191                                                 while (!infil -> eof() && strncmp(slask,m_strBoundary.c_str(),m_strBoundary.size() ))
00192                                                 {
00193                                                         val += slask;
00194                                                         infil -> fgets(slask, TMPSIZE);
00195                                                 }
00196                                                 // remove trailing cr/linefeed
00197                                                 while (!val.empty() && (val[val.size() - 1] == 13 || val[val.size() - 1] == 10))
00198                                                 {
00199                                                         val = val.substr(0,val.size() - 1);
00200                                                 }
00201                                                 cgi = new CGI(current_name, val);
00202                                                 m_cgi.push_back(cgi);
00203 DEB(                                            deb << current_name << ": " << val << Debug::endl();)
00204                                         }
00205                                         else // current_filename.size() > 0
00206                                         {
00207                                                 // read until m_strBoundary...
00208                                                 FILE *fil;
00209                                                 int out = 0;
00210                                                 char c;
00211                                                 char fn[2000]; // where post'd file will be saved
00212 #ifdef _WIN32
00213                                                 {
00214                                                         char tmp_path[2000];
00215                                                         ::GetTempPathA(2000, tmp_path);
00216                                                         if (tmp_path[strlen(tmp_path) - 1] != '\\')
00217                                                         {
00218                                                                 strcat(tmp_path, "\\");
00219                                                         }
00220                                                         sprintf(fn,"%s%s",tmp_path,current_filename.c_str());
00221                                                 }
00222 #else
00223                                                 sprintf(fn,"/tmp/%s",current_filename.c_str());
00224 #endif
00225                                                 if ((fil = fopen(fn, "wb")) != NULL)
00226                                                 {
00227                                                         infil -> fread(&c,1,1);
00228                                                         while (!infil -> eof())
00229                                                         {
00230                                                                 if (out)
00231                                                                 {
00232                                                                         fwrite(&tempcmp[tc],1,1,fil); // %! ??? should we write value of 'c' here?
00233                                                                 }
00234                                                                 tempcmp[tc] = c;
00235                                                                 tc++;
00236                                                                 if (tc >= l + extra)
00237                                                                 {
00238                                                                         tc = 0;
00239                                                                         out = 1;
00240                                                                 }
00241                                                                 if (tc)
00242                                                                 {
00243                                                                         if (!strncmp(tempcmp + tc + extra, m_strBoundary.c_str(), l - tc) &&
00244                                                                                         !strncmp(tempcmp, m_strBoundary.c_str() + l - tc, tc))
00245                                                                         {
00246                                                                                 break;
00247                                                                         }
00248                                                                 }
00249                                                                 else
00250                                                                 {
00251                                                                         if (!strncmp(tempcmp + extra, m_strBoundary.c_str(), l))
00252                                                                         {
00253                                                                                 break;
00254                                                                         }
00255                                                                 }
00256                                                                 infil -> fread(&c,1,1);
00257                                                         }
00258                                                         fclose(fil);
00259 
00260                                                         cgi = new CGI(current_name,fn,fn);
00261                                                         m_cgi.push_back(cgi);
00262                                                 
00263                                                         strcpy(slask, m_strBoundary.c_str());
00264                                                         infil -> fgets(slask + strlen(slask), TMPSIZE); // next line
00265                                                 }
00266                                                 else
00267                                                 {
00268                                                         // couldn't open file
00269                                                         break;
00270                                                 }
00271                                         }
00272                                 }
00273                                 else
00274                                 {
00275                                         // Probably '<m_strBoundary>--'
00276                                         break;
00277                                 }
00278                         } // while (!infil -> eof())
00279                         delete[] slask;
00280                 } // if (m_strBoundary)
00281                 if (tempcmp)
00282                 {
00283                         delete[] tempcmp;
00284                 }
00285         }
00286         else
00287         if (strstr(content_type.c_str(), "x-www-form-urlencoded"))
00288         {
00289                 bool got_name = false; // tnx to FatherNitwit
00290                 int cl = (int)content_length;
00291                 char c,chigh,clow;
00292                 std::string slask;
00293                 m_current = m_cgi.end();
00294                 std::string name;
00295 
00296                 infil -> fread(&c,1,1);
00297                 cl--;
00298                 while (cl >= 0 && !infil -> eof())
00299                 {
00300                         switch (c)
00301                         {
00302                                 case '=': /* end of name */
00303                                         name = slask;
00304                                         slask.resize(0);
00305                                         got_name = true;
00306                                         break;
00307                                 case '&': /* end of value */
00308                                         if (got_name)
00309                                         {
00310                                                 cgi = new CGI(name,slask);
00311                                                 got_name = false;
00312                                         }
00313                                         else
00314                                         {
00315                                                 cgi = new CGI(slask, "");
00316                                         }
00317                                         slask.resize(0);
00318                                         m_cgi.push_back(cgi);
00319                                         break;
00320                                 case '+': /* space */
00321                                         slask += " ";
00322                                         break;
00323                                 case '%': /* hex value */
00324                                         infil -> fread(&chigh,1,1);
00325                                         cl--;
00326                                         chigh -= 48 + (chigh > '9' ? 7 : 0) + (chigh >= 'a' ? 32 : 0);
00327                                         infil -> fread(&clow,1,1);
00328                                         cl--;
00329                                         clow -= 48 + (clow > '9' ? 7 : 0) + (clow >= 'a' ? 32 : 0);
00330                                         slask += (char)(chigh * 16 + clow);
00331                                         break;
00332                                 default: /* just another char */
00333                                         slask += c;
00334                                         break;
00335                         }
00336                         //
00337                         if (cl > 0)
00338                         {
00339                                 infil -> fread(&c,1,1);
00340                         }
00341                         cl--;
00342                 }
00343                 if (got_name)
00344                 {
00345                         cgi = new CGI(name,slask);
00346                 }
00347                 else
00348                 {
00349                         cgi = new CGI(slask, "");
00350                 }
00351                 m_cgi.push_back(cgi);
00352         }
00353 }

HttpdForm::HttpdForm ( const std::string &  query_string,
size_t  length 
)

Another constructor (used in GET operations).

Input is read from the environment variable QUERY_STRING.

Parameters:
query_string The httpd server provided QUERY_STRING
length Query string length.

Definition at line 358 of file HttpdForm.cpp.

References m_cgi, and m_current.

00358                                                      : raw(false)
00359 {
00360         CGI *cgi = NULL;
00361         std::string slask;
00362         std::string name;
00363         char c,chigh,clow;
00364         size_t ptr = 0;
00365         bool got_name = false;
00366 
00367         m_current = m_cgi.end();
00368 
00369         ptr = 0;
00370         while (ptr < l)
00371         {
00372                 c = buffer[ptr++];
00373                 switch (c)
00374                 {
00375                         case '=': /* end of name */
00376                                 name = slask;
00377                                 slask.resize(0);
00378                                 got_name = true;
00379                                 break;
00380                         case '&': /* end of value */
00381                                 if (got_name)
00382                                 {
00383                                         cgi = new CGI(name,slask);
00384                                         got_name = false;
00385                                 }
00386                                 else
00387                                 {
00388                                         cgi = new CGI(slask, "");
00389                                 }
00390                                 slask.resize(0);
00391                                 m_cgi.push_back(cgi);
00392                                 break;
00393                         case '+': /* space */
00394                                 slask += " ";
00395                                 break;
00396                         case '%': /* hex value */
00397                                 chigh = buffer[ptr++];
00398                                 chigh -= 48 + (chigh > '9' ? 7 : 0) + (chigh >= 'a' ? 32 : 0);
00399                                 clow = buffer[ptr++];
00400                                 clow -= 48 + (clow > '9' ? 7 : 0) + (clow >= 'a' ? 32 : 0);
00401                                 slask += (char)(chigh * 16 + clow);
00402                                 break;
00403                         default: /* just another char */
00404                                 slask += c;
00405                                 break;
00406                 }
00407         }
00408         if (got_name)
00409         {
00410                 cgi = new CGI(name,slask);
00411         }
00412         else
00413         {
00414                 cgi = new CGI(slask, "");
00415         }
00416         m_cgi.push_back(cgi);
00417 }

HttpdForm::~HttpdForm (  ) 

Definition at line 420 of file HttpdForm.cpp.

References m_cgi.

00421 {
00422         CGI *cgi = NULL; //,*tmp;
00423 
00424         for (cgi_v::iterator it = m_cgi.begin(); it != m_cgi.end(); it++)
00425         {
00426                 cgi = *it;
00427                 delete cgi;
00428         }
00429 }

HttpdForm::HttpdForm ( const HttpdForm  )  [inline, private]

Definition at line 104 of file HttpdForm.h.

00104 {}


Member Function Documentation

void HttpdForm::EnableRaw ( bool  b  ) 

Definition at line 432 of file HttpdForm.cpp.

References raw.

00433 {
00434         raw = b;
00435 }

void HttpdForm::strcpyval ( std::string &  v,
const char *  value 
) const

Encode characters '<' '>' '&' as < > &.

Definition at line 438 of file HttpdForm.cpp.

Referenced by getnext(), and getvalue().

00439 {
00440         v = "";
00441         for (size_t i = 0; i < strlen(value); i++)
00442         {
00443                 if (value[i] == '<')
00444                 {
00445                         v += "&lt;";
00446                 }
00447                 else
00448                 if (value[i] == '>')
00449                 {
00450                         v += "&gt;";
00451                 }
00452                 else
00453                 if (value[i] == '&')
00454                 {
00455                         v += "&amp;";
00456                 }
00457                 else
00458                 {
00459                         v += value[i];
00460                 }
00461         }
00462 }

bool HttpdForm::getfirst ( std::string &  n  )  const

Definition at line 465 of file HttpdForm.cpp.

References getnext(), m_cgi, and m_current.

00466 {
00467         m_current = m_cgi.begin();
00468         return getnext(n);
00469 }

bool HttpdForm::getnext ( std::string &  n  )  const

Definition at line 472 of file HttpdForm.cpp.

References m_cgi, and m_current.

Referenced by getfirst().

00473 {
00474         if (m_current != m_cgi.end() )
00475         {
00476                 CGI *current = *m_current;
00477                 n = current -> name;
00478                 m_current++;
00479                 return true;
00480         }
00481         else
00482         {
00483                 n = "";
00484         }
00485         return false;
00486 }

bool HttpdForm::getfirst ( std::string &  n,
std::string &  v 
) const

Definition at line 489 of file HttpdForm.cpp.

References getnext(), m_cgi, and m_current.

00490 {
00491         m_current = m_cgi.begin();
00492         return getnext(n,v);
00493 }

bool HttpdForm::getnext ( std::string &  n,
std::string &  v 
) const

Definition at line 496 of file HttpdForm.cpp.

References m_cgi, m_current, raw, and strcpyval().

00497 {
00498         if (m_current != m_cgi.end() )
00499         {
00500                 CGI *current = *m_current;
00501                 n = current -> name;
00502                 if (raw)
00503                 {
00504                         v = current -> value;
00505                 }
00506                 else
00507                 {
00508                         strcpyval(v,current -> value.c_str());
00509                 }
00510                 m_current++;
00511                 return true;
00512         }
00513         else
00514         {
00515                 n = "";
00516         }
00517         return false;
00518 }

int HttpdForm::getvalue ( const std::string &  n,
std::string &  v 
) const

Definition at line 521 of file HttpdForm.cpp.

References m_cgi, raw, and strcpyval().

00522 {
00523         CGI *cgi = NULL;
00524         int r = 0;
00525 
00526         for (cgi_v::const_iterator it = m_cgi.begin(); it != m_cgi.end(); it++)
00527         {
00528                 cgi = *it;
00529                 if (cgi -> name == n)
00530                         break;
00531                 cgi = NULL;
00532         }
00533         if (cgi)
00534         {
00535                 if (raw)
00536                 {
00537                         v = cgi -> value;
00538                 }
00539                 else
00540                 {
00541                         strcpyval(v,cgi -> value.c_str());
00542                 }
00543                 r++;
00544         }
00545         else
00546         {
00547                 v = "";
00548         }
00549 
00550         return r;
00551 }

std::string HttpdForm::getvalue ( const std::string &  n  )  const

Definition at line 554 of file HttpdForm.cpp.

References m_cgi.

00555 {
00556         for (cgi_v::const_iterator it = m_cgi.begin(); it != m_cgi.end(); it++)
00557         {
00558                 CGI *cgi = *it;
00559                 if (cgi -> name == n)
00560                 {
00561                         return cgi -> value;
00562                 }
00563         }
00564         return "";
00565 }

size_t HttpdForm::getlength ( const std::string &  n  )  const

Definition at line 568 of file HttpdForm.cpp.

References m_cgi, and raw.

00569 {
00570         CGI *cgi = NULL;
00571         size_t l;
00572 
00573         for (cgi_v::const_iterator it = m_cgi.begin(); it != m_cgi.end(); it++)
00574         {
00575                 cgi = *it;
00576                 if (cgi -> name == n)
00577                         break;
00578                 cgi = NULL;
00579         }
00580         l = cgi ? cgi -> value.size() : 0;
00581         if (cgi && !raw)
00582         {
00583                 for (size_t i = 0; i < cgi -> value.size(); i++)
00584                 {
00585                         switch (cgi -> value[i])
00586                         {
00587                         case '<': // &lt;
00588                         case '>': // &gt;
00589                                 l += 4;
00590                                 break;
00591                         case '&': // &amp;
00592                                 l += 5;
00593                                 break;
00594                         }
00595                 }
00596         }
00597         return l;
00598 }

HttpdForm::cgi_v & HttpdForm::getbase (  ) 

Definition at line 601 of file HttpdForm.cpp.

References m_cgi.

00602 {
00603         return m_cgi;
00604 }

const std::string & HttpdForm::GetBoundary (  )  const

Definition at line 607 of file HttpdForm.cpp.

References m_strBoundary.

00608 {
00609         return m_strBoundary;
00610 }

HttpdForm& HttpdForm::operator= ( const HttpdForm  )  [inline, private]

Definition at line 105 of file HttpdForm.h.

00105 { return *this; }


Member Data Documentation

Definition at line 106 of file HttpdForm.h.

Referenced by getbase(), getfirst(), getlength(), getnext(), getvalue(), HttpdForm(), and ~HttpdForm().

cgi_v::const_iterator HttpdForm::m_current [mutable, private]

Definition at line 107 of file HttpdForm.h.

Referenced by getfirst(), getnext(), and HttpdForm().

std::string HttpdForm::m_strBoundary [private]

Definition at line 108 of file HttpdForm.h.

Referenced by GetBoundary(), and HttpdForm().

bool HttpdForm::raw [private]

Definition at line 109 of file HttpdForm.h.

Referenced by EnableRaw(), getlength(), getnext(), and getvalue().


The documentation for this class was generated from the following files:
Page, code, and content Copyright (C) 2007 by Anders Hedström
Generated for C++ Sockets by  doxygen 1.4.4