blob: 4d1bcace551e91de41e93471c4574d3c862b4e21 [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 Tanous62598e32023-07-17 17:06:25 -0700109 BMCWEB_LOG_DEBUG("total: {} send_sofar: {}", res.body().size(),
Ed Tanousf42e8592023-08-25 10:47:44 -0700110 stream.sentSofar);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800111
Ed Tanousf42e8592023-08-25 10:47:44 -0700112 size_t toSend = std::min(res.body().size() - stream.sentSofar, length);
Ed Tanous62598e32023-07-17 17:06:25 -0700113 BMCWEB_LOG_DEBUG("Copying {} bytes to buf", toSend);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800114
115 std::string::iterator bodyBegin = res.body().begin();
Ed Tanousf42e8592023-08-25 10:47:44 -0700116 std::advance(bodyBegin, stream.sentSofar);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800117
118 memcpy(buf, &*bodyBegin, toSend);
Ed Tanousf42e8592023-08-25 10:47:44 -0700119 stream.sentSofar += toSend;
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800120
Ed Tanousf42e8592023-08-25 10:47:44 -0700121 if (stream.sentSofar >= res.body().size())
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800122 {
Ed Tanous62598e32023-07-17 17:06:25 -0700123 BMCWEB_LOG_DEBUG("Setting OEF flag");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800124 *dataFlags |= NGHTTP2_DATA_FLAG_EOF;
125 //*dataFlags |= NGHTTP2_DATA_FLAG_NO_COPY;
126 }
127 return static_cast<ssize_t>(toSend);
128 }
129
130 nghttp2_nv headerFromStringViews(std::string_view name,
131 std::string_view value)
132 {
133 uint8_t* nameData = std::bit_cast<uint8_t*>(name.data());
134 uint8_t* valueData = std::bit_cast<uint8_t*>(value.data());
135 return {nameData, valueData, name.size(), value.size(),
136 NGHTTP2_NV_FLAG_NONE};
137 }
138
139 int sendResponse(Response& completedRes, int32_t streamId)
140 {
Ed Tanous62598e32023-07-17 17:06:25 -0700141 BMCWEB_LOG_DEBUG("send_response stream_id:{}", streamId);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800142
143 auto it = streams.find(streamId);
144 if (it == streams.end())
145 {
146 close();
147 return -1;
148 }
Ed Tanousf42e8592023-08-25 10:47:44 -0700149 Response& thisRes = it->second.res;
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800150 thisRes = std::move(completedRes);
Ed Tanousf42e8592023-08-25 10:47:44 -0700151 crow::Request& thisReq = it->second.req;
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800152 std::vector<nghttp2_nv> hdr;
153
154 completeResponseFields(thisReq, thisRes);
155 thisRes.addHeader(boost::beast::http::field::date, getCachedDateStr());
156
Ed Tanouse01d0c32023-06-30 13:21:32 -0700157 boost::beast::http::fields& fields = thisRes.stringResponse.base();
158 std::string code = std::to_string(thisRes.stringResponse.result_int());
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800159 hdr.emplace_back(headerFromStringViews(":status", code));
160 for (const boost::beast::http::fields::value_type& header : fields)
161 {
162 hdr.emplace_back(
163 headerFromStringViews(header.name_string(), header.value()));
164 }
Ed Tanousf42e8592023-08-25 10:47:44 -0700165 Http2StreamData& stream = it->second;
166 stream.sentSofar = 0;
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800167
168 nghttp2_data_provider dataPrd{
Ed Tanousf42e8592023-08-25 10:47:44 -0700169 .source = {.fd = 0},
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800170 .read_callback = fileReadCallback,
171 };
172
173 int rv = ngSession.submitResponse(streamId, hdr, &dataPrd);
174 if (rv != 0)
175 {
Ed Tanous62598e32023-07-17 17:06:25 -0700176 BMCWEB_LOG_ERROR("Fatal error: {}", nghttp2_strerror(rv));
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800177 close();
178 return -1;
179 }
180 ngSession.send();
181
182 return 0;
183 }
184
185 nghttp2_session initializeNghttp2Session()
186 {
187 nghttp2_session_callbacks callbacks;
188 callbacks.setOnFrameRecvCallback(onFrameRecvCallbackStatic);
189 callbacks.setOnStreamCloseCallback(onStreamCloseCallbackStatic);
190 callbacks.setOnHeaderCallback(onHeaderCallbackStatic);
191 callbacks.setOnBeginHeadersCallback(onBeginHeadersCallbackStatic);
192 callbacks.setSendCallback(onSendCallbackStatic);
193
194 nghttp2_session session(callbacks);
195 session.setUserData(this);
196
197 return session;
198 }
199
200 int onRequestRecv(int32_t streamId)
201 {
Ed Tanous62598e32023-07-17 17:06:25 -0700202 BMCWEB_LOG_DEBUG("on_request_recv");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800203
204 auto it = streams.find(streamId);
205 if (it == streams.end())
206 {
207 close();
208 return -1;
209 }
210
Ed Tanousf42e8592023-08-25 10:47:44 -0700211 crow::Request& thisReq = it->second.req;
Ed Tanous62598e32023-07-17 17:06:25 -0700212 BMCWEB_LOG_DEBUG("Handling {} \"{}\"", logPtr(&thisReq),
213 thisReq.url().encoded_path());
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800214
Ed Tanousf42e8592023-08-25 10:47:44 -0700215 crow::Response& thisRes = it->second.res;
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800216
217 thisRes.setCompleteRequestHandler(
218 [this, streamId](Response& completeRes) {
Ed Tanous62598e32023-07-17 17:06:25 -0700219 BMCWEB_LOG_DEBUG("res.completeRequestHandler called");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800220 if (sendResponse(completeRes, streamId) != 0)
221 {
222 close();
223 return;
224 }
225 });
226 auto asyncResp =
Ed Tanousf42e8592023-08-25 10:47:44 -0700227 std::make_shared<bmcweb::AsyncResp>(std::move(it->second.res));
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800228 handler->handle(thisReq, asyncResp);
229
230 return 0;
231 }
232
233 int onFrameRecvCallback(const nghttp2_frame& frame)
234 {
Ed Tanous62598e32023-07-17 17:06:25 -0700235 BMCWEB_LOG_DEBUG("frame type {}", static_cast<int>(frame.hd.type));
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800236 switch (frame.hd.type)
237 {
238 case NGHTTP2_DATA:
239 case NGHTTP2_HEADERS:
240 // Check that the client request has finished
241 if ((frame.hd.flags & NGHTTP2_FLAG_END_STREAM) != 0)
242 {
243 return onRequestRecv(frame.hd.stream_id);
244 }
245 break;
246 default:
247 break;
248 }
249 return 0;
250 }
251
252 static int onFrameRecvCallbackStatic(nghttp2_session* /* session */,
253 const nghttp2_frame* frame,
254 void* userData)
255 {
Ed Tanous62598e32023-07-17 17:06:25 -0700256 BMCWEB_LOG_DEBUG("on_frame_recv_callback");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800257 if (userData == nullptr)
258 {
Ed Tanous62598e32023-07-17 17:06:25 -0700259 BMCWEB_LOG_CRITICAL("user data was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800260 return NGHTTP2_ERR_CALLBACK_FAILURE;
261 }
262 if (frame == nullptr)
263 {
Ed Tanous62598e32023-07-17 17:06:25 -0700264 BMCWEB_LOG_CRITICAL("frame was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800265 return NGHTTP2_ERR_CALLBACK_FAILURE;
266 }
267 return userPtrToSelf(userData).onFrameRecvCallback(*frame);
268 }
269
270 static self_type& userPtrToSelf(void* userData)
271 {
272 // This method exists to keep the unsafe reinterpret cast in one
273 // place.
274 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
275 return *reinterpret_cast<self_type*>(userData);
276 }
277
278 static int onStreamCloseCallbackStatic(nghttp2_session* /* session */,
279 int32_t streamId,
280 uint32_t /*unused*/, void* userData)
281 {
Ed Tanous62598e32023-07-17 17:06:25 -0700282 BMCWEB_LOG_DEBUG("on_stream_close_callback stream {}", streamId);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800283 if (userData == nullptr)
284 {
Ed Tanous62598e32023-07-17 17:06:25 -0700285 BMCWEB_LOG_CRITICAL("user data was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800286 return NGHTTP2_ERR_CALLBACK_FAILURE;
287 }
Ed Tanousf42e8592023-08-25 10:47:44 -0700288 if (userPtrToSelf(userData).streams.erase(streamId) <= 0)
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800289 {
290 return -1;
291 }
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800292 return 0;
293 }
294
295 int onHeaderCallback(const nghttp2_frame& frame,
296 std::span<const uint8_t> name,
297 std::span<const uint8_t> value)
298 {
299 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
300 std::string_view nameSv(reinterpret_cast<const char*>(name.data()),
301 name.size());
302 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
303 std::string_view valueSv(reinterpret_cast<const char*>(value.data()),
304 value.size());
305
Ed Tanous62598e32023-07-17 17:06:25 -0700306 BMCWEB_LOG_DEBUG("on_header_callback name: {} value {}", nameSv,
307 valueSv);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800308
309 switch (frame.hd.type)
310 {
311 case NGHTTP2_HEADERS:
312 if (frame.headers.cat != NGHTTP2_HCAT_REQUEST)
313 {
314 break;
315 }
316 auto thisStream = streams.find(frame.hd.stream_id);
317 if (thisStream == streams.end())
318 {
Ed Tanous62598e32023-07-17 17:06:25 -0700319 BMCWEB_LOG_ERROR("Unknown stream{}", frame.hd.stream_id);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800320 close();
321 return -1;
322 }
323
Ed Tanousf42e8592023-08-25 10:47:44 -0700324 crow::Request& thisReq = thisStream->second.req;
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800325
326 if (nameSv == ":path")
327 {
328 thisReq.target(valueSv);
329 }
330 else if (nameSv == ":method")
331 {
332 boost::beast::http::verb verb =
333 boost::beast::http::string_to_verb(valueSv);
334 if (verb == boost::beast::http::verb::unknown)
335 {
Ed Tanous62598e32023-07-17 17:06:25 -0700336 BMCWEB_LOG_ERROR("Unknown http verb {}", valueSv);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800337 close();
338 return -1;
339 }
340 thisReq.req.method(verb);
341 }
342 else if (nameSv == ":scheme")
343 {
344 // Nothing to check on scheme
345 }
346 else
347 {
348 thisReq.req.set(nameSv, valueSv);
349 }
350 break;
351 }
352 return 0;
353 }
354
355 static int onHeaderCallbackStatic(nghttp2_session* /* session */,
356 const nghttp2_frame* frame,
357 const uint8_t* name, size_t namelen,
358 const uint8_t* value, size_t vallen,
359 uint8_t /* flags */, void* userData)
360 {
361 if (userData == nullptr)
362 {
Ed Tanous62598e32023-07-17 17:06:25 -0700363 BMCWEB_LOG_CRITICAL("user data was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800364 return NGHTTP2_ERR_CALLBACK_FAILURE;
365 }
366 if (frame == nullptr)
367 {
Ed Tanous62598e32023-07-17 17:06:25 -0700368 BMCWEB_LOG_CRITICAL("frame was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800369 return NGHTTP2_ERR_CALLBACK_FAILURE;
370 }
371 if (name == nullptr)
372 {
Ed Tanous62598e32023-07-17 17:06:25 -0700373 BMCWEB_LOG_CRITICAL("name was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800374 return NGHTTP2_ERR_CALLBACK_FAILURE;
375 }
376 if (value == nullptr)
377 {
Ed Tanous62598e32023-07-17 17:06:25 -0700378 BMCWEB_LOG_CRITICAL("value was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800379 return NGHTTP2_ERR_CALLBACK_FAILURE;
380 }
381 return userPtrToSelf(userData).onHeaderCallback(*frame, {name, namelen},
382 {value, vallen});
383 }
384
385 int onBeginHeadersCallback(const nghttp2_frame& frame)
386 {
387 if (frame.hd.type == NGHTTP2_HEADERS &&
388 frame.headers.cat == NGHTTP2_HCAT_REQUEST)
389 {
Ed Tanous62598e32023-07-17 17:06:25 -0700390 BMCWEB_LOG_DEBUG("create stream for id {}", frame.hd.stream_id);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800391
Ed Tanousf42e8592023-08-25 10:47:44 -0700392 Http2StreamData& stream = streams[frame.hd.stream_id];
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800393 // http2 is by definition always tls
Ed Tanousf42e8592023-08-25 10:47:44 -0700394 stream.req.isSecure = true;
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800395 }
396 return 0;
397 }
398
399 static int onBeginHeadersCallbackStatic(nghttp2_session* /* session */,
400 const nghttp2_frame* frame,
401 void* userData)
402 {
Ed Tanous62598e32023-07-17 17:06:25 -0700403 BMCWEB_LOG_DEBUG("on_begin_headers_callback");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800404 if (userData == nullptr)
405 {
Ed Tanous62598e32023-07-17 17:06:25 -0700406 BMCWEB_LOG_CRITICAL("user data was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800407 return NGHTTP2_ERR_CALLBACK_FAILURE;
408 }
409 if (frame == nullptr)
410 {
Ed Tanous62598e32023-07-17 17:06:25 -0700411 BMCWEB_LOG_CRITICAL("frame was null?");
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800412 return NGHTTP2_ERR_CALLBACK_FAILURE;
413 }
414 return userPtrToSelf(userData).onBeginHeadersCallback(*frame);
415 }
416
417 static void afterWriteBuffer(const std::shared_ptr<self_type>& self,
418 const boost::system::error_code& ec,
419 size_t sendLength)
420 {
421 self->isWriting = false;
Ed Tanous62598e32023-07-17 17:06:25 -0700422 BMCWEB_LOG_DEBUG("Sent {}", sendLength);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800423 if (ec)
424 {
425 self->close();
426 return;
427 }
428 self->sendBuffer.consume(sendLength);
429 self->writeBuffer();
430 }
431
432 void writeBuffer()
433 {
434 if (isWriting)
435 {
436 return;
437 }
438 if (sendBuffer.size() <= 0)
439 {
440 return;
441 }
442 isWriting = true;
443 adaptor.async_write_some(
444 sendBuffer.data(),
445 std::bind_front(afterWriteBuffer, shared_from_this()));
446 }
447
448 ssize_t onSendCallback(nghttp2_session* /*session */, const uint8_t* data,
449 size_t length, int /* flags */)
450 {
Ed Tanous62598e32023-07-17 17:06:25 -0700451 BMCWEB_LOG_DEBUG("On send callback size={}", length);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800452 size_t copied = boost::asio::buffer_copy(
453 sendBuffer.prepare(length), boost::asio::buffer(data, length));
454 sendBuffer.commit(copied);
455 writeBuffer();
456 return static_cast<ssize_t>(length);
457 }
458
459 static ssize_t onSendCallbackStatic(nghttp2_session* session,
460 const uint8_t* data, size_t length,
461 int flags /* flags */, void* userData)
462 {
463 return userPtrToSelf(userData).onSendCallback(session, data, length,
464 flags);
465 }
466
467 void close()
468 {
469 if constexpr (std::is_same_v<Adaptor,
470 boost::beast::ssl_stream<
471 boost::asio::ip::tcp::socket>>)
472 {
473 adaptor.next_layer().close();
474 }
475 else
476 {
477 adaptor.close();
478 }
479 }
480
481 void doRead()
482 {
Ed Tanous62598e32023-07-17 17:06:25 -0700483 BMCWEB_LOG_DEBUG("{} doRead", logPtr(this));
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800484 adaptor.async_read_some(
485 inBuffer.prepare(8192),
486 [this, self(shared_from_this())](
487 const boost::system::error_code& ec, size_t bytesTransferred) {
Ed Tanous62598e32023-07-17 17:06:25 -0700488 BMCWEB_LOG_DEBUG("{} async_read_some {} Bytes", logPtr(this),
489 bytesTransferred);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800490
491 if (ec)
492 {
Ed Tanous62598e32023-07-17 17:06:25 -0700493 BMCWEB_LOG_ERROR("{} Error while reading: {}", logPtr(this),
494 ec.message());
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800495 close();
Ed Tanous62598e32023-07-17 17:06:25 -0700496 BMCWEB_LOG_DEBUG("{} from read(1)", logPtr(this));
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800497 return;
498 }
499 inBuffer.commit(bytesTransferred);
500
501 size_t consumed = 0;
502 for (const auto bufferIt : inBuffer.data())
503 {
504 std::span<const uint8_t> bufferSpan{
505 std::bit_cast<const uint8_t*>(bufferIt.data()),
506 bufferIt.size()};
Ed Tanous62598e32023-07-17 17:06:25 -0700507 BMCWEB_LOG_DEBUG("http2 is getting {} bytes",
508 bufferSpan.size());
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800509 ssize_t readLen = ngSession.memRecv(bufferSpan);
510 if (readLen <= 0)
511 {
Ed Tanous62598e32023-07-17 17:06:25 -0700512 BMCWEB_LOG_ERROR("nghttp2_session_mem_recv returned {}",
513 readLen);
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800514 close();
515 return;
516 }
517 consumed += static_cast<size_t>(readLen);
518 }
519 inBuffer.consume(consumed);
520
521 doRead();
522 });
523 }
524
525 // A mapping from http2 stream ID to Stream Data
Ed Tanousf42e8592023-08-25 10:47:44 -0700526 boost::container::flat_map<int32_t, Http2StreamData> streams;
Ed Tanousfca2cbe2021-01-28 14:49:59 -0800527
528 boost::beast::multi_buffer sendBuffer;
529 boost::beast::multi_buffer inBuffer;
530
531 Adaptor adaptor;
532 bool isWriting = false;
533
534 nghttp2_session ngSession;
535
536 Handler* handler;
537 std::function<std::string()>& getCachedDateStr;
538
539 using std::enable_shared_from_this<
540 HTTP2Connection<Adaptor, Handler>>::shared_from_this;
541
542 using std::enable_shared_from_this<
543 HTTP2Connection<Adaptor, Handler>>::weak_from_this;
544};
545} // namespace crow