blob: 5f4681f2a48fad687f6f9ba1b2c03c5e3ad91393 [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
Manojkiran Eda44250442020-06-16 12:51:38 +05304#include "http_response.h"
5#include "logging.h"
6#include "middleware_context.h"
7#include "timer_queue.h"
8#include "utility.h"
9
Ed Tanous1abe55e2018-09-05 08:30:59 -070010#include "http_utility.hpp"
11
Ed Tanouse0d918b2018-03-27 17:41:04 -070012#include <boost/algorithm/string.hpp>
Ed Tanous257f5792018-03-17 14:40:09 -070013#include <boost/algorithm/string/predicate.hpp>
Ed Tanous8f626352018-12-19 14:51:54 -080014#include <boost/asio/io_context.hpp>
Ed Tanous3112a142018-11-29 15:45:10 -080015#include <boost/asio/ip/tcp.hpp>
Ed Tanous2f1ebcd2019-02-13 19:39:07 -080016#include <boost/asio/ssl.hpp>
Ed Tanous3112a142018-11-29 15:45:10 -080017#include <boost/beast/core/flat_static_buffer.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050018#include <boost/beast/http.hpp>
Manojkiran Eda44250442020-06-16 12:51:38 +053019#include <boost/beast/ssl/ssl_stream.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050020#include <boost/beast/websocket.hpp>
21#include <ssl_key_handler.hpp>
22
Manojkiran Eda44250442020-06-16 12:51:38 +053023#include <atomic>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050024#include <chrono>
25#include <vector>
26
Ed Tanous1abe55e2018-09-05 08:30:59 -070027namespace crow
28{
Ed Tanous257f5792018-03-17 14:40:09 -070029
Ed Tanous1abe55e2018-09-05 08:30:59 -070030inline void prettyPrintJson(crow::Response& res)
31{
Jason M. Bills193ad2f2018-09-26 15:08:52 -070032 std::string value = res.jsonValue.dump(4, ' ', true);
Ed Tanousa29c9972018-11-29 15:54:32 -080033 utility::escapeHtml(value);
34 utility::convertToLinks(value);
Ed Tanous1abe55e2018-09-05 08:30:59 -070035 res.body() = "<html>\n"
36 "<head>\n"
37 "<title>Redfish API</title>\n"
38 "<link rel=\"stylesheet\" type=\"text/css\" "
39 "href=\"/styles/default.css\">\n"
40 "<script src=\"/highlight.pack.js\"></script>"
41 "<script>hljs.initHighlightingOnLoad();</script>"
42 "</head>\n"
43 "<body>\n"
44 "<div style=\"max-width: 576px;margin:0 auto;\">\n"
45 "<img src=\"/DMTF_Redfish_logo_2017.svg\" alt=\"redfish\" "
46 "height=\"406px\" "
47 "width=\"576px\">\n"
48 "<br>\n"
49 "<pre>\n"
50 "<code class=\"json\">" +
51 value +
52 "</code>\n"
53 "</pre>\n"
54 "</div>\n"
55 "</body>\n"
56 "</html>\n";
Ed Tanous93ef5802019-01-03 10:15:41 -080057 res.addHeader("Content-Type", "text/html;charset=UTF-8");
Ed Tanous257f5792018-03-17 14:40:09 -070058}
59
Ed Tanous7045c8d2017-04-03 10:04:37 -070060using namespace boost;
61using tcp = asio::ip::tcp;
62
Ed Tanous1abe55e2018-09-05 08:30:59 -070063namespace detail
64{
Gunnar Mills1214b7e2020-06-04 10:11:30 -050065template <typename MW>
66struct CheckBeforeHandleArity3Const
Ed Tanous1abe55e2018-09-05 08:30:59 -070067{
68 template <typename T,
69 void (T::*)(Request&, Response&, typename MW::Context&) const =
70 &T::beforeHandle>
71 struct Get
Gunnar Mills1214b7e2020-06-04 10:11:30 -050072 {};
Ed Tanous7045c8d2017-04-03 10:04:37 -070073};
74
Gunnar Mills1214b7e2020-06-04 10:11:30 -050075template <typename MW>
76struct CheckBeforeHandleArity3
Ed Tanous1abe55e2018-09-05 08:30:59 -070077{
78 template <typename T, void (T::*)(Request&, Response&,
79 typename MW::Context&) = &T::beforeHandle>
80 struct Get
Gunnar Mills1214b7e2020-06-04 10:11:30 -050081 {};
Ed Tanous7045c8d2017-04-03 10:04:37 -070082};
83
Gunnar Mills1214b7e2020-06-04 10:11:30 -050084template <typename MW>
85struct CheckAfterHandleArity3Const
Ed Tanous1abe55e2018-09-05 08:30:59 -070086{
87 template <typename T,
88 void (T::*)(Request&, Response&, typename MW::Context&) const =
89 &T::afterHandle>
90 struct Get
Gunnar Mills1214b7e2020-06-04 10:11:30 -050091 {};
Ed Tanous7045c8d2017-04-03 10:04:37 -070092};
93
Gunnar Mills1214b7e2020-06-04 10:11:30 -050094template <typename MW>
95struct CheckAfterHandleArity3
Ed Tanous1abe55e2018-09-05 08:30:59 -070096{
97 template <typename T, void (T::*)(Request&, Response&,
98 typename MW::Context&) = &T::afterHandle>
99 struct Get
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500100 {};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700101};
102
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500103template <typename T>
104struct IsBeforeHandleArity3Impl
Ed Tanous1abe55e2018-09-05 08:30:59 -0700105{
106 template <typename C>
107 static std::true_type
108 f(typename CheckBeforeHandleArity3Const<T>::template Get<C>*);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700109
Ed Tanous1abe55e2018-09-05 08:30:59 -0700110 template <typename C>
111 static std::true_type
112 f(typename CheckBeforeHandleArity3<T>::template Get<C>*);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700113
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500114 template <typename C>
115 static std::false_type f(...);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700116
Ed Tanous1abe55e2018-09-05 08:30:59 -0700117 public:
Ed Tanous0c838cf2019-10-24 10:01:46 -0700118 static constexpr bool value = decltype(f<T>(nullptr))::value;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700119};
120
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500121template <typename T>
122struct IsAfterHandleArity3Impl
Ed Tanous1abe55e2018-09-05 08:30:59 -0700123{
124 template <typename C>
125 static std::true_type
126 f(typename CheckAfterHandleArity3Const<T>::template Get<C>*);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700127
Ed Tanous1abe55e2018-09-05 08:30:59 -0700128 template <typename C>
129 static std::true_type
130 f(typename CheckAfterHandleArity3<T>::template Get<C>*);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700131
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500132 template <typename C>
133 static std::false_type f(...);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700134
Ed Tanous1abe55e2018-09-05 08:30:59 -0700135 public:
Ed Tanous0c838cf2019-10-24 10:01:46 -0700136 static constexpr bool value = decltype(f<T>(nullptr))::value;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700137};
138
139template <typename MW, typename Context, typename ParentContext>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700140typename std::enable_if<!IsBeforeHandleArity3Impl<MW>::value>::type
Ed Tanous1abe55e2018-09-05 08:30:59 -0700141 beforeHandlerCall(MW& mw, Request& req, Response& res, Context& ctx,
142 ParentContext& /*parent_ctx*/)
143{
144 mw.beforeHandle(req, res, ctx.template get<MW>(), ctx);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700145}
146
147template <typename MW, typename Context, typename ParentContext>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700148typename std::enable_if<IsBeforeHandleArity3Impl<MW>::value>::type
Ed Tanous1abe55e2018-09-05 08:30:59 -0700149 beforeHandlerCall(MW& mw, Request& req, Response& res, Context& ctx,
150 ParentContext& /*parent_ctx*/)
151{
152 mw.beforeHandle(req, res, ctx.template get<MW>());
Ed Tanous7045c8d2017-04-03 10:04:37 -0700153}
154
155template <typename MW, typename Context, typename ParentContext>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700156typename std::enable_if<!IsAfterHandleArity3Impl<MW>::value>::type
Ed Tanous1abe55e2018-09-05 08:30:59 -0700157 afterHandlerCall(MW& mw, Request& req, Response& res, Context& ctx,
158 ParentContext& /*parent_ctx*/)
159{
160 mw.afterHandle(req, res, ctx.template get<MW>(), ctx);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700161}
162
163template <typename MW, typename Context, typename ParentContext>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700164typename std::enable_if<IsAfterHandleArity3Impl<MW>::value>::type
Ed Tanous1abe55e2018-09-05 08:30:59 -0700165 afterHandlerCall(MW& mw, Request& req, Response& res, Context& ctx,
166 ParentContext& /*parent_ctx*/)
167{
168 mw.afterHandle(req, res, ctx.template get<MW>());
Ed Tanous7045c8d2017-04-03 10:04:37 -0700169}
170
Ed Tanous271584a2019-07-09 16:24:22 -0700171template <size_t N, typename Context, typename Container, typename CurrentMW,
Ed Tanous7045c8d2017-04-03 10:04:37 -0700172 typename... Middlewares>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700173bool middlewareCallHelper(Container& middlewares, Request& req, Response& res,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700174 Context& ctx)
175{
176 using parent_context_t = typename Context::template partial<N - 1>;
177 beforeHandlerCall<CurrentMW, Context, parent_context_t>(
Ed Tanous7045c8d2017-04-03 10:04:37 -0700178 std::get<N>(middlewares), req, res, ctx,
179 static_cast<parent_context_t&>(ctx));
Ed Tanous7045c8d2017-04-03 10:04:37 -0700180
Ed Tanous1abe55e2018-09-05 08:30:59 -0700181 if (res.isCompleted())
182 {
183 afterHandlerCall<CurrentMW, Context, parent_context_t>(
184 std::get<N>(middlewares), req, res, ctx,
185 static_cast<parent_context_t&>(ctx));
186 return true;
187 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700188
Ed Tanous1abe55e2018-09-05 08:30:59 -0700189 if (middlewareCallHelper<N + 1, Context, Container, Middlewares...>(
190 middlewares, req, res, ctx))
191 {
192 afterHandlerCall<CurrentMW, Context, parent_context_t>(
193 std::get<N>(middlewares), req, res, ctx,
194 static_cast<parent_context_t&>(ctx));
195 return true;
196 }
197
198 return false;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700199}
200
Ed Tanous271584a2019-07-09 16:24:22 -0700201template <size_t N, typename Context, typename Container>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700202bool middlewareCallHelper(Container& /*middlewares*/, Request& /*req*/,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700203 Response& /*res*/, Context& /*ctx*/)
204{
205 return false;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700206}
207
Ed Tanous271584a2019-07-09 16:24:22 -0700208template <size_t N, typename Context, typename Container>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700209typename std::enable_if<(N < 0)>::type
210 afterHandlersCallHelper(Container& /*middlewares*/, Context& /*Context*/,
211 Request& /*req*/, Response& /*res*/)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500212{}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700213
Ed Tanous271584a2019-07-09 16:24:22 -0700214template <size_t N, typename Context, typename Container>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700215typename std::enable_if<(N == 0)>::type
216 afterHandlersCallHelper(Container& middlewares, Context& ctx, Request& req,
217 Response& res)
218{
219 using parent_context_t = typename Context::template partial<N - 1>;
220 using CurrentMW = typename std::tuple_element<
221 N, typename std::remove_reference<Container>::type>::type;
222 afterHandlerCall<CurrentMW, Context, parent_context_t>(
223 std::get<N>(middlewares), req, res, ctx,
224 static_cast<parent_context_t&>(ctx));
Ed Tanous7045c8d2017-04-03 10:04:37 -0700225}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700226
Ed Tanous271584a2019-07-09 16:24:22 -0700227template <size_t N, typename Context, typename Container>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700228typename std::enable_if<(N > 0)>::type
229 afterHandlersCallHelper(Container& middlewares, Context& ctx, Request& req,
230 Response& res)
231{
232 using parent_context_t = typename Context::template partial<N - 1>;
233 using CurrentMW = typename std::tuple_element<
234 N, typename std::remove_reference<Container>::type>::type;
235 afterHandlerCall<CurrentMW, Context, parent_context_t>(
236 std::get<N>(middlewares), req, res, ctx,
237 static_cast<parent_context_t&>(ctx));
238 afterHandlersCallHelper<N - 1, Context, Container>(middlewares, ctx, req,
239 res);
240}
241} // namespace detail
Ed Tanous7045c8d2017-04-03 10:04:37 -0700242
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700243#ifdef BMCWEB_ENABLE_DEBUG
Ed Tanouse0d918b2018-03-27 17:41:04 -0700244static std::atomic<int> connectionCount;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700245#endif
Jennifer Leeacb7cfb2018-06-07 16:08:15 -0700246
Adriana Kobylak0e1cf262019-12-05 13:57:57 -0600247// request body limit size set by the BMCWEB_HTTP_REQ_BODY_LIMIT_MB option
248constexpr unsigned int httpReqBodyLimit =
249 1024 * 1024 * BMCWEB_HTTP_REQ_BODY_LIMIT_MB;
Jennifer Leeacb7cfb2018-06-07 16:08:15 -0700250
Ed Tanous7045c8d2017-04-03 10:04:37 -0700251template <typename Adaptor, typename Handler, typename... Middlewares>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500252class Connection :
253 public std::enable_shared_from_this<
254 Connection<Adaptor, Handler, Middlewares...>>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700255{
256 public:
Ed Tanous271584a2019-07-09 16:24:22 -0700257 Connection(boost::asio::io_context& ioService, Handler* handlerIn,
258 const std::string& ServerNameIn,
259 std::tuple<Middlewares...>* middlewaresIn,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700260 std::function<std::string()>& get_cached_date_str_f,
Ed Tanous271584a2019-07-09 16:24:22 -0700261 detail::TimerQueue& timerQueueIn, Adaptor adaptorIn) :
Ed Tanousceac6f72018-12-02 11:58:47 -0800262 adaptor(std::move(adaptorIn)),
Ed Tanous271584a2019-07-09 16:24:22 -0700263 handler(handlerIn), serverName(ServerNameIn),
264 middlewares(middlewaresIn), getCachedDateStr(get_cached_date_str_f),
265 timerQueue(timerQueueIn)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700266 {
267 parser.emplace(std::piecewise_construct, std::make_tuple());
Adriana Kobylak0e1cf262019-12-05 13:57:57 -0600268 // Temporarily set by the BMCWEB_HTTP_REQ_BODY_LIMIT_MB variable; Need
269 // to modify uploading/authentication mechanism to a better method that
270 // disallows a DOS attack based on a large file size.
Ed Tanous1abe55e2018-09-05 08:30:59 -0700271 parser->body_limit(httpReqBodyLimit);
272 req.emplace(parser->get());
Kowalski, Kamil55e43f62019-07-10 13:12:57 +0200273
274#ifdef BMCWEB_ENABLE_MUTUAL_TLS_AUTHENTICATION
Zbigniew Kurzynski009c2a42019-11-14 13:37:15 +0100275 auto ca_available = !std::filesystem::is_empty(
276 std::filesystem::path(ensuressl::trustStorePath));
277 if (ca_available && crow::persistent_data::SessionStore::getInstance()
278 .getAuthMethodsConfig()
279 .tls)
280 {
281 adaptor.set_verify_mode(boost::asio::ssl::verify_peer);
282 SSL_set_session_id_context(
283 adaptor.native_handle(),
284 reinterpret_cast<const unsigned char*>(serverName.c_str()),
Zbigniew Kurzynskicac94c52019-11-07 12:55:04 +0100285 static_cast<unsigned int>(serverName.length()));
Zbigniew Kurzynski009c2a42019-11-14 13:37:15 +0100286 BMCWEB_LOG_DEBUG << this << " TLS is enabled on this connection.";
287 }
288
Zbigniew Kurzynski2658d982019-11-19 18:01:08 +0100289 adaptor.set_verify_callback([this](
290 bool preverified,
291 boost::asio::ssl::verify_context& ctx) {
292 // do nothing if TLS is disabled
293 if (!crow::persistent_data::SessionStore::getInstance()
294 .getAuthMethodsConfig()
295 .tls)
296 {
297 BMCWEB_LOG_DEBUG << this << " TLS auth_config is disabled";
Kowalski, Kamil55e43f62019-07-10 13:12:57 +0200298 return true;
Zbigniew Kurzynski2658d982019-11-19 18:01:08 +0100299 }
300
301 // We always return true to allow full auth flow
302 if (!preverified)
303 {
Zbigniew Kurzynski009c2a42019-11-14 13:37:15 +0100304 BMCWEB_LOG_DEBUG << this << " TLS preverification failed.";
Zbigniew Kurzynski2658d982019-11-19 18:01:08 +0100305 return true;
306 }
307
308 X509_STORE_CTX* cts = ctx.native_handle();
309 if (cts == nullptr)
310 {
Zbigniew Kurzynski009c2a42019-11-14 13:37:15 +0100311 BMCWEB_LOG_DEBUG << this << " Cannot get native TLS handle.";
Zbigniew Kurzynski2658d982019-11-19 18:01:08 +0100312 return true;
313 }
314
315 // Get certificate
316 X509* peerCert =
317 X509_STORE_CTX_get_current_cert(ctx.native_handle());
318 if (peerCert == nullptr)
319 {
Zbigniew Kurzynski009c2a42019-11-14 13:37:15 +0100320 BMCWEB_LOG_DEBUG << this
321 << " Cannot get current TLS certificate.";
Zbigniew Kurzynski2658d982019-11-19 18:01:08 +0100322 return true;
323 }
324
325 // Check if certificate is OK
326 int error = X509_STORE_CTX_get_error(cts);
327 if (error != X509_V_OK)
328 {
Zbigniew Kurzynski009c2a42019-11-14 13:37:15 +0100329 BMCWEB_LOG_INFO << this << " Last TLS error is: " << error;
Zbigniew Kurzynski2658d982019-11-19 18:01:08 +0100330 return true;
331 }
332 // Check that we have reached final certificate in chain
333 int32_t depth = X509_STORE_CTX_get_error_depth(cts);
334 if (depth != 0)
335
336 {
337 BMCWEB_LOG_DEBUG
338 << this << " Certificate verification in progress (depth "
339 << depth << "), waiting to reach final depth";
340 return true;
341 }
342
343 BMCWEB_LOG_DEBUG << this
344 << " Certificate verification of final depth";
345
346 // Verify KeyUsage
347 bool isKeyUsageDigitalSignature = false;
348 bool isKeyUsageKeyAgreement = false;
349
350 ASN1_BIT_STRING* usage = static_cast<ASN1_BIT_STRING*>(
351 X509_get_ext_d2i(peerCert, NID_key_usage, NULL, NULL));
352
353 if (usage == nullptr)
354 {
Zbigniew Kurzynski009c2a42019-11-14 13:37:15 +0100355 BMCWEB_LOG_DEBUG << this << " TLS usage is null";
Zbigniew Kurzynski2658d982019-11-19 18:01:08 +0100356 return true;
357 }
358
359 for (int i = 0; i < usage->length; i++)
360 {
361 if (KU_DIGITAL_SIGNATURE & usage->data[i])
362 {
363 isKeyUsageDigitalSignature = true;
364 }
365 if (KU_KEY_AGREEMENT & usage->data[i])
366 {
367 isKeyUsageKeyAgreement = true;
368 }
369 }
370
371 if (!isKeyUsageDigitalSignature || !isKeyUsageKeyAgreement)
372 {
373 BMCWEB_LOG_DEBUG << this
374 << " Certificate ExtendedKeyUsage does "
375 "not allow provided certificate to "
376 "be used for user authentication";
377 return true;
378 }
Zbigniew Kurzynski09d02f82020-03-30 13:41:42 +0200379 ASN1_BIT_STRING_free(usage);
Zbigniew Kurzynski2658d982019-11-19 18:01:08 +0100380
381 // Determine that ExtendedKeyUsage includes Client Auth
382
383 stack_st_ASN1_OBJECT* extUsage = static_cast<stack_st_ASN1_OBJECT*>(
384 X509_get_ext_d2i(peerCert, NID_ext_key_usage, NULL, NULL));
385
386 if (extUsage == nullptr)
387 {
Zbigniew Kurzynski009c2a42019-11-14 13:37:15 +0100388 BMCWEB_LOG_DEBUG << this << " TLS extUsage is null";
Zbigniew Kurzynski2658d982019-11-19 18:01:08 +0100389 return true;
390 }
391
392 bool isExKeyUsageClientAuth = false;
393 for (int i = 0; i < sk_ASN1_OBJECT_num(extUsage); i++)
394 {
395 if (NID_client_auth ==
396 OBJ_obj2nid(sk_ASN1_OBJECT_value(extUsage, i)))
397 {
398 isExKeyUsageClientAuth = true;
399 break;
400 }
401 }
Zbigniew Kurzynski09d02f82020-03-30 13:41:42 +0200402 sk_ASN1_OBJECT_free(extUsage);
Zbigniew Kurzynski2658d982019-11-19 18:01:08 +0100403
404 // Certificate has to have proper key usages set
405 if (!isExKeyUsageClientAuth)
406 {
407 BMCWEB_LOG_DEBUG << this
408 << " Certificate ExtendedKeyUsage does "
409 "not allow provided certificate to "
410 "be used for user authentication";
411 return true;
412 }
413 std::string sslUser;
414 // Extract username contained in CommonName
415 sslUser.resize(256, '\0');
416
417 int status = X509_NAME_get_text_by_NID(
418 X509_get_subject_name(peerCert), NID_commonName, sslUser.data(),
419 static_cast<int>(sslUser.size()));
420
421 if (status == -1)
422 {
Zbigniew Kurzynski009c2a42019-11-14 13:37:15 +0100423 BMCWEB_LOG_DEBUG
424 << this << " TLS cannot get username to create session";
Zbigniew Kurzynski2658d982019-11-19 18:01:08 +0100425 return true;
426 }
427
428 size_t lastChar = sslUser.find('\0');
429 if (lastChar == std::string::npos || lastChar == 0)
430 {
Zbigniew Kurzynski009c2a42019-11-14 13:37:15 +0100431 BMCWEB_LOG_DEBUG << this << " Invalid TLS user name";
Zbigniew Kurzynski2658d982019-11-19 18:01:08 +0100432 return true;
433 }
434 sslUser.resize(lastChar);
435
436 session = persistent_data::SessionStore::getInstance()
437 .generateUserSession(
438 sslUser,
439 crow::persistent_data::PersistenceType::TIMEOUT);
Zbigniew Kurzynski009c2a42019-11-14 13:37:15 +0100440 if (auto sp = session.lock())
441 {
442 BMCWEB_LOG_DEBUG << this
443 << " Generating TLS session: " << sp->uniqueId;
444 }
Zbigniew Kurzynski2658d982019-11-19 18:01:08 +0100445 return true;
446 });
Kowalski, Kamil55e43f62019-07-10 13:12:57 +0200447#endif // BMCWEB_ENABLE_MUTUAL_TLS_AUTHENTICATION
448
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700449#ifdef BMCWEB_ENABLE_DEBUG
Ed Tanous1abe55e2018-09-05 08:30:59 -0700450 connectionCount++;
451 BMCWEB_LOG_DEBUG << this << " Connection open, total "
452 << connectionCount;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700453#endif
Ed Tanous1abe55e2018-09-05 08:30:59 -0700454 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700455
Ed Tanous1abe55e2018-09-05 08:30:59 -0700456 ~Connection()
457 {
458 res.completeRequestHandler = nullptr;
459 cancelDeadlineTimer();
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700460#ifdef BMCWEB_ENABLE_DEBUG
Ed Tanous1abe55e2018-09-05 08:30:59 -0700461 connectionCount--;
462 BMCWEB_LOG_DEBUG << this << " Connection closed, total "
463 << connectionCount;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700464#endif
Ed Tanous7045c8d2017-04-03 10:04:37 -0700465 }
466
Ed Tanousceac6f72018-12-02 11:58:47 -0800467 Adaptor& socket()
Ed Tanous1abe55e2018-09-05 08:30:59 -0700468 {
Ed Tanousceac6f72018-12-02 11:58:47 -0800469 return adaptor;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700470 }
471
Ed Tanous1abe55e2018-09-05 08:30:59 -0700472 void start()
473 {
Ed Tanous7045c8d2017-04-03 10:04:37 -0700474
Ed Tanousceac6f72018-12-02 11:58:47 -0800475 startDeadline();
476 // TODO(ed) Abstract this to a more clever class with the idea of an
477 // asynchronous "start"
478 if constexpr (std::is_same_v<Adaptor,
479 boost::beast::ssl_stream<
480 boost::asio::ip::tcp::socket>>)
481 {
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000482 adaptor.async_handshake(boost::asio::ssl::stream_base::server,
483 [this, self(shared_from_this())](
484 const boost::system::error_code& ec) {
485 if (ec)
486 {
487 return;
488 }
489 doReadHeaders();
490 });
Ed Tanousceac6f72018-12-02 11:58:47 -0800491 }
492 else
493 {
494 doReadHeaders();
495 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700496 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700497
Ed Tanous1abe55e2018-09-05 08:30:59 -0700498 void handle()
499 {
500 cancelDeadlineTimer();
501 bool isInvalidRequest = false;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700502
Ed Tanous1abe55e2018-09-05 08:30:59 -0700503 // Check for HTTP version 1.1.
504 if (req->version() == 11)
505 {
506 if (req->getHeaderValue(boost::beast::http::field::host).empty())
507 {
508 isInvalidRequest = true;
Ed Tanousde5c9f32019-03-26 09:17:55 -0700509 res.result(boost::beast::http::status::bad_request);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700510 }
511 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700512
Ed Tanouse278c182019-03-13 16:23:37 -0700513 BMCWEB_LOG_INFO << "Request: "
514 << " " << this << " HTTP/" << req->version() / 10 << "."
515 << req->version() % 10 << ' ' << req->methodString()
516 << " " << req->target();
Ed Tanous7045c8d2017-04-03 10:04:37 -0700517
Ed Tanous1abe55e2018-09-05 08:30:59 -0700518 needToCallAfterHandlers = false;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700519
Ed Tanous1abe55e2018-09-05 08:30:59 -0700520 if (!isInvalidRequest)
521 {
raviteja-b4722efe2020-02-03 12:23:18 -0600522 req->socket = [this, self = shared_from_this()]() -> Adaptor& {
523 return self->socket();
524 };
525
Ed Tanous1abe55e2018-09-05 08:30:59 -0700526 res.completeRequestHandler = [] {};
Ed Tanouse278c182019-03-13 16:23:37 -0700527 res.isAliveHelper = [this]() -> bool { return isAlive(); };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700528
Ed Tanous1abe55e2018-09-05 08:30:59 -0700529 ctx = detail::Context<Middlewares...>();
Ed Tanouse278c182019-03-13 16:23:37 -0700530 req->middlewareContext = static_cast<void*>(&ctx);
531 req->ioService = static_cast<decltype(req->ioService)>(
532 &adaptor.get_executor().context());
Kowalski, Kamil55e43f62019-07-10 13:12:57 +0200533
534#ifdef BMCWEB_ENABLE_MUTUAL_TLS_AUTHENTICATION
535 if (auto sp = session.lock())
536 {
Zbigniew Kurzynski009c2a42019-11-14 13:37:15 +0100537 // set cookie only if this is req from the browser.
538 if (req->getHeaderValue("User-Agent").empty())
539 {
540 BMCWEB_LOG_DEBUG << this << " TLS session: " << sp->uniqueId
541 << " will be used for this request.";
542 req->session = sp;
543 }
544 else
545 {
546 std::string_view cookieValue =
547 req->getHeaderValue("Cookie");
548 if (cookieValue.empty() ||
549 cookieValue.find("SESSION=") == std::string::npos)
550 {
551 res.addHeader("Set-Cookie",
552 "XSRF-TOKEN=" + sp->csrfToken +
553 "; Secure\r\nSet-Cookie: SESSION=" +
554 sp->sessionToken +
Zbigniew Kurzynski26139a52019-12-11 19:11:18 +0100555 "; Secure; HttpOnly\r\nSet-Cookie: "
556 "IsAuthenticated=true; Secure");
Zbigniew Kurzynski009c2a42019-11-14 13:37:15 +0100557 BMCWEB_LOG_DEBUG
558 << this << " TLS session: " << sp->uniqueId
559 << " with cookie will be used for this request.";
560 req->session = sp;
561 }
562 }
Kowalski, Kamil55e43f62019-07-10 13:12:57 +0200563 }
564#endif // BMCWEB_ENABLE_MUTUAL_TLS_AUTHENTICATION
565
Ed Tanous1abe55e2018-09-05 08:30:59 -0700566 detail::middlewareCallHelper<
Ed Tanous271584a2019-07-09 16:24:22 -0700567 0U, decltype(ctx), decltype(*middlewares), Middlewares...>(
Ed Tanous1abe55e2018-09-05 08:30:59 -0700568 *middlewares, *req, res, ctx);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700569
Ed Tanous1abe55e2018-09-05 08:30:59 -0700570 if (!res.completed)
571 {
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000572 needToCallAfterHandlers = true;
573 res.completeRequestHandler = [self(shared_from_this())] {
574 self->completeRequest();
575 };
Ed Tanous1abe55e2018-09-05 08:30:59 -0700576 if (req->isUpgrade() &&
577 boost::iequals(
578 req->getHeaderValue(boost::beast::http::field::upgrade),
579 "websocket"))
580 {
581 handler->handleUpgrade(*req, res, std::move(adaptor));
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000582 // delete lambda with self shared_ptr
583 // to enable connection destruction
584 res.completeRequestHandler = nullptr;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700585 return;
586 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700587 handler->handle(*req, res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700588 }
589 else
590 {
591 completeRequest();
592 }
593 }
594 else
595 {
596 completeRequest();
597 }
598 }
Ed Tanouse0d918b2018-03-27 17:41:04 -0700599
Ed Tanouse278c182019-03-13 16:23:37 -0700600 bool isAlive()
601 {
602
603 if constexpr (std::is_same_v<Adaptor,
604 boost::beast::ssl_stream<
605 boost::asio::ip::tcp::socket>>)
606 {
607 return adaptor.next_layer().is_open();
608 }
609 else
610 {
611 return adaptor.is_open();
612 }
613 }
614 void close()
615 {
Ed Tanouse278c182019-03-13 16:23:37 -0700616 if constexpr (std::is_same_v<Adaptor,
617 boost::beast::ssl_stream<
618 boost::asio::ip::tcp::socket>>)
619 {
620 adaptor.next_layer().close();
Kowalski, Kamil55e43f62019-07-10 13:12:57 +0200621#ifdef BMCWEB_ENABLE_MUTUAL_TLS_AUTHENTICATION
622 if (auto sp = session.lock())
623 {
Zbigniew Kurzynski009c2a42019-11-14 13:37:15 +0100624 BMCWEB_LOG_DEBUG << this
625 << " Removing TLS session: " << sp->uniqueId;
Kowalski, Kamil55e43f62019-07-10 13:12:57 +0200626 persistent_data::SessionStore::getInstance().removeSession(sp);
627 }
628#endif // BMCWEB_ENABLE_MUTUAL_TLS_AUTHENTICATION
Ed Tanouse278c182019-03-13 16:23:37 -0700629 }
630 else
631 {
632 adaptor.close();
633 }
634 }
635
Ed Tanous1abe55e2018-09-05 08:30:59 -0700636 void completeRequest()
637 {
638 BMCWEB_LOG_INFO << "Response: " << this << ' ' << req->url << ' '
639 << res.resultInt() << " keepalive=" << req->keepAlive();
Ed Tanous7045c8d2017-04-03 10:04:37 -0700640
Ed Tanous1abe55e2018-09-05 08:30:59 -0700641 if (needToCallAfterHandlers)
642 {
643 needToCallAfterHandlers = false;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700644
Ed Tanous1abe55e2018-09-05 08:30:59 -0700645 // call all afterHandler of middlewares
Ed Tanous271584a2019-07-09 16:24:22 -0700646 detail::afterHandlersCallHelper<sizeof...(Middlewares) - 1,
Ed Tanousb01bf292019-03-25 19:25:26 +0000647 decltype(ctx),
648 decltype(*middlewares)>(
649 *middlewares, ctx, *req, res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700650 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700651
Ed Tanouse278c182019-03-13 16:23:37 -0700652 if (!isAlive())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700653 {
654 // BMCWEB_LOG_DEBUG << this << " delete (socket is closed) " <<
655 // isReading
656 // << ' ' << isWriting;
657 // delete this;
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000658
659 // delete lambda with self shared_ptr
660 // to enable connection destruction
661 res.completeRequestHandler = nullptr;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700662 return;
663 }
664 if (res.body().empty() && !res.jsonValue.empty())
665 {
666 if (http_helpers::requestPrefersHtml(*req))
667 {
668 prettyPrintJson(res);
669 }
670 else
671 {
672 res.jsonMode();
Jason M. Bills193ad2f2018-09-26 15:08:52 -0700673 res.body() = res.jsonValue.dump(2, ' ', true);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700674 }
675 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700676
Ed Tanous1abe55e2018-09-05 08:30:59 -0700677 if (res.resultInt() >= 400 && res.body().empty())
678 {
679 res.body() = std::string(res.reason());
680 }
Ed Tanous6295bec2019-09-03 10:11:01 -0700681
682 if (res.result() == boost::beast::http::status::no_content)
683 {
684 // Boost beast throws if content is provided on a no-content
685 // response. Ideally, this would never happen, but in the case that
686 // it does, we don't want to throw.
687 BMCWEB_LOG_CRITICAL
Zbigniew Kurzynski2658d982019-11-19 18:01:08 +0100688 << this << " Response content provided but code was no-content";
Ed Tanous6295bec2019-09-03 10:11:01 -0700689 res.body().clear();
690 }
691
Ed Tanous1abe55e2018-09-05 08:30:59 -0700692 res.addHeader(boost::beast::http::field::server, serverName);
693 res.addHeader(boost::beast::http::field::date, getCachedDateStr());
694
695 res.keepAlive(req->keepAlive());
696
697 doWrite();
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000698
699 // delete lambda with self shared_ptr
700 // to enable connection destruction
701 res.completeRequestHandler = nullptr;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700702 }
703
704 private:
705 void doReadHeaders()
706 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700707 BMCWEB_LOG_DEBUG << this << " doReadHeaders";
708
709 // Clean up any previous Connection.
710 boost::beast::http::async_read_header(
Ed Tanousceac6f72018-12-02 11:58:47 -0800711 adaptor, buffer, *parser,
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000712 [this,
713 self(shared_from_this())](const boost::system::error_code& ec,
714 std::size_t bytes_transferred) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700715 BMCWEB_LOG_ERROR << this << " async_read_header "
716 << bytes_transferred << " Bytes";
717 bool errorWhileReading = false;
718 if (ec)
719 {
720 errorWhileReading = true;
721 BMCWEB_LOG_ERROR
722 << this << " Error while reading: " << ec.message();
723 }
724 else
725 {
726 // if the adaptor isn't open anymore, and wasn't handed to a
727 // websocket, treat as an error
Ed Tanouse278c182019-03-13 16:23:37 -0700728 if (!isAlive() && !req->isUpgrade())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700729 {
730 errorWhileReading = true;
731 }
732 }
733
734 if (errorWhileReading)
735 {
736 cancelDeadlineTimer();
Ed Tanouse278c182019-03-13 16:23:37 -0700737 close();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700738 BMCWEB_LOG_DEBUG << this << " from read(1)";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700739 return;
740 }
741
742 // Compute the url parameters for the request
743 req->url = req->target();
744 std::size_t index = req->url.find("?");
Ed Tanous39e77502019-03-04 17:35:53 -0800745 if (index != std::string_view::npos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700746 {
Jason M. Bills43fcbe52018-10-16 15:19:20 -0700747 req->url = req->url.substr(0, index);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700748 }
749 req->urlParams = QueryString(std::string(req->target()));
750 doRead();
751 });
752 }
753
754 void doRead()
755 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700756 BMCWEB_LOG_DEBUG << this << " doRead";
757
758 boost::beast::http::async_read(
Ed Tanousceac6f72018-12-02 11:58:47 -0800759 adaptor, buffer, *parser,
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000760 [this,
761 self(shared_from_this())](const boost::system::error_code& ec,
762 std::size_t bytes_transferred) {
Zbigniew Kurzynski2658d982019-11-19 18:01:08 +0100763 BMCWEB_LOG_DEBUG << this << " async_read " << bytes_transferred
Ed Tanous1abe55e2018-09-05 08:30:59 -0700764 << " Bytes";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700765
766 bool errorWhileReading = false;
767 if (ec)
768 {
Zbigniew Kurzynski2658d982019-11-19 18:01:08 +0100769 BMCWEB_LOG_ERROR
770 << this << " Error while reading: " << ec.message();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700771 errorWhileReading = true;
772 }
773 else
774 {
Ed Tanouse278c182019-03-13 16:23:37 -0700775 if (!isAlive())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700776 {
777 errorWhileReading = true;
778 }
779 }
780 if (errorWhileReading)
781 {
782 cancelDeadlineTimer();
Ed Tanouse278c182019-03-13 16:23:37 -0700783 close();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700784 BMCWEB_LOG_DEBUG << this << " from read(1)";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700785 return;
786 }
787 handle();
788 });
789 }
790
791 void doWrite()
792 {
Zbigniew Kurzynski2658d982019-11-19 18:01:08 +0100793 BMCWEB_LOG_DEBUG << this << " doWrite";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700794 res.preparePayload();
795 serializer.emplace(*res.stringResponse);
796 boost::beast::http::async_write(
Ed Tanousceac6f72018-12-02 11:58:47 -0800797 adaptor, *serializer,
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000798 [this,
799 self(shared_from_this())](const boost::system::error_code& ec,
800 std::size_t bytes_transferred) {
Zbigniew Kurzynski2658d982019-11-19 18:01:08 +0100801 BMCWEB_LOG_DEBUG << this << " async_write " << bytes_transferred
Ed Tanous1abe55e2018-09-05 08:30:59 -0700802 << " bytes";
803
804 if (ec)
805 {
806 BMCWEB_LOG_DEBUG << this << " from write(2)";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700807 return;
808 }
Ed Tanousceac6f72018-12-02 11:58:47 -0800809 if (!res.keepAlive())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700810 {
Ed Tanouse278c182019-03-13 16:23:37 -0700811 close();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700812 BMCWEB_LOG_DEBUG << this << " from write(1)";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700813 return;
814 }
815
816 serializer.reset();
817 BMCWEB_LOG_DEBUG << this << " Clearing response";
818 res.clear();
819 parser.emplace(std::piecewise_construct, std::make_tuple());
820 parser->body_limit(httpReqBodyLimit); // reset body limit for
821 // newly created parser
822 buffer.consume(buffer.size());
823
824 req.emplace(parser->get());
825 doReadHeaders();
826 });
827 }
828
Ed Tanous1abe55e2018-09-05 08:30:59 -0700829 void cancelDeadlineTimer()
830 {
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000831 if (timerCancelKey)
832 {
833 BMCWEB_LOG_DEBUG << this << " timer cancelled: " << &timerQueue
834 << ' ' << *timerCancelKey;
835 timerQueue.cancel(*timerCancelKey);
836 timerCancelKey.reset();
837 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700838 }
839
James Feistf0af8592020-03-27 16:28:59 -0700840 void startDeadline(size_t timerIterations = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700841 {
James Feistf0af8592020-03-27 16:28:59 -0700842 // drop all connections after 1 minute, this time limit was chosen
843 // arbitrarily and can be adjusted later if needed
844 constexpr const size_t maxReadAttempts =
845 (60 / detail::timerQueueTimeoutSeconds);
846
Ed Tanous1abe55e2018-09-05 08:30:59 -0700847 cancelDeadlineTimer();
848
James Feistf0af8592020-03-27 16:28:59 -0700849 timerCancelKey = timerQueue.add([this, self(shared_from_this()),
850 readCount{parser->get().body().size()},
851 timerIterations{timerIterations + 1}] {
852 // Mark timer as not active to avoid canceling it during
853 // Connection destructor which leads to double free issue
854 timerCancelKey.reset();
855 if (!isAlive())
856 {
857 return;
858 }
Jan Sowinski2b5e08e2020-01-09 17:16:02 +0100859
James Feistf0af8592020-03-27 16:28:59 -0700860 // Restart timer if read is in progress.
861 // With threshold can be used to drop slow connections
862 // to protect against slow-rate DoS attack
863 if ((parser->get().body().size() > readCount) &&
864 (timerIterations < maxReadAttempts))
865 {
866 BMCWEB_LOG_DEBUG << this << " restart timer - read in progress";
867 startDeadline(timerIterations);
868 return;
869 }
Jan Sowinski2b5e08e2020-01-09 17:16:02 +0100870
James Feistf0af8592020-03-27 16:28:59 -0700871 close();
872 });
James Feistcb6cb492020-04-03 13:36:17 -0700873
874 if (!timerCancelKey)
875 {
876 close();
877 return;
878 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700879 BMCWEB_LOG_DEBUG << this << " timer added: " << &timerQueue << ' '
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000880 << *timerCancelKey;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700881 }
882
883 private:
884 Adaptor adaptor;
885 Handler* handler;
886
Ed Tanousa24526d2018-12-10 15:17:59 -0800887 // Making this a std::optional allows it to be efficiently destroyed and
Ed Tanous1abe55e2018-09-05 08:30:59 -0700888 // re-created on Connection reset
Ed Tanousa24526d2018-12-10 15:17:59 -0800889 std::optional<
Ed Tanous1abe55e2018-09-05 08:30:59 -0700890 boost::beast::http::request_parser<boost::beast::http::string_body>>
891 parser;
892
Ed Tanous3112a142018-11-29 15:45:10 -0800893 boost::beast::flat_static_buffer<8192> buffer;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700894
Ed Tanousa24526d2018-12-10 15:17:59 -0800895 std::optional<boost::beast::http::response_serializer<
Ed Tanous1abe55e2018-09-05 08:30:59 -0700896 boost::beast::http::string_body>>
897 serializer;
898
Ed Tanousa24526d2018-12-10 15:17:59 -0800899 std::optional<crow::Request> req;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700900 crow::Response res;
Kowalski, Kamil55e43f62019-07-10 13:12:57 +0200901#ifdef BMCWEB_ENABLE_MUTUAL_TLS_AUTHENTICATION
902 std::weak_ptr<crow::persistent_data::UserSession> session;
903#endif // BMCWEB_ENABLE_MUTUAL_TLS_AUTHENTICATION
Ed Tanous1abe55e2018-09-05 08:30:59 -0700904
905 const std::string& serverName;
906
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000907 std::optional<size_t> timerCancelKey;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700908
Ed Tanous1abe55e2018-09-05 08:30:59 -0700909 bool needToCallAfterHandlers{};
910 bool needToStartReadAfterComplete{};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700911
912 std::tuple<Middlewares...>* middlewares;
913 detail::Context<Middlewares...> ctx;
914
915 std::function<std::string()>& getCachedDateStr;
916 detail::TimerQueue& timerQueue;
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000917
918 using std::enable_shared_from_this<
919 Connection<Adaptor, Handler, Middlewares...>>::shared_from_this;
Ed Tanous3112a142018-11-29 15:45:10 -0800920};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700921} // namespace crow