summaryrefslogtreecommitdiff
path: root/project2/cgi
diff options
context:
space:
mode:
authorrandomdan <randomdan@localhost>2010-08-07 13:36:00 +0000
committerrandomdan <randomdan@localhost>2010-08-07 13:36:00 +0000
commita6e25b8ff2722badbbb5299fedd7fa16ccf5b7fa (patch)
treee13406f5e28914d14340326d27658dd9fdb97623 /project2/cgi
parentCache the result of default column compose (diff)
downloadproject2-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.cpp63
-rw-r--r--project2/cgi/FCgiIO.h153
-rw-r--r--project2/cgi/cgiAppEngine.cpp198
-rw-r--r--project2/cgi/cgiAppEngine.h71
-rw-r--r--project2/cgi/cgiEnvironment.cpp42
-rw-r--r--project2/cgi/cgiEnvironment.h27
-rw-r--r--project2/cgi/p2webMain.cpp61
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;
+}