blob: a9e91d7a977c1c872334bb32e856a34c99ca8a3b [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>
Ed Tanousfca2cbe2021-01-28 14:49:59 -080024#include <boost/beast/http/write.hpp>
25#include <boost/beast/ssl/ssl_stream.hpp>
26#include <boost/beast/websocket.hpp>
27
28#include <atomic>
29#include <chrono>
30#include <vector>
31
32namespace crow
33{
34
35struct Http2StreamData
36{
Ed Tanous52e31622024-01-23 16:31:11 -080037 Request req{};
38 Response res{};
39 std::optional<bmcweb::FileBody::writer> writer;
Ed Tanousfca2cbe2021-01-28 14:49:59 -080040};
41
42template <typename Adaptor, typename Handler>
43class HTTP2Connection :
44 public std::enable_shared_from_this<HTTP2Connection<Adaptor, Handler>>
45{
46 using self_type = HTTP2Connection<Adaptor, Handler>;
47
48 public:
49 HTTP2Connection(Adaptor&& adaptorIn, Handler* handlerIn,
Ed Tanous52e31622024-01-23 16:31:11 -080050 std::function<std::string()>& getCachedDateStrF) :
Ed Tanousfca2cbe2021-01-28 14:49:59 -080051 adaptor(std::move(adaptorIn)),
Ed Tanous52e31622024-01-23 16:31:11 -080052 ngSession(initializeNghttp2Session()), handler(handlerIn),
53 getCachedDateStr(getCachedDateStrF)
Ed Tanousfca2cbe2021-01-28 14:49:59 -080054 {}
55
56 void start()
57 {
58 // Create the control stream
Ed Tanousf42e8592023-08-25 10:47:44 -070059 streams[0];
Ed Tanousfca2cbe2021-01-28 14:49:59 -080060
61 if (sendServerConnectionHeader() != 0)
62 {
Ed Tanous62598e32023-07-17 17:06:25 -070063 BMCWEB_LOG_ERROR("send_server_connection_header failed");
Ed Tanousfca2cbe2021-01-28 14:49:59 -080064 return;
65 }
66 doRead();
67 }
68
69 int sendServerConnectionHeader()
70 {
Ed Tanous62598e32023-07-17 17:06:25 -070071 BMCWEB_LOG_DEBUG("send_server_connection_header()");
Ed Tanousfca2cbe2021-01-28 14:49:59 -080072
73 uint32_t maxStreams = 4;
74 std::array<nghttp2_settings_entry, 2> iv = {
75 {{NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, maxStreams},
76 {NGHTTP2_SETTINGS_ENABLE_PUSH, 0}}};
77 int rv = ngSession.submitSettings(iv);
78 if (rv != 0)
79 {
Ed Tanous62598e32023-07-17 17:06:25 -070080 BMCWEB_LOG_ERROR("Fatal error: {}", nghttp2_strerror(rv));
Ed Tanousfca2cbe2021-01-28 14:49:59 -080081 return -1;
82 }
83 return 0;
84 }
85
86 static ssize_t fileReadCallback(nghttp2_session* /* session */,
Ed Tanousf42e8592023-08-25 10:47:44 -070087 int32_t streamId, uint8_t* buf,
Ed Tanousfca2cbe2021-01-28 14:49:59 -080088 size_t length, uint32_t* dataFlags,
Ed Tanousf42e8592023-08-25 10:47:44 -070089 nghttp2_data_source* /*source*/,
90 void* userPtr)
Ed Tanousfca2cbe2021-01-28 14:49:59 -080091 {
Ed Tanousf42e8592023-08-25 10:47:44 -070092 self_type& self = userPtrToSelf(userPtr);
93
94 auto streamIt = self.streams.find(streamId);
95 if (streamIt == self.streams.end())
Ed Tanousfca2cbe2021-01-28 14:49:59 -080096 {
Ed Tanousfca2cbe2021-01-28 14:49:59 -080097 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
98 }
Ed Tanousf42e8592023-08-25 10:47:44 -070099 Http2StreamData& stream = streamIt->second;
Ed Tanous62598e32023-07-17 17:06:25 -0700100 BMCWEB_LOG_DEBUG("File read callback length: {}", length);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800101
Ed Tanous52e31622024-01-23 16:31:11 -0800102 boost::beast::error_code ec;
103 boost::optional<std::pair<boost::asio::const_buffer, bool>> out =
104 stream.writer->getWithMaxSize(ec, length);
105 if (ec)
Ed Tanous27b0cf92023-08-07 12:02:40 -0700106 {
107 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
108 }
109
Ed Tanous52e31622024-01-23 16:31:11 -0800110 if (!out)
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800111 {
Ed Tanous52e31622024-01-23 16:31:11 -0800112 *dataFlags |= NGHTTP2_DATA_FLAG_EOF;
113 return 0;
114 }
115
116 BMCWEB_LOG_DEBUG("Send chunk of size: {}", out->first.size());
117 if (length < out->first.size())
118 {
119 // Should never happen because of length limit on get() above
120 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
121 }
122
123 BMCWEB_LOG_DEBUG("Copying {} bytes to buf", out->first.size());
124 memcpy(buf, out->first.data(), out->first.size());
125
126 if (!out->second)
127 {
128 BMCWEB_LOG_DEBUG("Setting OEF and nocopy flag");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800129 *dataFlags |= NGHTTP2_DATA_FLAG_EOF;
130 //*dataFlags |= NGHTTP2_DATA_FLAG_NO_COPY;
131 }
Ed Tanous52e31622024-01-23 16:31:11 -0800132 return static_cast<ssize_t>(out->first.size());
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800133 }
134
135 nghttp2_nv headerFromStringViews(std::string_view name,
Ed Tanous52e31622024-01-23 16:31:11 -0800136 std::string_view value, uint8_t flags)
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800137 {
138 uint8_t* nameData = std::bit_cast<uint8_t*>(name.data());
139 uint8_t* valueData = std::bit_cast<uint8_t*>(value.data());
Ed Tanous52e31622024-01-23 16:31:11 -0800140 return {nameData, valueData, name.size(), value.size(), flags};
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800141 }
142
143 int sendResponse(Response& completedRes, int32_t streamId)
144 {
Ed Tanous62598e32023-07-17 17:06:25 -0700145 BMCWEB_LOG_DEBUG("send_response stream_id:{}", streamId);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800146
147 auto it = streams.find(streamId);
148 if (it == streams.end())
149 {
150 close();
151 return -1;
152 }
Ed Tanousf42e8592023-08-25 10:47:44 -0700153 Response& thisRes = it->second.res;
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800154 thisRes = std::move(completedRes);
Ed Tanousf42e8592023-08-25 10:47:44 -0700155 crow::Request& thisReq = it->second.req;
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800156 std::vector<nghttp2_nv> hdr;
157
158 completeResponseFields(thisReq, thisRes);
159 thisRes.addHeader(boost::beast::http::field::date, getCachedDateStr());
160
Ed Tanous27b0cf92023-08-07 12:02:40 -0700161 boost::beast::http::fields& fields = thisRes.fields();
162 std::string code = std::to_string(thisRes.resultInt());
Ed Tanous52e31622024-01-23 16:31:11 -0800163 hdr.emplace_back(
164 headerFromStringViews(":status", code, NGHTTP2_NV_FLAG_NONE));
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800165 for (const boost::beast::http::fields::value_type& header : fields)
166 {
Ed Tanous52e31622024-01-23 16:31:11 -0800167 hdr.emplace_back(headerFromStringViews(
168 header.name_string(), header.value(),
169 NGHTTP2_NV_FLAG_NO_COPY_VALUE | NGHTTP2_NV_FLAG_NO_COPY_NAME));
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800170 }
Ed Tanousf42e8592023-08-25 10:47:44 -0700171 Http2StreamData& stream = it->second;
Ed Tanous52e31622024-01-23 16:31:11 -0800172 crow::Response& res = stream.res;
173 http::response<bmcweb::FileBody>& fbody = res.response;
174 stream.writer.emplace(fbody.base(), fbody.body());
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800175
176 nghttp2_data_provider dataPrd{
Ed Tanousf42e8592023-08-25 10:47:44 -0700177 .source = {.fd = 0},
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800178 .read_callback = fileReadCallback,
179 };
180
181 int rv = ngSession.submitResponse(streamId, hdr, &dataPrd);
182 if (rv != 0)
183 {
Ed Tanous62598e32023-07-17 17:06:25 -0700184 BMCWEB_LOG_ERROR("Fatal error: {}", nghttp2_strerror(rv));
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800185 close();
186 return -1;
187 }
188 ngSession.send();
189
190 return 0;
191 }
192
193 nghttp2_session initializeNghttp2Session()
194 {
195 nghttp2_session_callbacks callbacks;
196 callbacks.setOnFrameRecvCallback(onFrameRecvCallbackStatic);
197 callbacks.setOnStreamCloseCallback(onStreamCloseCallbackStatic);
198 callbacks.setOnHeaderCallback(onHeaderCallbackStatic);
199 callbacks.setOnBeginHeadersCallback(onBeginHeadersCallbackStatic);
200 callbacks.setSendCallback(onSendCallbackStatic);
201
202 nghttp2_session session(callbacks);
203 session.setUserData(this);
204
205 return session;
206 }
207
208 int onRequestRecv(int32_t streamId)
209 {
Ed Tanous62598e32023-07-17 17:06:25 -0700210 BMCWEB_LOG_DEBUG("on_request_recv");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800211
212 auto it = streams.find(streamId);
213 if (it == streams.end())
214 {
215 close();
216 return -1;
217 }
218
Ed Tanousf42e8592023-08-25 10:47:44 -0700219 crow::Request& thisReq = it->second.req;
Ed Tanous62598e32023-07-17 17:06:25 -0700220 BMCWEB_LOG_DEBUG("Handling {} \"{}\"", logPtr(&thisReq),
221 thisReq.url().encoded_path());
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800222
Ed Tanousf42e8592023-08-25 10:47:44 -0700223 crow::Response& thisRes = it->second.res;
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800224
225 thisRes.setCompleteRequestHandler(
226 [this, streamId](Response& completeRes) {
Ed Tanous62598e32023-07-17 17:06:25 -0700227 BMCWEB_LOG_DEBUG("res.completeRequestHandler called");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800228 if (sendResponse(completeRes, streamId) != 0)
229 {
230 close();
231 return;
232 }
233 });
234 auto asyncResp =
Ed Tanousf42e8592023-08-25 10:47:44 -0700235 std::make_shared<bmcweb::AsyncResp>(std::move(it->second.res));
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800236 handler->handle(thisReq, asyncResp);
237
238 return 0;
239 }
240
241 int onFrameRecvCallback(const nghttp2_frame& frame)
242 {
Ed Tanous62598e32023-07-17 17:06:25 -0700243 BMCWEB_LOG_DEBUG("frame type {}", static_cast<int>(frame.hd.type));
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800244 switch (frame.hd.type)
245 {
246 case NGHTTP2_DATA:
247 case NGHTTP2_HEADERS:
248 // Check that the client request has finished
249 if ((frame.hd.flags & NGHTTP2_FLAG_END_STREAM) != 0)
250 {
251 return onRequestRecv(frame.hd.stream_id);
252 }
253 break;
254 default:
255 break;
256 }
257 return 0;
258 }
259
260 static int onFrameRecvCallbackStatic(nghttp2_session* /* session */,
261 const nghttp2_frame* frame,
262 void* userData)
263 {
Ed Tanous62598e32023-07-17 17:06:25 -0700264 BMCWEB_LOG_DEBUG("on_frame_recv_callback");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800265 if (userData == nullptr)
266 {
Ed Tanous62598e32023-07-17 17:06:25 -0700267 BMCWEB_LOG_CRITICAL("user data was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800268 return NGHTTP2_ERR_CALLBACK_FAILURE;
269 }
270 if (frame == nullptr)
271 {
Ed Tanous62598e32023-07-17 17:06:25 -0700272 BMCWEB_LOG_CRITICAL("frame was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800273 return NGHTTP2_ERR_CALLBACK_FAILURE;
274 }
275 return userPtrToSelf(userData).onFrameRecvCallback(*frame);
276 }
277
278 static self_type& userPtrToSelf(void* userData)
279 {
280 // This method exists to keep the unsafe reinterpret cast in one
281 // place.
282 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
283 return *reinterpret_cast<self_type*>(userData);
284 }
285
286 static int onStreamCloseCallbackStatic(nghttp2_session* /* session */,
287 int32_t streamId,
288 uint32_t /*unused*/, void* userData)
289 {
Ed Tanous62598e32023-07-17 17:06:25 -0700290 BMCWEB_LOG_DEBUG("on_stream_close_callback stream {}", streamId);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800291 if (userData == nullptr)
292 {
Ed Tanous62598e32023-07-17 17:06:25 -0700293 BMCWEB_LOG_CRITICAL("user data was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800294 return NGHTTP2_ERR_CALLBACK_FAILURE;
295 }
Ed Tanousf42e8592023-08-25 10:47:44 -0700296 if (userPtrToSelf(userData).streams.erase(streamId) <= 0)
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800297 {
298 return -1;
299 }
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800300 return 0;
301 }
302
303 int onHeaderCallback(const nghttp2_frame& frame,
304 std::span<const uint8_t> name,
305 std::span<const uint8_t> value)
306 {
307 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
308 std::string_view nameSv(reinterpret_cast<const char*>(name.data()),
309 name.size());
310 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
311 std::string_view valueSv(reinterpret_cast<const char*>(value.data()),
312 value.size());
313
Ed Tanous62598e32023-07-17 17:06:25 -0700314 BMCWEB_LOG_DEBUG("on_header_callback name: {} value {}", nameSv,
315 valueSv);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800316
317 switch (frame.hd.type)
318 {
319 case NGHTTP2_HEADERS:
320 if (frame.headers.cat != NGHTTP2_HCAT_REQUEST)
321 {
322 break;
323 }
324 auto thisStream = streams.find(frame.hd.stream_id);
325 if (thisStream == streams.end())
326 {
Ed Tanous62598e32023-07-17 17:06:25 -0700327 BMCWEB_LOG_ERROR("Unknown stream{}", frame.hd.stream_id);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800328 close();
329 return -1;
330 }
331
Ed Tanousf42e8592023-08-25 10:47:44 -0700332 crow::Request& thisReq = thisStream->second.req;
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800333
334 if (nameSv == ":path")
335 {
336 thisReq.target(valueSv);
337 }
338 else if (nameSv == ":method")
339 {
340 boost::beast::http::verb verb =
341 boost::beast::http::string_to_verb(valueSv);
342 if (verb == boost::beast::http::verb::unknown)
343 {
Ed Tanous62598e32023-07-17 17:06:25 -0700344 BMCWEB_LOG_ERROR("Unknown http verb {}", valueSv);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800345 close();
346 return -1;
347 }
348 thisReq.req.method(verb);
349 }
350 else if (nameSv == ":scheme")
351 {
352 // Nothing to check on scheme
353 }
354 else
355 {
356 thisReq.req.set(nameSv, valueSv);
357 }
358 break;
359 }
360 return 0;
361 }
362
363 static int onHeaderCallbackStatic(nghttp2_session* /* session */,
364 const nghttp2_frame* frame,
365 const uint8_t* name, size_t namelen,
366 const uint8_t* value, size_t vallen,
367 uint8_t /* flags */, void* userData)
368 {
369 if (userData == nullptr)
370 {
Ed Tanous62598e32023-07-17 17:06:25 -0700371 BMCWEB_LOG_CRITICAL("user data was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800372 return NGHTTP2_ERR_CALLBACK_FAILURE;
373 }
374 if (frame == nullptr)
375 {
Ed Tanous62598e32023-07-17 17:06:25 -0700376 BMCWEB_LOG_CRITICAL("frame was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800377 return NGHTTP2_ERR_CALLBACK_FAILURE;
378 }
379 if (name == nullptr)
380 {
Ed Tanous62598e32023-07-17 17:06:25 -0700381 BMCWEB_LOG_CRITICAL("name was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800382 return NGHTTP2_ERR_CALLBACK_FAILURE;
383 }
384 if (value == nullptr)
385 {
Ed Tanous62598e32023-07-17 17:06:25 -0700386 BMCWEB_LOG_CRITICAL("value was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800387 return NGHTTP2_ERR_CALLBACK_FAILURE;
388 }
389 return userPtrToSelf(userData).onHeaderCallback(*frame, {name, namelen},
390 {value, vallen});
391 }
392
393 int onBeginHeadersCallback(const nghttp2_frame& frame)
394 {
395 if (frame.hd.type == NGHTTP2_HEADERS &&
396 frame.headers.cat == NGHTTP2_HCAT_REQUEST)
397 {
Ed Tanous62598e32023-07-17 17:06:25 -0700398 BMCWEB_LOG_DEBUG("create stream for id {}", frame.hd.stream_id);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800399
Ed Tanousf42e8592023-08-25 10:47:44 -0700400 Http2StreamData& stream = streams[frame.hd.stream_id];
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800401 // http2 is by definition always tls
Ed Tanousf42e8592023-08-25 10:47:44 -0700402 stream.req.isSecure = true;
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800403 }
404 return 0;
405 }
406
407 static int onBeginHeadersCallbackStatic(nghttp2_session* /* session */,
408 const nghttp2_frame* frame,
409 void* userData)
410 {
Ed Tanous62598e32023-07-17 17:06:25 -0700411 BMCWEB_LOG_DEBUG("on_begin_headers_callback");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800412 if (userData == nullptr)
413 {
Ed Tanous62598e32023-07-17 17:06:25 -0700414 BMCWEB_LOG_CRITICAL("user data was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800415 return NGHTTP2_ERR_CALLBACK_FAILURE;
416 }
417 if (frame == nullptr)
418 {
Ed Tanous62598e32023-07-17 17:06:25 -0700419 BMCWEB_LOG_CRITICAL("frame was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800420 return NGHTTP2_ERR_CALLBACK_FAILURE;
421 }
422 return userPtrToSelf(userData).onBeginHeadersCallback(*frame);
423 }
424
425 static void afterWriteBuffer(const std::shared_ptr<self_type>& self,
426 const boost::system::error_code& ec,
427 size_t sendLength)
428 {
429 self->isWriting = false;
Ed Tanous62598e32023-07-17 17:06:25 -0700430 BMCWEB_LOG_DEBUG("Sent {}", sendLength);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800431 if (ec)
432 {
433 self->close();
434 return;
435 }
436 self->sendBuffer.consume(sendLength);
437 self->writeBuffer();
438 }
439
440 void writeBuffer()
441 {
442 if (isWriting)
443 {
444 return;
445 }
446 if (sendBuffer.size() <= 0)
447 {
448 return;
449 }
450 isWriting = true;
451 adaptor.async_write_some(
452 sendBuffer.data(),
453 std::bind_front(afterWriteBuffer, shared_from_this()));
454 }
455
456 ssize_t onSendCallback(nghttp2_session* /*session */, const uint8_t* data,
457 size_t length, int /* flags */)
458 {
Ed Tanous62598e32023-07-17 17:06:25 -0700459 BMCWEB_LOG_DEBUG("On send callback size={}", length);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800460 size_t copied = boost::asio::buffer_copy(
461 sendBuffer.prepare(length), boost::asio::buffer(data, length));
462 sendBuffer.commit(copied);
463 writeBuffer();
464 return static_cast<ssize_t>(length);
465 }
466
467 static ssize_t onSendCallbackStatic(nghttp2_session* session,
468 const uint8_t* data, size_t length,
Ed Tanous52e31622024-01-23 16:31:11 -0800469 int flags, void* userData)
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800470 {
471 return userPtrToSelf(userData).onSendCallback(session, data, length,
472 flags);
473 }
474
475 void close()
476 {
477 if constexpr (std::is_same_v<Adaptor,
478 boost::beast::ssl_stream<
479 boost::asio::ip::tcp::socket>>)
480 {
481 adaptor.next_layer().close();
482 }
483 else
484 {
485 adaptor.close();
486 }
487 }
488
489 void doRead()
490 {
Ed Tanous62598e32023-07-17 17:06:25 -0700491 BMCWEB_LOG_DEBUG("{} doRead", logPtr(this));
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800492 adaptor.async_read_some(
493 inBuffer.prepare(8192),
494 [this, self(shared_from_this())](
495 const boost::system::error_code& ec, size_t bytesTransferred) {
Ed Tanous62598e32023-07-17 17:06:25 -0700496 BMCWEB_LOG_DEBUG("{} async_read_some {} Bytes", logPtr(this),
497 bytesTransferred);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800498
499 if (ec)
500 {
Ed Tanous62598e32023-07-17 17:06:25 -0700501 BMCWEB_LOG_ERROR("{} Error while reading: {}", logPtr(this),
502 ec.message());
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800503 close();
Ed Tanous62598e32023-07-17 17:06:25 -0700504 BMCWEB_LOG_DEBUG("{} from read(1)", logPtr(this));
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800505 return;
506 }
507 inBuffer.commit(bytesTransferred);
Ed Tanous52e31622024-01-23 16:31:11 -0800508 // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic)
509 for (const auto* it =
510 boost::asio::buffer_sequence_begin(inBuffer.data());
511 it != boost::asio::buffer_sequence_end(inBuffer.data()); it++)
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800512 {
Ed Tanous52e31622024-01-23 16:31:11 -0800513 // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic)
514 while (inBuffer.size() > 0)
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800515 {
Ed Tanous52e31622024-01-23 16:31:11 -0800516 std::span<const uint8_t> bufferSpan{
517 std::bit_cast<const uint8_t*>(it->data()), it->size()};
518 BMCWEB_LOG_DEBUG("http2 is getting {} bytes",
519 bufferSpan.size());
520 ssize_t readLen = ngSession.memRecv(bufferSpan);
521 if (readLen <= 0)
522 {
523 BMCWEB_LOG_ERROR("nghttp2_session_mem_recv returned {}",
524 readLen);
525 close();
526 return;
527 }
528 inBuffer.consume(static_cast<size_t>(readLen));
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800529 }
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800530 }
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800531
532 doRead();
Patrick Williams5a39f772023-10-20 11:20:21 -0500533 });
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800534 }
535
536 // A mapping from http2 stream ID to Stream Data
Ed Tanous52e31622024-01-23 16:31:11 -0800537 std::map<int32_t, Http2StreamData> streams;
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800538
539 boost::beast::multi_buffer sendBuffer;
Ed Tanous52e31622024-01-23 16:31:11 -0800540 boost::beast::flat_static_buffer<8192> inBuffer;
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800541
542 Adaptor adaptor;
543 bool isWriting = false;
544
545 nghttp2_session ngSession;
546
547 Handler* handler;
548 std::function<std::string()>& getCachedDateStr;
549
550 using std::enable_shared_from_this<
551 HTTP2Connection<Adaptor, Handler>>::shared_from_this;
552
553 using std::enable_shared_from_this<
554 HTTP2Connection<Adaptor, Handler>>::weak_from_this;
555};
556} // namespace crow