aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-12-08 13:45:08 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-12-14 12:02:13 +0200
commite28ab8f48c891c03cf4b3a8ed88b98d38a561960 (patch)
tree0ae1dbb54e497fc797e5a73fcf3dd2dc487a5572
parenta31dfac365feef7838b01b1efd3fe058c89484d7 (diff)
Separate brep module configuration from Apache server configuration
-rw-r--r--brep/buildfile22
-rw-r--r--brep/module63
-rw-r--r--brep/module.cxx167
-rw-r--r--brep/options.cli38
-rw-r--r--brep/package-details9
-rw-r--r--brep/package-details.cxx23
-rw-r--r--brep/package-search9
-rw-r--r--brep/package-search.cxx21
-rw-r--r--brep/package-version-details12
-rw-r--r--brep/package-version-details.cxx22
-rw-r--r--brep/package.cxx1
-rw-r--r--brep/page1
-rw-r--r--brep/page.cxx1
-rw-r--r--brep/repository-details9
-rw-r--r--brep/repository-details.cxx17
-rw-r--r--brep/repository-root29
-rw-r--r--brep/repository-root.cxx183
-rw-r--r--brep/services.cxx38
-rw-r--r--brep/shared-database.cxx7
-rw-r--r--brep/types-parsers1
-rw-r--r--brep/types-parsers.cxx1
-rwxr-xr-xbuild.sh14
-rw-r--r--etc/brep.conf49
-rwxr-xr-xetc/dev/apachectl (renamed from etc/apachectl)50
-rwxr-xr-xetc/dev/brep (renamed from etc/brep)0
-rw-r--r--etc/dev/brep-site.conf9
-rw-r--r--etc/dev/config (renamed from etc/config)16
-rw-r--r--etc/dev/httpd.conf51
-rwxr-xr-xetc/dev/pgctl (renamed from etc/pgctl)0
-rw-r--r--etc/httpd.conf113
-rwxr-xr-xetc/loader18
-rw-r--r--etc/package-details.conf15
-rw-r--r--etc/package-search.conf13
-rw-r--r--etc/package-version-details.conf14
-rw-r--r--etc/repository-details.conf7
-rw-r--r--loader/loader.cxx1
-rw-r--r--tests/loader/driver.cxx1
-rw-r--r--web/apache/request8
-rw-r--r--web/apache/service39
-rw-r--r--web/apache/service.cxx66
-rw-r--r--web/apache/service.txx11
-rw-r--r--web/module47
42 files changed, 717 insertions, 499 deletions
diff --git a/brep/buildfile b/brep/buildfile
index b879b2d..0369098 100644
--- a/brep/buildfile
+++ b/brep/buildfile
@@ -4,7 +4,10 @@
using cli
-.: libso{brep brep-apache}
+# @@ The target should actually be mod_brep.so, not libmod_brep.so. Such
+# customization is not supported yet.
+#
+.: libso{brep mod_brep}
# brep library build rules.
#
@@ -17,25 +20,26 @@ brep = cxx{package package-traits package-odb}
libso{brep}: $brep $libs
libso{brep}: cxx.export.poptions = -I$out_root -I$src_root
-# brep-apache library build rules.
+# mod_brep library build rules.
#
import libs += libstudxml%lib{studxml}
-brep = cxx{diagnostics module services repository-root package-search \
- package-details package-version-details repository-details \
- shared-database page types-parsers} \
+brep = cxx{services diagnostics module repository-root package-search \
+ package-details package-version-details repository-details \
+ shared-database page types-parsers} \
cli.cxx{options}
web = ../web/apache/cxx{request service} ../web/cxx{mime-url-encoding}
-libso{brep-apache}: $brep $web libso{brep} $libs
+libso{mod_brep}: $brep $web libso{brep} $libs
# Set option prefix to the empty value to handle all unknown request parameters
# uniformly with a single catch block.
#
-cli.options += -I $src_root --include-with-brackets --include-prefix brep \
---guard-prefix BREP --cxx-prologue "#include <brep/types-parsers>" \
+cli.options += --std c++11 -I $src_root --include-with-brackets \
+--include-prefix brep --guard-prefix BREP \
+--cxx-prologue "#include <brep/types-parsers>" \
--cli-namespace brep::cli --generate-file-scanner --suppress-usage \
---option-prefix ""
+--generate-modifier --generate-description --option-prefix ""
cli.cxx{options}: cli{options}
diff --git a/brep/module b/brep/module
index 295744d..4ac6023 100644
--- a/brep/module
+++ b/brep/module
@@ -9,6 +9,7 @@
#include <brep/types>
#include <brep/utility>
+
#include <brep/options>
#include <brep/diagnostics>
@@ -23,6 +24,7 @@ namespace brep
using web::status_code;
using web::invalid_request;
using web::sequence_error;
+ using web::option_descriptions;
using web::name_value;
using web::name_values;
using web::request;
@@ -94,12 +96,24 @@ namespace brep
module ();
module (const module& );
+ static name_values
+ filter (const name_values&, const option_descriptions&);
+
+ static option_descriptions
+ convert (const cli::options&);
+
+ static void
+ append (option_descriptions& dst, const cli::options& src);
+
+ static void
+ append (option_descriptions& dst, const option_descriptions& src);
+
// Can be used by module implementation to parse HTTP request parameters.
//
- class param_scanner: public cli::scanner
+ class name_value_scanner: public cli::scanner
{
public:
- param_scanner (const name_values&) noexcept;
+ name_value_scanner (const name_values&) noexcept;
virtual bool
more ();
@@ -120,36 +134,43 @@ namespace brep
};
public:
- // Can be called normally by the web server or our custom request
- // dispatching mechanism.
- //
- virtual void
- handle (request&, response&) = 0;
+ virtual const cli::options&
+ cli_options () const = 0;
- bool
- loaded () const noexcept {return loaded_;}
+ virtual void
+ init (cli::scanner&) = 0;
- private:
+ // Can be overriden by custom request dispatcher to initialize sub-modules.
+ //
virtual void
- handle (request&, response&, log&);
+ init (const name_values&);
virtual void
init (const name_values&, log&);
- // Can be overriden by module implementation which has configuration
- // options.
+ virtual bool
+ handle (request&, response&) = 0;
+
+ // web::module interface.
//
- virtual void
- init (cli::scanner& s)
- {
- // Just scan options to ensure there is no misspelled ones.
- //
- options::module o (s, cli::unknown_mode::fail, cli::unknown_mode::fail);
- }
+ public:
+ // Custom request dispatcher can aggregate its own option descriptions with
+ // sub-modules option descriptions. In this case it should still call the
+ // base implementation in order to include the brep::module's options.
+ //
+ virtual option_descriptions
+ options ();
+
+ private:
+ virtual bool
+ handle (request&, response&, log&);
+
+ name_values
+ expand_options (const name_values&);
// Diagnostics implementation details.
//
- private:
+ protected:
log* log_ {nullptr}; // Diagnostics backend provided by the web server.
private:
diff --git a/brep/module.cxx b/brep/module.cxx
index 68177b1..253d807 100644
--- a/brep/module.cxx
+++ b/brep/module.cxx
@@ -18,6 +18,7 @@
#include <brep/types>
#include <brep/utility>
+
#include <brep/options>
using namespace std;
@@ -29,7 +30,7 @@ namespace brep
// module
//
- void module::
+ bool module::
handle (request& rq, response& rs, log& l)
{
assert (loaded_);
@@ -38,7 +39,7 @@ namespace brep
try
{
- handle (rq, rs);
+ return handle (rq, rs);
}
catch (const server_error& e)
{
@@ -74,24 +75,77 @@ namespace brep
// it.
}
}
+
+ return true;
+ }
+
+ option_descriptions module::
+ convert (const cli::options& o)
+ {
+ option_descriptions r;
+ append (r, o);
+ return r;
}
- // Parse options with a cli-generated scanner. Options verb and conf are
- // recognized by brep::module::init while others to be interpreted by the
- // derived class init method. If there is an option which can not be
- // interpreted not by brep::module::init nor by derived class init method
- // then web server is terminated with a corresponding error message being
- // logged.
- //
void module::
- init (const name_values& options, log& log)
+ append (option_descriptions& dst, const cli::options& src)
{
- assert (!loaded_);
+ for (const auto& o: src)
+ {
+ bool v (!o.flag ());
+ auto i (dst.emplace (o.name (), v));
+ assert (i.first->second == v); // Consistent option/flag.
- log_ = &log;
- vector<const char*> argv;
+ for (const auto& a: o.aliases ())
+ {
+ i = dst.emplace (a, v);
+ assert (i.first->second == v);
+ }
+ }
+ }
+
+ void module::
+ append (option_descriptions& dst, const option_descriptions& src)
+ {
+ for (const auto& o: src)
+ {
+ auto i (dst.emplace (o));
+ assert (i.first->second == o.second); // Consistent option/flag.
+ }
+ }
+
+ name_values module::
+ filter (const name_values& v, const option_descriptions& d)
+ {
+ name_values r;
+ for (const auto& nv: v)
+ {
+ if (d.find (nv.name) != d.end ())
+ r.push_back (nv);
+ }
+
+ return r;
+ }
+
+ // Convert CLI option descriptions to the general interface of option
+ // descriptions, extend with brep::module own option descriptions.
+ //
+ option_descriptions module::
+ options ()
+ {
+ option_descriptions r ({{"conf", true}});
+ append (r, options::module::description ());
+ append (r, cli_options ());
+ return r;
+ }
- for (const auto& nv: options)
+ // Expand option list parsing configuration files.
+ //
+ name_values module::
+ expand_options (const name_values& v)
+ {
+ vector<const char*> argv;
+ for (const auto& nv: v)
{
argv.push_back (nv.name.c_str ());
@@ -100,29 +154,60 @@ namespace brep
}
int argc (argv.size ());
+ argv_file_scanner s (0, argc, const_cast<char**> (argv.data ()), "conf");
+
+ name_values r;
+ const option_descriptions& o (options ());
+
+ while (s.more ())
+ {
+ string n (s.next ());
+ auto i (o.find (n));
+
+ if (i == o.end ())
+ throw unknown_argument (n);
+
+ optional<string> v;
+ if (i->second)
+ v = s.next ();
+
+ r.emplace_back (move (n), move (v));
+ }
+
+ return r;
+ }
+
+ // Parse options with a cli-generated scanner. Options verb and conf are
+ // recognized by brep::module::init while others to be interpreted by the
+ // derived init(). If there is an option which can not be interpreted
+ // neither by brep::module nor by the derived class, then the web server
+ // is terminated with a corresponding error message being logged. Though
+ // this should not happen if the options() function returned the correct
+ // set of options.
+ //
+ void module::
+ init (const name_values& options, log& log)
+ {
+ assert (!loaded_);
+
+ log_ = &log;
try
{
- {
- // Read module implementation configuration.
- //
- argv_file_scanner s (0,
- argc,
- const_cast<char**> (argv.data ()),
- "conf");
+ name_values opts (expand_options (options));
- init (s);
- }
+ // Read module implementation configuration.
+ //
+ init (opts);
// Read brep::module configuration.
//
- argv_file_scanner s (0,
- argc,
- const_cast<char**> (argv.data ()),
- "conf");
+ static option_descriptions od (convert (options::module::description ()));
+ name_values mo (filter (opts, od));
+ name_value_scanner s (mo);
+ options::module o (s, unknown_mode::fail, unknown_mode::fail);
- options::module o (s, unknown_mode::skip, unknown_mode::skip);
- verb_ = o.verb ();
+ verb_ = o.log_verbosity ();
loaded_ = true;
}
catch (const server_error& e)
@@ -138,6 +223,14 @@ namespace brep
}
}
+ void module::
+ init (const name_values& options)
+ {
+ name_value_scanner s (options);
+ init (s);
+ assert (!s.more ()); // Module didn't handle its options.
+ }
+
module::
module (): log_writer_ (bind (&module::log_write, this, _1)) {}
@@ -208,7 +301,7 @@ namespace brep
//@@ Cast log_ to apache::log and write the records.
//
- auto al (dynamic_cast<::web::apache::log*> (log_));
+ auto al (dynamic_cast<web::apache::log*> (log_));
if (al)
{
@@ -240,23 +333,23 @@ namespace brep
}
}
- // module::param_scanner
+ // module::name_value_scanner
//
- module::param_scanner::
- param_scanner (const name_values& nv) noexcept
+ module::name_value_scanner::
+ name_value_scanner (const name_values& nv) noexcept
: name_values_ (nv),
i_ (nv.begin ()),
name_ (true)
{
}
- bool module::param_scanner::
+ bool module::name_value_scanner::
more ()
{
return i_ != name_values_.end ();
}
- const char* module::param_scanner::
+ const char* module::name_value_scanner::
peek ()
{
if (i_ != name_values_.end ())
@@ -265,7 +358,7 @@ namespace brep
throw eos_reached ();
}
- const char* module::param_scanner::
+ const char* module::name_value_scanner::
next ()
{
if (i_ != name_values_.end ())
@@ -278,7 +371,7 @@ namespace brep
throw eos_reached ();
}
- void module::param_scanner::
+ void module::name_value_scanner::
skip ()
{
if (i_ != name_values_.end ())
diff --git a/brep/options.cli b/brep/options.cli
index fa05b56..d5041c8 100644
--- a/brep/options.cli
+++ b/brep/options.cli
@@ -3,6 +3,7 @@
// license : MIT; see accompanying LICENSE file
include <brep/types>;
+
include <brep/options-types>;
namespace brep
@@ -11,10 +12,12 @@ namespace brep
//
namespace options
{
+ // Option groups.
+ //
class module
{
- uint16_t verb;
- dir_path root;
+ uint16_t log-verbosity;
+ dir_path root = "/";
};
class db
@@ -23,28 +26,39 @@ namespace brep
uint16_t db-port = 5432;
};
- class package_search: module, db
+ class search
+ {
+ uint16_t search-results = 10;
+ uint16_t pager-pages = 5;
+ };
+
+ class package
+ {
+ uint16_t description-len = 500; // ~ 80 chars x 6 lines.
+ uint16_t changes-len = 5000; // ~ 80 chars x 60 lines.
+ };
+
+ // Module options.
+ //
+ class package_search: module, db, search
{
- uint16_t results-on-page = 10;
- uint16_t pages-in-pager = 5;
};
- class package_details: module, db
+ class package_details: module, db, search, package
{
- uint16_t results-on-page = 10;
- uint16_t pages-in-pager = 5;
- uint16_t description-length = 500; // ~ 80 chars x 6 lines.
};
- class package_version_details: module, db
+ class package_version_details: module, db, package
{
- uint16_t description-length = 500; // ~ 80 chars x 6 lines.
- uint16_t changes-length = 5000; // ~ 80 chars x 60 lines.
};
class repository_details: module, db
{
};
+
+ class repository_root: module
+ {
+ };
}
// Web module HTTP request parameters.
diff --git a/brep/package-details b/brep/package-details
index 214a0fe..6766797 100644
--- a/brep/package-details
+++ b/brep/package-details
@@ -8,6 +8,7 @@
#include <odb/forward.hxx> // database
#include <brep/types>
+
#include <brep/module>
#include <brep/options>
@@ -15,10 +16,14 @@ namespace brep
{
class package_details: public module
{
- private:
- virtual void
+ public:
+ virtual bool
handle (request&, response&);
+ virtual const cli::options&
+ cli_options () const {return options::package_details::description ();}
+
+ private:
virtual void
init (cli::scanner&);
diff --git a/brep/package-details.cxx b/brep/package-details.cxx
index 4b99feb..30e185e 100644
--- a/brep/package-details.cxx
+++ b/brep/package-details.cxx
@@ -14,9 +14,10 @@
#include <web/module>
#include <web/mime-url-encoding>
-#include <brep/page>
#include <brep/types>
#include <brep/utility>
+
+#include <brep/page>
#include <brep/options>
#include <brep/package>
#include <brep/package-odb>
@@ -33,6 +34,9 @@ init (scanner& s)
options_ = make_shared<options::package_details> (
s, unknown_mode::fail, unknown_mode::fail);
+ if (options_->root ().empty ())
+ options_->root (dir_path ("/"));
+
db_ = shared_database (options_->db_host (), options_->db_port ());
}
@@ -51,7 +55,7 @@ search_params (const brep::string& n, const brep::string& q)
")";
}
-void brep::package_details::
+bool brep::package_details::
handle (request& rq, response& rs)
{
using namespace web;
@@ -62,11 +66,8 @@ handle (request& rq, response& rs)
// The module options object is not changed after being created once per
// server process.
//
- static const size_t res_page (options_->results_on_page ());
- static const dir_path& root (
- options_->root ().empty ()
- ? dir_path ("/")
- : options_->root ());
+ static const size_t res_page (options_->search_results ());
+ static const dir_path& root (options_->root ());
const string& name (*rq.path ().rbegin ());
const string ename (mime_url_encode (name));
@@ -76,7 +77,7 @@ handle (request& rq, response& rs)
try
{
- param_scanner s (rq.parameters ());
+ name_value_scanner s (rq.parameters ());
params = params::package_details (
s, unknown_mode::fail, unknown_mode::fail);
@@ -159,7 +160,7 @@ handle (request& rq, response& rs)
if (const auto& d = pkg->description)
s << (full
? P_DESCRIPTION (*d, id)
- : P_DESCRIPTION (*d, options_->description_length (),
+ : P_DESCRIPTION (*d, options_->description_len (),
url (!full, squery, page, id)));
s << TABLE(CLASS="proplist", ID="package")
@@ -231,9 +232,11 @@ handle (request& rq, response& rs)
t.commit ();
- s << DIV_PAGER (page, pkg_count, res_page, options_->pages_in_pager (),
+ s << DIV_PAGER (page, pkg_count, res_page, options_->pager_pages (),
url (full, squery))
<< ~DIV
<< ~BODY
<< ~HTML;
+
+ return true;
}
diff --git a/brep/package-search b/brep/package-search
index a5c441e..63ec6e0 100644
--- a/brep/package-search
+++ b/brep/package-search
@@ -8,6 +8,7 @@
#include <odb/forward.hxx> // database
#include <brep/types>
+
#include <brep/module>
#include <brep/options>
@@ -15,10 +16,14 @@ namespace brep
{
class package_search: public module
{
- private:
- virtual void
+ public:
+ virtual bool
handle (request&, response&);
+ virtual const cli::options&
+ cli_options () const {return options::package_search::description ();}
+
+ private:
virtual void
init (cli::scanner&);
diff --git a/brep/package-search.cxx b/brep/package-search.cxx
index f2f922c..62b162b 100644
--- a/brep/package-search.cxx
+++ b/brep/package-search.cxx
@@ -14,9 +14,10 @@
#include <web/module>
#include <web/mime-url-encoding>
-#include <brep/page>
#include <brep/types>
#include <brep/utility>
+
+#include <brep/page>
#include <brep/options>
#include <brep/package>
#include <brep/package-odb>
@@ -33,6 +34,9 @@ init (scanner& s)
options_ = make_shared<options::package_search> (
s, unknown_mode::fail, unknown_mode::fail);
+ if (options_->root ().empty ())
+ options_->root (dir_path ("/"));
+
db_ = shared_database (options_->db_host (), options_->db_port ());
}
@@ -48,7 +52,7 @@ search_param (const brep::string& q)
")";
}
-void brep::package_search::
+bool brep::package_search::
handle (request& rq, response& rs)
{
using namespace web::xhtml;
@@ -58,17 +62,14 @@ handle (request& rq, response& rs)
// The module options object is not changed after being created once per
// server process.
//
- static const size_t res_page (options_->results_on_page ());
- static const dir_path& root (
- options_->root ().empty ()
- ? dir_path ("/")
- : options_->root ());
+ static const size_t res_page (options_->search_results ());
+ static const dir_path& root (options_->root ());
params::package_search params;
try
{
- param_scanner s (rq.parameters ());
+ name_value_scanner s (rq.parameters ());
params = params::package_search (s, unknown_mode::fail, unknown_mode::fail);
}
catch (const unknown_argument& e)
@@ -137,9 +138,11 @@ handle (request& rq, response& rs)
t.commit ();
- s << DIV_PAGER (page, pkg_count, res_page, options_->pages_in_pager (),
+ s << DIV_PAGER (page, pkg_count, res_page, options_->pager_pages (),
root.string () + squery_param)
<< ~DIV
<< ~BODY
<< ~HTML;
+
+ return true;
}
diff --git a/brep/package-version-details b/brep/package-version-details
index 36b7420..8057097 100644
--- a/brep/package-version-details
+++ b/brep/package-version-details
@@ -8,6 +8,7 @@
#include <odb/forward.hxx> // database
#include <brep/types>
+
#include <brep/module>
#include <brep/options>
@@ -15,10 +16,17 @@ namespace brep
{
class package_version_details: public module
{
- private:
- virtual void
+ public:
+ virtual bool
handle (request&, response&);
+ virtual const cli::options&
+ cli_options () const
+ {
+ return options::package_version_details::description ();
+ }
+
+ private:
virtual void
init (cli::scanner&);
diff --git a/brep/package-version-details.cxx b/brep/package-version-details.cxx
index a0ad7d4..8f6cd7d 100644
--- a/brep/package-version-details.cxx
+++ b/brep/package-version-details.cxx
@@ -16,9 +16,10 @@
#include <web/module>
#include <web/mime-url-encoding>
-#include <brep/page>
#include <brep/types>
#include <brep/utility>
+
+#include <brep/page>
#include <brep/options>
#include <brep/package>
#include <brep/package-odb>
@@ -36,10 +37,13 @@ init (scanner& s)
options_ = make_shared<options::package_version_details> (
s, unknown_mode::fail, unknown_mode::fail);
+ if (options_->root ().empty ())
+ options_->root (dir_path ("/"));
+
db_ = shared_database (options_->db_host (), options_->db_port ());
}
-void brep::package_version_details::
+bool brep::package_version_details::
handle (request& rq, response& rs)
{
using namespace web;
@@ -50,10 +54,7 @@ handle (request& rq, response& rs)
// The module options object is not changed after being created once per
// server process.
//
- static const dir_path& root (
- options_->root ().empty ()
- ? dir_path ("/")
- : options_->root ());
+ static const dir_path& root (options_->root ());
auto i (rq.path ().rbegin ());
version ver;
@@ -77,7 +78,7 @@ handle (request& rq, response& rs)
try
{
- param_scanner s (rq.parameters ());
+ name_value_scanner s (rq.parameters ());
params = params::package_version_details (
s, unknown_mode::fail, unknown_mode::fail);
@@ -151,7 +152,7 @@ handle (request& rq, response& rs)
if (const auto& d = pkg->description)
s << (full
? P_DESCRIPTION (*d, id)
- : P_DESCRIPTION (*d, options_->description_length (),
+ : P_DESCRIPTION (*d, options_->description_len (),
url (!full, id)));
assert (pkg->location);
@@ -301,10 +302,11 @@ handle (request& rq, response& rs)
s << H3 << "Changes" << ~H3
<< (full
? PRE_CHANGES (ch)
- : PRE_CHANGES (ch, options_->description_length (),
- url (!full, "changes")));
+ : PRE_CHANGES (ch, options_->changes_len (), url (!full, "changes")));
s << ~DIV
<< ~BODY
<< ~HTML;
+
+ return true;
}
diff --git a/brep/package.cxx b/brep/package.cxx
index ecaa369..c221fe8 100644
--- a/brep/package.cxx
+++ b/brep/package.cxx
@@ -10,6 +10,7 @@
#include <brep/types>
#include <brep/utility>
+
#include <brep/package-odb>
using namespace std;
diff --git a/brep/page b/brep/page
index 907bc45..9868984 100644
--- a/brep/page
+++ b/brep/page
@@ -8,6 +8,7 @@
#include <xml/forward>
#include <brep/types>
+
#include <brep/package>
namespace brep
diff --git a/brep/page.cxx b/brep/page.cxx
index 780d759..638a72b 100644
--- a/brep/page.cxx
+++ b/brep/page.cxx
@@ -17,6 +17,7 @@
#include <brep/types>
#include <brep/utility>
+
#include <brep/package>
#include <brep/package-odb>
diff --git a/brep/repository-details b/brep/repository-details
index fb41e32..7efc6a6 100644
--- a/brep/repository-details
+++ b/brep/repository-details
@@ -8,6 +8,7 @@
#include <odb/forward.hxx> // database
#include <brep/types>
+
#include <brep/module>
#include <brep/options>
@@ -15,10 +16,14 @@ namespace brep
{
class repository_details: public module
{
- private:
- virtual void
+ public:
+ virtual bool
handle (request&, response&);
+ virtual const cli::options&
+ cli_options () const {return options::repository_details::description ();}
+
+ private:
virtual void
init (cli::scanner&);
diff --git a/brep/repository-details.cxx b/brep/repository-details.cxx
index eb2885c..ee34dc2 100644
--- a/brep/repository-details.cxx
+++ b/brep/repository-details.cxx
@@ -13,9 +13,10 @@
#include <web/module>
#include <web/mime-url-encoding>
-#include <brep/page>
#include <brep/types>
#include <brep/utility>
+
+#include <brep/page>
#include <brep/options>
#include <brep/package>
#include <brep/package-odb>
@@ -32,10 +33,13 @@ init (scanner& s)
options_ = make_shared<options::repository_details> (
s, unknown_mode::fail, unknown_mode::fail);
+ if (options_->root ().empty ())
+ options_->root (dir_path ("/"));
+
db_ = shared_database (options_->db_host (), options_->db_port ());
}
-void brep::repository_details::
+bool brep::repository_details::
handle (request& rq, response& rs)
{
using namespace web::xhtml;
@@ -45,16 +49,13 @@ handle (request& rq, response& rs)
// The module options object is not changed after being created once per
// server process.
//
- static const dir_path& root (
- options_->root ().empty ()
- ? dir_path ("/")
- : options_->root ());
+ static const dir_path& root (options_->root ());
// Make sure no parameters passed.
//
try
{
- param_scanner s (rq.parameters ());
+ name_value_scanner s (rq.parameters ());
params::repository_details (s, unknown_mode::fail, unknown_mode::fail);
}
catch (const unknown_argument& e)
@@ -106,4 +107,6 @@ handle (request& rq, response& rs)
s << ~DIV
<< ~BODY
<< ~HTML;
+
+ return true;
}
diff --git a/brep/repository-root b/brep/repository-root
index e5fba78..2397764 100644
--- a/brep/repository-root
+++ b/brep/repository-root
@@ -5,26 +5,45 @@
#ifndef BREP_REPOSITORY_ROOT
#define BREP_REPOSITORY_ROOT
+#include <brep/types>
+
#include <brep/module>
+#include <brep/options>
namespace brep
{
class package_search;
+ class package_details;
+ class package_version_details;
class repository_details;
class repository_root: public module
{
public:
- repository_root (package_search& ps, repository_details& rd)
- : package_search_ (ps), repository_details_ (rd) {}
+ repository_root ();
private:
- virtual void
+ virtual bool
handle (request&, response&);
+ virtual const cli::options&
+ cli_options () const {return options::repository_root::description ();}
+
+ virtual option_descriptions
+ options ();
+
+ virtual void
+ init (const name_values&);
+
+ virtual void
+ init (cli::scanner&);
+
private:
- package_search& package_search_;
- repository_details& repository_details_;
+ shared_ptr<package_search> package_search_;
+ shared_ptr<package_details> package_details_;
+ shared_ptr<package_version_details> package_version_details_;
+ shared_ptr<repository_details> repository_details_;
+ shared_ptr<options::repository_root> options_;
};
}
diff --git a/brep/repository-root.cxx b/brep/repository-root.cxx
index 180d61f..7af76b2 100644
--- a/brep/repository-root.cxx
+++ b/brep/repository-root.cxx
@@ -4,17 +4,22 @@
#include <brep/repository-root>
-#include <map>
-#include <functional>
+#include <sstream>
#include <web/module>
#include <brep/types>
#include <brep/utility>
+
+#include <brep/module>
+#include <brep/options>
#include <brep/package-search>
+#include <brep/package-details>
#include <brep/repository-details>
+#include <brep/package-version-details>
using namespace std;
+using namespace brep::cli;
namespace brep
{
@@ -45,75 +50,141 @@ namespace brep
// repository_root
//
+ repository_root::
+ repository_root ()
+ : package_search_ (make_shared<package_search> ()),
+ package_details_ (make_shared<package_details> ()),
+ package_version_details_ (make_shared<package_version_details> ()),
+ repository_details_ (make_shared<repository_details> ())
+ {
+ }
+
+ // Return amalgamation of repository_root and all its sub-modules option
+ // descriptions.
+ //
+ option_descriptions repository_root::
+ options ()
+ {
+ option_descriptions r (module::options ());
+ append (r, package_search_->options ());
+ append (r, package_details_->options ());
+ append (r, package_version_details_->options ());
+ append (r, repository_details_->options ());
+ return r;
+ }
+
+ // Initialize sub-modules and parse own configuration options.
+ //
void repository_root::
- handle (request& rq, response& rs)
+ init (const name_values& v)
{
- MODULE_DIAG;
+ auto sub_init ([this, &v](module& m)
+ {
+ m.init (filter (v, m.options ()), *log_);
+ });
- // Dispatch request handling to the appropriate module depending on the
- // function name passed as a first HTTP request parameter. The parameter
- // should have no value specified. If no function name is passed,
- // the default handler is selected. Example: cppget.org/?about
+ // Initialize sub-modules.
//
+ sub_init (*package_search_);
+ sub_init (*package_details_);
+ sub_init (*package_version_details_);
+ sub_init (*repository_details_);
- string func;
- name_values params (rq.parameters ());
-
- // Obtain the function name.
+ // Parse own configuration options.
//
- if (!params.empty () && !params.front ().value)
- {
- func = move (params.front ().name);
+ module::init (
+ filter (v, convert (options::repository_root::description ())));
+ }
- // Cleanup not to confuse the selected handler with the unknown parameter.
- //
- params.erase (params.begin ());
- }
+ void repository_root::
+ init (scanner& s)
+ {
+ MODULE_DIAG;
- // To handle the request a new module instance is created as a copy of
- // the corresponsing exemplar.
- //
- using module_ptr = unique_ptr<module>;
+ options_ = make_shared<options::repository_root> (
+ s, unknown_mode::fail, unknown_mode::fail);
- // Function name to module factory map.
- //
- const map<string, function<module_ptr()>>
- handlers ({
- {
- "about",
- [this]() -> module_ptr
- {return module_ptr (new repository_details (repository_details_));}
- },
- {
- string (), // The default handler.
- [this]() -> module_ptr
- {return module_ptr (new package_search (package_search_));}
- }});
+ if (options_->root ().empty ())
+ options_->root (dir_path ("/"));
+ }
- // Find proper handler.
- //
- auto i (handlers.find (func));
- if (i == handlers.end ())
- throw invalid_request (400, "unknown function");
+ bool repository_root::
+ handle (request& rq, response& rs)
+ {
+ MODULE_DIAG;
- module_ptr m (i->second ());
- if (m->loaded ())
+ static const dir_path& root (options_->root ());
+
+ const path& rpath (rq.path ());
+ if (!rpath.sub (root))
+ return false;
+
+ const path& lpath (rpath.leaf (root));
+
+ // @@ An exception thrown by the selected module handle () function call
+ // will be attributed to the repository-root service while being logged.
+ // Could intercept exception handling to add some sub-module attribution,
+ // but let's not complicate the code for the time being.
+ //
+ if (lpath.empty ())
{
- // Delegate request handling.
- //
- // @@ An exception thrown by the handler will be attributed to the
- // repository-root service while being logged. Could intercept
- // exception handling to fix that, but let's not complicate the
- // code for the time being.
+ // Dispatch request handling to the repository_details or the
+ // package_search module depending on the function name passed as a
+ // first HTTP request parameter. The parameter should have no value
+ // specified. Example: cppget.org/?about
//
- //
- request_proxy rqp (rq, params);
- m->handle (rqp, rs);
+ const name_values& params (rq.parameters ());
+ if (!params.empty () && !params.front ().value)
+ {
+ if (params.front ().name == "about")
+ {
+ // Cleanup not to confuse the selected module with the unknown
+ // parameter.
+ //
+ name_values p (params);
+ p.erase (p.begin ());
+
+ request_proxy rp (rq, p);
+ repository_details m (*repository_details_);
+ return m.handle (rp, rs);
+ }
+
+ throw invalid_request (400, "unknown function");
+ }
+ else
+ {
+ package_search m (*package_search_);
+ return m.handle (rq, rs);
+ }
}
else
- // The module is not loaded, presumably being disabled in the web server
- // configuration file.
+ {
+ // Dispatch request handling to the package_details or the
+ // package_version_details module depending on the HTTP request URL path.
+ //
+ auto i (lpath.begin ());
+ assert (i != lpath.end ());
+
+ const string& n (*i++); // Package name.
+
+ // Check if this is a package name and not a brep static content files
+ // (CSS) directory name or a repository directory name.
//
- throw invalid_request (404, "handler not available");
+ if (n != "@" && n.find_first_not_of ("0123456789") != string::npos)
+ {
+ if (i == lpath.end ())
+ {
+ package_details m (*package_details_);
+ return m.handle (rq, rs);
+ }
+ else if (++i == lpath.end ())
+ {
+ package_version_details m (*package_version_details_);
+ return m.handle (rq, rs);
+ }
+ }
+ }
+
+ return false;
}
}
diff --git a/brep/services.cxx b/brep/services.cxx
index b214a09..dcac22c 100644
--- a/brep/services.cxx
+++ b/brep/services.cxx
@@ -6,41 +6,7 @@
#include <web/apache/service>
-#include <brep/package-search>
-#include <brep/package-details>
#include <brep/repository-root>
-#include <brep/repository-details>
-#include <brep/package-version-details>
-using namespace brep;
-using web::apache::service;
-
-static package_search package_search_mod;
-service AP_MODULE_DECLARE_DATA package_search_srv (
- "package-search",
- package_search_mod,
- {"root", "db-host", "db-port", "conf"});
-
-static package_details package_details_mod;
-service AP_MODULE_DECLARE_DATA package_details_srv (
- "package-details",
- package_details_mod,
- {"root", "db-host", "db-port", "conf"});
-
-static package_version_details package_version_details_mod;
-service AP_MODULE_DECLARE_DATA package_version_details_srv (
- "package-version-details",
- package_version_details_mod,
- {"root", "db-host", "db-port", "conf"});
-
-static repository_details repository_details_mod;
-service AP_MODULE_DECLARE_DATA repository_details_srv (
- "repository-details",
- repository_details_mod,
- {"root", "db-host", "db-port", "conf"});
-
-static repository_root repository_root_mod (
- package_search_mod, repository_details_mod);
-service AP_MODULE_DECLARE_DATA repository_root_srv (
- "repository-root",
- repository_root_mod);
+static brep::repository_root mod;
+web::apache::service AP_MODULE_DECLARE_DATA brep_module ("brep", mod);
diff --git a/brep/shared-database.cxx b/brep/shared-database.cxx
index c1d128f..db6b811 100644
--- a/brep/shared-database.cxx
+++ b/brep/shared-database.cxx
@@ -19,10 +19,9 @@ namespace brep
using odb::pgsql::database;
static weak_ptr<database> db;
- // In C++11, function-static variable initialization is
- // guaranteed to be thread-safe, thought this doesn't
- // seem to be enough in our case (because we are re-
- // initializing the weak pointer).
+ // In C++11, function-static variable initialization is guaranteed to be
+ // thread-safe, thought this doesn't seem to be enough in our case
+ // (because we are re-initializing the weak pointer).
//
if (shared_ptr<database> d = db.lock ())
{
diff --git a/brep/types-parsers b/brep/types-parsers
index dfe86a6..3165518 100644
--- a/brep/types-parsers
+++ b/brep/types-parsers
@@ -9,6 +9,7 @@
#define BREP_TYPES_PARSERS
#include <brep/types>
+
#include <brep/options-types>
namespace brep
diff --git a/brep/types-parsers.cxx b/brep/types-parsers.cxx
index f7f1c1b..39c9b42 100644
--- a/brep/types-parsers.cxx
+++ b/brep/types-parsers.cxx
@@ -5,6 +5,7 @@
#include <brep/types-parsers>
#include <brep/types>
+
#include <brep/options>
using namespace std;
diff --git a/build.sh b/build.sh
index e04cb32..5772f85 100755
--- a/build.sh
+++ b/build.sh
@@ -24,24 +24,24 @@ g++ -shared $DEBUG -std=c++11 -I.. -I../../libbpkg \
-I../../libbutl -L../../libbpkg/bpkg -L../../libbutl/butl \
-fPIC -o libbrep.so $s -lbpkg -lbutl -lodb-pgsql -lodb
-echo "cli brep-apache options"
+echo "cli mod_brep options"
cli --include-with-brackets --include-prefix brep --hxx-suffix "" \
--guard-prefix BREP --cxx-prologue "#include <brep/types-parsers>" \
--cli-namespace brep::cli --generate-file-scanner --suppress-usage \
- --option-prefix "" ./options.cli
+ --generate-modifier --generate-description --option-prefix "" ./options.cli
-echo "g++ libbrep-apache.so"
+echo "g++ libmod_brep.so"
-s="package-search.cxx package-details.cxx package-version-details.cxx \
-repository-details.cxx repository-root.cxx module.cxx page.cxx services.cxx \
-options.cxx shared-database.cxx diagnostics.cxx \
+s="options.cxx services.cxx package-search.cxx package-details.cxx \
+package-version-details.cxx repository-details.cxx repository-root.cxx \
+module.cxx page.cxx shared-database.cxx diagnostics.cxx \
../web/apache/request.cxx ../web/apache/service.cxx \
../web/mime-url-encoding.cxx"
g++ -shared $DEBUG -std=c++11 -I/usr/include/apr-1 -I/usr/include/httpd \
-I.. -I../../libbpkg -I../../libbutl -L. -L../../libbpkg/bpkg \
- -fPIC -o libbrep-apache.so $s -lbrep -lbpkg -lodb-pgsql -lodb -lstudxml
+ -fPIC -o libmod_brep.so $s -lbrep -lbpkg -lodb-pgsql -lodb -lstudxml
cd ../loader
diff --git a/etc/brep.conf b/etc/brep.conf
new file mode 100644
index 0000000..6f806e8
--- /dev/null
+++ b/etc/brep.conf
@@ -0,0 +1,49 @@
+# The brep.conf file can be included once into Apache configuration file in
+# the <VirtualHost> section or in the main server context.
+#
+LoadModule brep_module modules/mod_brep.so
+LoadModule alias_module modules/mod_alias.so
+
+# Alternatively, if loading the modules in another place, make sure they
+# are loaded.
+#
+<IfModule !brep_module>
+ Error "mod_brep is not loaded"
+</IfModule>
+
+<IfModule !alias_module>
+ Error "mod_alias is not loaded"
+</IfModule>
+
+# To use a repository root other than /pkg/, replace all occurrences of
+# /pkg/ with the desired alternative root (use '/' for webserver root).
+#
+brep-root /pkg/
+brep-db-host localhost
+brep-db-port 5432
+brep-search-results 10
+brep-pager-pages 5
+brep-description-len 500
+brep-changes-len 5000
+brep-log-verbosity 0
+
+# To override brep module options place them into the separate configuration
+# file, suppressing the "brep-" prefix.
+#
+#brep-conf /path/to/brep-site.conf
+
+SetHandler brep
+
+# Location of the brep static content (CSS files).
+#
+Alias /pkg/@/ /usr/share/brep/static/
+
+<Directory "/usr/share/brep/static">
+ Require all granted
+</Directory>
+
+# Serve repository files from the repository root path. For example:
+#
+# http://example.org/pkg/1/... -> /path/to/repo/1/...
+#
+#AliasMatch ^/pkg/(\d+)/(.+) /path/to/repo/$1/$2
diff --git a/etc/apachectl b/etc/dev/apachectl
index 4c67c1f..4d45570 100755
--- a/etc/apachectl
+++ b/etc/dev/apachectl
@@ -20,14 +20,16 @@
# 8 - configuration syntax error
#
# When multiple arguments are given, only the error from the _last_
-# one is reported. Run "apachectl help" for usage info
+# one is reported. Run "apachectl help" for usage info.
+#
. `dirname $0`/config
ARGV="$@"
export AP_PORT
-export AP_SERVER_NAME
+export AP_GLOBAL_SERVER_NAME
+export AP_BREP_SERVER_NAME
export AP_ROOT
export AP_ADMIN_EMAIL
export AP_LOG_LEVEL
@@ -36,41 +38,55 @@ export AP_DB_PORT
export AP_MODULE_DIR
export AP_WWW_DIR
export AP_CONFIG_DIR
+export AP_LOG_DIR
export AP_WORKSPACE_DIR
export AP_REPOSITORY_DIR
-if test -n "$AP_LIB_DIRS"; then
- export LD_LIBRARY_PATH=$AP_LIB_DIRS:$LD_LIBRARY_PATH
+if [ -n "$AP_LIB_DIRS" ] ; then
+ export LD_LIBRARY_PATH=$AP_LIB_DIRS:$LD_LIBRARY_PATH
fi
mkdir -p "$AP_WORKSPACE_DIR"
mkdir -p "$AP_LOG_DIR"
mkdir -p "$AP_REPOSITORY_DIR"
-# the path to your httpd binary, including options if necessary
-
-HTTPD="/usr/sbin/httpd -d $AP_LOG_DIR -f $AP_CONFIG_DIR/httpd.conf"
+cat "$AP_CONFIG_DIR/../brep.conf" | \
+sed -e 's%modules\(/mod_brep.so\)%${AP_MODULE_DIR}\1%g' \
+ -e 's%/pkg/%${AP_ROOT}%g' \
+ -e 's%^\(brep-db-port\s*\).*%\1${AP_DB_PORT}%g' \
+ -e 's%^\(brep-db-host\s*\).*%\1${AP_DB_HOST}%g' \
+ -e 's%^#\(brep-conf\s*\)/path/to%\1${AP_CONFIG_DIR}%g' \
+ -e 's%/usr/share/brep/static%${AP_WWW_DIR}%g' \
+ -e 's%^#\(AliasMatch.*\)/path/to/repo%\1${AP_REPOSITORY_DIR}%g' \
+> "$AP_CONFIG_DIR/brep.conf"
+
+# The path to your httpd binary, including options if necessary.
+#
+HTTPD="/usr/sbin/httpd -f $AP_CONFIG_DIR/httpd.conf"
-# a command that outputs a formatted text version of the HTML at the
-# url given on the command line. Designed for lynx, however other
-# programs may work.
+# The command that outputs a formatted text version of the HTML at the url
+# given on the command line. Designed for lynx, however other programs may work.
+#
LYNX="lynx -dump"
-# the URL to your server's mod_status status page. If you do not
-# have one, then status and fullstatus will not work.
+# The URL to your server's mod_status status page. If you do not have one,
+# then status and fullstatus will not work.
+#
STATUSURL="http://localhost:$AP_PORT/server-status"
-# Set this variable to a command that increases the maximum
-# number of file descriptors allowed per child process. This is
-# critical for configurations that use many file descriptors,
-# such as mass vhosting, or a multithreaded server.
+# Set this variable to a command that increases the maximum number of file
+# descriptors allowed per child process. This is critical for configurations
+# that use many file descriptors, such as mass vhosting, or a multithreaded
+# server.
+#
ULIMIT_MAX_FILES="ulimit -S -n `ulimit -H -n`"
# -------------------- --------------------
# |||||||||||||||||||| END CONFIGURATION SECTION ||||||||||||||||||||
# Set the maximum number of file descriptors allowed per child process.
+#
if [ "x$ULIMIT_MAX_FILES" != "x" ] ; then
- $ULIMIT_MAX_FILES
+ $ULIMIT_MAX_FILES
fi
ERROR=0
diff --git a/etc/brep b/etc/dev/brep
index 3ec448b..3ec448b 100755
--- a/etc/brep
+++ b/etc/dev/brep
diff --git a/etc/dev/brep-site.conf b/etc/dev/brep-site.conf
new file mode 100644
index 0000000..09f020c
--- /dev/null
+++ b/etc/dev/brep-site.conf
@@ -0,0 +1,9 @@
+# file : etc/brep-site.conf
+# copyright : Copyright (c) 2014-2015 Code Synthesis Ltd
+# license : MIT; see accompanying LICENSE file
+#
+
+search-results 2
+description-len 100
+changes-len 100
+log-verbosity 1
diff --git a/etc/config b/etc/dev/config
index c7edd56..cdd0b53 100644
--- a/etc/config
+++ b/etc/dev/config
@@ -2,7 +2,7 @@
#
SCRIPT_DIR=`dirname $0`
CONFIG_DIR=`cd $SCRIPT_DIR; pwd`
-PROJECT_DIR="$CONFIG_DIR/.."
+PROJECT_DIR="$CONFIG_DIR/../.."
WORKSPACE_DIR="$PROJECT_DIR/var"
LIB_DIRS="$PROJECT_DIR/brep:$PROJECT_DIR/../libbutl/butl:$PROJECT_DIR/../libbpkg/bpkg"
@@ -17,9 +17,9 @@ PG_WORKSPACE_DIR="$WORKSPACE_DIR/run/pgsql"
# Apache settings (used in apachectl)
#
AP_PORT=8080
-AP_SERVER_NAME="cppget.org:$AP_PORT"
-AP_ROOT="" # Value examples: "", "/foo", "/foo/bar".
-AP_ADMIN_EMAIL=admin@cppget.org
+AP_GLOBAL_SERVER_NAME="localhost"
+AP_BREP_SERVER_NAME="dev.cppget.org"
+AP_ROOT="/" # Value examples: "/", "/foo/", "/foo/bar/".
AP_LOG_LEVEL=trace1
AP_DB_HOST="$PG_WORKSPACE_DIR"
AP_DB_PORT=$PG_PORT
@@ -30,11 +30,3 @@ AP_CONFIG_DIR="$CONFIG_DIR"
AP_LOG_DIR="$WORKSPACE_DIR/log/httpd"
AP_WORKSPACE_DIR="$WORKSPACE_DIR/run/httpd"
AP_REPOSITORY_DIR="$WORKSPACE_DIR/www"
-
-# brep-loader settings (used in loader)
-#
-LD_DB_HOST="$PG_WORKSPACE_DIR"
-LD_DB_PORT=$PG_PORT
-LD_REPOSITORIES="$CONFIG_DIR/repositories.conf"
-LD_LIB_DIRS="$LIB_DIRS"
-LD_EXE_DIRS="$PROJECT_DIR/loader"
diff --git a/etc/dev/httpd.conf b/etc/dev/httpd.conf
new file mode 100644
index 0000000..5943d70
--- /dev/null
+++ b/etc/dev/httpd.conf
@@ -0,0 +1,51 @@
+Listen ${AP_PORT}
+ServerName ${AP_GLOBAL_SERVER_NAME}:${AP_PORT}
+
+CoreDumpDirectory "${AP_WORKSPACE_DIR}"
+PidFile "${AP_WORKSPACE_DIR}/httpd.pid"
+
+ErrorLog "|/usr/sbin/rotatelogs ${AP_LOG_DIR}/error_log.%Y%m%d 86400"
+ErrorLogFormat "[%t] [%l] [%m] %M"
+LogLevel ${AP_LOG_LEVEL}
+
+Timeout 60
+KeepAlive On
+KeepAliveTimeout 3
+
+ThreadLimit 1000
+ServerLimit 2
+StartServers 1
+MaxClients 1000
+MinSpareThreads 400
+MaxSpareThreads 600
+ThreadsPerChild 500
+MaxRequestsPerChild 0
+
+LoadModule mpm_worker_module modules/mod_mpm_worker.so
+LoadModule unixd_module modules/mod_unixd.so
+LoadModule filter_module modules/mod_filter.so
+LoadModule authz_core_module modules/mod_authz_core.so
+LoadModule authz_host_module modules/mod_authz_host.so
+LoadModule status_module modules/mod_status.so
+LoadModule mime_module modules/mod_mime.so
+LoadModule deflate_module modules/mod_deflate.so
+
+<VirtualHost *:${AP_PORT}>
+ ServerName ${AP_GLOBAL_SERVER_NAME}
+</VirtualHost>
+
+<VirtualHost *:${AP_PORT}>
+ ServerName ${AP_BREP_SERVER_NAME}
+ Include ${AP_CONFIG_DIR}/brep.conf
+</VirtualHost>
+
+ExtendedStatus On
+
+<Location /server-status>
+ SetHandler server-status
+ Require local
+</Location>
+
+TypesConfig /etc/mime.types
+AddOutputFilterByType DEFLATE application/xhtml+xml
+AddOutputFilterByType DEFLATE text/css
diff --git a/etc/pgctl b/etc/dev/pgctl
index d1f676f..d1f676f 100755
--- a/etc/pgctl
+++ b/etc/dev/pgctl
diff --git a/etc/httpd.conf b/etc/httpd.conf
deleted file mode 100644
index dc56d9b..0000000
--- a/etc/httpd.conf
+++ /dev/null
@@ -1,113 +0,0 @@
-Listen ${AP_PORT}
-ServerName "${AP_SERVER_NAME}"
-ServerAdmin "${AP_ADMIN_EMAIL}"
-
-User apache
-Group apache
-
-CoreDumpDirectory "${AP_WORKSPACE_DIR}"
-PidFile "${AP_WORKSPACE_DIR}/httpd.pid"
-
-ErrorLog "|/usr/sbin/rotatelogs error_log.%Y%m%d 86400"
-ErrorLogFormat "[%t] [%l] [%m] %M"
-LogLevel ${AP_LOG_LEVEL}
-
-Timeout 60
-KeepAlive On
-KeepAliveTimeout 3
-
-ThreadLimit 1000
-ServerLimit 2
-StartServers 1
-MaxClients 1000
-MinSpareThreads 400
-MaxSpareThreads 600
-ThreadsPerChild 500
-MaxRequestsPerChild 0
-
-LoadModule mpm_worker_module /usr/lib64/httpd/modules/mod_mpm_worker.so
-LoadModule unixd_module /usr/lib64/httpd/modules/mod_unixd.so
-LoadModule filter_module /usr/lib64/httpd/modules/mod_filter.so
-LoadModule authz_core_module /usr/lib64/httpd/modules/mod_authz_core.so
-LoadModule authz_host_module /usr/lib64/httpd/modules/mod_authz_host.so
-LoadModule status_module /usr/lib64/httpd/modules/mod_status.so
-LoadModule mime_module /usr/lib64/httpd/modules/mod_mime.so
-LoadModule deflate_module /usr/lib64/httpd/modules/mod_deflate.so
-LoadModule alias_module /usr/lib64/httpd/modules/mod_alias.so
-
-LoadModule repository_root_srv ${AP_MODULE_DIR}/libbrep-apache.so
-
-LoadModule package_search_srv ${AP_MODULE_DIR}/libbrep-apache.so
-
-<IfModule package_search_srv>
- package-search-root "${AP_ROOT}"
- package-search-db-host ${AP_DB_HOST}
- package-search-db-port ${AP_DB_PORT}
- package-search-conf ${AP_CONFIG_DIR}/package-search.conf
-</IfModule>
-
-LoadModule package_details_srv ${AP_MODULE_DIR}/libbrep-apache.so
-
-<IfModule package_details_srv>
- package-details-root "${AP_ROOT}"
- package-details-db-host ${AP_DB_HOST}
- package-details-db-port ${AP_DB_PORT}
- package-details-conf ${AP_CONFIG_DIR}/package-details.conf
-</IfModule>
-
-LoadModule package_version_details_srv ${AP_MODULE_DIR}/libbrep-apache.so
-
-<IfModule package_version_details_srv>
- package-version-details-root "${AP_ROOT}"
- package-version-details-db-host ${AP_DB_HOST}
- package-version-details-db-port ${AP_DB_PORT}
- package-version-details-conf ${AP_CONFIG_DIR}/package-version-details.conf
-</IfModule>
-
-LoadModule repository_details_srv ${AP_MODULE_DIR}/libbrep-apache.so
-
-<IfModule repository_details_srv>
- repository-details-root "${AP_ROOT}"
- repository-details-db-host ${AP_DB_HOST}
- repository-details-db-port ${AP_DB_PORT}
- repository-details-conf ${AP_CONFIG_DIR}/repository-details.conf
-</IfModule>
-
-<LocationMatch ^${AP_ROOT}/?$>
- SetHandler repository-root
-</LocationMatch>
-
-<LocationMatch ^${AP_ROOT}/[^/]+$>
- SetHandler package-details
-</LocationMatch>
-
-<LocationMatch ^${AP_ROOT}/[^/]+/[^/]+$>
- SetHandler package-version-details
-</LocationMatch>
-
-# Disable package-version-details and package-details handlers on static files
-# and repository content locations.
-# Location examples: /@, /@/common.css, /1, /1/math/stable.
-#
-<LocationMatch ^${AP_ROOT}/(@|\d+)(/.*)?$>
- SetHandler None
-</LocationMatch>
-
-# Static files locations.
-#
-AliasMatch ^${AP_ROOT}/@/(.+) ${AP_WWW_DIR}/$1
-
-# Repository files locations.
-#
-AliasMatch ^${AP_ROOT}/(\d+)/(.+) ${AP_REPOSITORY_DIR}/$1/$2
-
-ExtendedStatus On
-
-<Location /server-status>
- SetHandler server-status
- Require local
-</Location>
-
-TypesConfig /etc/mime.types
-AddOutputFilterByType DEFLATE application/xhtml+xml
-AddOutputFilterByType DEFLATE text/css
diff --git a/etc/loader b/etc/loader
deleted file mode 100755
index 1ae3b48..0000000
--- a/etc/loader
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/sh
-# file : etc/loader
-# copyright : Copyright (c) 2014-2015 Code Synthesis Ltd
-# license : MIT; see accompanying LICENSE file
-#
-# Designed to simplify running brep-loader utility.
-
-. `dirname $0`/config
-
-if test -n "$LD_LIB_DIRS"; then
- export LD_LIBRARY_PATH=$LD_LIB_DIRS:$LD_LIBRARY_PATH
-fi
-
-if test -n "$LD_EXE_DIRS"; then
- export PATH=$LD_EXE_DIRS:$PATH
-fi
-
-brep-loader --db-host "$LD_DB_HOST" --db-port $PG_PORT "$LD_REPOSITORIES"
diff --git a/etc/package-details.conf b/etc/package-details.conf
deleted file mode 100644
index 66a7c17..0000000
--- a/etc/package-details.conf
+++ /dev/null
@@ -1,15 +0,0 @@
-# file : etc/package-details.conf
-# copyright : Copyright (c) 2014-2015 Code Synthesis Ltd
-# license : MIT; see accompanying LICENSE file
-#
-# brep::module options
-#
-verb 1
-
-# brep::package_details options
-#
-# @@ Set to 10.
-results-on-page 2
-pages-in-pager 5
-# @@ Set to 500 (~ 80 chars x 6 lines).
-description-length 100
diff --git a/etc/package-search.conf b/etc/package-search.conf
deleted file mode 100644
index 4c1484f..0000000
--- a/etc/package-search.conf
+++ /dev/null
@@ -1,13 +0,0 @@
-# file : etc/package-search.conf
-# copyright : Copyright (c) 2014-2015 Code Synthesis Ltd
-# license : MIT; see accompanying LICENSE file
-#
-# brep::module options
-#
-verb 1
-
-# brep::package_search options
-#
-# @@ Set to 10.
-results-on-page 2
-pages-in-pager 5
diff --git a/etc/package-version-details.conf b/etc/package-version-details.conf
deleted file mode 100644
index 865e162..0000000
--- a/etc/package-version-details.conf
+++ /dev/null
@@ -1,14 +0,0 @@
-# file : etc/package-version-details.conf
-# copyright : Copyright (c) 2014-2015 Code Synthesis Ltd
-# license : MIT; see accompanying LICENSE file
-#
-# brep::module options
-#
-verb 1
-
-# brep::package_version_details options
-#
-# @@ Set to 500 (~ 80 chars x 6 lines).
-description-length 100
-# @@ Set to 5000 (~ 80 chars x 60 lines).
-changes-length 100
diff --git a/etc/repository-details.conf b/etc/repository-details.conf
deleted file mode 100644
index e173cfb..0000000
--- a/etc/repository-details.conf
+++ /dev/null
@@ -1,7 +0,0 @@
-# file : etc/repository-details.conf
-# copyright : Copyright (c) 2014-2015 Code Synthesis Ltd
-# license : MIT; see accompanying LICENSE file
-#
-# brep::module options
-#
-verb 1
diff --git a/loader/loader.cxx b/loader/loader.cxx
index 402194c..3083366 100644
--- a/loader/loader.cxx
+++ b/loader/loader.cxx
@@ -23,6 +23,7 @@
#include <brep/types>
#include <brep/utility>
+
#include <brep/package>
#include <brep/package-odb>
diff --git a/tests/loader/driver.cxx b/tests/loader/driver.cxx
index 94a0b86..7ca1e6e 100644
--- a/tests/loader/driver.cxx
+++ b/tests/loader/driver.cxx
@@ -16,6 +16,7 @@
#include <brep/types>
#include <brep/utility>
+
#include <brep/package>
#include <brep/package-odb>
diff --git a/web/apache/request b/web/apache/request
index 88b38a9..8861dac 100644
--- a/web/apache/request
+++ b/web/apache/request
@@ -43,6 +43,11 @@ namespace web
int
flush ();
+ // Return true if content have been sent to the client, false otherwise.
+ //
+ bool
+ get_write_state () const noexcept {return write_state_;}
+
// Get request path.
//
virtual const path_type&
@@ -98,9 +103,6 @@ namespace web
void
parse_parameters (const char* args);
- bool
- get_write_state () const noexcept {return write_state_;}
-
virtual void
set_write_state ()
{
diff --git a/web/apache/service b/web/apache/service
index 33d5a0a..7eef81a 100644
--- a/web/apache/service
+++ b/web/apache/service
@@ -8,9 +8,7 @@
#include <httpd.h>
#include <string>
-#include <vector>
#include <cassert>
-#include <utility> // move()
#include <web/module>
#include <web/apache/log>
@@ -23,14 +21,10 @@ 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,
- option_names opts = option_names ())
+ service (const std::string& name, M& exemplar)
: ::module
{
STANDARD20_MODULE_STUFF,
@@ -42,8 +36,7 @@ namespace web
&register_hooks<M>
},
name_ (name),
- exemplar_ (exemplar),
- option_names_ (std::move (opts))
+ exemplar_ (exemplar)
{
init_directives ();
@@ -74,17 +67,31 @@ namespace web
static void
register_hooks (apr_pool_t*) noexcept
{
- // The registered function is called right after apache worker
- // process is started. Called for every new process spawned.
+ // The config_finalizer() function is called at the end of Apache
+ // server configuration parsing.
+ //
+ ap_hook_post_config (&config_finalizer<M>, NULL, NULL, APR_HOOK_LAST);
+
+ // The worker_initializer() function is called right after Apache
+ // worker process is started. Called for every new process spawned.
//
ap_hook_child_init (&worker_initializer<M>, NULL, NULL, APR_HOOK_LAST);
- // The registered function is called for each client request.
+ // The request_handler () function is called for each client request.
//
ap_hook_handler (&request_handler<M>, NULL, NULL, APR_HOOK_LAST);
}
template <typename M>
+ static int
+ config_finalizer (apr_pool_t*, apr_pool_t*, apr_pool_t*, server_rec*)
+ noexcept
+ {
+ instance<M> ()->options_parsed_ = true;
+ return OK;
+ }
+
+ template <typename M>
static void
worker_initializer (apr_pool_t*, server_rec* server) noexcept
{
@@ -112,7 +119,10 @@ namespace web
init_worker (log& l) noexcept;
static const char*
- add_option (cmd_parms* parms, void* mconfig, const char* args) noexcept;
+ parse_option (cmd_parms* parms, void* mconfig, const char* args) noexcept;
+
+ const char*
+ add_option (const char* name, optional<std::string> value);
template <typename M>
int handle (request& r, log& l) noexcept;
@@ -120,8 +130,9 @@ namespace web
private:
std::string name_;
module& exemplar_;
- option_names option_names_;
+ option_descriptions option_descriptions_;
name_values options_;
+ bool options_parsed_ = false;
};
}
}
diff --git a/web/apache/service.cxx b/web/apache/service.cxx
index 3bd60f6..1741af3 100644
--- a/web/apache/service.cxx
+++ b/web/apache/service.cxx
@@ -10,12 +10,15 @@
#include <httpd.h>
#include <http_config.h>
-#include <memory> // unique_ptr
+#include <memory> // unique_ptr
#include <string>
#include <cassert>
-#include <cstring> // strlen()
+#include <utility> // move()
+#include <cstring> // strlen()
#include <exception>
+#include <web/module>
+
using namespace std;
namespace web
@@ -34,19 +37,19 @@ namespace web
// 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]);
-
+ const option_descriptions& od (exemplar_.options ());
+ unique_ptr<command_rec[]> directives (new command_rec[od.size () + 1]);
command_rec* d (directives.get ());
- for (auto& o: option_names_)
+ for (const auto& o: od)
{
- o = name_ + "-" + o;
+ auto i (option_descriptions_.emplace (name_ + "-" + o.first, o.second));
+ assert (i.second);
*d++ =
{
- o.c_str (),
- reinterpret_cast<cmd_func> (add_option),
+ i.first->first.c_str (),
+ reinterpret_cast<cmd_func> (parse_option),
this,
RSRC_CONF,
// Move away from TAKE1 to be able to handle empty string and
@@ -58,36 +61,51 @@ namespace web
}
*d = {nullptr, nullptr, nullptr, 0, RAW_ARGS, nullptr};
-
cmds = directives.release ();
}
const char* service::
- add_option (cmd_parms* parms, void*, const char* args) noexcept
+ parse_option (cmd_parms* parms, void*, const char* args) noexcept
{
+ // @@ Current implementation does not consider configuration context
+ // (server config, virtual host, directory) for directive parsing, nor
+ // for request handling.
+ //
service& srv (*reinterpret_cast<service*> (parms->cmd->cmd_data));
- string name (parms->cmd->name + srv.name_.length () + 1);
- optional<string> value;
- // 'args' is an optionally double-quoted string. Use double quotes to
- // distinguish empty string from no-value case.
+ if (srv.options_parsed_)
+ // Apache is inside the second pass of its messy initialization cycle
+ // (more details at http://wiki.apache.org/httpd/ModuleLife). Just
+ // ignore it.
+ //
+ return 0;
+
+ // 'args' is an optionally double-quoted string. It uses double quotes
+ // to distinguish empty string from no-value case.
//
assert (args != nullptr);
+
+ optional<string> value;
if (auto l = strlen (args))
value = l >= 2 && args[0] == '"' && args[l - 1] == '"'
? string (args + 1, l - 2)
: args;
- for (auto& v: srv.options_)
- {
- if (v.name == name)
- {
- v.value = value;
- return 0;
- }
- }
+ return srv.add_option (parms->cmd->name, move (value));
+ }
+
+ const char* service::
+ add_option (const char* name, optional<string> value)
+ {
+ auto i (option_descriptions_.find (name));
+ assert (i != option_descriptions_.end ());
+
+ // Check that option value presense is expected.
+ //
+ if (i->second != static_cast<bool> (value))
+ return value ? "unexpected value" : "value expected";
- srv.options_.emplace_back (name, value);
+ options_.emplace_back (name + name_.length () + 1, move (value));
return 0;
}
diff --git a/web/apache/service.txx b/web/apache/service.txx
index 179980c..25a7435 100644
--- a/web/apache/service.txx
+++ b/web/apache/service.txx
@@ -20,8 +20,15 @@ namespace web
try
{
M m (static_cast<const M&> (exemplar_));
- static_cast<module&> (m).handle (r, r, l);
- return r.flush ();
+
+ if (static_cast<module&> (m).handle (r, r, l))
+ return r.flush ();
+
+ if (!r.get_write_state ())
+ return DECLINED;
+
+ l.write (nullptr, 0, func_name.c_str (), APLOG_ERR,
+ "handling declined while unbuffered content has been written");
}
catch (const invalid_request& e)
{
diff --git a/web/module b/web/module
index 1774884..50cc6be 100644
--- a/web/module
+++ b/web/module
@@ -5,6 +5,7 @@
#ifndef WEB_MODULE
#define WEB_MODULE
+#include <map>
#include <string>
#include <vector>
#include <iosfwd>
@@ -18,6 +19,8 @@
namespace web
{
+ using butl::optional;
+
// HTTP status code.
//
// @@ Define some commonly used constants?
@@ -58,7 +61,10 @@ namespace web
sequence_error (std::string d): std::runtime_error (std::move (d)) {}
};
- using butl::optional;
+ // Map of module configuration option names to the boolean flag indicating
+ // whether the value is expected for the option.
+ //
+ using option_descriptions = std::map<std::string, bool>;
struct name_value
{
@@ -182,27 +188,36 @@ namespace web
class module
{
public:
- // During startup the web server calls this function on the
- // module exemplar passing a list of configuration name-value
- // pairs. The place these configuration pairs come from is
- // implementation-specific (normally a configuration file).
- // Any exception thrown by this function terminates the web
+ // Description of configuration options supported by this module. Note:
+ // should be callable during static initialization.
+ //
+ virtual option_descriptions
+ options () = 0;
+
+ // During startup the web server calls this function on the module
+ // exemplar passing a list of configuration options. The place these
+ // configuration options come from is implementation-specific (normally
+ // a configuration file). The web server guarantees that only options
+ // listed in the map returned by the options() function above can be
+ // present. Any exception thrown by this function terminates the web
// server.
//
virtual void
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
- // as an internal server error (500). Similar to invalid_request,
- // it will try to return the status and description (obtained by
- // calling what() on std::exception) to the client, if possible.
- // The description is assume to be encoded in UTF-8. The
- // implementation may provide a configuration option to omit
- // the description from the response, for security/privacy
- // reasons.
+ // Return false if decline to handle the request. If handling have been
+ // declined after any unbuffered content has been written, then the
+ // implementation shall terminate the response in a suitable but
+ // unspecified manner. Any exception other than invalid_request described
+ // above that leaves this function is treated by the web server
+ // implementation as an internal server error (500). Similar to
+ // invalid_request, it will try to return the status and description
+ // (obtained by calling what() on std::exception) to the client, if
+ // possible. The description is assume to be encoded in UTF-8. The
+ // implementation may provide a configuration option to omit the
+ // description from the response, for security/privacy reasons.
//
- virtual void
+ virtual bool
handle (request&, response&, log&) = 0;
};
}