blob: 95d184e67b6e9addf284b9815d91027f049f4bc6 [file] [log] [blame]
Ed Tanousfca2cbe2021-01-28 14:49:59 -08001#pragma once
2#include "bmcweb_config.h"
3
4#include "async_resp.hpp"
5#include "authentication.hpp"
6#include "complete_response_fields.hpp"
7#include "http_response.hpp"
8#include "http_utility.hpp"
9#include "logging.hpp"
10#include "mutual_tls.hpp"
11#include "nghttp2_adapters.hpp"
12#include "ssl_key_handler.hpp"
13#include "utility.hpp"
14
Ed Tanousfca2cbe2021-01-28 14:49:59 -080015#include <boost/asio/io_context.hpp>
16#include <boost/asio/ip/tcp.hpp>
17#include <boost/asio/ssl/stream.hpp>
18#include <boost/asio/steady_timer.hpp>
19#include <boost/beast/core/multi_buffer.hpp>
20#include <boost/beast/http/error.hpp>
21#include <boost/beast/http/parser.hpp>
22#include <boost/beast/http/read.hpp>
23#include <boost/beast/http/serializer.hpp>
24#include <boost/beast/http/string_body.hpp>
25#include <boost/beast/http/write.hpp>
26#include <boost/beast/ssl/ssl_stream.hpp>
27#include <boost/beast/websocket.hpp>
28
29#include <atomic>
30#include <chrono>
31#include <vector>
32
33namespace crow
34{
35
36struct Http2StreamData
37{
38 crow::Request req{};
39 crow::Response res{};
40 size_t sentSofar = 0;
41};
42
43template <typename Adaptor, typename Handler>
44class HTTP2Connection :
45 public std::enable_shared_from_this<HTTP2Connection<Adaptor, Handler>>
46{
47 using self_type = HTTP2Connection<Adaptor, Handler>;
48
49 public:
50 HTTP2Connection(Adaptor&& adaptorIn, Handler* handlerIn,
51 std::function<std::string()>& getCachedDateStrF
52
53 ) :
54 adaptor(std::move(adaptorIn)),
55
56 ngSession(initializeNghttp2Session()),
57
58 handler(handlerIn), getCachedDateStr(getCachedDateStrF)
59 {}
60
61 void start()
62 {
63 // Create the control stream
Ed Tanousf42e8592023-08-25 10:47:44 -070064 streams[0];
Ed Tanousfca2cbe2021-01-28 14:49:59 -080065
66 if (sendServerConnectionHeader() != 0)
67 {
Ed Tanous62598e32023-07-17 17:06:25 -070068 BMCWEB_LOG_ERROR("send_server_connection_header failed");
Ed Tanousfca2cbe2021-01-28 14:49:59 -080069 return;
70 }
71 doRead();
72 }
73
74 int sendServerConnectionHeader()
75 {
Ed Tanous62598e32023-07-17 17:06:25 -070076 BMCWEB_LOG_DEBUG("send_server_connection_header()");
Ed Tanousfca2cbe2021-01-28 14:49:59 -080077
78 uint32_t maxStreams = 4;
79 std::array<nghttp2_settings_entry, 2> iv = {
80 {{NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, maxStreams},
81 {NGHTTP2_SETTINGS_ENABLE_PUSH, 0}}};
82 int rv = ngSession.submitSettings(iv);
83 if (rv != 0)
84 {
Ed Tanous62598e32023-07-17 17:06:25 -070085 BMCWEB_LOG_ERROR("Fatal error: {}", nghttp2_strerror(rv));
Ed Tanousfca2cbe2021-01-28 14:49:59 -080086 return -1;
87 }
88 return 0;
89 }
90
91 static ssize_t fileReadCallback(nghttp2_session* /* session */,
Ed Tanousf42e8592023-08-25 10:47:44 -070092 int32_t streamId, uint8_t* buf,
Ed Tanousfca2cbe2021-01-28 14:49:59 -080093 size_t length, uint32_t* dataFlags,
Ed Tanousf42e8592023-08-25 10:47:44 -070094 nghttp2_data_source* /*source*/,
95 void* userPtr)
Ed Tanousfca2cbe2021-01-28 14:49:59 -080096 {
Ed Tanousf42e8592023-08-25 10:47:44 -070097 self_type& self = userPtrToSelf(userPtr);
98
99 auto streamIt = self.streams.find(streamId);
100 if (streamIt == self.streams.end())
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800101 {
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800102 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
103 }
Ed Tanousf42e8592023-08-25 10:47:44 -0700104 Http2StreamData& stream = streamIt->second;
Ed Tanous62598e32023-07-17 17:06:25 -0700105 BMCWEB_LOG_DEBUG("File read callback length: {}", length);
Ed Tanousf42e8592023-08-25 10:47:44 -0700106 crow::Response& res = stream.res;
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800107
Ed Tanous27b0cf92023-08-07 12:02:40 -0700108 Response::string_response* body =
109 boost::variant2::get_if<Response::string_response>(&res.response);
110 Response::file_response* fbody =
111 boost::variant2::get_if<Response::file_response>(&res.response);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800112
Ed Tanous27b0cf92023-08-07 12:02:40 -0700113 size_t size = res.size();
114 BMCWEB_LOG_DEBUG("total: {} send_sofar: {}", size, stream.sentSofar);
115
116 size_t toSend = std::min(size - stream.sentSofar, length);
Ed Tanous62598e32023-07-17 17:06:25 -0700117 BMCWEB_LOG_DEBUG("Copying {} bytes to buf", toSend);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800118
Ed Tanous27b0cf92023-08-07 12:02:40 -0700119 if (body != nullptr)
120 {
121 std::string::const_iterator bodyBegin = body->body().begin();
122 std::advance(bodyBegin, stream.sentSofar);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800123
Ed Tanous27b0cf92023-08-07 12:02:40 -0700124 memcpy(buf, &*bodyBegin, toSend);
125 }
126 else if (fbody != nullptr)
127 {
128 boost::system::error_code ec;
129
130 size_t nread = fbody->body().file().read(buf, toSend, ec);
131 if (ec || nread != toSend)
132 {
133 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
134 }
135 }
136 else
137 {
138 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
139 }
140
Ed Tanousf42e8592023-08-25 10:47:44 -0700141 stream.sentSofar += toSend;
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800142
Ed Tanous27b0cf92023-08-07 12:02:40 -0700143 if (stream.sentSofar >= size)
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800144 {
Ed Tanous62598e32023-07-17 17:06:25 -0700145 BMCWEB_LOG_DEBUG("Setting OEF flag");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800146 *dataFlags |= NGHTTP2_DATA_FLAG_EOF;
147 //*dataFlags |= NGHTTP2_DATA_FLAG_NO_COPY;
148 }
149 return static_cast<ssize_t>(toSend);
150 }
151
152 nghttp2_nv headerFromStringViews(std::string_view name,
153 std::string_view value)
154 {
155 uint8_t* nameData = std::bit_cast<uint8_t*>(name.data());
156 uint8_t* valueData = std::bit_cast<uint8_t*>(value.data());
157 return {nameData, valueData, name.size(), value.size(),
158 NGHTTP2_NV_FLAG_NONE};
159 }
160
161 int sendResponse(Response& completedRes, int32_t streamId)
162 {
Ed Tanous62598e32023-07-17 17:06:25 -0700163 BMCWEB_LOG_DEBUG("send_response stream_id:{}", streamId);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800164
165 auto it = streams.find(streamId);
166 if (it == streams.end())
167 {
168 close();
169 return -1;
170 }
Ed Tanousf42e8592023-08-25 10:47:44 -0700171 Response& thisRes = it->second.res;
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800172 thisRes = std::move(completedRes);
Ed Tanousf42e8592023-08-25 10:47:44 -0700173 crow::Request& thisReq = it->second.req;
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800174 std::vector<nghttp2_nv> hdr;
175
176 completeResponseFields(thisReq, thisRes);
177 thisRes.addHeader(boost::beast::http::field::date, getCachedDateStr());
178
Ed Tanous27b0cf92023-08-07 12:02:40 -0700179 boost::beast::http::fields& fields = thisRes.fields();
180 std::string code = std::to_string(thisRes.resultInt());
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800181 hdr.emplace_back(headerFromStringViews(":status", code));
182 for (const boost::beast::http::fields::value_type& header : fields)
183 {
184 hdr.emplace_back(
185 headerFromStringViews(header.name_string(), header.value()));
186 }
Ed Tanousf42e8592023-08-25 10:47:44 -0700187 Http2StreamData& stream = it->second;
188 stream.sentSofar = 0;
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800189
190 nghttp2_data_provider dataPrd{
Ed Tanousf42e8592023-08-25 10:47:44 -0700191 .source = {.fd = 0},
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800192 .read_callback = fileReadCallback,
193 };
194
195 int rv = ngSession.submitResponse(streamId, hdr, &dataPrd);
196 if (rv != 0)
197 {
Ed Tanous62598e32023-07-17 17:06:25 -0700198 BMCWEB_LOG_ERROR("Fatal error: {}", nghttp2_strerror(rv));
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800199 close();
200 return -1;
201 }
202 ngSession.send();
203
204 return 0;
205 }
206
207 nghttp2_session initializeNghttp2Session()
208 {
209 nghttp2_session_callbacks callbacks;
210 callbacks.setOnFrameRecvCallback(onFrameRecvCallbackStatic);
211 callbacks.setOnStreamCloseCallback(onStreamCloseCallbackStatic);
212 callbacks.setOnHeaderCallback(onHeaderCallbackStatic);
213 callbacks.setOnBeginHeadersCallback(onBeginHeadersCallbackStatic);
214 callbacks.setSendCallback(onSendCallbackStatic);
215
216 nghttp2_session session(callbacks);
217 session.setUserData(this);
218
219 return session;
220 }
221
222 int onRequestRecv(int32_t streamId)
223 {
Ed Tanous62598e32023-07-17 17:06:25 -0700224 BMCWEB_LOG_DEBUG("on_request_recv");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800225
226 auto it = streams.find(streamId);
227 if (it == streams.end())
228 {
229 close();
230 return -1;
231 }
232
Ed Tanousf42e8592023-08-25 10:47:44 -0700233 crow::Request& thisReq = it->second.req;
Ed Tanous62598e32023-07-17 17:06:25 -0700234 BMCWEB_LOG_DEBUG("Handling {} \"{}\"", logPtr(&thisReq),
235 thisReq.url().encoded_path());
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800236
Ed Tanousf42e8592023-08-25 10:47:44 -0700237 crow::Response& thisRes = it->second.res;
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800238
239 thisRes.setCompleteRequestHandler(
240 [this, streamId](Response& completeRes) {
Ed Tanous62598e32023-07-17 17:06:25 -0700241 BMCWEB_LOG_DEBUG("res.completeRequestHandler called");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800242 if (sendResponse(completeRes, streamId) != 0)
243 {
244 close();
245 return;
246 }
247 });
248 auto asyncResp =
Ed Tanousf42e8592023-08-25 10:47:44 -0700249 std::make_shared<bmcweb::AsyncResp>(std::move(it->second.res));
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800250 handler->handle(thisReq, asyncResp);
251
252 return 0;
253 }
254
255 int onFrameRecvCallback(const nghttp2_frame& frame)
256 {
Ed Tanous62598e32023-07-17 17:06:25 -0700257 BMCWEB_LOG_DEBUG("frame type {}", static_cast<int>(frame.hd.type));
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800258 switch (frame.hd.type)
259 {
260 case NGHTTP2_DATA:
261 case NGHTTP2_HEADERS:
262 // Check that the client request has finished
263 if ((frame.hd.flags & NGHTTP2_FLAG_END_STREAM) != 0)
264 {
265 return onRequestRecv(frame.hd.stream_id);
266 }
267 break;
268 default:
269 break;
270 }
271 return 0;
272 }
273
274 static int onFrameRecvCallbackStatic(nghttp2_session* /* session */,
275 const nghttp2_frame* frame,
276 void* userData)
277 {
Ed Tanous62598e32023-07-17 17:06:25 -0700278 BMCWEB_LOG_DEBUG("on_frame_recv_callback");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800279 if (userData == nullptr)
280 {
Ed Tanous62598e32023-07-17 17:06:25 -0700281 BMCWEB_LOG_CRITICAL("user data was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800282 return NGHTTP2_ERR_CALLBACK_FAILURE;
283 }
284 if (frame == nullptr)
285 {
Ed Tanous62598e32023-07-17 17:06:25 -0700286 BMCWEB_LOG_CRITICAL("frame was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800287 return NGHTTP2_ERR_CALLBACK_FAILURE;
288 }
289 return userPtrToSelf(userData).onFrameRecvCallback(*frame);
290 }
291
292 static self_type& userPtrToSelf(void* userData)
293 {
294 // This method exists to keep the unsafe reinterpret cast in one
295 // place.
296 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
297 return *reinterpret_cast<self_type*>(userData);
298 }
299
300 static int onStreamCloseCallbackStatic(nghttp2_session* /* session */,
301 int32_t streamId,
302 uint32_t /*unused*/, void* userData)
303 {
Ed Tanous62598e32023-07-17 17:06:25 -0700304 BMCWEB_LOG_DEBUG("on_stream_close_callback stream {}", streamId);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800305 if (userData == nullptr)
306 {
Ed Tanous62598e32023-07-17 17:06:25 -0700307 BMCWEB_LOG_CRITICAL("user data was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800308 return NGHTTP2_ERR_CALLBACK_FAILURE;
309 }
Ed Tanousf42e8592023-08-25 10:47:44 -0700310 if (userPtrToSelf(userData).streams.erase(streamId) <= 0)
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800311 {
312 return -1;
313 }
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800314 return 0;
315 }
316
317 int onHeaderCallback(const nghttp2_frame& frame,
318 std::span<const uint8_t> name,
319 std::span<const uint8_t> value)
320 {
321 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
322 std::string_view nameSv(reinterpret_cast<const char*>(name.data()),
323 name.size());
324 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
325 std::string_view valueSv(reinterpret_cast<const char*>(value.data()),
326 value.size());
327
Ed Tanous62598e32023-07-17 17:06:25 -0700328 BMCWEB_LOG_DEBUG("on_header_callback name: {} value {}", nameSv,
329 valueSv);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800330
331 switch (frame.hd.type)
332 {
333 case NGHTTP2_HEADERS:
334 if (frame.headers.cat != NGHTTP2_HCAT_REQUEST)
335 {
336 break;
337 }
338 auto thisStream = streams.find(frame.hd.stream_id);
339 if (thisStream == streams.end())
340 {
Ed Tanous62598e32023-07-17 17:06:25 -0700341 BMCWEB_LOG_ERROR("Unknown stream{}", frame.hd.stream_id);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800342 close();
343 return -1;
344 }
345
Ed Tanousf42e8592023-08-25 10:47:44 -0700346 crow::Request& thisReq = thisStream->second.req;
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800347
348 if (nameSv == ":path")
349 {
350 thisReq.target(valueSv);
351 }
352 else if (nameSv == ":method")
353 {
354 boost::beast::http::verb verb =
355 boost::beast::http::string_to_verb(valueSv);
356 if (verb == boost::beast::http::verb::unknown)
357 {
Ed Tanous62598e32023-07-17 17:06:25 -0700358 BMCWEB_LOG_ERROR("Unknown http verb {}", valueSv);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800359 close();
360 return -1;
361 }
362 thisReq.req.method(verb);
363 }
364 else if (nameSv == ":scheme")
365 {
366 // Nothing to check on scheme
367 }
368 else
369 {
370 thisReq.req.set(nameSv, valueSv);
371 }
372 break;
373 }
374 return 0;
375 }
376
377 static int onHeaderCallbackStatic(nghttp2_session* /* session */,
378 const nghttp2_frame* frame,
379 const uint8_t* name, size_t namelen,
380 const uint8_t* value, size_t vallen,
381 uint8_t /* flags */, void* userData)
382 {
383 if (userData == nullptr)
384 {
Ed Tanous62598e32023-07-17 17:06:25 -0700385 BMCWEB_LOG_CRITICAL("user data was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800386 return NGHTTP2_ERR_CALLBACK_FAILURE;
387 }
388 if (frame == nullptr)
389 {
Ed Tanous62598e32023-07-17 17:06:25 -0700390 BMCWEB_LOG_CRITICAL("frame was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800391 return NGHTTP2_ERR_CALLBACK_FAILURE;
392 }
393 if (name == nullptr)
394 {
Ed Tanous62598e32023-07-17 17:06:25 -0700395 BMCWEB_LOG_CRITICAL("name was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800396 return NGHTTP2_ERR_CALLBACK_FAILURE;
397 }
398 if (value == nullptr)
399 {
Ed Tanous62598e32023-07-17 17:06:25 -0700400 BMCWEB_LOG_CRITICAL("value was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800401 return NGHTTP2_ERR_CALLBACK_FAILURE;
402 }
403 return userPtrToSelf(userData).onHeaderCallback(*frame, {name, namelen},
404 {value, vallen});
405 }
406
407 int onBeginHeadersCallback(const nghttp2_frame& frame)
408 {
409 if (frame.hd.type == NGHTTP2_HEADERS &&
410 frame.headers.cat == NGHTTP2_HCAT_REQUEST)
411 {
Ed Tanous62598e32023-07-17 17:06:25 -0700412 BMCWEB_LOG_DEBUG("create stream for id {}", frame.hd.stream_id);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800413
Ed Tanousf42e8592023-08-25 10:47:44 -0700414 Http2StreamData& stream = streams[frame.hd.stream_id];
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800415 // http2 is by definition always tls
Ed Tanousf42e8592023-08-25 10:47:44 -0700416 stream.req.isSecure = true;
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800417 }
418 return 0;
419 }
420
421 static int onBeginHeadersCallbackStatic(nghttp2_session* /* session */,
422 const nghttp2_frame* frame,
423 void* userData)
424 {
Ed Tanous62598e32023-07-17 17:06:25 -0700425 BMCWEB_LOG_DEBUG("on_begin_headers_callback");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800426 if (userData == nullptr)
427 {
Ed Tanous62598e32023-07-17 17:06:25 -0700428 BMCWEB_LOG_CRITICAL("user data was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800429 return NGHTTP2_ERR_CALLBACK_FAILURE;
430 }
431 if (frame == nullptr)
432 {
Ed Tanous62598e32023-07-17 17:06:25 -0700433 BMCWEB_LOG_CRITICAL("frame was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800434 return NGHTTP2_ERR_CALLBACK_FAILURE;
435 }
436 return userPtrToSelf(userData).onBeginHeadersCallback(*frame);
437 }
438
439 static void afterWriteBuffer(const std::shared_ptr<self_type>& self,
440 const boost::system::error_code& ec,
441 size_t sendLength)
442 {
443 self->isWriting = false;
Ed Tanous62598e32023-07-17 17:06:25 -0700444 BMCWEB_LOG_DEBUG("Sent {}", sendLength);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800445 if (ec)
446 {
447 self->close();
448 return;
449 }
450 self->sendBuffer.consume(sendLength);
451 self->writeBuffer();
452 }
453
454 void writeBuffer()
455 {
456 if (isWriting)
457 {
458 return;
459 }
460 if (sendBuffer.size() <= 0)
461 {
462 return;
463 }
464 isWriting = true;
465 adaptor.async_write_some(
466 sendBuffer.data(),
467 std::bind_front(afterWriteBuffer, shared_from_this()));
468 }
469
470 ssize_t onSendCallback(nghttp2_session* /*session */, const uint8_t* data,
471 size_t length, int /* flags */)
472 {
Ed Tanous62598e32023-07-17 17:06:25 -0700473 BMCWEB_LOG_DEBUG("On send callback size={}", length);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800474 size_t copied = boost::asio::buffer_copy(
475 sendBuffer.prepare(length), boost::asio::buffer(data, length));
476 sendBuffer.commit(copied);
477 writeBuffer();
478 return static_cast<ssize_t>(length);
479 }
480
481 static ssize_t onSendCallbackStatic(nghttp2_session* session,
482 const uint8_t* data, size_t length,
483 int flags /* flags */, void* userData)
484 {
485 return userPtrToSelf(userData).onSendCallback(session, data, length,
486 flags);
487 }
488
489 void close()
490 {
491 if constexpr (std::is_same_v<Adaptor,
492 boost::beast::ssl_stream<
493 boost::asio::ip::tcp::socket>>)
494 {
495 adaptor.next_layer().close();
496 }
497 else
498 {
499 adaptor.close();
500 }
501 }
502
503 void doRead()
504 {
Ed Tanous62598e32023-07-17 17:06:25 -0700505 BMCWEB_LOG_DEBUG("{} doRead", logPtr(this));
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800506 adaptor.async_read_some(
507 inBuffer.prepare(8192),
508 [this, self(shared_from_this())](
509 const boost::system::error_code& ec, size_t bytesTransferred) {
Ed Tanous62598e32023-07-17 17:06:25 -0700510 BMCWEB_LOG_DEBUG("{} async_read_some {} Bytes", logPtr(this),
511 bytesTransferred);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800512
513 if (ec)
514 {
Ed Tanous62598e32023-07-17 17:06:25 -0700515 BMCWEB_LOG_ERROR("{} Error while reading: {}", logPtr(this),
516 ec.message());
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800517 close();
Ed Tanous62598e32023-07-17 17:06:25 -0700518 BMCWEB_LOG_DEBUG("{} from read(1)", logPtr(this));
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800519 return;
520 }
521 inBuffer.commit(bytesTransferred);
522
523 size_t consumed = 0;
524 for (const auto bufferIt : inBuffer.data())
525 {
526 std::span<const uint8_t> bufferSpan{
527 std::bit_cast<const uint8_t*>(bufferIt.data()),
528 bufferIt.size()};
Ed Tanous62598e32023-07-17 17:06:25 -0700529 BMCWEB_LOG_DEBUG("http2 is getting {} bytes",
530 bufferSpan.size());
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800531 ssize_t readLen = ngSession.memRecv(bufferSpan);
532 if (readLen <= 0)
533 {
Ed Tanous62598e32023-07-17 17:06:25 -0700534 BMCWEB_LOG_ERROR("nghttp2_session_mem_recv returned {}",
535 readLen);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800536 close();
537 return;
538 }
539 consumed += static_cast<size_t>(readLen);
540 }
541 inBuffer.consume(consumed);
542
543 doRead();
Patrick Williams5a39f772023-10-20 11:20:21 -0500544 });
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800545 }
546
547 // A mapping from http2 stream ID to Stream Data
Ed Tanousf42e8592023-08-25 10:47:44 -0700548 boost::container::flat_map<int32_t, Http2StreamData> streams;
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800549
550 boost::beast::multi_buffer sendBuffer;
551 boost::beast::multi_buffer inBuffer;
552
553 Adaptor adaptor;
554 bool isWriting = false;
555
556 nghttp2_session ngSession;
557
558 Handler* handler;
559 std::function<std::string()>& getCachedDateStr;
560
561 using std::enable_shared_from_this<
562 HTTP2Connection<Adaptor, Handler>>::shared_from_this;
563
564 using std::enable_shared_from_this<
565 HTTP2Connection<Adaptor, Handler>>::weak_from_this;
566};
567} // namespace crow