blob: 995b4faf01708d348b43f067e9fbbb492272afb9 [file] [log] [blame]
#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