104e438cbSEd Tanous #pragma once 204e438cbSEd Tanous #include "logging.hpp" 304e438cbSEd Tanous #include "nlohmann/json.hpp" 404e438cbSEd Tanous 504e438cbSEd Tanous #include <boost/beast/http/message.hpp> 6d4b6c660SEd Tanous #include <boost/beast/http/string_body.hpp> 789f18008SEd Tanous #include <utils/hex_utils.hpp> 804e438cbSEd Tanous 98a9a25c8SEd Tanous #include <optional> 1004e438cbSEd Tanous #include <string> 118a9a25c8SEd Tanous #include <string_view> 1204e438cbSEd Tanous 1304e438cbSEd Tanous namespace crow 1404e438cbSEd Tanous { 1504e438cbSEd Tanous 1604e438cbSEd Tanous template <typename Adaptor, typename Handler> 1704e438cbSEd Tanous class Connection; 1804e438cbSEd Tanous 1904e438cbSEd Tanous struct Response 2004e438cbSEd Tanous { 2104e438cbSEd Tanous template <typename Adaptor, typename Handler> 2204e438cbSEd Tanous friend class crow::Connection; 2304e438cbSEd Tanous using response_type = 2404e438cbSEd Tanous boost::beast::http::response<boost::beast::http::string_body>; 2504e438cbSEd Tanous 2604e438cbSEd Tanous std::optional<response_type> stringResponse; 2704e438cbSEd Tanous 2804e438cbSEd Tanous nlohmann::json jsonValue; 2904e438cbSEd Tanous 3004e438cbSEd Tanous void addHeader(const std::string_view key, const std::string_view value) 3104e438cbSEd Tanous { 3204e438cbSEd Tanous stringResponse->set(key, value); 3304e438cbSEd Tanous } 3404e438cbSEd Tanous 3504e438cbSEd Tanous void addHeader(boost::beast::http::field key, std::string_view value) 3604e438cbSEd Tanous { 3704e438cbSEd Tanous stringResponse->set(key, value); 3804e438cbSEd Tanous } 3904e438cbSEd Tanous 4004e438cbSEd Tanous Response() : stringResponse(response_type{}) 4104e438cbSEd Tanous {} 4204e438cbSEd Tanous 43ecd6a3a2SEd Tanous ~Response() = default; 44ecd6a3a2SEd Tanous 45ecd6a3a2SEd Tanous Response(const Response&) = delete; 46ecd6a3a2SEd Tanous Response(Response&&) = delete; 4772374eb7SNan Zhou 4804e438cbSEd Tanous Response& operator=(const Response& r) = delete; 4904e438cbSEd Tanous 5004e438cbSEd Tanous Response& operator=(Response&& r) noexcept 5104e438cbSEd Tanous { 5272374eb7SNan Zhou BMCWEB_LOG_DEBUG << "Moving response containers; this: " << this 5372374eb7SNan Zhou << "; other: " << &r; 5472374eb7SNan Zhou if (this == &r) 5572374eb7SNan Zhou { 5672374eb7SNan Zhou return *this; 5772374eb7SNan Zhou } 5804e438cbSEd Tanous stringResponse = std::move(r.stringResponse); 5904e438cbSEd Tanous r.stringResponse.emplace(response_type{}); 6004e438cbSEd Tanous jsonValue = std::move(r.jsonValue); 6104e438cbSEd Tanous completed = r.completed; 6272374eb7SNan Zhou completeRequestHandler = std::move(r.completeRequestHandler); 6372374eb7SNan Zhou isAliveHelper = std::move(r.isAliveHelper); 6472374eb7SNan Zhou r.completeRequestHandler = nullptr; 6572374eb7SNan Zhou r.isAliveHelper = nullptr; 6604e438cbSEd Tanous return *this; 6704e438cbSEd Tanous } 6804e438cbSEd Tanous 6904e438cbSEd Tanous void result(boost::beast::http::status v) 7004e438cbSEd Tanous { 7104e438cbSEd Tanous stringResponse->result(v); 7204e438cbSEd Tanous } 7304e438cbSEd Tanous 74*bb60f4deSEd Tanous boost::beast::http::status result() const 7504e438cbSEd Tanous { 7604e438cbSEd Tanous return stringResponse->result(); 7704e438cbSEd Tanous } 7804e438cbSEd Tanous 79039a47e3SCarson Labrado unsigned resultInt() const 8004e438cbSEd Tanous { 8104e438cbSEd Tanous return stringResponse->result_int(); 8204e438cbSEd Tanous } 8304e438cbSEd Tanous 84*bb60f4deSEd Tanous std::string_view reason() const 8504e438cbSEd Tanous { 8604e438cbSEd Tanous return stringResponse->reason(); 8704e438cbSEd Tanous } 8804e438cbSEd Tanous 8904e438cbSEd Tanous bool isCompleted() const noexcept 9004e438cbSEd Tanous { 9104e438cbSEd Tanous return completed; 9204e438cbSEd Tanous } 9304e438cbSEd Tanous 9404e438cbSEd Tanous std::string& body() 9504e438cbSEd Tanous { 9604e438cbSEd Tanous return stringResponse->body(); 9704e438cbSEd Tanous } 9804e438cbSEd Tanous 9904e438cbSEd Tanous void keepAlive(bool k) 10004e438cbSEd Tanous { 10104e438cbSEd Tanous stringResponse->keep_alive(k); 10204e438cbSEd Tanous } 10304e438cbSEd Tanous 104*bb60f4deSEd Tanous bool keepAlive() const 10504e438cbSEd Tanous { 10604e438cbSEd Tanous return stringResponse->keep_alive(); 10704e438cbSEd Tanous } 10804e438cbSEd Tanous 10904e438cbSEd Tanous void preparePayload() 11004e438cbSEd Tanous { 11104e438cbSEd Tanous stringResponse->prepare_payload(); 11204e438cbSEd Tanous } 11304e438cbSEd Tanous 11404e438cbSEd Tanous void clear() 11504e438cbSEd Tanous { 11604e438cbSEd Tanous BMCWEB_LOG_DEBUG << this << " Clearing response containers"; 11704e438cbSEd Tanous stringResponse.emplace(response_type{}); 11804e438cbSEd Tanous jsonValue.clear(); 11904e438cbSEd Tanous completed = false; 12004e438cbSEd Tanous } 12104e438cbSEd Tanous 12281ce609eSEd Tanous void write(std::string_view bodyPart) 12304e438cbSEd Tanous { 12481ce609eSEd Tanous stringResponse->body() += std::string(bodyPart); 12504e438cbSEd Tanous } 12604e438cbSEd Tanous 12704e438cbSEd Tanous void end() 12804e438cbSEd Tanous { 12989f18008SEd Tanous // Only set etag if this request succeeded 13089f18008SEd Tanous if (result() == boost::beast::http::status::ok) 13189f18008SEd Tanous { 13289f18008SEd Tanous // and the json response isn't empty 13389f18008SEd Tanous if (!jsonValue.empty()) 13489f18008SEd Tanous { 13589f18008SEd Tanous size_t hashval = std::hash<nlohmann::json>{}(jsonValue); 13689f18008SEd Tanous std::string hexVal = "\"" + intToHexString(hashval, 8) + "\""; 13789f18008SEd Tanous addHeader(boost::beast::http::field::etag, hexVal); 13889f18008SEd Tanous } 13989f18008SEd Tanous } 14004e438cbSEd Tanous if (completed) 14104e438cbSEd Tanous { 14272374eb7SNan Zhou BMCWEB_LOG_ERROR << this << " Response was ended twice"; 14304e438cbSEd Tanous return; 14404e438cbSEd Tanous } 14504e438cbSEd Tanous completed = true; 14672374eb7SNan Zhou BMCWEB_LOG_DEBUG << this << " calling completion handler"; 14704e438cbSEd Tanous if (completeRequestHandler) 14804e438cbSEd Tanous { 14972374eb7SNan Zhou BMCWEB_LOG_DEBUG << this << " completion handler was valid"; 15072374eb7SNan Zhou completeRequestHandler(*this); 15104e438cbSEd Tanous } 15204e438cbSEd Tanous } 15304e438cbSEd Tanous 154*bb60f4deSEd Tanous bool isAlive() const 15504e438cbSEd Tanous { 15604e438cbSEd Tanous return isAliveHelper && isAliveHelper(); 15704e438cbSEd Tanous } 15804e438cbSEd Tanous 15972374eb7SNan Zhou void setCompleteRequestHandler(std::function<void(Response&)>&& handler) 1604147b8acSJohn Edward Broadbent { 16172374eb7SNan Zhou BMCWEB_LOG_DEBUG << this << " setting completion handler"; 16272374eb7SNan Zhou completeRequestHandler = std::move(handler); 16372374eb7SNan Zhou } 16472374eb7SNan Zhou 16572374eb7SNan Zhou std::function<void(Response&)> releaseCompleteRequestHandler() 16672374eb7SNan Zhou { 16772374eb7SNan Zhou BMCWEB_LOG_DEBUG << this << " releasing completion handler" 16872374eb7SNan Zhou << static_cast<bool>(completeRequestHandler); 16972374eb7SNan Zhou std::function<void(Response&)> ret = completeRequestHandler; 17072374eb7SNan Zhou completeRequestHandler = nullptr; 17172374eb7SNan Zhou return ret; 17272374eb7SNan Zhou } 17372374eb7SNan Zhou 17472374eb7SNan Zhou void setIsAliveHelper(std::function<bool()>&& handler) 17572374eb7SNan Zhou { 17672374eb7SNan Zhou isAliveHelper = std::move(handler); 17772374eb7SNan Zhou } 17872374eb7SNan Zhou 17972374eb7SNan Zhou std::function<bool()> releaseIsAliveHelper() 18072374eb7SNan Zhou { 18172374eb7SNan Zhou std::function<bool()> ret = std::move(isAliveHelper); 18272374eb7SNan Zhou isAliveHelper = nullptr; 18372374eb7SNan Zhou return ret; 1844147b8acSJohn Edward Broadbent } 1854147b8acSJohn Edward Broadbent 18604e438cbSEd Tanous private: 18772374eb7SNan Zhou bool completed = false; 18872374eb7SNan Zhou std::function<void(Response&)> completeRequestHandler; 18904e438cbSEd Tanous std::function<bool()> isAliveHelper; 19004e438cbSEd Tanous 19104e438cbSEd Tanous // In case of a JSON object, set the Content-Type header 19204e438cbSEd Tanous void jsonMode() 19304e438cbSEd Tanous { 19404e438cbSEd Tanous addHeader("Content-Type", "application/json"); 19504e438cbSEd Tanous } 19604e438cbSEd Tanous }; 19704e438cbSEd Tanous } // namespace crow 198