27 std::map<StreamId, std::shared_ptr<StreamData>>
streams;
33 configuration(
std::move(configuration_))
37 nghttp2_session_callbacks* callbacks =
nullptr;
38 nghttp2_session_callbacks_new(&callbacks);
39 nghttp2_session_callbacks_set_on_stream_close_callback(
40 callbacks, on_stream_close_callback);
41 nghttp2_session_callbacks_set_data_source_read_length_callback(
42 callbacks, on_data_source_read_length_callback);
43 nghttp2_session_callbacks_set_error_callback2(
44 callbacks, on_error_callback);
46 nghttp2_session_callbacks_set_on_begin_frame_callback(
47 callbacks, on_begin_frame_recv_callback);
48 nghttp2_session_callbacks_set_on_frame_recv_callback(
49 callbacks, on_frame_recv_callback);
50 nghttp2_session_callbacks_set_on_begin_headers_callback(
51 callbacks, on_begin_headers_callback);
52 nghttp2_session_callbacks_set_on_header_callback(
53 callbacks, on_header_callback);
54 nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
55 callbacks, on_data_callback);
59 if (nghttp2_session_client_new(&
session, callbacks,
this) != 0)
61 throw std::logic_error(
"Could not create new HTTP/2 client session");
66 if (nghttp2_session_server_new(&
session, callbacks,
this) != 0)
68 throw std::logic_error(
"Could not create new HTTP/2 server session");
73 std::vector<nghttp2_settings_entry> settings;
75 {NGHTTP2_SETTINGS_MAX_FRAME_SIZE,
77 ccf::http::default_max_frame_size))});
79 {NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS,
80 static_cast<uint32_t
>(
82 ccf::http::default_max_concurrent_streams_count))});
84 {NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE,
86 ccf::http::default_initial_window_size))});
90 {NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE,
91 static_cast<uint32_t
>(
93 ccf::http::default_max_headers_count) *
95 ccf::http::default_max_header_size))});
97 auto rv = nghttp2_submit_settings(
98 session, NGHTTP2_FLAG_NONE, settings.data(), settings.size());
101 throw std::logic_error(fmt::format(
102 "Error submitting settings for HTTP2 session: {}",
103 nghttp2_strerror(rv)));
106 nghttp2_session_callbacks_del(callbacks);
116 return last_stream_id;
122 return configuration;
127 handle_outgoing_data = std::move(cb);
131 StreamId stream_id,
const std::shared_ptr<StreamData>& stream_data)
133 auto it =
streams.find(stream_id);
136 throw std::logic_error(fmt::format(
137 "Cannot store new stream {} as it already exists", stream_id));
140 streams.insert(it, {stream_id, stream_data});
141 last_stream_id = stream_id;
146 auto it =
streams.find(stream_id);
156 auto s = std::make_shared<StreamData>();
164 auto it =
streams.find(stream_id);
170 auto stream_data = it->second;
174 stream_data->close_callback !=
nullptr &&
180 stream_data->close_callback();
182 catch (
const std::exception& e)
187 LOG_TRACE_FMT(
"Successfully destroyed stream {}", stream_id);
191 LOG_DEBUG_FMT(
"Cannot destroy unknown stream {}", stream_id);
195 bool execute(
const uint8_t* data,
size_t size)
198 auto readlen = nghttp2_session_mem_recv(
session, data, size);
201 throw std::logic_error(fmt::format(
202 "HTTP/2: Error receiving data: {}", nghttp2_strerror(readlen)));
210 nghttp2_session_want_read(
session) == 0 &&
211 nghttp2_session_want_write(
session) == 0)
213 LOG_TRACE_FMT(
"http2::Parser execute: Closing session gracefully");
223 const uint8_t* data =
nullptr;
224 while ((size = nghttp2_session_mem_send(
session, &data)) != 0)
228 handle_outgoing_data({data,
static_cast<size_t>(size)});
232 throw std::logic_error(fmt::format(
233 "HTTP/2: Error sending data: {}", nghttp2_strerror(size)));
246 if (trailers.empty())
252 std::vector<nghttp2_nv> trlrs;
253 trlrs.reserve(trailers.size());
254 for (
auto& [k, v] : trailers)
256 trlrs.emplace_back(make_nv(k.data(), v.data()));
260 nghttp2_submit_trailer(
session, stream_id, trlrs.data(), trlrs.size());
263 throw std::logic_error(fmt::format(
264 "nghttp2_submit_trailer error: {}", nghttp2_strerror(rv)));
268 void submit_response(
274 std::vector<nghttp2_nv> hdrs = {};
276 auto status_str = fmt::format(
277 "{}",
static_cast<std::underlying_type_t<ccf::http_status>
>(status));
279 make_nv(ccf::http2::headers::STATUS, status_str.data()));
281 for (
const auto& [k, v] : base_headers)
283 hdrs.emplace_back(make_nv(k.data(), v.data()));
286 for (
const auto& [k, v] : extra_headers)
288 hdrs.emplace_back(make_nv(k.data(), v.data()));
291 nghttp2_data_provider prov;
292 prov.read_callback = read_outgoing_callback;
294 int rv = nghttp2_submit_response(
295 session, stream_id, hdrs.data(), hdrs.size(), &prov);
298 throw std::logic_error(fmt::format(
299 "nghttp2_submit_response error: {}", nghttp2_strerror(rv)));
307 Parser(configuration_, false),
314 "http2::set_on_stream_close_callback: stream {}", stream_id);
316 auto* stream_data = get_stream_data(
session, stream_id);
317 if (stream_data ==
nullptr)
319 throw std::logic_error(
320 fmt::format(
"Stream {} no longer exists", stream_id));
323 stream_data->close_callback = cb;
331 std::vector<uint8_t>&& body)
334 "http2::respond: stream {} - {} headers - {} trailers - {} bytes "
341 auto* stream_data = get_stream_data(
session, stream_id);
342 if (stream_data ==
nullptr)
344 throw std::logic_error(
345 fmt::format(
"Stream {} no longer exists", stream_id));
348 bool should_submit_response =
354 extra_headers[ccf::http::headers::CONTENT_LENGTH] =
355 std::to_string(body.size());
356 auto thv = make_trailer_header_value(trailers);
359 extra_headers[ccf::http::headers::TRAILER] = thv.value();
362 stream_data->outgoing.body =
DataSource(std::move(body));
363 stream_data->outgoing.has_trailers = !trailers.empty();
365 if (should_submit_response)
367 submit_response(stream_id, status, std::move(headers), extra_headers);
371 submit_trailers(stream_id, std::move(trailers));
381 "http2::start_stream: stream {} - {} headers",
385 auto* stream_data = get_stream_data(
session, stream_id);
386 if (stream_data ==
nullptr)
388 throw std::logic_error(
389 fmt::format(
"Stream {} no longer exists", stream_id));
394 throw std::logic_error(fmt::format(
395 "Stream {} should be uninitialised to start stream", stream_id));
400 submit_response(stream_id, status, std::move(headers));
407 "http2::send_data: stream {} - {} bytes", stream_id, data.size());
409 auto* stream_data = get_stream_data(
session, stream_id);
410 if (stream_data ==
nullptr)
412 throw std::logic_error(
413 fmt::format(
"Stream {} no longer exists", stream_id));
418 throw std::logic_error(
419 fmt::format(
"Stream {} should be streaming to send data", stream_id));
422 stream_data->outgoing.body =
DataSource(std::move(data));
424 int rv = nghttp2_session_resume_data(
session, stream_id);
427 throw std::logic_error(fmt::format(
428 "nghttp2_session_resume_data error: {}", nghttp2_strerror(rv)));
437 "http2::close: stream {} - {} trailers ", stream_id, trailers.size());
439 auto* stream_data = get_stream_data(
session, stream_id);
440 if (stream_data ==
nullptr)
442 throw std::logic_error(
443 fmt::format(
"Stream {} no longer exists", stream_id));
446 auto it =
streams.find(stream_id);
450 stream_data->outgoing.has_trailers = !trailers.empty();
452 submit_trailers(stream_id, std::move(trailers));
463 if (stream_data ==
nullptr)
471 std::string url = {};
473 const auto url_it = headers.find(ccf::http2::headers::PATH);
474 if (url_it != headers.end())
476 url = url_it->second;
480 llhttp_method method = {};
482 const auto method_it = headers.find(ccf::http2::headers::METHOD);
483 if (method_it != headers.end())
485 method = ccf::http_method_from_str(method_it->second);
510 llhttp_method method,
511 const std::string& route,
513 std::vector<uint8_t>&& body)
515 std::vector<nghttp2_nv> hdrs;
517 make_nv(ccf::http2::headers::METHOD, llhttp_method_name(method)));
518 hdrs.emplace_back(make_nv(ccf::http2::headers::PATH, route.data()));
519 hdrs.emplace_back(make_nv(
":scheme",
"https"));
520 hdrs.emplace_back(make_nv(
":authority",
"localhost:8080"));
521 for (
auto const& [k, v] : headers)
523 hdrs.emplace_back(make_nv(k.data(), v.data()));
526 auto stream_data = std::make_shared<StreamData>();
527 stream_data->outgoing.body =
DataSource(std::move(body));
529 nghttp2_data_provider prov;
530 prov.read_callback = read_outgoing_callback;
534 auto stream_id = nghttp2_submit_request(
535 session,
nullptr, hdrs.data(), hdrs.size(), &prov, stream_data.get());
539 "Could not submit HTTP request: {}", nghttp2_strerror(stream_id));
546 LOG_DEBUG_FMT(
"Successfully sent request with stream id: {}", stream_id);
554 if (stream_data ==
nullptr)
564 const auto status_it = headers.find(ccf::http2::headers::STATUS);
565 if (status_it != headers.end())
Definition http2_types.h:67
Definition http2_parser.h:499
ClientParser(::http::ResponseProcessor &proc_)
Definition http2_parser.h:504
void send_structured_request(llhttp_method method, const std::string &route, const ccf::http::HeaderMap &headers, std::vector< uint8_t > &&body)
Definition http2_parser.h:509
void handle_completed(StreamId, StreamData *stream_data) override
Definition http2_parser.h:549
Definition http2_parser.h:18
void set_outgoing_data_handler(DataHandlerCB &&cb)
Definition http2_parser.h:125
std::map< StreamId, std::shared_ptr< StreamData > > streams
Definition http2_parser.h:27
nghttp2_session * session
Definition http2_parser.h:28
StreamId get_last_stream_id() const override
Definition http2_parser.h:114
ccf::http::ParserConfiguration get_configuration() const override
Definition http2_parser.h:119
~Parser() override
Definition http2_parser.h:109
void send_all_submitted()
Definition http2_parser.h:220
void store_stream(StreamId stream_id, const std::shared_ptr< StreamData > &stream_data)
Definition http2_parser.h:130
bool execute(const uint8_t *data, size_t size)
Definition http2_parser.h:195
std::shared_ptr< StreamData > get_stream(StreamId stream_id) override
Definition http2_parser.h:144
std::shared_ptr< StreamData > create_stream(StreamId stream_id) override
Definition http2_parser.h:154
void destroy_stream(StreamId stream_id) override
Definition http2_parser.h:162
Parser(ccf::http::ParserConfiguration configuration_, bool is_client=false)
Definition http2_parser.h:31
Definition http2_parser.h:240
void start_stream(StreamId stream_id, ccf::http_status status, ccf::http::HeaderMap &&headers)
Definition http2_parser.h:375
void send_data(StreamId stream_id, std::vector< uint8_t > &&data)
Definition http2_parser.h:404
void set_on_stream_close_callback(StreamId stream_id, StreamCloseCB cb)
Definition http2_parser.h:311
ServerParser(http::RequestProcessor &proc_, const ccf::http::ParserConfiguration &configuration_)
Definition http2_parser.h:304
void handle_completed(StreamId stream_id, StreamData *stream_data) override
Definition http2_parser.h:459
void respond(StreamId stream_id, ccf::http_status status, ccf::http::HeaderMap &&headers, ccf::http::HeaderMap &&trailers, std::vector< uint8_t > &&body)
Definition http2_parser.h:326
void close_stream(StreamId stream_id, ccf::http::HeaderMap &&trailers)
Definition http2_parser.h:434
Definition http_proc.h:20
virtual void handle_request(llhttp_method method, const std::string_view &url, ccf::http::HeaderMap &&headers, std::vector< uint8_t > &&body, int32_t stream_id=http2::DEFAULT_STREAM_ID)=0
Definition http_proc.h:33
virtual void handle_response(ccf::http_status status, ccf::http::HeaderMap &&headers, std::vector< uint8_t > &&body)=0
#define LOG_TRACE_FMT
Definition internal_logger.h:13
#define LOG_DEBUG_FMT
Definition internal_logger.h:14
#define LOG_FAIL_FMT
Definition internal_logger.h:16
std::map< std::string, std::string, std::less<> > HeaderMap
Definition http_header_map.h:10
Definition app_interface.h:14
llhttp_status http_status
Definition http_status.h:9
Definition http2_callbacks.h:12
int32_t StreamId
Definition http2_types.h:20
std::function< void(void)> StreamCloseCB
Definition http2_types.h:23
std::function< void(std::span< const uint8_t >)> DataHandlerCB
Definition http2_parser.h:15
Definition error_reporter.h:6
Definition http_configuration.h:24
std::optional< ccf::ds::SizeString > max_header_size
Definition http_configuration.h:26
std::optional< size_t > max_concurrent_streams_count
Definition http_configuration.h:30
std::optional< ccf::ds::SizeString > initial_window_size
Definition http_configuration.h:31
std::optional< uint32_t > max_headers_count
Definition http_configuration.h:27
std::optional< ccf::ds::SizeString > max_frame_size
Definition http_configuration.h:34
Definition http2_types.h:35
std::vector< uint8_t > body
Definition http2_types.h:51
ccf::http::HeaderMap headers
Definition http2_types.h:50
Definition http2_types.h:47
Incoming incoming
Definition http2_types.h:53