aboutsummaryrefslogtreecommitdiff
path: root/web/apache
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-05-04 21:22:14 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-05-04 21:22:14 +0200
commit63229f465aaea8dd5553814535220817319a64f5 (patch)
tree326ce5cbf4afd118b34ad74d8698a30a23860a42 /web/apache
parent73eb44142be85f964a32be00e8ce655f61063d08 (diff)
Cleanup the code
Diffstat (limited to 'web/apache')
-rw-r--r--web/apache/log30
-rw-r--r--web/apache/request70
-rw-r--r--web/apache/request.cxx224
-rw-r--r--web/apache/request.ixx147
-rw-r--r--web/apache/service192
-rw-r--r--web/apache/service.cxx109
-rw-r--r--web/apache/service.txx85
-rw-r--r--web/apache/stream23
8 files changed, 460 insertions, 420 deletions
diff --git a/web/apache/log b/web/apache/log
index 50e2f7c..acc7c92 100644
--- a/web/apache/log
+++ b/web/apache/log
@@ -48,25 +48,25 @@ namespace web
if (func)
ap_log_error (file,
- line,
- APLOG_NO_MODULE,
- level,
- 0,
- server_,
- "[%s]: %s",
- func,
- msg);
+ line,
+ APLOG_NO_MODULE,
+ level,
+ 0,
+ server_,
+ "[%s]: %s",
+ func,
+ msg);
else
// skip function name placeholder from log line
//
ap_log_error (file,
- line,
- APLOG_NO_MODULE,
- level,
- 0,
- server_,
- ": %s",
- msg);
+ line,
+ APLOG_NO_MODULE,
+ level,
+ 0,
+ server_,
+ ": %s",
+ msg);
}
private:
diff --git a/web/apache/request b/web/apache/request
index 4071bd1..1fb9cbe 100644
--- a/web/apache/request
+++ b/web/apache/request
@@ -46,48 +46,12 @@ namespace web
// Get request body data stream.
//
virtual std::istream&
- content ()
- {
- if (!in_)
- {
- std::unique_ptr<std::streambuf> in_buf (
- new istreambuf (rec_, *this));
-
- in_.reset (new std::istream (in_buf.get ()));
- in_buf_ = std::move (in_buf);
- in_->exceptions (std::ios::failbit | std::ios::badbit);
-
- // Save form data now otherwise will not be available to do later
- // when data read from stream.
- //
- form_data ();
- }
-
- return *in_;
- }
+ content ();
// Get request parameters.
//
virtual const name_values&
- parameters ()
- {
- if (!parameters_)
- {
- parameters_.reset (new name_values ());
-
- try
- {
- parse_parameters (rec_->args);
- parse_parameters (form_data ()->c_str ());
- }
- catch (const std::invalid_argument& )
- {
- throw invalid_request ();
- }
- }
-
- return *parameters_;
- }
+ parameters ();
// Get request cookies.
//
@@ -101,26 +65,7 @@ namespace web
// Set response status code.
//
virtual void
- status (status_code status)
- {
- if (status != rec_->status)
- {
- // Setting status code in exception handler is a common usecase
- // where no sense to throw but still need to signal apache a
- // proper status code.
- //
- if (get_write_state () && !std::current_exception ())
- {
- throw sequence_error ("::web::apache::request::status");
- }
-
- rec_->status = status;
- buffer_ = true;
- out_.reset ();
- out_buf_.reset ();
- ap_set_content_type (rec_, nullptr);
- }
- }
+ status (status_code status);
// Set response status code, content type and get body stream.
//
@@ -140,11 +85,9 @@ namespace web
bool secure = false);
private:
- using string_ptr = std::unique_ptr<std::string>;
-
// Get application/x-www-form-urlencoded form data.
//
- const string_ptr&
+ const std::string&
form_data ();
void
@@ -167,7 +110,7 @@ namespace web
// Preparing to write a response read and discard request
// body if any.
//
- int r = ap_discard_request_body (rec_);
+ int r (ap_discard_request_body (rec_));
if (r != OK)
{
@@ -179,7 +122,6 @@ namespace web
}
private:
-
request_rec* rec_;
bool buffer_ {true};
bool write_state_ {false};
@@ -189,7 +131,7 @@ namespace web
std::unique_ptr<std::istream> in_;
std::unique_ptr<name_values> parameters_;
std::unique_ptr<name_values> cookies_;
- string_ptr form_data_;
+ std::unique_ptr<std::string> form_data_;
};
}
}
diff --git a/web/apache/request.cxx b/web/apache/request.cxx
index 3711437..caf0d60 100644
--- a/web/apache/request.cxx
+++ b/web/apache/request.cxx
@@ -25,6 +25,48 @@ namespace web
{
namespace apache
{
+
+ istream& request::
+ content ()
+ {
+ if (!in_)
+ {
+ unique_ptr<streambuf> in_buf (new istreambuf (rec_, *this));
+
+ in_.reset (new istream (in_buf.get ()));
+ in_buf_ = move (in_buf);
+ in_->exceptions (ios::failbit | ios::badbit);
+
+ // Save form data now otherwise will not be available to do later
+ // when data already read from stream.
+ //
+ form_data ();
+ }
+
+ return *in_;
+ }
+
+ const name_values& request::
+ parameters ()
+ {
+ if (!parameters_)
+ {
+ parameters_.reset (new name_values ());
+
+ try
+ {
+ parse_parameters (rec_->args);
+ parse_parameters (form_data ().c_str ());
+ }
+ catch (const invalid_argument& )
+ {
+ throw invalid_request ();
+ }
+ }
+
+ return *parameters_;
+ }
+
const name_values& request::
cookies ()
{
@@ -32,8 +74,8 @@ namespace web
{
cookies_.reset (new name_values ());
- const apr_array_header_t* ha = apr_table_elts (rec_->headers_in);
- size_t n = ha->nelts;
+ const apr_array_header_t* ha (apr_table_elts (rec_->headers_in));
+ size_t n (ha->nelts);
for (auto h (reinterpret_cast<const apr_table_entry_t *> (ha->elts));
n--; ++h)
@@ -42,8 +84,8 @@ namespace web
{
for (const char* n (h->val); n != 0; )
{
- const char* v = strchr (n, '=');
- const char* e = strchr (n, ';');
+ const char* v (strchr (n, '='));
+ const char* e (strchr (n, ';'));
if (e && e < v)
v = 0;
@@ -97,12 +139,12 @@ namespace web
//
form_data ();
- unique_ptr<std::streambuf> out_buf (
+ unique_ptr<streambuf> out_buf (
buffer
- ? static_cast<std::streambuf*> (new std::stringbuf ())
- : static_cast<std::streambuf*> (new ostreambuf (rec_, *this)));
+ ? static_cast<streambuf*> (new stringbuf ())
+ : static_cast<streambuf*> (new ostreambuf (rec_, *this)));
- out_.reset (new std::ostream (out_buf.get ()));
+ out_.reset (new ostream (out_buf.get ()));
out_buf_ = move (out_buf);
out_->exceptions (ios::eofbit | ios::failbit | ios::badbit);
@@ -117,6 +159,28 @@ namespace web
}
void request::
+ status (status_code status)
+ {
+ if (status != rec_->status)
+ {
+ // Setting status code in exception handler is a common usecase
+ // where no sense to throw but still need to signal apache a
+ // proper status code.
+ //
+ if (get_write_state () && !current_exception ())
+ {
+ throw sequence_error ("::web::apache::request::status");
+ }
+
+ rec_->status = status;
+ buffer_ = true;
+ out_.reset ();
+ out_buf_.reset ();
+ ap_set_content_type (rec_, nullptr);
+ }
+ }
+
+ void request::
cookie (const char* name,
const char* value,
const chrono::seconds* max_age,
@@ -126,6 +190,8 @@ namespace web
{
if (get_write_state ())
{
+ // Too late to send cookie if content is already written.
+ //
throw sequence_error ("::web::apache::request::cookie");
}
@@ -136,12 +202,12 @@ namespace web
if (max_age)
{
- chrono::system_clock::time_point tp =
- chrono::system_clock::now () + *max_age;
+ chrono::system_clock::time_point tp (
+ chrono::system_clock::now () + *max_age);
- time_t t = chrono::system_clock::to_time_t (tp);
+ time_t t (chrono::system_clock::to_time_t (tp));
- // Assume global "C" locale is not changed.
+ // Assume global locale is not changed and still "C".
//
char b[100];
strftime (b, sizeof (b), "%a, %d-%b-%Y %H:%M:%S GMT", gmtime (&t));
@@ -166,5 +232,139 @@ namespace web
apr_table_add (rec_->err_headers_out, "Set-Cookie", s.str ().c_str ());
}
+ void request::
+ parse_parameters (const char* args)
+ {
+ for (auto n (args); n != 0; )
+ {
+ const char* v (strchr (n, '='));
+ const char* e (strchr (n, '&'));
+
+ if (e && e < v)
+ v = 0;
+
+ string name (v
+ ? mime_url_decode (n, v) :
+ (e
+ ? mime_url_decode (n, e)
+ : mime_url_decode (n, n + strlen (n))));
+
+ string value;
+
+ if (v++)
+ {
+ value = e
+ ? mime_url_decode (v, e)
+ : mime_url_decode (v, v + strlen (v));
+ }
+
+ if (!name.empty () || !value.empty ())
+ parameters_->emplace_back (move (name), move (value));
+
+ n = e ? e + 1 : 0;
+ }
+ }
+
+ void request::
+ mime_url_encode (const char* v, ostream& o)
+ {
+ char f (o.fill ());
+ ios_base::fmtflags g (o.flags ());
+ o << hex << uppercase << right << setfill ('0');
+
+ char c;
+
+ while ((c = *v++) != '\0')
+ {
+ if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
+ (c >= '0' && c <= '9'))
+ {
+ o << c;
+ }
+ else
+ switch (c)
+ {
+ case ' ': o << '+'; break;
+ case '.':
+ case '_':
+ case '-':
+ case '~': o << c; break;
+ default:
+ {
+ o << "%" << setw (2) << static_cast<unsigned short> (c);
+ break;
+ }
+ }
+ }
+
+ o.flags (g);
+ o.fill (f);
+ }
+
+ string request::
+ mime_url_decode (const char* b, const char* e, bool trim)
+ {
+ if (trim)
+ {
+ b += strspn (b, " ");
+
+ if (b >= e)
+ return string ();
+
+ while (*--e == ' ');
+ ++e;
+ }
+
+ string value;
+ value.reserve (e - b);
+
+ char bf[3];
+ bf[2] = '\0';
+
+ while (b != e)
+ {
+ char c (*b++);
+
+ switch (c)
+ {
+ case '+':
+ {
+ value.append (" ");
+ break;
+ }
+ case '%':
+ {
+ if (*b == '\0' || b[1] == '\0')
+ {
+ throw invalid_argument (
+ "::web::apache::request::mime_url_decode short");
+ }
+
+ *bf = *b;
+ bf[1] = b[1];
+
+ char* ebf (nullptr);
+ size_t vl (strtoul (bf, &ebf, 16));
+
+ if (*ebf != '\0')
+ {
+ throw invalid_argument (
+ "::web::apache::request::mime_url_decode wrong");
+ }
+
+ value.append (1, static_cast<char> (vl));
+ b += 2;
+ break;
+ }
+ default:
+ {
+ value.append (1, c);
+ break;
+ }
+ }
+ }
+
+ return value;
+ }
}
}
diff --git a/web/apache/request.ixx b/web/apache/request.ixx
index 06284fb..f7446e5 100644
--- a/web/apache/request.ixx
+++ b/web/apache/request.ixx
@@ -18,7 +18,7 @@ namespace web
{
if (buffer_ && out_buf_)
{
- auto b = dynamic_cast<std::stringbuf*> (out_buf_.get ());
+ auto b (dynamic_cast<std::stringbuf*> (out_buf_.get ()));
assert (b);
std::string s (b->str ());
@@ -27,7 +27,7 @@ namespace web
{
// Before writing response read and discard request body if any.
//
- int r = ap_discard_request_body (rec_);
+ int r (ap_discard_request_body (rec_));
if (r == OK)
{
@@ -36,7 +36,6 @@ namespace web
if (ap_rwrite (s.c_str (), s.length (), rec_) < 0)
rec_->status = HTTP_REQUEST_TIME_OUT;
}
-
else
rec_->status = r;
}
@@ -48,13 +47,13 @@ namespace web
return rec_->status == HTTP_OK || get_write_state () ? OK : rec_->status;
}
- inline const request::string_ptr& request::
+ inline const std::string& request::
form_data ()
{
if (!form_data_)
{
form_data_.reset (new std::string ());
- const char *ct = apr_table_get (rec_->headers_in, "Content-Type");
+ const char* ct (apr_table_get (rec_->headers_in, "Content-Type"));
if (ct && !strncasecmp ("application/x-www-form-urlencoded", ct, 33))
{
@@ -72,143 +71,7 @@ namespace web
}
}
- return form_data_;
- }
-
- inline void request::
- parse_parameters (const char* args)
- {
- for (auto n (args); n != 0; )
- {
- const char* v = std::strchr (n, '=');
- const char* e = ::strchr (n, '&');
-
- if (e && e < v)
- v = 0;
-
- std::string name (v
- ? mime_url_decode (n, v) :
- (e
- ? mime_url_decode (n, e)
- : mime_url_decode (n, n + std::strlen (n))));
-
- std::string value;
-
- if (v++)
- {
- value = e
- ? mime_url_decode (v, e)
- : mime_url_decode (v, v + std::strlen (v));
- }
-
- if (!name.empty () || !value.empty ())
- parameters_->emplace_back (std::move (name), std::move (value));
-
- n = e ? e + 1 : 0;
- }
+ return *form_data_;
}
-
- inline void request::
- mime_url_encode (const char* v, std::ostream& o)
- {
- char f = o.fill ();
- std::ios_base::fmtflags g = o.flags ();
- o << std::hex << std::uppercase << std::right << std::setfill ('0');
-
- char c;
-
- while ((c = *v++) != '\0')
- {
- if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
- (c >= '0' && c <= '9'))
- {
- o << c;
- }
- else
- switch (c)
- {
- case ' ': o << '+'; break;
- case '.':
- case '_':
- case '-':
- case '~': o << c; break;
- default:
- {
- o << "%" << std::setw (2) << static_cast<unsigned short> (c);
- break;
- }
- }
- }
-
- o.flags (g);
- o.fill (f);
- }
-
- inline std::string request::
- mime_url_decode (const char* b, const char* e, bool trim)
- {
- if (trim)
- {
- b += std::strspn (b, " ");
-
- if (b >= e)
- return std::string ();
-
- while (*--e == ' ');
- ++e;
- }
-
- std::string value;
- value.reserve (e - b);
-
- char bf[3];
- bf[2] = '\0';
-
- while (b != e)
- {
- char c = *b++;
-
- switch (c)
- {
- case '+':
- {
- value.append (" ");
- break;
- }
- case '%':
- {
- if (*b == '\0' || b[1] == '\0')
- {
- throw std::invalid_argument (
- "::web::apache::request::mime_url_decode short");
- }
-
- *bf = *b;
- bf[1] = b[1];
-
- char* ebf = 0;
- size_t vl = std::strtoul (bf, &ebf, 16);
-
- if (*ebf != '\0')
- {
- throw std::invalid_argument (
- "::web::apache::request::mime_url_decode wrong");
- }
-
- value.append (1, static_cast<char> (vl));
- b += 2;
- break;
- }
- default:
- {
- value.append (1, c);
- break;
- }
- }
- }
-
- return value;
- }
-
}
}
diff --git a/web/apache/service b/web/apache/service
index cd405ee..8456f12 100644
--- a/web/apache/service
+++ b/web/apache/service
@@ -5,18 +5,11 @@
#ifndef WEB_APACHE_SERVICE
#define WEB_APACHE_SERVICE
-#include <string.h> // memset()
-#include <unistd.h> // getppid()
-#include <signal.h> // kill()
-
#include <httpd/httpd.h>
-#include <httpd/http_config.h>
#include <string>
#include <vector>
-#include <memory> // unique_ptr
#include <cassert>
-#include <exception>
#include <algorithm> // move()
#include <web/module>
@@ -30,7 +23,6 @@ namespace web
class service: ::module
{
public:
-
using option_names = std::vector<std::string>;
// Note that the module exemplar is stored by-reference.
@@ -52,48 +44,17 @@ namespace web
name_ (name),
exemplar_ (exemplar),
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 = {};
+ init_directives();
// 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> ();
+ service*& srv (instance<M> ());
assert (srv == nullptr);
srv = this;
-
- cmds = directives.release ();
}
~service ()
@@ -101,23 +62,6 @@ namespace web
delete [] cmds;
}
- static const char*
- add_option (cmd_parms *parms, void *mconfig, const char *value)
- {
- 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;
- }
-
template <typename M>
static service*&
instance () noexcept
@@ -144,144 +88,44 @@ namespace web
static void
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->options_, l);
- }
- catch (const std::exception& e)
- {
- 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.
- //
- ::kill (::getppid (), SIGTERM);
- }
+ instance<M> ()->init_worker(l);
}
template <typename M>
static int
request_handler (request_rec* r) noexcept
{
- auto srv = instance<M> ();
-
- if (!r->handler || srv->name_ != r->handler)
- return DECLINED;
-
- static const std::string func_name (
- "web::apache::service<" + srv->name_ + ">::request_handler");
+ auto srv (instance<M> ());
+ if (!r->handler || srv->name_ != r->handler) return DECLINED;
request req (r);
log l (r->server);
+ return srv->handle<M>(req, l);
+ }
- try
- {
- M m (static_cast<const M&> (srv->exemplar_));
- static_cast<module&> (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 ());
- }
- }
+ private:
+ void
+ init_directives();
- }
+ void
+ init_worker(log& l) noexcept;
- return HTTP_INTERNAL_SERVER_ERROR;
- }
+ static const char*
+ add_option (cmd_parms *parms, void *mconfig, const char *value) noexcept;
- //@@ Implementation calls handle_ function pointer below:
- //
- // handle_ (rq, rs, l, exemplar_);
- //
+ template <typename M>
+ int handle(request& r, log& l) noexcept;
private:
-/*
- template <typename M>
- static void
- handle_impl (request& rq, response& rs, log& l, const module& exemplar)
- {
- M m (static_cast<const M&> (exemplar));
- static_cast<module&> (m).handle (rq, rs, l);
- }
-*/
std::string name_;
module& exemplar_;
option_names option_names_;
name_values options_;
-
-// void (*handle_) (request&, response&, log&, const module&);
};
}
}
+#include <web/apache/service.txx>
+
#endif // WEB_APACHE_SERVICE
diff --git a/web/apache/service.cxx b/web/apache/service.cxx
new file mode 100644
index 0000000..6b73e02
--- /dev/null
+++ b/web/apache/service.cxx
@@ -0,0 +1,109 @@
+// file : web/apache/service.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2015 Code Synthesis Tools CC
+// license : MIT; see accompanying LICENSE file
+
+#include <web/apache/service>
+
+#include <unistd.h> // getppid()
+#include <signal.h> // kill()
+
+#include <httpd/httpd.h>
+#include <httpd/http_config.h>
+
+#include <memory> // unique_ptr
+#include <string>
+#include <exception>
+
+using namespace std;
+
+namespace web
+{
+ namespace apache
+ {
+ void service::
+ init_directives()
+ {
+ assert(cmds == nullptr);
+
+ // 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.
+ //
+ 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 = {};
+
+ cmds = directives.release ();
+ }
+
+ const char* service::
+ add_option (cmd_parms *parms, void *mconfig, const char *value) noexcept
+ {
+ service& srv (*reinterpret_cast<service*> (parms->cmd->cmd_data));
+ 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;
+ }
+
+ void service::
+ init_worker(log& l) noexcept
+ {
+ static const string func_name (
+ "web::apache::service<" + name_ + ">::init_worker");
+
+ try
+ {
+ exemplar_.init (options_, l);
+ }
+ catch (const exception& e)
+ {
+ 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.
+ //
+ ::kill (::getppid (), SIGTERM);
+ }
+ }
+ }
+}
diff --git a/web/apache/service.txx b/web/apache/service.txx
new file mode 100644
index 0000000..06f3599
--- /dev/null
+++ b/web/apache/service.txx
@@ -0,0 +1,85 @@
+// file : web/apache/service.txx -*- C++ -*-
+// copyright : Copyright (c) 2014-2015 Code Synthesis Tools CC
+// license : MIT; see accompanying LICENSE file
+
+#include <httpd/http_log.h>
+
+#include <exception>
+
+namespace web
+{
+ namespace apache
+ {
+ template <typename M>
+ int service::
+ handle(request& r, log& l) noexcept
+ {
+ static const std::string func_name (
+ "web::apache::service<" + name_ + ">::handle");
+
+ try
+ {
+ M m (static_cast<const M&> (exemplar_));
+ static_cast<module&> (m).handle (r, r, l);
+ return r.flush ();
+ }
+ catch (const invalid_request& e)
+ {
+ if (!e.content.empty () && !r.get_write_state ())
+ {
+ try
+ {
+ r.content (e.status, e.type) << e.content;
+ return r.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 () && !r.get_write_state ())
+ {
+ try
+ {
+ r.content (HTTP_INTERNAL_SERVER_ERROR, "text/plain;charset=utf-8")
+ << e.what ();
+
+ return r.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 (!r.get_write_state ())
+ {
+ try
+ {
+ r.content (HTTP_INTERNAL_SERVER_ERROR, "text/plain;charset=utf-8")
+ << "unknown error";
+
+ return r.flush ();
+ }
+ catch (const std::exception& e)
+ {
+ l.write (nullptr, 0, func_name.c_str (), APLOG_ERR, e.what ());
+ }
+ }
+ }
+
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+ }
+}
diff --git a/web/apache/stream b/web/apache/stream
index 5f76347..2aa674d 100644
--- a/web/apache/stream
+++ b/web/apache/stream
@@ -9,7 +9,7 @@
#include <httpd/http_protocol.h>
#include <ios> // streamsize
-#include <memory> // unique_ptr
+#include <vector>
#include <cstring> // memmove()
#include <streambuf>
#include <algorithm> // min(), max()
@@ -52,7 +52,7 @@ namespace web
{
ws_.set_write_state ();
- char chr = c;
+ char chr (c);
// Throwing allows to distinguish comm failure from other IO error
// conditions.
@@ -89,7 +89,6 @@ namespace web
}
private:
-
request_rec* rec_;
write_state& ws_;
};
@@ -105,17 +104,17 @@ namespace web
ws_ (ws),
bufsize_ (std::max (bufsize, (size_t)1)),
putback_ (std::min (putback, bufsize_ - 1)),
- buf_ (new char[bufsize_])
+ buf_ (bufsize_)
{
if (ws_.get_write_state ())
{
throw sequence_error ("::web::apache::istreambuf::istreambuf");
}
- char* p = buf_.get () + putback_;
+ char* p (buf_.data () + putback_);
setg (p, p, p);
- int status = ap_setup_client_block (rec_, REQUEST_CHUNKED_DECHUNK);
+ int status (ap_setup_client_block (rec_, REQUEST_CHUNKED_DECHUNK));
if (status != OK)
{
@@ -135,11 +134,11 @@ namespace web
if (gptr () < egptr ())
return traits_type::to_int_type (*gptr ());
- size_t pb = std::min ((size_t)(gptr () - eback ()), putback_);
- std::memmove (buf_.get () + putback_ - pb, gptr () - pb, pb);
+ size_t pb (std::min ((size_t)(gptr () - eback ()), putback_));
+ std::memmove (buf_.data () + putback_ - pb, gptr () - pb, pb);
- char* p = buf_.get () + putback_;
- int rb = ap_get_client_block (rec_, p, bufsize_ - putback_);
+ char* p (buf_.data () + putback_);
+ int rb (ap_get_client_block (rec_, p, bufsize_ - putback_));
if (rb == 0)
{
@@ -156,14 +155,12 @@ namespace web
}
private:
-
request_rec* rec_;
write_state& ws_;
size_t bufsize_;
size_t putback_;
- std::unique_ptr<char[]> buf_;
+ std::vector<char> buf_;
};
-
}
}