aboutsummaryrefslogtreecommitdiff
path: root/brep
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-04-23 12:43:52 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-04-23 12:43:52 +0200
commita20443c285dabdec8d2ee740500c62e31ad90c7b (patch)
treeb18db4007e45f8db1f97c0d5abf78729138406ac /brep
parent370e361db628f60bca5509dcc354014569d56752 (diff)
Implement apache service
Diffstat (limited to 'brep')
-rw-r--r--brep/module27
-rw-r--r--brep/module.cxx144
-rw-r--r--brep/search.cxx31
-rw-r--r--brep/view20
-rw-r--r--brep/view.cxx15
5 files changed, 203 insertions, 34 deletions
diff --git a/brep/module b/brep/module
index 3f7b409..d976559 100644
--- a/brep/module
+++ b/brep/module
@@ -5,7 +5,9 @@
#ifndef BREP_MODULE
#define BREP_MODULE
+#include <string>
#include <utility> // move()
+#include <cstdint>
#include <web/module>
@@ -20,28 +22,14 @@ namespace brep
// web::module and our module. Or maybe not, need to try.
//
using web::status_code;
+ using web::invalid_request;
+ using web::sequence_error;
using web::name_value;
using web::name_values;
using web::request;
using web::response;
using web::log;
- // This exception is used to signal that the request is invalid
- // (4XX codes) rather than that it could not be processed (5XX).
- // By default 422 is returned, which means the request was
- // semantically invalid.
- //
- struct invalid_request
- {
- status_code status {422};
- std::string description;
-
- //@@ Maybe optional "try again" link?
- //
- invalid_request (std::string d, status_code s = 422)
- : status (s), description (std::move (d)) {}
- };
-
// And this exception indicated a server error (5XX). In particular,
// it is thrown by the fail diagnostics stream and is caught by the
// module implementation where it is both logged as an error and
@@ -105,6 +93,7 @@ namespace brep
//
protected:
module ();
+ module (const module& );
virtual void
handle (request&, response&, log&);
@@ -114,6 +103,12 @@ namespace brep
private:
log* log_ {nullptr}; // Diagnostics backend provided by the web server.
+ // Extract function name from a __PRETTY_FUNCTION__.
+ // Throw std::invalid_argument if fail to parse.
+ //
+ static std::string
+ func_name (const std::string& pretty_name);
+
void
log_write (diag_data&&) const;
diff --git a/brep/module.cxx b/brep/module.cxx
index 15e996f..17790de 100644
--- a/brep/module.cxx
+++ b/brep/module.cxx
@@ -4,7 +4,16 @@
#include <brep/module>
+#include <stdexcept>
+#include <string>
#include <functional> // bind()
+#include <cstring> // strncmp()
+
+#include <httpd/httpd.h>
+
+#include <web/module>
+
+#include <web/apache/log>
using namespace std;
using namespace placeholders; // For std::bind's _1, etc.
@@ -15,6 +24,7 @@ namespace brep
handle (request& rq, response& rs, log& l)
{
log_ = &l;
+ const basic_mark error (severity::error, log_writer_, __PRETTY_FUNCTION__);
try
{
@@ -22,39 +32,151 @@ namespace brep
}
catch (const invalid_request& e)
{
- // @@ Both log and format as HTML in proper style, etc.
- //
- rs.content (e.status, "text/html;charset=utf-8") << e.description;
+ if (e.description.empty ())
+ {
+ rs.status (e.status);
+ }
+ else
+ {
+ try
+ {
+ rs.content (e.status, "text/html;charset=utf-8") << e.description;
+ }
+ catch (const sequence_error& se)
+ {
+ error << se.what ();
+ rs.status (e.status);
+ }
+ }
}
catch (server_error& e) // Non-const because of move() below.
{
- // @@ Both log and return as 505.
- //
log_write (move (e.data));
+ rs.status (HTTP_INTERNAL_SERVER_ERROR);
}
catch (const exception& e)
{
- // @@ Exception: log e.what () & 505.
- //
- rs.status (505);
+ error << e.what ();
+ rs.status (HTTP_INTERNAL_SERVER_ERROR);
}
catch (...)
{
- // @@ Unknown exception: log & 505.
- //
- rs.status (505);
+ error << "unknown error";
+ rs.status (HTTP_INTERNAL_SERVER_ERROR);
}
}
module::
module (): log_writer_ (bind (&module::log_write, this, _1)) {}
+ // Custom copy constructor is required to initialize log_writer_ properly.
+ //
+ module::
+ module (const module& m): module () {verb_ = m.verb_;}
+
+// For function func declared like this:
+// using B = std::string (*)(int);
+// using A = B (*)(int,int);
+// A func(B (*)(char),B (*)(wchar_t));
+// __PRETTY_FUNCTION__ looks like this:
+// virtual std::string (* (* brep::search::func(std::string (* (*)(char))(int)\
+// ,std::string (* (*)(wchar_t))(int)) const)(int, int))(int)
+//
+ string module::
+ func_name (const string& pretty_name)
+ {
+ string::size_type b (0);
+ string::size_type e (pretty_name.find (' '));
+
+ // Position b at beginning of supposed function name,
+ //
+ if (e != string::npos && !strncmp (pretty_name.c_str (), "virtual ", 8))
+ {
+ // Skip keyword virtual.
+ //
+ b = pretty_name.find_first_not_of (' ', e);
+ e = pretty_name.find (' ', b);
+ }
+
+ if (pretty_name.find ('(', b) > e)
+ {
+ // Not a constructor nor destructor. Skip type or *.
+ //
+ b = pretty_name.find_first_not_of (' ', e);
+ }
+
+ if (b != string::npos)
+ {
+ // Position e at the last character of supposed function name.
+ //
+ e = pretty_name.find_last_of (')');
+
+ if (e != string::npos && e > b)
+ {
+ size_t d (1);
+
+ while (--e > b && d)
+ {
+ switch (pretty_name[e])
+ {
+ case ')': ++d; break;
+ case '(': --d; break;
+ }
+ }
+
+ if (!d)
+ {
+ return pretty_name[b] == '(' && pretty_name[e] == ')' ?
+ // Not a name yet, go deeper.
+ //
+ func_name (string(pretty_name, b + 1, e - b - 1)) :
+ // Got the name.
+ //
+ string (pretty_name, b, e - b + 1);
+ }
+ }
+ }
+
+ throw invalid_argument ("");
+ }
+
void module::
log_write (diag_data&& d) const
{
if (log_ == nullptr)
return; // No backend yet.
+ auto al = dynamic_cast<::web::apache::log*> (log_);
+
+ if (al)
+ {
+ // Considered using lambda for mapping but looks too verbose while can
+ // be a bit safer in runtime.
+ //
+ static int s[] = { APLOG_ERR, APLOG_WARNING, APLOG_INFO, APLOG_TRACE1 };
+
+ for (const auto& e : d)
+ {
+ string name;
+
+ try
+ {
+ name = func_name (e.name);
+ }
+ catch (const invalid_argument&)
+ {
+ // Log "pretty" function description, see in log file & fix.
+ name = e.name;
+ }
+
+ al->write (e.loc.file.c_str(),
+ e.loc.line,
+ name.c_str(),
+ s[static_cast<int> (e.sev)],
+ e.msg.c_str());
+ }
+ }
+
//@@ Cast log_ to apache::log and write the records.
//
diff --git a/brep/search.cxx b/brep/search.cxx
index 683016c..93690e4 100644
--- a/brep/search.cxx
+++ b/brep/search.cxx
@@ -5,6 +5,10 @@
#include <brep/search>
#include <ostream>
+#include <iostream>
+#include <chrono>
+
+#include <web/module>
using namespace std;
@@ -15,26 +19,39 @@ namespace brep
{
MODULE_DIAG;
+ chrono::seconds ma (60);
+ rs.cookie ("Oh", " Ah\n\n", &ma, "/");
+ rs.cookie ("Hm", ";Yes", &ma);
+
+ info << "handling search request from "; // << rq.client_ip ();
+
+ ostream& o (rs.content (200, "text/html;charset=utf-8", false));
+
+ o << "<html><head></head><body><b>Params:</b>";
+
const name_values& ps (rq.parameters ());
if (ps.empty ())
- throw invalid_request ("search parameters expected");
+ throw invalid_request (422, "search parameters expected");
if (ps.size () > 100)
fail << "too many parameters: " << ps.size () <<
info << "are you crazy to specify so many?";
- info << "handling search request from "; // << rq.client_ip ();
-
level2 ([&]{trace << "search request with " << ps.size () << " params";});
- ostream& o (rs.content (202, "text/html;charset=utf-8"));
+ for (const auto& p: ps)
+ {
+ o << "<br>\n" << p.name << "=" << p.value;
+ }
- o << "Search page:" << endl;
+ o << "<br>\n<b>Cookies:</b>";
- for (const name_value& p: ps)
+ for (const auto& c : rq.cookies ())
{
- o << p.name << "=" << p.value << endl;
+ o << "<br>\n" << c.name << "=" << c.value << " ";
}
+
+ o << "</body></html>";
}
}
diff --git a/brep/view b/brep/view
new file mode 100644
index 0000000..819eff3
--- /dev/null
+++ b/brep/view
@@ -0,0 +1,20 @@
+// file : brep/view -*- C++ -*-
+// copyright : Copyright (c) 2014-2015 Code Synthesis Tools CC
+// license : MIT; see accompanying LICENSE file
+
+#ifndef BREP_VIEW
+#define BREP_VIEW
+
+#include <brep/module>
+
+namespace brep
+{
+ class view: public module
+ {
+ public:
+ virtual void
+ handle (request&, response&);
+ };
+}
+
+#endif // BREP_VIEW
diff --git a/brep/view.cxx b/brep/view.cxx
new file mode 100644
index 0000000..6dafa1b
--- /dev/null
+++ b/brep/view.cxx
@@ -0,0 +1,15 @@
+// file : brep/view.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2015 Code Synthesis Tools CC
+// license : MIT; see accompanying LICENSE file
+
+#include <brep/view>
+
+using namespace std;
+
+namespace brep
+{
+ void view::
+ handle (request& rq, response& rs)
+ {
+ }
+}