From d7f9b55da365be26128ae9d4be316d4a99393c9f Mon Sep 17 00:00:00 2001 From: randomdan Date: Mon, 13 Feb 2012 22:49:51 +0000 Subject: Persist the CGI Environment over many iterations of the app engine, reloading the configuration only when needed --- project2/cgi/cgiAppEngine.cpp | 16 +++++--------- project2/cgi/cgiAppEngine.h | 10 ++++----- project2/cgi/cgiCommon.cpp | 9 ++++---- project2/cgi/cgiCommon.h | 3 ++- project2/cgi/cgiEnvironment.cpp | 48 ++++++++++++++++++++++++++++++++++++---- project2/cgi/cgiEnvironment.h | 22 +++++++++++------- project2/cgi/p2webCgi.cpp | 3 ++- project2/cgi/p2webFCgi.cpp | 3 ++- project2/cgi/testCgi.cpp | 3 ++- project2/common/environment.cpp | 47 +++++++++++++++++++++------------------ project2/common/environment.h | 8 ++++--- project2/common/optionsSource.h | 1 + project2/console/claOptions.cpp | 10 +++++++++ project2/files/optionsSource.cpp | 20 +++++++++++++++-- project2/files/optionsSource.h | 3 +++ 15 files changed, 144 insertions(+), 62 deletions(-) diff --git a/project2/cgi/cgiAppEngine.cpp b/project2/cgi/cgiAppEngine.cpp index c08eb3e..07aa737 100644 --- a/project2/cgi/cgiAppEngine.cpp +++ b/project2/cgi/cgiAppEngine.cpp @@ -15,22 +15,18 @@ typedef std::string SValue; SimpleMessageException(UnknownDomain); -static UUID -getSessionID(const std::vector & cookies) { - BOOST_FOREACH(const cgicc::HTTPCookie & c, cookies) { - if (c.getName() == SESSIONID) { - return c.getValue(); - } - } - return UUID(); -} CgiApplicationEngine::CgiApplicationEngine(const CgiEnvironment * e, std::ostream & io) : _env(e), sessionsContainer(LoaderBase::getLoader(e->sessionModule)->open()), IO(io), outputCachingActive(false) { - cursession = sessionsContainer->GetSession(getSessionID(e->getCookieList())); + try { + cursession = sessionsContainer->GetSession(e->getCookieValue(SESSIONID)); + } + catch (const NoSuchCookie &) { + cursession = sessionsContainer->GetSession(UUID()); + } currentStage = NextStage(new InitialStage(e)); } diff --git a/project2/cgi/cgiAppEngine.h b/project2/cgi/cgiAppEngine.h index b362ece..154ca09 100644 --- a/project2/cgi/cgiAppEngine.h +++ b/project2/cgi/cgiAppEngine.h @@ -15,8 +15,9 @@ #include #include "cgiOutputOptions.h" #include "cgiHttpHeader.h" +#include "cgiEnvironment.h" +#include -class CgiEnvironment; class Session; namespace cgicc { class HTTPHeader; @@ -43,10 +44,9 @@ class CgiApplicationEngine : public ApplicationEngine, public TransformChainLink SessionContainerPtr sessionsContainer; // Helpers void addVarToPresenter(const MultiRowSetPresenter * p, const Glib::ustring & name, const VariableType &) const; - typedef std::string (cgicc::CgiEnvironment::*StrEnvGetter)() const; - template - void addEnvToPresenter(const MultiRowSetPresenter * p, const char * name, X (cgicc::CgiEnvironment::*getter)() const) const { - addVarToPresenter(p, name, (_env->*getter)()); + template + void addEnvToPresenter(const MultiRowSetPresenter * p, const char * name, X (Y::*getter)() const) const { + addVarToPresenter(p, name, (_env->cgi->getEnvironment().*getter)()); } public: diff --git a/project2/cgi/cgiCommon.cpp b/project2/cgi/cgiCommon.cpp index 7559ea7..ac3e6d4 100644 --- a/project2/cgi/cgiCommon.cpp +++ b/project2/cgi/cgiCommon.cpp @@ -5,7 +5,6 @@ #include #include #include -#include "cgiEnvironment.h" #include "cgiAppEngine.h" #include #include @@ -38,13 +37,13 @@ doExceptionReporting(const E & e, std::ostream & IO) } void -cgiServe(cgicc::CgiInput * i, std::ostream & IO) +cgiServe(cgicc::CgiInput * i, CgiEnvironment * env, std::ostream & IO) { cgicc::Cgicc cgi(i); - CgiEnvironment env(&cgi); - env.init(); + env->setCGICC(&cgi); + env->init(); try { - CgiApplicationEngine app(&env, IO); + CgiApplicationEngine app(env, IO); LoaderBase::onAllComponents(boost::bind(&ComponentLoader::onBefore, _1)); Logger()->messagef(LOG_DEBUG, "%s: Processing request", __FUNCTION__); diff --git a/project2/cgi/cgiCommon.h b/project2/cgi/cgiCommon.h index 489e3fb..ce6108e 100644 --- a/project2/cgi/cgiCommon.h +++ b/project2/cgi/cgiCommon.h @@ -1,5 +1,6 @@ #include #include +#include "cgiEnvironment.h" -void cgiServe(cgicc::CgiInput * i, std::ostream & o); +void cgiServe(cgicc::CgiInput * i, CgiEnvironment *, std::ostream & o); diff --git a/project2/cgi/cgiEnvironment.cpp b/project2/cgi/cgiEnvironment.cpp index 001d4bd..2e977b2 100644 --- a/project2/cgi/cgiEnvironment.cpp +++ b/project2/cgi/cgiEnvironment.cpp @@ -23,10 +23,7 @@ makeVector(const boost::filesystem::path & y) return r; } -CgiEnvironment::CgiEnvironment(cgicc::Cgicc * c) : - cgicc::CgiEnvironment(c->getEnvironment()), - elems(makeVector(boost::filesystem::path(getRedirectURL()))), - cgi(c), +CgiEnvironment::CgiEnvironment() : cgiOptions("Project2 CGI options"), hpi(new HostnamePlatformIdentifier()) { @@ -69,6 +66,48 @@ CgiEnvironment::~CgiEnvironment() { } +void +CgiEnvironment::setCGICC(const cgicc::Cgicc * c) +{ + cgi = c; + elems = makeVector(boost::filesystem::path(getRedirectURL())); +} + +std::string +CgiEnvironment::getCookieValue(const std::string & name) const +{ + BOOST_FOREACH(const cgicc::HTTPCookie & c, cgi->getEnvironment().getCookieList()) { + if (c.getName() == name) { + return c.getValue(); + } + } + throw NoSuchCookie(name); +} + +std::string +CgiEnvironment::getRequestMethod() const +{ + return cgi->getEnvironment().getRequestMethod(); +} + +std::string +CgiEnvironment::getRedirectURL() const +{ + return cgi->getEnvironment().getRedirectURL(); +} + +std::string +CgiEnvironment::getScriptName() const +{ + return cgi->getEnvironment().getScriptName(); +} + +std::string +CgiEnvironment::getServerName() const +{ + return cgi->getEnvironment().getServerName(); +} + const Glib::ustring & CgiEnvironment::platform() const { @@ -125,6 +164,7 @@ HostnamePlatformIdentifier::reset() const { if (platform) { delete platform; + platform = NULL; } } diff --git a/project2/cgi/cgiEnvironment.h b/project2/cgi/cgiEnvironment.h index 78f8730..27b1694 100644 --- a/project2/cgi/cgiEnvironment.h +++ b/project2/cgi/cgiEnvironment.h @@ -6,6 +6,8 @@ #include "environment.h" #include +SimpleMessageException(NoSuchCookie); + namespace cgicc { class Cgicc; } @@ -22,19 +24,23 @@ class HostnamePlatformIdentifier : public Options::Target { mutable Glib::ustring * platform; }; -class CgiEnvironment : public Environment, public cgicc::CgiEnvironment { +class CgiEnvironment : public Environment { public: - CgiEnvironment(cgicc::Cgicc *); + CgiEnvironment(); virtual ~CgiEnvironment(); Glib::ustring getParamUri(unsigned int idx) const; unsigned int getParamUriCount() 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::string getServerName() const; + std::string getScriptName() const; + std::string getRedirectURL() const; + std::string getRequestMethod() const; + std::string getCookieValue(const std::string & name) const; + void setCGICC(const cgicc::Cgicc *); + const cgicc::Cgicc * cgi; std::vector elems; - const cgicc::Cgicc * const cgi; private: const Options & engineOptions() const; @@ -52,9 +58,9 @@ class CgiEnvironment : public Environment, public cgicc::CgiEnvironment { std::string errorPresentRoot; std::string notFoundPresent; std::string onErrorPresent; - std::string defaultPresenter; - std::string sessionModule; - std::string outputEncoding; + std::string defaultPresenter; + std::string sessionModule; + std::string outputEncoding; }; #endif diff --git a/project2/cgi/p2webCgi.cpp b/project2/cgi/p2webCgi.cpp index 0248df6..646d08b 100644 --- a/project2/cgi/p2webCgi.cpp +++ b/project2/cgi/p2webCgi.cpp @@ -6,7 +6,8 @@ int main(void) { LoaderBase::onAllComponents(boost::bind(&ComponentLoader::onBegin, _1)); - cgiServe(NULL, std::cout); + CgiEnvironment env; + cgiServe(NULL, &env, std::cout); LoaderBase::onAllComponents(boost::bind(&ComponentLoader::onIteration, _1)); LoaderBase::onAllComponents(boost::bind(&ComponentLoader::onPeriodic, _1)); LoaderBase::onAllComponents(boost::bind(&ComponentLoader::onIdle, _1)); diff --git a/project2/cgi/p2webFCgi.cpp b/project2/cgi/p2webFCgi.cpp index 3b833ed..a1786d2 100644 --- a/project2/cgi/p2webFCgi.cpp +++ b/project2/cgi/p2webFCgi.cpp @@ -40,11 +40,12 @@ main(void) fprintf(stderr, "Failed to set signal handler\n"); } alarm(60); + CgiEnvironment env; LoaderBase::onAllComponents(boost::bind(&ComponentLoader::onBegin, _1)); while (FCGX_Accept_r(&request) == 0) { alarm(0); cgicc::FCgiIO IO(request); - cgiServe(&IO, IO); + cgiServe(&IO, &env, IO); alarm(60); LoaderBase::onAllComponents(boost::bind(&ComponentLoader::onIteration, _1)); if (time(NULL) > lastPeriodic + periodicDelay) { diff --git a/project2/cgi/testCgi.cpp b/project2/cgi/testCgi.cpp index 6250cb0..1d3f72c 100644 --- a/project2/cgi/testCgi.cpp +++ b/project2/cgi/testCgi.cpp @@ -75,11 +75,12 @@ class TestInput : public cgicc::CgiInput { void run() { for (int run = 0; run < runCount; run += 1) { - cgiServe(this, std::cout); + cgiServe(this, &env, std::cout); } } private: + CgiEnvironment env; Options opts; int runCount; }; diff --git a/project2/common/environment.cpp b/project2/common/environment.cpp index 2047813..c0f84a2 100644 --- a/project2/common/environment.cpp +++ b/project2/common/environment.cpp @@ -10,11 +10,11 @@ #include const Environment * Environment::currentEnv(NULL); -int Environment::clLevel(-1); -int Environment::slLevel(-1); Environment::Environment() : - commonOptions("Project2 Common options") + commonOptions("Project2 Common options"), + clLevel(-1), + slLevel(-1) { currentEnv = this; commonOptions @@ -31,6 +31,10 @@ Environment::Environment() : ("common.sessionTimeOut", Options::value(&sessionTimeOut, 3600), "The time after which idle sessions are forgotten") ; + typedef std::map > ConfigParsersMap; + BOOST_FOREACH(const ConfigParsersMap::value_type & cp, *LoaderBase::objLoaders()) { + configs.push_back(cp.second->create()); + } } typedef std::vector AllOptions; @@ -66,26 +70,27 @@ class DefaultConfigConsumer : public ConfigConsumer { void Environment::init() { - DefaultConfigConsumer dcc; - dcc.allOptions.push_back(&commonOptions); - dcc.allOptions.push_back(&engineOptions()); - LoaderBase::onAllComponents(boost::bind(optionsHelper, &dcc.allOptions, boost::bind(&ComponentLoader::options, _1))); + if (std::find_if(configs.begin(), configs.end(), boost::bind(&OptionsSource::needReload, _1)) != configs.end()) { + DefaultConfigConsumer dcc; + dcc.allOptions.push_back(&commonOptions); + dcc.allOptions.push_back(&engineOptions()); + LoaderBase::onAllComponents(boost::bind(optionsHelper, &dcc.allOptions, boost::bind(&ComponentLoader::options, _1))); - BOOST_FOREACH(const AllOptions::value_type & v, dcc.allOptions) { - v->reset(); - } - - typedef std::map > ConfigParsersMap; - BOOST_FOREACH(const ConfigParsersMap::value_type & cp, *LoaderBase::objLoaders()) { - cp.second->create()->loadInto(dcc); - } + BOOST_FOREACH(const AllOptions::value_type & v, dcc.allOptions) { + v->reset(); + } - Logger()->clear(); - if (clLevel >= 0) { - Logger()->addLogger(new ConsoleLogDriver(stderr, clLevel, false)); - } - if (slLevel >= 0) { - Logger()->addLogger(new SyslogLogDriver(getScriptName().c_str(), slLevel)); + BOOST_FOREACH(const ConfigsMap::value_type & c, configs) { + c->loadInto(dcc); + } + Logger()->clear(); + if (clLevel >= 0) { + Logger()->addLogger(new ConsoleLogDriver(stderr, clLevel, false)); + } + if (slLevel >= 0) { + Logger()->addLogger(new SyslogLogDriver(getScriptName().c_str(), slLevel)); + } + Logger()->message(LOG_DEBUG, "Loaded configuration"); } } diff --git a/project2/common/environment.h b/project2/common/environment.h index 0c33283..894b2f8 100644 --- a/project2/common/environment.h +++ b/project2/common/environment.h @@ -5,7 +5,7 @@ #include #include #include -#include "options.h" +#include "optionsSource.h" #include "exceptions.h" #include "scripts.h" @@ -36,8 +36,10 @@ class Environment { static const Environment * currentEnv; - static int clLevel; - static int slLevel; + int clLevel; + int slLevel; + typedef std::vector ConfigsMap; + ConfigsMap configs; public: std::string datasourceRoot; diff --git a/project2/common/optionsSource.h b/project2/common/optionsSource.h index c73a500..f238a66 100644 --- a/project2/common/optionsSource.h +++ b/project2/common/optionsSource.h @@ -17,6 +17,7 @@ class ConfigConsumer { class OptionsSource : public IntrusivePtrBase { public: virtual void loadInto(const ConfigConsumer &) const = 0; + virtual bool needReload() const = 0; }; typedef boost::intrusive_ptr OptionsSourcePtr; diff --git a/project2/console/claOptions.cpp b/project2/console/claOptions.cpp index b931392..4660134 100644 --- a/project2/console/claOptions.cpp +++ b/project2/console/claOptions.cpp @@ -11,6 +11,9 @@ SimpleMessageException(UnknownOption); class CommandLineArguments : public OptionsSource { public: + CommandLineArguments() : + loadedAt(0) { + } void loadInto(const ConfigConsumer & consume) const { int argc = ConsoleEnvironment::argc; char ** argv = ConsoleEnvironment::argv; @@ -74,7 +77,14 @@ class CommandLineArguments : public OptionsSource { } } } + time(&loadedAt); + } + bool needReload() const + { + return !loadedAt; } + private: + mutable time_t loadedAt; }; // A... process first :) diff --git a/project2/files/optionsSource.cpp b/project2/files/optionsSource.cpp index 84c06dc..50e924d 100644 --- a/project2/files/optionsSource.cpp +++ b/project2/files/optionsSource.cpp @@ -5,12 +5,14 @@ #include FileOptions::FileOptions() : - file(".p2config") + file(".p2config"), + loadedAt(0) { } FileOptions::FileOptions(const Glib::ustring & f) : - file(f) + file(f), + loadedAt(0) { } @@ -53,11 +55,25 @@ FileOptions::loadInto(const ConfigConsumer & consume) const { break; } } + struct stat st; + if (stat(file.c_str(), &st) == 0) { + loadedAt = st.st_mtime; + } } catch (const Glib::FileError &) { } } +bool +FileOptions::needReload() const +{ + struct stat st; + if (stat(file.c_str(), &st) != 0) { + return true; + } + return (loadedAt != st.st_mtime); +} + // Z... process last :) DECLARE_COMPONENT_LOADER("Z_configfile", FileOptions, OptionsSourceLoader) diff --git a/project2/files/optionsSource.h b/project2/files/optionsSource.h index 722d7b9..5cd5250 100644 --- a/project2/files/optionsSource.h +++ b/project2/files/optionsSource.h @@ -9,8 +9,11 @@ class FileOptions : public OptionsSource { FileOptions(const Glib::ustring & file); void loadInto(const ConfigConsumer & consume) const; + bool needReload() const; + private: const Glib::ustring file; + mutable time_t loadedAt; }; #endif -- cgit v1.2.3