mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-03 08:46:46 +00:00
feat: Experimental attempt at RPC validation framework
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
#include <xrpld/rpc/Context.h>
|
||||
#include <xrpld/rpc/Role.h>
|
||||
#include <xrpld/rpc/handlers/Handlers.h>
|
||||
#include <xrpld/rpc/handlers/account/AccountInfo.h>
|
||||
#include <xrpld/rpc/handlers/ledger/Ledger.h>
|
||||
#include <xrpld/rpc/handlers/server_info/Version.h>
|
||||
|
||||
@@ -48,6 +49,16 @@ handle(JsonContext& context, Object& object)
|
||||
context.apiVersion >= HandlerImpl::minApiVer &&
|
||||
context.apiVersion <= HandlerImpl::maxApiVer,
|
||||
"xrpl::RPC::handle : valid API version");
|
||||
|
||||
if constexpr (requires { HandlerImpl::requestFields; })
|
||||
{
|
||||
if (auto status = validateFieldSpecs(context.params, HandlerImpl::requestFields))
|
||||
{
|
||||
status.inject(object);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
HandlerImpl handler(context);
|
||||
|
||||
auto status = handler.check();
|
||||
@@ -78,10 +89,6 @@ handlerFrom()
|
||||
Handler const kHANDLER_ARRAY[]{
|
||||
// Some handlers not specified here are added to the table via addHandler()
|
||||
// Request-response methods
|
||||
{.name = "account_info",
|
||||
.valueMethod = byRef(&doAccountInfo),
|
||||
.role = Role::USER,
|
||||
.condition = Condition::NoCondition},
|
||||
{.name = "account_currencies",
|
||||
.valueMethod = byRef(&doAccountCurrencies),
|
||||
.role = Role::USER,
|
||||
@@ -410,6 +417,7 @@ private:
|
||||
}
|
||||
|
||||
// This is where the new-style handlers are added.
|
||||
addHandler<AccountInfoHandler>();
|
||||
addHandler<LedgerHandler>();
|
||||
addHandler<VersionHandler>();
|
||||
}
|
||||
|
||||
@@ -6,8 +6,11 @@
|
||||
#include <xrpld/rpc/detail/Tuning.h>
|
||||
|
||||
#include <xrpl/protocol/ApiVersion.h>
|
||||
#include <xrpl/protocol/ErrorCodes.h>
|
||||
#include <xrpl/server/NetworkOPs.h>
|
||||
|
||||
#include <span>
|
||||
|
||||
namespace json {
|
||||
class Object;
|
||||
} // namespace json
|
||||
@@ -36,9 +39,37 @@ struct Handler
|
||||
unsigned maxApiVer = kAPI_MAXIMUM_VALID_VERSION;
|
||||
};
|
||||
|
||||
enum class FieldRequirement { Optional, Required };
|
||||
|
||||
struct FieldSpec
|
||||
{
|
||||
json::StaticString name;
|
||||
FieldRequirement requirement;
|
||||
json::ValueType type;
|
||||
};
|
||||
|
||||
Handler const*
|
||||
getHandler(unsigned int version, bool betaEnabled, std::string const&);
|
||||
|
||||
inline Status
|
||||
validateFieldSpecs(json::Value const& params, std::span<FieldSpec const> fields)
|
||||
{
|
||||
for (auto const& field : fields)
|
||||
{
|
||||
if (!params.isMember(field.name))
|
||||
{
|
||||
if (field.requirement == FieldRequirement::Required)
|
||||
return {RpcInvalidParams, missingFieldMessage(std::string(field.name))};
|
||||
continue;
|
||||
}
|
||||
|
||||
if (params[field.name].type() != field.type)
|
||||
return {RpcInvalidParams, invalidFieldMessage(field.name)};
|
||||
}
|
||||
|
||||
return Status::kOK;
|
||||
}
|
||||
|
||||
/** Return a json::ValueType::Object with a single entry. */
|
||||
template <class Value>
|
||||
json::Value
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#include <xrpld/rpc/handlers/account/AccountInfo.h>
|
||||
|
||||
#include <xrpld/app/main/Application.h>
|
||||
#include <xrpld/app/misc/TxQ.h>
|
||||
#include <xrpld/rpc/Context.h>
|
||||
@@ -91,14 +93,10 @@ doAccountInfo(RPC::JsonContext& context)
|
||||
std::string strIdent;
|
||||
if (params.isMember(jss::account))
|
||||
{
|
||||
if (!params[jss::account].isString())
|
||||
return RPC::invalidFieldError(jss::account);
|
||||
strIdent = params[jss::account].asString();
|
||||
}
|
||||
else if (params.isMember(jss::ident))
|
||||
{
|
||||
if (!params[jss::ident].isString())
|
||||
return RPC::invalidFieldError(jss::ident);
|
||||
strIdent = params[jss::ident].asString();
|
||||
}
|
||||
else
|
||||
@@ -340,4 +338,24 @@ doAccountInfo(RPC::JsonContext& context)
|
||||
return result;
|
||||
}
|
||||
|
||||
namespace RPC {
|
||||
|
||||
AccountInfoHandler::AccountInfoHandler(JsonContext& context) : context_(context)
|
||||
{
|
||||
}
|
||||
|
||||
Status
|
||||
AccountInfoHandler::check()
|
||||
{
|
||||
return Status::kOK;
|
||||
}
|
||||
|
||||
void
|
||||
AccountInfoHandler::writeResult(json::Value& value)
|
||||
{
|
||||
value = doAccountInfo(context_);
|
||||
}
|
||||
|
||||
} // namespace RPC
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
48
src/xrpld/rpc/handlers/account/AccountInfo.h
Normal file
48
src/xrpld/rpc/handlers/account/AccountInfo.h
Normal file
@@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpld/rpc/Context.h>
|
||||
#include <xrpld/rpc/Role.h>
|
||||
#include <xrpld/rpc/Status.h>
|
||||
#include <xrpld/rpc/detail/Handler.h>
|
||||
|
||||
#include <xrpl/protocol/ApiVersion.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace xrpl::RPC {
|
||||
|
||||
class AccountInfoHandler
|
||||
{
|
||||
public:
|
||||
explicit AccountInfoHandler(JsonContext&);
|
||||
|
||||
Status
|
||||
check();
|
||||
|
||||
void
|
||||
writeResult(json::Value&);
|
||||
|
||||
// NOLINTBEGIN(readability-identifier-naming)
|
||||
static constexpr char name[] = "account_info";
|
||||
|
||||
static constexpr unsigned minApiVer = RPC::kAPI_MINIMUM_SUPPORTED_VERSION;
|
||||
|
||||
static constexpr unsigned maxApiVer = RPC::kAPI_MAXIMUM_VALID_VERSION;
|
||||
|
||||
static constexpr Role role = Role::USER;
|
||||
|
||||
static constexpr Condition condition = Condition::NoCondition;
|
||||
|
||||
static constexpr std::array requestFields = {
|
||||
FieldSpec{jss::account, FieldRequirement::Optional, json::ValueType::String},
|
||||
FieldSpec{jss::ident, FieldRequirement::Optional, json::ValueType::String},
|
||||
FieldSpec{jss::queue, FieldRequirement::Optional, json::ValueType::Boolean},
|
||||
};
|
||||
// NOLINTEND(readability-identifier-naming)
|
||||
|
||||
private:
|
||||
JsonContext& context_;
|
||||
};
|
||||
|
||||
} // namespace xrpl::RPC
|
||||
Reference in New Issue
Block a user