From b72424fca7a6af6ff7921101c450850fef875152 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Sun, 6 Mar 2016 13:52:48 +0300 Subject: Support multiple instances of brep in a single Apache instance --- web/apache/service.txx | 156 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 135 insertions(+), 21 deletions(-) (limited to 'web/apache/service.txx') 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 // getppid() +#include // kill() + #include +#include // move() #include namespace web @@ -11,37 +15,147 @@ namespace web namespace apache { template + void service:: + init_worker (log& l) + { + const std::string func_name ( + "web::apache::service<" + name_ + ">::init_worker"); + + try + { + const M* exemplar (dynamic_cast (&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 ' 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 (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 int service:: - handle (request& r, log& l) noexcept + request_handler (request_rec* r) noexcept + { + auto srv (instance ()); + 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 (rq, id, lg); + } + + template + 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 (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 (exemplar)); + assert (e != nullptr); + + M m (*e); - if (static_cast (m).handle (r, r, l)) - return r.flush (); + if (static_cast (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 ()); } } } -- cgit v1.1