aboutsummaryrefslogtreecommitdiff
path: root/web
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-04-30 14:25:29 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-04-30 14:25:29 +0200
commit07780b06aa7b0fe049cc412309cf87e7fb10a0ef (patch)
treeb6d0f1ee50223f5cbbc4b8c5d0dc4f69ff7f2352 /web
parent259a92ac4e1ac50e4c029f54265b735f6214b49d (diff)
Implement module configuration with an option list
Diffstat (limited to 'web')
-rw-r--r--web/apache/log12
-rw-r--r--web/apache/service127
-rw-r--r--web/module6
3 files changed, 93 insertions, 52 deletions
diff --git a/web/apache/log b/web/apache/log
index f8c65e9..50e2f7c 100644
--- a/web/apache/log
+++ b/web/apache/log
@@ -21,7 +21,7 @@ namespace web
{
public:
- log (request_rec* req) noexcept: req_ (req) {}
+ log (server_rec* server) noexcept: server_ (server) {}
virtual void
write (const char* msg) {write (APLOG_ERR, msg);}
@@ -47,30 +47,30 @@ namespace web
level = std::min (level, APLOG_TRACE8);
if (func)
- ap_log_rerror (file,
+ ap_log_error (file,
line,
APLOG_NO_MODULE,
level,
0,
- req_,
+ server_,
"[%s]: %s",
func,
msg);
else
// skip function name placeholder from log line
//
- ap_log_rerror (file,
+ ap_log_error (file,
line,
APLOG_NO_MODULE,
level,
0,
- req_,
+ server_,
": %s",
msg);
}
private:
- request_rec* req_;
+ server_rec* server_;
};
}
}
diff --git a/web/apache/service b/web/apache/service
index d003767..cd405ee 100644
--- a/web/apache/service
+++ b/web/apache/service
@@ -13,8 +13,11 @@
#include <httpd/http_config.h>
#include <string>
+#include <vector>
+#include <memory> // unique_ptr
#include <cassert>
#include <exception>
+#include <algorithm> // move()
#include <web/module>
#include <web/apache/log>
@@ -27,10 +30,15 @@ namespace web
class service: ::module
{
public:
+
+ using option_names = std::vector<std::string>;
+
// Note that the module exemplar is stored by-reference.
//
template <typename M>
- service (const std::string& name, M& exemplar)
+ service (const std::string& name,
+ M& exemplar,
+ option_names opts = option_names ())
: ::module
{
STANDARD20_MODULE_STUFF,
@@ -38,36 +46,44 @@ namespace web
nullptr,
nullptr,
nullptr,
- directives_,
+ nullptr,
&register_hooks<M>
},
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
- // "<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 ()
- }
- }
+ option_names_ (std::move (opts))
// Doesn't look like handle_ member is required at all.
// handle_ (&handle_impl<M>)
{
+ // Fill apache module directive definitions. Directives share
+ // common name space in apache configuration file, so to prevent name
+ // clash have to form directive name as a combination of module and
+ // option names: <module name>-<option name>. This why for option
+ // bar of module foo the corresponding directive will appear in apache
+ // configuration file as foo-bar.
+ //
+ std::unique_ptr<command_rec[]> directives (
+ new command_rec[option_names_.size () + 1]);
+
+ command_rec* d = directives.get ();
+
+ for (auto& o: option_names_)
+ {
+ o = name_ + "-" + o;
+
+ *d++ =
+ {
+ o.c_str (),
+ reinterpret_cast<cmd_func> (add_option),
+ this,
+ RSRC_CONF,
+ TAKE1,
+ nullptr
+ };
+ }
+
+ *d = {};
+
// 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
@@ -76,12 +92,29 @@ namespace web
service*& srv = instance<M> ();
assert (srv == nullptr);
srv = this;
+
+ cmds = directives.release ();
+ }
+
+ ~service ()
+ {
+ delete [] cmds;
}
static const char*
- config_file (cmd_parms *parms, void *mconfig, const char *w)
+ add_option (cmd_parms *parms, void *mconfig, const char *value)
{
- reinterpret_cast<service*> (parms->cmd->cmd_data)->conf_file_ = w;
+ service& srv = *reinterpret_cast<service*> (parms->cmd->cmd_data);
+ std::string name (parms->cmd->name + srv.name_.length () + 1);
+
+ for (auto& v: srv.options_)
+ if (v.name == name)
+ {
+ v.value = value;
+ return 0;
+ }
+
+ srv.options_.emplace_back (name, value);
return 0;
}
@@ -95,12 +128,12 @@ namespace web
template <typename M>
static void
- register_hooks (apr_pool_t *pool) noexcept
+ register_hooks (apr_pool_t*) 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);
+ ap_hook_child_init (&worker_initializer<M>, NULL, NULL, APR_HOOK_LAST);
// The registered function is called for each client request.
//
@@ -109,25 +142,33 @@ namespace web
template <typename M>
static void
- child_initializer (apr_pool_t *pchild, server_rec *s) noexcept
+ worker_initializer (apr_pool_t*, server_rec* server) noexcept
{
auto srv = instance<M> ();
+ log l (server);
+
+ static const std::string func_name (
+ "web::apache::service<" + srv->name_ + ">::worker_initializer");
try
{
- srv->exemplar_.init (srv->conf_file_.c_str ());
+ srv->exemplar_.init (srv->options_, l);
}
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 ());
+ l.write (nullptr, 0, func_name.c_str (), APLOG_EMERG, e.what ());
+
+ // Terminate the root apache process.
+ //
+ ::kill (::getppid (), SIGTERM);
+ }
+ catch (...)
+ {
+ l.write (nullptr,
+ 0,
+ func_name.c_str (),
+ APLOG_EMERG,
+ "unknown error");
// Terminate the root apache process.
//
@@ -148,7 +189,7 @@ namespace web
"web::apache::service<" + srv->name_ + ">::request_handler");
request req (r);
- log l (r);
+ log l (r->server);
try
{
@@ -235,10 +276,8 @@ namespace web
*/
std::string name_;
module& exemplar_;
- std::string conf_;
- std::string conf_err_;
- command_rec directives_[2];
- std::string conf_file_;
+ option_names option_names_;
+ name_values options_;
// void (*handle_) (request&, response&, log&, const module&);
};
diff --git a/web/module b/web/module
index 22f9fcc..8657c51 100644
--- a/web/module
+++ b/web/module
@@ -116,7 +116,9 @@ namespace web
// new status.
//
virtual std::ostream&
- content (status_code, const std::string& type, bool buffer = true) = 0;
+ content (status_code code = 200,
+ const std::string& type = "text/html;charset=utf-8",
+ bool buffer = true) = 0;
// Set status code without writing any content. On status change,
// discard buffered content or throw sequence_error if content was
@@ -175,7 +177,7 @@ namespace web
// @@ Is log available? Should we pass it?
//
virtual void
- init (const name_values&) = 0;
+ init (const name_values&, log&) = 0;
// Any exception other than invalid_request described above that
// leaves this function is treated by the web server implementation