xref: /openbmc/bmcweb/http/http_connection.hpp (revision 37b912fd9596ca66736b9d20de856bf4e66e9898)
140e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0
240e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors
304e438cbSEd Tanous #pragma once
475312981SEd Tanous #include "bmcweb_config.h"
504e438cbSEd Tanous 
6d093c996SEd Tanous #include "async_resp.hpp"
7d055a34aSNan Zhou #include "authentication.hpp"
8ed5f8954SEd Tanous #include "complete_response_fields.hpp"
9d7857201SEd Tanous #include "forward_unauthorized.hpp"
10fca2cbeaSEd Tanous #include "http2_connection.hpp"
11b2896149SEd Tanous #include "http_body.hpp"
12796ba93bSEd Tanous #include "http_connect_types.hpp"
13d7857201SEd Tanous #include "http_request.hpp"
1404e438cbSEd Tanous #include "http_response.hpp"
1504e438cbSEd Tanous #include "http_utility.hpp"
1604e438cbSEd Tanous #include "logging.hpp"
173ccb3adbSEd Tanous #include "mutual_tls.hpp"
18d7857201SEd Tanous #include "sessions.hpp"
1918f8f608SEd Tanous #include "str_utility.hpp"
20cd7dbb30SEd Tanous #include "utility.hpp"
2104e438cbSEd Tanous 
22d7857201SEd Tanous #include <boost/asio/error.hpp>
2304e438cbSEd Tanous #include <boost/asio/ip/tcp.hpp>
2404e438cbSEd Tanous #include <boost/asio/ssl/stream.hpp>
25d7857201SEd Tanous #include <boost/asio/ssl/stream_base.hpp>
26d7857201SEd Tanous #include <boost/asio/ssl/verify_context.hpp>
275dfb5b2dSEd Tanous #include <boost/asio/steady_timer.hpp>
284fa45dffSEd Tanous #include <boost/beast/_experimental/test/stream.hpp>
294d69861fSEd Tanous #include <boost/beast/core/buffers_generator.hpp>
30796ba93bSEd Tanous #include <boost/beast/core/detect_ssl.hpp>
31796ba93bSEd Tanous #include <boost/beast/core/error.hpp>
3204e438cbSEd Tanous #include <boost/beast/core/flat_static_buffer.hpp>
33a4326fe2SMyung Bae #include <boost/beast/http/error.hpp>
34d7857201SEd Tanous #include <boost/beast/http/field.hpp>
354d69861fSEd Tanous #include <boost/beast/http/message_generator.hpp>
36918ef25bSEd Tanous #include <boost/beast/http/parser.hpp>
37918ef25bSEd Tanous #include <boost/beast/http/read.hpp>
38cd7dbb30SEd Tanous #include <boost/beast/http/rfc7230.hpp>
39d7857201SEd Tanous #include <boost/beast/http/status.hpp>
40d7857201SEd Tanous #include <boost/beast/http/verb.hpp>
41d7857201SEd Tanous #include <boost/none.hpp>
42d7857201SEd Tanous #include <boost/optional/optional.hpp>
4304e438cbSEd Tanous 
44d7857201SEd Tanous #include <bit>
4504e438cbSEd Tanous #include <chrono>
46d7857201SEd Tanous #include <cstddef>
47d7857201SEd Tanous #include <cstdint>
48d7857201SEd Tanous #include <functional>
49102a4cdaSJonathan Doman #include <memory>
50d7857201SEd Tanous #include <optional>
51d7857201SEd Tanous #include <string>
52d7857201SEd Tanous #include <string_view>
53d7857201SEd Tanous #include <system_error>
54d7857201SEd Tanous #include <type_traits>
55d7857201SEd Tanous #include <utility>
5604e438cbSEd Tanous 
5704e438cbSEd Tanous namespace crow
5804e438cbSEd Tanous {
5904e438cbSEd Tanous 
60cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
616fbdbcabSEd Tanous static int connectionCount = 0;
6204e438cbSEd Tanous 
6325b54dbaSEd Tanous // request body limit size set by the BMCWEB_HTTP_BODY_LIMIT option
6425b54dbaSEd Tanous constexpr uint64_t httpReqBodyLimit = 1024UL * 1024UL * BMCWEB_HTTP_BODY_LIMIT;
6504e438cbSEd Tanous 
661d1d7784SEd Tanous constexpr uint64_t loggedOutPostBodyLimit = 4096U;
6704e438cbSEd Tanous 
681d1d7784SEd Tanous constexpr uint32_t httpHeaderLimit = 8192U;
6904e438cbSEd Tanous 
7004e438cbSEd Tanous template <typename Adaptor, typename Handler>
7104e438cbSEd Tanous class Connection :
7204e438cbSEd Tanous     public std::enable_shared_from_this<Connection<Adaptor, Handler>>
7304e438cbSEd Tanous {
747c8e064dSEd Tanous     using self_type = Connection<Adaptor, Handler>;
757c8e064dSEd Tanous 
7604e438cbSEd Tanous   public:
Connection(Handler * handlerIn,HttpType httpTypeIn,boost::asio::steady_timer && timerIn,std::function<std::string ()> & getCachedDateStrF,boost::asio::ssl::stream<Adaptor> && adaptorIn)77796ba93bSEd Tanous     Connection(Handler* handlerIn, HttpType httpTypeIn,
78796ba93bSEd Tanous                boost::asio::steady_timer&& timerIn,
7981ce609eSEd Tanous                std::function<std::string()>& getCachedDateStrF,
80796ba93bSEd Tanous                boost::asio::ssl::stream<Adaptor>&& adaptorIn) :
81796ba93bSEd Tanous         httpType(httpTypeIn), adaptor(std::move(adaptorIn)), handler(handlerIn),
82bd79bce8SPatrick Williams         timer(std::move(timerIn)), getCachedDateStr(getCachedDateStrF)
8304e438cbSEd Tanous     {
841d1d7784SEd Tanous         initParser();
8504e438cbSEd Tanous 
8640aa058dSEd Tanous         connectionCount++;
876fbdbcabSEd Tanous 
881d1d7784SEd Tanous         BMCWEB_LOG_DEBUG("{} Connection created, total {}", logPtr(this),
8962598e31SEd Tanous                          connectionCount);
9040aa058dSEd Tanous     }
9140aa058dSEd Tanous 
~Connection()9240aa058dSEd Tanous     ~Connection()
9340aa058dSEd Tanous     {
941d1d7784SEd Tanous         res.releaseCompleteRequestHandler();
9540aa058dSEd Tanous         cancelDeadlineTimer();
966fbdbcabSEd Tanous 
9740aa058dSEd Tanous         connectionCount--;
9862598e31SEd Tanous         BMCWEB_LOG_DEBUG("{} Connection closed, total {}", logPtr(this),
9962598e31SEd Tanous                          connectionCount);
10040aa058dSEd Tanous     }
10140aa058dSEd Tanous 
102ecd6a3a2SEd Tanous     Connection(const Connection&) = delete;
103ecd6a3a2SEd Tanous     Connection(Connection&&) = delete;
104ecd6a3a2SEd Tanous     Connection& operator=(const Connection&) = delete;
105ecd6a3a2SEd Tanous     Connection& operator=(Connection&&) = delete;
106ecd6a3a2SEd Tanous 
tlsVerifyCallback(bool preverified,boost::asio::ssl::verify_context & ctx)1077c8e064dSEd Tanous     bool tlsVerifyCallback(bool preverified,
1087c8e064dSEd Tanous                            boost::asio::ssl::verify_context& ctx)
1097c8e064dSEd Tanous     {
1103281bcf1SEd Tanous         BMCWEB_LOG_DEBUG("{} tlsVerifyCallback called with preverified {}",
1113281bcf1SEd Tanous                          logPtr(this), preverified);
1127c8e064dSEd Tanous         if (preverified)
1137c8e064dSEd Tanous         {
1141d1d7784SEd Tanous             mtlsSession = verifyMtlsUser(ip, ctx);
115b4963077SBoleslaw Ogonczyk Makowski             if (mtlsSession)
1167c8e064dSEd Tanous             {
1173281bcf1SEd Tanous                 BMCWEB_LOG_DEBUG("{} Generated TLS session: {}", logPtr(this),
11862598e31SEd Tanous                                  mtlsSession->uniqueId);
1197c8e064dSEd Tanous             }
1207c8e064dSEd Tanous         }
1213281bcf1SEd Tanous         const persistent_data::AuthConfigMethods& c =
1223281bcf1SEd Tanous             persistent_data::SessionStore::getInstance().getAuthMethodsConfig();
1233281bcf1SEd Tanous         if (c.tlsStrict)
1243281bcf1SEd Tanous         {
125463a0e3eSEd Tanous             BMCWEB_LOG_DEBUG(
126463a0e3eSEd Tanous                 "{} TLS is in strict mode, returning preverified as is.",
127463a0e3eSEd Tanous                 logPtr(this));
1283281bcf1SEd Tanous             return preverified;
1293281bcf1SEd Tanous         }
1303281bcf1SEd Tanous         // If tls strict mode is disabled
1313281bcf1SEd Tanous         // We always return true to allow full auth flow for resources that
1323281bcf1SEd Tanous         // don't require auth
1337c8e064dSEd Tanous         return true;
1347c8e064dSEd Tanous     }
1357c8e064dSEd Tanous 
prepareMutualTls()1363281bcf1SEd Tanous     bool prepareMutualTls()
13740aa058dSEd Tanous     {
1383281bcf1SEd Tanous         BMCWEB_LOG_DEBUG("prepareMutualTls");
13946ff87baSEd Tanous 
1403281bcf1SEd Tanous         constexpr std::string_view id = "bmcweb";
1413281bcf1SEd Tanous 
1423281bcf1SEd Tanous         const char* idPtr = id.data();
1433281bcf1SEd Tanous         const auto* idCPtr = std::bit_cast<const unsigned char*>(idPtr);
1443281bcf1SEd Tanous         auto idLen = static_cast<unsigned int>(id.length());
145796ba93bSEd Tanous         int ret =
146796ba93bSEd Tanous             SSL_set_session_id_context(adaptor.native_handle(), idCPtr, idLen);
14704e438cbSEd Tanous         if (ret == 0)
14804e438cbSEd Tanous         {
14962598e31SEd Tanous             BMCWEB_LOG_ERROR("{} failed to set SSL id", logPtr(this));
1503281bcf1SEd Tanous             return false;
15104e438cbSEd Tanous         }
15204e438cbSEd Tanous 
1533281bcf1SEd Tanous         BMCWEB_LOG_DEBUG("set_verify_callback");
1543281bcf1SEd Tanous 
1553281bcf1SEd Tanous         boost::system::error_code ec;
156002d39b4SEd Tanous         adaptor.set_verify_callback(
1573281bcf1SEd Tanous             std::bind_front(&self_type::tlsVerifyCallback, this), ec);
1583281bcf1SEd Tanous         if (ec)
1593281bcf1SEd Tanous         {
1603281bcf1SEd Tanous             BMCWEB_LOG_ERROR("Failed to set verify callback {}", ec);
1613281bcf1SEd Tanous             return false;
16204e438cbSEd Tanous         }
16304e438cbSEd Tanous 
1643281bcf1SEd Tanous         return true;
16504e438cbSEd Tanous     }
16604e438cbSEd Tanous 
afterDetectSsl(const std::shared_ptr<self_type> &,boost::beast::error_code ec,bool isTls)167796ba93bSEd Tanous     void afterDetectSsl(const std::shared_ptr<self_type>& /*self*/,
168796ba93bSEd Tanous                         boost::beast::error_code ec, bool isTls)
169796ba93bSEd Tanous     {
170796ba93bSEd Tanous         if (ec)
171796ba93bSEd Tanous         {
172796ba93bSEd Tanous             BMCWEB_LOG_ERROR("Couldn't detect ssl ", ec);
173796ba93bSEd Tanous             return;
174796ba93bSEd Tanous         }
175796ba93bSEd Tanous         BMCWEB_LOG_DEBUG("{} TLS was detected as {}", logPtr(this), isTls);
176796ba93bSEd Tanous         if (isTls)
177796ba93bSEd Tanous         {
178796ba93bSEd Tanous             if (httpType != HttpType::HTTPS && httpType != HttpType::BOTH)
179796ba93bSEd Tanous             {
180796ba93bSEd Tanous                 BMCWEB_LOG_WARNING(
181796ba93bSEd Tanous                     "{} Connection closed due to incompatible type",
182796ba93bSEd Tanous                     logPtr(this));
183796ba93bSEd Tanous                 return;
184796ba93bSEd Tanous             }
185796ba93bSEd Tanous             httpType = HttpType::HTTPS;
186796ba93bSEd Tanous             adaptor.async_handshake(
187796ba93bSEd Tanous                 boost::asio::ssl::stream_base::server, buffer.data(),
188796ba93bSEd Tanous                 std::bind_front(&self_type::afterSslHandshake, this,
189796ba93bSEd Tanous                                 shared_from_this()));
190796ba93bSEd Tanous         }
191796ba93bSEd Tanous         else
192796ba93bSEd Tanous         {
193796ba93bSEd Tanous             if (httpType != HttpType::HTTP && httpType != HttpType::BOTH)
194796ba93bSEd Tanous             {
195796ba93bSEd Tanous                 BMCWEB_LOG_WARNING(
196796ba93bSEd Tanous                     "{} Connection closed due to incompatible type",
197796ba93bSEd Tanous                     logPtr(this));
198796ba93bSEd Tanous                 return;
199796ba93bSEd Tanous             }
200796ba93bSEd Tanous 
201796ba93bSEd Tanous             httpType = HttpType::HTTP;
202796ba93bSEd Tanous             BMCWEB_LOG_INFO("Starting non-SSL session");
203796ba93bSEd Tanous             doReadHeaders();
204796ba93bSEd Tanous         }
205796ba93bSEd Tanous     }
206796ba93bSEd Tanous 
start()20704e438cbSEd Tanous     void start()
20804e438cbSEd Tanous     {
2091d1d7784SEd Tanous         BMCWEB_LOG_DEBUG("{} Connection started, total {}", logPtr(this),
2101d1d7784SEd Tanous                          connectionCount);
2114f63be0cSGunnar Mills         if (connectionCount >= 200)
2126fbdbcabSEd Tanous         {
21362598e31SEd Tanous             BMCWEB_LOG_CRITICAL("{} Max connection count exceeded.",
21462598e31SEd Tanous                                 logPtr(this));
2156fbdbcabSEd Tanous             return;
2166fbdbcabSEd Tanous         }
2176fbdbcabSEd Tanous 
2183281bcf1SEd Tanous         if constexpr (BMCWEB_MUTUAL_TLS_AUTH)
2193281bcf1SEd Tanous         {
2203281bcf1SEd Tanous             if (!prepareMutualTls())
2213281bcf1SEd Tanous             {
2223281bcf1SEd Tanous                 BMCWEB_LOG_ERROR("{} Failed to prepare mTLS", logPtr(this));
2233281bcf1SEd Tanous                 return;
2243281bcf1SEd Tanous             }
2253281bcf1SEd Tanous         }
2263281bcf1SEd Tanous 
2275dfb5b2dSEd Tanous         startDeadline();
228c0ea7ae1SSunitha Harish 
2291d1d7784SEd Tanous         readClientIp();
230796ba93bSEd Tanous         boost::beast::async_detect_ssl(
231796ba93bSEd Tanous             adaptor.next_layer(), buffer,
232796ba93bSEd Tanous             std::bind_front(&self_type::afterDetectSsl, this,
233796ba93bSEd Tanous                             shared_from_this()));
234796ba93bSEd Tanous     }
2351d1d7784SEd Tanous 
afterSslHandshake(const std::shared_ptr<self_type> &,const boost::system::error_code & ec,size_t bytesParsed)236796ba93bSEd Tanous     void afterSslHandshake(const std::shared_ptr<self_type>& /*self*/,
237796ba93bSEd Tanous                            const boost::system::error_code& ec,
238796ba93bSEd Tanous                            size_t bytesParsed)
23904e438cbSEd Tanous     {
240796ba93bSEd Tanous         buffer.consume(bytesParsed);
24104e438cbSEd Tanous         if (ec)
24204e438cbSEd Tanous         {
243796ba93bSEd Tanous             BMCWEB_LOG_ERROR("{} SSL handshake failed", logPtr(this));
24404e438cbSEd Tanous             return;
24504e438cbSEd Tanous         }
246796ba93bSEd Tanous         BMCWEB_LOG_DEBUG("{} SSL handshake succeeded", logPtr(this));
247fca2cbeaSEd Tanous         // If http2 is enabled, negotiate the protocol
24825b54dbaSEd Tanous         if constexpr (BMCWEB_EXPERIMENTAL_HTTP2)
249fca2cbeaSEd Tanous         {
250fca2cbeaSEd Tanous             const unsigned char* alpn = nullptr;
251fca2cbeaSEd Tanous             unsigned int alpnlen = 0;
252fca2cbeaSEd Tanous             SSL_get0_alpn_selected(adaptor.native_handle(), &alpn, &alpnlen);
253fca2cbeaSEd Tanous             if (alpn != nullptr)
254fca2cbeaSEd Tanous             {
255fca2cbeaSEd Tanous                 std::string_view selectedProtocol(
256fca2cbeaSEd Tanous                     std::bit_cast<const char*>(alpn), alpnlen);
25762598e31SEd Tanous                 BMCWEB_LOG_DEBUG("ALPN selected protocol \"{}\" len: {}",
25862598e31SEd Tanous                                  selectedProtocol, alpnlen);
259fca2cbeaSEd Tanous                 if (selectedProtocol == "h2")
260fca2cbeaSEd Tanous                 {
261796ba93bSEd Tanous                     upgradeToHttp2();
262fca2cbeaSEd Tanous                     return;
263fca2cbeaSEd Tanous                 }
264fca2cbeaSEd Tanous             }
265fca2cbeaSEd Tanous         }
266fca2cbeaSEd Tanous 
267fca2cbeaSEd Tanous         doReadHeaders();
268fca2cbeaSEd Tanous     }
269fca2cbeaSEd Tanous 
initParser()2701d1d7784SEd Tanous     void initParser()
2711d1d7784SEd Tanous     {
2721d1d7784SEd Tanous         boost::beast::http::request_parser<bmcweb::HttpBody>& instance =
27338afdb91SEd Tanous             parser.emplace();
2741d1d7784SEd Tanous 
2751d1d7784SEd Tanous         // reset header limit for newly created parser
2761d1d7784SEd Tanous         instance.header_limit(httpHeaderLimit);
2771d1d7784SEd Tanous 
2781d1d7784SEd Tanous         // Initially set no body limit. We don't yet know if the user is
2791d1d7784SEd Tanous         // authenticated.
2801d1d7784SEd Tanous         instance.body_limit(boost::none);
2811d1d7784SEd Tanous     }
2821d1d7784SEd Tanous 
upgradeToHttp2()283796ba93bSEd Tanous     void upgradeToHttp2()
284796ba93bSEd Tanous     {
285796ba93bSEd Tanous         auto http2 = std::make_shared<HTTP2Connection<Adaptor, Handler>>(
286ebe4c574SEd Tanous             std::move(adaptor), handler, getCachedDateStr, httpType);
287796ba93bSEd Tanous         if (http2settings.empty())
288796ba93bSEd Tanous         {
289796ba93bSEd Tanous             http2->start();
290796ba93bSEd Tanous         }
291796ba93bSEd Tanous         else
292796ba93bSEd Tanous         {
293796ba93bSEd Tanous             http2->startFromSettings(http2settings);
294796ba93bSEd Tanous         }
295796ba93bSEd Tanous     }
296796ba93bSEd Tanous 
297cd7dbb30SEd Tanous     // returns whether connection was upgraded
doUpgrade(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)298cd7dbb30SEd Tanous     bool doUpgrade(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
299cd7dbb30SEd Tanous     {
300cd7dbb30SEd Tanous         using boost::beast::http::field;
301cd7dbb30SEd Tanous         using boost::beast::http::token_list;
302cd7dbb30SEd Tanous 
303cd7dbb30SEd Tanous         bool isSse =
304cd7dbb30SEd Tanous             isContentTypeAllowed(req->getHeaderValue("Accept"),
305cd7dbb30SEd Tanous                                  http_helpers::ContentType::EventStream, false);
306cd7dbb30SEd Tanous 
307cd7dbb30SEd Tanous         bool isWebsocket = false;
308cd7dbb30SEd Tanous         bool isH2c = false;
309cd7dbb30SEd Tanous         // Check connection header is upgrade
310cd7dbb30SEd Tanous         if (token_list{req->req[field::connection]}.exists("upgrade"))
311cd7dbb30SEd Tanous         {
312cd7dbb30SEd Tanous             BMCWEB_LOG_DEBUG("{} Connection: Upgrade header was present",
313cd7dbb30SEd Tanous                              logPtr(this));
314cd7dbb30SEd Tanous             // Parse if upgrade is h2c or websocket
315cd7dbb30SEd Tanous             token_list upgrade{req->req[field::upgrade]};
316cd7dbb30SEd Tanous             isWebsocket = upgrade.exists("websocket");
317cd7dbb30SEd Tanous             isH2c = upgrade.exists("h2c");
318cd7dbb30SEd Tanous             BMCWEB_LOG_DEBUG("{} Upgrade isWebsocket: {} isH2c: {}",
319cd7dbb30SEd Tanous                              logPtr(this), isWebsocket, isH2c);
320cd7dbb30SEd Tanous         }
321cd7dbb30SEd Tanous 
322cd7dbb30SEd Tanous         if (BMCWEB_EXPERIMENTAL_HTTP2 && isH2c)
323cd7dbb30SEd Tanous         {
324cd7dbb30SEd Tanous             std::string_view base64settings = req->req[field::http2_settings];
325cd7dbb30SEd Tanous             if (utility::base64Decode<true>(base64settings, http2settings))
326cd7dbb30SEd Tanous             {
327cd7dbb30SEd Tanous                 res.result(boost::beast::http::status::switching_protocols);
328cd7dbb30SEd Tanous                 res.addHeader(boost::beast::http::field::connection, "Upgrade");
329cd7dbb30SEd Tanous                 res.addHeader(boost::beast::http::field::upgrade, "h2c");
330cd7dbb30SEd Tanous             }
331cd7dbb30SEd Tanous         }
332cd7dbb30SEd Tanous 
333cd7dbb30SEd Tanous         // websocket and SSE are only allowed on GET
334cd7dbb30SEd Tanous         if (req->req.method() == boost::beast::http::verb::get)
335cd7dbb30SEd Tanous         {
336cd7dbb30SEd Tanous             if (isWebsocket || isSse)
337cd7dbb30SEd Tanous             {
338cd7dbb30SEd Tanous                 asyncResp->res.setCompleteRequestHandler(
339cd7dbb30SEd Tanous                     [self(shared_from_this())](crow::Response& thisRes) {
340cd7dbb30SEd Tanous                         if (thisRes.result() != boost::beast::http::status::ok)
341cd7dbb30SEd Tanous                         {
342cd7dbb30SEd Tanous                             // When any error occurs before handle upgradation,
343cd7dbb30SEd Tanous                             // the result in response will be set to respective
344cd7dbb30SEd Tanous                             // error. By default the Result will be OK (200),
345cd7dbb30SEd Tanous                             // which implies successful handle upgrade. Response
346cd7dbb30SEd Tanous                             // needs to be sent over this connection only on
347cd7dbb30SEd Tanous                             // failure.
348cd7dbb30SEd Tanous                             self->completeRequest(thisRes);
349cd7dbb30SEd Tanous                             return;
350cd7dbb30SEd Tanous                         }
351cd7dbb30SEd Tanous                     });
352cd7dbb30SEd Tanous                 BMCWEB_LOG_INFO("{} Upgrading socket", logPtr(this));
353796ba93bSEd Tanous                 if (httpType == HttpType::HTTP)
354796ba93bSEd Tanous                 {
355796ba93bSEd Tanous                     handler->handleUpgrade(req, asyncResp,
356796ba93bSEd Tanous                                            std::move(adaptor.next_layer()));
357796ba93bSEd Tanous                 }
358796ba93bSEd Tanous                 else
359796ba93bSEd Tanous                 {
360cd7dbb30SEd Tanous                     handler->handleUpgrade(req, asyncResp, std::move(adaptor));
361796ba93bSEd Tanous                 }
362796ba93bSEd Tanous 
363cd7dbb30SEd Tanous                 return true;
364cd7dbb30SEd Tanous             }
365cd7dbb30SEd Tanous         }
366cd7dbb30SEd Tanous         return false;
367cd7dbb30SEd Tanous     }
368cd7dbb30SEd Tanous 
handle()36904e438cbSEd Tanous     void handle()
37004e438cbSEd Tanous     {
371f79b7a50SEd Tanous         std::error_code reqEc;
372e01d0c36SEd Tanous         if (!parser)
373e01d0c36SEd Tanous         {
374e01d0c36SEd Tanous             return;
375e01d0c36SEd Tanous         }
376102a4cdaSJonathan Doman         req = std::make_shared<crow::Request>(parser->release(), reqEc);
377f79b7a50SEd Tanous         if (reqEc)
378f79b7a50SEd Tanous         {
37962598e31SEd Tanous             BMCWEB_LOG_DEBUG("Request failed to construct{}", reqEc.message());
380262f1152SGunnar Mills             res.result(boost::beast::http::status::bad_request);
381262f1152SGunnar Mills             completeRequest(res);
382f79b7a50SEd Tanous             return;
383f79b7a50SEd Tanous         }
384102a4cdaSJonathan Doman         req->session = userSession;
38589cda63dSEd Tanous         accept = req->getHeaderValue("Accept");
386f65b0beaSIvan Mikhaylov         // Fetch the client IP address
387102a4cdaSJonathan Doman         req->ipAddress = ip;
388f65b0beaSIvan Mikhaylov 
38904e438cbSEd Tanous         // Check for HTTP version 1.1.
390102a4cdaSJonathan Doman         if (req->version() == 11)
39104e438cbSEd Tanous         {
392102a4cdaSJonathan Doman             if (req->getHeaderValue(boost::beast::http::field::host).empty())
39304e438cbSEd Tanous             {
39404e438cbSEd Tanous                 res.result(boost::beast::http::status::bad_request);
39572374eb7SNan Zhou                 completeRequest(res);
3966c7f01ddSEd Tanous                 return;
39704e438cbSEd Tanous             }
39804e438cbSEd Tanous         }
39904e438cbSEd Tanous 
40062598e31SEd Tanous         BMCWEB_LOG_INFO("Request:  {} HTTP/{}.{} {} {} {}", logPtr(this),
401102a4cdaSJonathan Doman                         req->version() / 10, req->version() % 10,
402102a4cdaSJonathan Doman                         req->methodString(), req->target(),
403102a4cdaSJonathan Doman                         req->ipAddress.to_string());
404d32c4fa9SEd Tanous 
4056c7f01ddSEd Tanous         if (res.completed)
40604e438cbSEd Tanous         {
40772374eb7SNan Zhou             completeRequest(res);
4086c7f01ddSEd Tanous             return;
4096c7f01ddSEd Tanous         }
410102a4cdaSJonathan Doman         keepAlive = req->keepAlive();
411796ba93bSEd Tanous 
412796ba93bSEd Tanous         if (authenticationEnabled)
41383328316SEd Tanous         {
414102a4cdaSJonathan Doman             if (!crow::authentication::isOnAllowlist(req->url().path(),
415102a4cdaSJonathan Doman                                                      req->method()) &&
416102a4cdaSJonathan Doman                 req->session == nullptr)
4171d3c14aaSEd Tanous             {
41862598e31SEd Tanous                 BMCWEB_LOG_WARNING("Authentication failed");
4191d3c14aaSEd Tanous                 forward_unauthorized::sendUnauthorized(
420102a4cdaSJonathan Doman                     req->url().encoded_path(),
421102a4cdaSJonathan Doman                     req->getHeaderValue("X-Requested-With"),
422102a4cdaSJonathan Doman                     req->getHeaderValue("Accept"), res);
42372374eb7SNan Zhou                 completeRequest(res);
4241d3c14aaSEd Tanous                 return;
4251d3c14aaSEd Tanous             }
42683328316SEd Tanous         }
427796ba93bSEd Tanous 
42872374eb7SNan Zhou         auto asyncResp = std::make_shared<bmcweb::AsyncResp>();
42962598e31SEd Tanous         BMCWEB_LOG_DEBUG("Setting completion handler");
43072374eb7SNan Zhou         asyncResp->res.setCompleteRequestHandler(
43172374eb7SNan Zhou             [self(shared_from_this())](crow::Response& thisRes) {
43272374eb7SNan Zhou                 self->completeRequest(thisRes);
4334147b8acSJohn Edward Broadbent             });
434cd7dbb30SEd Tanous         if (doUpgrade(asyncResp))
43504e438cbSEd Tanous         {
43604e438cbSEd Tanous             return;
43704e438cbSEd Tanous         }
438291d709dSEd Tanous         std::string_view expected =
439102a4cdaSJonathan Doman             req->getHeaderValue(boost::beast::http::field::if_none_match);
440291d709dSEd Tanous         if (!expected.empty())
441291d709dSEd Tanous         {
442*37b912fdSEd Tanous             asyncResp->res.setExpectedHash(expected);
443291d709dSEd Tanous         }
44452e31629SEd Tanous         handler->handle(req, asyncResp);
44504e438cbSEd Tanous     }
44604e438cbSEd Tanous 
hardClose()4471d1d7784SEd Tanous     void hardClose()
44804e438cbSEd Tanous     {
4491d1d7784SEd Tanous         BMCWEB_LOG_DEBUG("{} Closing socket", logPtr(this));
450796ba93bSEd Tanous         adaptor.next_layer().close();
4511d1d7784SEd Tanous     }
4521d1d7784SEd Tanous 
tlsShutdownComplete(const std::shared_ptr<self_type> & self,const boost::system::error_code & ec)4531d1d7784SEd Tanous     void tlsShutdownComplete(const std::shared_ptr<self_type>& self,
4541d1d7784SEd Tanous                              const boost::system::error_code& ec)
45504e438cbSEd Tanous     {
4561d1d7784SEd Tanous         if (ec)
4571d1d7784SEd Tanous         {
4581d1d7784SEd Tanous             BMCWEB_LOG_WARNING("{} Failed to shut down TLS cleanly {}",
4591d1d7784SEd Tanous                                logPtr(self.get()), ec);
4601d1d7784SEd Tanous         }
4611d1d7784SEd Tanous         self->hardClose();
4621d1d7784SEd Tanous     }
4631d1d7784SEd Tanous 
gracefulClose()4641d1d7784SEd Tanous     void gracefulClose()
4651d1d7784SEd Tanous     {
4661d1d7784SEd Tanous         BMCWEB_LOG_DEBUG("{} Socket close requested", logPtr(this));
4673281bcf1SEd Tanous 
468796ba93bSEd Tanous         if (httpType == HttpType::HTTPS)
4691d1d7784SEd Tanous         {
470796ba93bSEd Tanous             if (mtlsSession != nullptr)
471796ba93bSEd Tanous             {
472796ba93bSEd Tanous                 BMCWEB_LOG_DEBUG("{} Removing TLS session: {}", logPtr(this),
473796ba93bSEd Tanous                                  mtlsSession->uniqueId);
474796ba93bSEd Tanous                 persistent_data::SessionStore::getInstance().removeSession(
475796ba93bSEd Tanous                     mtlsSession);
476796ba93bSEd Tanous             }
477796ba93bSEd Tanous 
4781d1d7784SEd Tanous             adaptor.async_shutdown(std::bind_front(
4791d1d7784SEd Tanous                 &self_type::tlsShutdownComplete, this, shared_from_this()));
48004e438cbSEd Tanous         }
48104e438cbSEd Tanous         else
48204e438cbSEd Tanous         {
4831d1d7784SEd Tanous             hardClose();
48404e438cbSEd Tanous         }
48504e438cbSEd Tanous     }
48604e438cbSEd Tanous 
completeRequest(crow::Response & thisRes)48772374eb7SNan Zhou     void completeRequest(crow::Response& thisRes)
48804e438cbSEd Tanous     {
48972374eb7SNan Zhou         res = std::move(thisRes);
4904cdc2e8dSEd Tanous         res.keepAlive(keepAlive);
4915ae6f925SEd Tanous 
49289cda63dSEd Tanous         completeResponseFields(accept, res);
493998e0cbdSEd Tanous         res.addHeader(boost::beast::http::field::date, getCachedDateStr());
494291d709dSEd Tanous 
49552e31629SEd Tanous         doWrite();
49604e438cbSEd Tanous 
49704e438cbSEd Tanous         // delete lambda with self shared_ptr
49804e438cbSEd Tanous         // to enable connection destruction
4994147b8acSJohn Edward Broadbent         res.setCompleteRequestHandler(nullptr);
50004e438cbSEd Tanous     }
50104e438cbSEd Tanous 
readClientIp()502c0ea7ae1SSunitha Harish     void readClientIp()
503c0ea7ae1SSunitha Harish     {
504c0ea7ae1SSunitha Harish         boost::system::error_code ec;
5054fa45dffSEd Tanous 
506c0ea7ae1SSunitha Harish         boost::asio::ip::tcp::endpoint endpoint =
507c0ea7ae1SSunitha Harish             boost::beast::get_lowest_layer(adaptor).remote_endpoint(ec);
508c0ea7ae1SSunitha Harish 
509c0ea7ae1SSunitha Harish         if (ec)
510c0ea7ae1SSunitha Harish         {
511c0ea7ae1SSunitha Harish             // If remote endpoint fails keep going. "ClientOriginIPAddress"
512c0ea7ae1SSunitha Harish             // will be empty.
513796ba93bSEd Tanous             BMCWEB_LOG_ERROR("Failed to get the client's IP Address. ec : {}",
514796ba93bSEd Tanous                              ec);
5151d1d7784SEd Tanous             return;
516c0ea7ae1SSunitha Harish         }
51759b98b22SJohn Edward Broadbent         ip = endpoint.address();
5184fa45dffSEd Tanous     }
519796ba93bSEd Tanous 
disableAuth()520796ba93bSEd Tanous     void disableAuth()
521796ba93bSEd Tanous     {
522796ba93bSEd Tanous         authenticationEnabled = false;
523c0ea7ae1SSunitha Harish     }
524c0ea7ae1SSunitha Harish 
52504e438cbSEd Tanous   private:
getContentLengthLimit()5261d1d7784SEd Tanous     uint64_t getContentLengthLimit()
5271d1d7784SEd Tanous     {
52883328316SEd Tanous         if constexpr (!BMCWEB_INSECURE_DISABLE_AUTH)
52983328316SEd Tanous         {
5301d1d7784SEd Tanous             if (userSession == nullptr)
5311d1d7784SEd Tanous             {
5321d1d7784SEd Tanous                 return loggedOutPostBodyLimit;
5331d1d7784SEd Tanous             }
53483328316SEd Tanous         }
5351d1d7784SEd Tanous 
5361d1d7784SEd Tanous         return httpReqBodyLimit;
5371d1d7784SEd Tanous     }
5381d1d7784SEd Tanous 
5391d1d7784SEd Tanous     // Returns true if content length was within limits
5401d1d7784SEd Tanous     // Returns false if content length error has been returned
handleContentLengthError()5411d1d7784SEd Tanous     bool handleContentLengthError()
5421d1d7784SEd Tanous     {
5431d1d7784SEd Tanous         if (!parser)
5441d1d7784SEd Tanous         {
545efff2b5dSManojkiran Eda             BMCWEB_LOG_CRITICAL("Parser was null");
5461d1d7784SEd Tanous             return false;
5471d1d7784SEd Tanous         }
5481d1d7784SEd Tanous         const boost::optional<uint64_t> contentLength =
5491d1d7784SEd Tanous             parser->content_length();
5501d1d7784SEd Tanous         if (!contentLength)
5511d1d7784SEd Tanous         {
5521d1d7784SEd Tanous             BMCWEB_LOG_DEBUG("{} No content length available", logPtr(this));
5531d1d7784SEd Tanous             return true;
5541d1d7784SEd Tanous         }
5551d1d7784SEd Tanous 
5561d1d7784SEd Tanous         uint64_t maxAllowedContentLength = getContentLengthLimit();
5571d1d7784SEd Tanous 
5581d1d7784SEd Tanous         if (*contentLength > maxAllowedContentLength)
5591d1d7784SEd Tanous         {
5601d1d7784SEd Tanous             // If the users content limit is between the logged in
5611d1d7784SEd Tanous             // and logged out limits They probably just didn't log
5621d1d7784SEd Tanous             // in
5631d1d7784SEd Tanous             if (*contentLength > loggedOutPostBodyLimit &&
5641d1d7784SEd Tanous                 *contentLength < httpReqBodyLimit)
5651d1d7784SEd Tanous             {
5661d1d7784SEd Tanous                 BMCWEB_LOG_DEBUG(
5671d1d7784SEd Tanous                     "{} Content length {} valid, but greater than logged out"
5681d1d7784SEd Tanous                     " limit of {}. Setting unauthorized",
5691d1d7784SEd Tanous                     logPtr(this), *contentLength, loggedOutPostBodyLimit);
5701d1d7784SEd Tanous                 res.result(boost::beast::http::status::unauthorized);
5711d1d7784SEd Tanous             }
5721d1d7784SEd Tanous             else
5731d1d7784SEd Tanous             {
5741d1d7784SEd Tanous                 // Otherwise they're over both limits, so inform
5751d1d7784SEd Tanous                 // them
5761d1d7784SEd Tanous                 BMCWEB_LOG_DEBUG(
5771d1d7784SEd Tanous                     "{} Content length {} was greater than global limit {}."
5781d1d7784SEd Tanous                     " Setting payload too large",
5791d1d7784SEd Tanous                     logPtr(this), *contentLength, httpReqBodyLimit);
5801d1d7784SEd Tanous                 res.result(boost::beast::http::status::payload_too_large);
5811d1d7784SEd Tanous             }
5821d1d7784SEd Tanous 
5831d1d7784SEd Tanous             keepAlive = false;
5841d1d7784SEd Tanous             doWrite();
5851d1d7784SEd Tanous             return false;
5861d1d7784SEd Tanous         }
5871d1d7784SEd Tanous 
5881d1d7784SEd Tanous         return true;
5891d1d7784SEd Tanous     }
5901d1d7784SEd Tanous 
afterReadHeaders(const std::shared_ptr<self_type> &,const boost::system::error_code & ec,std::size_t bytesTransferred)591116370d8SEd Tanous     void afterReadHeaders(const std::shared_ptr<self_type>& /*self*/,
592116370d8SEd Tanous                           const boost::system::error_code& ec,
593116370d8SEd Tanous                           std::size_t bytesTransferred)
59404e438cbSEd Tanous     {
59562598e31SEd Tanous         BMCWEB_LOG_DEBUG("{} async_read_header {} Bytes", logPtr(this),
59662598e31SEd Tanous                          bytesTransferred);
59752e31629SEd Tanous 
59804e438cbSEd Tanous         if (ec)
59904e438cbSEd Tanous         {
60052e31629SEd Tanous             cancelDeadlineTimer();
60152e31629SEd Tanous 
6021d1d7784SEd Tanous             if (ec == boost::beast::http::error::header_limit)
6031d1d7784SEd Tanous             {
6041d1d7784SEd Tanous                 BMCWEB_LOG_ERROR("{} Header field too large, closing",
6051d1d7784SEd Tanous                                  logPtr(this), ec.message());
6061d1d7784SEd Tanous 
6071d1d7784SEd Tanous                 res.result(boost::beast::http::status::
6081d1d7784SEd Tanous                                request_header_fields_too_large);
6091d1d7784SEd Tanous                 keepAlive = false;
6101d1d7784SEd Tanous                 doWrite();
6111d1d7784SEd Tanous                 return;
6121d1d7784SEd Tanous             }
613a4326fe2SMyung Bae             if (ec == boost::beast::http::error::end_of_stream)
6141c801e1fSAndrew Geissler             {
615116370d8SEd Tanous                 BMCWEB_LOG_WARNING("{} End of stream, closing {}", logPtr(this),
616116370d8SEd Tanous                                    ec);
6171d1d7784SEd Tanous                 hardClose();
61804e438cbSEd Tanous                 return;
61904e438cbSEd Tanous             }
62004e438cbSEd Tanous 
6211d1d7784SEd Tanous             BMCWEB_LOG_DEBUG("{} Closing socket due to read error {}",
6221d1d7784SEd Tanous                              logPtr(this), ec.message());
6231d1d7784SEd Tanous             gracefulClose();
62404e438cbSEd Tanous 
6251d1d7784SEd Tanous             return;
62659b98b22SJohn Edward Broadbent         }
6271d1d7784SEd Tanous 
628116370d8SEd Tanous         if (!parser)
629116370d8SEd Tanous         {
630116370d8SEd Tanous             BMCWEB_LOG_ERROR("Parser was unexpectedly null");
631116370d8SEd Tanous             return;
632116370d8SEd Tanous         }
633116370d8SEd Tanous 
634796ba93bSEd Tanous         if (authenticationEnabled)
63583328316SEd Tanous         {
63683328316SEd Tanous             boost::beast::http::verb method = parser->get().method();
637796ba93bSEd Tanous             userSession = authentication::authenticate(
63883328316SEd Tanous                 ip, res, method, parser->get().base(), mtlsSession);
63983328316SEd Tanous         }
64083328316SEd Tanous 
6411d1d7784SEd Tanous         std::string_view expect =
642102a4cdaSJonathan Doman             parser->get()[boost::beast::http::field::expect];
6431d1d7784SEd Tanous         if (bmcweb::asciiIEquals(expect, "100-continue"))
6441d1d7784SEd Tanous         {
6451d1d7784SEd Tanous             res.result(boost::beast::http::status::continue_);
6461d1d7784SEd Tanous             doWrite();
6471d1d7784SEd Tanous             return;
6481d1d7784SEd Tanous         }
6491d1d7784SEd Tanous 
6501d1d7784SEd Tanous         if (!handleContentLengthError())
65104e438cbSEd Tanous         {
65204e438cbSEd Tanous             return;
65304e438cbSEd Tanous         }
65404e438cbSEd Tanous 
6551d1d7784SEd Tanous         parser->body_limit(getContentLengthLimit());
6565dfb5b2dSEd Tanous 
6577d243eb7SEd Tanous         if (parser->is_done())
6587d243eb7SEd Tanous         {
6597d243eb7SEd Tanous             handle();
6607d243eb7SEd Tanous             return;
6617d243eb7SEd Tanous         }
6627d243eb7SEd Tanous 
66304e438cbSEd Tanous         doRead();
66404e438cbSEd Tanous     }
66504e438cbSEd Tanous 
doReadHeaders()666116370d8SEd Tanous     void doReadHeaders()
66704e438cbSEd Tanous     {
668116370d8SEd Tanous         BMCWEB_LOG_DEBUG("{} doReadHeaders", logPtr(this));
669e01d0c36SEd Tanous         if (!parser)
670e01d0c36SEd Tanous         {
671116370d8SEd Tanous             BMCWEB_LOG_CRITICAL("Parser was not initialized.");
672e01d0c36SEd Tanous             return;
673e01d0c36SEd Tanous         }
674796ba93bSEd Tanous 
675796ba93bSEd Tanous         if (httpType == HttpType::HTTP)
676796ba93bSEd Tanous         {
677796ba93bSEd Tanous             boost::beast::http::async_read_header(
678796ba93bSEd Tanous                 adaptor.next_layer(), buffer, *parser,
679796ba93bSEd Tanous                 std::bind_front(&self_type::afterReadHeaders, this,
680796ba93bSEd Tanous                                 shared_from_this()));
681796ba93bSEd Tanous         }
682796ba93bSEd Tanous         else
683796ba93bSEd Tanous         {
684116370d8SEd Tanous             boost::beast::http::async_read_header(
6857d243eb7SEd Tanous                 adaptor, buffer, *parser,
686116370d8SEd Tanous                 std::bind_front(&self_type::afterReadHeaders, this,
687116370d8SEd Tanous                                 shared_from_this()));
688116370d8SEd Tanous         }
689796ba93bSEd Tanous     }
690116370d8SEd Tanous 
afterRead(const std::shared_ptr<self_type> &,const boost::system::error_code & ec,std::size_t bytesTransferred)691116370d8SEd Tanous     void afterRead(const std::shared_ptr<self_type>& /*self*/,
692116370d8SEd Tanous                    const boost::system::error_code& ec,
693116370d8SEd Tanous                    std::size_t bytesTransferred)
694116370d8SEd Tanous     {
69562598e31SEd Tanous         BMCWEB_LOG_DEBUG("{} async_read_some {} Bytes", logPtr(this),
69662598e31SEd Tanous                          bytesTransferred);
6977d243eb7SEd Tanous 
69804e438cbSEd Tanous         if (ec)
69904e438cbSEd Tanous         {
70062598e31SEd Tanous             BMCWEB_LOG_ERROR("{} Error while reading: {}", logPtr(this),
70162598e31SEd Tanous                              ec.message());
7021d1d7784SEd Tanous             if (ec == boost::beast::http::error::body_limit)
7031d1d7784SEd Tanous             {
7041d1d7784SEd Tanous                 if (handleContentLengthError())
7051d1d7784SEd Tanous                 {
706116370d8SEd Tanous                     BMCWEB_LOG_CRITICAL("Body length limit reached, "
7071d1d7784SEd Tanous                                         "but no content-length "
7081d1d7784SEd Tanous                                         "available?  Should never happen");
709116370d8SEd Tanous                     res.result(
710116370d8SEd Tanous                         boost::beast::http::status::internal_server_error);
7111d1d7784SEd Tanous                     keepAlive = false;
7121d1d7784SEd Tanous                     doWrite();
7131d1d7784SEd Tanous                 }
7141d1d7784SEd Tanous                 return;
7151d1d7784SEd Tanous             }
7161d1d7784SEd Tanous 
7171d1d7784SEd Tanous             gracefulClose();
71804e438cbSEd Tanous             return;
71904e438cbSEd Tanous         }
7207d243eb7SEd Tanous 
721bd79bce8SPatrick Williams         // If the user is logged in, allow them to send files
722bd79bce8SPatrick Williams         // incrementally one piece at a time. If authentication is
723bd79bce8SPatrick Williams         // disabled then there is no user session hence always allow to
724bd79bce8SPatrick Williams         // send one piece at a time.
7257d243eb7SEd Tanous         if (userSession != nullptr)
7267d243eb7SEd Tanous         {
7277d243eb7SEd Tanous             cancelDeadlineTimer();
7287d243eb7SEd Tanous         }
729116370d8SEd Tanous 
730116370d8SEd Tanous         if (!parser)
731116370d8SEd Tanous         {
732116370d8SEd Tanous             BMCWEB_LOG_ERROR("Parser was unexpectedly null");
733116370d8SEd Tanous             return;
734116370d8SEd Tanous         }
7357d243eb7SEd Tanous         if (!parser->is_done())
7367d243eb7SEd Tanous         {
7377d243eb7SEd Tanous             doRead();
7387d243eb7SEd Tanous             return;
7397d243eb7SEd Tanous         }
7407d243eb7SEd Tanous 
7417d243eb7SEd Tanous         cancelDeadlineTimer();
74204e438cbSEd Tanous         handle();
743116370d8SEd Tanous     }
744116370d8SEd Tanous 
doRead()745116370d8SEd Tanous     void doRead()
746116370d8SEd Tanous     {
747116370d8SEd Tanous         BMCWEB_LOG_DEBUG("{} doRead", logPtr(this));
748116370d8SEd Tanous         if (!parser)
749116370d8SEd Tanous         {
750116370d8SEd Tanous             return;
751116370d8SEd Tanous         }
752116370d8SEd Tanous         startDeadline();
753796ba93bSEd Tanous         if (httpType == HttpType::HTTP)
754796ba93bSEd Tanous         {
755796ba93bSEd Tanous             boost::beast::http::async_read_some(
756796ba93bSEd Tanous                 adaptor.next_layer(), buffer, *parser,
757796ba93bSEd Tanous                 std::bind_front(&self_type::afterRead, this,
758796ba93bSEd Tanous                                 shared_from_this()));
759796ba93bSEd Tanous         }
760796ba93bSEd Tanous         else
761796ba93bSEd Tanous         {
762116370d8SEd Tanous             boost::beast::http::async_read_some(
763116370d8SEd Tanous                 adaptor, buffer, *parser,
764796ba93bSEd Tanous                 std::bind_front(&self_type::afterRead, this,
765796ba93bSEd Tanous                                 shared_from_this()));
766796ba93bSEd Tanous         }
76704e438cbSEd Tanous     }
76804e438cbSEd Tanous 
afterDoWrite(const std::shared_ptr<self_type> &,const boost::system::error_code & ec,std::size_t bytesTransferred)76927b0cf90SEd Tanous     void afterDoWrite(const std::shared_ptr<self_type>& /*self*/,
770002d39b4SEd Tanous                       const boost::system::error_code& ec,
77127b0cf90SEd Tanous                       std::size_t bytesTransferred)
77227b0cf90SEd Tanous     {
7730242baffSEd Tanous         BMCWEB_LOG_DEBUG("{} async_write wrote {} bytes, ec={}", logPtr(this),
7741d1d7784SEd Tanous                          bytesTransferred, ec);
77504e438cbSEd Tanous 
77604e438cbSEd Tanous         cancelDeadlineTimer();
77704e438cbSEd Tanous 
7780242baffSEd Tanous         if (ec == boost::system::errc::operation_would_block ||
7790242baffSEd Tanous             ec == boost::system::errc::resource_unavailable_try_again)
7800242baffSEd Tanous         {
7810242baffSEd Tanous             doWrite();
7820242baffSEd Tanous             return;
7830242baffSEd Tanous         }
78404e438cbSEd Tanous         if (ec)
78504e438cbSEd Tanous         {
78662598e31SEd Tanous             BMCWEB_LOG_DEBUG("{} from write(2)", logPtr(this));
78704e438cbSEd Tanous             return;
78804e438cbSEd Tanous         }
7891d1d7784SEd Tanous 
790cd7dbb30SEd Tanous         if (res.result() == boost::beast::http::status::switching_protocols)
791cd7dbb30SEd Tanous         {
792796ba93bSEd Tanous             upgradeToHttp2();
793cd7dbb30SEd Tanous             return;
794cd7dbb30SEd Tanous         }
795cd7dbb30SEd Tanous 
7961d1d7784SEd Tanous         if (res.result() == boost::beast::http::status::continue_)
7971d1d7784SEd Tanous         {
7981d1d7784SEd Tanous             // Reset the result to ok
7991d1d7784SEd Tanous             res.result(boost::beast::http::status::ok);
8001d1d7784SEd Tanous             doRead();
8011d1d7784SEd Tanous             return;
8021d1d7784SEd Tanous         }
8031d1d7784SEd Tanous 
8044cdc2e8dSEd Tanous         if (!keepAlive)
80504e438cbSEd Tanous         {
8061d1d7784SEd Tanous             BMCWEB_LOG_DEBUG("{} keepalive not set.  Closing socket",
8071d1d7784SEd Tanous                              logPtr(this));
8081d1d7784SEd Tanous 
8091d1d7784SEd Tanous             gracefulClose();
81004e438cbSEd Tanous             return;
81104e438cbSEd Tanous         }
81204e438cbSEd Tanous 
81362598e31SEd Tanous         BMCWEB_LOG_DEBUG("{} Clearing response", logPtr(this));
81404e438cbSEd Tanous         res.clear();
8151d1d7784SEd Tanous         initParser();
81604e438cbSEd Tanous 
8179a69d5a5SEd Tanous         userSession = nullptr;
8189a69d5a5SEd Tanous 
819102a4cdaSJonathan Doman         req->clear();
82004e438cbSEd Tanous         doReadHeaders();
82127b0cf90SEd Tanous     }
82227b0cf90SEd Tanous 
doWrite()82352e31629SEd Tanous     void doWrite()
82427b0cf90SEd Tanous     {
82527b0cf90SEd Tanous         BMCWEB_LOG_DEBUG("{} doWrite", logPtr(this));
82652e31629SEd Tanous         res.preparePayload();
82727b0cf90SEd Tanous 
82827b0cf90SEd Tanous         startDeadline();
829796ba93bSEd Tanous         if (httpType == HttpType::HTTP)
830796ba93bSEd Tanous         {
831796ba93bSEd Tanous             boost::beast::async_write(
832796ba93bSEd Tanous                 adaptor.next_layer(),
833796ba93bSEd Tanous                 boost::beast::http::message_generator(std::move(res.response)),
834796ba93bSEd Tanous                 std::bind_front(&self_type::afterDoWrite, this,
835796ba93bSEd Tanous                                 shared_from_this()));
836796ba93bSEd Tanous         }
837796ba93bSEd Tanous         else
838796ba93bSEd Tanous         {
8394d69861fSEd Tanous             boost::beast::async_write(
8404d69861fSEd Tanous                 adaptor,
8414d69861fSEd Tanous                 boost::beast::http::message_generator(std::move(res.response)),
84252e31629SEd Tanous                 std::bind_front(&self_type::afterDoWrite, this,
84352e31629SEd Tanous                                 shared_from_this()));
84404e438cbSEd Tanous         }
845796ba93bSEd Tanous     }
84604e438cbSEd Tanous 
cancelDeadlineTimer()84704e438cbSEd Tanous     void cancelDeadlineTimer()
84804e438cbSEd Tanous     {
8495dfb5b2dSEd Tanous         timer.cancel();
85004e438cbSEd Tanous     }
85104e438cbSEd Tanous 
afterTimerWait(const std::weak_ptr<self_type> & weakSelf,const boost::system::error_code & ec)852116370d8SEd Tanous     void afterTimerWait(const std::weak_ptr<self_type>& weakSelf,
853116370d8SEd Tanous                         const boost::system::error_code& ec)
85404e438cbSEd Tanous     {
8555dfb5b2dSEd Tanous         // Note, we are ignoring other types of errors here;  If the timer
8565dfb5b2dSEd Tanous         // failed for any reason, we should still close the connection
857116370d8SEd Tanous         std::shared_ptr<Connection<Adaptor, Handler>> self = weakSelf.lock();
8585dfb5b2dSEd Tanous         if (!self)
85904e438cbSEd Tanous         {
8601d1d7784SEd Tanous             if (ec == boost::asio::error::operation_aborted)
8611d1d7784SEd Tanous             {
8621d1d7784SEd Tanous                 BMCWEB_LOG_DEBUG(
8631d1d7784SEd Tanous                     "{} Timer canceled on connection being destroyed",
8641d1d7784SEd Tanous                     logPtr(self.get()));
8651d1d7784SEd Tanous             }
866116370d8SEd Tanous             else
867116370d8SEd Tanous             {
86862598e31SEd Tanous                 BMCWEB_LOG_CRITICAL("{} Failed to capture connection",
86962598e31SEd Tanous                                     logPtr(self.get()));
870116370d8SEd Tanous             }
87104e438cbSEd Tanous             return;
87204e438cbSEd Tanous         }
8737d243eb7SEd Tanous 
8747d243eb7SEd Tanous         self->timerStarted = false;
8757d243eb7SEd Tanous 
8765dfb5b2dSEd Tanous         if (ec)
8775dfb5b2dSEd Tanous         {
8781d1d7784SEd Tanous             if (ec == boost::asio::error::operation_aborted)
8791d1d7784SEd Tanous             {
8801d1d7784SEd Tanous                 BMCWEB_LOG_DEBUG("{} Timer canceled", logPtr(self.get()));
8811d1d7784SEd Tanous                 return;
8821d1d7784SEd Tanous             }
883116370d8SEd Tanous             BMCWEB_LOG_CRITICAL("{} Timer failed {}", logPtr(self.get()), ec);
8845dfb5b2dSEd Tanous         }
8855dfb5b2dSEd Tanous 
8861d1d7784SEd Tanous         BMCWEB_LOG_WARNING("{} Connection timed out, hard closing",
88762598e31SEd Tanous                            logPtr(self.get()));
88804e438cbSEd Tanous 
8891d1d7784SEd Tanous         self->hardClose();
890116370d8SEd Tanous     }
891116370d8SEd Tanous 
startDeadline()892116370d8SEd Tanous     void startDeadline()
893116370d8SEd Tanous     {
894116370d8SEd Tanous         // Timer is already started so no further action is required.
895116370d8SEd Tanous         if (timerStarted)
896116370d8SEd Tanous         {
897116370d8SEd Tanous             return;
898116370d8SEd Tanous         }
899116370d8SEd Tanous 
900116370d8SEd Tanous         std::chrono::seconds timeout(15);
901116370d8SEd Tanous 
902116370d8SEd Tanous         std::weak_ptr<Connection<Adaptor, Handler>> weakSelf = weak_from_this();
903116370d8SEd Tanous         timer.expires_after(timeout);
904116370d8SEd Tanous         timer.async_wait(std::bind_front(&self_type::afterTimerWait, this,
905116370d8SEd Tanous                                          weak_from_this()));
90604e438cbSEd Tanous 
9077d243eb7SEd Tanous         timerStarted = true;
90862598e31SEd Tanous         BMCWEB_LOG_DEBUG("{} timer started", logPtr(this));
90904e438cbSEd Tanous     }
91004e438cbSEd Tanous 
911796ba93bSEd Tanous     bool authenticationEnabled = !BMCWEB_INSECURE_DISABLE_AUTH;
912796ba93bSEd Tanous     HttpType httpType = HttpType::BOTH;
913796ba93bSEd Tanous 
914796ba93bSEd Tanous     boost::asio::ssl::stream<Adaptor> adaptor;
91504e438cbSEd Tanous     Handler* handler;
9161d1d7784SEd Tanous 
9171d1d7784SEd Tanous     boost::asio::ip::address ip;
9181d1d7784SEd Tanous 
91904e438cbSEd Tanous     // Making this a std::optional allows it to be efficiently destroyed and
92004e438cbSEd Tanous     // re-created on Connection reset
921b2896149SEd Tanous     std::optional<boost::beast::http::request_parser<bmcweb::HttpBody>> parser;
92204e438cbSEd Tanous 
92304e438cbSEd Tanous     boost::beast::flat_static_buffer<8192> buffer;
92404e438cbSEd Tanous 
925102a4cdaSJonathan Doman     std::shared_ptr<crow::Request> req;
92689cda63dSEd Tanous     std::string accept;
927cd7dbb30SEd Tanous     std::string http2settings;
92804e438cbSEd Tanous     crow::Response res;
92904e438cbSEd Tanous 
93059b98b22SJohn Edward Broadbent     std::shared_ptr<persistent_data::UserSession> userSession;
931b4963077SBoleslaw Ogonczyk Makowski     std::shared_ptr<persistent_data::UserSession> mtlsSession;
93204e438cbSEd Tanous 
9335dfb5b2dSEd Tanous     boost::asio::steady_timer timer;
93404e438cbSEd Tanous 
9354cdc2e8dSEd Tanous     bool keepAlive = true;
9364cdc2e8dSEd Tanous 
9377d243eb7SEd Tanous     bool timerStarted = false;
9387d243eb7SEd Tanous 
93904e438cbSEd Tanous     std::function<std::string()>& getCachedDateStr;
94004e438cbSEd Tanous 
94104e438cbSEd Tanous     using std::enable_shared_from_this<
94204e438cbSEd Tanous         Connection<Adaptor, Handler>>::shared_from_this;
9435dfb5b2dSEd Tanous 
9445dfb5b2dSEd Tanous     using std::enable_shared_from_this<
9455dfb5b2dSEd Tanous         Connection<Adaptor, Handler>>::weak_from_this;
94604e438cbSEd Tanous };
94704e438cbSEd Tanous } // namespace crow
948