Clio  develop
The XRP Ledger API server.
Loading...
Searching...
No Matches
ForwardingProxy.hpp
1#pragma once
2
4#include "rpc/Errors.hpp"
5#include "rpc/RPCCenter.hpp"
6#include "rpc/RPCHelpers.hpp"
7#include "rpc/common/Types.hpp"
8#include "util/log/Logger.hpp"
9#include "web/Context.hpp"
10
11#include <xrpl/protocol/ErrorCodes.h>
12
13#include <functional>
14#include <memory>
15#include <string>
16#include <unordered_set>
17#include <utility>
18
19namespace rpc::impl {
20
21template <typename CountersType, typename HandlerProviderType>
22class ForwardingProxy {
23 util::Logger log_{"RPC"};
24
25 std::shared_ptr<etl::LoadBalancerInterface> balancer_;
26 std::reference_wrapper<CountersType> counters_;
27 std::shared_ptr<HandlerProviderType const> handlerProvider_;
28
29public:
30 ForwardingProxy(
31 std::shared_ptr<etl::LoadBalancerInterface> const& balancer,
32 CountersType& counters,
33 std::shared_ptr<HandlerProviderType const> const& handlerProvider
34 )
35 : balancer_{balancer}, counters_{std::ref(counters)}, handlerProvider_{handlerProvider}
36 {
37 }
38
39 bool
40 shouldForward(web::Context const& ctx) const
41 {
42 auto const& request = ctx.params;
43
44 if (ctx.method == "subscribe" || ctx.method == "unsubscribe")
45 return false;
46
47 if (handlerProvider_->isClioOnly(ctx.method))
48 return false;
49
50 if (isProxied(ctx.method))
51 return true;
52
54 return true;
55
56 if (isForcedForward(ctx))
57 return true;
58
59 auto const checkAccountInfoForward = [&]() {
60 return ctx.method == "account_info" and request.contains("queue") and
61 request.at("queue").is_bool() and request.at("queue").as_bool();
62 };
63
64 auto const checkLedgerForward = [&]() {
65 return ctx.method == "ledger" and request.contains("queue") and
66 request.at("queue").is_bool() and request.at("queue").as_bool();
67 };
68
69 return static_cast<bool>(checkAccountInfoForward() or checkLedgerForward());
70 }
71
72 Result
73 forward(web::Context const& ctx)
74 {
75 auto toForward = ctx.params;
76 toForward["command"] = ctx.method;
77
78 auto res = balancer_->forwardToRippled(toForward, ctx.clientIp, ctx.isAdmin, ctx.yield);
79 if (not res) {
80 notifyFailedToForward(ctx.method);
81 return Result{Status{CombinedError{res.error()}}};
82 }
83
84 notifyForwarded(ctx.method);
85 return Result{std::move(res).value()};
86 }
87
88 bool
89 isProxied(std::string const& method) const
90 {
91 return RPCCenter::isForwarded(method);
92 }
93
94private:
95 void
96 notifyForwarded(std::string const& method)
97 {
98 if (validHandler(method))
99 counters_.get().rpcForwarded(method);
100 }
101
102 void
103 notifyFailedToForward(std::string const& method)
104 {
105 if (validHandler(method))
106 counters_.get().rpcFailedToForward(method);
107 }
108
109 bool
110 validHandler(std::string const& method) const
111 {
112 return handlerProvider_->contains(method) || isProxied(method);
113 }
114
115 bool
116 isForcedForward(web::Context const& ctx) const
117 {
118 static constexpr auto kFORCE_FORWARD = "force_forward";
119 return ctx.isAdmin and ctx.params.contains(kFORCE_FORWARD) and
120 ctx.params.at(kFORCE_FORWARD).is_bool() and ctx.params.at(kFORCE_FORWARD).as_bool();
121 }
122};
123
124} // namespace rpc::impl
A simple thread-safe logger for the channel specified in the constructor.
Definition Logger.hpp:77
std::variant< RippledError, ClioError > CombinedError
Clio operates on a combination of Rippled and Custom Clio error codes.
Definition Errors.hpp:62
bool specifiesCurrentOrClosedLedger(boost::json::object const &request)
Check whether the request specifies the current or closed ledger.
Definition RPCHelpers.cpp:1591
static bool isForwarded(std::string_view s)
Checks if a string is a RPC command that will be forwarded to rippled.
Definition RPCCenter.cpp:94
Result type used to return responses or error statuses to the Webserver subsystem.
Definition Types.hpp:110
A status returned from any RPC handler.
Definition Errors.hpp:65
Context that is used by the Webserver to pass around information about an incoming request.
Definition Context.hpp:22