LCOV - code coverage report
Current view: top level - http/server - http_server_base.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 100.0 % 9 9
Test Date: 2026-02-20 15:38:22 Functions: 90.0 % 10 9

            Line data    Source code
       1              : #ifndef THINGER_HTTP_SERVER_BASE_HPP
       2              : #define THINGER_HTTP_SERVER_BASE_HPP
       3              : 
       4              : #include "routing/route_handler.hpp"
       5              : #include "routing/route.hpp"
       6              : #include "http_stream.hpp"
       7              : #include "../../asio/socket_server.hpp"
       8              : #include "../../asio/socket_server_base.hpp"
       9              : #include "../../asio/unix_socket_server.hpp"
      10              : #include "../../util/types.hpp"
      11              : #include <memory>
      12              : #include <string>
      13              : #include <functional>
      14              : #include <chrono>
      15              : 
      16              : namespace thinger::http {
      17              : 
      18              : // Forward declarations
      19              : class request;
      20              : class response;
      21              : 
      22              : // Middleware function type
      23              : using middleware_function = std::function<void(request&, response&, std::function<void()>)>;
      24              : 
      25              : class http_server_base {
      26              : protected:
      27              :     route_handler router_;
      28              :     std::unique_ptr<asio::socket_server_base> socket_server_;
      29              :     std::vector<middleware_function> middlewares_;
      30              :     std::string host_ = "0.0.0.0";
      31              :     std::string port_ = "8080";
      32              :     std::string unix_path_;
      33              :     bool cors_enabled_{false};
      34              :     bool ssl_enabled_{false};
      35              :     bool use_unix_socket_{false};
      36              :     
      37              :     // Connection timeout setting
      38          725 :     std::chrono::seconds connection_timeout_{120};
      39              : 
      40              :     // Maximum allowed request body size
      41              :     size_t max_body_size_{8 * 1024 * 1024}; // 8MB default
      42              :     
      43              :     // Listening attempts (-1 = infinite)
      44              :     int max_listening_attempts_ = -1;
      45              :     
      46              : public:
      47         3625 :     http_server_base() = default;
      48          725 :     virtual ~http_server_base() = default;
      49              :     
      50              :     // Route registration methods - all return route& for chaining
      51              :     route& get(const std::string& path, route_callback_response_only handler);
      52              :     route& get(const std::string& path, route_callback_json_response handler);
      53              :     route& get(const std::string& path, route_callback_request_response handler);
      54              :     route& get(const std::string& path, route_callback_request_json_response handler);
      55              :     
      56              :     route& post(const std::string& path, route_callback_response_only handler);
      57              :     route& post(const std::string& path, route_callback_json_response handler);
      58              :     route& post(const std::string& path, route_callback_request_response handler);
      59              :     route& post(const std::string& path, route_callback_request_json_response handler);
      60              :     
      61              :     route& put(const std::string& path, route_callback_response_only handler);
      62              :     route& put(const std::string& path, route_callback_json_response handler);
      63              :     route& put(const std::string& path, route_callback_request_response handler);
      64              :     route& put(const std::string& path, route_callback_request_json_response handler);
      65              :     
      66              :     route& del(const std::string& path, route_callback_response_only handler);  // delete is keyword
      67              :     route& del(const std::string& path, route_callback_json_response handler);
      68              :     route& del(const std::string& path, route_callback_request_response handler);
      69              :     route& del(const std::string& path, route_callback_request_json_response handler);
      70              :     
      71              :     route& patch(const std::string& path, route_callback_response_only handler);
      72              :     route& patch(const std::string& path, route_callback_json_response handler);
      73              :     route& patch(const std::string& path, route_callback_request_response handler);
      74              :     route& patch(const std::string& path, route_callback_request_json_response handler);
      75              :     
      76              :     route& head(const std::string& path, route_callback_response_only handler);
      77              :     route& head(const std::string& path, route_callback_request_response handler);
      78              :     
      79              :     route& options(const std::string& path, route_callback_response_only handler);
      80              :     route& options(const std::string& path, route_callback_request_response handler);
      81              : 
      82              :     // Awaitable (deferred body) route registration — auto-enables deferred_body
      83              :     // Uses template + requires to avoid ambiguity with std::function<void(...)> overloads
      84              :     template<typename F>
      85              :         requires requires(F f, request& req, response& res) {
      86              :             { f(req, res) } -> std::same_as<thinger::awaitable<void>>;
      87              :         }
      88              :     route& get(const std::string& path, F&& handler) {
      89              :         return router_[method::GET][path] = route_callback_awaitable(std::forward<F>(handler));
      90              :     }
      91              : 
      92              :     template<typename F>
      93              :         requires requires(F f, request& req, response& res) {
      94              :             { f(req, res) } -> std::same_as<thinger::awaitable<void>>;
      95              :         }
      96            4 :     route& post(const std::string& path, F&& handler) {
      97            4 :         return router_[method::POST][path] = route_callback_awaitable(std::forward<F>(handler));
      98              :     }
      99              : 
     100              :     template<typename F>
     101              :         requires requires(F f, request& req, response& res) {
     102              :             { f(req, res) } -> std::same_as<thinger::awaitable<void>>;
     103              :         }
     104           10 :     route& put(const std::string& path, F&& handler) {
     105           10 :         return router_[method::PUT][path] = route_callback_awaitable(std::forward<F>(handler));
     106              :     }
     107              : 
     108              :     template<typename F>
     109              :         requires requires(F f, request& req, response& res) {
     110              :             { f(req, res) } -> std::same_as<thinger::awaitable<void>>;
     111              :         }
     112              :     route& del(const std::string& path, F&& handler) {
     113              :         return router_[method::DELETE][path] = route_callback_awaitable(std::forward<F>(handler));
     114              :     }
     115              : 
     116              :     template<typename F>
     117              :         requires requires(F f, request& req, response& res) {
     118              :             { f(req, res) } -> std::same_as<thinger::awaitable<void>>;
     119              :         }
     120              :     route& patch(const std::string& path, F&& handler) {
     121              :         return router_[method::PATCH][path] = route_callback_awaitable(std::forward<F>(handler));
     122              :     }
     123              : 
     124              :     // Middleware
     125              :     void use(middleware_function middleware);
     126              :     
     127              :     // Basic Auth helpers
     128              :     using auth_verify_function = std::function<bool(const std::string& username, const std::string& password)>;
     129              :     
     130              :     // Add basic auth for a specific path prefix
     131              :     void set_basic_auth(const std::string& path_prefix, 
     132              :                        const std::string& realm,
     133              :                        auth_verify_function verify);
     134              :     
     135              :     // Add basic auth with simple username/password
     136              :     void set_basic_auth(const std::string& path_prefix,
     137              :                        const std::string& realm,
     138              :                        const std::string& username,
     139              :                        const std::string& password);
     140              :     
     141              :     // Add basic auth with multiple users
     142              :     void set_basic_auth(const std::string& path_prefix,
     143              :                        const std::string& realm,
     144              :                        const std::map<std::string, std::string>& users);
     145              :     
     146              :     // Fallback handler
     147              :     void set_not_found_handler(route_callback_response_only handler);
     148              :     void set_not_found_handler(route_callback_request_response handler);
     149              :     
     150              :     // Configuration
     151              :     void enable_cors(bool enabled = true);
     152              :     void enable_ssl(bool enabled = true);
     153              :     void set_connection_timeout(std::chrono::seconds timeout);
     154              :     void set_max_body_size(size_t size);
     155              :     void set_max_listening_attempts(int attempts);
     156              :     
     157              :     // Static file serving
     158              :     void serve_static(const std::string& url_prefix, 
     159              :                      const std::string& directory,
     160              :                      bool fallback_to_index = true);
     161              :     
     162              :     // Server control
     163              :     virtual bool listen(const std::string& host, uint16_t port);
     164              :     virtual bool listen_unix(const std::string& unix_path);
     165              : 
     166              :     // Start methods with automatic wait()
     167              :     bool start(uint16_t port);
     168              :     bool start(uint16_t port, const std::function<void()> &on_listening);
     169              :     bool start(const std::string& host, uint16_t port);
     170              :     bool start(const std::string& host, uint16_t port, const std::function<void()> &on_listening);
     171              :     
     172              :     // Unix socket start methods
     173              :     bool start_unix(const std::string& unix_path);
     174              :     bool start_unix(const std::string& unix_path, const std::function<void()> &on_listening);
     175              : 
     176              :     virtual bool stop();
     177              :     
     178              :     // Check if server is listening
     179              :     bool is_listening() const;
     180              : 
     181              :     // Get the port assigned by the OS after listen()
     182              :     uint16_t local_port() const;
     183              :     
     184              :     // Access to router for advanced use cases
     185            2 :     route_handler& router() { return router_; }
     186            2 :     const route_handler& router() const { return router_; }
     187              :     
     188              :     // Abstract methods that derived classes must implement
     189              :     virtual void wait() = 0;
     190              :     
     191              : protected:
     192              :     // Virtual method for creating socket server - can be overridden by subclasses
     193              :     virtual std::unique_ptr<asio::socket_server> create_socket_server(
     194              :         const std::string& host, const std::string& port) = 0;
     195              :     
     196              :     // Virtual method for creating Unix socket server
     197              :     virtual std::unique_ptr<asio::unix_socket_server> create_unix_socket_server(
     198              :         const std::string& unix_path) = 0;
     199              :     
     200              : private:
     201              :     void setup_connection_handler();
     202              :     void execute_middlewares(request& req, std::shared_ptr<http_stream> stream, size_t index, std::function<void()> final_handler);
     203              : };
     204              : 
     205              : } // namespace thinger::http
     206              : 
     207              : #endif // THINGER_HTTP_SERVER_BASE_HPP
        

Generated by: LCOV version 2.0-1