diff options
author | Karen Arutyunov <karen@codesynthesis.com> | 2016-03-06 13:52:48 +0300 |
---|---|---|
committer | Karen Arutyunov <karen@codesynthesis.com> | 2016-03-07 00:05:29 +0300 |
commit | b72424fca7a6af6ff7921101c450850fef875152 (patch) | |
tree | ac295d1e228379b1b31c6af3a84e7057f2ea96ae /web/apache/service.txx | |
parent | 0f9c65e489a7b59f76ccbf2ca6e76ab0a1012932 (diff) |
Support multiple instances of brep in a single Apache instance
Diffstat (limited to 'web/apache/service.txx')
-rw-r--r-- | web/apache/service.txx | 156 |
1 files changed, 135 insertions, 21 deletions
diff --git a/web/apache/service.txx b/web/apache/service.txx index 300a2a8..b57befc 100644 --- a/web/apache/service.txx +++ b/web/apache/service.txx @@ -2,8 +2,12 @@ // copyright : Copyright (c) 2014-2016 Code Synthesis Ltd // license : MIT; see accompanying LICENSE file +#include <unistd.h> // getppid() +#include <signal.h> // kill() + #include <http_log.h> +#include <utility> // move() #include <exception> namespace web @@ -11,37 +15,147 @@ namespace web namespace apache { template <typename M> + void service:: + init_worker (log& l) + { + const std::string func_name ( + "web::apache::service<" + name_ + ">::init_worker"); + + try + { + const M* exemplar (dynamic_cast<const M*> (&exemplar_)); + assert (exemplar != nullptr); + + // For each directory configuration context create the module exemplar + // as a deep copy of the exemplar_ member and initialize it with the + // context-specific option list. Note that there can be contexts + // having no module options specified for them and no options + // inherited from enclosing contexts. Such contexts will not appear in + // the options_ map. Meanwhile 'SetHandler <modname>' directive can be + // in effect for such contexts, and we should be ready to handle + // requests for them (by using the "root exemplar"). + // + for (const auto& o: options_) + { + const context* c (o.first); + + if (c->server != nullptr) // Is a directory configuration context. + { + auto r ( + exemplars_.emplace ( + make_context_id (c), + std::unique_ptr<module> (new M (*exemplar)))); + + r.first->second->init (o.second, l); + } + } + + // Options are not needed anymore. Free up the space. + // + options_.clear (); + + // Initialize the "root exemplar" by default (with no options). It + // will be used to handle requests for configuration contexts having + // no options specified, and no options inherited from enclosing + // contexts. + // + exemplar_.init (name_values (), l); + } + catch (const std::exception& e) + { + l.write (nullptr, 0, func_name.c_str (), APLOG_EMERG, e.what ()); + + // Terminate the root apache process. Indeed we can only try to + // terminate the process, and most likely will fail in a production + // environment, where the apache root process usually runs under root, + // and worker processes run under some other user. This is why the + // implementation should consider the possibility of not being + // initialized at the time of HTTP request processing. In such a case + // it should respond with an internal server error (500 HTTP status), + // reporting misconfiguration. + // + kill (getppid (), SIGTERM); + } + catch (...) + { + l.write (nullptr, + 0, + func_name.c_str (), + APLOG_EMERG, + "unknown error"); + + // Terminate the root apache process. + // + kill (getppid (), SIGTERM); + } + } + + template <typename M> int service:: - handle (request& r, log& l) noexcept + request_handler (request_rec* r) noexcept + { + auto srv (instance<M> ()); + if (!r->handler || srv->name_ != r->handler) return DECLINED; + + assert (r->per_dir_config != nullptr); + + // Obtain the request-associated configuration context id. + // + context_id id ( + make_context_id (ap_get_module_config (r->per_dir_config, srv))); + + assert (!is_null (id)); + + request rq (r); + log lg (r->server, srv); + return srv->template handle<M> (rq, id, lg); + } + + template <typename M> + int service:: + handle (request& rq, context_id id, log& lg) const { static const std::string func_name ( "web::apache::service<" + name_ + ">::handle"); try { - M m (static_cast<const M&> (exemplar_)); + auto i (exemplars_.find (id)); + + // Use the context-specific exemplar if found, otherwise use the + // default one. + // + const module* exemplar (i != exemplars_.end () + ? i->second.get () + : &exemplar_); + + const M* e (dynamic_cast<const M*> (exemplar)); + assert (e != nullptr); + + M m (*e); - if (static_cast<module&> (m).handle (r, r, l)) - return r.flush (); + if (static_cast<module&> (m).handle (rq, rq, lg)) + return rq.flush (); - if (!r.get_write_state ()) + if (!rq.get_write_state ()) return DECLINED; - l.write (nullptr, 0, func_name.c_str (), APLOG_ERR, - "handling declined while unbuffered content has been written"); + lg.write (nullptr, 0, func_name.c_str (), APLOG_ERR, + "handling declined while unbuffered content " + "has been written"); } catch (const invalid_request& e) { - if (!e.content.empty () && !r.get_write_state ()) + if (!e.content.empty () && !rq.get_write_state ()) { try { - r.content (e.status, e.type) << e.content; - return r.flush (); + rq.content (e.status, e.type) << e.content; + return rq.flush (); } catch (const std::exception& e) { - l.write (nullptr, 0, func_name.c_str (), APLOG_ERR, e.what ()); + lg.write (nullptr, 0, func_name.c_str (), APLOG_ERR, e.what ()); } } @@ -49,39 +163,39 @@ namespace web } catch (const std::exception& e) { - l.write (nullptr, 0, func_name.c_str (), APLOG_ERR, e.what ()); + lg.write (nullptr, 0, func_name.c_str (), APLOG_ERR, e.what ()); - if (*e.what () && !r.get_write_state ()) + if (*e.what () && !rq.get_write_state ()) { try { - r.content (HTTP_INTERNAL_SERVER_ERROR, "text/plain;charset=utf-8") + rq.content (HTTP_INTERNAL_SERVER_ERROR, "text/plain;charset=utf-8") << e.what (); - return r.flush (); + return rq.flush (); } catch (const std::exception& e) { - l.write (nullptr, 0, func_name.c_str (), APLOG_ERR, e.what ()); + lg.write (nullptr, 0, func_name.c_str (), APLOG_ERR, e.what ()); } } } catch (...) { - l.write (nullptr, 0, func_name.c_str (), APLOG_ERR, "unknown error"); + lg.write (nullptr, 0, func_name.c_str (), APLOG_ERR, "unknown error"); - if (!r.get_write_state ()) + if (!rq.get_write_state ()) { try { - r.content (HTTP_INTERNAL_SERVER_ERROR, "text/plain;charset=utf-8") + rq.content (HTTP_INTERNAL_SERVER_ERROR, "text/plain;charset=utf-8") << "unknown error"; - return r.flush (); + return rq.flush (); } catch (const std::exception& e) { - l.write (nullptr, 0, func_name.c_str (), APLOG_ERR, e.what ()); + lg.write (nullptr, 0, func_name.c_str (), APLOG_ERR, e.what ()); } } } |