| #pragma once |
| #include "logging.hpp" |
| #include "nlohmann/json.hpp" |
| |
| #include <boost/beast/http/message.hpp> |
| #include <boost/beast/http/string_body.hpp> |
| #include <utils/hex_utils.hpp> |
| |
| #include <optional> |
| #include <string> |
| #include <string_view> |
| |
| namespace crow |
| { |
| |
| template <typename Adaptor, typename Handler> |
| class Connection; |
| |
| struct Response |
| { |
| template <typename Adaptor, typename Handler> |
| friend class crow::Connection; |
| using response_type = |
| boost::beast::http::response<boost::beast::http::string_body>; |
| |
| std::optional<response_type> stringResponse; |
| |
| nlohmann::json jsonValue; |
| |
| void addHeader(const std::string_view key, const std::string_view value) |
| { |
| stringResponse->set(key, value); |
| } |
| |
| void addHeader(boost::beast::http::field key, std::string_view value) |
| { |
| stringResponse->set(key, value); |
| } |
| |
| Response() : stringResponse(response_type{}) |
| {} |
| |
| ~Response() = default; |
| |
| Response(const Response&) = delete; |
| Response(Response&&) = delete; |
| |
| Response& operator=(const Response& r) = delete; |
| |
| Response& operator=(Response&& r) noexcept |
| { |
| BMCWEB_LOG_DEBUG << "Moving response containers; this: " << this |
| << "; other: " << &r; |
| if (this == &r) |
| { |
| return *this; |
| } |
| stringResponse = std::move(r.stringResponse); |
| r.stringResponse.emplace(response_type{}); |
| jsonValue = std::move(r.jsonValue); |
| completed = r.completed; |
| completeRequestHandler = std::move(r.completeRequestHandler); |
| isAliveHelper = std::move(r.isAliveHelper); |
| r.completeRequestHandler = nullptr; |
| r.isAliveHelper = nullptr; |
| return *this; |
| } |
| |
| void result(boost::beast::http::status v) |
| { |
| stringResponse->result(v); |
| } |
| |
| boost::beast::http::status result() const |
| { |
| return stringResponse->result(); |
| } |
| |
| unsigned resultInt() const |
| { |
| return stringResponse->result_int(); |
| } |
| |
| std::string_view reason() const |
| { |
| return stringResponse->reason(); |
| } |
| |
| bool isCompleted() const noexcept |
| { |
| return completed; |
| } |
| |
| std::string& body() |
| { |
| return stringResponse->body(); |
| } |
| |
| void keepAlive(bool k) |
| { |
| stringResponse->keep_alive(k); |
| } |
| |
| bool keepAlive() const |
| { |
| return stringResponse->keep_alive(); |
| } |
| |
| void preparePayload() |
| { |
| stringResponse->prepare_payload(); |
| } |
| |
| void clear() |
| { |
| BMCWEB_LOG_DEBUG << this << " Clearing response containers"; |
| stringResponse.emplace(response_type{}); |
| jsonValue.clear(); |
| completed = false; |
| } |
| |
| void write(std::string_view bodyPart) |
| { |
| stringResponse->body() += std::string(bodyPart); |
| } |
| |
| void end() |
| { |
| // Only set etag if this request succeeded |
| if (result() == boost::beast::http::status::ok) |
| { |
| // and the json response isn't empty |
| if (!jsonValue.empty()) |
| { |
| size_t hashval = std::hash<nlohmann::json>{}(jsonValue); |
| std::string hexVal = "\"" + intToHexString(hashval, 8) + "\""; |
| addHeader(boost::beast::http::field::etag, hexVal); |
| } |
| } |
| if (completed) |
| { |
| BMCWEB_LOG_ERROR << this << " Response was ended twice"; |
| return; |
| } |
| completed = true; |
| BMCWEB_LOG_DEBUG << this << " calling completion handler"; |
| if (completeRequestHandler) |
| { |
| BMCWEB_LOG_DEBUG << this << " completion handler was valid"; |
| completeRequestHandler(*this); |
| } |
| } |
| |
| bool isAlive() const |
| { |
| return isAliveHelper && isAliveHelper(); |
| } |
| |
| void setCompleteRequestHandler(std::function<void(Response&)>&& handler) |
| { |
| BMCWEB_LOG_DEBUG << this << " setting completion handler"; |
| completeRequestHandler = std::move(handler); |
| } |
| |
| std::function<void(Response&)> releaseCompleteRequestHandler() |
| { |
| BMCWEB_LOG_DEBUG << this << " releasing completion handler" |
| << static_cast<bool>(completeRequestHandler); |
| std::function<void(Response&)> ret = completeRequestHandler; |
| completeRequestHandler = nullptr; |
| return ret; |
| } |
| |
| void setIsAliveHelper(std::function<bool()>&& handler) |
| { |
| isAliveHelper = std::move(handler); |
| } |
| |
| std::function<bool()> releaseIsAliveHelper() |
| { |
| std::function<bool()> ret = std::move(isAliveHelper); |
| isAliveHelper = nullptr; |
| return ret; |
| } |
| |
| private: |
| bool completed = false; |
| std::function<void(Response&)> completeRequestHandler; |
| std::function<bool()> isAliveHelper; |
| |
| // In case of a JSON object, set the Content-Type header |
| void jsonMode() |
| { |
| addHeader("Content-Type", "application/json"); |
| } |
| }; |
| } // namespace crow |