// file : web/apache/service -*- C++ -*- // copyright : Copyright (c) 2014-2015 Code Synthesis Tools CC // license : MIT; see accompanying LICENSE file #ifndef WEB_APACHE_SERVICE #define WEB_APACHE_SERVICE #include // memset() #include // getppid() #include // kill() #include #include #include #include #include #include #include #include namespace web { namespace apache { class service: ::module { public: // Note that the module exemplar is stored by-reference. // template service (const std::string& name, M& exemplar) : ::module { STANDARD20_MODULE_STUFF, nullptr, nullptr, nullptr, nullptr, directives_, ®ister_hooks }, name_ (name), 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 () 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 { static service* instance; return instance; } template 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 { auto srv = instance (); 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); try { M m (static_cast (srv->exemplar_)); static_cast (m).handle (req, req, l); 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, 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, 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; } //@@ Implementation calls handle_ function pointer below: // // handle_ (rq, rs, l, exemplar_); // private: /* template static void handle_impl (request& rq, response& rs, log& l, const module& exemplar) { M m (static_cast (exemplar)); static_cast (m).handle (rq, rs, l); } */ std::string name_; module& exemplar_; std::string conf_; std::string conf_err_; command_rec directives_[2]; std::string conf_file_; // void (*handle_) (request&, response&, log&, const module&); }; } } #endif // WEB_APACHE_SERVICE