diff options
25 files changed, 563 insertions, 281 deletions
diff --git a/project2/Jamfile.jam b/project2/Jamfile.jam index 1d9ba9b..0b8425e 100644 --- a/project2/Jamfile.jam +++ b/project2/Jamfile.jam @@ -16,6 +16,7 @@ alias libxslt : : : : lib fcgi : : <name>fcgi ; lib fcgi++ : : <name>fcgi++ ; lib boost_regex : : <name>boost_regex ; +lib boost_system : : <name>boost_system ; lib boost_filesystem : : <name>boost_filesystem ; lib boost_date_time : : <name>boost_date_time ; lib boost_program_options : : <name>boost_program_options ; @@ -39,6 +40,11 @@ feature uuid : boost ossp : propagated ; feature odbc : yes no ; feature pq : yes no ; +project + : requirements + <variant>debug:<linkflags>-Wl,-z,defs <cflags>"-W -Wall -Werror -Wwrite-strings" + ; + lib p2uuid : uuid.cpp : @@ -58,6 +64,7 @@ lib p2common : : <include>../libmisc <library>libxmlpp + <library>boost_system <library>boost_filesystem <library>boost_date_time <library>boost_program_options @@ -65,10 +72,11 @@ lib p2common : lib p2xml : xmlRows.cpp xslRows.cpp - p2url : <include>../libmisc <library>libxmlpp + <library>p2common + <library>p2url <library>libxslt ; @@ -77,6 +85,8 @@ lib p2processes : : <include>../libmisc <library>libxmlpp + <library>p2common + <library>p2files ; lib p2files : @@ -87,6 +97,8 @@ lib p2files : <include>../libmisc <library>libxmlpp <library>boost_filesystem + <library>boost_system + <library>p2common ; lib p2regex : @@ -95,6 +107,7 @@ lib p2regex : <include>../libmisc <library>boost_regex <library>libxmlpp + <library>p2common ; lib p2xmlSession : @@ -102,8 +115,8 @@ lib p2xmlSession : : <include>../libmisc <library>libxmlpp - : : <library>p2uuid + <library>p2common ; obj rdbmsDataSource : @@ -123,6 +136,7 @@ lib p2sql : <odbc>yes:<library>../libodbcpp//odbcpp <pq>yes:<library>../libpqpp//pqpp <library>libxmlpp + <library>p2common <include>../libmisc : : <odbc>yes:<library>../libodbcpp//odbcpp @@ -134,9 +148,13 @@ lib p2url : curlHelper.cpp ../libmisc/curlsup.cpp : + <library>p2common + <library>p2files <include>../libmisc <library>libxmlpp <library>curl + : : + <library>curl ; lib p2mail : @@ -146,6 +164,7 @@ lib p2mail : <library>libxmlpp <library>libxslt <library>esmtp + <library>p2common ; lib p2web : @@ -155,9 +174,13 @@ lib p2web : <library>cgicc <library>glibmm <library>libxmlpp + <library>p2common + <library>p2uuid + <library>boost_program_options + <library>boost_regex + <library>p2xmlSession : : <library>p2parts - <library>p2xmlSession ; exe p2cgi : diff --git a/project2/cgi/cgiAppEngine.cpp b/project2/cgi/cgiAppEngine.cpp index 7df0279..547506d 100644 --- a/project2/cgi/cgiAppEngine.cpp +++ b/project2/cgi/cgiAppEngine.cpp @@ -2,14 +2,12 @@ #include <cgicc/Cgicc.h> #include <cgicc/HTTPHeader.h> #include "cgiEnvironment.h" -#include "../xmlObjectLoader.h" #include "../iterate.h" #include "../logger.h" #include <boost/bind.hpp> #include <boost/regex.hpp> #include <boost/foreach.hpp> #include "../sessionXml.h" -#include <cxxabi.h> #include <boost/date_time/microsec_time_clock.hpp> const std::string SESSIONID = "sessionID"; @@ -20,32 +18,6 @@ SessionContainer * sessionsContainer = new SessionContainerXml(); SimpleMessageException(UnknownDomain); -class Project2HttpHeader : public cgicc::HTTPHeader { - public: - typedef std::map<std::string, const Glib::ustring> Headers; - Project2HttpHeader(const std::string & s, const std::string & t) : - cgicc::HTTPHeader("") - { - addHeader("Status", s); - addHeader("Content-Type", t); - } - void addHeader(const std::string & name, const Glib::ustring & value) { - headers.erase(name); - headers.insert(Headers::value_type(name, value)); - } - void render(std::ostream & out) const { - BOOST_FOREACH(const Headers::value_type & h, headers) { - out << h.first << ": " << h.second << std::endl; - } - BOOST_FOREACH(const cgicc::HTTPCookie & cookie, getCookies()) { - out << cookie << std::endl; - } - out << std::endl; - } - private: - Headers headers; -}; - static int xmlWrite(void * _out, const char * buf, int len) @@ -64,20 +36,7 @@ CgiApplicationEngine::CgiApplicationEngine(const CgiEnvironment * e) : sessionID = c.getValue(); } } - try { - if (_env->getRequestMethod() == "POST") { - currentStage = new RequestStage(e->elems[0]); - } - else { - currentStage = new PresentStage(e->elems.size() > 0 ? e->elems[0] : "index"); - } - } - catch (const XmlScriptParser::NotFound & nf) { - currentStage = new NotFoundStage(_env, nf); - } - catch (const std::exception & ex) { - currentStage = new ErrorStage(_env, ex); - } + currentStage = new InitialStage(e); } CgiApplicationEngine::~CgiApplicationEngine() @@ -114,25 +73,41 @@ void CgiApplicationEngine::process() const { startTime = boost::date_time::microsec_clock<boost::posix_time::ptime>::universal_time(); - try { - for (StagePtr nextStage; (nextStage = currentStage->run()); ) { - currentStage = nextStage; + bool triedNotFound = false; + bool triedOnError = false; + StagePtr nextStage; + do { + try { + nextStage = currentStage->run(); } - } - catch (const XmlScriptParser::NotFound & nf) { - currentStage = new NotFoundStage(_env, nf); - } - catch (const std::exception & ex) { - currentStage = new ErrorStage(_env, ex); - } + catch (const XmlScriptParser::NotFound & nf) { + if (_env->notFoundPresent.empty() || triedNotFound) { + nextStage = new DefaultNotFoundStage(_env, nf); + } + else { + triedNotFound = true; + nextStage = new CustomNotFoundStage(_env, nf); + } + } + catch (const std::exception & ex) { + if (_env->onErrorPresent.empty() || triedOnError) { + nextStage = new DefaultErrorStage(_env, ex); + } + else { + triedNotFound = true; + nextStage = new CustomErrorStage(_env, ex); + } + } + } while (nextStage && (currentStage = nextStage)); endTime = boost::date_time::microsec_clock<boost::posix_time::ptime>::universal_time(); - const Presenter * p = boost::dynamic_pointer_cast<const Presenter>(currentStage).get(); + PresenterPtr p = boost::dynamic_pointer_cast<Presenter>(currentStage); if (p) { - addAppData(p); + addAppData(p.get()); } } -CgiApplicationEngine::Stage::Stage() +CgiApplicationEngine::Stage::Stage(const CgiEnvironment * env) : + e(env) { } @@ -140,59 +115,36 @@ CgiApplicationEngine::Stage::~Stage() { } -CgiApplicationEngine::PresentStage::PresentStage(const std::string & id) : - XmlProcessPresenter("present", id, false) -{ -} - -CgiApplicationEngine::PresentStage::~PresentStage() -{ -} - -CgiApplicationEngine::StagePtr -CgiApplicationEngine::PresentStage::run() -{ - BOOST_FOREACH(ParamCheckers::value_type pc, parameterChecks.get<bySOOrder>()) { - if (!pc->performCheck()) { - return new PresentStage(pc->present); - } - } - execute(); - return NULL; -} - CgiApplicationEngine::HttpHeaderPtr -CgiApplicationEngine::PresentStage::getHeader() const +CgiApplicationEngine::Stage::getHeader() const { - Project2HttpHeader * header = new Project2HttpHeader("200 OK", contentType); - header->addHeader("Cache-control", "no-cache"); - return HttpHeaderPtr(header); + return CgiApplicationEngine::HttpHeaderPtr(); } CgiApplicationEngine::XmlDocPtr -CgiApplicationEngine::PresentStage::getDataDocument() const +CgiApplicationEngine::Stage::getDataDocument() const { - return XmlProcessPresenter::getDataDocument(); + return XmlDocPtr(); } void CgiApplicationEngine::addEnvData(const Presenter * p) const { // These were for debug... but why not pass them on? - p->addField("servername", "project2", env()->getServerName()); - p->addField("scriptname", "project2", env()->getScriptName()); + p->addField("servername", env()->getXmlPrefix(), env()->getServerName()); + p->addField("scriptname", env()->getXmlPrefix(), env()->getScriptName()); // URL elements - p->pushSub("uriElems", "project2"); + p->pushSub("uriElems", env()->getXmlPrefix()); BOOST_FOREACH(std::string s, _env->elems) { - p->addField("uriElem", "project2", s); + p->addField("uriElem", env()->getXmlPrefix(), s); } p->popSub(); // Parameters - p->pushSub("params", "project2"); + p->pushSub("params", env()->getXmlPrefix()); BOOST_FOREACH(cgicc::FormEntry fe, _env->cgi->getElements()) { - p->pushSub("param", "project2"); + p->pushSub("param", env()->getXmlPrefix()); p->addAttr("name", fe.getName()); p->addAttr("value", fe.getValue()); p->popSub(); @@ -205,11 +157,11 @@ CgiApplicationEngine::addAppData(const Presenter * p) const { // Sessions variables if (!sessionID.is_nil()) { - p->pushSub("session", "project2"); + p->pushSub("session", env()->getXmlPrefix()); p->addField("id", sessionID.str()); Session::Values session(sessionsContainer->GetSession(sessionID)->GetValuesCopy()); BOOST_FOREACH(Session::Values::value_type sv, session) { - p->pushSub("var", "project2"); + p->pushSub("var", env()->getXmlPrefix()); p->addAttr("value", sv.second); p->addAttr("name", sv.first); p->popSub(); @@ -218,7 +170,7 @@ CgiApplicationEngine::addAppData(const Presenter * p) const } // Timing info - p->pushSub("timing", "project2"); + p->pushSub("timing", env()->getXmlPrefix()); p->addAttr("start", startTime); if (!endTime.is_not_a_date_time()) { p->addAttr("end", endTime); @@ -227,60 +179,6 @@ CgiApplicationEngine::addAppData(const Presenter * p) const p->popSub(); } -CgiApplicationEngine::RequestStage::RequestStage(const std::string & id) -{ - XmlScriptParser request("request", id, false); - xmlpp::Element * requestRoot = request.get_document()->get_root_node(); - present = requestRoot->get_attribute_value("present"); - rollbackBeforeHandle = requestRoot->get_attribute_value("rollbackBeforeHandle") == "true"; - localErrorHandling = requestRoot->get_attribute_value("errorHandling") == "local"; - - LoaderBase loader("http://project2.randomdan.homeip.net", true); - loader.supportedStorers.insert(Storer::into(¶meterChecks)); - loader.supportedStorers.insert(Storer::into(&rowSets)); - loader.supportedStorers.insert(Storer::into(&tasks)); - loader.collectAll(this, requestRoot, true); -} -CgiApplicationEngine::RequestStage::~RequestStage() -{ -} -CgiApplicationEngine::StagePtr -CgiApplicationEngine::RequestStage::run() -{ - BOOST_FOREACH(const ParamCheckers::value_type & pc, parameterChecks.get<bySOOrder>()) { - if (!pc->performCheck()) { - return new PresentStage(pc->present); - } - } - RequestHost::run(); - return present.empty() ? NULL : new PresentStage(present); -} - -CgiApplicationEngine::HttpHeaderPtr -CgiApplicationEngine::RequestStage::getHeader() const -{ - return HttpHeaderPtr(new Project2HttpHeader("200 OK", "text/xml")); -} - -CgiApplicationEngine::XmlDocPtr -CgiApplicationEngine::RequestStage::getDataDocument() const -{ - return XmlPresenter::getDataDocument(); -} - -const Glib::ustring CgiApplicationEngine::RequestStage::resp("request"); -const Glib::ustring CgiApplicationEngine::RequestStage::style; -const Glib::ustring & -CgiApplicationEngine::RequestStage::getResponseRootNodeName() const -{ - return resp; -} -const Glib::ustring & -CgiApplicationEngine::RequestStage::getResponseStyle() const -{ - return style; -} - SessionPtr CgiApplicationEngine::session() const { @@ -310,89 +208,4 @@ CgiApplicationEngine::loadEngineSection(const xmlpp::Element * e) const domplat.push_back(DomainPlatforms::value_type(e->get_attribute_value("name"), e->get_attribute_value("platform"))); } -CgiApplicationEngine::FailStage::FailStage(const CgiEnvironment * e) : - env(e) -{ -} - -CgiApplicationEngine::FailStage::~FailStage() -{ -} - -const Glib::ustring & -CgiApplicationEngine::FailStage::getResponseStyle() const -{ - return env->errorTransformStyle; -} - -CgiApplicationEngine::StagePtr -CgiApplicationEngine::FailStage::run() -{ - return NULL; -} - -CgiApplicationEngine::NotFoundStage::NotFoundStage(const CgiEnvironment * e, const XmlScriptParser::NotFound & nf) : - CgiApplicationEngine::FailStage(e) -{ - initDoc(); - responseDoc->get_root_node()->add_child("resource")->set_child_text(nf.what()); -} - -CgiApplicationEngine::NotFoundStage::~NotFoundStage() -{ -} - -CgiApplicationEngine::HttpHeaderPtr -CgiApplicationEngine::NotFoundStage::getHeader() const -{ - return HttpHeaderPtr(new Project2HttpHeader("404 Not found", env->errorContentType)); -} - -const Glib::ustring CgiApplicationEngine::NotFoundStage::resp("notfound"); -const Glib::ustring & -CgiApplicationEngine::NotFoundStage::getResponseRootNodeName() const -{ - return resp; -} - -CgiApplicationEngine::XmlDocPtr -CgiApplicationEngine::NotFoundStage::getDataDocument() const -{ - return XmlPresenter::getDataDocument(); -} - -CgiApplicationEngine::ErrorStage::ErrorStage(const CgiEnvironment * e, const std::exception & ex) : - CgiApplicationEngine::FailStage(e) -{ - initDoc(); - char * buf = __cxxabiv1::__cxa_demangle(typeid(ex).name(), NULL, NULL, NULL); - Logger()->messagef(LOG_ERR, "%s: Request errored: %s: %s", __FUNCTION__, buf, ex.what()); - responseDoc->get_root_node()->add_child("type")->set_child_text(buf); - responseDoc->get_root_node()->add_child("what")->set_child_text(ex.what()); - free(buf); -} - -CgiApplicationEngine::ErrorStage::~ErrorStage() -{ -} - -CgiApplicationEngine::HttpHeaderPtr -CgiApplicationEngine::ErrorStage::getHeader() const -{ - return HttpHeaderPtr(new Project2HttpHeader("500 Internal Server Error", env->errorContentType)); -} - -const Glib::ustring CgiApplicationEngine::ErrorStage::resp("error"); -const Glib::ustring & -CgiApplicationEngine::ErrorStage::getResponseRootNodeName() const -{ - return resp; -} - -CgiApplicationEngine::XmlDocPtr -CgiApplicationEngine::ErrorStage::getDataDocument() const -{ - return XmlPresenter::getDataDocument(); -} - diff --git a/project2/cgi/cgiAppEngine.h b/project2/cgi/cgiAppEngine.h index cfab7c4..de9b95a 100644 --- a/project2/cgi/cgiAppEngine.h +++ b/project2/cgi/cgiAppEngine.h @@ -47,19 +47,29 @@ class CgiApplicationEngine : public ApplicationEngine { class Stage; typedef boost::intrusive_ptr<Stage> StagePtr; + /// Base class for a stage iteration that should eventually produce a response for the client class Stage : public virtual CommonObjects { public: - Stage(); + Stage(const CgiEnvironment * e); virtual ~Stage() = 0; virtual StagePtr run() = 0; - virtual XmlDocPtr getDataDocument() const = 0; - virtual HttpHeaderPtr getHeader() const = 0; + virtual XmlDocPtr getDataDocument() const; + virtual HttpHeaderPtr getHeader() const; + protected: + const CgiEnvironment * e; + }; + + /// Stage implementation used to bootstrap the iteration process based on the CGI environment + class InitialStage : public Stage { + public: + InitialStage(const CgiEnvironment * e); + virtual StagePtr run(); }; + /// Stage to process POST requests class RequestStage : public Stage, public XmlPresenter, RequestHost { public: - RequestStage(const std::string & id); - virtual ~RequestStage(); + RequestStage(const CgiEnvironment *, const std::string & id); virtual StagePtr run(); virtual XmlDocPtr getDataDocument() const; @@ -77,51 +87,73 @@ class CgiApplicationEngine : public ApplicationEngine { static const Glib::ustring style; }; - class PresentStage : public Stage, public XmlProcessPresenter { + /// Stage to process GET requests and follow up RequestStages + class PresentStage : public virtual Stage, public XmlProcessPresenter { public: - PresentStage(const std::string & id); - virtual ~PresentStage(); + PresentStage(const CgiEnvironment * e, const std::string & id); + PresentStage(const CgiEnvironment * e, const std::string & group, const std::string & id); virtual StagePtr run(); virtual XmlDocPtr getDataDocument() const; virtual HttpHeaderPtr getHeader() const; }; - class FailStage : public Stage, public XmlPresenter { + /// The built-in fail-safe not found stage + class DefaultNotFoundStage : public virtual Stage, public XmlPresenter { public: - FailStage(const CgiEnvironment *); - virtual ~FailStage(); + DefaultNotFoundStage(const CgiEnvironment *, const XmlScriptParser::NotFound &); - virtual const Glib::ustring & getResponseStyle() const; + virtual XmlDocPtr getDataDocument() const; + virtual HttpHeaderPtr getHeader() const; virtual StagePtr run(); + virtual const Glib::ustring & getResponseRootNodeName() const; + virtual const Glib::ustring & getResponseStyle() const; + private: + static const Glib::ustring resp; + const CgiEnvironment * e; + const XmlScriptParser::NotFound nf; + }; - protected: - const CgiEnvironment * env; + /// Custom not found handling stage + class CustomNotFoundStage : public DefaultNotFoundStage, public PresentStage { + public: + CustomNotFoundStage(const CgiEnvironment *, const XmlScriptParser::NotFound &); + virtual StagePtr run(); + virtual XmlDocPtr getDataDocument() const; + virtual HttpHeaderPtr getHeader() const; + virtual const Glib::ustring & getResponseRootNodeName() const; + virtual const Glib::ustring & getResponseStyle() const; }; - class NotFoundStage : public FailStage { + /// The built-in fail-safe unhandled error stage + class DefaultErrorStage : public virtual Stage, public XmlPresenter { public: - NotFoundStage(const CgiEnvironment *, const XmlScriptParser::NotFound &); - virtual ~NotFoundStage(); + DefaultErrorStage(const CgiEnvironment *, const std::exception &); + ~DefaultErrorStage(); virtual XmlDocPtr getDataDocument() const; virtual HttpHeaderPtr getHeader() const; + virtual StagePtr run(); virtual const Glib::ustring & getResponseRootNodeName() const; + virtual const Glib::ustring & getResponseStyle() const; private: static const Glib::ustring resp; + const CgiEnvironment * e; + char * buf; + std::string what; }; - class ErrorStage : public FailStage { + /// Custom unhandled error handling stage + class CustomErrorStage : public DefaultErrorStage, public PresentStage { public: - ErrorStage(const CgiEnvironment *, const std::exception &); - virtual ~ErrorStage(); - + CustomErrorStage(const CgiEnvironment *, const std::exception &); + virtual StagePtr run(); virtual XmlDocPtr getDataDocument() const; virtual HttpHeaderPtr getHeader() const; virtual const Glib::ustring & getResponseRootNodeName() const; - private: - static const Glib::ustring resp; + virtual const Glib::ustring & getResponseStyle() const; }; + mutable StagePtr currentStage; mutable UUID sessionID; }; diff --git a/project2/cgi/cgiEnvironment.cpp b/project2/cgi/cgiEnvironment.cpp index 43f45f2..e8d5ba3 100644 --- a/project2/cgi/cgiEnvironment.cpp +++ b/project2/cgi/cgiEnvironment.cpp @@ -28,10 +28,22 @@ CgiEnvironment::addOptions(boost::program_options::positional_options_descriptio { boost::program_options::options_description cgi("Project2 CGI options"); cgi.add_options() + ("defaultpresent", boost::program_options::value(&defaultPresent)->default_value("index"), + "The present script to use when no other is specified") + ("presentroot", boost::program_options::value(&presentRoot)->default_value("present"), + "The folder in which to find presentation scripts") + ("requestroot", boost::program_options::value(&requestRoot)->default_value("request"), + "The folder in which to find request scripts") + ("errorpresentroot", boost::program_options::value(&errorPresentRoot)->default_value("error"), + "The folder in which to find presentation scripts for error handling") ("errorcontenttype", boost::program_options::value(&errorContentType)->default_value("text/xml"), "The Content-Type to use in HTTP headers in event of an error") ("errortransformstyle", boost::program_options::value(&errorTransformStyle), "The xml-stylesheet to specify in the data document in event of an error") + ("notfoundpresent", boost::program_options::value(¬FoundPresent), + "The present script to use when the requested script does not exist") + ("onerrorpresent", boost::program_options::value(&onErrorPresent), + "The present script to use when the requested script (or child) fails") #ifndef NDEBUG ("dumpdatadoc", boost::program_options::value(&dumpdatadoc), "Write a copy of the data document before sending it to the web server") diff --git a/project2/cgi/cgiEnvironment.h b/project2/cgi/cgiEnvironment.h index c9b33fa..ce765bf 100644 --- a/project2/cgi/cgiEnvironment.h +++ b/project2/cgi/cgiEnvironment.h @@ -32,6 +32,12 @@ class CgiEnvironment : public Environment, public cgicc::CgiEnvironment { #endif Glib::ustring errorContentType; Glib::ustring errorTransformStyle; + std::string defaultPresent; + std::string presentRoot; + std::string requestRoot; + std::string errorPresentRoot; + std::string notFoundPresent; + std::string onErrorPresent; }; #endif diff --git a/project2/cgi/cgiHttpHeader.cpp b/project2/cgi/cgiHttpHeader.cpp new file mode 100644 index 0000000..37a48c9 --- /dev/null +++ b/project2/cgi/cgiHttpHeader.cpp @@ -0,0 +1,29 @@ +#include "cgiHttpHeader.h" +#include <boost/foreach.hpp> + +Project2HttpHeader::Project2HttpHeader(const std::string & s, const std::string & t) : + cgicc::HTTPHeader("") +{ + addHeader("Status", s); + addHeader("Content-Type", t); +} + +void +Project2HttpHeader::addHeader(const std::string & name, const Glib::ustring & value) +{ + headers.erase(name); + headers.insert(Headers::value_type(name, value)); +} + +void +Project2HttpHeader::render(std::ostream & out) const +{ + BOOST_FOREACH(const Headers::value_type & h, headers) { + out << h.first << ": " << h.second << std::endl; + } + BOOST_FOREACH(const cgicc::HTTPCookie & cookie, getCookies()) { + out << cookie << std::endl; + } + out << std::endl; +} + diff --git a/project2/cgi/cgiHttpHeader.h b/project2/cgi/cgiHttpHeader.h new file mode 100644 index 0000000..f84c707 --- /dev/null +++ b/project2/cgi/cgiHttpHeader.h @@ -0,0 +1,20 @@ +#ifndef HTTP_HEADER_H +#define HTTP_HEADER_H + +#include <cgicc/HTTPHeader.h> +#include <string> +#include <map> +#include <glibmm/ustring.h> + +class Project2HttpHeader : public cgicc::HTTPHeader { + public: + typedef std::map<std::string, const Glib::ustring> Headers; + Project2HttpHeader(const std::string & s, const std::string & t); + void addHeader(const std::string & name, const Glib::ustring & value); + void render(std::ostream & out) const; + private: + Headers headers; +}; + +#endif + diff --git a/project2/cgi/cgiStageCustomError.cpp b/project2/cgi/cgiStageCustomError.cpp new file mode 100644 index 0000000..a3fbc1f --- /dev/null +++ b/project2/cgi/cgiStageCustomError.cpp @@ -0,0 +1,44 @@ +#include "cgiAppEngine.h" +#include "cgiEnvironment.h" +#include "cgiHttpHeader.h" +#include "../logger.h" + +CgiApplicationEngine::CustomErrorStage::CustomErrorStage(const CgiEnvironment * env, const std::exception & ex) : + CgiApplicationEngine::Stage(env), + CgiApplicationEngine::DefaultErrorStage(env, ex), + CgiApplicationEngine::PresentStage(env, env->errorPresentRoot, env->onErrorPresent) +{ +} + +CgiApplicationEngine::HttpHeaderPtr +CgiApplicationEngine::CustomErrorStage::getHeader() const +{ + return CgiApplicationEngine::DefaultErrorStage::getHeader(); +} + +CgiApplicationEngine::StagePtr +CgiApplicationEngine::CustomErrorStage::run() +{ + CgiApplicationEngine::DefaultErrorStage::run(); + return CgiApplicationEngine::PresentStage::run(); +} + +const Glib::ustring & +CgiApplicationEngine::CustomErrorStage::getResponseRootNodeName() const +{ + return CgiApplicationEngine::PresentStage::getResponseRootNodeName(); +} + +CgiApplicationEngine::XmlDocPtr +CgiApplicationEngine::CustomErrorStage::getDataDocument() const +{ + return CgiApplicationEngine::PresentStage::getDataDocument(); +} + +const Glib::ustring & +CgiApplicationEngine::CustomErrorStage::getResponseStyle() const +{ + return CgiApplicationEngine::PresentStage::getResponseStyle(); +} + + diff --git a/project2/cgi/cgiStageCustomNotFound.cpp b/project2/cgi/cgiStageCustomNotFound.cpp new file mode 100644 index 0000000..a2d33dc --- /dev/null +++ b/project2/cgi/cgiStageCustomNotFound.cpp @@ -0,0 +1,43 @@ +#include "cgiAppEngine.h" +#include "cgiEnvironment.h" +#include "cgiHttpHeader.h" +#include "../logger.h" + +CgiApplicationEngine::CustomNotFoundStage::CustomNotFoundStage(const CgiEnvironment * env, const XmlScriptParser::NotFound & notfound) : + CgiApplicationEngine::Stage(env), + CgiApplicationEngine::DefaultNotFoundStage(env, notfound), + CgiApplicationEngine::PresentStage(env, env->errorPresentRoot, env->notFoundPresent) +{ +} + +CgiApplicationEngine::HttpHeaderPtr +CgiApplicationEngine::CustomNotFoundStage::getHeader() const +{ + return CgiApplicationEngine::DefaultNotFoundStage::getHeader(); +} + +CgiApplicationEngine::StagePtr +CgiApplicationEngine::CustomNotFoundStage::run() +{ + CgiApplicationEngine::DefaultNotFoundStage::run(); + return CgiApplicationEngine::PresentStage::run(); +} + +const Glib::ustring & +CgiApplicationEngine::CustomNotFoundStage::getResponseRootNodeName() const +{ + return CgiApplicationEngine::PresentStage::getResponseRootNodeName(); +} + +CgiApplicationEngine::XmlDocPtr +CgiApplicationEngine::CustomNotFoundStage::getDataDocument() const +{ + return CgiApplicationEngine::PresentStage::getDataDocument(); +} + +const Glib::ustring & +CgiApplicationEngine::CustomNotFoundStage::getResponseStyle() const +{ + return CgiApplicationEngine::PresentStage::getResponseStyle(); +} + diff --git a/project2/cgi/cgiStageDefaultError.cpp b/project2/cgi/cgiStageDefaultError.cpp new file mode 100644 index 0000000..c881da1 --- /dev/null +++ b/project2/cgi/cgiStageDefaultError.cpp @@ -0,0 +1,52 @@ +#include "cgiAppEngine.h" +#include "cgiHttpHeader.h" +#include "../logger.h" +#include "cgiEnvironment.h" +#include <cxxabi.h> + +const Glib::ustring CgiApplicationEngine::DefaultErrorStage::resp("error"); + +CgiApplicationEngine::DefaultErrorStage::DefaultErrorStage(const CgiEnvironment * env, const std::exception & ex) : + CgiApplicationEngine::Stage(env), + buf(__cxxabiv1::__cxa_demangle(typeid(ex).name(), NULL, NULL, NULL)), + what(ex.what()) +{ +} + +CgiApplicationEngine::DefaultErrorStage::~DefaultErrorStage() +{ + free(buf); +} + +CgiApplicationEngine::HttpHeaderPtr +CgiApplicationEngine::DefaultErrorStage::getHeader() const +{ + return HttpHeaderPtr(new Project2HttpHeader("500 Internal Server Error", e->errorContentType)); +} + +CgiApplicationEngine::StagePtr +CgiApplicationEngine::DefaultErrorStage::run() +{ + addField("error-type", e->getXmlPrefix(), buf); + addField("error-what", e->getXmlPrefix(), what.c_str()); + return NULL; +} + +const Glib::ustring & +CgiApplicationEngine::DefaultErrorStage::getResponseRootNodeName() const +{ + return resp; +} + +CgiApplicationEngine::XmlDocPtr +CgiApplicationEngine::DefaultErrorStage::getDataDocument() const +{ + return XmlPresenter::getDataDocument(); +} + +const Glib::ustring & +CgiApplicationEngine::DefaultErrorStage::getResponseStyle() const +{ + return e->errorTransformStyle; +} + diff --git a/project2/cgi/cgiStageDefaultNotFound.cpp b/project2/cgi/cgiStageDefaultNotFound.cpp new file mode 100644 index 0000000..f32ad1f --- /dev/null +++ b/project2/cgi/cgiStageDefaultNotFound.cpp @@ -0,0 +1,44 @@ +#include "cgiAppEngine.h" +#include "cgiEnvironment.h" +#include "cgiHttpHeader.h" +#include "../logger.h" + +CgiApplicationEngine::DefaultNotFoundStage::DefaultNotFoundStage(const CgiEnvironment * env, const XmlScriptParser::NotFound & notfound) : + CgiApplicationEngine::Stage(env), + nf(notfound) +{ + Logger()->messagef(LOG_ERR, "%s: Resource not found: %s", __FUNCTION__, nf.what()); +} + +CgiApplicationEngine::HttpHeaderPtr +CgiApplicationEngine::DefaultNotFoundStage::getHeader() const +{ + return HttpHeaderPtr(new Project2HttpHeader("404 Not found", e->errorContentType)); +} + +CgiApplicationEngine::StagePtr +CgiApplicationEngine::DefaultNotFoundStage::run() +{ + addField("missing-resource", e->getXmlPrefix(), nf.what()); + return NULL; +} + +const Glib::ustring CgiApplicationEngine::DefaultNotFoundStage::resp("notfound"); +const Glib::ustring & +CgiApplicationEngine::DefaultNotFoundStage::getResponseRootNodeName() const +{ + return resp; +} + +CgiApplicationEngine::XmlDocPtr +CgiApplicationEngine::DefaultNotFoundStage::getDataDocument() const +{ + return XmlPresenter::getDataDocument(); +} + +const Glib::ustring & +CgiApplicationEngine::DefaultNotFoundStage::getResponseStyle() const +{ + return e->errorTransformStyle; +} + diff --git a/project2/cgi/cgiStageInitial.cpp b/project2/cgi/cgiStageInitial.cpp new file mode 100644 index 0000000..a9315bc --- /dev/null +++ b/project2/cgi/cgiStageInitial.cpp @@ -0,0 +1,19 @@ +#include "cgiAppEngine.h" +#include "cgiEnvironment.h" + +CgiApplicationEngine::InitialStage::InitialStage(const CgiEnvironment * env) : + CgiApplicationEngine::Stage(env) +{ +} + +CgiApplicationEngine::StagePtr +CgiApplicationEngine::InitialStage::run() +{ + if (e->getRequestMethod() == "POST") { + return new RequestStage(e, e->elems[0]); + } + else { + return new PresentStage(e, e->elems.empty() ? e->defaultPresent : e->elems[0]); + } +} + diff --git a/project2/cgi/cgiStagePresent.cpp b/project2/cgi/cgiStagePresent.cpp new file mode 100644 index 0000000..9dcf124 --- /dev/null +++ b/project2/cgi/cgiStagePresent.cpp @@ -0,0 +1,44 @@ +#include "cgiAppEngine.h" +#include "cgiEnvironment.h" +#include "cgiHttpHeader.h" +#include <boost/foreach.hpp> + +CgiApplicationEngine::PresentStage::PresentStage(const CgiEnvironment * e, const std::string & id) : + CgiApplicationEngine::Stage(e), + XmlProcessPresenter(e->presentRoot, id, false) +{ +} + +CgiApplicationEngine::PresentStage::PresentStage(const CgiEnvironment * e, const std::string & group, const std::string & id) : + CgiApplicationEngine::Stage(e), + XmlProcessPresenter(group, id, false) +{ +} + +CgiApplicationEngine::StagePtr +CgiApplicationEngine::PresentStage::run() +{ + BOOST_FOREACH(ParamCheckers::value_type pc, parameterChecks.get<bySOOrder>()) { + if (!pc->performCheck()) { + return new PresentStage(e, pc->present); + } + } + execute(); + return NULL; +} + +CgiApplicationEngine::HttpHeaderPtr +CgiApplicationEngine::PresentStage::getHeader() const +{ + Project2HttpHeader * header = new Project2HttpHeader("200 OK", contentType); + header->addHeader("Cache-control", "no-cache"); + return HttpHeaderPtr(header); +} + +CgiApplicationEngine::XmlDocPtr +CgiApplicationEngine::PresentStage::getDataDocument() const +{ + return XmlProcessPresenter::getDataDocument(); +} + + diff --git a/project2/cgi/cgiStageRequest.cpp b/project2/cgi/cgiStageRequest.cpp new file mode 100644 index 0000000..6602527 --- /dev/null +++ b/project2/cgi/cgiStageRequest.cpp @@ -0,0 +1,60 @@ +#include "cgiAppEngine.h" +#include "cgiEnvironment.h" +#include "cgiHttpHeader.h" +#include "../xmlObjectLoader.h" +#include <boost/foreach.hpp> + +CgiApplicationEngine::RequestStage::RequestStage(const CgiEnvironment * e, const std::string & id) : + CgiApplicationEngine::Stage(e) +{ + XmlScriptParser request(e->requestRoot, id, false); + xmlpp::Element * requestRoot = request.get_document()->get_root_node(); + present = requestRoot->get_attribute_value("present"); + rollbackBeforeHandle = requestRoot->get_attribute_value("rollbackBeforeHandle") == "true"; + localErrorHandling = requestRoot->get_attribute_value("errorHandling") == "local"; + + LoaderBase loader(ApplicationEngine::getCurrent()->env()->getXmlNamespace(), true); + loader.supportedStorers.insert(Storer::into(¶meterChecks)); + loader.supportedStorers.insert(Storer::into(&rowSets)); + loader.supportedStorers.insert(Storer::into(&tasks)); + loader.collectAll(this, requestRoot, true); +} + +CgiApplicationEngine::StagePtr +CgiApplicationEngine::RequestStage::run() +{ + BOOST_FOREACH(const ParamCheckers::value_type & pc, parameterChecks.get<bySOOrder>()) { + if (!pc->performCheck()) { + return new PresentStage(e, pc->present); + } + } + RequestHost::run(); + return present.empty() ? NULL : new PresentStage(e, present); +} + +CgiApplicationEngine::HttpHeaderPtr +CgiApplicationEngine::RequestStage::getHeader() const +{ + return HttpHeaderPtr(new Project2HttpHeader("200 OK", "text/xml")); +} + +CgiApplicationEngine::XmlDocPtr +CgiApplicationEngine::RequestStage::getDataDocument() const +{ + return XmlPresenter::getDataDocument(); +} + +const Glib::ustring CgiApplicationEngine::RequestStage::resp("request"); +const Glib::ustring CgiApplicationEngine::RequestStage::style; +const Glib::ustring & +CgiApplicationEngine::RequestStage::getResponseRootNodeName() const +{ + return resp; +} +const Glib::ustring & +CgiApplicationEngine::RequestStage::getResponseStyle() const +{ + return style; +} + + diff --git a/project2/cgi/p2webFCgi.cpp b/project2/cgi/p2webFCgi.cpp index d501787..d1aa29e 100644 --- a/project2/cgi/p2webFCgi.cpp +++ b/project2/cgi/p2webFCgi.cpp @@ -1,7 +1,6 @@ #include "cgiCommon.h" #include "FCgiIO.h" #include "../xmlObjectLoader.h" -#include "../logger.h" time_t lastPeriodic = 0; time_t periodicDelay = 600; diff --git a/project2/commonObjects.cpp b/project2/commonObjects.cpp index b6a3b7d..d661588 100644 --- a/project2/commonObjects.cpp +++ b/project2/commonObjects.cpp @@ -1,4 +1,5 @@ #include "commonObjects.h" +#include "appEngine.h" #include "xmlObjectLoader.h" #include "xmlScriptParser.h" @@ -21,9 +22,9 @@ CommonObjects::getSource(const std::string & name) const CommonObjects::DataSources::index<bySOName>::type::const_iterator CommonObjects::loadDataSource(const std::string & name) const { - XmlScriptParser xml("datasources", name, true); + XmlScriptParser xml(ApplicationEngine::getCurrent()->env()->getDatasourceRoot(), name, true); - LoaderBase loader("http://project2.randomdan.homeip.net", true); + LoaderBase loader(ApplicationEngine::getCurrent()->env()->getXmlNamespace(), true); loader.supportedStorers.insert(Storer::into(&datasources)); loader.collectAll(xml.get_document()->get_root_node(), false); diff --git a/project2/console/consoleAppEngine.cpp b/project2/console/consoleAppEngine.cpp index a45f704..7a08f69 100644 --- a/project2/console/consoleAppEngine.cpp +++ b/project2/console/consoleAppEngine.cpp @@ -64,7 +64,7 @@ ConsoleApplicationEngine::ConsoleApplicationEngine(const ConsoleEnvironment * en rollbackBeforeHandle = requestRoot->get_attribute_value("rollbackBeforeHandle") == "true"; localErrorHandling = requestRoot->get_attribute_value("errorHandling") == "local"; - LoaderBase loader("http://project2.randomdan.homeip.net", true); + LoaderBase loader(ApplicationEngine::getCurrent()->env()->getXmlNamespace(), true); loader.supportedStorers.insert(Storer::into(¶meterChecks)); loader.supportedStorers.insert(Storer::into(&tasks)); loader.supportedStorers.insert(Storer::into(&rowSets)); diff --git a/project2/environment.cpp b/project2/environment.cpp index a3985ca..a3a3d5e 100644 --- a/project2/environment.cpp +++ b/project2/environment.cpp @@ -28,6 +28,12 @@ Environment::init() "Log to syslog with level <arg> (default OFF)") ("consoleloglevel,c", po::value(&clLevel)->default_value(LOG_WARNING), "Log to console with level <arg> (default WARNING)") + ("datasourceroot", boost::program_options::value(&datasourceRoot)->default_value("datasources"), + "The folder in which to find datasource definitions") + ("xmlnamespace", boost::program_options::value(&xmlNamespace)->default_value("http://project2.randomdan.homeip.net"), + "The XML namespace to use for Project2 components and responses") + ("xmlprefix", boost::program_options::value(&xmlPrefix)->default_value("project2"), + "The XML namespace prefix to use for the Project2 XML namespace") ; allOptions.add(common).add(addOptions(posOptions)); optionsBuilt = true; @@ -58,3 +64,21 @@ Environment::~Environment() Logger()->clear(); } +const std::string & +Environment::getDatasourceRoot() const +{ + return datasourceRoot; +} + +const Glib::ustring & +Environment::getXmlNamespace() const +{ + return xmlNamespace; +} + +const Glib::ustring & +Environment::getXmlPrefix() const +{ + return xmlPrefix; +} + diff --git a/project2/environment.h b/project2/environment.h index 99f9253..5c66518 100644 --- a/project2/environment.h +++ b/project2/environment.h @@ -13,6 +13,10 @@ class Environment { void init(); + const std::string & getDatasourceRoot() const; + const Glib::ustring & getXmlNamespace() const; + const Glib::ustring & getXmlPrefix() const; + virtual Glib::ustring getParamUri(unsigned int idx) const = 0; virtual Glib::ustring getParamQuery(const std::string & idx) const = 0; @@ -30,6 +34,10 @@ class Environment { static int clLevel; static int slLevel; + + std::string datasourceRoot; + Glib::ustring xmlNamespace; + Glib::ustring xmlPrefix; }; #endif diff --git a/project2/if.cpp b/project2/if.cpp index b1b98a6..01368cc 100644 --- a/project2/if.cpp +++ b/project2/if.cpp @@ -1,4 +1,5 @@ #include "if.h" +#include "appEngine.h" #include "logger.h" #include "xmlObjectLoader.h" #include <boost/foreach.hpp> @@ -10,7 +11,7 @@ SimpleMessageException(IfModeIsNonsense); IfSet::IfSet(const xmlpp::Element * e) : mode(e->get_attribute_value("mode") == "or" ? Or : And) { - LoaderBase loader("http://project2.randomdan.homeip.net", true); + LoaderBase loader(ApplicationEngine::getCurrent()->env()->getXmlNamespace(), true); loader.supportedStorers.insert(Storer::into(&checks)); loader.collectAll(e, true, IgnoreUnsupported); } @@ -44,7 +45,7 @@ If::If(const xmlpp::Element * e) : IfSet(e), localErrorHandling(e->get_attribute_value("errorHandling") == "local") { - LoaderBase loader("http://project2.randomdan.homeip.net", true); + LoaderBase loader(ApplicationEngine::getCurrent()->env()->getXmlNamespace(), true); loader.supportedStorers.insert(Storer::into(&subNOEs)); loader.supportedStorers.insert(Storer::into(&subViews)); loader.collectAll(e, true, IgnoreUnsupported); diff --git a/project2/iterate.cpp b/project2/iterate.cpp index ccf289e..b06d7e1 100644 --- a/project2/iterate.cpp +++ b/project2/iterate.cpp @@ -1,4 +1,5 @@ #include "iterate.h" +#include "appEngine.h" #include <boost/foreach.hpp> #include "xmlObjectLoader.h" @@ -10,7 +11,7 @@ Iterate::Iterate(const xmlpp::Element * p) : RowProcessor(p), localErrorHandling(p->get_attribute_value("errorHandling") == "local") { - LoaderBase loader("http://project2.randomdan.homeip.net", true); + LoaderBase loader(ApplicationEngine::getCurrent()->env()->getXmlNamespace(), true); loader.supportedStorers.insert(Storer::into(&subNOEs)); loader.collectAll(p, true, IgnoreUnsupported); } diff --git a/project2/rowView.cpp b/project2/rowView.cpp index e036dd7..541bf5e 100644 --- a/project2/rowView.cpp +++ b/project2/rowView.cpp @@ -1,4 +1,5 @@ #include "rowView.h" +#include "appEngine.h" #include "presenter.h" #include "xmlObjectLoader.h" #include <boost/foreach.hpp> @@ -20,7 +21,7 @@ RowView::RowView(const xmlpp::Element * p) : Variable::makeParent(elem->get_child_text()->get_content(), elem->get_attribute_value("source") == "attribute", 0))); } } - LoaderBase loader("http://project2.randomdan.homeip.net", true); + LoaderBase loader(ApplicationEngine::getCurrent()->env()->getXmlNamespace(), true); loader.supportedStorers.insert(Storer::into(&subViews)); loader.collectAll(p, true, IgnoreUnsupported); } diff --git a/project2/sqlMergeTask.cpp b/project2/sqlMergeTask.cpp index 0160a7f..ab8546b 100644 --- a/project2/sqlMergeTask.cpp +++ b/project2/sqlMergeTask.cpp @@ -1,4 +1,5 @@ #include "sqlMergeTask.h" +#include "appEngine.h" #include "commonObjects.h" #include "rdbmsDataSource.h" #include "exceptions.h" @@ -56,7 +57,7 @@ SqlMergeTask::SqlMergeTask(const xmlpp::Element * p) : dtable(p->get_attribute_value("targettable")), dtablet(stringf("tmp_%s_%d", dtable.c_str(), getpid())) { - LoaderBase loader("http://project2.randomdan.homeip.net", true); + LoaderBase loader(ApplicationEngine::getCurrent()->env()->getXmlNamespace(), true); loader.supportedStorers.insert(Storer::into(&sources)); loader.collectAll(p, true); diff --git a/project2/xmlPresenter.cpp b/project2/xmlPresenter.cpp index 244c96c..494a88e 100644 --- a/project2/xmlPresenter.cpp +++ b/project2/xmlPresenter.cpp @@ -1,6 +1,7 @@ #include "xmlPresenter.h" #include "xmlObjectLoader.h" #include "variables.h" +#include "appEngine.h" XmlPresenter::XmlPresenter() : responseDoc(XmlDocumentPtr(new xmlpp::Document("1.0"))) @@ -12,17 +13,21 @@ XmlPresenter::~XmlPresenter() } void -XmlPresenter::initDoc() +XmlPresenter::createDoc() const { - nodeStack.push_back(responseDoc->create_root_node(getResponseRootNodeName())); - xmlNewNs(nodeStack.back()->cobj(), BAD_CAST "http://project2.randomdan.homeip.net", BAD_CAST "project2"); - // XSLT Style - char * buf; - if (!getResponseStyle().empty() && asprintf(&buf, "type=\"text/xsl\" href=\"%s\"", - getResponseStyle().c_str()) > 0) { - xmlAddPrevSibling(nodeStack.back()->cobj(), - xmlNewDocPI(responseDoc->cobj(), BAD_CAST "xml-stylesheet", BAD_CAST buf)); - free(buf); + if (nodeStack.empty()) { + nodeStack.push_back(responseDoc->create_root_node(getResponseRootNodeName())); + xmlNewNs(nodeStack.back()->cobj(), + BAD_CAST ApplicationEngine::getCurrent()->env()->getXmlNamespace().c_str(), + BAD_CAST ApplicationEngine::getCurrent()->env()->getXmlPrefix().c_str()); + // XSLT Style + char * buf; + if (!getResponseStyle().empty() && asprintf(&buf, "type=\"text/xsl\" href=\"%s\"", + getResponseStyle().c_str()) > 0) { + xmlAddPrevSibling(nodeStack.back()->cobj(), + xmlNewDocPI(responseDoc->cobj(), BAD_CAST "xml-stylesheet", BAD_CAST buf)); + free(buf); + } } } @@ -32,12 +37,11 @@ XmlProcessPresenter::XmlProcessPresenter(const std::string & group, const std::s responseStyle(present.get_document()->get_root_node()->get_attribute_value("style")), contentType(present.get_document()->get_root_node()->get_attribute_value("contenttype")) { - LoaderBase loader("http://project2.randomdan.homeip.net", true); + LoaderBase loader(ApplicationEngine::getCurrent()->env()->getXmlNamespace(), true); loader.supportedStorers.insert(Storer::into(&rowSets)); loader.supportedStorers.insert(Storer::into(&views)); loader.supportedStorers.insert(Storer::into(¶meterChecks)); loader.collectAll(this, present.get_document()->get_root_node(), true); - initDoc(); } XmlProcessPresenter::~XmlProcessPresenter() @@ -65,6 +69,7 @@ XmlPresenter::getDataDocument() const void XmlPresenter::pushSub(const Glib::ustring & name, const Glib::ustring & ns) const { + createDoc(); nodeStack.push_back(nodeStack.back()->add_child(name, ns)); } @@ -72,6 +77,7 @@ void XmlPresenter::addAttr(const Glib::ustring & name, const Glib::ustring & ns, const VariableType & value) const { if (!boost::get<Null>(&value)) { + createDoc(); nodeStack.back()->set_attribute(name, value, ns); } } @@ -80,6 +86,7 @@ void XmlPresenter::setText(const VariableType & value) const { if (!boost::get<Null>(&value)) { + createDoc(); nodeStack.back()->set_child_text(value); } } diff --git a/project2/xmlPresenter.h b/project2/xmlPresenter.h index 8ced38f..cc1312a 100644 --- a/project2/xmlPresenter.h +++ b/project2/xmlPresenter.h @@ -23,11 +23,9 @@ class XmlPresenter : public Presenter { virtual const Glib::ustring & getResponseRootNodeName() const = 0; virtual const Glib::ustring & getResponseStyle() const = 0; - protected: - void initDoc(); - XmlDocumentPtr responseDoc; - private: + void createDoc() const; + XmlDocumentPtr responseDoc; mutable std::vector<xmlpp::Element *> nodeStack; }; |