mirror of
				https://github.com/XRPLF/clio.git
				synced 2025-11-04 11:55:51 +00:00 
			
		
		
		
	Compare commits
	
		
			2 Commits
		
	
	
		
			release/2.
			...
			2.2.5-rc1
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					8b0e68f48e | ||
| 
						 | 
					189098d092 | 
							
								
								
									
										4
									
								
								.github/workflows/nightly.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/nightly.yml
									
									
									
									
										vendored
									
									
								
							@@ -13,12 +13,15 @@ jobs:
 | 
			
		||||
        include:
 | 
			
		||||
          - os: macos14
 | 
			
		||||
            build_type: Release
 | 
			
		||||
            static: false
 | 
			
		||||
          - os: heavy
 | 
			
		||||
            build_type: Release
 | 
			
		||||
            static: true
 | 
			
		||||
            container:
 | 
			
		||||
              image: rippleci/clio_ci:latest
 | 
			
		||||
          - os: heavy
 | 
			
		||||
            build_type: Debug
 | 
			
		||||
            static: true
 | 
			
		||||
            container:
 | 
			
		||||
              image: rippleci/clio_ci:latest
 | 
			
		||||
    runs-on: [self-hosted, "${{ matrix.os }}"]
 | 
			
		||||
@@ -50,6 +53,7 @@ jobs:
 | 
			
		||||
          conan_profile: ${{ steps.conan.outputs.conan_profile }}
 | 
			
		||||
          conan_cache_hit: ${{ steps.restore_cache.outputs.conan_cache_hit }}
 | 
			
		||||
          build_type: ${{ matrix.build_type }}
 | 
			
		||||
          static: ${{ matrix.static }}
 | 
			
		||||
 | 
			
		||||
      - name: Build Clio
 | 
			
		||||
        uses: ./.github/actions/build_clio
 | 
			
		||||
 
 | 
			
		||||
@@ -11,18 +11,16 @@ target_sources(clio_server PRIVATE Main.cpp)
 | 
			
		||||
target_link_libraries(clio_server PRIVATE clio)
 | 
			
		||||
 | 
			
		||||
if (static)
 | 
			
		||||
  target_link_options(clio_server PRIVATE -static)
 | 
			
		||||
 | 
			
		||||
  if (is_gcc AND NOT san)
 | 
			
		||||
  if (san)
 | 
			
		||||
    message(FATAL_ERROR "Static linkage not allowed when using sanitizers")
 | 
			
		||||
  elseif (is_appleclang)
 | 
			
		||||
    message(FATAL_ERROR "Static linkage not supported on AppleClang")
 | 
			
		||||
  else ()
 | 
			
		||||
    target_link_options(
 | 
			
		||||
      # For now let's assume that we only using libstdc++ under gcc.
 | 
			
		||||
      # Note: -static-libstdc++ can statically link both libstdc++ and libc++
 | 
			
		||||
      clio_server PRIVATE -static-libstdc++ -static-libgcc
 | 
			
		||||
    )
 | 
			
		||||
  endif ()
 | 
			
		||||
 | 
			
		||||
  if (is_appleclang)
 | 
			
		||||
    message(FATAL_ERROR "Static linkage not supported on AppleClang")
 | 
			
		||||
  endif ()
 | 
			
		||||
endif ()
 | 
			
		||||
 | 
			
		||||
set_target_properties(clio_server PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
 | 
			
		||||
 
 | 
			
		||||
@@ -134,7 +134,7 @@ private:
 | 
			
		||||
        // The timer below can be called with no error code even if the operation is completed before the timeout, so we
 | 
			
		||||
        // need an additional flag here
 | 
			
		||||
        timer.async_wait([&cancellationSignal, isCompleted](boost::system::error_code errorCode) {
 | 
			
		||||
            if (!errorCode and not *isCompleted)
 | 
			
		||||
            if (!errorCode and not*isCompleted)
 | 
			
		||||
                cancellationSignal.emit(boost::asio::cancellation_type::terminal);
 | 
			
		||||
        });
 | 
			
		||||
        operation(cyield);
 | 
			
		||||
 
 | 
			
		||||
@@ -69,10 +69,8 @@ namespace web {
 | 
			
		||||
 * @tparam HandlerType The executor to handle the requests
 | 
			
		||||
 */
 | 
			
		||||
template <
 | 
			
		||||
    template <typename>
 | 
			
		||||
    class PlainSessionType,
 | 
			
		||||
    template <typename>
 | 
			
		||||
    class SslSessionType,
 | 
			
		||||
    template <typename> class PlainSessionType,
 | 
			
		||||
    template <typename> class SslSessionType,
 | 
			
		||||
    SomeServerHandler HandlerType>
 | 
			
		||||
class Detector : public std::enable_shared_from_this<Detector<PlainSessionType, SslSessionType, HandlerType>> {
 | 
			
		||||
    using std::enable_shared_from_this<Detector<PlainSessionType, SslSessionType, HandlerType>>::shared_from_this;
 | 
			
		||||
@@ -191,10 +189,8 @@ public:
 | 
			
		||||
 * @tparam HandlerType The handler to process the request and return response.
 | 
			
		||||
 */
 | 
			
		||||
template <
 | 
			
		||||
    template <typename>
 | 
			
		||||
    class PlainSessionType,
 | 
			
		||||
    template <typename>
 | 
			
		||||
    class SslSessionType,
 | 
			
		||||
    template <typename> class PlainSessionType,
 | 
			
		||||
    template <typename> class SslSessionType,
 | 
			
		||||
    SomeServerHandler HandlerType>
 | 
			
		||||
class Server : public std::enable_shared_from_this<Server<PlainSessionType, SslSessionType, HandlerType>> {
 | 
			
		||||
    using std::enable_shared_from_this<Server<PlainSessionType, SslSessionType, HandlerType>>::shared_from_this;
 | 
			
		||||
 
 | 
			
		||||
@@ -23,6 +23,9 @@
 | 
			
		||||
#include "rpc/common/Types.hpp"
 | 
			
		||||
#include "util/Taggable.hpp"
 | 
			
		||||
#include "util/log/Logger.hpp"
 | 
			
		||||
#include "util/prometheus/Gauge.hpp"
 | 
			
		||||
#include "util/prometheus/Label.hpp"
 | 
			
		||||
#include "util/prometheus/Prometheus.hpp"
 | 
			
		||||
#include "web/DOSGuard.hpp"
 | 
			
		||||
#include "web/interface/Concepts.hpp"
 | 
			
		||||
#include "web/interface/ConnectionBase.hpp"
 | 
			
		||||
@@ -71,6 +74,8 @@ template <template <typename> typename Derived, SomeServerHandler HandlerType>
 | 
			
		||||
class WsBase : public ConnectionBase, public std::enable_shared_from_this<WsBase<Derived, HandlerType>> {
 | 
			
		||||
    using std::enable_shared_from_this<WsBase<Derived, HandlerType>>::shared_from_this;
 | 
			
		||||
 | 
			
		||||
    std::reference_wrapper<util::prometheus::GaugeInt> messagesLength_;
 | 
			
		||||
 | 
			
		||||
    boost::beast::flat_buffer buffer_;
 | 
			
		||||
    std::reference_wrapper<web::DOSGuard> dosGuard_;
 | 
			
		||||
    bool sending_ = false;
 | 
			
		||||
@@ -103,15 +108,26 @@ public:
 | 
			
		||||
        std::shared_ptr<HandlerType> const& handler,
 | 
			
		||||
        boost::beast::flat_buffer&& buffer
 | 
			
		||||
    )
 | 
			
		||||
        : ConnectionBase(tagFactory, ip), buffer_(std::move(buffer)), dosGuard_(dosGuard), handler_(handler)
 | 
			
		||||
        : ConnectionBase(tagFactory, ip)
 | 
			
		||||
        , messagesLength_(PrometheusService::gaugeInt(
 | 
			
		||||
              "ws_messages_length",
 | 
			
		||||
              util::prometheus::Labels(),
 | 
			
		||||
              "The total length of messages in the queue"
 | 
			
		||||
          ))
 | 
			
		||||
        , buffer_(std::move(buffer))
 | 
			
		||||
        , dosGuard_(dosGuard)
 | 
			
		||||
        , handler_(handler)
 | 
			
		||||
    {
 | 
			
		||||
        upgraded = true;  // NOLINT (cppcoreguidelines-pro-type-member-init)
 | 
			
		||||
 | 
			
		||||
        LOG(perfLog_.debug()) << tag() << "session created";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~WsBase() override
 | 
			
		||||
    {
 | 
			
		||||
        LOG(perfLog_.debug()) << tag() << "session closed";
 | 
			
		||||
        if (!messages_.empty())
 | 
			
		||||
            messagesLength_.get() -= messages_.size();
 | 
			
		||||
        dosGuard_.get().decrement(clientIp);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -135,6 +151,7 @@ public:
 | 
			
		||||
    onWrite(boost::system::error_code ec, std::size_t)
 | 
			
		||||
    {
 | 
			
		||||
        messages_.pop();
 | 
			
		||||
        --messagesLength_.get();
 | 
			
		||||
        sending_ = false;
 | 
			
		||||
        if (ec) {
 | 
			
		||||
            wsFail(ec, "Failed to write");
 | 
			
		||||
@@ -165,6 +182,7 @@ public:
 | 
			
		||||
            derived().ws().get_executor(),
 | 
			
		||||
            [this, self = derived().shared_from_this(), msg = std::move(msg)]() {
 | 
			
		||||
                messages_.push(msg);
 | 
			
		||||
                ++messagesLength_.get();
 | 
			
		||||
                maybeSendNext();
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
 
 | 
			
		||||
@@ -22,6 +22,7 @@
 | 
			
		||||
#include "util/MockPrometheus.hpp"
 | 
			
		||||
#include "util/TestHttpSyncClient.hpp"
 | 
			
		||||
#include "util/config/Config.hpp"
 | 
			
		||||
#include "util/prometheus/Gauge.hpp"
 | 
			
		||||
#include "util/prometheus/Label.hpp"
 | 
			
		||||
#include "util/prometheus/Prometheus.hpp"
 | 
			
		||||
#include "web/DOSGuard.hpp"
 | 
			
		||||
@@ -42,6 +43,7 @@
 | 
			
		||||
#include <boost/json/parse.hpp>
 | 
			
		||||
#include <boost/system/system_error.hpp>
 | 
			
		||||
#include <fmt/core.h>
 | 
			
		||||
#include <gmock/gmock.h>
 | 
			
		||||
#include <gtest/gtest.h>
 | 
			
		||||
 | 
			
		||||
#include <chrono>
 | 
			
		||||
@@ -202,6 +204,8 @@ private:
 | 
			
		||||
    std::optional<std::thread> runner;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct WebServerTestsWithMockPrometheus : WebServerTest, prometheus::WithMockPrometheus {};
 | 
			
		||||
 | 
			
		||||
class EchoExecutor {
 | 
			
		||||
public:
 | 
			
		||||
    void
 | 
			
		||||
@@ -263,7 +267,7 @@ makeServerSync(
 | 
			
		||||
 | 
			
		||||
}  // namespace
 | 
			
		||||
 | 
			
		||||
TEST_F(WebServerTest, Http)
 | 
			
		||||
TEST_F(WebServerTestsWithMockPrometheus, Http)
 | 
			
		||||
{
 | 
			
		||||
    auto e = std::make_shared<EchoExecutor>();
 | 
			
		||||
    auto const server = makeServerSync(cfg, ctx, std::nullopt, dosGuard, e);
 | 
			
		||||
@@ -271,8 +275,13 @@ TEST_F(WebServerTest, Http)
 | 
			
		||||
    EXPECT_EQ(res, R"({"Hello":1})");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_F(WebServerTest, Ws)
 | 
			
		||||
TEST_F(WebServerTestsWithMockPrometheus, Ws)
 | 
			
		||||
{
 | 
			
		||||
    ::testing::StrictMock<util::prometheus::MockCounterImplInt>& wsMessagesCounterMock =
 | 
			
		||||
        makeMock<util::prometheus::GaugeInt>("ws_messages_length", "");
 | 
			
		||||
    EXPECT_CALL(wsMessagesCounterMock, add(1));
 | 
			
		||||
    EXPECT_CALL(wsMessagesCounterMock, add(-1));
 | 
			
		||||
 | 
			
		||||
    auto e = std::make_shared<EchoExecutor>();
 | 
			
		||||
    auto const server = makeServerSync(cfg, ctx, std::nullopt, dosGuard, e);
 | 
			
		||||
    WebSocketSyncClient wsClient;
 | 
			
		||||
@@ -282,7 +291,7 @@ TEST_F(WebServerTest, Ws)
 | 
			
		||||
    wsClient.disconnect();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_F(WebServerTest, HttpInternalError)
 | 
			
		||||
TEST_F(WebServerTestsWithMockPrometheus, HttpInternalError)
 | 
			
		||||
{
 | 
			
		||||
    auto e = std::make_shared<ExceptionExecutor>();
 | 
			
		||||
    auto const server = makeServerSync(cfg, ctx, std::nullopt, dosGuard, e);
 | 
			
		||||
@@ -293,8 +302,13 @@ TEST_F(WebServerTest, HttpInternalError)
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_F(WebServerTest, WsInternalError)
 | 
			
		||||
TEST_F(WebServerTestsWithMockPrometheus, WsInternalError)
 | 
			
		||||
{
 | 
			
		||||
    ::testing::StrictMock<util::prometheus::MockCounterImplInt>& wsMessagesCounterMock =
 | 
			
		||||
        makeMock<util::prometheus::GaugeInt>("ws_messages_length", "");
 | 
			
		||||
    EXPECT_CALL(wsMessagesCounterMock, add(1));
 | 
			
		||||
    EXPECT_CALL(wsMessagesCounterMock, add(-1));
 | 
			
		||||
 | 
			
		||||
    auto e = std::make_shared<ExceptionExecutor>();
 | 
			
		||||
    auto const server = makeServerSync(cfg, ctx, std::nullopt, dosGuard, e);
 | 
			
		||||
    WebSocketSyncClient wsClient;
 | 
			
		||||
@@ -307,8 +321,13 @@ TEST_F(WebServerTest, WsInternalError)
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_F(WebServerTest, WsInternalErrorNotJson)
 | 
			
		||||
TEST_F(WebServerTestsWithMockPrometheus, WsInternalErrorNotJson)
 | 
			
		||||
{
 | 
			
		||||
    ::testing::StrictMock<util::prometheus::MockCounterImplInt>& wsMessagesCounterMock =
 | 
			
		||||
        makeMock<util::prometheus::GaugeInt>("ws_messages_length", "");
 | 
			
		||||
    EXPECT_CALL(wsMessagesCounterMock, add(1));
 | 
			
		||||
    EXPECT_CALL(wsMessagesCounterMock, add(-1));
 | 
			
		||||
 | 
			
		||||
    auto e = std::make_shared<ExceptionExecutor>();
 | 
			
		||||
    auto const server = makeServerSync(cfg, ctx, std::nullopt, dosGuard, e);
 | 
			
		||||
    WebSocketSyncClient wsClient;
 | 
			
		||||
@@ -321,7 +340,7 @@ TEST_F(WebServerTest, WsInternalErrorNotJson)
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_F(WebServerTest, Https)
 | 
			
		||||
TEST_F(WebServerTestsWithMockPrometheus, Https)
 | 
			
		||||
{
 | 
			
		||||
    auto e = std::make_shared<EchoExecutor>();
 | 
			
		||||
    auto sslCtx = parseCertsForTest();
 | 
			
		||||
@@ -331,8 +350,13 @@ TEST_F(WebServerTest, Https)
 | 
			
		||||
    EXPECT_EQ(res, R"({"Hello":1})");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_F(WebServerTest, Wss)
 | 
			
		||||
TEST_F(WebServerTestsWithMockPrometheus, Wss)
 | 
			
		||||
{
 | 
			
		||||
    ::testing::StrictMock<util::prometheus::MockCounterImplInt>& wsMessagesCounterMock =
 | 
			
		||||
        makeMock<util::prometheus::GaugeInt>("ws_messages_length", "");
 | 
			
		||||
    EXPECT_CALL(wsMessagesCounterMock, add(1));
 | 
			
		||||
    EXPECT_CALL(wsMessagesCounterMock, add(-1));
 | 
			
		||||
 | 
			
		||||
    auto e = std::make_shared<EchoExecutor>();
 | 
			
		||||
    auto sslCtx = parseCertsForTest();
 | 
			
		||||
    auto const ctxSslRef = sslCtx ? std::optional<std::reference_wrapper<ssl::context>>{sslCtx.value()} : std::nullopt;
 | 
			
		||||
@@ -345,7 +369,7 @@ TEST_F(WebServerTest, Wss)
 | 
			
		||||
    wsClient.disconnect();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_F(WebServerTest, HttpRequestOverload)
 | 
			
		||||
TEST_F(WebServerTestsWithMockPrometheus, HttpRequestOverload)
 | 
			
		||||
{
 | 
			
		||||
    auto e = std::make_shared<EchoExecutor>();
 | 
			
		||||
    auto const server = makeServerSync(cfg, ctx, std::nullopt, dosGuardOverload, e);
 | 
			
		||||
@@ -358,8 +382,13 @@ TEST_F(WebServerTest, HttpRequestOverload)
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_F(WebServerTest, WsRequestOverload)
 | 
			
		||||
TEST_F(WebServerTestsWithMockPrometheus, WsRequestOverload)
 | 
			
		||||
{
 | 
			
		||||
    ::testing::StrictMock<util::prometheus::MockCounterImplInt>& wsMessagesCounterMock =
 | 
			
		||||
        makeMock<util::prometheus::GaugeInt>("ws_messages_length", "");
 | 
			
		||||
    EXPECT_CALL(wsMessagesCounterMock, add(1)).Times(2);
 | 
			
		||||
    EXPECT_CALL(wsMessagesCounterMock, add(-1)).Times(2);
 | 
			
		||||
 | 
			
		||||
    auto e = std::make_shared<EchoExecutor>();
 | 
			
		||||
    auto const server = makeServerSync(cfg, ctx, std::nullopt, dosGuardOverload, e);
 | 
			
		||||
    WebSocketSyncClient wsClient;
 | 
			
		||||
@@ -377,7 +406,7 @@ TEST_F(WebServerTest, WsRequestOverload)
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_F(WebServerTest, HttpPayloadOverload)
 | 
			
		||||
TEST_F(WebServerTestsWithMockPrometheus, HttpPayloadOverload)
 | 
			
		||||
{
 | 
			
		||||
    std::string const s100(100, 'a');
 | 
			
		||||
    auto e = std::make_shared<EchoExecutor>();
 | 
			
		||||
@@ -389,8 +418,13 @@ TEST_F(WebServerTest, HttpPayloadOverload)
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_F(WebServerTest, WsPayloadOverload)
 | 
			
		||||
TEST_F(WebServerTestsWithMockPrometheus, WsPayloadOverload)
 | 
			
		||||
{
 | 
			
		||||
    ::testing::StrictMock<util::prometheus::MockCounterImplInt>& wsMessagesCounterMock =
 | 
			
		||||
        makeMock<util::prometheus::GaugeInt>("ws_messages_length", "");
 | 
			
		||||
    EXPECT_CALL(wsMessagesCounterMock, add(1));
 | 
			
		||||
    EXPECT_CALL(wsMessagesCounterMock, add(-1));
 | 
			
		||||
 | 
			
		||||
    std::string const s100(100, 'a');
 | 
			
		||||
    auto e = std::make_shared<EchoExecutor>();
 | 
			
		||||
    auto server = makeServerSync(cfg, ctx, std::nullopt, dosGuardOverload, e);
 | 
			
		||||
@@ -404,7 +438,7 @@ TEST_F(WebServerTest, WsPayloadOverload)
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_F(WebServerTest, WsTooManyConnection)
 | 
			
		||||
TEST_F(WebServerTestsWithMockPrometheus, WsTooManyConnection)
 | 
			
		||||
{
 | 
			
		||||
    auto e = std::make_shared<EchoExecutor>();
 | 
			
		||||
    auto server = makeServerSync(cfg, ctx, std::nullopt, dosGuardOverload, e);
 | 
			
		||||
@@ -510,10 +544,17 @@ struct WebServerAdminTestParams {
 | 
			
		||||
    std::string expectedResponse;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class WebServerAdminTest : public WebServerTest, public ::testing::WithParamInterface<WebServerAdminTestParams> {};
 | 
			
		||||
class WebServerAdminTest : public WebServerTest,
 | 
			
		||||
                           public ::testing::WithParamInterface<WebServerAdminTestParams>,
 | 
			
		||||
                           public prometheus::WithMockPrometheus {};
 | 
			
		||||
 | 
			
		||||
TEST_P(WebServerAdminTest, WsAdminCheck)
 | 
			
		||||
{
 | 
			
		||||
    ::testing::StrictMock<util::prometheus::MockCounterImplInt>& wsMessagesCounterMock =
 | 
			
		||||
        makeMock<util::prometheus::GaugeInt>("ws_messages_length", "");
 | 
			
		||||
    EXPECT_CALL(wsMessagesCounterMock, add(1));
 | 
			
		||||
    EXPECT_CALL(wsMessagesCounterMock, add(-1));
 | 
			
		||||
 | 
			
		||||
    auto e = std::make_shared<AdminCheckExecutor>();
 | 
			
		||||
    Config const serverConfig{parse(GetParam().config)};
 | 
			
		||||
    auto server = makeServerSync(serverConfig, ctx, std::nullopt, dosGuardOverload, e);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user