blob: ee3a2188075f19c5e6150a2584cab609f6f27497 [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
15#include <boost/algorithm/string/predicate.hpp>
16#include <boost/asio/io_context.hpp>
17#include <boost/asio/ip/tcp.hpp>
18#include <boost/asio/ssl/stream.hpp>
19#include <boost/asio/steady_timer.hpp>
20#include <boost/beast/core/multi_buffer.hpp>
21#include <boost/beast/http/error.hpp>
22#include <boost/beast/http/parser.hpp>
23#include <boost/beast/http/read.hpp>
24#include <boost/beast/http/serializer.hpp>
25#include <boost/beast/http/string_body.hpp>
26#include <boost/beast/http/write.hpp>
27#include <boost/beast/ssl/ssl_stream.hpp>
28#include <boost/beast/websocket.hpp>
29
30#include <atomic>
31#include <chrono>
32#include <vector>
33
34namespace crow
35{
36
37struct Http2StreamData
38{
39 crow::Request req{};
40 crow::Response res{};
41 size_t sentSofar = 0;
42};
43
44template <typename Adaptor, typename Handler>
45class HTTP2Connection :
46 public std::enable_shared_from_this<HTTP2Connection<Adaptor, Handler>>
47{
48 using self_type = HTTP2Connection<Adaptor, Handler>;
49
50 public:
51 HTTP2Connection(Adaptor&& adaptorIn, Handler* handlerIn,
52 std::function<std::string()>& getCachedDateStrF
53
54 ) :
55 adaptor(std::move(adaptorIn)),
56
57 ngSession(initializeNghttp2Session()),
58
59 handler(handlerIn), getCachedDateStr(getCachedDateStrF)
60 {}
61
62 void start()
63 {
64 // Create the control stream
Ed Tanousf42e8592023-08-25 10:47:44 -070065 streams[0];
Ed Tanousfca2cbe2021-01-28 14:49:59 -080066
67 if (sendServerConnectionHeader() != 0)
68 {
Ed Tanous62598e32023-07-17 17:06:25 -070069 BMCWEB_LOG_ERROR("send_server_connection_header failed");
Ed Tanousfca2cbe2021-01-28 14:49:59 -080070 return;
71 }
72 doRead();
73 }
74
75 int sendServerConnectionHeader()
76 {
Ed Tanous62598e32023-07-17 17:06:25 -070077 BMCWEB_LOG_DEBUG("send_server_connection_header()");
Ed Tanousfca2cbe2021-01-28 14:49:59 -080078
79 uint32_t maxStreams = 4;
80 std::array<nghttp2_settings_entry, 2> iv = {
81 {{NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, maxStreams},
82 {NGHTTP2_SETTINGS_ENABLE_PUSH, 0}}};
83 int rv = ngSession.submitSettings(iv);
84 if (rv != 0)
85 {
Ed Tanous62598e32023-07-17 17:06:25 -070086 BMCWEB_LOG_ERROR("Fatal error: {}", nghttp2_strerror(rv));
Ed Tanousfca2cbe2021-01-28 14:49:59 -080087 return -1;
88 }
89 return 0;
90 }
91
92 static ssize_t fileReadCallback(nghttp2_session* /* session */,
Ed Tanousf42e8592023-08-25 10:47:44 -070093 int32_t streamId, uint8_t* buf,
Ed Tanousfca2cbe2021-01-28 14:49:59 -080094 size_t length, uint32_t* dataFlags,
Ed Tanousf42e8592023-08-25 10:47:44 -070095 nghttp2_data_source* /*source*/,
96 void* userPtr)
Ed Tanousfca2cbe2021-01-28 14:49:59 -080097 {
Ed Tanousf42e8592023-08-25 10:47:44 -070098 self_type& self = userPtrToSelf(userPtr);
99
100 auto streamIt = self.streams.find(streamId);
101 if (streamIt == self.streams.end())
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800102 {
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800103 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
104 }
Ed Tanousf42e8592023-08-25 10:47:44 -0700105 Http2StreamData& stream = streamIt->second;
Ed Tanous62598e32023-07-17 17:06:25 -0700106 BMCWEB_LOG_DEBUG("File read callback length: {}", length);
Ed Tanousf42e8592023-08-25 10:47:44 -0700107 crow::Response& res = stream.res;
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800108
Ed Tanous27b0cf92023-08-07 12:02:40 -0700109 Response::string_response* body =
110 boost::variant2::get_if<Response::string_response>(&res.response);
111 Response::file_response* fbody =
112 boost::variant2::get_if<Response::file_response>(&res.response);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800113
Ed Tanous27b0cf92023-08-07 12:02:40 -0700114 size_t size = res.size();
115 BMCWEB_LOG_DEBUG("total: {} send_sofar: {}", size, stream.sentSofar);
116
117 size_t toSend = std::min(size - stream.sentSofar, length);
Ed Tanous62598e32023-07-17 17:06:25 -0700118 BMCWEB_LOG_DEBUG("Copying {} bytes to buf", toSend);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800119
Ed Tanous27b0cf92023-08-07 12:02:40 -0700120 if (body != nullptr)
121 {
122 std::string::const_iterator bodyBegin = body->body().begin();
123 std::advance(bodyBegin, stream.sentSofar);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800124
Ed Tanous27b0cf92023-08-07 12:02:40 -0700125 memcpy(buf, &*bodyBegin, toSend);
126 }
127 else if (fbody != nullptr)
128 {
129 boost::system::error_code ec;
130
131 size_t nread = fbody->body().file().read(buf, toSend, ec);
132 if (ec || nread != toSend)
133 {
134 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
135 }
136 }
137 else
138 {
139 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
140 }
141
Ed Tanousf42e8592023-08-25 10:47:44 -0700142 stream.sentSofar += toSend;
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800143
Ed Tanous27b0cf92023-08-07 12:02:40 -0700144 if (stream.sentSofar >= size)
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800145 {
Ed Tanous62598e32023-07-17 17:06:25 -0700146 BMCWEB_LOG_DEBUG("Setting OEF flag");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800147 *dataFlags |= NGHTTP2_DATA_FLAG_EOF;
148 //*dataFlags |= NGHTTP2_DATA_FLAG_NO_COPY;
149 }
150 return static_cast<ssize_t>(toSend);
151 }
152
153 nghttp2_nv headerFromStringViews(std::string_view name,
154 std::string_view value)
155 {
156 uint8_t* nameData = std::bit_cast<uint8_t*>(name.data());
157 uint8_t* valueData = std::bit_cast<uint8_t*>(value.data());
158 return {nameData, valueData, name.size(), value.size(),
159 NGHTTP2_NV_FLAG_NONE};
160 }
161
162 int sendResponse(Response& completedRes, int32_t streamId)
163 {
Ed Tanous62598e32023-07-17 17:06:25 -0700164 BMCWEB_LOG_DEBUG("send_response stream_id:{}", streamId);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800165
166 auto it = streams.find(streamId);
167 if (it == streams.end())
168 {
169 close();
170 return -1;
171 }
Ed Tanousf42e8592023-08-25 10:47:44 -0700172 Response& thisRes = it->second.res;
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800173 thisRes = std::move(completedRes);
Ed Tanousf42e8592023-08-25 10:47:44 -0700174 crow::Request& thisReq = it->second.req;
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800175 std::vector<nghttp2_nv> hdr;
176
177 completeResponseFields(thisReq, thisRes);
178 thisRes.addHeader(boost::beast::http::field::date, getCachedDateStr());
179
Ed Tanous27b0cf92023-08-07 12:02:40 -0700180 boost::beast::http::fields& fields = thisRes.fields();
181 std::string code = std::to_string(thisRes.resultInt());
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800182 hdr.emplace_back(headerFromStringViews(":status", code));
183 for (const boost::beast::http::fields::value_type& header : fields)
184 {
185 hdr.emplace_back(
186 headerFromStringViews(header.name_string(), header.value()));
187 }
Ed Tanousf42e8592023-08-25 10:47:44 -0700188 Http2StreamData& stream = it->second;
189 stream.sentSofar = 0;
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800190
191 nghttp2_data_provider dataPrd{
Ed Tanousf42e8592023-08-25 10:47:44 -0700192 .source = {.fd = 0},
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800193 .read_callback = fileReadCallback,
194 };
195
196 int rv = ngSession.submitResponse(streamId, hdr, &dataPrd);
197 if (rv != 0)
198 {
Ed Tanous62598e32023-07-17 17:06:25 -0700199 BMCWEB_LOG_ERROR("Fatal error: {}", nghttp2_strerror(rv));
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800200 close();
201 return -1;
202 }
203 ngSession.send();
204
205 return 0;
206 }
207
208 nghttp2_session initializeNghttp2Session()
209 {
210 nghttp2_session_callbacks callbacks;
211 callbacks.setOnFrameRecvCallback(onFrameRecvCallbackStatic);
212 callbacks.setOnStreamCloseCallback(onStreamCloseCallbackStatic);
213 callbacks.setOnHeaderCallback(onHeaderCallbackStatic);
214 callbacks.setOnBeginHeadersCallback(onBeginHeadersCallbackStatic);
215 callbacks.setSendCallback(onSendCallbackStatic);
216
217 nghttp2_session session(callbacks);
218 session.setUserData(this);
219
220 return session;
221 }
222
223 int onRequestRecv(int32_t streamId)
224 {
Ed Tanous62598e32023-07-17 17:06:25 -0700225 BMCWEB_LOG_DEBUG("on_request_recv");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800226
227 auto it = streams.find(streamId);
228 if (it == streams.end())
229 {
230 close();
231 return -1;
232 }
233
Ed Tanousf42e8592023-08-25 10:47:44 -0700234 crow::Request& thisReq = it->second.req;
Ed Tanous62598e32023-07-17 17:06:25 -0700235 BMCWEB_LOG_DEBUG("Handling {} \"{}\"", logPtr(&thisReq),
236 thisReq.url().encoded_path());
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800237
Ed Tanousf42e8592023-08-25 10:47:44 -0700238 crow::Response& thisRes = it->second.res;
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800239
240 thisRes.setCompleteRequestHandler(
241 [this, streamId](Response& completeRes) {
Ed Tanous62598e32023-07-17 17:06:25 -0700242 BMCWEB_LOG_DEBUG("res.completeRequestHandler called");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800243 if (sendResponse(completeRes, streamId) != 0)
244 {
245 close();
246 return;
247 }
248 });
249 auto asyncResp =
Ed Tanousf42e8592023-08-25 10:47:44 -0700250 std::make_shared<bmcweb::AsyncResp>(std::move(it->second.res));
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800251 handler->handle(thisReq, asyncResp);
252
253 return 0;
254 }
255
256 int onFrameRecvCallback(const nghttp2_frame& frame)
257 {
Ed Tanous62598e32023-07-17 17:06:25 -0700258 BMCWEB_LOG_DEBUG("frame type {}", static_cast<int>(frame.hd.type));
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800259 switch (frame.hd.type)
260 {
261 case NGHTTP2_DATA:
262 case NGHTTP2_HEADERS:
263 // Check that the client request has finished
264 if ((frame.hd.flags & NGHTTP2_FLAG_END_STREAM) != 0)
265 {
266 return onRequestRecv(frame.hd.stream_id);
267 }
268 break;
269 default:
270 break;
271 }
272 return 0;
273 }
274
275 static int onFrameRecvCallbackStatic(nghttp2_session* /* session */,
276 const nghttp2_frame* frame,
277 void* userData)
278 {
Ed Tanous62598e32023-07-17 17:06:25 -0700279 BMCWEB_LOG_DEBUG("on_frame_recv_callback");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800280 if (userData == nullptr)
281 {
Ed Tanous62598e32023-07-17 17:06:25 -0700282 BMCWEB_LOG_CRITICAL("user data was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800283 return NGHTTP2_ERR_CALLBACK_FAILURE;
284 }
285 if (frame == nullptr)
286 {
Ed Tanous62598e32023-07-17 17:06:25 -0700287 BMCWEB_LOG_CRITICAL("frame was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800288 return NGHTTP2_ERR_CALLBACK_FAILURE;
289 }
290 return userPtrToSelf(userData).onFrameRecvCallback(*frame);
291 }
292
293 static self_type& userPtrToSelf(void* userData)
294 {
295 // This method exists to keep the unsafe reinterpret cast in one
296 // place.
297 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
298 return *reinterpret_cast<self_type*>(userData);
299 }
300
301 static int onStreamCloseCallbackStatic(nghttp2_session* /* session */,
302 int32_t streamId,
303 uint32_t /*unused*/, void* userData)
304 {
Ed Tanous62598e32023-07-17 17:06:25 -0700305 BMCWEB_LOG_DEBUG("on_stream_close_callback stream {}", streamId);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800306 if (userData == nullptr)
307 {
Ed Tanous62598e32023-07-17 17:06:25 -0700308 BMCWEB_LOG_CRITICAL("user data was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800309 return NGHTTP2_ERR_CALLBACK_FAILURE;
310 }
Ed Tanousf42e8592023-08-25 10:47:44 -0700311 if (userPtrToSelf(userData).streams.erase(streamId) <= 0)
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800312 {
313 return -1;
314 }
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800315 return 0;
316 }
317
318 int onHeaderCallback(const nghttp2_frame& frame,
319 std::span<const uint8_t> name,
320 std::span<const uint8_t> value)
321 {
322 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
323 std::string_view nameSv(reinterpret_cast<const char*>(name.data()),
324 name.size());
325 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
326 std::string_view valueSv(reinterpret_cast<const char*>(value.data()),
327 value.size());
328
Ed Tanous62598e32023-07-17 17:06:25 -0700329 BMCWEB_LOG_DEBUG("on_header_callback name: {} value {}", nameSv,
330 valueSv);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800331
332 switch (frame.hd.type)
333 {
334 case NGHTTP2_HEADERS:
335 if (frame.headers.cat != NGHTTP2_HCAT_REQUEST)
336 {
337 break;
338 }
339 auto thisStream = streams.find(frame.hd.stream_id);
340 if (thisStream == streams.end())
341 {
Ed Tanous62598e32023-07-17 17:06:25 -0700342 BMCWEB_LOG_ERROR("Unknown stream{}", frame.hd.stream_id);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800343 close();
344 return -1;
345 }
346
Ed Tanousf42e8592023-08-25 10:47:44 -0700347 crow::Request& thisReq = thisStream->second.req;
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800348
349 if (nameSv == ":path")
350 {
351 thisReq.target(valueSv);
352 }
353 else if (nameSv == ":method")
354 {
355 boost::beast::http::verb verb =
356 boost::beast::http::string_to_verb(valueSv);
357 if (verb == boost::beast::http::verb::unknown)
358 {
Ed Tanous62598e32023-07-17 17:06:25 -0700359 BMCWEB_LOG_ERROR("Unknown http verb {}", valueSv);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800360 close();
361 return -1;
362 }
363 thisReq.req.method(verb);
364 }
365 else if (nameSv == ":scheme")
366 {
367 // Nothing to check on scheme
368 }
369 else
370 {
371 thisReq.req.set(nameSv, valueSv);
372 }
373 break;
374 }
375 return 0;
376 }
377
378 static int onHeaderCallbackStatic(nghttp2_session* /* session */,
379 const nghttp2_frame* frame,
380 const uint8_t* name, size_t namelen,
381 const uint8_t* value, size_t vallen,
382 uint8_t /* flags */, void* userData)
383 {
384 if (userData == nullptr)
385 {
Ed Tanous62598e32023-07-17 17:06:25 -0700386 BMCWEB_LOG_CRITICAL("user data was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800387 return NGHTTP2_ERR_CALLBACK_FAILURE;
388 }
389 if (frame == nullptr)
390 {
Ed Tanous62598e32023-07-17 17:06:25 -0700391 BMCWEB_LOG_CRITICAL("frame was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800392 return NGHTTP2_ERR_CALLBACK_FAILURE;
393 }
394 if (name == nullptr)
395 {
Ed Tanous62598e32023-07-17 17:06:25 -0700396 BMCWEB_LOG_CRITICAL("name was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800397 return NGHTTP2_ERR_CALLBACK_FAILURE;
398 }
399 if (value == nullptr)
400 {
Ed Tanous62598e32023-07-17 17:06:25 -0700401 BMCWEB_LOG_CRITICAL("value was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800402 return NGHTTP2_ERR_CALLBACK_FAILURE;
403 }
404 return userPtrToSelf(userData).onHeaderCallback(*frame, {name, namelen},
405 {value, vallen});
406 }
407
408 int onBeginHeadersCallback(const nghttp2_frame& frame)
409 {
410 if (frame.hd.type == NGHTTP2_HEADERS &&
411 frame.headers.cat == NGHTTP2_HCAT_REQUEST)
412 {
Ed Tanous62598e32023-07-17 17:06:25 -0700413 BMCWEB_LOG_DEBUG("create stream for id {}", frame.hd.stream_id);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800414
Ed Tanousf42e8592023-08-25 10:47:44 -0700415 Http2StreamData& stream = streams[frame.hd.stream_id];
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800416 // http2 is by definition always tls
Ed Tanousf42e8592023-08-25 10:47:44 -0700417 stream.req.isSecure = true;
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800418 }
419 return 0;
420 }
421
422 static int onBeginHeadersCallbackStatic(nghttp2_session* /* session */,
423 const nghttp2_frame* frame,
424 void* userData)
425 {
Ed Tanous62598e32023-07-17 17:06:25 -0700426 BMCWEB_LOG_DEBUG("on_begin_headers_callback");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800427 if (userData == nullptr)
428 {
Ed Tanous62598e32023-07-17 17:06:25 -0700429 BMCWEB_LOG_CRITICAL("user data was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800430 return NGHTTP2_ERR_CALLBACK_FAILURE;
431 }
432 if (frame == nullptr)
433 {
Ed Tanous62598e32023-07-17 17:06:25 -0700434 BMCWEB_LOG_CRITICAL("frame was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800435 return NGHTTP2_ERR_CALLBACK_FAILURE;
436 }
437 return userPtrToSelf(userData).onBeginHeadersCallback(*frame);
438 }
439
440 static void afterWriteBuffer(const std::shared_ptr<self_type>& self,
441 const boost::system::error_code& ec,
442 size_t sendLength)
443 {
444 self->isWriting = false;
Ed Tanous62598e32023-07-17 17:06:25 -0700445 BMCWEB_LOG_DEBUG("Sent {}", sendLength);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800446 if (ec)
447 {
448 self->close();
449 return;
450 }
451 self->sendBuffer.consume(sendLength);
452 self->writeBuffer();
453 }
454
455 void writeBuffer()
456 {
457 if (isWriting)
458 {
459 return;
460 }
461 if (sendBuffer.size() <= 0)
462 {
463 return;
464 }
465 isWriting = true;
466 adaptor.async_write_some(
467 sendBuffer.data(),
468 std::bind_front(afterWriteBuffer, shared_from_this()));
469 }
470
471 ssize_t onSendCallback(nghttp2_session* /*session */, const uint8_t* data,
472 size_t length, int /* flags */)
473 {
Ed Tanous62598e32023-07-17 17:06:25 -0700474 BMCWEB_LOG_DEBUG("On send callback size={}", length);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800475 size_t copied = boost::asio::buffer_copy(
476 sendBuffer.prepare(length), boost::asio::buffer(data, length));
477 sendBuffer.commit(copied);
478 writeBuffer();
479 return static_cast<ssize_t>(length);
480 }
481
482 static ssize_t onSendCallbackStatic(nghttp2_session* session,
483 const uint8_t* data, size_t length,
484 int flags /* flags */, void* userData)
485 {
486 return userPtrToSelf(userData).onSendCallback(session, data, length,
487 flags);
488 }
489
490 void close()
491 {
492 if constexpr (std::is_same_v<Adaptor,
493 boost::beast::ssl_stream<
494 boost::asio::ip::tcp::socket>>)
495 {
496 adaptor.next_layer().close();
497 }
498 else
499 {
500 adaptor.close();
501 }
502 }
503
504 void doRead()
505 {
Ed Tanous62598e32023-07-17 17:06:25 -0700506 BMCWEB_LOG_DEBUG("{} doRead", logPtr(this));
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800507 adaptor.async_read_some(
508 inBuffer.prepare(8192),
509 [this, self(shared_from_this())](
510 const boost::system::error_code& ec, size_t bytesTransferred) {
Ed Tanous62598e32023-07-17 17:06:25 -0700511 BMCWEB_LOG_DEBUG("{} async_read_some {} Bytes", logPtr(this),
512 bytesTransferred);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800513
514 if (ec)
515 {
Ed Tanous62598e32023-07-17 17:06:25 -0700516 BMCWEB_LOG_ERROR("{} Error while reading: {}", logPtr(this),
517 ec.message());
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800518 close();
Ed Tanous62598e32023-07-17 17:06:25 -0700519 BMCWEB_LOG_DEBUG("{} from read(1)", logPtr(this));
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800520 return;
521 }
522 inBuffer.commit(bytesTransferred);
523
524 size_t consumed = 0;
525 for (const auto bufferIt : inBuffer.data())
526 {
527 std::span<const uint8_t> bufferSpan{
528 std::bit_cast<const uint8_t*>(bufferIt.data()),
529 bufferIt.size()};
Ed Tanous62598e32023-07-17 17:06:25 -0700530 BMCWEB_LOG_DEBUG("http2 is getting {} bytes",
531 bufferSpan.size());
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800532 ssize_t readLen = ngSession.memRecv(bufferSpan);
533 if (readLen <= 0)
534 {
Ed Tanous62598e32023-07-17 17:06:25 -0700535 BMCWEB_LOG_ERROR("nghttp2_session_mem_recv returned {}",
536 readLen);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800537 close();
538 return;
539 }
540 consumed += static_cast<size_t>(readLen);
541 }
542 inBuffer.consume(consumed);
543
544 doRead();
Patrick Williams5a39f772023-10-20 11:20:21 -0500545 });
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800546 }
547
548 // A mapping from http2 stream ID to Stream Data
Ed Tanousf42e8592023-08-25 10:47:44 -0700549 boost::container::flat_map<int32_t, Http2StreamData> streams;
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800550
551 boost::beast::multi_buffer sendBuffer;
552 boost::beast::multi_buffer inBuffer;
553
554 Adaptor adaptor;
555 bool isWriting = false;
556
557 nghttp2_session ngSession;
558
559 Handler* handler;
560 std::function<std::string()>& getCachedDateStr;
561
562 using std::enable_shared_from_this<
563 HTTP2Connection<Adaptor, Handler>>::shared_from_this;
564
565 using std::enable_shared_from_this<
566 HTTP2Connection<Adaptor, Handler>>::weak_from_this;
567};
568} // namespace crow