CgiEnvironment.cpp

00001 /* -*-mode:c++; c-file-style: "gnu";-*- */
00002 /*
00003  *  $Id: CgiEnvironment_8cpp-source.html,v 1.1 2007/07/03 21:34:46 sebdiaz Exp $
00004  *
00005  *  Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
00006  *                       2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
00007  *  Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
00008  *
00009  *  This library is free software; you can redistribute it and/or
00010  *  modify it under the terms of the GNU Lesser General Public
00011  *  License as published by the Free Software Foundation; either
00012  *  version 3 of the License, or (at your option) any later version.
00013  *
00014  *  This library is distributed in the hope that it will be useful,
00015  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  *  Lesser General Public License for more details.
00018  *
00019  *  You should have received a copy of the GNU Lesser General Public
00020  *  License along with this library; if not, write to the Free Software
00021  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
00022  *
00023  */
00024 
00025 #ifdef __GNUG__
00026 #  pragma implementation
00027 #endif
00028 
00029 #include <new>
00030 #include <memory>
00031 #include <stdexcept>
00032 #include <cstdlib>
00033 #include <cctype>
00034 
00035 #ifdef WIN32
00036 #  include <io.h>
00037 #  include <fcntl.h>
00038 #  include <stdio.h>
00039 #endif
00040 
00041 #include "cgicc/CgiEnvironment.h"
00042 
00043 // ========== Constructor/Destructor
00044 
00045 cgicc::CgiEnvironment::CgiEnvironment(CgiInput *input)
00046 {
00047   // Create a local CgiInput object for us to use
00048   // In the vast majority of cases, this will be used
00049   // For FastCGI applications it won't but the performance hit of
00050   // an empty inline constructor is negligible
00051   CgiInput local_input;
00052 
00053   if(0 == input)
00054     readEnvironmentVariables(&local_input);
00055   else
00056     readEnvironmentVariables(input);
00057 
00058   // On Win32, use binary read to avoid CRLF conversion
00059 #ifdef WIN32
00060 #  ifdef __BORLANDC__
00061   setmode(_fileno(stdin), O_BINARY);
00062 #  else
00063   _setmode(_fileno(stdin), _O_BINARY);
00064 #  endif
00065 #endif
00066      
00067   if(stringsAreEqual(fRequestMethod, "post")) {
00068     // Don't use auto_ptr, but vector instead
00069     // Bug reported by shinra@j10n.org
00070     std::vector<char> data(fContentLength);
00071     
00072     // If input is 0, use the default implementation of CgiInput
00073     if(0 == input) {
00074       if(local_input.read(&data[0],fContentLength) != fContentLength)
00075         throw std::runtime_error("I/O error");
00076     }
00077     else {
00078       if(input->read(&data[0], fContentLength) != fContentLength)
00079         throw std::runtime_error("I/O error");
00080     }
00081 
00082     fPostData = std::string(&data[0], fContentLength);
00083   }
00084   
00085   fCookies.reserve(10);
00086   parseCookies();
00087 }
00088 
00089 cgicc::CgiEnvironment::~CgiEnvironment()
00090 {}
00091 
00092 // Overloaded operators
00093 bool 
00094 cgicc::CgiEnvironment::operator== (const CgiEnvironment& env)           const
00095 {
00096   bool result;
00097   
00098   result =  fServerPort         == env.fServerPort;
00099   result &= fContentLength      == env.fContentLength;
00100   result &= fUsingHTTPS         == env.fUsingHTTPS;
00101   result &= fServerSoftware     == env.fServerSoftware;
00102   result &= fServerName         == env.fServerName;
00103   result &= fGatewayInterface   == env.fGatewayInterface;
00104   result &= fServerProtocol     == env.fServerProtocol;
00105   result &= fRequestMethod      == env.fRequestMethod;
00106   result &= fPathInfo           == env.fPathInfo;
00107   result &= fPathTranslated     == env.fPathTranslated;
00108   result &= fScriptName         == env.fScriptName;
00109   result &= fQueryString        == env.fQueryString;
00110   result &= fRemoteHost         == env.fRemoteHost;
00111   result &= fRemoteAddr         == env.fRemoteAddr;
00112   result &= fAuthType           == env.fAuthType;
00113   result &= fRemoteUser         == env.fRemoteUser;
00114   result &= fRemoteIdent        == env.fRemoteIdent;
00115   result &= fContentType        == env.fContentType;
00116   result &= fAccept             == env.fAccept;
00117   result &= fUserAgent          == env.fUserAgent;
00118   result &= fPostData           == env.fPostData;
00119   result &= fRedirectRequest    == env.fRedirectRequest;
00120   result &= fRedirectURL        == env.fRedirectURL;
00121   result &= fRedirectStatus     == env.fRedirectStatus;
00122   result &= fReferrer           == env.fReferrer;
00123   result &= fCookie             == env.fCookie;
00124 
00125   return result;
00126 }
00127 
00128 cgicc::CgiEnvironment& 
00129 cgicc::CgiEnvironment::operator= (const CgiEnvironment& env)
00130 {
00131   fServerPort           = env.fServerPort;
00132   fContentLength        = env.fContentLength;
00133   fUsingHTTPS           = env.fUsingHTTPS;
00134   fServerSoftware       = env.fServerSoftware;
00135   fServerName           = env.fServerName;
00136   fGatewayInterface     = env.fGatewayInterface;
00137   fServerProtocol       = env.fServerProtocol;
00138   fRequestMethod        = env.fRequestMethod;
00139   fPathInfo             = env.fPathInfo;
00140   fPathTranslated       = env.fPathTranslated;
00141   fScriptName           = env.fScriptName;
00142   fQueryString          = env.fQueryString;
00143   fRemoteHost           = env.fRemoteHost;
00144   fRemoteAddr           = env.fRemoteAddr;
00145   fAuthType             = env.fAuthType;
00146   fRemoteUser           = env.fRemoteUser;
00147   fRemoteIdent          = env.fRemoteIdent;
00148   fContentType          = env.fContentType;
00149   fAccept               = env.fAccept;
00150   fUserAgent            = env.fUserAgent;
00151   fPostData             = env.fPostData;
00152   fRedirectRequest      = env.fRedirectRequest;
00153   fRedirectURL          = env.fRedirectURL;
00154   fRedirectStatus       = env.fRedirectStatus;
00155   fReferrer             = env.fReferrer;
00156   fCookie               = env.fCookie;
00157 
00158   fCookies.clear();
00159   fCookies.reserve(env.fCookies.size());
00160   parseCookies();
00161 
00162   return *this;
00163 }
00164 
00165 void
00166 cgicc::CgiEnvironment::parseCookies()
00167 {
00168   std::string data = fCookie;
00169 
00170   if(false == data.empty()) {
00171     std::string::size_type pos;
00172     std::string::size_type oldPos = 0;
00173 
00174     while(true) {
00175       // find the ';' terminating a name=value pair
00176       pos = data.find(";", oldPos);
00177 
00178       // if no ';' was found, the rest of the string is a single cookie
00179       if(std::string::npos == pos) {
00180         parseCookie(data.substr(oldPos));
00181         return;
00182       }
00183 
00184       // otherwise, the string contains multiple cookies
00185       // extract it and add the cookie to the list
00186       parseCookie(data.substr(oldPos, pos - oldPos));
00187       
00188       // update pos (+1 to skip ';')
00189       oldPos = pos + 1;
00190     }
00191   }
00192 }
00193 
00194 void
00195 cgicc::CgiEnvironment::parseCookie(const std::string& data)
00196 {
00197   // find the '=' separating the name and value
00198   std::string::size_type pos = data.find("=", 0);
00199 
00200   // if no '=' was found, return
00201   if(std::string::npos == pos)
00202     return;
00203 
00204   // skip leading whitespace - " \f\n\r\t\v"
00205   std::string::size_type wscount = 0;
00206   std::string::const_iterator data_iter;
00207   
00208   for(data_iter = data.begin(); data_iter != data.end(); ++data_iter,++wscount)
00209     if(0 == std::isspace(*data_iter))
00210       break;                    
00211   
00212   // Per RFC 2091, do not unescape the data (thanks to afm@othello.ch)
00213   std::string name      = data.substr(wscount, pos - wscount);
00214   std::string value     = data.substr(++pos);
00215 
00216   fCookies.push_back(HTTPCookie(name, value));
00217 }
00218 
00219 // Read in all the environment variables
00220 void
00221 cgicc::CgiEnvironment::readEnvironmentVariables(CgiInput *input)
00222 {
00223   fServerSoftware       = input->getenv("SERVER_SOFTWARE");
00224   fServerName           = input->getenv("SERVER_NAME");
00225   fGatewayInterface     = input->getenv("GATEWAY_INTERFACE");
00226   fServerProtocol       = input->getenv("SERVER_PROTOCOL");
00227 
00228   std::string port      = input->getenv("SERVER_PORT");
00229   fServerPort           = std::atol(port.c_str());
00230 
00231   fRequestMethod        = input->getenv("REQUEST_METHOD");
00232   fPathInfo             = input->getenv("PATH_INFO");
00233   fPathTranslated       = input->getenv("PATH_TRANSLATED");
00234   fScriptName           = input->getenv("SCRIPT_NAME");
00235   fQueryString          = input->getenv("QUERY_STRING");
00236   fRemoteHost           = input->getenv("REMOTE_HOST");
00237   fRemoteAddr           = input->getenv("REMOTE_ADDR");
00238   fAuthType             = input->getenv("AUTH_TYPE");
00239   fRemoteUser           = input->getenv("REMOTE_USER");
00240   fRemoteIdent          = input->getenv("REMOTE_IDENT");
00241   fContentType          = input->getenv("CONTENT_TYPE");
00242 
00243   std::string length    = input->getenv("CONTENT_LENGTH");
00244   fContentLength        = std::atol(length.c_str());
00245 
00246   fAccept               = input->getenv("HTTP_ACCEPT");
00247   fUserAgent            = input->getenv("HTTP_USER_AGENT");
00248   fRedirectRequest      = input->getenv("REDIRECT_REQUEST");
00249   fRedirectURL          = input->getenv("REDIRECT_URL");
00250   fRedirectStatus       = input->getenv("REDIRECT_STATUS");
00251   fReferrer             = input->getenv("HTTP_REFERER");
00252   fCookie               = input->getenv("HTTP_COOKIE");
00253 
00254 #ifdef WIN32
00255   // Win32 bug fix by Peter Goedtkindt
00256   std::string https     = input->getenv("HTTPS");
00257   if(stringsAreEqual(https, "on"))
00258     fUsingHTTPS = true;
00259   else
00260     fUsingHTTPS = false;
00261 #else
00262   fUsingHTTPS = (0 != getenv("HTTPS"));
00263 #endif
00264 }
00265 
00266 void
00267 cgicc::CgiEnvironment::save(const std::string& filename)        const
00268 {
00269   std::ofstream file( filename.c_str(), std::ios::out );
00270 
00271   if( ! file )
00272     throw std::runtime_error("I/O error");
00273 
00274   writeLong(file, fContentLength);
00275   writeLong(file, fServerPort);
00276   writeLong(file, (unsigned long) usingHTTPS());
00277 
00278   writeString(file, fServerSoftware);
00279   writeString(file, fServerName);
00280   writeString(file, fGatewayInterface);
00281   writeString(file, fServerProtocol);
00282   writeString(file, fRequestMethod);
00283   writeString(file, fPathInfo);
00284   writeString(file, fPathTranslated);
00285   writeString(file, fScriptName);
00286   writeString(file, fQueryString);
00287   writeString(file, fRemoteHost);
00288   writeString(file, fRemoteAddr);
00289   writeString(file, fAuthType);
00290   writeString(file, fRemoteUser);
00291   writeString(file, fRemoteIdent);
00292   writeString(file, fContentType);
00293   writeString(file, fAccept);
00294   writeString(file, fUserAgent);
00295   writeString(file, fRedirectRequest);
00296   writeString(file, fRedirectURL);
00297   writeString(file, fRedirectStatus);
00298   writeString(file, fReferrer);
00299   writeString(file, fCookie);
00300   
00301   if(stringsAreEqual(fRequestMethod, "post"))
00302     writeString(file, fPostData);
00303 
00304   if(file.bad() || file.fail())
00305     throw std::runtime_error("I/O error");
00306 
00307   file.close();
00308 }
00309 
00310 void
00311 cgicc::CgiEnvironment::restore(const std::string& filename)
00312 {
00313   std::ifstream file( filename.c_str(), std::ios::in );
00314 
00315   if( ! file )
00316     throw std::runtime_error("I/O error");
00317 
00318   file.flags(file.flags() & std::ios::skipws);
00319 
00320   fContentLength        = readLong(file);
00321   fServerPort           = readLong(file);
00322   fUsingHTTPS           = (bool) readLong(file);
00323 
00324   fServerSoftware       = readString(file);
00325   fServerName           = readString(file);
00326   fGatewayInterface     = readString(file);
00327   fServerProtocol       = readString(file);
00328   fRequestMethod        = readString(file);
00329   fPathInfo             = readString(file);
00330   fPathTranslated       = readString(file);
00331   fScriptName           = readString(file);
00332   fQueryString          = readString(file);
00333   fRemoteHost           = readString(file);
00334   fRemoteAddr           = readString(file);
00335   fAuthType             = readString(file);
00336   fRemoteUser           = readString(file);
00337   fRemoteIdent          = readString(file);
00338   fContentType          = readString(file);
00339   fAccept               = readString(file);
00340   fUserAgent            = readString(file);
00341   fRedirectRequest      = readString(file);
00342   fRedirectURL          = readString(file);
00343   fRedirectStatus       = readString(file);
00344   fReferrer             = readString(file);
00345   fCookie               = readString(file);
00346   
00347   if(stringsAreEqual(fRequestMethod, "post"))
00348     fPostData = readString(file);
00349 
00350   file.close();
00351 
00352   fCookies.clear();
00353   fCookies.reserve(10);
00354   parseCookies();
00355 }

Generated on Tue Jul 3 15:44:28 2007 for GNUCgicc by  doxygen 1.5.1