Network System 0.1.1
High-performance modular networking library for scalable client-server applications
Loading...
Searching...
No Matches
http2_server.h
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2024, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
5#pragma once
6
7#include "frame.h"
8#include "hpack.h"
9#include "http2_client.h"
10#include "http2_request.h"
11#include "http2_server_stream.h"
13
14#include <asio.hpp>
15#include <asio/ssl.hpp>
16
17#include <atomic>
18#include <chrono>
19#include <cstdint>
20#include <functional>
21#include <future>
22#include <map>
23#include <memory>
24#include <mutex>
25#include <optional>
26#include <string>
27#include <string_view>
28#include <vector>
29
30#if defined(NETWORK_ENABLE_TEST_INJECTION)
31namespace kcenon::network::tests::support
32{
33 class http2_server_test_access;
34} // namespace kcenon::network::tests::support
35#endif
36
38{
39 // Forward declaration
40 class http2_server_connection;
41
47 {
48 std::string cert_file;
49 std::string key_file;
50 std::string ca_file;
51 bool verify_client = false;
52 };
53
99 class http2_server : public std::enable_shared_from_this<http2_server>
100 {
101 public:
103 using request_handler_t = std::function<void(
104 http2_server_stream& stream,
105 const http2_request& request)>;
106
108 using error_handler_t = std::function<void(
109 const std::string& error_message)>;
110
115 explicit http2_server(std::string_view server_id);
116
121
122 // Non-copyable
123 http2_server(const http2_server&) = delete;
125
126 // Non-movable (contains std::atomic members)
129
137 auto start(unsigned short port) -> VoidResult;
138
147 auto start_tls(unsigned short port, const tls_config& config) -> VoidResult;
148
155 auto stop() -> VoidResult;
156
161 [[nodiscard]] auto is_running() const -> bool;
162
168 auto wait() -> void;
169
177 auto set_request_handler(request_handler_t handler) -> void;
178
183 auto set_error_handler(error_handler_t handler) -> void;
184
189 auto set_settings(const http2_settings& settings) -> void;
190
195 [[nodiscard]] auto get_settings() const -> http2_settings;
196
201 [[nodiscard]] auto active_connections() const -> size_t;
202
207 [[nodiscard]] auto active_streams() const -> size_t;
208
213 [[nodiscard]] auto server_id() const -> std::string_view;
214
215 private:
216 // Internal connection handling
217 auto do_accept() -> void;
218 auto do_accept_tls() -> void;
219 auto handle_accept(std::error_code ec, asio::ip::tcp::socket socket) -> void;
220 auto handle_accept_tls(std::error_code ec, asio::ip::tcp::socket socket) -> void;
221
222 // Connection management
223 auto add_connection(std::shared_ptr<http2_server_connection> conn) -> void;
224 auto remove_connection(uint64_t connection_id) -> void;
225 auto cleanup_dead_connections() -> void;
226 auto start_cleanup_timer() -> void;
227
228 // I/O thread management
229 auto run_io() -> void;
230 auto stop_io() -> void;
231
232 // Member variables
233 std::string server_id_;
234
235 // ASIO context
236 std::unique_ptr<asio::io_context> io_context_;
237 std::unique_ptr<asio::ssl::context> ssl_context_;
238 std::unique_ptr<asio::ip::tcp::acceptor> acceptor_;
239 std::unique_ptr<asio::executor_work_guard<asio::io_context::executor_type>> work_guard_;
240 std::future<void> io_future_;
241
242 // Server state
243 std::atomic<bool> is_running_{false};
244 std::atomic<bool> use_tls_{false};
245 std::promise<void> stop_promise_;
246 std::future<void> stop_future_;
247
248 // Handlers
251
252 // Connection management
254 std::map<uint64_t, std::shared_ptr<http2_server_connection>> connections_;
255 std::atomic<uint64_t> next_connection_id_{1};
256
257 // Settings
258 mutable std::mutex settings_mutex_;
260
261 // HPACK encoder for all connections
262 std::shared_ptr<hpack_encoder> encoder_;
263 std::shared_ptr<hpack_decoder> decoder_;
264
265 // Cleanup timer
266 std::unique_ptr<asio::steady_timer> cleanup_timer_;
267
268 // Constants
269 static constexpr std::string_view CONNECTION_PREFACE =
270 "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
271 static constexpr size_t FRAME_HEADER_SIZE = 9;
272 };
273
281 class http2_server_connection : public std::enable_shared_from_this<http2_server_connection>
282 {
283 public:
293 asio::ip::tcp::socket socket,
295 http2_server::request_handler_t request_handler,
296 http2_server::error_handler_t error_handler);
297
307 std::unique_ptr<asio::ssl::stream<asio::ip::tcp::socket>> socket,
309 http2_server::request_handler_t request_handler,
310 http2_server::error_handler_t error_handler);
311
316
317 // Non-copyable, non-movable
322
327 auto start() -> VoidResult;
328
333 auto stop() -> VoidResult;
334
339 [[nodiscard]] auto is_alive() const -> bool;
340
345 [[nodiscard]] auto connection_id() const -> uint64_t;
346
351 [[nodiscard]] auto stream_count() const -> size_t;
352
353 private:
354 friend class http2_server;
355 auto shutdown_transport() -> void;
356
357 // Connection setup
358 auto read_connection_preface() -> void;
359 auto send_settings() -> VoidResult;
362
363 // Frame I/O
364 auto start_reading() -> void;
365 auto read_frame_header() -> void;
366 auto read_frame_payload(uint32_t length) -> void;
367 auto send_frame(const frame& f) -> VoidResult;
368 auto process_frame(std::unique_ptr<frame> f) -> VoidResult;
369
370 // Stream management
371 auto get_or_create_stream(uint32_t stream_id) -> http2_stream*;
372 auto close_stream(uint32_t stream_id) -> void;
373
374 // Frame handlers
376 auto handle_data_frame(const data_frame& f) -> VoidResult;
378 auto handle_ping_frame(const ping_frame& f) -> VoidResult;
381
382 // Request completion
383 auto dispatch_request(uint32_t stream_id) -> void;
384
385 uint64_t connection_id_;
386 bool use_tls_;
387
388 // Socket (one of these is used)
389 std::unique_ptr<asio::ip::tcp::socket> plain_socket_;
390 std::unique_ptr<asio::ssl::stream<asio::ip::tcp::socket>> tls_socket_;
392
393 // Connection state
394 std::atomic<bool> is_alive_{true};
395 std::atomic<bool> preface_received_{false};
396 std::atomic<bool> goaway_sent_{false};
397
398 // Stream management
399 std::mutex streams_mutex_;
400 std::map<uint32_t, http2_stream> streams_;
401 uint32_t last_stream_id_{0};
402
403 // Settings
406
407 // HPACK
410
411 // Flow control
413
414 // Handlers
417
418 // Read buffer
419 std::vector<uint8_t> read_buffer_;
420 std::array<uint8_t, 9> frame_header_buffer_;
421
422#if defined(NETWORK_ENABLE_TEST_INJECTION)
423 // Test-only: grants tests/support/http2_server_test_access access to
424 // the private process_frame() dispatcher and selected member fields
425 // without leaking them through the public API. Used by
426 // tests/unit/http2_server_dispatcher_branch_test.cpp to bypass the
427 // SETTINGS handshake gate so per-frame branches can be measured under
428 // coverage instrumentation (Issue #1121).
429 friend class kcenon::network::tests::support::http2_server_test_access;
430#endif
431 };
432
433} // namespace kcenon::network::protocols::http2
DATA frame (RFC 7540 Section 6.1)
Definition frame.h:139
Base class for HTTP/2 frames.
Definition frame.h:82
GOAWAY frame (RFC 7540 Section 6.8)
Definition frame.h:387
HEADERS frame (RFC 7540 Section 6.2)
Definition frame.h:189
HPACK header decoder (RFC 7541)
Definition hpack.h:209
HPACK header encoder (RFC 7541)
Definition hpack.h:159
Represents a single HTTP/2 connection on the server side.
http2_server_connection(uint64_t connection_id, asio::ip::tcp::socket socket, const http2_settings &settings, http2_server::request_handler_t request_handler, http2_server::error_handler_t error_handler)
Construct server connection with plain socket.
auto handle_data_frame(const data_frame &f) -> VoidResult
auto get_or_create_stream(uint32_t stream_id) -> http2_stream *
std::unique_ptr< asio::ip::tcp::socket > plain_socket_
auto start() -> VoidResult
Start connection handling.
auto stream_count() const -> size_t
Get number of active streams.
auto handle_goaway_frame(const goaway_frame &f) -> VoidResult
std::mutex transport_shutdown_mutex_
Serialize close and shutdown.
auto connection_id() const -> uint64_t
Get connection identifier.
auto handle_window_update_frame(const window_update_frame &f) -> VoidResult
auto process_frame(std::unique_ptr< frame > f) -> VoidResult
http2_server_connection(http2_server_connection &&)=delete
auto handle_settings_frame(const settings_frame &frame) -> VoidResult
auto handle_rst_stream_frame(const rst_stream_frame &f) -> VoidResult
std::unique_ptr< asio::ssl::stream< asio::ip::tcp::socket > > tls_socket_
http2_server_connection & operator=(http2_server_connection &&)=delete
auto handle_headers_frame(const headers_frame &f) -> VoidResult
auto is_alive() const -> bool
Check if connection is alive.
http2_server_connection & operator=(const http2_server_connection &)=delete
http2_server_connection(const http2_server_connection &)=delete
auto handle_ping_frame(const ping_frame &f) -> VoidResult
Server-side HTTP/2 stream for sending responses.
auto active_streams() const -> size_t
Get total number of active streams across all connections.
auto remove_connection(uint64_t connection_id) -> void
http2_server(std::string_view server_id)
Construct HTTP/2 server.
auto set_error_handler(error_handler_t handler) -> void
Set error handler.
http2_server & operator=(http2_server &&)=delete
std::unique_ptr< asio::io_context > io_context_
http2_server(const http2_server &)=delete
std::function< void( const std::string &error_message)> error_handler_t
Error handler function type.
auto server_id() const -> std::string_view
Get server identifier.
std::shared_ptr< hpack_encoder > encoder_
auto set_settings(const http2_settings &settings) -> void
Set server settings.
auto handle_accept(std::error_code ec, asio::ip::tcp::socket socket) -> void
std::shared_ptr< hpack_decoder > decoder_
auto get_settings() const -> http2_settings
Get current settings.
~http2_server()
Destructor - stops server gracefully.
auto stop() -> VoidResult
Stop the server.
http2_server & operator=(const http2_server &)=delete
auto active_connections() const -> size_t
Get number of active connections.
auto is_running() const -> bool
Check if server is running.
auto add_connection(std::shared_ptr< http2_server_connection > conn) -> void
static constexpr std::string_view CONNECTION_PREFACE
auto handle_accept_tls(std::error_code ec, asio::ip::tcp::socket socket) -> void
std::map< uint64_t, std::shared_ptr< http2_server_connection > > connections_
auto set_request_handler(request_handler_t handler) -> void
Set request handler.
auto start(unsigned short port) -> VoidResult
Start HTTP/2 server without TLS (h2c - HTTP/2 cleartext)
auto start_tls(unsigned short port, const tls_config &config) -> VoidResult
Start HTTP/2 server with TLS.
std::function< void( http2_server_stream &stream, const http2_request &request)> request_handler_t
Request handler function type.
std::unique_ptr< asio::steady_timer > cleanup_timer_
auto wait() -> void
Wait for server to stop.
std::unique_ptr< asio::ssl::context > ssl_context_
std::unique_ptr< asio::executor_work_guard< asio::io_context::executor_type > > work_guard_
std::unique_ptr< asio::ip::tcp::acceptor > acceptor_
PING frame (RFC 7540 Section 6.7)
Definition frame.h:344
RST_STREAM frame (RFC 7540 Section 6.4)
Definition frame.h:307
SETTINGS frame (RFC 7540 Section 6.5)
Definition frame.h:265
WINDOW_UPDATE frame (RFC 7540 Section 6.9)
Definition frame.h:438
error_code
HTTP/2 error codes (RFC 7540 Section 7)
Definition frame.h:471
Result< std::monostate > VoidResult
std::mutex mutex
Network-specific error and result type definitions.
TLS configuration for HTTP/2 server.
bool verify_client
Require client certificate.
std::string ca_file
Path to CA certificate file (optional)
std::string cert_file
Path to certificate file (PEM)
std::string key_file
Path to private key file (PEM)