Fixed 503 response code (#214)

The rate limiting warning response of Clio now follows the XRPL standard.
This commit is contained in:
Brandon Kong
2022-07-26 13:39:09 -04:00
committed by GitHub
parent d83975e750
commit 39ef2ae33c
3 changed files with 63 additions and 55 deletions

View File

@@ -15,6 +15,7 @@ class DOSGuard
std::uint32_t const maxFetches_;
std::uint32_t const sweepInterval_;
// Load config setting for DOSGuard
std::optional<boost::json::object>
getConfig(boost::json::object const& config) const
{

View File

@@ -242,12 +242,16 @@ public:
},
dosGuard_.isWhiteListed(*ip)))
{
// Non-whitelist connection rejected due to full connection queue
http::response<http::string_body> res{
http::status::ok, req_.version()};
res.set(http::field::server, "clio-server-v0.0.0");
res.set(
http::field::server,
"clio-server-" + Build::getClioVersionString());
res.set(http::field::content_type, "application/json");
res.keep_alive(req_.keep_alive());
res.body() = "Server overloaded";
res.body() = boost::json::serialize(
RPC::make_error(RPC::Error::rpcTOO_BUSY));
res.prepare_payload();
lambda_(std::move(res));
}
@@ -304,7 +308,9 @@ handle_request(
std::string content_type,
std::string message) {
http::response<http::string_body> res{status, req.version()};
res.set(http::field::server, "xrpl-reporting-server-v0.0.0");
res.set(
http::field::server,
"clio-server-" + Build::getClioVersionString());
res.set(http::field::content_type, content_type);
res.keep_alive(req.keep_alive());
res.body() = std::string(message);
@@ -324,9 +330,9 @@ handle_request(
if (!dosGuard.isOk(ip))
return send(httpResponse(
http::status::ok,
"application/json",
boost::json::serialize(RPC::make_error(RPC::Error::rpcSLOW_DOWN))));
http::status::service_unavailable,
"text/plain",
"Server is overloaded"));
try
{
@@ -350,13 +356,6 @@ handle_request(
RPC::make_error(RPC::Error::rpcBAD_SYNTAX))));
}
if (!dosGuard.isOk(ip))
return send(httpResponse(
http::status::ok,
"application/json",
boost::json::serialize(
RPC::make_error(RPC::Error::rpcSLOW_DOWN))));
auto range = backend->fetchLedgerRange();
if (!range)
return send(httpResponse(
@@ -429,8 +428,7 @@ handle_request(
responseStr = boost::json::serialize(response);
if (!dosGuard.add(ip, responseStr.size()))
{
warnings.emplace_back("Too many requests");
response["warnings"] = warnings;
response["warning"] = "load";
// reserialize when we need to include this warning
responseStr = boost::json::serialize(response);
}

View File

@@ -245,40 +245,24 @@ public:
}
void
handle_request(std::string const&& msg, boost::asio::yield_context& yc)
handle_request(
boost::json::object const&& request,
boost::json::value const& id,
boost::asio::yield_context& yield)
{
auto ip = derived().ip();
if (!ip)
return;
boost::json::object response = {};
auto sendError = [this](auto error, boost::json::value id) {
auto sendError = [this, &request, id](auto error) {
auto e = RPC::make_error(error);
if (!id.is_null())
e["id"] = id;
e["request"] = request;
send(boost::json::serialize(e));
};
boost::json::value raw = [](std::string const&& msg) {
try
{
return boost::json::parse(msg);
}
catch (std::exception&)
{
return boost::json::value{nullptr};
}
}(std::move(msg));
if (!raw.is_object())
return sendError(RPC::Error::rpcINVALID_PARAMS, nullptr);
boost::json::object request = raw.as_object();
auto id = request.contains("id") ? request.at("id") : nullptr;
try
{
BOOST_LOG_TRIVIAL(debug) << " received request : " << request;
@@ -286,10 +270,10 @@ public:
{
auto range = backend_->fetchLedgerRange();
if (!range)
return sendError(RPC::Error::rpcNOT_READY, id);
return sendError(RPC::Error::rpcNOT_READY);
std::optional<RPC::Context> context = RPC::make_WsContext(
yc,
yield,
request,
backend_,
subscriptions_.lock(),
@@ -301,7 +285,7 @@ public:
*ip);
if (!context)
return sendError(RPC::Error::rpcBAD_SYNTAX, id);
return sendError(RPC::Error::rpcBAD_SYNTAX);
response = getDefaultWsResponse(id);
@@ -334,7 +318,7 @@ public:
catch (Backend::DatabaseTimeout const& t)
{
BOOST_LOG_TRIVIAL(error) << __func__ << " Database timeout";
return sendError(RPC::Error::rpcNOT_READY, id);
return sendError(RPC::Error::rpcNOT_READY);
}
}
catch (std::exception const& e)
@@ -342,7 +326,7 @@ public:
BOOST_LOG_TRIVIAL(error)
<< __func__ << " caught exception : " << e.what();
return sendError(RPC::Error::rpcINTERNAL, id);
return sendError(RPC::Error::rpcINTERNAL);
}
boost::json::array warnings;
@@ -358,8 +342,7 @@ public:
std::string responseStr = boost::json::serialize(response);
if (!dosGuard_.add(*ip, responseStr.size()))
{
warnings.emplace_back("Too many requests");
response["warnings"] = warnings;
response["warning"] = "load";
// reserialize if we need to include this warning
responseStr = boost::json::serialize(response);
}
@@ -383,33 +366,59 @@ public:
BOOST_LOG_TRIVIAL(debug)
<< __func__ << " received request from ip = " << *ip;
auto sendError = [&](auto&& msg) {
boost::json::object response;
response["error"] = std::move(msg);
std::string responseStr = boost::json::serialize(response);
auto sendError = [this, ip](
auto error,
boost::json::value const& id,
boost::json::object const& request) {
auto e = RPC::make_error(error);
if (!id.is_null())
e["id"] = id;
e["request"] = request;
auto responseStr = boost::json::serialize(e);
BOOST_LOG_TRIVIAL(trace) << __func__ << " : " << responseStr;
dosGuard_.add(*ip, responseStr.size());
send(std::move(responseStr));
};
boost::json::value raw = [](std::string const&& msg) {
try
{
return boost::json::parse(msg);
}
catch (std::exception&)
{
return boost::json::value{nullptr};
}
}(std::move(msg));
boost::json::object request;
if (!raw.is_object())
return sendError(RPC::Error::rpcINVALID_PARAMS, nullptr, request);
request = raw.as_object();
auto id = request.contains("id") ? request.at("id") : nullptr;
if (!dosGuard_.isOk(*ip))
{
sendError("Too many requests. Slow down");
sendError(RPC::Error::rpcSLOW_DOWN, id, request);
}
else
{
if (!queue_.postCoro(
[m = std::move(msg), shared_this = shared_from_this()](
boost::asio::yield_context yield) {
shared_this->handle_request(std::move(m), yield);
[shared_this = shared_from_this(),
r = std::move(request),
id](boost::asio::yield_context yield) {
shared_this->handle_request(std::move(r), id, yield);
},
dosGuard_.isWhiteListed(*ip)))
sendError("Server overloaded");
sendError(RPC::Error::rpcTOO_BUSY, id, request);
}
do_read();
}
};
#endif // RIPPLE_REPORTING_WS_BASE_SESSION_H
#endif // RIPPLE_REPORTING_WS_BASE_SESSION_H