diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2015-04-27 13:52:25 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2015-04-27 13:52:25 +0200 |
commit | 04c1324c57692dfd22fab211a7443aaf484f07ce (patch) | |
tree | 9dcc8f36d6d94f02b7c3b2ed1485a50417e3b5e0 /web/apache/service | |
parent | b4c7f615916cd41e4772c5dc1b2f9f59b3b2ae6c (diff) |
Implement module configuration, cleanup the code
Diffstat (limited to 'web/apache/service')
-rw-r--r-- | web/apache/service | 167 |
1 files changed, 142 insertions, 25 deletions
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 <exception> -#include <string> -#include <cassert> +#include <string.h> // memset() +#include <unistd.h> // getppid() +#include <signal.h> // kill() #include <httpd/httpd.h> #include <httpd/http_config.h> -#include <web/module> +#include <string> +#include <cassert> +#include <exception> +#include <web/module> #include <web/apache/log> #include <web/apache/request> @@ -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 <typename M> - 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<M> }, 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 + // "<module_name>_conf <conf_file_path>". 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<cmd_func> (config_file), + this, + RSRC_CONF, + TAKE1, + conf_err_.c_str () + } + } // Doesn't look like handle_ member is required at all. // handle_ (&handle_impl<M>) { - // instance<M> () 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<M> () 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<M> (); assert (srv == nullptr); srv = this; } + static const char* + config_file (cmd_parms *parms, void *mconfig, const char *w) + { + reinterpret_cast<service*> (parms->cmd->cmd_data)->conf_file_ = w; + return 0; + } + template <typename M> 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<M>, NULL, NULL, APR_HOOK_LAST); + + // The registered function is called for each client request. + // ap_hook_handler (&request_handler<M>, NULL, NULL, APR_HOOK_LAST); } template <typename M> + static void + child_initializer (apr_pool_t *pchild, server_rec *s) noexcept + { + auto srv = instance<M> (); + + 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 <typename M> 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<const M&> (srv->exemplar_)); static_cast<module&> (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&); }; } |