| #include "http_response.hpp" |
| |
| #include "logging.hpp" |
| #include "utils/hex_utils.hpp" |
| |
| #include <nlohmann/json.hpp> |
| |
| namespace crow |
| { |
| |
| Response& 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); |
| |
| // Only need to move completion handler if not already completed |
| // Note, there are cases where we might move out of a Response object |
| // while in a completion handler for that response object. This check |
| // is intended to prevent destructing the functor we are currently |
| // executing from in that case. |
| if (!r.completed) |
| { |
| completeRequestHandler = std::move(r.completeRequestHandler); |
| r.completeRequestHandler = nullptr; |
| } |
| else |
| { |
| completeRequestHandler = nullptr; |
| } |
| completed = r.completed; |
| isAliveHelper = std::move(r.isAliveHelper); |
| r.isAliveHelper = nullptr; |
| return *this; |
| } |
| |
| void Response::clear() |
| { |
| BMCWEB_LOG_DEBUG << this << " Clearing response containers"; |
| stringResponse.emplace(response_type{}); |
| jsonValue.clear(); |
| completed = false; |
| expectedHash = std::nullopt; |
| } |
| |
| std::string Response::computeEtag() const |
| { |
| // Only set etag if this request succeeded |
| if (result() != boost::beast::http::status::ok) |
| { |
| return ""; |
| } |
| // and the json response isn't empty |
| if (jsonValue.empty()) |
| { |
| return ""; |
| } |
| size_t hashval = std::hash<nlohmann::json>{}(jsonValue); |
| return "\"" + intToHexString(hashval, 8) + "\""; |
| } |
| |
| void Response::setHashAndHandleNotModified() |
| { |
| // Can only hash if we have content that's valid |
| if (jsonValue.empty() || result() != boost::beast::http::status::ok) |
| { |
| return; |
| } |
| size_t hashval = std::hash<nlohmann::json>{}(jsonValue); |
| std::string hexVal = "\"" + intToHexString(hashval, 8) + "\""; |
| addHeader(boost::beast::http::field::etag, hexVal); |
| if (expectedHash && hexVal == *expectedHash) |
| { |
| jsonValue.clear(); |
| result(boost::beast::http::status::not_modified); |
| } |
| } |
| |
| void Response::end() |
| { |
| std::string etag = computeEtag(); |
| if (!etag.empty()) |
| { |
| addHeader(boost::beast::http::field::etag, etag); |
| } |
| 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); |
| } |
| } |
| |
| void Response::setCompleteRequestHandler( |
| std::function<void(Response&)>&& handler) |
| { |
| completeRequestHandler = std::move(handler); |
| BMCWEB_LOG_DEBUG << this << " setting completion handler" |
| << &completeRequestHandler; |
| // Now that we have a new completion handler attached, we're no longer |
| // complete |
| completed = false; |
| } |
| |
| std::function<void(Response&)> Response::releaseCompleteRequestHandler() |
| { |
| BMCWEB_LOG_DEBUG << this << " releasing completion handler" |
| << &completeRequestHandler; |
| std::function<void(Response&)> ret = completeRequestHandler; |
| completeRequestHandler = nullptr; |
| completed = true; |
| return ret; |
| } |
| |
| } // namespace crow |