From 8f3d3956b1e837c726859eb8bbe19dad79c54a42 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Sat, 29 Apr 2017 23:55:46 +0300 Subject: Add hxx extension for headers and lib prefix for library dirs --- web/apache/log | 81 ------------ web/apache/log.hxx | 81 ++++++++++++ web/apache/request | 190 ---------------------------- web/apache/request.cxx | 4 +- web/apache/request.hxx | 190 ++++++++++++++++++++++++++++ web/apache/service | 330 ------------------------------------------------- web/apache/service.cxx | 6 +- web/apache/service.hxx | 330 +++++++++++++++++++++++++++++++++++++++++++++++++ web/apache/stream | 149 ---------------------- web/apache/stream.hxx | 149 ++++++++++++++++++++++ 10 files changed, 755 insertions(+), 755 deletions(-) delete mode 100644 web/apache/log create mode 100644 web/apache/log.hxx delete mode 100644 web/apache/request create mode 100644 web/apache/request.hxx delete mode 100644 web/apache/service create mode 100644 web/apache/service.hxx delete mode 100644 web/apache/stream create mode 100644 web/apache/stream.hxx (limited to 'web/apache') diff --git a/web/apache/log b/web/apache/log deleted file mode 100644 index dda9099..0000000 --- a/web/apache/log +++ /dev/null @@ -1,81 +0,0 @@ -// file : web/apache/log -*- C++ -*- -// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd -// license : MIT; see accompanying LICENSE file - -#ifndef WEB_APACHE_LOG -#define WEB_APACHE_LOG - -#include // request_rec, server_rec -#include -#include // module - -#include // uint64_t -#include // min() - -#include - -namespace web -{ - namespace apache - { - class log: public web::log - { - public: - - log (server_rec* s, const ::module* m) noexcept - : server_ (s), module_ (m) {} - - virtual void - write (const char* msg) {write (APLOG_ERR, msg);} - - // Apache-specific interface. - // - void - write (int level, const char* msg) const noexcept - { - write (nullptr, 0, nullptr, level, msg); - } - - void - write (const char* file, - std::uint64_t line, - const char* func, - int level, - const char* msg) const noexcept - { - if (file && *file) - file = nullptr; // Skip file/line placeholder from log line. - - level = std::min (level, APLOG_TRACE8); - - if (func) - ap_log_error (file, - line, - module_->module_index, - level, - 0, - server_, - "[%s]: %s", - func, - msg); - else - // Skip function name placeholder from log line. - // - ap_log_error (file, - line, - module_->module_index, - level, - 0, - server_, - ": %s", - msg); - } - - private: - server_rec* server_; - const ::module* module_; // Apache module. - }; - } -} - -#endif // WEB_APACHE_LOG diff --git a/web/apache/log.hxx b/web/apache/log.hxx new file mode 100644 index 0000000..4397875 --- /dev/null +++ b/web/apache/log.hxx @@ -0,0 +1,81 @@ +// file : web/apache/log.hxx -*- C++ -*- +// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#ifndef WEB_APACHE_LOG_HXX +#define WEB_APACHE_LOG_HXX + +#include // request_rec, server_rec +#include +#include // module + +#include // uint64_t +#include // min() + +#include + +namespace web +{ + namespace apache + { + class log: public web::log + { + public: + + log (server_rec* s, const ::module* m) noexcept + : server_ (s), module_ (m) {} + + virtual void + write (const char* msg) {write (APLOG_ERR, msg);} + + // Apache-specific interface. + // + void + write (int level, const char* msg) const noexcept + { + write (nullptr, 0, nullptr, level, msg); + } + + void + write (const char* file, + std::uint64_t line, + const char* func, + int level, + const char* msg) const noexcept + { + if (file && *file) + file = nullptr; // Skip file/line placeholder from log line. + + level = std::min (level, APLOG_TRACE8); + + if (func) + ap_log_error (file, + line, + module_->module_index, + level, + 0, + server_, + "[%s]: %s", + func, + msg); + else + // Skip function name placeholder from log line. + // + ap_log_error (file, + line, + module_->module_index, + level, + 0, + server_, + ": %s", + msg); + } + + private: + server_rec* server_; + const ::module* module_; // Apache module. + }; + } +} + +#endif // WEB_APACHE_LOG_HXX diff --git a/web/apache/request b/web/apache/request deleted file mode 100644 index a35c5dc..0000000 --- a/web/apache/request +++ /dev/null @@ -1,190 +0,0 @@ -// file : web/apache/request -*- C++ -*- -// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd -// license : MIT; see accompanying LICENSE file - -#ifndef WEB_APACHE_REQUEST -#define WEB_APACHE_REQUEST - -#include // request_rec, HTTP_*, OK, M_POST - -#include -#include // unique_ptr -#include -#include -#include -#include - -#include -#include - -namespace web -{ - namespace apache - { - // The state of the request processing, reflecting an interaction with - // Apache API (like reading/writing content function calls), with no - // buffering taken into account. Any state different from the initial - // suppose that some irrevocable interaction with Apache API have - // happened, so request processing should be either completed, or - // reported as failed. State values are ordered in a sense that the - // higher value reflects the more advanced stage of processing, so the - // request current state value may not decrease. - // - enum class request_state - { - // Denotes the initial stage of the request handling. At this stage - // the request line and headers are already parsed by Apache. - // - initial, - - // Reading the request content. - // - reading, - - // Adding the response headers (cookies in particular). - // - headers, - - // Writing the response content. - // - writing - }; - - // Extends istreambuf with read limit checking, caching, etc. (see the - // implementation for details). - // - class istreambuf_cache; - - class request: public web::request, - public web::response, - public stream_state - { - friend class service; - - // Can not be inline/default due to the member of - // unique_ptr type. Note that istreambuf_cache type is - // incomplete. - // - request (request_rec* rec) noexcept; - ~request (); - - request_state - state () const noexcept {return state_;} - - // Flush the buffered response content if present. The returned value - // should be passed to Apache API on request handler exit. - // - int - flush (); - - // Prepare for the request re-processing if possible (no unbuffered - // read/write operations have been done). Throw sequence_error - // otherwise. In particular, the preparation can include the response - // content buffer cleanup, the request content buffer rewind. - // - void - rewind (); - - // Get request path. - // - virtual const path_type& - path (); - - // Get request body data stream. - // - virtual std::istream& - content (size_t limit = 0, size_t buffer = 0); - - // Get request parameters. - // - virtual const name_values& - parameters (); - - // Get request cookies. - // - virtual const name_values& - cookies (); - - // Get response status code. - // - status_code - status () const noexcept {return rec_->status;} - - // Set response status code. - // - virtual void - status (status_code status); - - // Set response status code, content type and get body stream. - // - virtual std::ostream& - content (status_code status, - const std::string& type, - bool buffer = true); - - // Add response cookie. - // - virtual void - cookie (const char* name, - const char* value, - const std::chrono::seconds* max_age = nullptr, - const char* path = nullptr, - const char* domain = nullptr, - bool secure = false, - bool buffer = true); - - private: - // Get application/x-www-form-urlencoded form data. If request::content() - // was not called yet (and so limits are not specified) then set both of - // them to 64KB. Rewind the stream afterwards, so it's available for the - // application as well, unless no buffering were requested beforehand. - // - const std::string& - form_data (); - - void - parse_parameters (const char* args); - - // Advance the request processing state. Noop if new state is equal to - // the current one. Throw sequence_error if the new state is less then - // the current one. Can throw invalid_request if HTTP request is - // malformed. - // - void - state (request_state); - - // stream_state members implementation. - // - virtual void - set_read_state () {state (request_state::reading);} - - virtual void - set_write_state () {state (request_state::writing);} - - // Rewind the input stream (that must exist). Throw sequence_error if - // some unbuffered content have already been read. - // - void - rewind_istream (); - - private: - request_rec* rec_; - request_state state_ = request_state::initial; - - path_type path_; - std::unique_ptr parameters_; - std::unique_ptr cookies_; - std::unique_ptr form_data_; - - std::unique_ptr in_buf_; - std::unique_ptr in_; - - std::unique_ptr out_buf_; - std::unique_ptr out_; - }; - } -} - -#include - -#endif // WEB_APACHE_REQUEST diff --git a/web/apache/request.cxx b/web/apache/request.cxx index b4fb080..219f887 100644 --- a/web/apache/request.cxx +++ b/web/apache/request.cxx @@ -2,7 +2,7 @@ // copyright : Copyright (c) 2014-2017 Code Synthesis Ltd // license : MIT; see accompanying LICENSE file -#include +#include #include // apr_table_*, apr_array_header_t #include // apr_pstrdup() @@ -31,7 +31,7 @@ #include #include -#include +#include using namespace std; using namespace butl; diff --git a/web/apache/request.hxx b/web/apache/request.hxx new file mode 100644 index 0000000..0488fb2 --- /dev/null +++ b/web/apache/request.hxx @@ -0,0 +1,190 @@ +// file : web/apache/request.hxx -*- C++ -*- +// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#ifndef WEB_APACHE_REQUEST_HXX +#define WEB_APACHE_REQUEST_HXX + +#include // request_rec, HTTP_*, OK, M_POST + +#include +#include // unique_ptr +#include +#include +#include +#include + +#include +#include + +namespace web +{ + namespace apache + { + // The state of the request processing, reflecting an interaction with + // Apache API (like reading/writing content function calls), with no + // buffering taken into account. Any state different from the initial + // suppose that some irrevocable interaction with Apache API have + // happened, so request processing should be either completed, or + // reported as failed. State values are ordered in a sense that the + // higher value reflects the more advanced stage of processing, so the + // request current state value may not decrease. + // + enum class request_state + { + // Denotes the initial stage of the request handling. At this stage + // the request line and headers are already parsed by Apache. + // + initial, + + // Reading the request content. + // + reading, + + // Adding the response headers (cookies in particular). + // + headers, + + // Writing the response content. + // + writing + }; + + // Extends istreambuf with read limit checking, caching, etc. (see the + // implementation for details). + // + class istreambuf_cache; + + class request: public web::request, + public web::response, + public stream_state + { + friend class service; + + // Can not be inline/default due to the member of + // unique_ptr type. Note that istreambuf_cache type is + // incomplete. + // + request (request_rec* rec) noexcept; + ~request (); + + request_state + state () const noexcept {return state_;} + + // Flush the buffered response content if present. The returned value + // should be passed to Apache API on request handler exit. + // + int + flush (); + + // Prepare for the request re-processing if possible (no unbuffered + // read/write operations have been done). Throw sequence_error + // otherwise. In particular, the preparation can include the response + // content buffer cleanup, the request content buffer rewind. + // + void + rewind (); + + // Get request path. + // + virtual const path_type& + path (); + + // Get request body data stream. + // + virtual std::istream& + content (size_t limit = 0, size_t buffer = 0); + + // Get request parameters. + // + virtual const name_values& + parameters (); + + // Get request cookies. + // + virtual const name_values& + cookies (); + + // Get response status code. + // + status_code + status () const noexcept {return rec_->status;} + + // Set response status code. + // + virtual void + status (status_code status); + + // Set response status code, content type and get body stream. + // + virtual std::ostream& + content (status_code status, + const std::string& type, + bool buffer = true); + + // Add response cookie. + // + virtual void + cookie (const char* name, + const char* value, + const std::chrono::seconds* max_age = nullptr, + const char* path = nullptr, + const char* domain = nullptr, + bool secure = false, + bool buffer = true); + + private: + // Get application/x-www-form-urlencoded form data. If request::content() + // was not called yet (and so limits are not specified) then set both of + // them to 64KB. Rewind the stream afterwards, so it's available for the + // application as well, unless no buffering were requested beforehand. + // + const std::string& + form_data (); + + void + parse_parameters (const char* args); + + // Advance the request processing state. Noop if new state is equal to + // the current one. Throw sequence_error if the new state is less then + // the current one. Can throw invalid_request if HTTP request is + // malformed. + // + void + state (request_state); + + // stream_state members implementation. + // + virtual void + set_read_state () {state (request_state::reading);} + + virtual void + set_write_state () {state (request_state::writing);} + + // Rewind the input stream (that must exist). Throw sequence_error if + // some unbuffered content have already been read. + // + void + rewind_istream (); + + private: + request_rec* rec_; + request_state state_ = request_state::initial; + + path_type path_; + std::unique_ptr parameters_; + std::unique_ptr cookies_; + std::unique_ptr form_data_; + + std::unique_ptr in_buf_; + std::unique_ptr in_; + + std::unique_ptr out_buf_; + std::unique_ptr out_; + }; + } +} + +#include + +#endif // WEB_APACHE_REQUEST_HXX diff --git a/web/apache/service b/web/apache/service deleted file mode 100644 index 45cf39b..0000000 --- a/web/apache/service +++ /dev/null @@ -1,330 +0,0 @@ -// file : web/apache/service -*- C++ -*- -// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd -// license : MIT; see accompanying LICENSE file - -#ifndef WEB_APACHE_SERVICE -#define WEB_APACHE_SERVICE - -#include // apr_pool_t -#include // APR_HOOK_* - -#include // request_rec, server_rec, HTTP_*, DECLINED -#include // module, cmd_parms, ap_hook_*() - -#include -#include // unique_ptr -#include -#include - -#include -#include -#include - -namespace web -{ - namespace apache - { - // Apache has 3 configuration scopes: main server, virtual server, and - // directory (location). It provides configuration scope-aware modules - // with the ability to build a hierarchy of configuration contexts. Later, - // when processing a request, Apache passes the appropriate directory - // configuration context to the request handler. - // - // This Apache service implementation first makes a copy of the provided - // (in the constructor below) module exemplar for each directory context. - // It then initializes each of these "context exemplars" with the (merged) - // set of configuration options. Finally, when handling a request, it - // copies the corresponding "context exemplar" to create the "handling - // instance". Note that the "context exemplars" are created as a copy of - // the provided exemplar, which is never initialized. As a result, it is - // possible to detect if the module's copy constructor is used to create a - // "context exemplar" or a "handling instance". - // - class service: ::module - { - public: - // Note that the module exemplar is stored by-reference. - // - template - service (const std::string& name, M& exemplar) - : ::module - { - STANDARD20_MODULE_STUFF, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - ®ister_hooks - }, - name_ (name), - exemplar_ (exemplar) - { - init_directives (); - - // Set configuration context management hooks. - // - // The overall process of building the configuration hierarchy for a - // module is as follows: - // - // 1. Apache creates directory and server configuration contexts for - // scopes containing module-defined directives by calling the - // create_{server,dir}_context() callback functions. For directives - // at the server scope the special directory context is created as - // well. - // - // 2. Apache calls parse_option() function for each module-defined - // directive. The function parses the directives and places the - // resulting options into the corresponding configuration context. - // It also establishes the directory-server contexts relations. - // - // 3. Apache calls merge_server_context() function for each virtual - // server. The function complements virtual server context options - // with the ones from the main server. - // - // 4. Apache calls config_finalizer() which complements the directory - // contexts options with the ones from the enclosing servers. - // - // 5. Apache calls worker_initializer() which creates module exemplar - // for each directory configuration context that have - // 'SetHandler ' directive in effect for it. - // - // References: - // http://www.apachetutor.org/dev/config - // http://httpd.apache.org/docs/2.4/developer/modguide.html - // http://wiki.apache.org/httpd/ModuleLife - // - create_server_config = &create_server_context; - create_dir_config = &create_dir_context; - merge_server_config = &merge_server_context; - - // instance () is invented to delegate processing from apache - // request handler C function to the service non static member - // function. This appoach resticts number of service objects per - // specific module implementation class with just one instance. - // - service*& srv (instance ()); - assert (srv == nullptr); - srv = this; - } - - ~service () - { - delete [] cmds; - } - - private: - template - static service*& - instance () noexcept - { - static service* instance; - return instance; - } - - template - static void - register_hooks (apr_pool_t*) noexcept - { - // The config_finalizer() function is called at the end of Apache - // server configuration parsing. - // - ap_hook_post_config (&config_finalizer, 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, NULL, NULL, APR_HOOK_LAST); - - // The request_handler () function is called for each client request. - // - ap_hook_handler (&request_handler, NULL, NULL, APR_HOOK_LAST); - } - - template - static int - config_finalizer (apr_pool_t*, apr_pool_t*, apr_pool_t*, server_rec* s) - noexcept - { - instance ()->finalize_config (s); - return OK; - } - - template - static void - worker_initializer (apr_pool_t*, server_rec* s) noexcept - { - auto srv (instance ()); - log l (s, srv); - srv->template init_worker (l); - } - - template - static int - request_handler (request_rec* r) noexcept; - - private: - - // Reflects the allowability of the request handling in the specific - // configuration scope. - // - enum class request_handling - { - // Configuration scope has 'SetHandler ' directive - // specified. The module is allowed to handle a request in the scope. - // - allowed, - - // Configuration scope has 'SetHandler |None' - // directive specified. The module is disallowed to handle a request - // in the scope. - // - disallowed, - - // - // Note that if there are several SetHandler directives specified - // in the specific scope, then the latest one takes the precedence. - - // Configuration scope has no SetHandler directive specified. The - // request handling allowability is established by the enclosing - // scopes. - // - inherit - }; - - // Our representation of the Apache configuration context. - // - // The lifetime of this object is under the control of the Apache API, - // which treats it as a raw sequence of bytes. In order not to tinker - // with the C-style structures and APR memory pools, we will keep it a - // (C++11) POD type with just the members required to maintain the - // context hierarchy. - // - // We will then use the pointers to these context objects as keys in - // maps to (1) the corresponding application-level option lists during - // the configuration cycle and to (2) the corresponding module exemplar - // during the HTTP request handling phase. We will also use the same - // type for both directory and server configuration contexts. - // - struct context - { - // Outer (server) configuration context for the directory - // configuration context, NULL otherwise. - // - context* server = nullptr; - - // If module directives appear directly in the server configuration - // scope, Apache creates a special directory context for them. This - // context appears at the same hierarchy level as the user-defined - // directory contexts of the same server scope. - // - bool special; - - // Request handling allowability for the corresponding configuration - // scope. - // - request_handling handling = request_handling::inherit; - - // Create the server configuration context. - // - context (): special (false) {} - - // Create the directory configuration context. Due to the Apache API - // implementation details it is not possible to detect the enclosing - // server configuration context at the time of directory context - // creation. As a result, the server member is set by the module's - // parse_option() function. - // - context (bool s): special (s) {} - - // Ensure the object is only destroyed by Apache. - // - ~context () = delete; - }; - - static context* - context_cast (void* config) noexcept - {return static_cast (config);} - - private: - void - init_directives (); - - // Create the server configuration context. Called by the Apache API - // whenever a new object of that type is required. - // - static void* - create_server_context (apr_pool_t*, server_rec*) noexcept; - - // Create the server directory configuration context. Called by the - // Apache API whenever a new object of that type is required. - // - static void* - create_dir_context (apr_pool_t*, char* dir) noexcept; - - template - static void* - merge_server_context (apr_pool_t*, void* enclosing, void* enclosed) - noexcept - { - instance ()->complement ( - context_cast (enclosed), context_cast (enclosing)); - - return enclosed; - } - - static const char* - parse_option (cmd_parms* parms, void* conf, const char* args) noexcept; - - const char* - add_option (context*, const char* name, optional value); - - void - finalize_config (server_rec*); - - void - clear_config (); - - // Complement the enclosed context with options of the enclosing one. - // If the 'handling' member of the enclosed context is set to - // request_handling::inherit value, assign it a value from the enclosing - // context. - // - void - complement (context* enclosed, context* enclosing); - - template - void - init_worker (log&); - - template - int - handle (request&, const context*, log&) const; - - private: - std::string name_; - module& exemplar_; - option_descriptions option_descriptions_; - - // The context objects pointed to by the key can change during the - // configuration phase. - // - using options = std::map; - options options_; - - // The context objects pointed to by the key can not change during the - // request handling phase. - // - using exemplars = std::map>; - exemplars exemplars_; - - bool options_parsed_ = false; - bool version_logged_ = false; - }; - } -} - -#include - -#endif // WEB_APACHE_SERVICE diff --git a/web/apache/service.cxx b/web/apache/service.cxx index ca8e235..8c3fa82 100644 --- a/web/apache/service.cxx +++ b/web/apache/service.cxx @@ -2,7 +2,7 @@ // copyright : Copyright (c) 2014-2017 Code Synthesis Ltd // license : MIT; see accompanying LICENSE file -#include +#include #include // apr_palloc() @@ -18,8 +18,8 @@ #include -#include -#include +#include +#include using namespace std; diff --git a/web/apache/service.hxx b/web/apache/service.hxx new file mode 100644 index 0000000..44d064f --- /dev/null +++ b/web/apache/service.hxx @@ -0,0 +1,330 @@ +// file : web/apache/service.hxx -*- C++ -*- +// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#ifndef WEB_APACHE_SERVICE_HXX +#define WEB_APACHE_SERVICE_HXX + +#include // apr_pool_t +#include // APR_HOOK_* + +#include // request_rec, server_rec, HTTP_*, DECLINED +#include // module, cmd_parms, ap_hook_*() + +#include +#include // unique_ptr +#include +#include + +#include +#include +#include + +namespace web +{ + namespace apache + { + // Apache has 3 configuration scopes: main server, virtual server, and + // directory (location). It provides configuration scope-aware modules + // with the ability to build a hierarchy of configuration contexts. Later, + // when processing a request, Apache passes the appropriate directory + // configuration context to the request handler. + // + // This Apache service implementation first makes a copy of the provided + // (in the constructor below) module exemplar for each directory context. + // It then initializes each of these "context exemplars" with the (merged) + // set of configuration options. Finally, when handling a request, it + // copies the corresponding "context exemplar" to create the "handling + // instance". Note that the "context exemplars" are created as a copy of + // the provided exemplar, which is never initialized. As a result, it is + // possible to detect if the module's copy constructor is used to create a + // "context exemplar" or a "handling instance". + // + class service: ::module + { + public: + // Note that the module exemplar is stored by-reference. + // + template + service (const std::string& name, M& exemplar) + : ::module + { + STANDARD20_MODULE_STUFF, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + ®ister_hooks + }, + name_ (name), + exemplar_ (exemplar) + { + init_directives (); + + // Set configuration context management hooks. + // + // The overall process of building the configuration hierarchy for a + // module is as follows: + // + // 1. Apache creates directory and server configuration contexts for + // scopes containing module-defined directives by calling the + // create_{server,dir}_context() callback functions. For directives + // at the server scope the special directory context is created as + // well. + // + // 2. Apache calls parse_option() function for each module-defined + // directive. The function parses the directives and places the + // resulting options into the corresponding configuration context. + // It also establishes the directory-server contexts relations. + // + // 3. Apache calls merge_server_context() function for each virtual + // server. The function complements virtual server context options + // with the ones from the main server. + // + // 4. Apache calls config_finalizer() which complements the directory + // contexts options with the ones from the enclosing servers. + // + // 5. Apache calls worker_initializer() which creates module exemplar + // for each directory configuration context that have + // 'SetHandler ' directive in effect for it. + // + // References: + // http://www.apachetutor.org/dev/config + // http://httpd.apache.org/docs/2.4/developer/modguide.html + // http://wiki.apache.org/httpd/ModuleLife + // + create_server_config = &create_server_context; + create_dir_config = &create_dir_context; + merge_server_config = &merge_server_context; + + // instance () is invented to delegate processing from apache + // request handler C function to the service non static member + // function. This appoach resticts number of service objects per + // specific module implementation class with just one instance. + // + service*& srv (instance ()); + assert (srv == nullptr); + srv = this; + } + + ~service () + { + delete [] cmds; + } + + private: + template + static service*& + instance () noexcept + { + static service* instance; + return instance; + } + + template + static void + register_hooks (apr_pool_t*) noexcept + { + // The config_finalizer() function is called at the end of Apache + // server configuration parsing. + // + ap_hook_post_config (&config_finalizer, 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, NULL, NULL, APR_HOOK_LAST); + + // The request_handler () function is called for each client request. + // + ap_hook_handler (&request_handler, NULL, NULL, APR_HOOK_LAST); + } + + template + static int + config_finalizer (apr_pool_t*, apr_pool_t*, apr_pool_t*, server_rec* s) + noexcept + { + instance ()->finalize_config (s); + return OK; + } + + template + static void + worker_initializer (apr_pool_t*, server_rec* s) noexcept + { + auto srv (instance ()); + log l (s, srv); + srv->template init_worker (l); + } + + template + static int + request_handler (request_rec* r) noexcept; + + private: + + // Reflects the allowability of the request handling in the specific + // configuration scope. + // + enum class request_handling + { + // Configuration scope has 'SetHandler ' directive + // specified. The module is allowed to handle a request in the scope. + // + allowed, + + // Configuration scope has 'SetHandler |None' + // directive specified. The module is disallowed to handle a request + // in the scope. + // + disallowed, + + // + // Note that if there are several SetHandler directives specified + // in the specific scope, then the latest one takes the precedence. + + // Configuration scope has no SetHandler directive specified. The + // request handling allowability is established by the enclosing + // scopes. + // + inherit + }; + + // Our representation of the Apache configuration context. + // + // The lifetime of this object is under the control of the Apache API, + // which treats it as a raw sequence of bytes. In order not to tinker + // with the C-style structures and APR memory pools, we will keep it a + // (C++11) POD type with just the members required to maintain the + // context hierarchy. + // + // We will then use the pointers to these context objects as keys in + // maps to (1) the corresponding application-level option lists during + // the configuration cycle and to (2) the corresponding module exemplar + // during the HTTP request handling phase. We will also use the same + // type for both directory and server configuration contexts. + // + struct context + { + // Outer (server) configuration context for the directory + // configuration context, NULL otherwise. + // + context* server = nullptr; + + // If module directives appear directly in the server configuration + // scope, Apache creates a special directory context for them. This + // context appears at the same hierarchy level as the user-defined + // directory contexts of the same server scope. + // + bool special; + + // Request handling allowability for the corresponding configuration + // scope. + // + request_handling handling = request_handling::inherit; + + // Create the server configuration context. + // + context (): special (false) {} + + // Create the directory configuration context. Due to the Apache API + // implementation details it is not possible to detect the enclosing + // server configuration context at the time of directory context + // creation. As a result, the server member is set by the module's + // parse_option() function. + // + context (bool s): special (s) {} + + // Ensure the object is only destroyed by Apache. + // + ~context () = delete; + }; + + static context* + context_cast (void* config) noexcept + {return static_cast (config);} + + private: + void + init_directives (); + + // Create the server configuration context. Called by the Apache API + // whenever a new object of that type is required. + // + static void* + create_server_context (apr_pool_t*, server_rec*) noexcept; + + // Create the server directory configuration context. Called by the + // Apache API whenever a new object of that type is required. + // + static void* + create_dir_context (apr_pool_t*, char* dir) noexcept; + + template + static void* + merge_server_context (apr_pool_t*, void* enclosing, void* enclosed) + noexcept + { + instance ()->complement ( + context_cast (enclosed), context_cast (enclosing)); + + return enclosed; + } + + static const char* + parse_option (cmd_parms* parms, void* conf, const char* args) noexcept; + + const char* + add_option (context*, const char* name, optional value); + + void + finalize_config (server_rec*); + + void + clear_config (); + + // Complement the enclosed context with options of the enclosing one. + // If the 'handling' member of the enclosed context is set to + // request_handling::inherit value, assign it a value from the enclosing + // context. + // + void + complement (context* enclosed, context* enclosing); + + template + void + init_worker (log&); + + template + int + handle (request&, const context*, log&) const; + + private: + std::string name_; + module& exemplar_; + option_descriptions option_descriptions_; + + // The context objects pointed to by the key can change during the + // configuration phase. + // + using options = std::map; + options options_; + + // The context objects pointed to by the key can not change during the + // request handling phase. + // + using exemplars = std::map>; + exemplars exemplars_; + + bool options_parsed_ = false; + bool version_logged_ = false; + }; + } +} + +#include + +#endif // WEB_APACHE_SERVICE_HXX diff --git a/web/apache/stream b/web/apache/stream deleted file mode 100644 index d4abb4e..0000000 --- a/web/apache/stream +++ /dev/null @@ -1,149 +0,0 @@ -// file : web/apache/stream -*- C++ -*- -// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd -// license : MIT; see accompanying LICENSE file - -#ifndef WEB_APACHE_STREAM -#define WEB_APACHE_STREAM - -#include // request_rec, HTTP_* -#include // ap_*() - -#include // streamsize -#include -#include // memmove(), size_t -#include -#include // min(), max() - -#include // invalid_request - -namespace web -{ - namespace apache - { - // Object of a class implementing this interface is intended for keeping - // the state of communication with the client. - // - struct stream_state - { - // Called by istreambuf functions when content is about to be read from - // the client. Can throw invalid_request or sequence_error. - // - virtual void - set_read_state () = 0; - - // Called by ostreambuf functions when some content is about to be - // written to the client. Can throw invalid_request or sequence_error. - // - virtual void - set_write_state () = 0; - }; - - // Base class for ostreambuf and istreambuf. References request and - // communication state structures. - // - class rbuf: public std::streambuf - { - protected: - rbuf (request_rec* r, stream_state& s): rec_ (r), state_ (s) {} - - protected: - request_rec* rec_; - stream_state& state_; - }; - - class ostreambuf: public rbuf - { - public: - ostreambuf (request_rec* r, stream_state& s): rbuf (r, s) {} - - private: - virtual int_type - overflow (int_type c) - { - if (c != traits_type::eof ()) - { - state_.set_write_state (); - - char chr (c); - - // Throwing allows to distinguish comm failure from other IO error - // conditions. - // - if (ap_rwrite (&chr, sizeof (chr), rec_) == -1) - throw invalid_request (HTTP_REQUEST_TIME_OUT); - } - - return c; - } - - virtual std::streamsize - xsputn (const char* s, std::streamsize num) - { - state_.set_write_state (); - - if (ap_rwrite (s, num, rec_) < 0) - throw invalid_request (HTTP_REQUEST_TIME_OUT); - - return num; - } - - virtual int - sync () - { - if (ap_rflush (rec_) < 0) - throw invalid_request (HTTP_REQUEST_TIME_OUT); - - return 0; - } - }; - - class istreambuf: public rbuf - { - public: - istreambuf (request_rec* r, - stream_state& s, - size_t bufsize = 1024, - size_t putback = 1) - : rbuf (r, s), - bufsize_ (std::max (bufsize, (size_t)1)), - putback_ (std::min (putback, bufsize_ - 1)), - buf_ (bufsize_) - { - char* p (buf_.data () + putback_); - setg (p, p, p); - } - - protected: - virtual int_type - underflow () - { - if (gptr () < egptr ()) - return traits_type::to_int_type (*gptr ()); - - state_.set_read_state (); - - size_t pb (std::min ((size_t)(gptr () - eback ()), putback_)); - std::memmove (buf_.data () + putback_ - pb, gptr () - pb, pb); - - char* p (buf_.data () + putback_); - int rb (ap_get_client_block (rec_, p, bufsize_ - putback_)); - - if (rb == 0) - return traits_type::eof (); - - if (rb < 0) - throw invalid_request (HTTP_REQUEST_TIME_OUT); - - setg (p - pb, p, p + rb); - return traits_type::to_int_type (*gptr ()); - } - - protected: - size_t bufsize_; - size_t putback_; - std::vector buf_; - }; - } -} - -#endif // WEB_APACHE_STREAM diff --git a/web/apache/stream.hxx b/web/apache/stream.hxx new file mode 100644 index 0000000..3bb422d --- /dev/null +++ b/web/apache/stream.hxx @@ -0,0 +1,149 @@ +// file : web/apache/stream.hxx -*- C++ -*- +// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#ifndef WEB_APACHE_STREAM_HXX +#define WEB_APACHE_STREAM_HXX + +#include // request_rec, HTTP_* +#include // ap_*() + +#include // streamsize +#include +#include // memmove(), size_t +#include +#include // min(), max() + +#include // invalid_request + +namespace web +{ + namespace apache + { + // Object of a class implementing this interface is intended for keeping + // the state of communication with the client. + // + struct stream_state + { + // Called by istreambuf functions when content is about to be read from + // the client. Can throw invalid_request or sequence_error. + // + virtual void + set_read_state () = 0; + + // Called by ostreambuf functions when some content is about to be + // written to the client. Can throw invalid_request or sequence_error. + // + virtual void + set_write_state () = 0; + }; + + // Base class for ostreambuf and istreambuf. References request and + // communication state structures. + // + class rbuf: public std::streambuf + { + protected: + rbuf (request_rec* r, stream_state& s): rec_ (r), state_ (s) {} + + protected: + request_rec* rec_; + stream_state& state_; + }; + + class ostreambuf: public rbuf + { + public: + ostreambuf (request_rec* r, stream_state& s): rbuf (r, s) {} + + private: + virtual int_type + overflow (int_type c) + { + if (c != traits_type::eof ()) + { + state_.set_write_state (); + + char chr (c); + + // Throwing allows to distinguish comm failure from other IO error + // conditions. + // + if (ap_rwrite (&chr, sizeof (chr), rec_) == -1) + throw invalid_request (HTTP_REQUEST_TIME_OUT); + } + + return c; + } + + virtual std::streamsize + xsputn (const char* s, std::streamsize num) + { + state_.set_write_state (); + + if (ap_rwrite (s, num, rec_) < 0) + throw invalid_request (HTTP_REQUEST_TIME_OUT); + + return num; + } + + virtual int + sync () + { + if (ap_rflush (rec_) < 0) + throw invalid_request (HTTP_REQUEST_TIME_OUT); + + return 0; + } + }; + + class istreambuf: public rbuf + { + public: + istreambuf (request_rec* r, + stream_state& s, + size_t bufsize = 1024, + size_t putback = 1) + : rbuf (r, s), + bufsize_ (std::max (bufsize, (size_t)1)), + putback_ (std::min (putback, bufsize_ - 1)), + buf_ (bufsize_) + { + char* p (buf_.data () + putback_); + setg (p, p, p); + } + + protected: + virtual int_type + underflow () + { + if (gptr () < egptr ()) + return traits_type::to_int_type (*gptr ()); + + state_.set_read_state (); + + size_t pb (std::min ((size_t)(gptr () - eback ()), putback_)); + std::memmove (buf_.data () + putback_ - pb, gptr () - pb, pb); + + char* p (buf_.data () + putback_); + int rb (ap_get_client_block (rec_, p, bufsize_ - putback_)); + + if (rb == 0) + return traits_type::eof (); + + if (rb < 0) + throw invalid_request (HTTP_REQUEST_TIME_OUT); + + setg (p - pb, p, p + rb); + return traits_type::to_int_type (*gptr ()); + } + + protected: + size_t bufsize_; + size_t putback_; + std::vector buf_; + }; + } +} + +#endif // WEB_APACHE_STREAM_HXX -- cgit v1.1