Network System 0.1.1
High-performance modular networking library for scalable client-server applications
Loading...
Searching...
No Matches
kcenon::network::protocols::http2::http2_client Class Reference

HTTP/2 client with TLS support. More...

#include <http2_client.h>

Inheritance diagram for kcenon::network::protocols::http2::http2_client:
Inheritance graph
Collaboration diagram for kcenon::network::protocols::http2::http2_client:
Collaboration graph

Public Member Functions

 http2_client (std::string_view client_id)
 Construct HTTP/2 client.
 
 ~http2_client ()
 Destructor - closes connection gracefully.
 
 http2_client (const http2_client &)=delete
 
http2_clientoperator= (const http2_client &)=delete
 
 http2_client (http2_client &&)=delete
 
http2_clientoperator= (http2_client &&)=delete
 
auto connect (const std::string &host, unsigned short port=443) -> VoidResult
 Connect to HTTP/2 server.
 
auto disconnect () -> VoidResult
 Disconnect from server.
 
auto is_connected () const -> bool
 Check if connected.
 
auto get (const std::string &path, const std::vector< http_header > &headers={}) -> Result< http2_response >
 Perform HTTP/2 GET request.
 
auto post (const std::string &path, const std::string &body, const std::vector< http_header > &headers={}) -> Result< http2_response >
 Perform HTTP/2 POST request.
 
auto post (const std::string &path, const std::vector< uint8_t > &body, const std::vector< http_header > &headers={}) -> Result< http2_response >
 Perform HTTP/2 POST request with binary body.
 
auto put (const std::string &path, const std::string &body, const std::vector< http_header > &headers={}) -> Result< http2_response >
 Perform HTTP/2 PUT request.
 
auto del (const std::string &path, const std::vector< http_header > &headers={}) -> Result< http2_response >
 Perform HTTP/2 DELETE request.
 
auto set_timeout (std::chrono::milliseconds timeout) -> void
 Set request timeout.
 
auto get_timeout () const -> std::chrono::milliseconds
 Get current timeout.
 
auto start_stream (const std::string &path, const std::vector< http_header > &headers, std::function< void(std::vector< uint8_t >)> on_data, std::function< void(std::vector< http_header >)> on_headers, std::function< void(int)> on_complete) -> Result< uint32_t >
 Start a streaming POST request.
 
auto write_stream (uint32_t stream_id, const std::vector< uint8_t > &data, bool end_stream=false) -> VoidResult
 Write data to an open stream.
 
auto close_stream_writer (uint32_t stream_id) -> VoidResult
 Close the write side of a stream.
 
auto cancel_stream (uint32_t stream_id) -> VoidResult
 Cancel a stream.
 
auto get_settings () const -> http2_settings
 Get local settings.
 
auto set_settings (const http2_settings &settings) -> void
 Update local settings.
 

Private Member Functions

auto send_connection_preface () -> VoidResult
 
auto send_settings () -> VoidResult
 
auto handle_settings_frame (const settings_frame &frame) -> VoidResult
 
auto send_settings_ack () -> VoidResult
 
auto send_frame (const frame &f) -> VoidResult
 
auto read_frame () -> Result< std::unique_ptr< frame > >
 
auto process_frame (std::unique_ptr< frame > f) -> VoidResult
 
auto allocate_stream_id () -> uint32_t
 
auto get_stream (uint32_t stream_id) -> http2_stream *
 
auto create_stream () -> http2_stream &
 
auto close_stream (uint32_t stream_id) -> void
 
auto send_request (const std::string &method, const std::string &path, const std::vector< http_header > &headers, const std::vector< uint8_t > &body) -> Result< http2_response >
 
auto build_headers (const std::string &method, const std::string &path, const std::vector< http_header > &additional) -> std::vector< http_header >
 
auto handle_headers_frame (const headers_frame &f) -> VoidResult
 
auto handle_data_frame (const data_frame &f) -> VoidResult
 
auto handle_rst_stream_frame (const rst_stream_frame &f) -> VoidResult
 
auto handle_goaway_frame (const goaway_frame &f) -> VoidResult
 
auto handle_window_update_frame (const window_update_frame &f) -> VoidResult
 
auto handle_ping_frame (const ping_frame &f) -> VoidResult
 
auto run_io () -> void
 
auto stop_io () -> void
 

Private Attributes

std::string client_id_
 Client identifier.
 
std::string host_
 Connected host.
 
unsigned short port_ = 443
 Connected port.
 
std::unique_ptr< asio::io_context > io_context_
 
std::unique_ptr< asio::ssl::context > ssl_context_
 
std::unique_ptr< asio::ssl::stream< asio::ip::tcp::socket > > socket_
 
std::unique_ptr< asio::executor_work_guard< asio::io_context::executor_type > > work_guard_
 
std::future< void > io_future_
 
std::atomic< bool > is_connected_ {false}
 
std::atomic< bool > is_running_ {false}
 
std::atomic< bool > goaway_received_ {false}
 
std::mutex streams_mutex_
 
std::map< uint32_t, http2_streamstreams_
 
std::atomic< uint32_t > next_stream_id_ {1}
 Client streams are odd.
 
int32_t connection_window_size_ = 65535
 
http2_settings local_settings_
 
http2_settings remote_settings_
 
hpack_encoder encoder_
 
hpack_decoder decoder_
 
std::chrono::milliseconds timeout_ {30000}
 
std::vector< uint8_t > read_buffer_
 

Static Private Attributes

static constexpr std::string_view CONNECTION_PREFACE
 
static constexpr size_t FRAME_HEADER_SIZE = 9
 
static constexpr size_t DEFAULT_WINDOW_SIZE = 65535
 

Detailed Description

HTTP/2 client with TLS support.

Thread Safety

  • All public methods are thread-safe
  • Multiple requests can be made concurrently (multiplexing)
  • Uses single TLS connection for all requests

Features

  • HTTP/2 protocol support (RFC 7540)
  • HPACK header compression (RFC 7541)
  • TLS 1.3 with ALPN negotiation
  • Stream multiplexing
  • Flow control
  • Server push disabled by default

Usage Example

auto client = std::make_shared<http2_client>("my-client");
// Connect to server
auto connect_result = client->connect("example.com", 443);
if (!connect_result) {
std::cerr << "Connect failed: " << connect_result.error().message << "\n";
return;
}
// Simple GET request
auto response = client->get("/api/users");
if (response) {
std::cout << "Status: " << response->status_code << "\n";
std::cout << "Body: " << response->get_body_string() << "\n";
}
// POST with JSON body
std::vector<http_header> headers = {
{"content-type", "application/json"}
};
std::string json_body = R"({"name": "John"})";
auto post_response = client->post("/api/users", json_body, headers);
// Disconnect
client->disconnect();

Definition at line 154 of file http2_client.h.

Constructor & Destructor Documentation

◆ http2_client() [1/3]

kcenon::network::protocols::http2::http2_client::http2_client ( std::string_view client_id)
explicit

Construct HTTP/2 client.

Parameters
client_idUnique client identifier for logging

Definition at line 44 of file http2_client.cpp.

◆ ~http2_client()

kcenon::network::protocols::http2::http2_client::~http2_client ( )

Destructor - closes connection gracefully.

Definition at line 51 of file http2_client.cpp.

52 {
53 try
54 {
55 if (is_connected_)
56 {
57 disconnect();
58 }
59 }
60 catch (...)
61 {
62 // Suppress exceptions in destructor
63 }
64 }
auto disconnect() -> VoidResult
Disconnect from server.

References disconnect(), and is_connected_.

Here is the call graph for this function:

◆ http2_client() [2/3]

kcenon::network::protocols::http2::http2_client::http2_client ( const http2_client & )
delete

◆ http2_client() [3/3]

kcenon::network::protocols::http2::http2_client::http2_client ( http2_client && )
delete

Member Function Documentation

◆ allocate_stream_id()

auto kcenon::network::protocols::http2::http2_client::allocate_stream_id ( ) -> uint32_t
private

Definition at line 685 of file http2_client.cpp.

686 {
687 uint32_t id = next_stream_id_.fetch_add(2);
688 return id;
689 }
std::atomic< uint32_t > next_stream_id_
Client streams are odd.

◆ build_headers()

auto kcenon::network::protocols::http2::http2_client::build_headers ( const std::string & method,
const std::string & path,
const std::vector< http_header > & additional ) -> std::vector<http_header>
private

Definition at line 846 of file http2_client.cpp.

850 {
851 std::vector<http_header> headers;
852
853 // Pseudo-headers (must come first)
854 headers.emplace_back(":method", method);
855 headers.emplace_back(":scheme", "https");
856 headers.emplace_back(":authority", host_);
857 headers.emplace_back(":path", path.empty() ? "/" : path);
858
859 // Standard headers
860 headers.emplace_back("user-agent", "network_system/http2_client");
861
862 // Additional headers
863 for (const auto& h : additional)
864 {
865 // Skip pseudo-headers in additional
866 if (!h.name.empty() && h.name[0] != ':')
867 {
868 headers.push_back(h);
869 }
870 }
871
872 return headers;
873 }

References kcenon::network::protocols::http2::headers.

◆ cancel_stream()

auto kcenon::network::protocols::http2::http2_client::cancel_stream ( uint32_t stream_id) -> VoidResult

Cancel a stream.

Parameters
stream_idStream identifier
Returns
Success or error

Definition at line 430 of file http2_client.cpp.

431 {
432 if (!is_connected())
433 {
435 "Not connected",
436 "http2_client::cancel_stream");
437 }
438
439 auto* stream = get_stream(stream_id);
440 if (!stream)
441 {
443 "Stream not found",
444 "http2_client::cancel_stream");
445 }
446
447 if (stream->state == stream_state::closed)
448 {
449 return ok(); // Already closed
450 }
451
452 // Send RST_STREAM frame
453 rst_stream_frame rsf(stream_id, static_cast<uint32_t>(error_code::cancel));
454 auto send_result = send_frame(rsf);
455 if (send_result.is_err())
456 {
457 return send_result;
458 }
459
460 stream->state = stream_state::closed;
461 return ok();
462 }
auto is_connected() const -> bool
Check if connected.
auto send_frame(const frame &f) -> VoidResult
auto get_stream(uint32_t stream_id) -> http2_stream *
VoidResult error_void(int code, const std::string &message, const std::string &source="network_system", const std::string &details="")
VoidResult ok()

References kcenon::network::protocols::http2::cancel, kcenon::network::protocols::http2::closed, kcenon::network::error_codes::network_system::connection_closed, kcenon::network::error_void(), kcenon::network::error_codes::common_errors::not_found, and kcenon::network::ok().

Here is the call graph for this function:

◆ close_stream()

auto kcenon::network::protocols::http2::http2_client::close_stream ( uint32_t stream_id) -> void
private

Definition at line 713 of file http2_client.cpp.

714 {
715 std::lock_guard<std::mutex> lock(streams_mutex_);
716 auto it = streams_.find(stream_id);
717 if (it != streams_.end())
718 {
719 it->second.state = stream_state::closed;
720 }
721 }
std::map< uint32_t, http2_stream > streams_

References kcenon::network::protocols::http2::closed.

◆ close_stream_writer()

auto kcenon::network::protocols::http2::http2_client::close_stream_writer ( uint32_t stream_id) -> VoidResult

Close the write side of a stream.

Parameters
stream_idStream identifier
Returns
Success or error

Definition at line 395 of file http2_client.cpp.

396 {
397 if (!is_connected())
398 {
400 "Not connected",
401 "http2_client::close_stream_writer");
402 }
403
404 auto* stream = get_stream(stream_id);
405 if (!stream)
406 {
408 "Stream not found",
409 "http2_client::close_stream_writer");
410 }
411
412 if (stream->state == stream_state::closed ||
413 stream->state == stream_state::half_closed_local)
414 {
415 return ok(); // Already closed
416 }
417
418 // Send empty DATA frame with END_STREAM
419 data_frame df(stream_id, {}, true);
420 auto send_result = send_frame(df);
421 if (send_result.is_err())
422 {
423 return send_result;
424 }
425
426 stream->state = stream_state::half_closed_local;
427 return ok();
428 }
@ half_closed_local
Local end closed, remote can send.

References kcenon::network::protocols::http2::closed, kcenon::network::error_codes::network_system::connection_closed, kcenon::network::error_void(), kcenon::network::protocols::http2::half_closed_local, kcenon::network::error_codes::common_errors::not_found, and kcenon::network::ok().

Here is the call graph for this function:

◆ connect()

auto kcenon::network::protocols::http2::http2_client::connect ( const std::string & host,
unsigned short port = 443 ) -> VoidResult

Connect to HTTP/2 server.

Parameters
hostServer hostname
portServer port (default 443)
Returns
Success or error

Establishes TLS connection with ALPN "h2", sends connection preface, and exchanges SETTINGS frames.

Definition at line 66 of file http2_client.cpp.

67 {
68 // Create tracing span for connect operation
69 auto span = tracing::is_tracing_enabled()
70 ? std::make_optional(tracing::trace_context::create_span("http2.client.connect"))
71 : std::nullopt;
72 if (span)
73 {
74 span->set_attribute("net.peer.name", host)
75 .set_attribute("net.peer.port", static_cast<int64_t>(port))
76 .set_attribute("net.transport", "tcp")
77 .set_attribute("http.flavor", "2.0")
78 .set_attribute("client.id", client_id_);
79 }
80
81 if (is_connected_)
82 {
83 if (span)
84 {
85 span->set_error("Already connected");
86 }
88 "Already connected", "http2_client::connect");
89 }
90
91 if (host.empty())
92 {
93 if (span)
94 {
95 span->set_error("Host cannot be empty");
96 }
98 "Host cannot be empty", "http2_client::connect");
99 }
100
101 host_ = host;
102 port_ = port;
103
104 try
105 {
106 // Create I/O context
107 io_context_ = std::make_unique<asio::io_context>();
108
109 // Create SSL context with TLS 1.3
110 ssl_context_ = std::make_unique<asio::ssl::context>(asio::ssl::context::tlsv13_client);
111
112 // Set ALPN for HTTP/2
113 SSL_CTX* native_ctx = ssl_context_->native_handle();
114 static const unsigned char alpn_protos[] = { 2, 'h', '2' };
115 SSL_CTX_set_alpn_protos(native_ctx, alpn_protos, sizeof(alpn_protos));
116
117 // Verify peer certificate
118 ssl_context_->set_default_verify_paths();
119 ssl_context_->set_verify_mode(asio::ssl::verify_peer);
120
121 // Create socket
122 asio::ip::tcp::resolver resolver(*io_context_);
123 auto endpoints = resolver.resolve(host, std::to_string(port));
124
125 socket_ = std::make_unique<asio::ssl::stream<asio::ip::tcp::socket>>(
127
128 // Set SNI hostname
129 SSL_set_tlsext_host_name(socket_->native_handle(), host.c_str());
130
131 // Connect TCP
132 asio::connect(socket_->lowest_layer(), endpoints);
133
134 // Perform SSL handshake
135 socket_->handshake(asio::ssl::stream_base::client);
136
137 // Verify ALPN negotiation
138 const unsigned char* alpn_result = nullptr;
139 unsigned int alpn_len = 0;
140 SSL_get0_alpn_selected(socket_->native_handle(), &alpn_result, &alpn_len);
141
142 if (alpn_len != 2 || alpn_result == nullptr ||
143 std::string(reinterpret_cast<const char*>(alpn_result), alpn_len) != "h2")
144 {
145 socket_->lowest_layer().close();
146 if (span)
147 {
148 span->set_error("Server does not support HTTP/2 via ALPN");
149 }
151 "Server does not support HTTP/2 via ALPN",
152 "http2_client::connect");
153 }
154
155 is_connected_ = true;
156 is_running_ = true;
157
158 // Send connection preface
159 auto preface_result = send_connection_preface();
160 if (preface_result.is_err())
161 {
162 is_connected_ = false;
163 is_running_ = false;
164 if (span)
165 {
166 span->set_error(preface_result.error().message);
167 }
168 return preface_result;
169 }
170
171 // Send initial SETTINGS
172 auto settings_result = send_settings();
173 if (settings_result.is_err())
174 {
175 is_connected_ = false;
176 is_running_ = false;
177 if (span)
178 {
179 span->set_error(settings_result.error().message);
180 }
181 return settings_result;
182 }
183
184 // Start I/O thread
185 work_guard_ = std::make_unique<asio::executor_work_guard<asio::io_context::executor_type>>(
186 asio::make_work_guard(*io_context_));
187
188 io_future_ = std::async(std::launch::async, [this]() { run_io(); });
189
190 if (span)
191 {
192 span->set_status(tracing::span_status::ok);
193 }
194 return ok();
195 }
196 catch (const std::exception& e)
197 {
198 is_connected_ = false;
199 is_running_ = false;
200 if (span)
201 {
202 span->set_error(std::string("Connection failed: ") + e.what());
203 }
205 std::string("Connection failed: ") + e.what(),
206 "http2_client::connect");
207 }
208 }
std::unique_ptr< asio::io_context > io_context_
std::unique_ptr< asio::executor_work_guard< asio::io_context::executor_type > > work_guard_
std::unique_ptr< asio::ssl::context > ssl_context_
std::unique_ptr< asio::ssl::stream< asio::ip::tcp::socket > > socket_
static auto create_span(std::string_view name) -> span
Create a new root span with a new trace context.
struct ssl_ctx_st SSL_CTX
Definition crypto.h:20
auto is_tracing_enabled() -> bool
Check if tracing is enabled.
@ ok
Operation completed successfully.

References kcenon::network::error_codes::common_errors::already_exists, kcenon::network::error_codes::network_system::connection_failed, kcenon::network::tracing::trace_context::create_span(), kcenon::network::error_void(), kcenon::network::error_codes::common_errors::invalid_argument, kcenon::network::tracing::is_tracing_enabled(), kcenon::network::ok(), and kcenon::network::tracing::ok.

Here is the call graph for this function:

◆ create_stream()

auto kcenon::network::protocols::http2::http2_client::create_stream ( ) -> http2_stream&
private

Definition at line 702 of file http2_client.cpp.

703 {
704 std::lock_guard<std::mutex> lock(streams_mutex_);
705 uint32_t stream_id = allocate_stream_id();
706 auto& stream = streams_[stream_id];
707 stream.stream_id = stream_id;
708 stream.state = stream_state::idle;
709 stream.window_size = remote_settings_.initial_window_size;
710 return stream;
711 }
uint32_t initial_window_size
Initial flow control window.

References kcenon::network::protocols::http2::idle.

◆ del()

auto kcenon::network::protocols::http2::http2_client::del ( const std::string & path,
const std::vector< http_header > & headers = {} ) -> Result<http2_response>

Perform HTTP/2 DELETE request.

Parameters
pathRequest path
headersAdditional headers (optional)
Returns
Result containing response or error

Definition at line 277 of file http2_client.cpp.

280 {
281 return send_request("DELETE", path, headers, {});
282 }
auto send_request(const std::string &method, const std::string &path, const std::vector< http_header > &headers, const std::vector< uint8_t > &body) -> Result< http2_response >

References kcenon::network::protocols::http2::headers.

◆ disconnect()

auto kcenon::network::protocols::http2::http2_client::disconnect ( ) -> VoidResult

Disconnect from server.

Returns
Success or error

Sends GOAWAY frame and closes connection gracefully.

Definition at line 210 of file http2_client.cpp.

211 {
212 if (!is_connected_)
213 {
214 return ok();
215 }
216
217 try
218 {
219 // Send GOAWAY frame
220 if (socket_ && socket_->lowest_layer().is_open())
221 {
222 goaway_frame goaway(next_stream_id_ - 2,
223 static_cast<uint32_t>(error_code::no_error));
225 }
226 }
227 catch (...)
228 {
229 // Ignore errors during GOAWAY
230 }
231
232 stop_io();
233
234 is_connected_ = false;
235
236 return ok();
237 }

References kcenon::network::protocols::http2::goaway, kcenon::network::protocols::http2::no_error, and kcenon::network::ok().

Referenced by ~http2_client().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get()

auto kcenon::network::protocols::http2::http2_client::get ( const std::string & path,
const std::vector< http_header > & headers = {} ) -> Result<http2_response>

Perform HTTP/2 GET request.

Parameters
pathRequest path (e.g., "/api/users")
headersAdditional headers (optional)
Returns
Result containing response or error

Definition at line 244 of file http2_client.cpp.

247 {
248 return send_request("GET", path, headers, {});
249 }

References kcenon::network::protocols::http2::headers.

◆ get_settings()

auto kcenon::network::protocols::http2::http2_client::get_settings ( ) const -> http2_settings

Get local settings.

Returns
Current local settings

Definition at line 294 of file http2_client.cpp.

295 {
296 return local_settings_;
297 }

References local_settings_.

◆ get_stream()

auto kcenon::network::protocols::http2::http2_client::get_stream ( uint32_t stream_id) -> http2_stream*
private

Definition at line 691 of file http2_client.cpp.

692 {
693 std::lock_guard<std::mutex> lock(streams_mutex_);
694 auto it = streams_.find(stream_id);
695 if (it != streams_.end())
696 {
697 return &it->second;
698 }
699 return nullptr;
700 }

◆ get_timeout()

auto kcenon::network::protocols::http2::http2_client::get_timeout ( ) const -> std::chrono::milliseconds

Get current timeout.

Returns
Timeout duration

Definition at line 289 of file http2_client.cpp.

290 {
291 return timeout_;
292 }

References timeout_.

◆ handle_data_frame()

auto kcenon::network::protocols::http2::http2_client::handle_data_frame ( const data_frame & f) -> VoidResult
private

Definition at line 960 of file http2_client.cpp.

961 {
962 uint32_t stream_id = f.header().stream_id;
963 auto* stream = get_stream(stream_id);
964
965 if (!stream)
966 {
968 "Unknown stream ID",
969 "http2_client::handle_data_frame");
970 }
971
972 // Get data
973 auto data = f.data();
974
975 // For streaming, call callback immediately; otherwise buffer
976 if (stream->is_streaming && stream->on_data)
977 {
978 stream->on_data(std::vector<uint8_t>(data.begin(), data.end()));
979 }
980 else
981 {
982 stream->response_body.insert(stream->response_body.end(),
983 data.begin(), data.end());
984 }
985
986 // Update flow control window
987 stream->window_size -= static_cast<int32_t>(data.size());
988 connection_window_size_ -= static_cast<int32_t>(data.size());
989
990 // Send WINDOW_UPDATE if needed
991 if (stream->window_size < static_cast<int32_t>(DEFAULT_WINDOW_SIZE / 2))
992 {
993 int32_t increment = DEFAULT_WINDOW_SIZE - stream->window_size;
994 window_update_frame wuf(stream_id, increment);
995 send_frame(wuf);
996 stream->window_size += increment;
997 }
998
999 if (connection_window_size_ < static_cast<int32_t>(DEFAULT_WINDOW_SIZE / 2))
1000 {
1001 int32_t increment = DEFAULT_WINDOW_SIZE - connection_window_size_;
1002 window_update_frame wuf(0, increment); // Stream 0 = connection level
1003 send_frame(wuf);
1004 connection_window_size_ += increment;
1005 }
1006
1007 if (f.is_end_stream())
1008 {
1009 stream->body_complete = true;
1010 stream->state = stream_state::closed;
1011
1012 // Extract status code
1013 int status_code = 0;
1014 for (const auto& h : stream->response_headers)
1015 {
1016 if (h.name == ":status")
1017 {
1018 try
1019 {
1020 status_code = std::stoi(h.value);
1021 }
1022 catch (...)
1023 {
1024 status_code = 0;
1025 }
1026 break;
1027 }
1028 }
1029
1030 // Handle streaming vs non-streaming
1031 if (stream->is_streaming)
1032 {
1033 if (stream->on_complete)
1034 {
1035 stream->on_complete(status_code);
1036 }
1037 }
1038 else
1039 {
1040 http2_response response;
1041 response.headers = stream->response_headers;
1042 response.body = stream->response_body;
1043 response.status_code = status_code;
1044 stream->promise.set_value(std::move(response));
1045 }
1046 }
1047
1048 return ok();
1049 }
status_code
gRPC status codes (as defined in grpc/status.h)
Definition status.h:36

References kcenon::network::protocols::http2::http2_response::body, kcenon::network::protocols::http2::closed, kcenon::network::protocols::http2::data, kcenon::network::error_void(), kcenon::network::protocols::http2::http2_response::headers, kcenon::network::error_codes::common_errors::not_found, kcenon::network::ok(), and kcenon::network::protocols::http2::http2_response::status_code.

Here is the call graph for this function:

◆ handle_goaway_frame()

auto kcenon::network::protocols::http2::http2_client::handle_goaway_frame ( const goaway_frame & f) -> VoidResult
private

Definition at line 1069 of file http2_client.cpp.

1070 {
1071 goaway_received_ = true;
1072
1073 // Close all streams with ID > last_stream_id
1074 uint32_t last_stream = f.last_stream_id();
1075 {
1076 std::lock_guard<std::mutex> lock(streams_mutex_);
1077 for (auto& [id, stream] : streams_)
1078 {
1079 if (id > last_stream && stream.state != stream_state::closed)
1080 {
1081 stream.state = stream_state::closed;
1082 http2_response response;
1083 response.status_code = 0;
1084 stream.promise.set_value(std::move(response));
1085 }
1086 }
1087 }
1088
1089 return ok();
1090 }

References kcenon::network::protocols::http2::closed, kcenon::network::ok(), and kcenon::network::protocols::http2::http2_response::status_code.

Here is the call graph for this function:

◆ handle_headers_frame()

auto kcenon::network::protocols::http2::http2_client::handle_headers_frame ( const headers_frame & f) -> VoidResult
private

Definition at line 875 of file http2_client.cpp.

876 {
877 uint32_t stream_id = f.header().stream_id;
878 auto* stream = get_stream(stream_id);
879
880 if (!stream)
881 {
883 "Unknown stream ID",
884 "http2_client::handle_headers_frame");
885 }
886
887 // Decode headers
888 auto decode_result = decoder_.decode(f.header_block());
889 if (decode_result.is_err())
890 {
891 const auto& err = decode_result.error();
892 return error_void(err.code, err.message,
893 "http2_client::handle_headers_frame",
894 get_error_details(err));
895 }
896
897 auto& decoded_headers = decode_result.value();
898
899 // Append to stream headers
900 stream->response_headers.insert(stream->response_headers.end(),
901 decoded_headers.begin(),
902 decoded_headers.end());
903
904 if (f.is_end_headers())
905 {
906 stream->headers_complete = true;
907
908 // Call streaming callback if set
909 if (stream->is_streaming && stream->on_headers)
910 {
911 stream->on_headers(stream->response_headers);
912 }
913 }
914
915 if (f.is_end_stream())
916 {
917 stream->body_complete = true;
918 stream->state = stream_state::closed;
919
920 // Extract status code
921 int status_code = 0;
922 for (const auto& h : stream->response_headers)
923 {
924 if (h.name == ":status")
925 {
926 try
927 {
928 status_code = std::stoi(h.value);
929 }
930 catch (...)
931 {
932 status_code = 0;
933 }
934 break;
935 }
936 }
937
938 // Handle streaming vs non-streaming
939 if (stream->is_streaming)
940 {
941 if (stream->on_complete)
942 {
943 stream->on_complete(status_code);
944 }
945 }
946 else
947 {
948 // Build response for non-streaming
949 http2_response response;
950 response.headers = stream->response_headers;
951 response.body = stream->response_body;
952 response.status_code = status_code;
953 stream->promise.set_value(std::move(response));
954 }
955 }
956
957 return ok();
958 }
auto decode(std::span< const uint8_t > data) -> Result< std::vector< http_header > >
Decode HPACK binary to headers.
Definition hpack.cpp:407
std::string get_error_details(const simple_error &err)

References kcenon::network::protocols::http2::http2_response::body, kcenon::network::protocols::http2::closed, kcenon::network::error_void(), kcenon::network::get_error_details(), kcenon::network::protocols::http2::http2_response::headers, kcenon::network::error_codes::common_errors::not_found, kcenon::network::ok(), and kcenon::network::protocols::http2::http2_response::status_code.

Here is the call graph for this function:

◆ handle_ping_frame()

auto kcenon::network::protocols::http2::http2_client::handle_ping_frame ( const ping_frame & f) -> VoidResult
private

Definition at line 1114 of file http2_client.cpp.

1115 {
1116 if (!f.is_ack())
1117 {
1118 // Send PING ACK
1119 ping_frame ack(f.opaque_data(), true);
1120 return send_frame(ack);
1121 }
1122 return ok();
1123 }

References kcenon::network::ok().

Here is the call graph for this function:

◆ handle_rst_stream_frame()

auto kcenon::network::protocols::http2::http2_client::handle_rst_stream_frame ( const rst_stream_frame & f) -> VoidResult
private

Definition at line 1051 of file http2_client.cpp.

1052 {
1053 uint32_t stream_id = f.header().stream_id;
1054 auto* stream = get_stream(stream_id);
1055
1056 if (stream)
1057 {
1058 stream->state = stream_state::closed;
1059
1060 // Set error response
1061 http2_response response;
1062 response.status_code = 0; // Indicate error
1063 stream->promise.set_value(std::move(response));
1064 }
1065
1066 return ok();
1067 }

References kcenon::network::protocols::http2::closed, kcenon::network::ok(), and kcenon::network::protocols::http2::http2_response::status_code.

Here is the call graph for this function:

◆ handle_settings_frame()

auto kcenon::network::protocols::http2::http2_client::handle_settings_frame ( const settings_frame & frame) -> VoidResult
private

Definition at line 503 of file http2_client.cpp.

504 {
505 if (frame.is_ack())
506 {
507 // Our settings were acknowledged
508 return ok();
509 }
510
511 // Apply remote settings
512 for (const auto& param : frame.settings())
513 {
514 switch (static_cast<setting_identifier>(param.identifier))
515 {
518 encoder_.set_max_table_size(param.value);
519 break;
521 remote_settings_.enable_push = (param.value != 0);
522 break;
525 break;
528 break;
530 remote_settings_.max_frame_size = param.value;
531 break;
534 break;
535 }
536 }
537
538 return send_settings_ack();
539 }
auto set_max_table_size(size_t size) -> void
Set maximum dynamic table size.
Definition hpack.cpp:257
setting_identifier
SETTINGS frame parameter identifiers (RFC 7540 Section 6.5.2)
Definition frame.h:248
@ max_header_list_size
SETTINGS_MAX_HEADER_LIST_SIZE.
@ max_concurrent_streams
SETTINGS_MAX_CONCURRENT_STREAMS.
@ initial_window_size
SETTINGS_INITIAL_WINDOW_SIZE.
std::variant< padding_frame, ping_frame, ack_frame, reset_stream_frame, stop_sending_frame, crypto_frame, new_token_frame, stream_frame, max_data_frame, max_stream_data_frame, max_streams_frame, data_blocked_frame, stream_data_blocked_frame, streams_blocked_frame, new_connection_id_frame, retire_connection_id_frame, path_challenge_frame, path_response_frame, connection_close_frame, handshake_done_frame > frame
Variant type holding any QUIC frame.
uint32_t max_frame_size
Max frame payload size.
uint32_t max_header_list_size
Max header list size.
uint32_t max_concurrent_streams
Max concurrent streams.

References kcenon::network::protocols::http2::enable_push, kcenon::network::protocols::http2::header_table_size, kcenon::network::protocols::http2::initial_window_size, kcenon::network::protocols::http2::max_concurrent_streams, kcenon::network::protocols::http2::max_frame_size, kcenon::network::protocols::http2::max_header_list_size, and kcenon::network::ok().

Here is the call graph for this function:

◆ handle_window_update_frame()

auto kcenon::network::protocols::http2::http2_client::handle_window_update_frame ( const window_update_frame & f) -> VoidResult
private

Definition at line 1092 of file http2_client.cpp.

1093 {
1094 uint32_t stream_id = f.header().stream_id;
1095 int32_t increment = static_cast<int32_t>(f.window_size_increment());
1096
1097 if (stream_id == 0)
1098 {
1099 // Connection-level window update
1100 connection_window_size_ += increment;
1101 }
1102 else
1103 {
1104 auto* stream = get_stream(stream_id);
1105 if (stream)
1106 {
1107 stream->window_size += increment;
1108 }
1109 }
1110
1111 return ok();
1112 }

References kcenon::network::ok().

Here is the call graph for this function:

◆ is_connected()

auto kcenon::network::protocols::http2::http2_client::is_connected ( ) const -> bool

Check if connected.

Returns
True if connected

Definition at line 239 of file http2_client.cpp.

240 {
242 }

References goaway_received_, and is_connected_.

◆ operator=() [1/2]

http2_client & kcenon::network::protocols::http2::http2_client::operator= ( const http2_client & )
delete

◆ operator=() [2/2]

http2_client & kcenon::network::protocols::http2::http2_client::operator= ( http2_client && )
delete

◆ post() [1/2]

auto kcenon::network::protocols::http2::http2_client::post ( const std::string & path,
const std::string & body,
const std::vector< http_header > & headers = {} ) -> Result<http2_response>

Perform HTTP/2 POST request.

Parameters
pathRequest path
bodyRequest body as string
headersAdditional headers (optional)
Returns
Result containing response or error

Definition at line 251 of file http2_client.cpp.

255 {
256 std::vector<uint8_t> body_bytes(body.begin(), body.end());
257 return send_request("POST", path, headers, body_bytes);
258 }

References kcenon::network::protocols::http2::headers.

◆ post() [2/2]

auto kcenon::network::protocols::http2::http2_client::post ( const std::string & path,
const std::vector< uint8_t > & body,
const std::vector< http_header > & headers = {} ) -> Result<http2_response>

Perform HTTP/2 POST request with binary body.

Parameters
pathRequest path
bodyRequest body as bytes
headersAdditional headers (optional)
Returns
Result containing response or error

Definition at line 260 of file http2_client.cpp.

264 {
265 return send_request("POST", path, headers, body);
266 }

References kcenon::network::protocols::http2::headers.

◆ process_frame()

auto kcenon::network::protocols::http2::http2_client::process_frame ( std::unique_ptr< frame > f) -> VoidResult
private

Definition at line 618 of file http2_client.cpp.

619 {
620 if (!f)
621 {
623 "Null frame", "http2_client::process_frame");
624 }
625
626 switch (f->header().type)
627 {
629 if (auto* sf = dynamic_cast<settings_frame*>(f.get()))
630 {
631 return handle_settings_frame(*sf);
632 }
633 break;
634
636 if (auto* hf = dynamic_cast<headers_frame*>(f.get()))
637 {
638 return handle_headers_frame(*hf);
639 }
640 break;
641
642 case frame_type::data:
643 if (auto* df = dynamic_cast<data_frame*>(f.get()))
644 {
645 return handle_data_frame(*df);
646 }
647 break;
648
650 if (auto* rf = dynamic_cast<rst_stream_frame*>(f.get()))
651 {
652 return handle_rst_stream_frame(*rf);
653 }
654 break;
655
657 if (auto* gf = dynamic_cast<goaway_frame*>(f.get()))
658 {
659 return handle_goaway_frame(*gf);
660 }
661 break;
662
664 if (auto* wf = dynamic_cast<window_update_frame*>(f.get()))
665 {
666 return handle_window_update_frame(*wf);
667 }
668 break;
669
670 case frame_type::ping:
671 if (auto* pf = dynamic_cast<ping_frame*>(f.get()))
672 {
673 return handle_ping_frame(*pf);
674 }
675 break;
676
677 default:
678 // Ignore unknown frame types
679 break;
680 }
681
682 return ok();
683 }
auto handle_window_update_frame(const window_update_frame &f) -> VoidResult
auto handle_rst_stream_frame(const rst_stream_frame &f) -> VoidResult
auto handle_headers_frame(const headers_frame &f) -> VoidResult
auto handle_data_frame(const data_frame &f) -> VoidResult
auto handle_settings_frame(const settings_frame &frame) -> VoidResult
auto handle_ping_frame(const ping_frame &f) -> VoidResult
auto handle_goaway_frame(const goaway_frame &f) -> VoidResult

References kcenon::network::protocols::http2::data, kcenon::network::error_void(), kcenon::network::protocols::http2::goaway, kcenon::network::protocols::http2::headers, kcenon::network::error_codes::common_errors::invalid_argument, kcenon::network::ok(), kcenon::network::protocols::http2::ping, kcenon::network::protocols::http2::rst_stream, kcenon::network::protocols::http2::settings, and kcenon::network::protocols::http2::window_update.

Here is the call graph for this function:

◆ put()

auto kcenon::network::protocols::http2::http2_client::put ( const std::string & path,
const std::string & body,
const std::vector< http_header > & headers = {} ) -> Result<http2_response>

Perform HTTP/2 PUT request.

Parameters
pathRequest path
bodyRequest body
headersAdditional headers (optional)
Returns
Result containing response or error

Definition at line 268 of file http2_client.cpp.

272 {
273 std::vector<uint8_t> body_bytes(body.begin(), body.end());
274 return send_request("PUT", path, headers, body_bytes);
275 }

References kcenon::network::protocols::http2::headers.

◆ read_frame()

auto kcenon::network::protocols::http2::http2_client::read_frame ( ) -> Result<std::unique_ptr<frame>>
private

Definition at line 569 of file http2_client.cpp.

570 {
571 if (!socket_ || !socket_->lowest_layer().is_open())
572 {
574 "Connection closed",
575 "http2_client::read_frame");
576 }
577
578 try
579 {
580 // Read frame header (9 bytes)
581 std::vector<uint8_t> header_buf(FRAME_HEADER_SIZE);
582 asio::read(*socket_, asio::buffer(header_buf));
583
584 auto header_result = frame_header::parse(header_buf);
585 if (header_result.is_err())
586 {
587 const auto& err = header_result.error();
588 return error<std::unique_ptr<frame>>(err.code, err.message,
589 "http2_client::read_frame",
590 get_error_details(err));
591 }
592
593 const auto& header = header_result.value();
594
595 // Read frame payload
596 std::vector<uint8_t> payload(header.length);
597 if (header.length > 0)
598 {
599 asio::read(*socket_, asio::buffer(payload));
600 }
601
602 // Combine header and payload for parsing
603 std::vector<uint8_t> frame_data;
604 frame_data.reserve(FRAME_HEADER_SIZE + payload.size());
605 frame_data.insert(frame_data.end(), header_buf.begin(), header_buf.end());
606 frame_data.insert(frame_data.end(), payload.begin(), payload.end());
607
608 return frame::parse(frame_data);
609 }
610 catch (const std::exception& e)
611 {
613 std::string("Failed to read frame: ") + e.what(),
614 "http2_client::read_frame");
615 }
616 }
static auto parse(std::span< const uint8_t > data) -> Result< std::unique_ptr< frame > >
Parse frame from raw bytes.
Definition frame.cpp:94
static auto parse(std::span< const uint8_t > data) -> Result< frame_header >
Parse frame header from raw bytes.
Definition frame.cpp:52

References kcenon::network::error_codes::network_system::connection_closed, kcenon::network::error, kcenon::network::get_error_details(), kcenon::network::protocols::http2::frame::parse(), kcenon::network::protocols::http2::frame_header::parse(), and kcenon::network::error_codes::network_system::receive_failed.

Here is the call graph for this function:

◆ run_io()

auto kcenon::network::protocols::http2::http2_client::run_io ( ) -> void
private

Definition at line 1125 of file http2_client.cpp.

1126 {
1127 while (is_running_ && is_connected_)
1128 {
1129 try
1130 {
1131 auto frame_result = read_frame();
1132 if (frame_result.is_err())
1133 {
1134 if (is_running_)
1135 {
1136 is_connected_ = false;
1137 }
1138 break;
1139 }
1140
1141 process_frame(std::move(frame_result.value()));
1142 }
1143 catch (...)
1144 {
1145 if (is_running_)
1146 {
1147 is_connected_ = false;
1148 }
1149 break;
1150 }
1151 }
1152 }
auto read_frame() -> Result< std::unique_ptr< frame > >
auto process_frame(std::unique_ptr< frame > f) -> VoidResult

◆ send_connection_preface()

auto kcenon::network::protocols::http2::http2_client::send_connection_preface ( ) -> VoidResult
private

Definition at line 466 of file http2_client.cpp.

467 {
468 try
469 {
470 asio::write(*socket_,
471 asio::buffer(CONNECTION_PREFACE.data(), CONNECTION_PREFACE.size()));
472 return ok();
473 }
474 catch (const std::exception& e)
475 {
477 std::string("Failed to send connection preface: ") + e.what(),
478 "http2_client::send_connection_preface");
479 }
480 }
static constexpr std::string_view CONNECTION_PREFACE

References kcenon::network::error_void(), kcenon::network::ok(), and kcenon::network::error_codes::network_system::send_failed.

Here is the call graph for this function:

◆ send_frame()

auto kcenon::network::protocols::http2::http2_client::send_frame ( const frame & f) -> VoidResult
private

Definition at line 547 of file http2_client.cpp.

548 {
549 if (!socket_ || !socket_->lowest_layer().is_open())
550 {
552 "Connection closed", "http2_client::send_frame");
553 }
554
555 try
556 {
557 auto data = f.serialize();
558 asio::write(*socket_, asio::buffer(data));
559 return ok();
560 }
561 catch (const std::exception& e)
562 {
564 std::string("Failed to send frame: ") + e.what(),
565 "http2_client::send_frame");
566 }
567 }

References kcenon::network::error_codes::network_system::connection_closed, kcenon::network::protocols::http2::data, kcenon::network::error_void(), kcenon::network::ok(), and kcenon::network::error_codes::network_system::send_failed.

Here is the call graph for this function:

◆ send_request()

auto kcenon::network::protocols::http2::http2_client::send_request ( const std::string & method,
const std::string & path,
const std::vector< http_header > & headers,
const std::vector< uint8_t > & body ) -> Result<http2_response>
private

Definition at line 723 of file http2_client.cpp.

728 {
729 // Create tracing span for HTTP request
730 auto span = tracing::is_tracing_enabled()
731 ? std::make_optional(tracing::trace_context::create_span("http2.request"))
732 : std::nullopt;
733 if (span)
734 {
735 span->set_attribute("http.method", method)
736 .set_attribute("http.url", "https://" + host_ + ":" + std::to_string(port_) + path)
737 .set_attribute("http.flavor", "2.0")
738 .set_attribute("http.request.body_size", static_cast<int64_t>(body.size()))
739 .set_attribute("net.peer.name", host_)
740 .set_attribute("net.peer.port", static_cast<int64_t>(port_));
741 }
742
743 if (!is_connected())
744 {
745 if (span)
746 {
747 span->set_error("Not connected");
748 }
750 "Not connected",
751 "http2_client::send_request");
752 }
753
754 // Create stream
755 http2_stream& stream = create_stream();
756 stream.state = stream_state::open;
757
758 if (span)
759 {
760 span->set_attribute("http2.stream_id", static_cast<int64_t>(stream.stream_id));
761 }
762
763 // Build headers
764 auto request_headers = build_headers(method, path, headers);
765 stream.request_headers = request_headers;
766 stream.request_body = body;
767
768 // Encode headers with HPACK
769 auto encoded_headers = encoder_.encode(request_headers);
770
771 // Send HEADERS frame
772 bool end_stream = body.empty();
773 headers_frame hf(stream.stream_id, std::move(encoded_headers), end_stream, true);
774
775 auto send_result = send_frame(hf);
776 if (send_result.is_err())
777 {
778 close_stream(stream.stream_id);
779 const auto& err = send_result.error();
780 if (span)
781 {
782 span->set_error(err.message);
783 }
784 return error<http2_response>(err.code, err.message,
785 "http2_client::send_request",
786 get_error_details(err));
787 }
788
789 // Send DATA frame if body exists
790 if (!body.empty())
791 {
792 data_frame df(stream.stream_id, std::vector<uint8_t>(body), true);
793 send_result = send_frame(df);
794 if (send_result.is_err())
795 {
796 close_stream(stream.stream_id);
797 const auto& err = send_result.error();
798 if (span)
799 {
800 span->set_error(err.message);
801 }
802 return error<http2_response>(err.code, err.message,
803 "http2_client::send_request",
804 get_error_details(err));
805 }
806 stream.state = stream_state::half_closed_local;
807 }
808 else
809 {
810 stream.state = stream_state::half_closed_local;
811 }
812
813 // Wait for response with timeout
814 auto future = stream.promise.get_future();
815 auto status = future.wait_for(timeout_);
816
817 if (status == std::future_status::timeout)
818 {
819 close_stream(stream.stream_id);
820 if (span)
821 {
822 span->set_error("Request timeout");
823 }
825 "Request timeout",
826 "http2_client::send_request");
827 }
828
829 auto response = future.get();
830 if (span)
831 {
832 span->set_attribute("http.status_code", static_cast<int64_t>(response.status_code))
833 .set_attribute("http.response.body_size", static_cast<int64_t>(response.body.size()));
834 if (response.status_code >= 400)
835 {
836 span->set_status(tracing::span_status::error, "HTTP " + std::to_string(response.status_code));
837 }
838 else
839 {
840 span->set_status(tracing::span_status::ok);
841 }
842 }
843 return ok(std::move(response));
844 }
auto encode(const std::vector< http_header > &headers) -> std::vector< uint8_t >
Encode headers to HPACK binary format.
Definition hpack.cpp:196
auto close_stream(uint32_t stream_id) -> void
auto build_headers(const std::string &method, const std::string &path, const std::vector< http_header > &additional) -> std::vector< http_header >

References kcenon::network::error_codes::network_system::connection_closed, kcenon::network::tracing::trace_context::create_span(), kcenon::network::error, kcenon::network::tracing::error, kcenon::network::get_error_details(), kcenon::network::protocols::http2::half_closed_local, kcenon::network::protocols::http2::headers, kcenon::network::tracing::is_tracing_enabled(), kcenon::network::ok(), kcenon::network::tracing::ok, kcenon::network::protocols::http2::open, kcenon::network::protocols::http2::http2_stream::promise, kcenon::network::protocols::http2::http2_stream::request_body, kcenon::network::protocols::http2::http2_stream::request_headers, kcenon::network::protocols::http2::http2_stream::state, kcenon::network::protocols::http2::http2_stream::stream_id, and kcenon::network::error_codes::common_errors::timeout.

Here is the call graph for this function:

◆ send_settings()

◆ send_settings_ack()

auto kcenon::network::protocols::http2::http2_client::send_settings_ack ( ) -> VoidResult
private

Definition at line 541 of file http2_client.cpp.

542 {
543 settings_frame ack({}, true);
544 return send_frame(ack);
545 }

◆ set_settings()

auto kcenon::network::protocols::http2::http2_client::set_settings ( const http2_settings & settings) -> void

Update local settings.

Parameters
settingsNew settings to apply

Definition at line 299 of file http2_client.cpp.

300 {
302 encoder_.set_max_table_size(settings.header_table_size);
303 decoder_.set_max_table_size(settings.header_table_size);
304 }
auto set_max_table_size(size_t size) -> void
Set maximum dynamic table size.
Definition hpack.cpp:526

References kcenon::network::protocols::http2::settings.

◆ set_timeout()

auto kcenon::network::protocols::http2::http2_client::set_timeout ( std::chrono::milliseconds timeout) -> void

Set request timeout.

Parameters
timeoutTimeout duration

Definition at line 284 of file http2_client.cpp.

285 {
287 }

◆ start_stream()

auto kcenon::network::protocols::http2::http2_client::start_stream ( const std::string & path,
const std::vector< http_header > & headers,
std::function< void(std::vector< uint8_t >)> on_data,
std::function< void(std::vector< http_header >)> on_headers,
std::function< void(int)> on_complete ) -> Result<uint32_t>

Start a streaming POST request.

Parameters
pathRequest path
headersAdditional headers
on_dataCallback for each data chunk received
on_headersCallback when headers are received
on_completeCallback when stream completes (with status code)
Returns
Stream ID on success, or error

Use write_stream() to send data and close_stream_writer() when done.

Definition at line 306 of file http2_client.cpp.

312 {
313 if (!is_connected())
314 {
316 "Not connected",
317 "http2_client::start_stream");
318 }
319
320 // Create stream with callbacks
321 http2_stream& stream = create_stream();
322 stream.state = stream_state::open;
323 stream.is_streaming = true;
324 stream.on_data = std::move(on_data);
325 stream.on_headers = std::move(on_headers);
326 stream.on_complete = std::move(on_complete);
327
328 // Build headers for POST (streaming requests use POST)
329 auto request_headers = build_headers("POST", path, headers);
330 stream.request_headers = request_headers;
331
332 // Encode headers with HPACK
333 auto encoded_headers = encoder_.encode(request_headers);
334
335 // Send HEADERS frame (not end_stream since we might send more data)
336 headers_frame hf(stream.stream_id, std::move(encoded_headers), false, true);
337
338 auto send_result = send_frame(hf);
339 if (send_result.is_err())
340 {
341 close_stream(stream.stream_id);
342 const auto& err = send_result.error();
343 return error<uint32_t>(err.code, err.message,
344 "http2_client::start_stream",
345 get_error_details(err));
346 }
347
348 uint32_t result_id = stream.stream_id;
349 return ok(std::move(result_id));
350 }

References kcenon::network::error_codes::network_system::connection_closed, kcenon::network::error, kcenon::network::get_error_details(), kcenon::network::protocols::http2::headers, kcenon::network::protocols::http2::http2_stream::is_streaming, kcenon::network::ok(), kcenon::network::protocols::http2::http2_stream::on_complete, kcenon::network::protocols::http2::http2_stream::on_data, kcenon::network::protocols::http2::http2_stream::on_headers, kcenon::network::protocols::http2::open, kcenon::network::protocols::http2::http2_stream::request_headers, kcenon::network::protocols::http2::http2_stream::state, and kcenon::network::protocols::http2::http2_stream::stream_id.

Here is the call graph for this function:

◆ stop_io()

auto kcenon::network::protocols::http2::http2_client::stop_io ( ) -> void
private

Definition at line 1154 of file http2_client.cpp.

1155 {
1156 is_running_ = false;
1157
1158 if (work_guard_)
1159 {
1160 work_guard_->reset();
1161 }
1162
1163 if (socket_ && socket_->lowest_layer().is_open())
1164 {
1165 std::error_code ec;
1166 socket_->lowest_layer().shutdown(asio::ip::tcp::socket::shutdown_both, ec);
1167 socket_->lowest_layer().close(ec);
1168 }
1169
1170 if (io_future_.valid())
1171 {
1172 io_future_.wait_for(std::chrono::seconds(5));
1173 }
1174
1175 if (io_context_)
1176 {
1177 io_context_->stop();
1178 }
1179 }

◆ write_stream()

auto kcenon::network::protocols::http2::http2_client::write_stream ( uint32_t stream_id,
const std::vector< uint8_t > & data,
bool end_stream = false ) -> VoidResult

Write data to an open stream.

Parameters
stream_idStream identifier
dataData to write
end_streamSet to true to signal end of client data
Returns
Success or error

Definition at line 352 of file http2_client.cpp.

355 {
356 if (!is_connected())
357 {
359 "Not connected",
360 "http2_client::write_stream");
361 }
362
363 auto* stream = get_stream(stream_id);
364 if (!stream)
365 {
367 "Stream not found",
368 "http2_client::write_stream");
369 }
370
371 if (stream->state == stream_state::closed ||
372 stream->state == stream_state::half_closed_local)
373 {
375 "Stream not writable",
376 "http2_client::write_stream");
377 }
378
379 // Send DATA frame
380 data_frame df(stream_id, std::vector<uint8_t>(data), end_stream);
381 auto send_result = send_frame(df);
382 if (send_result.is_err())
383 {
384 return send_result;
385 }
386
387 if (end_stream)
388 {
389 stream->state = stream_state::half_closed_local;
390 }
391
392 return ok();
393 }

References kcenon::network::protocols::http2::closed, kcenon::network::error_codes::network_system::connection_closed, kcenon::network::protocols::http2::data, kcenon::network::error_void(), kcenon::network::protocols::http2::half_closed_local, kcenon::network::error_codes::common_errors::internal_error, kcenon::network::error_codes::common_errors::not_found, and kcenon::network::ok().

Here is the call graph for this function:

Member Data Documentation

◆ client_id_

std::string kcenon::network::protocols::http2::http2_client::client_id_
private

Client identifier.

Definition at line 365 of file http2_client.h.

◆ CONNECTION_PREFACE

std::string_view kcenon::network::protocols::http2::http2_client::CONNECTION_PREFACE
staticconstexprprivate
Initial value:
=
"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"

Definition at line 402 of file http2_client.h.

◆ connection_window_size_

int32_t kcenon::network::protocols::http2::http2_client::connection_window_size_ = 65535
private

Definition at line 385 of file http2_client.h.

◆ decoder_

hpack_decoder kcenon::network::protocols::http2::http2_client::decoder_
private

Definition at line 393 of file http2_client.h.

◆ DEFAULT_WINDOW_SIZE

size_t kcenon::network::protocols::http2::http2_client::DEFAULT_WINDOW_SIZE = 65535
staticconstexprprivate

Definition at line 405 of file http2_client.h.

◆ encoder_

hpack_encoder kcenon::network::protocols::http2::http2_client::encoder_
private

Definition at line 392 of file http2_client.h.

◆ FRAME_HEADER_SIZE

size_t kcenon::network::protocols::http2::http2_client::FRAME_HEADER_SIZE = 9
staticconstexprprivate

Definition at line 404 of file http2_client.h.

◆ goaway_received_

std::atomic<bool> kcenon::network::protocols::http2::http2_client::goaway_received_ {false}
private

Definition at line 379 of file http2_client.h.

379{false};

Referenced by is_connected().

◆ host_

std::string kcenon::network::protocols::http2::http2_client::host_
private

Connected host.

Definition at line 366 of file http2_client.h.

◆ io_context_

std::unique_ptr<asio::io_context> kcenon::network::protocols::http2::http2_client::io_context_
private

Definition at line 370 of file http2_client.h.

◆ io_future_

std::future<void> kcenon::network::protocols::http2::http2_client::io_future_
private

Definition at line 374 of file http2_client.h.

◆ is_connected_

std::atomic<bool> kcenon::network::protocols::http2::http2_client::is_connected_ {false}
private

Definition at line 377 of file http2_client.h.

377{false};

Referenced by is_connected(), and ~http2_client().

◆ is_running_

std::atomic<bool> kcenon::network::protocols::http2::http2_client::is_running_ {false}
private

Definition at line 378 of file http2_client.h.

378{false};

◆ local_settings_

http2_settings kcenon::network::protocols::http2::http2_client::local_settings_
private

Definition at line 388 of file http2_client.h.

Referenced by get_settings().

◆ next_stream_id_

std::atomic<uint32_t> kcenon::network::protocols::http2::http2_client::next_stream_id_ {1}
private

Client streams are odd.

Definition at line 384 of file http2_client.h.

384{1};

◆ port_

unsigned short kcenon::network::protocols::http2::http2_client::port_ = 443
private

Connected port.

Definition at line 367 of file http2_client.h.

◆ read_buffer_

std::vector<uint8_t> kcenon::network::protocols::http2::http2_client::read_buffer_
private

Definition at line 399 of file http2_client.h.

◆ remote_settings_

http2_settings kcenon::network::protocols::http2::http2_client::remote_settings_
private

Definition at line 389 of file http2_client.h.

◆ socket_

std::unique_ptr<asio::ssl::stream<asio::ip::tcp::socket> > kcenon::network::protocols::http2::http2_client::socket_
private

Definition at line 372 of file http2_client.h.

◆ ssl_context_

std::unique_ptr<asio::ssl::context> kcenon::network::protocols::http2::http2_client::ssl_context_
private

Definition at line 371 of file http2_client.h.

◆ streams_

std::map<uint32_t, http2_stream> kcenon::network::protocols::http2::http2_client::streams_
private

Definition at line 383 of file http2_client.h.

◆ streams_mutex_

std::mutex kcenon::network::protocols::http2::http2_client::streams_mutex_
private

Definition at line 382 of file http2_client.h.

◆ timeout_

std::chrono::milliseconds kcenon::network::protocols::http2::http2_client::timeout_ {30000}
private

Definition at line 396 of file http2_client.h.

396{30000};

Referenced by get_timeout().

◆ work_guard_

std::unique_ptr<asio::executor_work_guard<asio::io_context::executor_type> > kcenon::network::protocols::http2::http2_client::work_guard_
private

Definition at line 373 of file http2_client.h.


The documentation for this class was generated from the following files: