diff options
author | randomdan <randomdan@localhost> | 2010-08-07 13:36:00 +0000 |
---|---|---|
committer | randomdan <randomdan@localhost> | 2010-08-07 13:36:00 +0000 |
commit | a6e25b8ff2722badbbb5299fedd7fa16ccf5b7fa (patch) | |
tree | e13406f5e28914d14340326d27658dd9fdb97623 /project2/cgi | |
parent | Cache the result of default column compose (diff) | |
download | project2-a6e25b8ff2722badbbb5299fedd7fa16ccf5b7fa.tar.bz2 project2-a6e25b8ff2722badbbb5299fedd7fa16ccf5b7fa.tar.xz project2-a6e25b8ff2722badbbb5299fedd7fa16ccf5b7fa.zip |
Move CGI code into its own folder
Diffstat (limited to 'project2/cgi')
-rw-r--r-- | project2/cgi/FCgiIO.cpp | 63 | ||||
-rw-r--r-- | project2/cgi/FCgiIO.h | 153 | ||||
-rw-r--r-- | project2/cgi/cgiAppEngine.cpp | 198 | ||||
-rw-r--r-- | project2/cgi/cgiAppEngine.h | 71 | ||||
-rw-r--r-- | project2/cgi/cgiEnvironment.cpp | 42 | ||||
-rw-r--r-- | project2/cgi/cgiEnvironment.h | 27 | ||||
-rw-r--r-- | project2/cgi/p2webMain.cpp | 61 |
7 files changed, 615 insertions, 0 deletions
diff --git a/project2/cgi/FCgiIO.cpp b/project2/cgi/FCgiIO.cpp new file mode 100644 index 0000000..7a3dd09 --- /dev/null +++ b/project2/cgi/FCgiIO.cpp @@ -0,0 +1,63 @@ +/* + * $Id: FCgiIO.cpp,v 1.6 2007/07/02 18:48:19 sebdiaz Exp $ + * + * Copyright (C) 2002 Steve McAndrewSmith + * Copyright (C) 2002 - 2004 Stephen F. Booth + * 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 <iostream> +#include <stdexcept> +#include <cstdlib> + +#include "FCgiIO.h" + +cgicc::FCgiIO::FCgiIO(FCGX_Request& request) + : std::ostream(&fOutBuf), + fRequest(request), + fOutBuf(request.out), + fErrBuf(request.err), + fErr(&fErrBuf) +{ + rdbuf(&fOutBuf); + fErr.rdbuf(&fErrBuf); + + // Parse environment + for(char **e = fRequest.envp; *e != NULL; ++e) { + std::string s(*e); + std::string::size_type i = s.find('='); + if(i == std::string::npos) + throw std::runtime_error("Illegally formed environment"); + fEnv[s.substr(0, i)] = s.substr(i + 1); + } +} + +cgicc::FCgiIO::FCgiIO(const FCgiIO& io) + : CgiInput(io), + std::ostream(&fOutBuf), + fRequest(io.fRequest), + fErr(&fErrBuf), + fEnv(io.fEnv) +{ + rdbuf(&fOutBuf); + fErr.rdbuf(&fErrBuf); +} diff --git a/project2/cgi/FCgiIO.h b/project2/cgi/FCgiIO.h new file mode 100644 index 0000000..a8b67f3 --- /dev/null +++ b/project2/cgi/FCgiIO.h @@ -0,0 +1,153 @@ +/* -*-c++-*- */ +/* + * $Id: FCgiIO.h,v 1.3 2007/07/02 18:48:19 sebdiaz Exp $ + * + * Copyright (C) 2002 Steve McAndrewSmith + * Copyright (C) 2002 Stephen F. Booth + * 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* + */ + +#ifndef _FCGIIO_H_ +#define _FCGIIO_H_ 1 + +#ifdef __GNUG__ +# pragma interface +#endif + +/*! \file FCgiIO.h + * \brief Class that implements input and output through a FastCGI request. + * + * This class provides access to the input byte-stream and environment + * variable interfaces of a FastCGI request. It is fully compatible with the + * Cgicc input API. + * + * It also provides access to the request's output and error streams, using a + * similar interface. + */ + +#include <ostream> +#include <string> +#include <map> + +#include "fcgio.h" + +#include "cgicc/CgiInput.h" + +namespace cgicc { + + // ============================================================ + // Class FCgiIO + // ============================================================ + + /*! \class FCgiIO FCgiIO.h FCgiIO.h + * \brief Class that implements input and output through a FastCGI request. + * + * This class provides access to the input byte-stream and environment + * variable interfaces of a FastCGI request. It is fully compatible with the + * Cgicc input API. + * + * It also provides access to the request's output and error streams, using a + * similar interface. + */ + class CGICC_API FCgiIO : public cgicc::CgiInput, public std::ostream + { + public: + + // ============================================================ + + /*! \name Constructor and Destructor */ + //@{ + + /*! + * \brief Constructor + * + * Create a new FCgiIO object + */ + FCgiIO(FCGX_Request& request); + + /*! + * \brief Copy constructor + * + */ + FCgiIO(const FCgiIO& io); + + /*! + * \brief Destructor + * + * Delete this FCgiIO object + */ + virtual inline + ~FCgiIO() + {} + //@} + + // ============================================================ + + /*! \name Data Sources */ + //@{ + + /*! + * \brief Read data from the request's input stream. + * + * \param data The target buffer + * \param length The number of characters to read + * \return The number of characters read + */ + virtual inline size_t read(char *data, size_t length) + { + return FCGX_GetStr(data, length, fRequest.in); + } + + /*! + * \brief Query the value of an environment variable stored in the request. + * + * \param varName The name of an environment variable + * \return The value of the requested environment variable, or an empty + * string if not found. + */ + virtual inline std::string getenv(const char *varName) + { + return fEnv[varName]; + } + //@} + + // ============================================================ + + /*! \name Data Target Streams */ + //@{ + + /*! + * \brief Provides access to the error stream. + */ + inline std::ostream& err(void) + { + return fErr; + } + //@} + + protected: + FCGX_Request& fRequest; + fcgi_streambuf fOutBuf; + fcgi_streambuf fErrBuf; + std::ostream fErr; + std::map<std::string, std::string> fEnv; + }; + +} // namespace cgicc + +#endif /* ! _FCGIIO_H_ */ diff --git a/project2/cgi/cgiAppEngine.cpp b/project2/cgi/cgiAppEngine.cpp new file mode 100644 index 0000000..5348246 --- /dev/null +++ b/project2/cgi/cgiAppEngine.cpp @@ -0,0 +1,198 @@ +#include "cgiAppEngine.h" +#include <syslog.h> +#include <cgicc/Cgicc.h> +#include <cgicc/HTTPContentHeader.h> +#include "cgiEnvironment.h" +#include <libxml/xinclude.h> +#include "../xmlObjectLoader.h" +#include "../iterate.h" +#include <boost/bind.hpp> +#include <boost/lexical_cast.hpp> +#include <boost/uuid/uuid_io.hpp> +#include "../sessionShm.h" +#include <boost/uuid/uuid_generators.hpp> + +const std::string SESSIONID = "sessionID"; +typedef boost::uuids::uuid SIDKey; +typedef std::string SValue; + +SessionContainer * sessionsContainer = new SessionContainerShm(); + +CgiApplicationEngine::CgiApplicationEngine(const CgiEnvironment * e) : + ApplicationEngine(e), + _env(e), + header(NULL), + sessionID(boost::uuids::nil_generator()()) +{ + BOOST_FOREACH(const cgicc::HTTPCookie c, e->getCookieList()) { + if (c.getName() == SESSIONID) { + sessionID = boost::uuids::string_generator()(c.getValue()); + } + } + if (_env->getRequestMethod() == "POST") { + currentStage = new RequestStage(this, e->elems[0]); + } + else { + currentStage = new PresentStage(this, e->elems.size() > 0 ? e->elems[0] : "index"); + } +} + +CgiApplicationEngine::~CgiApplicationEngine() +{ + delete header; +} + +const Environment * +CgiApplicationEngine::env() const +{ + return _env; +} + +void +CgiApplicationEngine::process() const +{ + while (!doc && currentStage) { + Stage * prev = currentStage; + currentStage = currentStage->run(); + delete prev; + } + if (!sessionID.is_nil()) { + header->setCookie(cgicc::HTTPCookie(SESSIONID, boost::lexical_cast<std::string>(sessionID), "Session ID", + _env->getServerName().substr(_env->getServerName().find(".")), 3600, "/", false)); + } +} + +CgiApplicationEngine::Stage::Stage(const CgiApplicationEngine * e) : appEngine(e) +{ +} + +CgiApplicationEngine::Stage::~Stage() +{ +} + +CgiApplicationEngine::PresentStage::PresentStage(const CgiApplicationEngine * e, const std::string & id) : + CgiApplicationEngine::Stage(e), + Presenter("present", id) +{ +} +CgiApplicationEngine::PresentStage::PresentStage(const CgiApplicationEngine * e, const std::string & group, const std::string & id) : + CgiApplicationEngine::Stage(e), + Presenter(group, id) +{ +} +CgiApplicationEngine::PresentStage::~PresentStage() +{ +} +CgiApplicationEngine::Stage * +CgiApplicationEngine::PresentStage::run() +{ + BOOST_FOREACH(OrderedParamCheckers::value_type pc, parameterChecks) { + if (!pc.second->performCheck(appEngine)) { + return new PresentStage(appEngine, pc.second->present); + } + } + appEngine->doc = getDataDocument(); + sessionsContainer->CleanUp(); + return NULL; +} + +Presenter::XmlDocumentPtr +CgiApplicationEngine::PresentStage::getDataDocument() const +{ + XmlDocumentPtr responseDoc = Presenter::getDataDocument(); + xmlpp::Element * responseRoot = responseDoc->get_root_node(); + // URL elements + xmlpp::Element * uriElems = responseRoot->add_child("uriElems", "project2"); + BOOST_FOREACH(std::string s, appEngine->_env->elems) { + uriElems->add_child("uriElem", "project2")->set_child_text(s); + } + // Parameters + xmlpp::Element * paramsXml = responseRoot->add_child("params", "project2"); + BOOST_FOREACH(cgicc::FormEntry fe, appEngine->_env->cgi->getElements()) { + xmlpp::Element * param = paramsXml->add_child("param", "project2"); + param->add_child_text(fe.getValue()); + param->set_attribute("name", fe.getName()); + } + // Sessions variables + if (!appEngine->sessionID.is_nil()) { + xmlpp::Element * sessionXml = responseRoot->add_child("session", "project2"); + sessionXml->set_attribute("id", boost::lexical_cast<Glib::ustring>(appEngine->sessionID)); + Session::Values session(sessionsContainer->GetSession(appEngine->sessionID)->GetValuesCopy()); + BOOST_FOREACH(SessionShm::Values::value_type sv, session) { + xmlpp::Element * param = sessionXml->add_child("var", "project2"); + param->add_child_text(sv.second); + param->set_attribute("name", sv.first); + } + } + // XSLT Style + char * buf; + if (responseStyle.length() && asprintf(&buf, "type=\"text/xsl\" href=\"%s\"", + responseStyle.c_str()) > 0) { + xmlAddPrevSibling(responseRoot->cobj(), + xmlNewDocPI(responseDoc->cobj(), BAD_CAST "xml-stylesheet", BAD_CAST buf)); + free(buf); + appEngine->header = new cgicc::HTTPContentHeader("text/xml-xslt"); + } + else { + appEngine->header = new cgicc::HTTPContentHeader("text/xml"); + } + return responseDoc; +} + +CgiApplicationEngine::RequestStage::RequestStage(const CgiApplicationEngine * e, const std::string & id) : + CgiApplicationEngine::Stage(e) +{ + xmlpp::DomParser request("request/" + id + ".xml"); + while (xmlXIncludeProcessFlags(request.get_document()->cobj(), XML_PARSE_NOXINCNODE) > 0); + xmlpp::Element * requestRoot = request.get_document()->get_root_node(); + present = requestRoot->get_attribute_value("present"); + + Loaders loaders; + _DataSource::AddLoaders(loaders, appEngine->datasources); + _ParamChecker::AddLoaders(loaders, parameterChecks); + _Task::AddLoaders(loaders, tasks); + _Iterate::AddLoaders(loaders, tasks); + _LoaderBase::collectAll(loaders, "project2", requestRoot, true, true); +} +CgiApplicationEngine::RequestStage::~RequestStage() +{ +} +CgiApplicationEngine::Stage * +CgiApplicationEngine::RequestStage::run() +{ + BOOST_FOREACH(OrderedParamCheckers::value_type pc, parameterChecks) { + if (!pc.second->performCheck(appEngine)) { + return new PresentStage(appEngine, pc.second->present); + } + } + try { + BOOST_FOREACH(NoOutputExecutes::value_type t, tasks) { + t.second->execute(); + } + // Commit data source transactions (without invoking a connection) + BOOST_FOREACH(DataSources::value_type ds, appEngine->datasources) { + ds.second->commit(); + } + } + catch (...) { + // Do something about the error + BOOST_FOREACH(DataSources::value_type ds, appEngine->datasources) { + ds.second->rollback(); + } + throw; + } + return new PresentStage(appEngine, present); +} + +SessionPtr +CgiApplicationEngine::session() const +{ + return sessionsContainer->GetSession(sessionID); +} + +PresenterPtr +CgiApplicationEngine::getPresenter(const std::string & group, const std::string & id) const +{ + return PresenterPtr(new PresentStage(this, group, id)); +} + diff --git a/project2/cgi/cgiAppEngine.h b/project2/cgi/cgiAppEngine.h new file mode 100644 index 0000000..112e672 --- /dev/null +++ b/project2/cgi/cgiAppEngine.h @@ -0,0 +1,71 @@ +#ifndef CGIAPPENGINE_H +#define CGIAPPENGINE_H + +#include "../appEngine.h" +#include "../task.h" +#include "../paramChecker.h" +#include "../presenter.h" +#include <boost/shared_ptr.hpp> +#include <boost/uuid/uuid.hpp> +#include <libxml++/document.h> +#include <libxml++/parsers/domparser.h> + +class CgiEnvironment; +class Session; +namespace cgicc { + class HTTPContentHeader; +} + +class CgiApplicationEngine : public ApplicationEngine { + public: + CgiApplicationEngine(const CgiEnvironment *); + virtual ~CgiApplicationEngine(); + + void process() const; + const cgicc::HTTPContentHeader * getHeader() const { return header; } + template <class Writer> + void write(const Writer & w) const + { + w(doc->cobj()); + } + const Environment * env() const; + SessionPtr session() const; + PresenterPtr getPresenter(const std::string & group, const std::string & id) const; + const CgiEnvironment * _env; + protected: + mutable cgicc::HTTPContentHeader * header; + private: + mutable boost::shared_ptr<xmlpp::Document> doc; + class Stage { + public: + Stage(const CgiApplicationEngine *); + virtual ~Stage() = 0; + virtual Stage * run() = 0; + protected: + const CgiApplicationEngine * appEngine; + }; + class RequestStage : public Stage { + public: + RequestStage(const CgiApplicationEngine *, const std::string & id); + virtual ~RequestStage(); + virtual Stage * run(); + std::string present; + protected: + OrderedParamCheckers parameterChecks; + NoOutputExecutes tasks; + }; + class PresentStage : public Stage, public Presenter { + public: + PresentStage(const CgiApplicationEngine *, const std::string & id); + PresentStage(const CgiApplicationEngine *, const std::string & group, const std::string & id); + virtual ~PresentStage(); + virtual Stage * run(); + protected: + XmlDocumentPtr getDataDocument() const; + }; + mutable Stage * currentStage; + mutable boost::uuids::uuid sessionID; +}; + +#endif + diff --git a/project2/cgi/cgiEnvironment.cpp b/project2/cgi/cgiEnvironment.cpp new file mode 100644 index 0000000..630629a --- /dev/null +++ b/project2/cgi/cgiEnvironment.cpp @@ -0,0 +1,42 @@ +#include "cgiEnvironment.h" +#include "../appEngine.h" +#include <map> +#include <cgicc/Cgicc.h> +#include <boost/tokenizer.hpp> + +template <class X, class Y> +std::vector<X>makeVector(const Y & y) +{ + return std::vector<X>(y.begin(), y.end()); +} + +CgiEnvironment::CgiEnvironment(cgicc::Cgicc * c) : + cgicc::CgiEnvironment(c->getEnvironment()), + elems(makeVector<std::string>(boost::tokenizer<boost::char_separator<char> >(getRedirectURL(), boost::char_separator<char>("/")))), + cgi(c) +{ +} + +CgiEnvironment::~CgiEnvironment() +{ +} + +Glib::ustring +CgiEnvironment::getParamUri(unsigned int p) const +{ + if (p >= elems.size()) { + throw ApplicationEngine::UriElementOutOfRange(); + } + return elems[p]; +} + +Glib::ustring +CgiEnvironment::getParamQuery(const std::string & p) const +{ + cgicc::const_form_iterator i = cgi->getElement(p); + if (i == cgi->getElements().end()) { + throw ApplicationEngine::ParamNotFound(); + } + return (*cgi)(p); +} + diff --git a/project2/cgi/cgiEnvironment.h b/project2/cgi/cgiEnvironment.h new file mode 100644 index 0000000..5c0455c --- /dev/null +++ b/project2/cgi/cgiEnvironment.h @@ -0,0 +1,27 @@ +#ifndef ENVPROC_H +#define ENVPROC_H + +#include <string> +#include <vector> +#include "../environment.h" +#include <cgicc/CgiEnvironment.h> + +namespace cgicc { + class Cgicc; +} + +class CgiEnvironment : public Environment, public cgicc::CgiEnvironment { + public: + CgiEnvironment(cgicc::Cgicc *); + virtual ~CgiEnvironment(); + + Glib::ustring getParamUri(unsigned int idx) const; + Glib::ustring getParamQuery(const std::string & idx) const; + std::string getServerName() const { return cgicc::CgiEnvironment::getServerName(); } + std::string getScriptName() const { return cgicc::CgiEnvironment::getScriptName(); } + + std::vector<std::string> elems; + const cgicc::Cgicc * const cgi; +}; + +#endif diff --git a/project2/cgi/p2webMain.cpp b/project2/cgi/p2webMain.cpp new file mode 100644 index 0000000..ef070f0 --- /dev/null +++ b/project2/cgi/p2webMain.cpp @@ -0,0 +1,61 @@ +#include <libxml/tree.h> +#include <cgicc/Cgicc.h> +#include <cgicc/CgiEnvironment.h> +#include <cgicc/HTTPContentHeader.h> +FILE * realstdout = stdout; +#include <fcgi_stdio.h> +#include "cgiEnvironment.h" +#include "cgiAppEngine.h" +#include <boost/bind.hpp> +#include "FCgiIO.h" + +int +xmlWrite(void * _out, const char * buf, int len) +{ + cgicc::FCgiIO & IO = *((cgicc::FCgiIO*)_out); + IO.write(buf, len); + return len; +} + +int main(void) +{ + if (!FCGX_IsCGI()) { + FCGX_Request request; + + FCGX_Init(); + FCGX_InitRequest(&request, 0, 0); + + while (FCGX_Accept_r(&request) == 0) { + cgicc::FCgiIO IO(request); + try { + cgicc::Cgicc cgi(&IO); + CgiEnvironment env(&cgi); + CgiApplicationEngine app(&env); + app.process(); + IO << "Cache-control: no-cache" << std::endl; + app.getHeader()->render(IO); + xmlOutputBufferPtr out = xmlOutputBufferCreateIO( + xmlWrite, NULL, &IO, xmlGetCharEncodingHandler(XML_CHAR_ENCODING_UTF8)); + app.write(boost::bind(xmlSaveFileTo, out, _1, "utf-8")); + } + catch (const std::exception & e) { + cgicc::HTTPContentHeader header("text/plain"); + header.render(IO); + IO << "Kaboom!" << std::endl << std::endl << e.what(); + } + catch (...) { + cgicc::HTTPContentHeader header("text/plain"); + header.render(IO); + IO << "Kaboom!" << std::endl << std::endl << "Unknown exception."; + } + } + } + else { + cgicc::Cgicc cgi(NULL); + CgiEnvironment env(&cgi); + CgiApplicationEngine app(&env); + app.process(); + app.write(boost::bind(xmlDocDump, realstdout, _1)); + } + return 0; +} |