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
|