Fix race condition and ub (#631)

This commit is contained in:
Alex Kremer
2023-05-10 18:35:04 +01:00
committed by GitHub
parent b3db4cadab
commit 4cae248b5c
17 changed files with 416 additions and 324 deletions

View File

@@ -119,6 +119,7 @@ if(BUILD_TESTS)
unittests/rpc/BaseTests.cpp
unittests/rpc/RPCHelpersTest.cpp
unittests/rpc/CountersTest.cpp
unittests/rpc/AdminVerificationTest.cpp
## RPC handlers
unittests/rpc/handlers/DefaultProcessorTests.cpp
unittests/rpc/handlers/TestHandlerTests.cpp

View File

@@ -96,9 +96,9 @@ SimpleCache::getPredecessor(ripple::uint256 const& key, uint32_t seq) const
std::optional<Blob>
SimpleCache::get(ripple::uint256 const& key, uint32_t seq) const
{
std::shared_lock lck{mtx_};
if (seq > latestSeq_)
return {};
std::shared_lock lck{mtx_};
objectReqCounter_++;
auto e = map_.find(key);
if (e == map_.end())

View File

@@ -56,8 +56,8 @@ struct TransactionAndMetadata
{
Blob transaction;
Blob metadata;
std::uint32_t ledgerSequence;
std::uint32_t date;
std::uint32_t ledgerSequence = 0;
std::uint32_t date = 0;
TransactionAndMetadata() = default;
TransactionAndMetadata(

View File

@@ -30,6 +30,7 @@
#include <etl/ReportingETL.h>
#include <log/Logger.h>
#include <rpc/Counters.h>
#include <rpc/RPCEngine.h>
#include <rpc/common/impl/HandlerProvider.h>
#include <webserver/Listener.h>

View File

@@ -19,7 +19,6 @@
#include <rpc/Counters.h>
#include <rpc/JS.h>
#include <rpc/RPC.h>
#include <rpc/RPCHelpers.h>
namespace RPC {

View File

@@ -18,8 +18,7 @@
//==============================================================================
#include <etl/ETLSource.h>
#include <log/Logger.h>
#include <rpc/RPCHelpers.h>
#include <rpc/RPC.h>
#include <rpc/common/impl/HandlerProvider.h>
#include <webserver/HttpBase.h>
#include <webserver/WsBase.h>
@@ -32,12 +31,6 @@ using namespace std;
using namespace clio;
using namespace RPC;
// local to compilation unit loggers
namespace {
clio::Logger gPerfLog{"Performance"};
clio::Logger gLog{"RPC"};
} // namespace
namespace RPC {
optional<Web::Context>
@@ -92,165 +85,4 @@ make_HttpContext(
return make_optional<Web::Context>(yc, command, 1, array.at(0).as_object(), nullptr, tagFactory, range, clientIp);
}
static unordered_set<string> forwardCommands{
"submit",
"submit_multisigned",
"fee",
"ledger_closed",
"ledger_current",
"ripple_path_find",
"manifest",
"channel_authorize",
"channel_verify"};
RPCEngine::RPCEngine(
std::shared_ptr<BackendInterface> const& backend,
std::shared_ptr<SubscriptionManager> const& subscriptions,
std::shared_ptr<ETLLoadBalancer> const& balancer,
std::shared_ptr<ReportingETL> const& etl,
clio::DOSGuard const& dosGuard,
WorkQueue& workQueue,
Counters& counters,
std::shared_ptr<HandlerProvider const> const& handlerProvider)
: backend_{backend}
, subscriptions_{subscriptions}
, balancer_{balancer}
, dosGuard_{std::cref(dosGuard)}
, workQueue_{std::ref(workQueue)}
, counters_{std::ref(counters)}
, handlerTable_{handlerProvider}
{
}
std::shared_ptr<RPCEngine>
RPCEngine::make_RPCEngine(
clio::Config const& config,
std::shared_ptr<BackendInterface> const& backend,
std::shared_ptr<SubscriptionManager> const& subscriptions,
std::shared_ptr<ETLLoadBalancer> const& balancer,
std::shared_ptr<ReportingETL> const& etl,
clio::DOSGuard const& dosGuard,
WorkQueue& workQueue,
Counters& counters,
std::shared_ptr<HandlerProvider const> const& handlerProvider)
{
return std::make_shared<RPCEngine>(
backend, subscriptions, balancer, etl, dosGuard, workQueue, counters, handlerProvider);
}
bool
RPCEngine::validHandler(string const& method) const
{
return handlerTable_.contains(method) || forwardCommands.contains(method);
}
bool
RPCEngine::isClioOnly(string const& method) const
{
return handlerTable_.isClioOnly(method);
}
bool
RPCEngine::shouldForwardToRippled(Web::Context const& ctx) const
{
auto request = ctx.params;
if (isClioOnly(ctx.method))
return false;
if (forwardCommands.find(ctx.method) != forwardCommands.end())
return true;
if (specifiesCurrentOrClosedLedger(request))
return true;
if (ctx.method == "account_info" && request.contains("queue") && request.at("queue").as_bool())
return true;
return false;
}
Result
RPCEngine::buildResponse(Web::Context const& ctx)
{
if (shouldForwardToRippled(ctx))
{
auto toForward = ctx.params;
toForward["command"] = ctx.method;
auto const res = balancer_->forwardToRippled(toForward, ctx.clientIp, ctx.yield);
notifyForwarded(ctx.method);
if (!res)
return Status{RippledError::rpcFAILED_TO_FORWARD};
return *res;
}
if (backend_->isTooBusy())
{
gLog.error() << "Database is too busy. Rejecting request";
return Status{RippledError::rpcTOO_BUSY};
}
auto const method = handlerTable_.getHandler(ctx.method);
if (!method)
return Status{RippledError::rpcUNKNOWN_COMMAND};
try
{
gPerfLog.debug() << ctx.tag() << " start executing rpc `" << ctx.method << '`';
auto const isAdmin = ctx.clientIp == "127.0.0.1"; // TODO: this should be a strategy
auto const context = Context{ctx.yield, ctx.session, isAdmin, ctx.clientIp};
auto const v = (*method).process(ctx.params, context);
gPerfLog.debug() << ctx.tag() << " finish executing rpc `" << ctx.method << '`';
if (v)
return v->as_object();
else
return Status{v.error()};
}
catch (InvalidParamsError const& err)
{
return Status{RippledError::rpcINVALID_PARAMS, err.what()};
}
catch (AccountNotFoundError const& err)
{
return Status{RippledError::rpcACT_NOT_FOUND, err.what()};
}
catch (Backend::DatabaseTimeout const& t)
{
gLog.error() << "Database timeout";
return Status{RippledError::rpcTOO_BUSY};
}
catch (exception const& err)
{
gLog.error() << ctx.tag() << " caught exception: " << err.what();
return Status{RippledError::rpcINTERNAL};
}
}
void
RPCEngine::notifyComplete(std::string const& method, std::chrono::microseconds const& duration)
{
if (validHandler(method))
counters_.get().rpcComplete(method, duration);
}
void
RPCEngine::notifyErrored(std::string const& method)
{
if (validHandler(method))
counters_.get().rpcErrored(method);
}
void
RPCEngine::notifyForwarded(std::string const& method)
{
if (validHandler(method))
counters_.get().rpcForwarded(method);
}
} // namespace RPC

View File

@@ -20,34 +20,24 @@
#pragma once
#include <backend/BackendInterface.h>
#include <config/Config.h>
#include <log/Logger.h>
#include <rpc/Counters.h>
#include <rpc/Errors.h>
#include <rpc/HandlerTable.h>
#include <rpc/common/AnyHandler.h>
#include <util/Taggable.h>
#include <webserver/Context.h>
#include <webserver/DOSGuard.h>
#include <boost/asio/spawn.hpp>
#include <boost/json.hpp>
#include <fmt/core.h>
#include <chrono>
#include <optional>
#include <string>
#include <unordered_map>
#include <variant>
/*
* This file contains various classes necessary for executing RPC handlers.
* Context gives the handlers access to various other parts of the application
* Status is used to report errors.
* And lastly, there are various functions for making Contexts, Statuses and
* serializing Status to JSON.
* This file is meant to contain any class or function that code outside of the
* rpc folder needs to use. For helper functions or classes used within the rpc
* folder, use RPCHelpers.h.
* Context gives the handlers access to various other parts of the application Status is used to report errors.
* And lastly, there are various functions for making Contexts, Statuses and serializing Status to JSON.
* This file is meant to contain any class or function that code outside of the rpc folder needs to use. For helper
* functions or classes used within the rpc folder, use RPCHelpers.h.
*/
class WsBase;
@@ -57,26 +47,6 @@ class ReportingETL;
namespace RPC {
struct AccountCursor
{
ripple::uint256 index;
std::uint32_t hint;
std::string
toString() const
{
return ripple::strHex(index) + "," + std::to_string(hint);
}
bool
isNonZero() const
{
return index.isNonZero() || hint != 0;
}
};
using Result = std::variant<Status, boost::json::object>;
std::optional<Web::Context>
make_WsContext(
boost::asio::yield_context& yc,
@@ -94,114 +64,4 @@ make_HttpContext(
Backend::LedgerRange const& range,
std::string const& clientIp);
/**
* @brief The RPC engine that ties all RPC-related functionality together
*/
class RPCEngine
{
std::shared_ptr<BackendInterface> backend_;
std::shared_ptr<SubscriptionManager> subscriptions_;
std::shared_ptr<ETLLoadBalancer> balancer_;
std::reference_wrapper<clio::DOSGuard const> dosGuard_;
std::reference_wrapper<WorkQueue> workQueue_;
std::reference_wrapper<Counters> counters_;
HandlerTable handlerTable_;
public:
RPCEngine(
std::shared_ptr<BackendInterface> const& backend,
std::shared_ptr<SubscriptionManager> const& subscriptions,
std::shared_ptr<ETLLoadBalancer> const& balancer,
std::shared_ptr<ReportingETL> const& etl,
clio::DOSGuard const& dosGuard,
WorkQueue& workQueue,
Counters& counters,
std::shared_ptr<HandlerProvider const> const& handlerProvider);
static std::shared_ptr<RPCEngine>
make_RPCEngine(
clio::Config const& config,
std::shared_ptr<BackendInterface> const& backend,
std::shared_ptr<SubscriptionManager> const& subscriptions,
std::shared_ptr<ETLLoadBalancer> const& balancer,
std::shared_ptr<ReportingETL> const& etl,
clio::DOSGuard const& dosGuard,
WorkQueue& workQueue,
Counters& counters,
std::shared_ptr<HandlerProvider const> const& handlerProvider);
/**
* @brief Main request processor routine
* @param ctx The @ref Context of the request
*/
Result
buildResponse(Web::Context const& ctx);
/**
* @brief Used to schedule request processing onto the work queue
* @param func The lambda to execute when this request is handled
* @param ip The ip address for which this request is being executed
*/
template <typename Fn>
bool
post(Fn&& func, std::string const& ip)
{
return workQueue_.get().postCoro(std::forward<Fn>(func), dosGuard_.get().isWhiteListed(ip));
}
/**
* @brief Notify the system that specified method was executed
* @param method
* @param duration The time it took to execute the method specified in
* microseconds
*/
void
notifyComplete(std::string const& method, std::chrono::microseconds const& duration);
/**
* @brief Notify the system that specified method failed to execute
* @param method
*/
void
notifyErrored(std::string const& method);
/**
* @brief Notify the system that specified method execution was forwarded to rippled
* @param method
*/
void
notifyForwarded(std::string const& method);
private:
bool
shouldForwardToRippled(Web::Context const& ctx) const;
bool
isClioOnly(std::string const& method) const;
bool
validHandler(std::string const& method) const;
};
template <class T>
void
logDuration(Web::Context const& ctx, T const& dur)
{
using boost::json::serialize;
static clio::Logger log{"RPC"};
auto const millis = std::chrono::duration_cast<std::chrono::milliseconds>(dur).count();
auto const seconds = std::chrono::duration_cast<std::chrono::seconds>(dur).count();
auto const msg =
fmt::format("Request processing duration = {} milliseconds. request = {}", millis, serialize(ctx.params));
if (seconds > 10)
log.error() << ctx.tag() << msg;
else if (seconds > 1)
log.warn() << ctx.tag() << msg;
else
log.info() << ctx.tag() << msg;
}
} // namespace RPC

275
src/rpc/RPCEngine.h Normal file
View File

@@ -0,0 +1,275 @@
//------------------------------------------------------------------------------
/*
This file is part of clio: https://github.com/XRPLF/clio
Copyright (c) 2022, the clio developers.
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#pragma once
#include <backend/BackendInterface.h>
#include <config/Config.h>
#include <etl/ETLSource.h>
#include <log/Logger.h>
#include <rpc/Counters.h>
#include <rpc/Errors.h>
#include <rpc/HandlerTable.h>
#include <rpc/RPCHelpers.h>
#include <rpc/common/AnyHandler.h>
#include <rpc/common/Types.h>
#include <rpc/common/impl/AdminVerificationStrategy.h>
#include <util/Taggable.h>
#include <webserver/Context.h>
#include <webserver/DOSGuard.h>
#include <boost/asio/spawn.hpp>
#include <boost/json.hpp>
#include <fmt/core.h>
#include <optional>
#include <string>
#include <unordered_map>
#include <variant>
class WsBase;
class SubscriptionManager;
class ETLLoadBalancer;
class ReportingETL;
namespace RPC {
/**
* @brief The RPC engine that ties all RPC-related functionality together
*/
template <typename AdminVerificationStrategyType>
class RPCEngineBase
{
clio::Logger perfLog_{"Performance"};
clio::Logger log_{"RPC"};
std::shared_ptr<BackendInterface> backend_;
std::shared_ptr<SubscriptionManager> subscriptions_;
std::shared_ptr<ETLLoadBalancer> balancer_;
std::reference_wrapper<clio::DOSGuard const> dosGuard_;
std::reference_wrapper<WorkQueue> workQueue_;
std::reference_wrapper<Counters> counters_;
HandlerTable handlerTable_;
AdminVerificationStrategyType adminVerifier_;
public:
RPCEngineBase(
std::shared_ptr<BackendInterface> const& backend,
std::shared_ptr<SubscriptionManager> const& subscriptions,
std::shared_ptr<ETLLoadBalancer> const& balancer,
std::shared_ptr<ReportingETL> const& etl,
clio::DOSGuard const& dosGuard,
WorkQueue& workQueue,
Counters& counters,
std::shared_ptr<HandlerProvider const> const& handlerProvider)
: backend_{backend}
, subscriptions_{subscriptions}
, balancer_{balancer}
, dosGuard_{std::cref(dosGuard)}
, workQueue_{std::ref(workQueue)}
, counters_{std::ref(counters)}
, handlerTable_{handlerProvider}
{
}
static std::shared_ptr<RPCEngineBase>
make_RPCEngine(
clio::Config const& config,
std::shared_ptr<BackendInterface> const& backend,
std::shared_ptr<SubscriptionManager> const& subscriptions,
std::shared_ptr<ETLLoadBalancer> const& balancer,
std::shared_ptr<ReportingETL> const& etl,
clio::DOSGuard const& dosGuard,
WorkQueue& workQueue,
Counters& counters,
std::shared_ptr<HandlerProvider const> const& handlerProvider)
{
return std::make_shared<RPCEngineBase>(
backend, subscriptions, balancer, etl, dosGuard, workQueue, counters, handlerProvider);
}
/**
* @brief Main request processor routine
* @param ctx The @ref Context of the request
*/
Result
buildResponse(Web::Context const& ctx)
{
if (shouldForwardToRippled(ctx))
{
auto toForward = ctx.params;
toForward["command"] = ctx.method;
auto const res = balancer_->forwardToRippled(toForward, ctx.clientIp, ctx.yield);
notifyForwarded(ctx.method);
if (!res)
return Status{RippledError::rpcFAILED_TO_FORWARD};
return *res;
}
if (backend_->isTooBusy())
{
log_.error() << "Database is too busy. Rejecting request";
return Status{RippledError::rpcTOO_BUSY};
}
auto const method = handlerTable_.getHandler(ctx.method);
if (!method)
return Status{RippledError::rpcUNKNOWN_COMMAND};
try
{
perfLog_.debug() << ctx.tag() << " start executing rpc `" << ctx.method << '`';
auto const isAdmin = adminVerifier_.isAdmin(ctx.clientIp);
auto const context = Context{ctx.yield, ctx.session, isAdmin, ctx.clientIp};
auto const v = (*method).process(ctx.params, context);
perfLog_.debug() << ctx.tag() << " finish executing rpc `" << ctx.method << '`';
if (v)
return v->as_object();
else
return Status{v.error()};
}
catch (InvalidParamsError const& err)
{
return Status{RippledError::rpcINVALID_PARAMS, err.what()};
}
catch (AccountNotFoundError const& err)
{
return Status{RippledError::rpcACT_NOT_FOUND, err.what()};
}
catch (Backend::DatabaseTimeout const& t)
{
log_.error() << "Database timeout";
return Status{RippledError::rpcTOO_BUSY};
}
catch (std::exception const& err)
{
log_.error() << ctx.tag() << " caught exception: " << err.what();
return Status{RippledError::rpcINTERNAL};
}
}
/**
* @brief Used to schedule request processing onto the work queue
* @param func The lambda to execute when this request is handled
* @param ip The ip address for which this request is being executed
*/
template <typename Fn>
bool
post(Fn&& func, std::string const& ip)
{
return workQueue_.get().postCoro(std::forward<Fn>(func), dosGuard_.get().isWhiteListed(ip));
}
/**
* @brief Notify the system that specified method was executed
* @param method
* @param duration The time it took to execute the method specified in
* microseconds
*/
void
notifyComplete(std::string const& method, std::chrono::microseconds const& duration)
{
if (validHandler(method))
counters_.get().rpcComplete(method, duration);
}
/**
* @brief Notify the system that specified method failed to execute
* @param method
*/
void
notifyErrored(std::string const& method)
{
if (validHandler(method))
counters_.get().rpcErrored(method);
}
/**
* @brief Notify the system that specified method execution was forwarded to rippled
* @param method
*/
void
notifyForwarded(std::string const& method)
{
if (validHandler(method))
counters_.get().rpcForwarded(method);
}
private:
bool
shouldForwardToRippled(Web::Context const& ctx) const
{
auto request = ctx.params;
if (isClioOnly(ctx.method))
return false;
if (isForwardCommand(ctx.method))
return true;
if (specifiesCurrentOrClosedLedger(request))
return true;
if (ctx.method == "account_info" && request.contains("queue") && request.at("queue").as_bool())
return true;
return false;
}
bool
isForwardCommand(std::string const& method) const
{
static std::unordered_set<std::string> const FORWARD_COMMANDS{
"submit",
"submit_multisigned",
"fee",
"ledger_closed",
"ledger_current",
"ripple_path_find",
"manifest",
"channel_authorize",
"channel_verify",
};
return FORWARD_COMMANDS.contains(method);
}
bool
isClioOnly(std::string const& method) const
{
return handlerTable_.isClioOnly(method);
}
bool
validHandler(std::string const& method) const
{
return handlerTable_.contains(method) || isForwardCommand(method);
}
};
using RPCEngine = RPCEngineBase<detail::IPAdminVerificationStrategy>;
} // namespace RPC

View File

@@ -21,7 +21,6 @@
#include <backend/BackendInterface.h>
#include <log/Logger.h>
#include <rpc/Errors.h>
#include <rpc/RPC.h>
#include <rpc/RPCHelpers.h>
#include <util/Profiler.h>

View File

@@ -20,8 +20,7 @@
#pragma once
/*
* This file contains a variety of utility functions used when executing
* the handlers
* This file contains a variety of utility functions used when executing the handlers.
*/
#include <ripple/app/ledger/Ledger.h>
@@ -30,9 +29,11 @@
#include <ripple/protocol/STTx.h>
#include <backend/BackendInterface.h>
#include <rpc/JS.h>
#include <rpc/RPC.h>
#include <rpc/common/Types.h>
#include <webserver/Context.h>
#include <fmt/core.h>
namespace RPC {
std::optional<ripple::AccountID>
@@ -281,4 +282,24 @@ traverseTransactions(
std::optional<Backend::TransactionsCursor> const&,
boost::asio::yield_context& yield)> transactionFetcher);
template <class T>
void
logDuration(Web::Context const& ctx, T const& dur)
{
using boost::json::serialize;
static clio::Logger log{"RPC"};
auto const millis = std::chrono::duration_cast<std::chrono::milliseconds>(dur).count();
auto const seconds = std::chrono::duration_cast<std::chrono::seconds>(dur).count();
auto const msg =
fmt::format("Request processing duration = {} milliseconds. request = {}", millis, serialize(ctx.params));
if (seconds > 10)
log.error() << ctx.tag() << msg;
else if (seconds > 1)
log.warn() << ctx.tag() << msg;
else
log.info() << ctx.tag() << msg;
}
} // namespace RPC

View File

@@ -22,6 +22,8 @@
#include <rpc/Errors.h>
#include <util/Expected.h>
#include <ripple/basics/base_uint.h>
#include <boost/asio/spawn.hpp>
#include <boost/json/value.hpp>
@@ -71,6 +73,26 @@ struct Context
std::string clientIp;
};
using Result = std::variant<Status, boost::json::object>;
struct AccountCursor
{
ripple::uint256 index;
std::uint32_t hint;
std::string
toString() const
{
return ripple::strHex(index) + "," + std::to_string(hint);
}
bool
isNonZero() const
{
return index.isNonZero() || hint != 0;
}
};
class AnyHandler;
class HandlerProvider

View File

@@ -0,0 +1,42 @@
//------------------------------------------------------------------------------
/*
This file is part of clio: https://github.com/XRPLF/clio
Copyright (c) 2023, the clio developers.
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#pragma once
#include <string_view>
namespace RPC::detail {
class IPAdminVerificationStrategy final
{
public:
/**
* @brief Checks whether request is from a host that is considered authorized as admin.
*
* @param ip The ip addr of the client
* @return true if authorized; false otherwise
*/
bool
isAdmin(std::string_view ip) const
{
return ip == "127.0.0.1";
}
};
} // namespace RPC::detail

View File

@@ -17,7 +17,6 @@
*/
//==============================================================================
#include <rpc/RPC.h>
#include <rpc/handlers/AccountLines.h>
namespace RPC {

View File

@@ -18,7 +18,6 @@
//==============================================================================
#include <ripple/protocol/TxFlags.h>
#include <rpc/RPC.h>
#include <rpc/handlers/NoRippleCheck.h>
#include <fmt/core.h>

View File

@@ -41,6 +41,7 @@
#include <main/Build.h>
#include <rpc/Counters.h>
#include <rpc/RPC.h>
#include <rpc/RPCEngine.h>
#include <rpc/WorkQueue.h>
#include <util/Profiler.h>
#include <util/Taggable.h>

View File

@@ -25,6 +25,7 @@
#include <log/Logger.h>
#include <rpc/Counters.h>
#include <rpc/RPC.h>
#include <rpc/RPCEngine.h>
#include <rpc/WorkQueue.h>
#include <subscriptions/Message.h>
#include <subscriptions/SubscriptionManager.h>

View File

@@ -0,0 +1,40 @@
//------------------------------------------------------------------------------
/*
This file is part of clio: https://github.com/XRPLF/clio
Copyright (c) 2023, the clio developers.
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <util/Fixtures.h>
#include <rpc/common/impl/AdminVerificationStrategy.h>
#include <boost/json.hpp>
#include <gtest/gtest.h>
class RPCAdminVerificationTest : public NoLoggerFixture
{
protected:
RPC::detail::IPAdminVerificationStrategy strat_;
};
TEST_F(RPCAdminVerificationTest, IsAdminOnlyForIP_127_0_0_1)
{
EXPECT_TRUE(strat_.isAdmin("127.0.0.1"));
EXPECT_FALSE(strat_.isAdmin("127.0.0.2"));
EXPECT_FALSE(strat_.isAdmin("127"));
EXPECT_FALSE(strat_.isAdmin(""));
EXPECT_FALSE(strat_.isAdmin("localhost"));
}