From 04c1324c57692dfd22fab211a7443aaf484f07ce Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 27 Apr 2015 13:52:25 +0200 Subject: Implement module configuration, cleanup the code --- web/apache/service | 167 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 142 insertions(+), 25 deletions(-) (limited to 'web/apache/service') diff --git a/web/apache/service b/web/apache/service index 688f8f1..d003767 100644 --- a/web/apache/service +++ b/web/apache/service @@ -5,15 +5,18 @@ #ifndef WEB_APACHE_SERVICE #define WEB_APACHE_SERVICE -#include -#include -#include +#include // memset() +#include // getppid() +#include // kill() #include #include -#include +#include +#include +#include +#include #include #include @@ -21,13 +24,13 @@ namespace web { namespace apache { - class service : ::module + class service: ::module { public: // Note that the module exemplar is stored by-reference. // template - service (const std::string& name, const M& exemplar) + service (const std::string& name, M& exemplar) : ::module { STANDARD20_MODULE_STUFF, @@ -35,25 +38,53 @@ namespace web nullptr, nullptr, nullptr, - nullptr, + directives_, ®ister_hooks }, name_ (name), - exemplar_ (exemplar) - + exemplar_ (exemplar), + conf_ (name + "_conf"), + conf_err_ ("A file containing configuration options for module " + + name_), + + // Defines service configuration directives. At the moment the + // only configuration directive is + // "_conf ". Configuration file path + // specified will be passed as a parameter to + // web::module::init call on exemplar_ object when apache worker + // process is started but prior to accepting client requests. + // + directives_ + { + { + conf_.c_str (), + reinterpret_cast (config_file), + this, + RSRC_CONF, + TAKE1, + conf_err_.c_str () + } + } // Doesn't look like handle_ member is required at all. // handle_ (&handle_impl) { - // instance () invented to delegate processing from apache request - // handler C function to service non static member function. - // This appoach resticts number of service objects per module - // implementation class with just one instance. + // instance () is invented to delegate processing from apache + // request handler C function to the service non static member + // function. This appoach resticts number of service objects per + // specific module implementation class with just one instance. // service*& srv = instance (); assert (srv == nullptr); srv = this; } + static const char* + config_file (cmd_parms *parms, void *mconfig, const char *w) + { + reinterpret_cast (parms->cmd->cmd_data)->conf_file_ = w; + return 0; + } + template static service*& instance () noexcept @@ -66,10 +97,45 @@ namespace web static void register_hooks (apr_pool_t *pool) noexcept { + // The registered function is called right after apache worker + // process is started. Called for every new process spawned. + // + ap_hook_child_init (&child_initializer, NULL, NULL, APR_HOOK_LAST); + + // The registered function is called for each client request. + // ap_hook_handler (&request_handler, NULL, NULL, APR_HOOK_LAST); } template + static void + child_initializer (apr_pool_t *pchild, server_rec *s) noexcept + { + auto srv = instance (); + + try + { + srv->exemplar_.init (srv->conf_file_.c_str ()); + } + catch (const std::exception& e) + { + ap_log_error (0, + 0, + APLOG_NO_MODULE, + APLOG_EMERG, + 0, + s, + "[::web::apache::service<%s>::child_initializer]: %s", + srv->name_.c_str (), + e.what ()); + + // Terminate the root apache process. + // + ::kill (::getppid (), SIGTERM); + } + } + + template static int request_handler (request_rec* r) noexcept { @@ -78,29 +144,75 @@ namespace web if (!r->handler || srv->name_ != r->handler) return DECLINED; + static const std::string func_name ( + "web::apache::service<" + srv->name_ + ">::request_handler"); + request req (r); - log l(r); + log l (r); - // As soons as M (), handle () and flush () can throw need to handle - // exceptions here. - // try { M m (static_cast (srv->exemplar_)); static_cast (m).handle (req, req, l); - return req.flush(); + return req.flush (); + } + catch (const invalid_request& e) + { + if (!e.content.empty () && !req.get_write_state ()) + { + try + { + req.content (e.status, e.type) << e.content; + return req.flush (); + } + catch (const std::exception& e) + { + l.write (nullptr, 0, func_name.c_str (), APLOG_ERR, e.what ()); + } + } + + return e.status; } catch (const std::exception& e) { - l.write (nullptr, 0, __PRETTY_FUNCTION__, APLOG_ERR, e.what ()); + l.write (nullptr, 0, func_name.c_str (), APLOG_ERR, e.what ()); + + if (*e.what () && !req.get_write_state ()) + { + try + { + req.content (HTTP_INTERNAL_SERVER_ERROR, + "text/plain;charset=utf-8") + << e.what (); + + return req.flush (); + } + catch (const std::exception& e) + { + l.write (nullptr, 0, func_name.c_str (), APLOG_ERR, e.what ()); + } + } } catch (...) { - l.write (nullptr, - 0, - __PRETTY_FUNCTION__, - APLOG_ERR, - "unknown error"); + l.write (nullptr, 0, func_name.c_str (), APLOG_ERR, "unknown error"); + + if (!req.get_write_state ()) + { + try + { + req.content (HTTP_INTERNAL_SERVER_ERROR, + "text/plain;charset=utf-8") + << "unknown error"; + + return req.flush (); + } + catch (const std::exception& e) + { + l.write (nullptr, 0, func_name.c_str (), APLOG_ERR, e.what ()); + } + } + } return HTTP_INTERNAL_SERVER_ERROR; @@ -122,7 +234,12 @@ namespace web } */ std::string name_; - const module& exemplar_; + module& exemplar_; + std::string conf_; + std::string conf_err_; + command_rec directives_[2]; + std::string conf_file_; + // void (*handle_) (request&, response&, log&, const module&); }; } -- cgit v1.1