-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
975 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
#pragma once | ||
|
||
#include <boost/asio/io_context.hpp> | ||
#include <boost/asio/ip/address.hpp> | ||
|
||
#include <boost/asio/ip/tcp.hpp> | ||
|
||
#include <filesystem> | ||
|
||
#include <kelcoro/job.hpp> | ||
#include <kelcoro/task.hpp> | ||
#include <kelcoro/thread_pool.hpp> | ||
#include <anyany/anyany.hpp> | ||
|
||
#include "boost/smart_ptr/intrusive_ptr.hpp" | ||
#include "tgbm/net/http_base.hpp" | ||
#include "tgbm/net/tcp_connection.hpp" | ||
#include "tgbm/tools/deadline.hpp" | ||
#include "tgbm/tools/memory.hpp" | ||
|
||
namespace tgbm { | ||
|
||
namespace asio = boost::asio; | ||
|
||
struct http_server { | ||
virtual dd::task<http_response> handle_request(http_request) = 0; | ||
virtual ~http_server() = default; | ||
}; | ||
|
||
struct http2_server_options { | ||
// required to set | ||
std::filesystem::path ssl_cert_path; | ||
std::filesystem::path private_key_path; | ||
uint32_t max_send_frame_size = 8 * 1024; // 8 KB | ||
uint32_t max_receive_frame_size = uint32_t(-1); | ||
uint32_t hpack_dyntab_size = 4096; | ||
uint32_t initial_stream_window_size = -1; | ||
uint32_t max_concurrent_stream_per_connection = -1; | ||
// TODO use | ||
duration_t idle_timeout; // when drop client if it not send anything | ||
// TODO ? somehow handle overloading, мб через таймауты на отправку?.. | ||
// хотя самое логичное это как то детектить перегрузку и обрывать новые стримы если перегруз | ||
// (settings и поставить макс конкурент стрим 0) | ||
}; | ||
|
||
struct http2_server; | ||
|
||
using http2_server_ptr = boost::intrusive_ptr<http2_server>; | ||
|
||
struct ssl_context; | ||
using ssl_context_ptr = boost::intrusive_ptr<ssl_context>; | ||
|
||
struct http2_server : http_server { | ||
private: | ||
asio::io_context io_ctx; | ||
http2_server_options options; | ||
tcp_connection_options tcp_options; | ||
ssl_context_ptr sslctx = nullptr; | ||
std::atomic<size_t> refcount = 0; | ||
std::atomic_bool _stop_requested = false; | ||
// accepts on all threads, but each connection works only on one worker | ||
// by value, because work endlessly on io_ctx | ||
dd::thread_pool tp; | ||
using work_guard_t = decltype(asio::make_work_guard(io_ctx)); | ||
std::shared_ptr<work_guard_t> work_guard = nullptr; | ||
friend struct client_session; | ||
std::atomic_size_t opened_sessions = 0; | ||
|
||
/* | ||
acceptы on all threads, then creates session | ||
which works on one thread | ||
*/ | ||
dd::job start_accept(asio::ip::tcp::endpoint); | ||
|
||
friend void intrusive_ptr_add_ref(http2_server* server) noexcept { | ||
server->refcount.fetch_add(1, std::memory_order_acq_rel); | ||
} | ||
friend void intrusive_ptr_release(http2_server* server) noexcept { | ||
if (server->refcount.fetch_sub(1, std::memory_order_acq_rel) == 1) | ||
delete server; | ||
} | ||
|
||
protected: | ||
// protected, must not be created on stack | ||
~http2_server() { | ||
stop(); | ||
} | ||
|
||
public: | ||
explicit http2_server(http2_server_options, tcp_connection_options = {}, | ||
size_t listen_thread_count = std::thread::hardware_concurrency()); | ||
|
||
http2_server(http2_server&&) = delete; | ||
void operator=(http2_server&&) = delete; | ||
|
||
const http2_server_options& get_options() const noexcept { | ||
return options; | ||
} | ||
// adds addr to listen addrs | ||
void listen(asio::ip::tcp::endpoint); | ||
void listen(asio::ip::address addr, asio::ip::port_type port = 443) { | ||
return listen({addr, port}); | ||
} | ||
|
||
[[nodiscard]] bool stop_requested() const noexcept { | ||
return _stop_requested.load(std::memory_order_acquire); | ||
} | ||
|
||
void run(); | ||
void stop(); | ||
}; | ||
|
||
} // namespace tgbm |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
#include "tgbm/net/http2/hpack.hpp" | ||
#include "tgbm/net/http_base.hpp" | ||
#include "tgbm/net/http2/protocol.hpp" | ||
|
||
namespace tgbm::http2 { | ||
|
||
void parse_http2_request_headers(hpack::decoder& d, std::span<const hpack::byte_t> bytes, http_request& req) { | ||
const auto* in = bytes.data(); | ||
const auto* e = in + bytes.size(); | ||
hpack::header_view header; | ||
|
||
// parse required pseudoheaders | ||
|
||
bool scheme_parsed = false; | ||
bool path_parsed = false; | ||
bool method_parsed = false; | ||
bool authority_parsed = false; | ||
while (in != e) { | ||
d.decode_header(in, e, header); | ||
if (!header) // skip dynamic size updates | ||
continue; | ||
if (header.name == ":path") { | ||
if (path_parsed) | ||
throw protocol_error{}; | ||
path_parsed = true; | ||
req.path = header.name.str(); | ||
} else if (header.name == ":method") { | ||
if (method_parsed) | ||
throw protocol_error{}; | ||
method_parsed = true; | ||
enum_from_string(header.value.str(), req.method); | ||
} else if (header.name == ":scheme") { | ||
if (scheme_parsed) | ||
throw protocol_error{}; | ||
scheme_parsed = true; | ||
enum_from_string(header.value.str(), req.scheme); | ||
} else if (header.name == ":authority") { | ||
if (authority_parsed) | ||
throw protocol_error{}; | ||
authority_parsed = true; | ||
req.authority = header.value.str(); | ||
} else { | ||
break; | ||
} | ||
} | ||
if (header) | ||
req.headers.push_back(http_header_t(std::string(header.name.str()), std::string(header.value.str()))); | ||
while (in != e) { | ||
d.decode_header(in, e, header); | ||
if (!header) | ||
continue; | ||
req.headers.push_back(http_header_t(std::string(header.name.str()), std::string(header.value.str()))); | ||
} | ||
} | ||
|
||
} // namespace tgbm::http2 |
Oops, something went wrong.