27 std::map<StreamId, std::shared_ptr<StreamData>>
streams;
33 bool is_client =
false) :
34 configuration(configuration_)
38 nghttp2_session_callbacks* callbacks;
39 nghttp2_session_callbacks_new(&callbacks);
40 nghttp2_session_callbacks_set_on_stream_close_callback(
41 callbacks, on_stream_close_callback);
42 nghttp2_session_callbacks_set_data_source_read_length_callback(
43 callbacks, on_data_source_read_length_callback);
44 nghttp2_session_callbacks_set_error_callback2(
45 callbacks, on_error_callback);
47 nghttp2_session_callbacks_set_on_begin_frame_callback(
48 callbacks, on_begin_frame_recv_callback);
49 nghttp2_session_callbacks_set_on_frame_recv_callback(
50 callbacks, on_frame_recv_callback);
51 nghttp2_session_callbacks_set_on_begin_headers_callback(
52 callbacks, on_begin_headers_callback);
53 nghttp2_session_callbacks_set_on_header_callback(
54 callbacks, on_header_callback);
55 nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
56 callbacks, on_data_callback);
60 if (nghttp2_session_client_new(&
session, callbacks,
this) != 0)
62 throw std::logic_error(
"Could not create new HTTP/2 client session");
67 if (nghttp2_session_server_new(&
session, callbacks,
this) != 0)
69 throw std::logic_error(
"Could not create new HTTP/2 server session");
74 std::vector<nghttp2_settings_entry> settings;
76 {NGHTTP2_SETTINGS_MAX_FRAME_SIZE,
78 ccf::http::default_max_frame_size))});
80 {NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS,
81 static_cast<uint32_t
>(
83 ccf::http::default_max_concurrent_streams_count))});
85 {NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE,
87 ccf::http::default_initial_window_size))});
91 {NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE,
92 static_cast<uint32_t
>(
94 ccf::http::default_max_headers_count) *
96 ccf::http::default_max_header_size))});
98 auto rv = nghttp2_submit_settings(
99 session, NGHTTP2_FLAG_NONE, settings.data(), settings.size());
102 throw std::logic_error(fmt::format(
103 "Error submitting settings for HTTP2 session: {}",
104 nghttp2_strerror(rv)));
107 nghttp2_session_callbacks_del(callbacks);
117 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(
278 static_cast<std::underlying_type<ccf::http_status>::type
>(status));
280 make_nv(ccf::http2::headers::STATUS, status_str.data()));
282 for (
auto& [k, v] : base_headers)
284 hdrs.emplace_back(make_nv(k.data(), v.data()));
287 for (
auto& [k, v] : extra_headers)
289 hdrs.emplace_back(make_nv(k.data(), v.data()));
292 nghttp2_data_provider prov;
293 prov.read_callback = read_outgoing_callback;
295 int rv = nghttp2_submit_response(
296 session, stream_id, hdrs.data(), hdrs.size(), &prov);
299 throw std::logic_error(fmt::format(
300 "nghttp2_submit_response error: {}", nghttp2_strerror(rv)));
308 Parser(configuration_, false),
315 "http2::set_on_stream_close_callback: stream {}", stream_id);
317 auto* stream_data = get_stream_data(
session, stream_id);
318 if (stream_data ==
nullptr)
320 throw std::logic_error(
321 fmt::format(
"Stream {} no longer exists", stream_id));
324 stream_data->close_callback = cb;
332 std::span<const uint8_t> body)
335 "http2::respond: stream {} - {} headers - {} trailers - {} bytes "
342 auto* stream_data = get_stream_data(
session, stream_id);
343 if (stream_data ==
nullptr)
345 throw std::logic_error(
346 fmt::format(
"Stream {} no longer exists", stream_id));
349 bool should_submit_response =
355 extra_headers[ccf::http::headers::CONTENT_LENGTH] =
356 std::to_string(body.size());
357 auto thv = make_trailer_header_value(trailers);
360 extra_headers[ccf::http::headers::TRAILER] = thv.value();
363 stream_data->outgoing.body =
DataSource(body);
364 stream_data->outgoing.has_trailers = !trailers.empty();
366 if (should_submit_response)
368 submit_response(stream_id, status, headers, extra_headers);
372 submit_trailers(stream_id, std::move(trailers));
382 "http2::start_stream: stream {} - {} headers",
386 auto* stream_data = get_stream_data(
session, stream_id);
387 if (stream_data ==
nullptr)
389 throw std::logic_error(
390 fmt::format(
"Stream {} no longer exists", stream_id));
395 throw std::logic_error(fmt::format(
396 "Stream {} should be uninitialised to start stream", stream_id));
401 submit_response(stream_id, status, headers);
408 "http2::send_data: stream {} - {} bytes", stream_id, data.size());
410 auto* stream_data = get_stream_data(
session, stream_id);
411 if (stream_data ==
nullptr)
413 throw std::logic_error(
414 fmt::format(
"Stream {} no longer exists", stream_id));
419 throw std::logic_error(
420 fmt::format(
"Stream {} should be streaming to send data", stream_id));
423 stream_data->outgoing.body =
DataSource(data);
425 int rv = nghttp2_session_resume_data(
session, stream_id);
428 throw std::logic_error(fmt::format(
429 "nghttp2_session_resume_data error: {}", nghttp2_strerror(rv)));
438 "http2::close: stream {} - {} trailers ", stream_id, trailers.size());
440 auto* stream_data = get_stream_data(
session, stream_id);
441 if (stream_data ==
nullptr)
443 throw std::logic_error(
444 fmt::format(
"Stream {} no longer exists", stream_id));
447 auto it =
streams.find(stream_id);
451 stream_data->outgoing.has_trailers = !trailers.empty();
453 submit_trailers(stream_id, std::move(trailers));
465 if (stream_data ==
nullptr)
473 std::string url = {};
475 const auto url_it = headers.find(ccf::http2::headers::PATH);
476 if (url_it != headers.end())
478 url = url_it->second;
482 llhttp_method method = {};
484 const auto method_it = headers.find(ccf::http2::headers::METHOD);
485 if (method_it != headers.end())
487 method = ccf::http_method_from_str(method_it->second.c_str());
512 llhttp_method method,
513 const std::string& route,
515 std::span<const uint8_t> body)
517 std::vector<nghttp2_nv> hdrs;
519 make_nv(ccf::http2::headers::METHOD, llhttp_method_name(method)));
520 hdrs.emplace_back(make_nv(ccf::http2::headers::PATH, route.data()));
521 hdrs.emplace_back(make_nv(
":scheme",
"https"));
522 hdrs.emplace_back(make_nv(
":authority",
"localhost:8080"));
523 for (
auto const& [k, v] : headers)
525 hdrs.emplace_back(make_nv(k.data(), v.data()));
528 auto stream_data = std::make_shared<StreamData>();
529 stream_data->outgoing.body =
DataSource(body);
531 nghttp2_data_provider prov;
532 prov.read_callback = read_outgoing_callback;
536 auto stream_id = nghttp2_submit_request(
537 session,
nullptr, hdrs.data(), hdrs.size(), &prov, stream_data.get());
541 "Could not submit HTTP request: {}", nghttp2_strerror(stream_id));
548 LOG_DEBUG_FMT(
"Successfully sent request with stream id: {}", stream_id);
555 if (stream_data ==
nullptr)
565 const auto status_it = headers.find(ccf::http2::headers::STATUS);
566 if (status_it != headers.end())
Definition http2_types.h:85
Definition http2_parser.h:501
ClientParser(::http::ResponseProcessor &proc_)
Definition http2_parser.h:506
void send_structured_request(llhttp_method method, const std::string &route, const ccf::http::HeaderMap &headers, std::span< const uint8_t > body)
Definition http2_parser.h:511
void handle_completed(StreamId stream_id, StreamData *stream_data) override
Definition http2_parser.h:551
Definition http2_types.h:36
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:115
ccf::http::ParserConfiguration get_configuration() const override
Definition http2_parser.h:120
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
virtual ~Parser()
Definition http2_parser.h:110
void destroy_stream(StreamId stream_id) override
Definition http2_parser.h:162
Parser(const ccf::http::ParserConfiguration &configuration_, bool is_client=false)
Definition http2_parser.h:31
Definition http2_parser.h:240
void send_data(StreamId stream_id, std::span< const uint8_t > data)
Definition http2_parser.h:405
void start_stream(StreamId stream_id, ccf::http_status status, const ccf::http::HeaderMap &headers)
Definition http2_parser.h:376
void set_on_stream_close_callback(StreamId stream_id, StreamCloseCB cb)
Definition http2_parser.h:312
virtual void handle_completed(StreamId stream_id, StreamData *stream_data) override
Definition http2_parser.h:460
ServerParser(http::RequestProcessor &proc_, const ccf::http::ParserConfiguration &configuration_)
Definition http2_parser.h:305
void respond(StreamId stream_id, ccf::http_status status, const ccf::http::HeaderMap &headers, ccf::http::HeaderMap &&trailers, std::span< const uint8_t > body)
Definition http2_parser.h:327
void close_stream(StreamId stream_id, ccf::http::HeaderMap &&trailers)
Definition http2_parser.h:435
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:31
virtual void handle_response(ccf::http_status status, ccf::http::HeaderMap &&headers, std::vector< uint8_t > &&body)=0
#define LOG_TRACE_FMT
Definition logger.h:356
#define LOG_DEBUG_FMT
Definition logger.h:357
#define LOG_FAIL_FMT
Definition logger.h:363
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:21
ccf::http::StreamOnCloseCallback StreamCloseCB
Definition http2_types.h:24
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
std::vector< uint8_t > body
Definition http2_types.h:69
ccf::http::HeaderMap headers
Definition http2_types.h:68
Definition http2_types.h:65
Incoming incoming
Definition http2_types.h:71