mirror of
https://github.com/XRPLF/clio.git
synced 2025-12-06 17:27:58 +00:00
Add option to set X-User header value for forwarded requests (#1425)
Fixes #1422.
This commit is contained in:
@@ -27,6 +27,7 @@
|
||||
#include <boost/json/serialize.hpp>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
@@ -42,7 +43,7 @@ struct ForwardingSourceTests : SyncAsioContextTest {
|
||||
TEST_F(ForwardingSourceTests, ConnectionFailed)
|
||||
{
|
||||
runSpawn([&](boost::asio::yield_context yield) {
|
||||
auto result = forwardingSource.forwardToRippled({}, {}, yield);
|
||||
auto result = forwardingSource.forwardToRippled({}, {}, {}, yield);
|
||||
EXPECT_FALSE(result);
|
||||
});
|
||||
}
|
||||
@@ -59,11 +60,34 @@ struct ForwardingSourceOperationsTests : ForwardingSourceTests {
|
||||
[&]() { ASSERT_FALSE(failedConnection); }();
|
||||
|
||||
auto connection = server_.acceptConnection(yield);
|
||||
[&]() { ASSERT_TRUE(connection); }();
|
||||
[&]() { ASSERT_TRUE(connection) << connection.error().message(); }();
|
||||
return std::move(connection).value();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(ForwardingSourceOperationsTests, XUserHeader)
|
||||
{
|
||||
std::string const xUserValue = "some_user";
|
||||
boost::asio::spawn(ctx, [&](boost::asio::yield_context yield) {
|
||||
auto connection = serverConnection(yield);
|
||||
auto headers = connection.headers();
|
||||
ASSERT_FALSE(headers.empty());
|
||||
auto it = std::find_if(headers.begin(), headers.end(), [](auto const& header) {
|
||||
return std::holds_alternative<std::string>(header.name) && std::get<std::string>(header.name) == "X-User";
|
||||
});
|
||||
ASSERT_FALSE(it == headers.end());
|
||||
EXPECT_EQ(std::get<std::string>(it->name), "X-User");
|
||||
EXPECT_EQ(it->value, xUserValue);
|
||||
connection.close(yield);
|
||||
});
|
||||
|
||||
runSpawn([&](boost::asio::yield_context yield) {
|
||||
auto result =
|
||||
forwardingSource.forwardToRippled(boost::json::parse(message_).as_object(), {}, xUserValue, yield);
|
||||
EXPECT_FALSE(result);
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(ForwardingSourceOperationsTests, ReadFailed)
|
||||
{
|
||||
boost::asio::spawn(ctx, [&](boost::asio::yield_context yield) {
|
||||
@@ -72,7 +96,7 @@ TEST_F(ForwardingSourceOperationsTests, ReadFailed)
|
||||
});
|
||||
|
||||
runSpawn([&](boost::asio::yield_context yield) {
|
||||
auto result = forwardingSource.forwardToRippled(boost::json::parse(message_).as_object(), {}, yield);
|
||||
auto result = forwardingSource.forwardToRippled(boost::json::parse(message_).as_object(), {}, {}, yield);
|
||||
EXPECT_FALSE(result);
|
||||
});
|
||||
}
|
||||
@@ -93,7 +117,7 @@ TEST_F(ForwardingSourceOperationsTests, ParseFailed)
|
||||
});
|
||||
|
||||
runSpawn([&](boost::asio::yield_context yield) {
|
||||
auto result = forwardingSource.forwardToRippled(boost::json::parse(message_).as_object(), {}, yield);
|
||||
auto result = forwardingSource.forwardToRippled(boost::json::parse(message_).as_object(), {}, {}, yield);
|
||||
EXPECT_FALSE(result);
|
||||
});
|
||||
}
|
||||
@@ -115,7 +139,7 @@ TEST_F(ForwardingSourceOperationsTests, GotNotAnObject)
|
||||
});
|
||||
|
||||
runSpawn([&](boost::asio::yield_context yield) {
|
||||
auto result = forwardingSource.forwardToRippled(boost::json::parse(message_).as_object(), {}, yield);
|
||||
auto result = forwardingSource.forwardToRippled(boost::json::parse(message_).as_object(), {}, {}, yield);
|
||||
EXPECT_FALSE(result);
|
||||
});
|
||||
}
|
||||
@@ -134,7 +158,7 @@ TEST_F(ForwardingSourceOperationsTests, Success)
|
||||
});
|
||||
|
||||
runSpawn([&](boost::asio::yield_context yield) {
|
||||
auto result = forwardingSource.forwardToRippled(boost::json::parse(message_).as_object(), "some_ip", yield);
|
||||
auto result = forwardingSource.forwardToRippled(boost::json::parse(message_).as_object(), "some_ip", {}, yield);
|
||||
[&]() { ASSERT_TRUE(result); }();
|
||||
auto expectedReply = reply_;
|
||||
expectedReply["forwarded"] = true;
|
||||
|
||||
@@ -485,37 +485,66 @@ struct LoadBalancerForwardToRippledTests : LoadBalancerConstructorTests, SyncAsi
|
||||
TEST_F(LoadBalancerForwardToRippledTests, forward)
|
||||
{
|
||||
auto loadBalancer = makeLoadBalancer();
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), forwardToRippled(request_, clientIP_, testing::_))
|
||||
EXPECT_CALL(
|
||||
sourceFactory_.sourceAt(0),
|
||||
forwardToRippled(request_, clientIP_, LoadBalancer::ADMIN_FORWARDING_X_USER_VALUE, testing::_)
|
||||
)
|
||||
.WillOnce(Return(response_));
|
||||
|
||||
runSpawn([&](boost::asio::yield_context yield) {
|
||||
EXPECT_EQ(loadBalancer->forwardToRippled(request_, clientIP_, yield), response_);
|
||||
EXPECT_EQ(loadBalancer->forwardToRippled(request_, clientIP_, true, yield), response_);
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(LoadBalancerForwardToRippledTests, forwardWithXUserHeader)
|
||||
{
|
||||
auto loadBalancer = makeLoadBalancer();
|
||||
EXPECT_CALL(
|
||||
sourceFactory_.sourceAt(0),
|
||||
forwardToRippled(request_, clientIP_, LoadBalancer::USER_FORWARDING_X_USER_VALUE, testing::_)
|
||||
)
|
||||
.WillOnce(Return(response_));
|
||||
|
||||
runSpawn([&](boost::asio::yield_context yield) {
|
||||
EXPECT_EQ(loadBalancer->forwardToRippled(request_, clientIP_, false, yield), response_);
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(LoadBalancerForwardToRippledTests, source0Fails)
|
||||
{
|
||||
auto loadBalancer = makeLoadBalancer();
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), forwardToRippled(request_, clientIP_, testing::_))
|
||||
EXPECT_CALL(
|
||||
sourceFactory_.sourceAt(0),
|
||||
forwardToRippled(request_, clientIP_, LoadBalancer::USER_FORWARDING_X_USER_VALUE, testing::_)
|
||||
)
|
||||
.WillOnce(Return(std::nullopt));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), forwardToRippled(request_, clientIP_, testing::_))
|
||||
EXPECT_CALL(
|
||||
sourceFactory_.sourceAt(1),
|
||||
forwardToRippled(request_, clientIP_, LoadBalancer::USER_FORWARDING_X_USER_VALUE, testing::_)
|
||||
)
|
||||
.WillOnce(Return(response_));
|
||||
|
||||
runSpawn([&](boost::asio::yield_context yield) {
|
||||
EXPECT_EQ(loadBalancer->forwardToRippled(request_, clientIP_, yield), response_);
|
||||
EXPECT_EQ(loadBalancer->forwardToRippled(request_, clientIP_, false, yield), response_);
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(LoadBalancerForwardToRippledTests, bothSourcesFail)
|
||||
{
|
||||
auto loadBalancer = makeLoadBalancer();
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), forwardToRippled(request_, clientIP_, testing::_))
|
||||
EXPECT_CALL(
|
||||
sourceFactory_.sourceAt(0),
|
||||
forwardToRippled(request_, clientIP_, LoadBalancer::USER_FORWARDING_X_USER_VALUE, testing::_)
|
||||
)
|
||||
.WillOnce(Return(std::nullopt));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), forwardToRippled(request_, clientIP_, testing::_))
|
||||
EXPECT_CALL(
|
||||
sourceFactory_.sourceAt(1),
|
||||
forwardToRippled(request_, clientIP_, LoadBalancer::USER_FORWARDING_X_USER_VALUE, testing::_)
|
||||
)
|
||||
.WillOnce(Return(std::nullopt));
|
||||
|
||||
runSpawn([&](boost::asio::yield_context yield) {
|
||||
EXPECT_EQ(loadBalancer->forwardToRippled(request_, clientIP_, yield), std::nullopt);
|
||||
EXPECT_EQ(loadBalancer->forwardToRippled(request_, clientIP_, false, yield), std::nullopt);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -526,15 +555,24 @@ TEST_F(LoadBalancerForwardToRippledTests, forwardingCacheEnabled)
|
||||
|
||||
auto const request = boost::json::object{{"command", "server_info"}};
|
||||
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), forwardToRippled(request, clientIP_, testing::_))
|
||||
EXPECT_CALL(
|
||||
sourceFactory_.sourceAt(0),
|
||||
forwardToRippled(request, clientIP_, LoadBalancer::USER_FORWARDING_X_USER_VALUE, testing::_)
|
||||
)
|
||||
.WillOnce(Return(response_));
|
||||
|
||||
runSpawn([&](boost::asio::yield_context yield) {
|
||||
EXPECT_EQ(loadBalancer->forwardToRippled(request, clientIP_, yield), response_);
|
||||
EXPECT_EQ(loadBalancer->forwardToRippled(request, clientIP_, yield), response_);
|
||||
EXPECT_EQ(loadBalancer->forwardToRippled(request, clientIP_, false, yield), response_);
|
||||
EXPECT_EQ(loadBalancer->forwardToRippled(request, clientIP_, false, yield), response_);
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(LoadBalancerForwardToRippledTests, forwardingCacheDisabledOnLedgerClosedHookCalled)
|
||||
{
|
||||
auto loadBalancer = makeLoadBalancer();
|
||||
EXPECT_NO_THROW(sourceFactory_.callbacksAt(0).onLedgerClosed());
|
||||
}
|
||||
|
||||
TEST_F(LoadBalancerForwardToRippledTests, onLedgerClosedHookInvalidatesCache)
|
||||
{
|
||||
configJson_.as_object()["forwarding_cache_timeout"] = 10.;
|
||||
@@ -542,16 +580,22 @@ TEST_F(LoadBalancerForwardToRippledTests, onLedgerClosedHookInvalidatesCache)
|
||||
|
||||
auto const request = boost::json::object{{"command", "server_info"}};
|
||||
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), forwardToRippled(request, clientIP_, testing::_))
|
||||
EXPECT_CALL(
|
||||
sourceFactory_.sourceAt(0),
|
||||
forwardToRippled(request, clientIP_, LoadBalancer::USER_FORWARDING_X_USER_VALUE, testing::_)
|
||||
)
|
||||
.WillOnce(Return(response_));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), forwardToRippled(request, clientIP_, testing::_))
|
||||
EXPECT_CALL(
|
||||
sourceFactory_.sourceAt(1),
|
||||
forwardToRippled(request, clientIP_, LoadBalancer::USER_FORWARDING_X_USER_VALUE, testing::_)
|
||||
)
|
||||
.WillOnce(Return(boost::json::object{}));
|
||||
|
||||
runSpawn([&](boost::asio::yield_context yield) {
|
||||
EXPECT_EQ(loadBalancer->forwardToRippled(request, clientIP_, yield), response_);
|
||||
EXPECT_EQ(loadBalancer->forwardToRippled(request, clientIP_, yield), response_);
|
||||
EXPECT_EQ(loadBalancer->forwardToRippled(request, clientIP_, false, yield), response_);
|
||||
EXPECT_EQ(loadBalancer->forwardToRippled(request, clientIP_, false, yield), response_);
|
||||
sourceFactory_.callbacksAt(0).onLedgerClosed();
|
||||
EXPECT_EQ(loadBalancer->forwardToRippled(request, clientIP_, yield), boost::json::object{});
|
||||
EXPECT_EQ(loadBalancer->forwardToRippled(request, clientIP_, false, yield), boost::json::object{});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@@ -67,7 +68,7 @@ struct ForwardingSourceMock {
|
||||
MOCK_METHOD(
|
||||
ForwardToRippledReturnType,
|
||||
forwardToRippled,
|
||||
(boost::json::object const&, ClientIpOpt const&, boost::asio::yield_context),
|
||||
(boost::json::object const&, ClientIpOpt const&, std::string_view, boost::asio::yield_context),
|
||||
(const)
|
||||
);
|
||||
};
|
||||
@@ -175,12 +176,14 @@ TEST_F(SourceImplTest, forwardToRippled)
|
||||
{
|
||||
boost::json::object const request = {{"some_key", "some_value"}};
|
||||
std::optional<std::string> const clientIp = "some_client_ip";
|
||||
std::string_view xUserValue = "some_user";
|
||||
|
||||
EXPECT_CALL(forwardingSourceMock_, forwardToRippled(request, clientIp, testing::_)).WillOnce(Return(request));
|
||||
EXPECT_CALL(forwardingSourceMock_, forwardToRippled(request, clientIp, xUserValue, testing::_))
|
||||
.WillOnce(Return(request));
|
||||
|
||||
boost::asio::io_context ioContext;
|
||||
boost::asio::spawn(ioContext, [&](boost::asio::yield_context yield) {
|
||||
auto const response = source_.forwardToRippled(request, clientIp, yield);
|
||||
auto const response = source_.forwardToRippled(request, clientIp, xUserValue, yield);
|
||||
EXPECT_EQ(response, request);
|
||||
});
|
||||
ioContext.run();
|
||||
|
||||
Reference in New Issue
Block a user