blob: 1a8f6cdca910ca2c798f5f011afc83963c884030 [file] [log] [blame]
Ed Tanous7045c8d2017-04-03 10:04:37 -07001#pragma once
Adriana Kobylak0e1cf262019-12-05 13:57:57 -06002#include "config.h"
3
Ed Tanous1abe55e2018-09-05 08:30:59 -07004#include "http_utility.hpp"
5
Ed Tanouse0d918b2018-03-27 17:41:04 -07006#include <boost/algorithm/string.hpp>
Ed Tanous257f5792018-03-17 14:40:09 -07007#include <boost/algorithm/string/predicate.hpp>
Ed Tanous8f626352018-12-19 14:51:54 -08008#include <boost/asio/io_context.hpp>
Ed Tanous3112a142018-11-29 15:45:10 -08009#include <boost/asio/ip/tcp.hpp>
Ed Tanous2f1ebcd2019-02-13 19:39:07 -080010#include <boost/asio/ssl.hpp>
Ed Tanous3112a142018-11-29 15:45:10 -080011#include <boost/beast/core/flat_static_buffer.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050012
13#include <atomic>
Ed Tanouse278c182019-03-13 16:23:37 -070014#if BOOST_VERSION >= 107000
15#include <boost/beast/ssl/ssl_stream.hpp>
16#else
Ed Tanous2f1ebcd2019-02-13 19:39:07 -080017#include <boost/beast/experimental/core/ssl_stream.hpp>
Ed Tanouse278c182019-03-13 16:23:37 -070018#endif
Ed Tanousc94ad492019-10-10 15:39:33 -070019#include "http_response.h"
20#include "logging.h"
21#include "middleware_context.h"
22#include "timer_queue.h"
23#include "utility.h"
Ed Tanous7045c8d2017-04-03 10:04:37 -070024
Gunnar Mills1214b7e2020-06-04 10:11:30 -050025#include <boost/beast/http.hpp>
26#include <boost/beast/websocket.hpp>
27#include <ssl_key_handler.hpp>
28
29#include <chrono>
30#include <vector>
31
Ed Tanous1abe55e2018-09-05 08:30:59 -070032namespace crow
33{
Ed Tanous257f5792018-03-17 14:40:09 -070034
Ed Tanous1abe55e2018-09-05 08:30:59 -070035inline void prettyPrintJson(crow::Response& res)
36{
Jason M. Bills193ad2f2018-09-26 15:08:52 -070037 std::string value = res.jsonValue.dump(4, ' ', true);
Ed Tanousa29c9972018-11-29 15:54:32 -080038 utility::escapeHtml(value);
39 utility::convertToLinks(value);
Ed Tanous1abe55e2018-09-05 08:30:59 -070040 res.body() = "<html>\n"
41 "<head>\n"
42 "<title>Redfish API</title>\n"
43 "<link rel=\"stylesheet\" type=\"text/css\" "
44 "href=\"/styles/default.css\">\n"
45 "<script src=\"/highlight.pack.js\"></script>"
46 "<script>hljs.initHighlightingOnLoad();</script>"
47 "</head>\n"
48 "<body>\n"
49 "<div style=\"max-width: 576px;margin:0 auto;\">\n"
50 "<img src=\"/DMTF_Redfish_logo_2017.svg\" alt=\"redfish\" "
51 "height=\"406px\" "
52 "width=\"576px\">\n"
53 "<br>\n"
54 "<pre>\n"
55 "<code class=\"json\">" +
56 value +
57 "</code>\n"
58 "</pre>\n"
59 "</div>\n"
60 "</body>\n"
61 "</html>\n";
Ed Tanous93ef5802019-01-03 10:15:41 -080062 res.addHeader("Content-Type", "text/html;charset=UTF-8");
Ed Tanous257f5792018-03-17 14:40:09 -070063}
64
Ed Tanous7045c8d2017-04-03 10:04:37 -070065using namespace boost;
66using tcp = asio::ip::tcp;
67
Ed Tanous1abe55e2018-09-05 08:30:59 -070068namespace detail
69{
Gunnar Mills1214b7e2020-06-04 10:11:30 -050070template <typename MW>
71struct CheckBeforeHandleArity3Const
Ed Tanous1abe55e2018-09-05 08:30:59 -070072{
73 template <typename T,
74 void (T::*)(Request&, Response&, typename MW::Context&) const =
75 &T::beforeHandle>
76 struct Get
Gunnar Mills1214b7e2020-06-04 10:11:30 -050077 {};
Ed Tanous7045c8d2017-04-03 10:04:37 -070078};
79
Gunnar Mills1214b7e2020-06-04 10:11:30 -050080template <typename MW>
81struct CheckBeforeHandleArity3
Ed Tanous1abe55e2018-09-05 08:30:59 -070082{
83 template <typename T, void (T::*)(Request&, Response&,
84 typename MW::Context&) = &T::beforeHandle>
85 struct Get
Gunnar Mills1214b7e2020-06-04 10:11:30 -050086 {};
Ed Tanous7045c8d2017-04-03 10:04:37 -070087};
88
Gunnar Mills1214b7e2020-06-04 10:11:30 -050089template <typename MW>
90struct CheckAfterHandleArity3Const
Ed Tanous1abe55e2018-09-05 08:30:59 -070091{
92 template <typename T,
93 void (T::*)(Request&, Response&, typename MW::Context&) const =
94 &T::afterHandle>
95 struct Get
Gunnar Mills1214b7e2020-06-04 10:11:30 -050096 {};
Ed Tanous7045c8d2017-04-03 10:04:37 -070097};
98
Gunnar Mills1214b7e2020-06-04 10:11:30 -050099template <typename MW>
100struct CheckAfterHandleArity3
Ed Tanous1abe55e2018-09-05 08:30:59 -0700101{
102 template <typename T, void (T::*)(Request&, Response&,
103 typename MW::Context&) = &T::afterHandle>
104 struct Get
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500105 {};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700106};
107
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500108template <typename T>
109struct IsBeforeHandleArity3Impl
Ed Tanous1abe55e2018-09-05 08:30:59 -0700110{
111 template <typename C>
112 static std::true_type
113 f(typename CheckBeforeHandleArity3Const<T>::template Get<C>*);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700114
Ed Tanous1abe55e2018-09-05 08:30:59 -0700115 template <typename C>
116 static std::true_type
117 f(typename CheckBeforeHandleArity3<T>::template Get<C>*);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700118
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500119 template <typename C>
120 static std::false_type f(...);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700121
Ed Tanous1abe55e2018-09-05 08:30:59 -0700122 public:
Ed Tanous0c838cf2019-10-24 10:01:46 -0700123 static constexpr bool value = decltype(f<T>(nullptr))::value;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700124};
125
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500126template <typename T>
127struct IsAfterHandleArity3Impl
Ed Tanous1abe55e2018-09-05 08:30:59 -0700128{
129 template <typename C>
130 static std::true_type
131 f(typename CheckAfterHandleArity3Const<T>::template Get<C>*);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700132
Ed Tanous1abe55e2018-09-05 08:30:59 -0700133 template <typename C>
134 static std::true_type
135 f(typename CheckAfterHandleArity3<T>::template Get<C>*);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700136
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500137 template <typename C>
138 static std::false_type f(...);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700139
Ed Tanous1abe55e2018-09-05 08:30:59 -0700140 public:
Ed Tanous0c838cf2019-10-24 10:01:46 -0700141 static constexpr bool value = decltype(f<T>(nullptr))::value;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700142};
143
144template <typename MW, typename Context, typename ParentContext>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700145typename std::enable_if<!IsBeforeHandleArity3Impl<MW>::value>::type
Ed Tanous1abe55e2018-09-05 08:30:59 -0700146 beforeHandlerCall(MW& mw, Request& req, Response& res, Context& ctx,
147 ParentContext& /*parent_ctx*/)
148{
149 mw.beforeHandle(req, res, ctx.template get<MW>(), ctx);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700150}
151
152template <typename MW, typename Context, typename ParentContext>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700153typename std::enable_if<IsBeforeHandleArity3Impl<MW>::value>::type
Ed Tanous1abe55e2018-09-05 08:30:59 -0700154 beforeHandlerCall(MW& mw, Request& req, Response& res, Context& ctx,
155 ParentContext& /*parent_ctx*/)
156{
157 mw.beforeHandle(req, res, ctx.template get<MW>());
Ed Tanous7045c8d2017-04-03 10:04:37 -0700158}
159
160template <typename MW, typename Context, typename ParentContext>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700161typename std::enable_if<!IsAfterHandleArity3Impl<MW>::value>::type
Ed Tanous1abe55e2018-09-05 08:30:59 -0700162 afterHandlerCall(MW& mw, Request& req, Response& res, Context& ctx,
163 ParentContext& /*parent_ctx*/)
164{
165 mw.afterHandle(req, res, ctx.template get<MW>(), ctx);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700166}
167
168template <typename MW, typename Context, typename ParentContext>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700169typename std::enable_if<IsAfterHandleArity3Impl<MW>::value>::type
Ed Tanous1abe55e2018-09-05 08:30:59 -0700170 afterHandlerCall(MW& mw, Request& req, Response& res, Context& ctx,
171 ParentContext& /*parent_ctx*/)
172{
173 mw.afterHandle(req, res, ctx.template get<MW>());
Ed Tanous7045c8d2017-04-03 10:04:37 -0700174}
175
Ed Tanous271584a2019-07-09 16:24:22 -0700176template <size_t N, typename Context, typename Container, typename CurrentMW,
Ed Tanous7045c8d2017-04-03 10:04:37 -0700177 typename... Middlewares>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700178bool middlewareCallHelper(Container& middlewares, Request& req, Response& res,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700179 Context& ctx)
180{
181 using parent_context_t = typename Context::template partial<N - 1>;
182 beforeHandlerCall<CurrentMW, Context, parent_context_t>(
Ed Tanous7045c8d2017-04-03 10:04:37 -0700183 std::get<N>(middlewares), req, res, ctx,
184 static_cast<parent_context_t&>(ctx));
Ed Tanous7045c8d2017-04-03 10:04:37 -0700185
Ed Tanous1abe55e2018-09-05 08:30:59 -0700186 if (res.isCompleted())
187 {
188 afterHandlerCall<CurrentMW, Context, parent_context_t>(
189 std::get<N>(middlewares), req, res, ctx,
190 static_cast<parent_context_t&>(ctx));
191 return true;
192 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700193
Ed Tanous1abe55e2018-09-05 08:30:59 -0700194 if (middlewareCallHelper<N + 1, Context, Container, Middlewares...>(
195 middlewares, req, res, ctx))
196 {
197 afterHandlerCall<CurrentMW, Context, parent_context_t>(
198 std::get<N>(middlewares), req, res, ctx,
199 static_cast<parent_context_t&>(ctx));
200 return true;
201 }
202
203 return false;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700204}
205
Ed Tanous271584a2019-07-09 16:24:22 -0700206template <size_t N, typename Context, typename Container>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700207bool middlewareCallHelper(Container& /*middlewares*/, Request& /*req*/,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700208 Response& /*res*/, Context& /*ctx*/)
209{
210 return false;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700211}
212
Ed Tanous271584a2019-07-09 16:24:22 -0700213template <size_t N, typename Context, typename Container>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700214typename std::enable_if<(N < 0)>::type
215 afterHandlersCallHelper(Container& /*middlewares*/, Context& /*Context*/,
216 Request& /*req*/, Response& /*res*/)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500217{}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700218
Ed Tanous271584a2019-07-09 16:24:22 -0700219template <size_t N, typename Context, typename Container>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700220typename std::enable_if<(N == 0)>::type
221 afterHandlersCallHelper(Container& middlewares, Context& ctx, Request& req,
222 Response& res)
223{
224 using parent_context_t = typename Context::template partial<N - 1>;
225 using CurrentMW = typename std::tuple_element<
226 N, typename std::remove_reference<Container>::type>::type;
227 afterHandlerCall<CurrentMW, Context, parent_context_t>(
228 std::get<N>(middlewares), req, res, ctx,
229 static_cast<parent_context_t&>(ctx));
Ed Tanous7045c8d2017-04-03 10:04:37 -0700230}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700231
Ed Tanous271584a2019-07-09 16:24:22 -0700232template <size_t N, typename Context, typename Container>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700233typename std::enable_if<(N > 0)>::type
234 afterHandlersCallHelper(Container& middlewares, Context& ctx, Request& req,
235 Response& res)
236{
237 using parent_context_t = typename Context::template partial<N - 1>;
238 using CurrentMW = typename std::tuple_element<
239 N, typename std::remove_reference<Container>::type>::type;
240 afterHandlerCall<CurrentMW, Context, parent_context_t>(
241 std::get<N>(middlewares), req, res, ctx,
242 static_cast<parent_context_t&>(ctx));
243 afterHandlersCallHelper<N - 1, Context, Container>(middlewares, ctx, req,
244 res);
245}
246} // namespace detail
Ed Tanous7045c8d2017-04-03 10:04:37 -0700247
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700248#ifdef BMCWEB_ENABLE_DEBUG
Ed Tanouse0d918b2018-03-27 17:41:04 -0700249static std::atomic<int> connectionCount;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700250#endif
Jennifer Leeacb7cfb2018-06-07 16:08:15 -0700251
Adriana Kobylak0e1cf262019-12-05 13:57:57 -0600252// request body limit size set by the BMCWEB_HTTP_REQ_BODY_LIMIT_MB option
253constexpr unsigned int httpReqBodyLimit =
254 1024 * 1024 * BMCWEB_HTTP_REQ_BODY_LIMIT_MB;
Jennifer Leeacb7cfb2018-06-07 16:08:15 -0700255
Ed Tanous7045c8d2017-04-03 10:04:37 -0700256template <typename Adaptor, typename Handler, typename... Middlewares>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500257class Connection :
258 public std::enable_shared_from_this<
259 Connection<Adaptor, Handler, Middlewares...>>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700260{
261 public:
Ed Tanous271584a2019-07-09 16:24:22 -0700262 Connection(boost::asio::io_context& ioService, Handler* handlerIn,
263 const std::string& ServerNameIn,
264 std::tuple<Middlewares...>* middlewaresIn,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700265 std::function<std::string()>& get_cached_date_str_f,
Ed Tanous271584a2019-07-09 16:24:22 -0700266 detail::TimerQueue& timerQueueIn, Adaptor adaptorIn) :
Ed Tanousceac6f72018-12-02 11:58:47 -0800267 adaptor(std::move(adaptorIn)),
Ed Tanous271584a2019-07-09 16:24:22 -0700268 handler(handlerIn), serverName(ServerNameIn),
269 middlewares(middlewaresIn), getCachedDateStr(get_cached_date_str_f),
270 timerQueue(timerQueueIn)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700271 {
272 parser.emplace(std::piecewise_construct, std::make_tuple());
Adriana Kobylak0e1cf262019-12-05 13:57:57 -0600273 // Temporarily set by the BMCWEB_HTTP_REQ_BODY_LIMIT_MB variable; Need
274 // to modify uploading/authentication mechanism to a better method that
275 // disallows a DOS attack based on a large file size.
Ed Tanous1abe55e2018-09-05 08:30:59 -0700276 parser->body_limit(httpReqBodyLimit);
277 req.emplace(parser->get());
Kowalski, Kamil55e43f62019-07-10 13:12:57 +0200278
279#ifdef BMCWEB_ENABLE_MUTUAL_TLS_AUTHENTICATION
Zbigniew Kurzynski009c2a42019-11-14 13:37:15 +0100280 auto ca_available = !std::filesystem::is_empty(
281 std::filesystem::path(ensuressl::trustStorePath));
282 if (ca_available && crow::persistent_data::SessionStore::getInstance()
283 .getAuthMethodsConfig()
284 .tls)
285 {
286 adaptor.set_verify_mode(boost::asio::ssl::verify_peer);
287 SSL_set_session_id_context(
288 adaptor.native_handle(),
289 reinterpret_cast<const unsigned char*>(serverName.c_str()),
Zbigniew Kurzynskicac94c52019-11-07 12:55:04 +0100290 static_cast<unsigned int>(serverName.length()));
Zbigniew Kurzynski009c2a42019-11-14 13:37:15 +0100291 BMCWEB_LOG_DEBUG << this << " TLS is enabled on this connection.";
292 }
293
Zbigniew Kurzynski2658d982019-11-19 18:01:08 +0100294 adaptor.set_verify_callback([this](
295 bool preverified,
296 boost::asio::ssl::verify_context& ctx) {
297 // do nothing if TLS is disabled
298 if (!crow::persistent_data::SessionStore::getInstance()
299 .getAuthMethodsConfig()
300 .tls)
301 {
302 BMCWEB_LOG_DEBUG << this << " TLS auth_config is disabled";
Kowalski, Kamil55e43f62019-07-10 13:12:57 +0200303 return true;
Zbigniew Kurzynski2658d982019-11-19 18:01:08 +0100304 }
305
306 // We always return true to allow full auth flow
307 if (!preverified)
308 {
Zbigniew Kurzynski009c2a42019-11-14 13:37:15 +0100309 BMCWEB_LOG_DEBUG << this << " TLS preverification failed.";
Zbigniew Kurzynski2658d982019-11-19 18:01:08 +0100310 return true;
311 }
312
313 X509_STORE_CTX* cts = ctx.native_handle();
314 if (cts == nullptr)
315 {
Zbigniew Kurzynski009c2a42019-11-14 13:37:15 +0100316 BMCWEB_LOG_DEBUG << this << " Cannot get native TLS handle.";
Zbigniew Kurzynski2658d982019-11-19 18:01:08 +0100317 return true;
318 }
319
320 // Get certificate
321 X509* peerCert =
322 X509_STORE_CTX_get_current_cert(ctx.native_handle());
323 if (peerCert == nullptr)
324 {
Zbigniew Kurzynski009c2a42019-11-14 13:37:15 +0100325 BMCWEB_LOG_DEBUG << this
326 << " Cannot get current TLS certificate.";
Zbigniew Kurzynski2658d982019-11-19 18:01:08 +0100327 return true;
328 }
329
330 // Check if certificate is OK
331 int error = X509_STORE_CTX_get_error(cts);
332 if (error != X509_V_OK)
333 {
Zbigniew Kurzynski009c2a42019-11-14 13:37:15 +0100334 BMCWEB_LOG_INFO << this << " Last TLS error is: " << error;
Zbigniew Kurzynski2658d982019-11-19 18:01:08 +0100335 return true;
336 }
337 // Check that we have reached final certificate in chain
338 int32_t depth = X509_STORE_CTX_get_error_depth(cts);
339 if (depth != 0)
340
341 {
342 BMCWEB_LOG_DEBUG
343 << this << " Certificate verification in progress (depth "
344 << depth << "), waiting to reach final depth";
345 return true;
346 }
347
348 BMCWEB_LOG_DEBUG << this
349 << " Certificate verification of final depth";
350
351 // Verify KeyUsage
352 bool isKeyUsageDigitalSignature = false;
353 bool isKeyUsageKeyAgreement = false;
354
355 ASN1_BIT_STRING* usage = static_cast<ASN1_BIT_STRING*>(
356 X509_get_ext_d2i(peerCert, NID_key_usage, NULL, NULL));
357
358 if (usage == nullptr)
359 {
Zbigniew Kurzynski009c2a42019-11-14 13:37:15 +0100360 BMCWEB_LOG_DEBUG << this << " TLS usage is null";
Zbigniew Kurzynski2658d982019-11-19 18:01:08 +0100361 return true;
362 }
363
364 for (int i = 0; i < usage->length; i++)
365 {
366 if (KU_DIGITAL_SIGNATURE & usage->data[i])
367 {
368 isKeyUsageDigitalSignature = true;
369 }
370 if (KU_KEY_AGREEMENT & usage->data[i])
371 {
372 isKeyUsageKeyAgreement = true;
373 }
374 }
375
376 if (!isKeyUsageDigitalSignature || !isKeyUsageKeyAgreement)
377 {
378 BMCWEB_LOG_DEBUG << this
379 << " Certificate ExtendedKeyUsage does "
380 "not allow provided certificate to "
381 "be used for user authentication";
382 return true;
383 }
Zbigniew Kurzynski09d02f82020-03-30 13:41:42 +0200384 ASN1_BIT_STRING_free(usage);
Zbigniew Kurzynski2658d982019-11-19 18:01:08 +0100385
386 // Determine that ExtendedKeyUsage includes Client Auth
387
388 stack_st_ASN1_OBJECT* extUsage = static_cast<stack_st_ASN1_OBJECT*>(
389 X509_get_ext_d2i(peerCert, NID_ext_key_usage, NULL, NULL));
390
391 if (extUsage == nullptr)
392 {
Zbigniew Kurzynski009c2a42019-11-14 13:37:15 +0100393 BMCWEB_LOG_DEBUG << this << " TLS extUsage is null";
Zbigniew Kurzynski2658d982019-11-19 18:01:08 +0100394 return true;
395 }
396
397 bool isExKeyUsageClientAuth = false;
398 for (int i = 0; i < sk_ASN1_OBJECT_num(extUsage); i++)
399 {
400 if (NID_client_auth ==
401 OBJ_obj2nid(sk_ASN1_OBJECT_value(extUsage, i)))
402 {
403 isExKeyUsageClientAuth = true;
404 break;
405 }
406 }
Zbigniew Kurzynski09d02f82020-03-30 13:41:42 +0200407 sk_ASN1_OBJECT_free(extUsage);
Zbigniew Kurzynski2658d982019-11-19 18:01:08 +0100408
409 // Certificate has to have proper key usages set
410 if (!isExKeyUsageClientAuth)
411 {
412 BMCWEB_LOG_DEBUG << this
413 << " Certificate ExtendedKeyUsage does "
414 "not allow provided certificate to "
415 "be used for user authentication";
416 return true;
417 }
418 std::string sslUser;
419 // Extract username contained in CommonName
420 sslUser.resize(256, '\0');
421
422 int status = X509_NAME_get_text_by_NID(
423 X509_get_subject_name(peerCert), NID_commonName, sslUser.data(),
424 static_cast<int>(sslUser.size()));
425
426 if (status == -1)
427 {
Zbigniew Kurzynski009c2a42019-11-14 13:37:15 +0100428 BMCWEB_LOG_DEBUG
429 << this << " TLS cannot get username to create session";
Zbigniew Kurzynski2658d982019-11-19 18:01:08 +0100430 return true;
431 }
432
433 size_t lastChar = sslUser.find('\0');
434 if (lastChar == std::string::npos || lastChar == 0)
435 {
Zbigniew Kurzynski009c2a42019-11-14 13:37:15 +0100436 BMCWEB_LOG_DEBUG << this << " Invalid TLS user name";
Zbigniew Kurzynski2658d982019-11-19 18:01:08 +0100437 return true;
438 }
439 sslUser.resize(lastChar);
440
441 session = persistent_data::SessionStore::getInstance()
442 .generateUserSession(
443 sslUser,
444 crow::persistent_data::PersistenceType::TIMEOUT);
Zbigniew Kurzynski009c2a42019-11-14 13:37:15 +0100445 if (auto sp = session.lock())
446 {
447 BMCWEB_LOG_DEBUG << this
448 << " Generating TLS session: " << sp->uniqueId;
449 }
Zbigniew Kurzynski2658d982019-11-19 18:01:08 +0100450 return true;
451 });
Kowalski, Kamil55e43f62019-07-10 13:12:57 +0200452#endif // BMCWEB_ENABLE_MUTUAL_TLS_AUTHENTICATION
453
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700454#ifdef BMCWEB_ENABLE_DEBUG
Ed Tanous1abe55e2018-09-05 08:30:59 -0700455 connectionCount++;
456 BMCWEB_LOG_DEBUG << this << " Connection open, total "
457 << connectionCount;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700458#endif
Ed Tanous1abe55e2018-09-05 08:30:59 -0700459 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700460
Ed Tanous1abe55e2018-09-05 08:30:59 -0700461 ~Connection()
462 {
463 res.completeRequestHandler = nullptr;
464 cancelDeadlineTimer();
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700465#ifdef BMCWEB_ENABLE_DEBUG
Ed Tanous1abe55e2018-09-05 08:30:59 -0700466 connectionCount--;
467 BMCWEB_LOG_DEBUG << this << " Connection closed, total "
468 << connectionCount;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700469#endif
Ed Tanous7045c8d2017-04-03 10:04:37 -0700470 }
471
Ed Tanousceac6f72018-12-02 11:58:47 -0800472 Adaptor& socket()
Ed Tanous1abe55e2018-09-05 08:30:59 -0700473 {
Ed Tanousceac6f72018-12-02 11:58:47 -0800474 return adaptor;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700475 }
476
Ed Tanous1abe55e2018-09-05 08:30:59 -0700477 void start()
478 {
Ed Tanous7045c8d2017-04-03 10:04:37 -0700479
Ed Tanousceac6f72018-12-02 11:58:47 -0800480 startDeadline();
481 // TODO(ed) Abstract this to a more clever class with the idea of an
482 // asynchronous "start"
483 if constexpr (std::is_same_v<Adaptor,
484 boost::beast::ssl_stream<
485 boost::asio::ip::tcp::socket>>)
486 {
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000487 adaptor.async_handshake(boost::asio::ssl::stream_base::server,
488 [this, self(shared_from_this())](
489 const boost::system::error_code& ec) {
490 if (ec)
491 {
492 return;
493 }
494 doReadHeaders();
495 });
Ed Tanousceac6f72018-12-02 11:58:47 -0800496 }
497 else
498 {
499 doReadHeaders();
500 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700501 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700502
Ed Tanous1abe55e2018-09-05 08:30:59 -0700503 void handle()
504 {
505 cancelDeadlineTimer();
506 bool isInvalidRequest = false;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700507
Ed Tanous1abe55e2018-09-05 08:30:59 -0700508 // Check for HTTP version 1.1.
509 if (req->version() == 11)
510 {
511 if (req->getHeaderValue(boost::beast::http::field::host).empty())
512 {
513 isInvalidRequest = true;
Ed Tanousde5c9f32019-03-26 09:17:55 -0700514 res.result(boost::beast::http::status::bad_request);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700515 }
516 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700517
Ed Tanouse278c182019-03-13 16:23:37 -0700518 BMCWEB_LOG_INFO << "Request: "
519 << " " << this << " HTTP/" << req->version() / 10 << "."
520 << req->version() % 10 << ' ' << req->methodString()
521 << " " << req->target();
Ed Tanous7045c8d2017-04-03 10:04:37 -0700522
Ed Tanous1abe55e2018-09-05 08:30:59 -0700523 needToCallAfterHandlers = false;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700524
Ed Tanous1abe55e2018-09-05 08:30:59 -0700525 if (!isInvalidRequest)
526 {
raviteja-b4722efe2020-02-03 12:23:18 -0600527 req->socket = [this, self = shared_from_this()]() -> Adaptor& {
528 return self->socket();
529 };
530
Ed Tanous1abe55e2018-09-05 08:30:59 -0700531 res.completeRequestHandler = [] {};
Ed Tanouse278c182019-03-13 16:23:37 -0700532 res.isAliveHelper = [this]() -> bool { return isAlive(); };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700533
Ed Tanous1abe55e2018-09-05 08:30:59 -0700534 ctx = detail::Context<Middlewares...>();
Ed Tanouse278c182019-03-13 16:23:37 -0700535 req->middlewareContext = static_cast<void*>(&ctx);
536 req->ioService = static_cast<decltype(req->ioService)>(
537 &adaptor.get_executor().context());
Kowalski, Kamil55e43f62019-07-10 13:12:57 +0200538
539#ifdef BMCWEB_ENABLE_MUTUAL_TLS_AUTHENTICATION
540 if (auto sp = session.lock())
541 {
Zbigniew Kurzynski009c2a42019-11-14 13:37:15 +0100542 // set cookie only if this is req from the browser.
543 if (req->getHeaderValue("User-Agent").empty())
544 {
545 BMCWEB_LOG_DEBUG << this << " TLS session: " << sp->uniqueId
546 << " will be used for this request.";
547 req->session = sp;
548 }
549 else
550 {
551 std::string_view cookieValue =
552 req->getHeaderValue("Cookie");
553 if (cookieValue.empty() ||
554 cookieValue.find("SESSION=") == std::string::npos)
555 {
556 res.addHeader("Set-Cookie",
557 "XSRF-TOKEN=" + sp->csrfToken +
558 "; Secure\r\nSet-Cookie: SESSION=" +
559 sp->sessionToken +
Zbigniew Kurzynski26139a52019-12-11 19:11:18 +0100560 "; Secure; HttpOnly\r\nSet-Cookie: "
561 "IsAuthenticated=true; Secure");
Zbigniew Kurzynski009c2a42019-11-14 13:37:15 +0100562 BMCWEB_LOG_DEBUG
563 << this << " TLS session: " << sp->uniqueId
564 << " with cookie will be used for this request.";
565 req->session = sp;
566 }
567 }
Kowalski, Kamil55e43f62019-07-10 13:12:57 +0200568 }
569#endif // BMCWEB_ENABLE_MUTUAL_TLS_AUTHENTICATION
570
Ed Tanous1abe55e2018-09-05 08:30:59 -0700571 detail::middlewareCallHelper<
Ed Tanous271584a2019-07-09 16:24:22 -0700572 0U, decltype(ctx), decltype(*middlewares), Middlewares...>(
Ed Tanous1abe55e2018-09-05 08:30:59 -0700573 *middlewares, *req, res, ctx);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700574
Ed Tanous1abe55e2018-09-05 08:30:59 -0700575 if (!res.completed)
576 {
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000577 needToCallAfterHandlers = true;
578 res.completeRequestHandler = [self(shared_from_this())] {
579 self->completeRequest();
580 };
Ed Tanous1abe55e2018-09-05 08:30:59 -0700581 if (req->isUpgrade() &&
582 boost::iequals(
583 req->getHeaderValue(boost::beast::http::field::upgrade),
584 "websocket"))
585 {
586 handler->handleUpgrade(*req, res, std::move(adaptor));
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000587 // delete lambda with self shared_ptr
588 // to enable connection destruction
589 res.completeRequestHandler = nullptr;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700590 return;
591 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700592 handler->handle(*req, res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700593 }
594 else
595 {
596 completeRequest();
597 }
598 }
599 else
600 {
601 completeRequest();
602 }
603 }
Ed Tanouse0d918b2018-03-27 17:41:04 -0700604
Ed Tanouse278c182019-03-13 16:23:37 -0700605 bool isAlive()
606 {
607
608 if constexpr (std::is_same_v<Adaptor,
609 boost::beast::ssl_stream<
610 boost::asio::ip::tcp::socket>>)
611 {
612 return adaptor.next_layer().is_open();
613 }
614 else
615 {
616 return adaptor.is_open();
617 }
618 }
619 void close()
620 {
Ed Tanouse278c182019-03-13 16:23:37 -0700621 if constexpr (std::is_same_v<Adaptor,
622 boost::beast::ssl_stream<
623 boost::asio::ip::tcp::socket>>)
624 {
625 adaptor.next_layer().close();
Kowalski, Kamil55e43f62019-07-10 13:12:57 +0200626#ifdef BMCWEB_ENABLE_MUTUAL_TLS_AUTHENTICATION
627 if (auto sp = session.lock())
628 {
Zbigniew Kurzynski009c2a42019-11-14 13:37:15 +0100629 BMCWEB_LOG_DEBUG << this
630 << " Removing TLS session: " << sp->uniqueId;
Kowalski, Kamil55e43f62019-07-10 13:12:57 +0200631 persistent_data::SessionStore::getInstance().removeSession(sp);
632 }
633#endif // BMCWEB_ENABLE_MUTUAL_TLS_AUTHENTICATION
Ed Tanouse278c182019-03-13 16:23:37 -0700634 }
635 else
636 {
637 adaptor.close();
638 }
639 }
640
Ed Tanous1abe55e2018-09-05 08:30:59 -0700641 void completeRequest()
642 {
643 BMCWEB_LOG_INFO << "Response: " << this << ' ' << req->url << ' '
644 << res.resultInt() << " keepalive=" << req->keepAlive();
Ed Tanous7045c8d2017-04-03 10:04:37 -0700645
Ed Tanous1abe55e2018-09-05 08:30:59 -0700646 if (needToCallAfterHandlers)
647 {
648 needToCallAfterHandlers = false;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700649
Ed Tanous1abe55e2018-09-05 08:30:59 -0700650 // call all afterHandler of middlewares
Ed Tanous271584a2019-07-09 16:24:22 -0700651 detail::afterHandlersCallHelper<sizeof...(Middlewares) - 1,
Ed Tanousb01bf292019-03-25 19:25:26 +0000652 decltype(ctx),
653 decltype(*middlewares)>(
654 *middlewares, ctx, *req, res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700655 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700656
Ed Tanouse278c182019-03-13 16:23:37 -0700657 if (!isAlive())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700658 {
659 // BMCWEB_LOG_DEBUG << this << " delete (socket is closed) " <<
660 // isReading
661 // << ' ' << isWriting;
662 // delete this;
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000663
664 // delete lambda with self shared_ptr
665 // to enable connection destruction
666 res.completeRequestHandler = nullptr;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700667 return;
668 }
669 if (res.body().empty() && !res.jsonValue.empty())
670 {
671 if (http_helpers::requestPrefersHtml(*req))
672 {
673 prettyPrintJson(res);
674 }
675 else
676 {
677 res.jsonMode();
Jason M. Bills193ad2f2018-09-26 15:08:52 -0700678 res.body() = res.jsonValue.dump(2, ' ', true);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700679 }
680 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700681
Ed Tanous1abe55e2018-09-05 08:30:59 -0700682 if (res.resultInt() >= 400 && res.body().empty())
683 {
684 res.body() = std::string(res.reason());
685 }
Ed Tanous6295bec2019-09-03 10:11:01 -0700686
687 if (res.result() == boost::beast::http::status::no_content)
688 {
689 // Boost beast throws if content is provided on a no-content
690 // response. Ideally, this would never happen, but in the case that
691 // it does, we don't want to throw.
692 BMCWEB_LOG_CRITICAL
Zbigniew Kurzynski2658d982019-11-19 18:01:08 +0100693 << this << " Response content provided but code was no-content";
Ed Tanous6295bec2019-09-03 10:11:01 -0700694 res.body().clear();
695 }
696
Ed Tanous1abe55e2018-09-05 08:30:59 -0700697 res.addHeader(boost::beast::http::field::server, serverName);
698 res.addHeader(boost::beast::http::field::date, getCachedDateStr());
699
700 res.keepAlive(req->keepAlive());
701
702 doWrite();
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000703
704 // delete lambda with self shared_ptr
705 // to enable connection destruction
706 res.completeRequestHandler = nullptr;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700707 }
708
709 private:
710 void doReadHeaders()
711 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700712 BMCWEB_LOG_DEBUG << this << " doReadHeaders";
713
714 // Clean up any previous Connection.
715 boost::beast::http::async_read_header(
Ed Tanousceac6f72018-12-02 11:58:47 -0800716 adaptor, buffer, *parser,
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000717 [this,
718 self(shared_from_this())](const boost::system::error_code& ec,
719 std::size_t bytes_transferred) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700720 BMCWEB_LOG_ERROR << this << " async_read_header "
721 << bytes_transferred << " Bytes";
722 bool errorWhileReading = false;
723 if (ec)
724 {
725 errorWhileReading = true;
726 BMCWEB_LOG_ERROR
727 << this << " Error while reading: " << ec.message();
728 }
729 else
730 {
731 // if the adaptor isn't open anymore, and wasn't handed to a
732 // websocket, treat as an error
Ed Tanouse278c182019-03-13 16:23:37 -0700733 if (!isAlive() && !req->isUpgrade())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700734 {
735 errorWhileReading = true;
736 }
737 }
738
739 if (errorWhileReading)
740 {
741 cancelDeadlineTimer();
Ed Tanouse278c182019-03-13 16:23:37 -0700742 close();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700743 BMCWEB_LOG_DEBUG << this << " from read(1)";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700744 return;
745 }
746
747 // Compute the url parameters for the request
748 req->url = req->target();
749 std::size_t index = req->url.find("?");
Ed Tanous39e77502019-03-04 17:35:53 -0800750 if (index != std::string_view::npos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700751 {
Jason M. Bills43fcbe52018-10-16 15:19:20 -0700752 req->url = req->url.substr(0, index);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700753 }
754 req->urlParams = QueryString(std::string(req->target()));
755 doRead();
756 });
757 }
758
759 void doRead()
760 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700761 BMCWEB_LOG_DEBUG << this << " doRead";
762
763 boost::beast::http::async_read(
Ed Tanousceac6f72018-12-02 11:58:47 -0800764 adaptor, buffer, *parser,
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000765 [this,
766 self(shared_from_this())](const boost::system::error_code& ec,
767 std::size_t bytes_transferred) {
Zbigniew Kurzynski2658d982019-11-19 18:01:08 +0100768 BMCWEB_LOG_DEBUG << this << " async_read " << bytes_transferred
Ed Tanous1abe55e2018-09-05 08:30:59 -0700769 << " Bytes";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700770
771 bool errorWhileReading = false;
772 if (ec)
773 {
Zbigniew Kurzynski2658d982019-11-19 18:01:08 +0100774 BMCWEB_LOG_ERROR
775 << this << " Error while reading: " << ec.message();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700776 errorWhileReading = true;
777 }
778 else
779 {
Ed Tanouse278c182019-03-13 16:23:37 -0700780 if (!isAlive())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700781 {
782 errorWhileReading = true;
783 }
784 }
785 if (errorWhileReading)
786 {
787 cancelDeadlineTimer();
Ed Tanouse278c182019-03-13 16:23:37 -0700788 close();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700789 BMCWEB_LOG_DEBUG << this << " from read(1)";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700790 return;
791 }
792 handle();
793 });
794 }
795
796 void doWrite()
797 {
Zbigniew Kurzynski2658d982019-11-19 18:01:08 +0100798 BMCWEB_LOG_DEBUG << this << " doWrite";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700799 res.preparePayload();
800 serializer.emplace(*res.stringResponse);
801 boost::beast::http::async_write(
Ed Tanousceac6f72018-12-02 11:58:47 -0800802 adaptor, *serializer,
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000803 [this,
804 self(shared_from_this())](const boost::system::error_code& ec,
805 std::size_t bytes_transferred) {
Zbigniew Kurzynski2658d982019-11-19 18:01:08 +0100806 BMCWEB_LOG_DEBUG << this << " async_write " << bytes_transferred
Ed Tanous1abe55e2018-09-05 08:30:59 -0700807 << " bytes";
808
809 if (ec)
810 {
811 BMCWEB_LOG_DEBUG << this << " from write(2)";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700812 return;
813 }
Ed Tanousceac6f72018-12-02 11:58:47 -0800814 if (!res.keepAlive())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700815 {
Ed Tanouse278c182019-03-13 16:23:37 -0700816 close();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700817 BMCWEB_LOG_DEBUG << this << " from write(1)";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700818 return;
819 }
820
821 serializer.reset();
822 BMCWEB_LOG_DEBUG << this << " Clearing response";
823 res.clear();
824 parser.emplace(std::piecewise_construct, std::make_tuple());
825 parser->body_limit(httpReqBodyLimit); // reset body limit for
826 // newly created parser
827 buffer.consume(buffer.size());
828
829 req.emplace(parser->get());
830 doReadHeaders();
831 });
832 }
833
Ed Tanous1abe55e2018-09-05 08:30:59 -0700834 void cancelDeadlineTimer()
835 {
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000836 if (timerCancelKey)
837 {
838 BMCWEB_LOG_DEBUG << this << " timer cancelled: " << &timerQueue
839 << ' ' << *timerCancelKey;
840 timerQueue.cancel(*timerCancelKey);
841 timerCancelKey.reset();
842 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700843 }
844
James Feistf0af8592020-03-27 16:28:59 -0700845 void startDeadline(size_t timerIterations = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700846 {
James Feistf0af8592020-03-27 16:28:59 -0700847 // drop all connections after 1 minute, this time limit was chosen
848 // arbitrarily and can be adjusted later if needed
849 constexpr const size_t maxReadAttempts =
850 (60 / detail::timerQueueTimeoutSeconds);
851
Ed Tanous1abe55e2018-09-05 08:30:59 -0700852 cancelDeadlineTimer();
853
James Feistf0af8592020-03-27 16:28:59 -0700854 timerCancelKey = timerQueue.add([this, self(shared_from_this()),
855 readCount{parser->get().body().size()},
856 timerIterations{timerIterations + 1}] {
857 // Mark timer as not active to avoid canceling it during
858 // Connection destructor which leads to double free issue
859 timerCancelKey.reset();
860 if (!isAlive())
861 {
862 return;
863 }
Jan Sowinski2b5e08e2020-01-09 17:16:02 +0100864
James Feistf0af8592020-03-27 16:28:59 -0700865 // Restart timer if read is in progress.
866 // With threshold can be used to drop slow connections
867 // to protect against slow-rate DoS attack
868 if ((parser->get().body().size() > readCount) &&
869 (timerIterations < maxReadAttempts))
870 {
871 BMCWEB_LOG_DEBUG << this << " restart timer - read in progress";
872 startDeadline(timerIterations);
873 return;
874 }
Jan Sowinski2b5e08e2020-01-09 17:16:02 +0100875
James Feistf0af8592020-03-27 16:28:59 -0700876 close();
877 });
James Feistcb6cb492020-04-03 13:36:17 -0700878
879 if (!timerCancelKey)
880 {
881 close();
882 return;
883 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700884 BMCWEB_LOG_DEBUG << this << " timer added: " << &timerQueue << ' '
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000885 << *timerCancelKey;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700886 }
887
888 private:
889 Adaptor adaptor;
890 Handler* handler;
891
Ed Tanousa24526d2018-12-10 15:17:59 -0800892 // Making this a std::optional allows it to be efficiently destroyed and
Ed Tanous1abe55e2018-09-05 08:30:59 -0700893 // re-created on Connection reset
Ed Tanousa24526d2018-12-10 15:17:59 -0800894 std::optional<
Ed Tanous1abe55e2018-09-05 08:30:59 -0700895 boost::beast::http::request_parser<boost::beast::http::string_body>>
896 parser;
897
Ed Tanous3112a142018-11-29 15:45:10 -0800898 boost::beast::flat_static_buffer<8192> buffer;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700899
Ed Tanousa24526d2018-12-10 15:17:59 -0800900 std::optional<boost::beast::http::response_serializer<
Ed Tanous1abe55e2018-09-05 08:30:59 -0700901 boost::beast::http::string_body>>
902 serializer;
903
Ed Tanousa24526d2018-12-10 15:17:59 -0800904 std::optional<crow::Request> req;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700905 crow::Response res;
Kowalski, Kamil55e43f62019-07-10 13:12:57 +0200906#ifdef BMCWEB_ENABLE_MUTUAL_TLS_AUTHENTICATION
907 std::weak_ptr<crow::persistent_data::UserSession> session;
908#endif // BMCWEB_ENABLE_MUTUAL_TLS_AUTHENTICATION
Ed Tanous1abe55e2018-09-05 08:30:59 -0700909
910 const std::string& serverName;
911
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000912 std::optional<size_t> timerCancelKey;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700913
Ed Tanous1abe55e2018-09-05 08:30:59 -0700914 bool needToCallAfterHandlers{};
915 bool needToStartReadAfterComplete{};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700916
917 std::tuple<Middlewares...>* middlewares;
918 detail::Context<Middlewares...> ctx;
919
920 std::function<std::string()>& getCachedDateStr;
921 detail::TimerQueue& timerQueue;
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000922
923 using std::enable_shared_from_this<
924 Connection<Adaptor, Handler, Middlewares...>>::shared_from_this;
Ed Tanous3112a142018-11-29 15:45:10 -0800925};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700926} // namespace crow