blob: 97dcf4e2bbbba79fdd016b47d5ccb979d495b793 [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>
Ed Tanousfca2cbe2021-01-28 14:49:59 -080019#include <boost/beast/http/error.hpp>
20#include <boost/beast/http/parser.hpp>
21#include <boost/beast/http/read.hpp>
22#include <boost/beast/http/serializer.hpp>
Ed Tanousfca2cbe2021-01-28 14:49:59 -080023#include <boost/beast/http/write.hpp>
24#include <boost/beast/ssl/ssl_stream.hpp>
25#include <boost/beast/websocket.hpp>
Ed Tanousd0882182024-01-26 23:45:25 -080026#include <boost/system/error_code.hpp>
Ed Tanousfca2cbe2021-01-28 14:49:59 -080027
Ed Tanousd0882182024-01-26 23:45:25 -080028#include <array>
Ed Tanousfca2cbe2021-01-28 14:49:59 -080029#include <atomic>
30#include <chrono>
Ed Tanousd0882182024-01-26 23:45:25 -080031#include <functional>
32#include <memory>
Ed Tanousfca2cbe2021-01-28 14:49:59 -080033#include <vector>
34
35namespace crow
36{
37
38struct Http2StreamData
39{
Ed Tanous52e31622024-01-23 16:31:11 -080040 Request req{};
41 Response res{};
42 std::optional<bmcweb::FileBody::writer> writer;
Ed Tanousfca2cbe2021-01-28 14:49:59 -080043};
44
45template <typename Adaptor, typename Handler>
46class HTTP2Connection :
47 public std::enable_shared_from_this<HTTP2Connection<Adaptor, Handler>>
48{
49 using self_type = HTTP2Connection<Adaptor, Handler>;
50
51 public:
52 HTTP2Connection(Adaptor&& adaptorIn, Handler* handlerIn,
Ed Tanous52e31622024-01-23 16:31:11 -080053 std::function<std::string()>& getCachedDateStrF) :
Ed Tanousfca2cbe2021-01-28 14:49:59 -080054 adaptor(std::move(adaptorIn)),
Ed Tanous52e31622024-01-23 16:31:11 -080055 ngSession(initializeNghttp2Session()), handler(handlerIn),
56 getCachedDateStr(getCachedDateStrF)
Ed Tanousfca2cbe2021-01-28 14:49:59 -080057 {}
58
59 void start()
60 {
61 // Create the control stream
Ed Tanousf42e8592023-08-25 10:47:44 -070062 streams[0];
Ed Tanousfca2cbe2021-01-28 14:49:59 -080063
64 if (sendServerConnectionHeader() != 0)
65 {
Ed Tanous62598e32023-07-17 17:06:25 -070066 BMCWEB_LOG_ERROR("send_server_connection_header failed");
Ed Tanousfca2cbe2021-01-28 14:49:59 -080067 return;
68 }
69 doRead();
70 }
71
72 int sendServerConnectionHeader()
73 {
Ed Tanous62598e32023-07-17 17:06:25 -070074 BMCWEB_LOG_DEBUG("send_server_connection_header()");
Ed Tanousfca2cbe2021-01-28 14:49:59 -080075
76 uint32_t maxStreams = 4;
77 std::array<nghttp2_settings_entry, 2> iv = {
78 {{NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, maxStreams},
79 {NGHTTP2_SETTINGS_ENABLE_PUSH, 0}}};
80 int rv = ngSession.submitSettings(iv);
81 if (rv != 0)
82 {
Ed Tanous62598e32023-07-17 17:06:25 -070083 BMCWEB_LOG_ERROR("Fatal error: {}", nghttp2_strerror(rv));
Ed Tanousfca2cbe2021-01-28 14:49:59 -080084 return -1;
85 }
Ed Tanousd0882182024-01-26 23:45:25 -080086 writeBuffer();
Ed Tanousfca2cbe2021-01-28 14:49:59 -080087 return 0;
88 }
89
90 static ssize_t fileReadCallback(nghttp2_session* /* session */,
Ed Tanousf42e8592023-08-25 10:47:44 -070091 int32_t streamId, uint8_t* buf,
Ed Tanousfca2cbe2021-01-28 14:49:59 -080092 size_t length, uint32_t* dataFlags,
Ed Tanousf42e8592023-08-25 10:47:44 -070093 nghttp2_data_source* /*source*/,
94 void* userPtr)
Ed Tanousfca2cbe2021-01-28 14:49:59 -080095 {
Ed Tanousf42e8592023-08-25 10:47:44 -070096 self_type& self = userPtrToSelf(userPtr);
97
98 auto streamIt = self.streams.find(streamId);
99 if (streamIt == self.streams.end())
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800100 {
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800101 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
102 }
Ed Tanousf42e8592023-08-25 10:47:44 -0700103 Http2StreamData& stream = streamIt->second;
Ed Tanous62598e32023-07-17 17:06:25 -0700104 BMCWEB_LOG_DEBUG("File read callback length: {}", length);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800105
Ed Tanous52e31622024-01-23 16:31:11 -0800106 boost::beast::error_code ec;
107 boost::optional<std::pair<boost::asio::const_buffer, bool>> out =
108 stream.writer->getWithMaxSize(ec, length);
109 if (ec)
Ed Tanous27b0cf92023-08-07 12:02:40 -0700110 {
111 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
112 }
113
Ed Tanous52e31622024-01-23 16:31:11 -0800114 if (!out)
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800115 {
Ed Tanous52e31622024-01-23 16:31:11 -0800116 *dataFlags |= NGHTTP2_DATA_FLAG_EOF;
117 return 0;
118 }
119
120 BMCWEB_LOG_DEBUG("Send chunk of size: {}", out->first.size());
121 if (length < out->first.size())
122 {
123 // Should never happen because of length limit on get() above
124 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
125 }
126
127 BMCWEB_LOG_DEBUG("Copying {} bytes to buf", out->first.size());
128 memcpy(buf, out->first.data(), out->first.size());
129
130 if (!out->second)
131 {
132 BMCWEB_LOG_DEBUG("Setting OEF and nocopy flag");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800133 *dataFlags |= NGHTTP2_DATA_FLAG_EOF;
134 //*dataFlags |= NGHTTP2_DATA_FLAG_NO_COPY;
135 }
Ed Tanous52e31622024-01-23 16:31:11 -0800136 return static_cast<ssize_t>(out->first.size());
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800137 }
138
139 nghttp2_nv headerFromStringViews(std::string_view name,
Ed Tanous52e31622024-01-23 16:31:11 -0800140 std::string_view value, uint8_t flags)
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800141 {
142 uint8_t* nameData = std::bit_cast<uint8_t*>(name.data());
143 uint8_t* valueData = std::bit_cast<uint8_t*>(value.data());
Ed Tanous52e31622024-01-23 16:31:11 -0800144 return {nameData, valueData, name.size(), value.size(), flags};
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800145 }
146
147 int sendResponse(Response& completedRes, int32_t streamId)
148 {
Ed Tanous62598e32023-07-17 17:06:25 -0700149 BMCWEB_LOG_DEBUG("send_response stream_id:{}", streamId);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800150
151 auto it = streams.find(streamId);
152 if (it == streams.end())
153 {
154 close();
155 return -1;
156 }
Ed Tanousf42e8592023-08-25 10:47:44 -0700157 Response& thisRes = it->second.res;
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800158 thisRes = std::move(completedRes);
Ed Tanousf42e8592023-08-25 10:47:44 -0700159 crow::Request& thisReq = it->second.req;
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800160 std::vector<nghttp2_nv> hdr;
161
162 completeResponseFields(thisReq, thisRes);
163 thisRes.addHeader(boost::beast::http::field::date, getCachedDateStr());
164
Ed Tanous27b0cf92023-08-07 12:02:40 -0700165 boost::beast::http::fields& fields = thisRes.fields();
166 std::string code = std::to_string(thisRes.resultInt());
Ed Tanous52e31622024-01-23 16:31:11 -0800167 hdr.emplace_back(
168 headerFromStringViews(":status", code, NGHTTP2_NV_FLAG_NONE));
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800169 for (const boost::beast::http::fields::value_type& header : fields)
170 {
Ed Tanous52e31622024-01-23 16:31:11 -0800171 hdr.emplace_back(headerFromStringViews(
Ed Tanousd0882182024-01-26 23:45:25 -0800172 header.name_string(), header.value(), NGHTTP2_NV_FLAG_NONE));
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800173 }
Ed Tanousf42e8592023-08-25 10:47:44 -0700174 Http2StreamData& stream = it->second;
Ed Tanous52e31622024-01-23 16:31:11 -0800175 crow::Response& res = stream.res;
176 http::response<bmcweb::FileBody>& fbody = res.response;
177 stream.writer.emplace(fbody.base(), fbody.body());
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800178
179 nghttp2_data_provider dataPrd{
Ed Tanousf42e8592023-08-25 10:47:44 -0700180 .source = {.fd = 0},
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800181 .read_callback = fileReadCallback,
182 };
183
184 int rv = ngSession.submitResponse(streamId, hdr, &dataPrd);
185 if (rv != 0)
186 {
Ed Tanous62598e32023-07-17 17:06:25 -0700187 BMCWEB_LOG_ERROR("Fatal error: {}", nghttp2_strerror(rv));
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800188 close();
189 return -1;
190 }
Ed Tanousd0882182024-01-26 23:45:25 -0800191 writeBuffer();
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800192
193 return 0;
194 }
195
196 nghttp2_session initializeNghttp2Session()
197 {
198 nghttp2_session_callbacks callbacks;
199 callbacks.setOnFrameRecvCallback(onFrameRecvCallbackStatic);
200 callbacks.setOnStreamCloseCallback(onStreamCloseCallbackStatic);
201 callbacks.setOnHeaderCallback(onHeaderCallbackStatic);
202 callbacks.setOnBeginHeadersCallback(onBeginHeadersCallbackStatic);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800203
204 nghttp2_session session(callbacks);
205 session.setUserData(this);
206
207 return session;
208 }
209
210 int onRequestRecv(int32_t streamId)
211 {
Ed Tanous62598e32023-07-17 17:06:25 -0700212 BMCWEB_LOG_DEBUG("on_request_recv");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800213
214 auto it = streams.find(streamId);
215 if (it == streams.end())
216 {
217 close();
218 return -1;
219 }
220
Ed Tanousf42e8592023-08-25 10:47:44 -0700221 crow::Request& thisReq = it->second.req;
Ed Tanous62598e32023-07-17 17:06:25 -0700222 BMCWEB_LOG_DEBUG("Handling {} \"{}\"", logPtr(&thisReq),
223 thisReq.url().encoded_path());
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800224
Ed Tanousf42e8592023-08-25 10:47:44 -0700225 crow::Response& thisRes = it->second.res;
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800226
227 thisRes.setCompleteRequestHandler(
228 [this, streamId](Response& completeRes) {
Ed Tanous62598e32023-07-17 17:06:25 -0700229 BMCWEB_LOG_DEBUG("res.completeRequestHandler called");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800230 if (sendResponse(completeRes, streamId) != 0)
231 {
232 close();
233 return;
234 }
235 });
236 auto asyncResp =
Ed Tanousf42e8592023-08-25 10:47:44 -0700237 std::make_shared<bmcweb::AsyncResp>(std::move(it->second.res));
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800238 handler->handle(thisReq, asyncResp);
239
240 return 0;
241 }
242
243 int onFrameRecvCallback(const nghttp2_frame& frame)
244 {
Ed Tanous62598e32023-07-17 17:06:25 -0700245 BMCWEB_LOG_DEBUG("frame type {}", static_cast<int>(frame.hd.type));
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800246 switch (frame.hd.type)
247 {
248 case NGHTTP2_DATA:
249 case NGHTTP2_HEADERS:
250 // Check that the client request has finished
251 if ((frame.hd.flags & NGHTTP2_FLAG_END_STREAM) != 0)
252 {
253 return onRequestRecv(frame.hd.stream_id);
254 }
255 break;
256 default:
257 break;
258 }
259 return 0;
260 }
261
262 static int onFrameRecvCallbackStatic(nghttp2_session* /* session */,
263 const nghttp2_frame* frame,
264 void* userData)
265 {
Ed Tanous62598e32023-07-17 17:06:25 -0700266 BMCWEB_LOG_DEBUG("on_frame_recv_callback");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800267 if (userData == nullptr)
268 {
Ed Tanous62598e32023-07-17 17:06:25 -0700269 BMCWEB_LOG_CRITICAL("user data was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800270 return NGHTTP2_ERR_CALLBACK_FAILURE;
271 }
272 if (frame == nullptr)
273 {
Ed Tanous62598e32023-07-17 17:06:25 -0700274 BMCWEB_LOG_CRITICAL("frame was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800275 return NGHTTP2_ERR_CALLBACK_FAILURE;
276 }
277 return userPtrToSelf(userData).onFrameRecvCallback(*frame);
278 }
279
280 static self_type& userPtrToSelf(void* userData)
281 {
282 // This method exists to keep the unsafe reinterpret cast in one
283 // place.
284 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
285 return *reinterpret_cast<self_type*>(userData);
286 }
287
288 static int onStreamCloseCallbackStatic(nghttp2_session* /* session */,
289 int32_t streamId,
290 uint32_t /*unused*/, void* userData)
291 {
Ed Tanous62598e32023-07-17 17:06:25 -0700292 BMCWEB_LOG_DEBUG("on_stream_close_callback stream {}", streamId);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800293 if (userData == nullptr)
294 {
Ed Tanous62598e32023-07-17 17:06:25 -0700295 BMCWEB_LOG_CRITICAL("user data was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800296 return NGHTTP2_ERR_CALLBACK_FAILURE;
297 }
Ed Tanousf42e8592023-08-25 10:47:44 -0700298 if (userPtrToSelf(userData).streams.erase(streamId) <= 0)
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800299 {
300 return -1;
301 }
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800302 return 0;
303 }
304
305 int onHeaderCallback(const nghttp2_frame& frame,
306 std::span<const uint8_t> name,
307 std::span<const uint8_t> value)
308 {
309 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
310 std::string_view nameSv(reinterpret_cast<const char*>(name.data()),
311 name.size());
312 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
313 std::string_view valueSv(reinterpret_cast<const char*>(value.data()),
314 value.size());
315
Ed Tanous62598e32023-07-17 17:06:25 -0700316 BMCWEB_LOG_DEBUG("on_header_callback name: {} value {}", nameSv,
317 valueSv);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800318
319 switch (frame.hd.type)
320 {
321 case NGHTTP2_HEADERS:
322 if (frame.headers.cat != NGHTTP2_HCAT_REQUEST)
323 {
324 break;
325 }
326 auto thisStream = streams.find(frame.hd.stream_id);
327 if (thisStream == streams.end())
328 {
Ed Tanous62598e32023-07-17 17:06:25 -0700329 BMCWEB_LOG_ERROR("Unknown stream{}", frame.hd.stream_id);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800330 close();
331 return -1;
332 }
333
Ed Tanousf42e8592023-08-25 10:47:44 -0700334 crow::Request& thisReq = thisStream->second.req;
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800335
336 if (nameSv == ":path")
337 {
338 thisReq.target(valueSv);
339 }
340 else if (nameSv == ":method")
341 {
342 boost::beast::http::verb verb =
343 boost::beast::http::string_to_verb(valueSv);
344 if (verb == boost::beast::http::verb::unknown)
345 {
Ed Tanous62598e32023-07-17 17:06:25 -0700346 BMCWEB_LOG_ERROR("Unknown http verb {}", valueSv);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800347 close();
348 return -1;
349 }
350 thisReq.req.method(verb);
351 }
352 else if (nameSv == ":scheme")
353 {
354 // Nothing to check on scheme
355 }
356 else
357 {
358 thisReq.req.set(nameSv, valueSv);
359 }
360 break;
361 }
362 return 0;
363 }
364
365 static int onHeaderCallbackStatic(nghttp2_session* /* session */,
366 const nghttp2_frame* frame,
367 const uint8_t* name, size_t namelen,
368 const uint8_t* value, size_t vallen,
369 uint8_t /* flags */, void* userData)
370 {
371 if (userData == nullptr)
372 {
Ed Tanous62598e32023-07-17 17:06:25 -0700373 BMCWEB_LOG_CRITICAL("user data was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800374 return NGHTTP2_ERR_CALLBACK_FAILURE;
375 }
376 if (frame == nullptr)
377 {
Ed Tanous62598e32023-07-17 17:06:25 -0700378 BMCWEB_LOG_CRITICAL("frame was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800379 return NGHTTP2_ERR_CALLBACK_FAILURE;
380 }
381 if (name == nullptr)
382 {
Ed Tanous62598e32023-07-17 17:06:25 -0700383 BMCWEB_LOG_CRITICAL("name was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800384 return NGHTTP2_ERR_CALLBACK_FAILURE;
385 }
386 if (value == nullptr)
387 {
Ed Tanous62598e32023-07-17 17:06:25 -0700388 BMCWEB_LOG_CRITICAL("value was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800389 return NGHTTP2_ERR_CALLBACK_FAILURE;
390 }
391 return userPtrToSelf(userData).onHeaderCallback(*frame, {name, namelen},
392 {value, vallen});
393 }
394
395 int onBeginHeadersCallback(const nghttp2_frame& frame)
396 {
397 if (frame.hd.type == NGHTTP2_HEADERS &&
398 frame.headers.cat == NGHTTP2_HCAT_REQUEST)
399 {
Ed Tanous62598e32023-07-17 17:06:25 -0700400 BMCWEB_LOG_DEBUG("create stream for id {}", frame.hd.stream_id);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800401
Ed Tanousf42e8592023-08-25 10:47:44 -0700402 Http2StreamData& stream = streams[frame.hd.stream_id];
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800403 // http2 is by definition always tls
Ed Tanousf42e8592023-08-25 10:47:44 -0700404 stream.req.isSecure = true;
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800405 }
406 return 0;
407 }
408
409 static int onBeginHeadersCallbackStatic(nghttp2_session* /* session */,
410 const nghttp2_frame* frame,
411 void* userData)
412 {
Ed Tanous62598e32023-07-17 17:06:25 -0700413 BMCWEB_LOG_DEBUG("on_begin_headers_callback");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800414 if (userData == nullptr)
415 {
Ed Tanous62598e32023-07-17 17:06:25 -0700416 BMCWEB_LOG_CRITICAL("user data was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800417 return NGHTTP2_ERR_CALLBACK_FAILURE;
418 }
419 if (frame == nullptr)
420 {
Ed Tanous62598e32023-07-17 17:06:25 -0700421 BMCWEB_LOG_CRITICAL("frame was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800422 return NGHTTP2_ERR_CALLBACK_FAILURE;
423 }
424 return userPtrToSelf(userData).onBeginHeadersCallback(*frame);
425 }
426
427 static void afterWriteBuffer(const std::shared_ptr<self_type>& self,
428 const boost::system::error_code& ec,
429 size_t sendLength)
430 {
431 self->isWriting = false;
Ed Tanous62598e32023-07-17 17:06:25 -0700432 BMCWEB_LOG_DEBUG("Sent {}", sendLength);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800433 if (ec)
434 {
435 self->close();
436 return;
437 }
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800438 self->writeBuffer();
439 }
440
441 void writeBuffer()
442 {
443 if (isWriting)
444 {
445 return;
446 }
Ed Tanousd0882182024-01-26 23:45:25 -0800447 std::span<const uint8_t> data = ngSession.memSend();
448 if (data.empty())
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800449 {
450 return;
451 }
452 isWriting = true;
453 adaptor.async_write_some(
Ed Tanousd0882182024-01-26 23:45:25 -0800454 boost::asio::buffer(data.data(), data.size()),
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800455 std::bind_front(afterWriteBuffer, shared_from_this()));
456 }
457
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800458 void close()
459 {
460 if constexpr (std::is_same_v<Adaptor,
461 boost::beast::ssl_stream<
462 boost::asio::ip::tcp::socket>>)
463 {
464 adaptor.next_layer().close();
465 }
466 else
467 {
468 adaptor.close();
469 }
470 }
471
Ed Tanousd0882182024-01-26 23:45:25 -0800472 void afterDoRead(const std::shared_ptr<self_type>& /*self*/,
473 const boost::system::error_code& ec,
474 size_t bytesTransferred)
475 {
476 BMCWEB_LOG_DEBUG("{} async_read_some {} Bytes", logPtr(this),
477 bytesTransferred);
478
479 if (ec)
480 {
481 BMCWEB_LOG_ERROR("{} Error while reading: {}", logPtr(this),
482 ec.message());
483 close();
484 BMCWEB_LOG_DEBUG("{} from read(1)", logPtr(this));
485 return;
486 }
487 std::span<uint8_t> bufferSpan{inBuffer.data(), bytesTransferred};
488
489 ssize_t readLen = ngSession.memRecv(bufferSpan);
490 if (readLen < 0)
491 {
492 BMCWEB_LOG_ERROR("nghttp2_session_mem_recv returned {}", readLen);
493 close();
494 return;
495 }
496 writeBuffer();
497
498 doRead();
499 }
500
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800501 void doRead()
502 {
Ed Tanous62598e32023-07-17 17:06:25 -0700503 BMCWEB_LOG_DEBUG("{} doRead", logPtr(this));
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800504 adaptor.async_read_some(
Ed Tanousd0882182024-01-26 23:45:25 -0800505 boost::asio::buffer(inBuffer),
506 std::bind_front(&self_type::afterDoRead, this, shared_from_this()));
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800507 }
508
509 // A mapping from http2 stream ID to Stream Data
Ed Tanous52e31622024-01-23 16:31:11 -0800510 std::map<int32_t, Http2StreamData> streams;
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800511
Ed Tanousd0882182024-01-26 23:45:25 -0800512 std::array<uint8_t, 8192> inBuffer{};
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800513
514 Adaptor adaptor;
515 bool isWriting = false;
516
517 nghttp2_session ngSession;
518
519 Handler* handler;
520 std::function<std::string()>& getCachedDateStr;
521
522 using std::enable_shared_from_this<
523 HTTP2Connection<Adaptor, Handler>>::shared_from_this;
524
525 using std::enable_shared_from_this<
526 HTTP2Connection<Adaptor, Handler>>::weak_from_this;
527};
528} // namespace crow