Clio develop
The XRP Ledger API server.
Loading...
Searching...
No Matches
ErrorHandling.hpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of clio: https://github.com/XRPLF/clio
4 Copyright (c) 2023, the clio developers.
5
6 Permission to use, copy, modify, and distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#pragma once
21
22#include "rpc/Errors.hpp"
23#include "rpc/JS.hpp"
24#include "util/Assert.hpp"
25#include "web/interface/ConnectionBase.hpp"
26
27#include <boost/beast/http/status.hpp>
28#include <boost/json/object.hpp>
29#include <boost/json/serialize.hpp>
30#include <fmt/core.h>
31#include <xrpl/protocol/ErrorCodes.h>
32#include <xrpl/protocol/jss.h>
33
34#include <memory>
35#include <optional>
36#include <string>
37#include <utility>
38#include <variant>
39
40namespace web::impl {
41
46 std::shared_ptr<web::ConnectionBase> connection_;
47 std::optional<boost::json::object> request_;
48
49public:
51 std::shared_ptr<web::ConnectionBase> const& connection,
52 std::optional<boost::json::object> request = std::nullopt
53 )
54 : connection_{connection}, request_{std::move(request)}
55 {
56 }
57
58 void
59 sendError(rpc::Status const& err) const
60 {
61 if (connection_->upgraded) {
62 connection_->send(boost::json::serialize(composeError(err)));
63 } else {
64 // Note: a collection of crutches to match rippled output follows
65 if (auto const clioCode = std::get_if<rpc::ClioError>(&err.code)) {
66 switch (*clioCode) {
67 case rpc::ClioError::RpcInvalidApiVersion:
68 connection_->send(
69 std::string{rpc::getErrorInfo(*clioCode).error}, boost::beast::http::status::bad_request
70 );
71 break;
72 case rpc::ClioError::RpcCommandIsMissing:
73 connection_->send("Null method", boost::beast::http::status::bad_request);
74 break;
75 case rpc::ClioError::RpcCommandIsEmpty:
76 connection_->send("method is empty", boost::beast::http::status::bad_request);
77 break;
78 case rpc::ClioError::RpcCommandNotString:
79 connection_->send("method is not string", boost::beast::http::status::bad_request);
80 break;
81 case rpc::ClioError::RpcParamsUnparseable:
82 connection_->send("params unparseable", boost::beast::http::status::bad_request);
83 break;
84
85 // others are not applicable but we want a compilation error next time we add one
86 case rpc::ClioError::RpcUnknownOption:
87 case rpc::ClioError::RpcMalformedCurrency:
88 case rpc::ClioError::RpcMalformedRequest:
89 case rpc::ClioError::RpcMalformedOwner:
90 case rpc::ClioError::RpcMalformedAddress:
91 case rpc::ClioError::RpcFieldNotFoundTransaction:
92 case rpc::ClioError::RpcMalformedOracleDocumentId:
93 case rpc::ClioError::RpcMalformedAuthorizedCredentials:
94 case rpc::ClioError::EtlConnectionError:
95 case rpc::ClioError::EtlRequestError:
96 case rpc::ClioError::EtlRequestTimeout:
97 case rpc::ClioError::EtlInvalidResponse:
98 ASSERT(
99 false, "Unknown rpc error code {}", static_cast<int>(*clioCode)
100 ); // this should never happen
101 break;
102 }
103 } else {
104 connection_->send(boost::json::serialize(composeError(err)), boost::beast::http::status::bad_request);
105 }
106 }
107 }
108
109 void
110 sendInternalError() const
111 {
112 connection_->send(
113 boost::json::serialize(composeError(rpc::RippledError::rpcINTERNAL)),
114 boost::beast::http::status::internal_server_error
115 );
116 }
117
118 void
119 sendNotReadyError() const
120 {
121 connection_->send(
122 boost::json::serialize(composeError(rpc::RippledError::rpcNOT_READY)), boost::beast::http::status::ok
123 );
124 }
125
126 void
127 sendTooBusyError() const
128 {
129 if (connection_->upgraded) {
130 connection_->send(
131 boost::json::serialize(rpc::makeError(rpc::RippledError::rpcTOO_BUSY)), boost::beast::http::status::ok
132 );
133 } else {
134 connection_->send(
135 boost::json::serialize(rpc::makeError(rpc::RippledError::rpcTOO_BUSY)),
136 boost::beast::http::status::service_unavailable
137 );
138 }
139 }
140
141 void
142 sendJsonParsingError() const
143 {
144 if (connection_->upgraded) {
145 connection_->send(boost::json::serialize(rpc::makeError(rpc::RippledError::rpcBAD_SYNTAX)));
146 } else {
147 connection_->send(
148 fmt::format("Unable to parse JSON from the request"), boost::beast::http::status::bad_request
149 );
150 }
151 }
152
153 boost::json::object
154 composeError(auto const& error) const
155 {
156 auto e = rpc::makeError(error);
157
158 if (request_) {
159 auto const appendFieldIfExist = [&](auto const& field) {
160 if (request_->contains(field) and not request_->at(field).is_null())
161 e[field] = request_->at(field);
162 };
163
164 appendFieldIfExist(JS(id));
165
166 if (connection_->upgraded)
167 appendFieldIfExist(JS(api_version));
168
169 e[JS(request)] = request_.value();
170 }
171
172 if (connection_->upgraded) {
173 return e;
174 }
175 return {{JS(result), e}};
176 }
177};
178
179} // namespace web::impl
A helper that attempts to match rippled reporting mode HTTP errors as close as possible.
Definition ErrorHandling.hpp:45
ClioErrorInfo const & getErrorInfo(ClioError code)
Get the error info object from an clio-specific error code.
Definition Errors.cpp:75
boost::json::object makeError(RippledError err, std::optional< std::string_view > customError, std::optional< std::string_view > customMessage)
Generate JSON from a rpc::RippledError.
Definition Errors.cpp:120
A status returned from any RPC handler.
Definition Errors.hpp:82