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