emsApplication/sdk/include/cgicc/CgiEnvironment.cpp

364 lines
11 KiB
C++
Raw Normal View History

2024-05-24 12:23:42 +08:00
/* -*-mode:c++; c-file-style: "gnu";-*- */
/*
* $Id: CgiEnvironment.cpp,v 1.31 2017/06/22 20:26:35 sebdiaz Exp $
*
* Copyright (C) 1996 - 2004 Stephen F. Booth <sbooth@gnu.org>
* 2007 Sebastien DIAZ <sebastien.diaz@gmail.com>
* Part of the GNU cgicc library, http://www.gnu.org/software/cgicc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*
*/
#ifdef __GNUG__
# pragma implementation
#endif
#include <new>
#include <memory>
#include <stdexcept>
#include <cstdlib>
#include <cctype>
#ifdef WIN32
# include <io.h>
# include <fcntl.h>
# include <stdio.h>
#endif
#include "CgiEnvironment.h"
// ========== Constructor/Destructor
cgicc::CgiEnvironment::CgiEnvironment(CgiInput *input)
{
// Create a local CgiInput object for us to use
// In the vast majority of cases, this will be used
// For FastCGI applications it won't but the performance hit of
// an empty inline constructor is negligible
CgiInput local_input;
if(0 == input)
readEnvironmentVariables(&local_input);
else
readEnvironmentVariables(input);
// On Win32, use binary read to avoid CRLF conversion
#ifdef WIN32
# ifdef __BORLANDC__
setmode(_fileno(stdin), O_BINARY);
# else
_setmode(_fileno(stdin), _O_BINARY);
# endif
#endif
if(stringsAreEqual(fRequestMethod, "post") || stringsAreEqual(fRequestMethod, "put")) {
// Don't use auto_ptr, but vector instead
// Bug reported by shinra@j10n.org
std::vector<char> data(fContentLength);
if(getenv("CGICC_MAX_CONTENTLENGTH")&&getContentLength()>(long unsigned int)atoi(getenv("CGICC_MAX_CONTENTLENGTH")))
{
throw std::runtime_error("Malformed input");
}
else
// If input is 0, use the default implementation of CgiInput
if ( getContentLength() )
{
// If input is 0, use the default implementation of CgiInput
if ( input == 0 )
{
if ( local_input.read( &data[0], getContentLength() ) != getContentLength() )
throw std::runtime_error("I/O error");
}
else
if ( input->read( &data[0], getContentLength() ) != getContentLength() )
throw std::runtime_error("I/O error");
fPostData = std::string( &data[0], getContentLength() );
}
}
fCookies.reserve(10);
parseCookies();
}
cgicc::CgiEnvironment::~CgiEnvironment()
{}
// Overloaded operators
bool
cgicc::CgiEnvironment::operator== (const CgiEnvironment& env) const
{
bool result;
result = fServerPort == env.fServerPort;
result &= fContentLength == env.fContentLength;
result &= fUsingHTTPS == env.fUsingHTTPS;
result &= fServerSoftware == env.fServerSoftware;
result &= fServerName == env.fServerName;
result &= fGatewayInterface == env.fGatewayInterface;
result &= fServerProtocol == env.fServerProtocol;
result &= fRequestMethod == env.fRequestMethod;
result &= fPathInfo == env.fPathInfo;
result &= fPathTranslated == env.fPathTranslated;
result &= fScriptName == env.fScriptName;
result &= fQueryString == env.fQueryString;
result &= fRemoteHost == env.fRemoteHost;
result &= fRemoteAddr == env.fRemoteAddr;
result &= fAuthType == env.fAuthType;
result &= fRemoteUser == env.fRemoteUser;
result &= fRemoteIdent == env.fRemoteIdent;
result &= fContentType == env.fContentType;
result &= fAccept == env.fAccept;
result &= fUserAgent == env.fUserAgent;
result &= fPostData == env.fPostData;
result &= fRedirectRequest == env.fRedirectRequest;
result &= fRedirectURL == env.fRedirectURL;
result &= fRedirectStatus == env.fRedirectStatus;
result &= fReferrer == env.fReferrer;
result &= fCookie == env.fCookie;
return result;
}
cgicc::CgiEnvironment&
cgicc::CgiEnvironment::operator= (const CgiEnvironment& env)
{
fServerPort = env.fServerPort;
fContentLength = env.fContentLength;
fUsingHTTPS = env.fUsingHTTPS;
fServerSoftware = env.fServerSoftware;
fServerName = env.fServerName;
fGatewayInterface = env.fGatewayInterface;
fServerProtocol = env.fServerProtocol;
fRequestMethod = env.fRequestMethod;
fPathInfo = env.fPathInfo;
fPathTranslated = env.fPathTranslated;
fScriptName = env.fScriptName;
fQueryString = env.fQueryString;
fRemoteHost = env.fRemoteHost;
fRemoteAddr = env.fRemoteAddr;
fAuthType = env.fAuthType;
fRemoteUser = env.fRemoteUser;
fRemoteIdent = env.fRemoteIdent;
fContentType = env.fContentType;
fAccept = env.fAccept;
fUserAgent = env.fUserAgent;
fPostData = env.fPostData;
fRedirectRequest = env.fRedirectRequest;
fRedirectURL = env.fRedirectURL;
fRedirectStatus = env.fRedirectStatus;
fReferrer = env.fReferrer;
fCookie = env.fCookie;
fCookies.clear();
fCookies.reserve(env.fCookies.size());
parseCookies();
return *this;
}
void
cgicc::CgiEnvironment::parseCookies()
{
std::string data = fCookie;
if(false == data.empty()) {
std::string::size_type pos;
std::string::size_type oldPos = 0;
while(true) {
// find the ';' terminating a name=value pair
pos = data.find(";", oldPos);
// if no ';' was found, the rest of the string is a single cookie
if(std::string::npos == pos) {
parseCookie(data.substr(oldPos));
return;
}
// otherwise, the string contains multiple cookies
// extract it and add the cookie to the list
parseCookie(data.substr(oldPos, pos - oldPos));
// update pos (+1 to skip ';')
oldPos = pos + 1;
}
}
}
void
cgicc::CgiEnvironment::parseCookie(const std::string& data)
{
// find the '=' separating the name and value
std::string::size_type pos = data.find("=", 0);
// if no '=' was found, return
if(std::string::npos == pos)
return;
// skip leading whitespace - " \f\n\r\t\v"
std::string::size_type wscount = 0;
std::string::const_iterator data_iter;
for(data_iter = data.begin(); data_iter != data.end(); ++data_iter,++wscount)
if(0 == std::isspace(*data_iter))
break;
// Per RFC 2091, do not unescape the data (thanks to afm@othello.ch)
std::string name = data.substr(wscount, pos - wscount);
std::string value = data.substr(++pos);
fCookies.push_back(HTTPCookie(name, value));
}
// Read in all the environment variables
void
cgicc::CgiEnvironment::readEnvironmentVariables(CgiInput *input)
{
fServerSoftware = input->getenv("SERVER_SOFTWARE");
fServerName = input->getenv("SERVER_NAME");
fGatewayInterface = input->getenv("GATEWAY_INTERFACE");
fServerProtocol = input->getenv("SERVER_PROTOCOL");
std::string port = input->getenv("SERVER_PORT");
fServerPort = std::atol(port.c_str());
fRequestMethod = input->getenv("REQUEST_METHOD");
fPathInfo = input->getenv("PATH_INFO");
fPathTranslated = input->getenv("PATH_TRANSLATED");
fScriptName = input->getenv("SCRIPT_NAME");
fQueryString = input->getenv("QUERY_STRING");
fRemoteHost = input->getenv("REMOTE_HOST");
fRemoteAddr = input->getenv("REMOTE_ADDR");
fAuthType = input->getenv("AUTH_TYPE");
fRemoteUser = input->getenv("REMOTE_USER");
fRemoteIdent = input->getenv("REMOTE_IDENT");
fContentType = input->getenv("CONTENT_TYPE");
std::string length = input->getenv("CONTENT_LENGTH");
fContentLength = std::atol(length.c_str());
fAccept = input->getenv("HTTP_ACCEPT");
fUserAgent = input->getenv("HTTP_USER_AGENT");
fRedirectRequest = input->getenv("REDIRECT_REQUEST");
fRedirectURL = input->getenv("REDIRECT_URL");
fRedirectStatus = input->getenv("REDIRECT_STATUS");
fReferrer = input->getenv("HTTP_REFERER");
fCookie = input->getenv("HTTP_COOKIE");
fAcceptLanguageString = input->getenv("HTTP_ACCEPT_LANGUAGE");
// Win32 bug fix by Peter Goedtkindt
std::string https = input->getenv("HTTPS");
if(stringsAreEqual(https, "on"))
fUsingHTTPS = true;
else
fUsingHTTPS = false;
}
void
cgicc::CgiEnvironment::save(const std::string& filename) const
{
std::ofstream file( filename.c_str(), std::ios::binary |std::ios::out );
if( ! file )
throw std::runtime_error("I/O error");
writeLong(file, fContentLength);
writeLong(file, fServerPort);
writeLong(file, (unsigned long) usingHTTPS());
writeString(file, fServerSoftware);
writeString(file, fServerName);
writeString(file, fGatewayInterface);
writeString(file, fServerProtocol);
writeString(file, fRequestMethod);
writeString(file, fPathInfo);
writeString(file, fPathTranslated);
writeString(file, fScriptName);
writeString(file, fQueryString);
writeString(file, fRemoteHost);
writeString(file, fRemoteAddr);
writeString(file, fAuthType);
writeString(file, fRemoteUser);
writeString(file, fRemoteIdent);
writeString(file, fContentType);
writeString(file, fAccept);
writeString(file, fUserAgent);
writeString(file, fRedirectRequest);
writeString(file, fRedirectURL);
writeString(file, fRedirectStatus);
writeString(file, fReferrer);
writeString(file, fCookie);
if(stringsAreEqual(fRequestMethod, "post") || stringsAreEqual(fRequestMethod, "put"))
writeString(file, fPostData);
if(file.bad() || file.fail())
throw std::runtime_error("I/O error");
file.close();
}
void
cgicc::CgiEnvironment::restore(const std::string& filename)
{
std::ifstream file( filename.c_str(), std::ios::binary | std::ios::in );
if( ! file )
throw std::runtime_error("I/O error");
file.flags(file.flags() & std::ios::skipws);
fContentLength = readLong(file);
fServerPort = readLong(file);
fUsingHTTPS = (bool) readLong(file);
fServerSoftware = readString(file);
fServerName = readString(file);
fGatewayInterface = readString(file);
fServerProtocol = readString(file);
fRequestMethod = readString(file);
fPathInfo = readString(file);
fPathTranslated = readString(file);
fScriptName = readString(file);
fQueryString = readString(file);
fRemoteHost = readString(file);
fRemoteAddr = readString(file);
fAuthType = readString(file);
fRemoteUser = readString(file);
fRemoteIdent = readString(file);
fContentType = readString(file);
fAccept = readString(file);
fUserAgent = readString(file);
fRedirectRequest = readString(file);
fRedirectURL = readString(file);
fRedirectStatus = readString(file);
fReferrer = readString(file);
fCookie = readString(file);
if(stringsAreEqual(fRequestMethod, "post") || stringsAreEqual(fRequestMethod, "put"))
fPostData = readString(file);
file.close();
fCookies.clear();
fCookies.reserve(10);
parseCookies();
}