Main Page   Namespace List   Class Hierarchy   Compound List   File List   Namespace Members   Compound Members  

config_processor.cc

00001 /*
00002 *  Name:      config_processor.cc
00003 *  Author:    Rafael Jesus Alcantara Perez
00004 *  Summary:   CGI config processor
00005 *  Date:      $Date: 2003/04/14 00:18:35 $
00006 *  Revision:  $Revision: 1.1 $
00007 *
00008 *  Copyright (C) 1994-2002  Rafael Jesus Alcantara Perez <rafa@dedalo-ing.com>
00009 *
00010 *  This program is free software; you can redistribute it and/or modify
00011 *  it under the terms of the GNU General Public License as published by
00012 *  the Free Software Foundation; either version 2 of the License, or
00013 *  (at your option) any later version.
00014 *
00015 *  This program is distributed in the hope that it will be useful,
00016 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 *  GNU General Public License for more details.
00019 *
00020 *  You should have received a copy of the GNU General Public License
00021 *  along with this program; if not, write to the Free Software
00022 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
00023 *  MA 02111-1307, USA.
00024 */
00025 
00026 #include <cstdlib>
00027 #include <fstream>
00028 #include <sstream>
00029 #include <mpcl/net/cgi/config_processor.hh>
00030 #include <mpcl/net/cgi/exceptions.hh>
00031 #include <mpcl/net/url_decoder.hh>
00032 #include <mpcl/text/regex/matcher.hh>
00033 
00034 
00035 //
00036 //  C O N S T R U C T O R S
00037 //
00038 
00039 mpcl::net::cgi::TConfigProcessor::
00040 TConfigProcessor ( int          iPARAMETER_COUNT ,
00041                    const char** ppkcPARAMETERS   )                 :
00042   util::prefs::TConfigProcessor (iPARAMETER_COUNT, ppkcPARAMETERS) ,
00043   gHasInput                     (false)
00044 {
00045 
00046   addEnvironmentVariable ("AUTH_TYPE");
00047   addEnvironmentVariable ("CONTENT_LENGTH");
00048   addEnvironmentVariable ("CONTENT_TYPE");
00049   addEnvironmentVariable ("GATEWAY_INTERFACE");
00050   addEnvironmentVariable ("HTTP_COOKIE");
00051   addEnvironmentVariable ("HTTP_USER_AGENT");
00052   addEnvironmentVariable ("PATH_INFO");
00053   addEnvironmentVariable ("PATH_TRANSLATED");
00054   addEnvironmentVariable ("QUERY_STRING");
00055   addEnvironmentVariable ("REMOTE_ADDR");
00056   addEnvironmentVariable ("REMOTE_HOST");
00057   addEnvironmentVariable ("REMOTE_IDENT");
00058   addEnvironmentVariable ("REMOTE_USER");
00059   addEnvironmentVariable ("REQUEST_METHOD");
00060   addEnvironmentVariable ("SCRIPT_NAME");
00061   addEnvironmentVariable ("SERVER_NAME");
00062   addEnvironmentVariable ("SERVER_PORT");
00063   addEnvironmentVariable ("SERVER_PROTOCOL");
00064   addEnvironmentVariable ("SERVER_SOFTWARE");
00065 
00066 }  // TConfigProcessor()
00067 
00068 
00069 void mpcl::net::cgi::TConfigProcessor::processOptions (void)
00070 {
00071 
00072   using std::cin;
00073   using std::strtoul;
00074 
00075   if ( !gOptionsProcessed )
00076   {
00077     //
00078     //  Due to problems with standard input (random access),
00079     //  it musts read the entire input in a variable, and then
00080     //  parses it (yQuery).
00081     //
00082     TString   yQuery;
00083 
00084     //
00085     //  Process options from configuration file (if any).
00086     //
00087     processConfigFile();
00088 
00089     //
00090     //  If REQUEST_METHOD is "POST" then get input form data
00091     //  from standard input, else get input from QUERY_STRING.
00092     //
00093     if ( ( environmentValue ("REQUEST_METHOD") == "GET"  ) ||
00094          ( environmentValue ("REQUEST_METHOD") == "HEAD" )  )
00095     {
00096       //
00097       //  REQUEST_METHOD is GET or HEAD.
00098       //
00099       yQuery = environmentValue ("QUERY_STRING");
00100     }
00101     else if ( environmentValue ("REQUEST_METHOD") == "POST" )
00102     {
00103       //
00104       //  REQUEST_METHOD is POST.
00105       //  The  environment variable  CONTENT_LENGTH  contains the length of the
00106       //  string to be read from standard input.
00107       //
00108 
00109       long unsigned int   luiContentLength;
00110       char*               pcBuffer;
00111       
00112       luiContentLength = strtoul (environmentValue ("CONTENT_LENGTH").c_str(), NULL, 10);
00113       pcBuffer         = new char [luiContentLength + 1];
00114       cin.read (pcBuffer, luiContentLength);
00115       pcBuffer [luiContentLength] = '\0';
00116       yQuery                      = pcBuffer;
00117       delete [] pcBuffer;
00118     }
00119     else
00120     {
00121       throw TBadFormException ("not supported REQUEST_METHOD", __FILE__, __LINE__);
00122     }
00123 
00124     //
00125     //  Loads form data encoded using 'application/x-www-form-urlencoded' media
00126     //  type.
00127     //
00128     {
00129       std::basic_istringstream<char>   tQueryIstringstream (yQuery);
00130 
00131       readFormData (tQueryIstringstream);
00132       gOptionsProcessed = true;
00133     }
00134   }
00135 
00136 }  // processOptions()
00137 
00138 
00139 void mpcl::net::cgi::TConfigProcessor::processCommandLine (void)
00140 {
00141 
00142   for (register int J = 1; ( J < iParametersCount ) ;++J)
00143   {
00144     updateOptionWithName (ppkcParametersList [J], "");
00145   }
00146 
00147 }  // processCommandLine()
00148 
00149 
00150 void mpcl::net::cgi::TConfigProcessor::
00151 readFormData (std::basic_istream<char_type, traits_type>& rtSOURCE_ISTREAM)
00152 {
00153 
00154   using text::html::kcIdentifierValueSeparator;
00155   using text::regex::TMatcher;
00156 
00157   TString    yName;
00158   TString    yValue;
00159   TMatcher   tMatcher (rtSOURCE_ISTREAM);
00160   bool       gSuccess = true;
00161 
00162   //
00163   //  CGI form submission message body format:
00164   //
00165   //    [{<name_1>=[<value_1>]&}<name_n>=[<value_n>]]
00166   //
00167   //  <value> can be formed by spaces (that are changed by '+' spaces),
00168   //  other characters can be escaped by %NN construction, that means
00169   //  the character with ASCII value 0xNN.
00170   //
00171 
00172   while ( gSuccess )
00173   {
00174     gSuccess = ( tMatcher.scan ("%t=%t&", &yName, &yValue, NULL) > 0 );
00175     if ( !gSuccess )
00176     {
00177       gSuccess = ( tMatcher.scan ("%t=%t", &yName, &yValue, NULL) > 0 );
00178     }
00179     if ( gSuccess )
00180     {
00181       TString::size_type   zSeparatorOffset = 0;
00182       TString::size_type   zPointOffset     = 0;
00183 
00184       yName  = TUrlDecoder::_decode (yName.c_str());
00185       yValue = TUrlDecoder::_decode (yValue.c_str());
00186       if ( TString::npos != (zSeparatorOffset = yName.find (kcIdentifierValueSeparator)) )
00187       {
00188         if ( TString::npos != (zPointOffset = yName.find ('.', zSeparatorOffset)) )
00189         {
00190           //
00191           //  Case:  <identifier>:<value>.x=<x position>
00192           //         <identifier>:<value>.y=<y position>
00193           //
00194           yValue = yName.substr (zSeparatorOffset + 1, zPointOffset - zSeparatorOffset - 1);
00195           yName  = yName.substr (0, zSeparatorOffset);
00196         }
00197         else
00198         {
00199           //
00200           //  Case:  <identifier>:<value>=<value>
00201           //
00202           yName = yName.substr (0, zSeparatorOffset);
00203         }
00204       } 
00205       updateFormOption (yName, yValue);
00206       gHasInput = true;
00207     }
00208   }
00209 
00210 }  // read()
00211 
00212 
00213 mpcl::util::prefs::TOption& mpcl::net::cgi::TConfigProcessor::
00214 updateFormOption (const TString& rkyNAME, const TString& rkyVALUE)
00215 {
00216 
00217   bool                            gFound = false;
00218   TOptionVector::const_iterator   ktEnd  = tFormOptionVector.end();
00219   TOptionVector::iterator         I      = tFormOptionVector.begin();
00220 
00221   if ( !rkyNAME.empty() )
00222   {
00223     for (; ( I != ktEnd ) ;++I)
00224     {
00225       if ( I->name() == rkyNAME )
00226       {
00227         if ( !I->hasValue (rkyVALUE) )
00228         {
00229           I->addValue (rkyVALUE);
00230         }
00231         gFound = true;
00232         break;
00233       }
00234     }
00235   }
00236   if ( !gFound )
00237   {
00238     TOption   tNewOption (rkyNAME, "", "");
00239 
00240     //
00241     //  If there is no such option, it adds a new one,
00242     //  and adds to the new option, the first value.
00243     //
00244     tNewOption.addValue (rkyVALUE);
00245     tFormOptionVector.push_back (tNewOption);
00246     I = tFormOptionVector.end() - 1;
00247   }
00248   return *I;
00249 
00250 }  // updateFormOption()
00251 
00252 
00253 mpcl::util::prefs::TOption& mpcl::net::cgi::TConfigProcessor::
00254 updateOptionWithName ( const TString& rkyNAME  ,
00255                        const TString& rkyVALUE )
00256 {
00257 
00258   bool                            gFound = false;
00259   TOptionVector::const_iterator   ktEnd  = tOptionVector.end();
00260   TOptionVector::iterator         I      = tOptionVector.begin();
00261 
00262   if ( !rkyNAME.empty() )
00263   {
00264     for (; ( I != ktEnd ) ;++I)
00265     {
00266       if ( I->name() == rkyNAME )
00267       {
00268         if ( !I->hasValue (rkyVALUE) )
00269         {
00270           I->addValue (rkyVALUE);
00271         }
00272         gFound = true;
00273         break;
00274       }
00275     }
00276   }
00277   if ( !gFound )
00278   {
00279     TOption   tNewOption (rkyNAME, "", "");
00280 
00281     //
00282     //  If there is no such option, it adds a new one,
00283     //  and adds to the new option, the first value.
00284     //
00285     tNewOption.addValue (rkyVALUE);
00286     tOptionVector.push_back (tNewOption);
00287     I = tOptionVector.end() - 1;
00288   }
00289   return *I;
00290 
00291 }  // updateOption()
00292 
00293 
00294 //
00295 //  S E L E C T O R S
00296 //
00297 
00298 const mpcl::text::TString& mpcl::net::cgi::TConfigProcessor::
00299 getFormValue (const char* pkcNAME) const
00300 {
00301 
00302   using mpcl::text::Format;
00303   using mpcl::text::TString;
00304   using std::vector;
00305 
00306   TOptionVector::iterator         I     = tFormOptionVector.begin();
00307   TOptionVector::const_iterator   ktEnd = tFormOptionVector.end();
00308   
00309   for (; ( I != ktEnd ) ;++I)
00310   {
00311     if ( I->name() == pkcNAME )
00312     {
00313       break;
00314     } 
00315   }
00316   if ( I == ktEnd )
00317   {
00318     TString   yMessage;
00319     
00320     yMessage = Format ("form option '%s' not found", pkcNAME);
00321     throw TVariableNotFoundException (yMessage, __FILE__, __LINE__);
00322   }
00323   return I->getValue();
00324 
00325 }  // getFormValue()
00326 
00327 
00328 bool mpcl::net::cgi::TConfigProcessor::
00329 hasFormOption (const TString& rkyNAME) const
00330 {
00331 
00332   bool                            gSuccess = false;
00333   TOptionVector::const_iterator   ktEnd    = tFormOptionVector.end();
00334   TOptionVector::iterator         I        = tFormOptionVector.begin();
00335   
00336   for (; ( I != ktEnd ) ;++I)
00337   {
00338     if ( I->name() == rkyNAME )
00339     {
00340       gSuccess = true;
00341       break;
00342     }
00343   }
00344   return gSuccess;
00345 
00346 }  // hasFormOption()
00347 
00348 
00349 bool mpcl::net::cgi::TConfigProcessor::
00350 hasOption (const TString& rkyNAME) const
00351 {
00352 
00353   bool                            gSuccess = false;
00354   TOptionVector::const_iterator   ktEnd    = tOptionVector.end();
00355   TOptionVector::iterator         I        = tOptionVector.begin();
00356   
00357   for (; ( I != ktEnd ) ;++I)
00358   {
00359     if ( I->name() == rkyNAME )
00360     {
00361       gSuccess = true;
00362       break;
00363     }
00364   }
00365   return gSuccess;
00366 
00367 }  // hasOption()
00368 
00369 
00370 void mpcl::net::cgi::TConfigProcessor::
00371 updateForm (text::html::TForm& rtTARGET_FORM) const
00372 {
00373 
00374   TOptionVector::const_iterator   ktEnd = tFormOptionVector.end();
00375   TOptionVector::iterator         I     = tFormOptionVector.begin();
00376 
00377   rtTARGET_FORM.reset();
00378   for (; ( I != ktEnd ) ;++I)
00379   {
00380     rtTARGET_FORM.setValues (I->name(), I->getValues());
00381   }
00382 
00383 }  // updateForm()

Generated on Mon Oct 13 02:35:22 2003 for MPCL by doxygen1.2.18