diff --git a/src/etlng/impl/ext/Core.cpp b/src/etlng/impl/ext/Core.cpp index fa2c3c9fa..3049961fd 100644 --- a/src/etlng/impl/ext/Core.cpp +++ b/src/etlng/impl/ext/Core.cpp @@ -23,7 +23,6 @@ #include "etlng/Models.hpp" #include "util/log/Logger.hpp" - #include #include #include diff --git a/src/web/CMakeLists.txt b/src/web/CMakeLists.txt index 083eae90c..251fda1bd 100644 --- a/src/web/CMakeLists.txt +++ b/src/web/CMakeLists.txt @@ -10,7 +10,6 @@ target_sources( ng/impl/ErrorHandling.cpp ng/impl/ConnectionHandler.cpp ng/impl/ServerSslContext.cpp - ng/impl/WsConnection.cpp ng/Request.cpp ng/Response.cpp ng/Server.cpp diff --git a/src/web/ng/Server.cpp b/src/web/ng/Server.cpp index a209fea35..be3fe1064 100644 --- a/src/web/ng/Server.cpp +++ b/src/web/ng/Server.cpp @@ -46,6 +46,7 @@ #include #include +#include #include #include #include @@ -136,13 +137,19 @@ makeConnection( if (not sslContext.has_value()) return std::unexpected{"Error creating a connection: SSL is not supported by this server"}; - connection = std::make_unique( + auto sslConnection = std::make_unique( std::move(sslDetectionResult.socket), std::move(ip), std::move(sslDetectionResult.buffer), *sslContext, tagDecoratorFactory ); + sslConnection->setTimeout(std::chrono::seconds{10}); + auto const maybeError = sslConnection->sslHandshake(yield); + if (maybeError.has_value()) + return std::unexpected{fmt::format("SSL handshake error: {}", maybeError->message())}; + + connection = std::move(sslConnection); } else { connection = std::make_unique( std::move(sslDetectionResult.socket), @@ -164,7 +171,6 @@ makeConnection( std::expected tryUpgradeConnection( impl::UpgradableConnectionPtr connection, - std::optional& sslContext, util::TagDecoratorFactory& tagDecoratorFactory, boost::asio::yield_context yield ) @@ -177,7 +183,7 @@ tryUpgradeConnection( } if (*expectedIsUpgrade) { - auto expectedUpgradedConnection = connection->upgrade(sslContext, tagDecoratorFactory, yield); + auto expectedUpgradedConnection = connection->upgrade(tagDecoratorFactory, yield); if (expectedUpgradedConnection.has_value()) return std::move(expectedUpgradedConnection).value(); @@ -316,8 +322,7 @@ Server::handleConnection(boost::asio::ip::tcp::socket socket, boost::asio::yield return; } - auto connection = - tryUpgradeConnection(std::move(connectionExpected).value(), sslContext_, tagDecoratorFactory_, yield); + auto connection = tryUpgradeConnection(std::move(connectionExpected).value(), tagDecoratorFactory_, yield); if (not connection.has_value()) { LOG(log_.info()) << connection.error(); return; diff --git a/src/web/ng/impl/HttpConnection.hpp b/src/web/ng/impl/HttpConnection.hpp index b7bdfae6a..0cad34383 100644 --- a/src/web/ng/impl/HttpConnection.hpp +++ b/src/web/ng/impl/HttpConnection.hpp @@ -28,10 +28,12 @@ #include "web/ng/impl/Concepts.hpp" #include "web/ng/impl/WsConnection.hpp" +#include #include #include #include #include +#include #include #include #include @@ -57,11 +59,7 @@ public: isUpgradeRequested(boost::asio::yield_context yield) = 0; virtual std::expected - upgrade( - std::optional& sslContext, - util::TagDecoratorFactory const& tagDecoratorFactory, - boost::asio::yield_context yield - ) = 0; + upgrade(util::TagDecoratorFactory const& tagDecoratorFactory, boost::asio::yield_context yield) = 0; virtual std::optional sendRaw( @@ -104,6 +102,22 @@ public: { } + std::optional + sslHandshake(boost::asio::yield_context yield) + requires IsSslTcpStream + { + boost::system::error_code error; + boost::beast::get_lowest_layer(stream_).expires_after(timeout_); + auto const bytesUsed = + stream_.async_handshake(boost::asio::ssl::stream_base::server, buffer_.cdata(), yield[error]); + if (error) + return error; + + buffer_.consume(bytesUsed); + + return std::nullopt; + } + bool wasUpgraded() const override { @@ -183,35 +197,18 @@ public: } std::expected - upgrade( - [[maybe_unused]] std::optional& sslContext, - util::TagDecoratorFactory const& tagDecoratorFactory, - boost::asio::yield_context yield - ) override + upgrade(util::TagDecoratorFactory const& tagDecoratorFactory, boost::asio::yield_context yield) override { ASSERT(request_.has_value(), "Request must be present to upgrade the connection"); - if constexpr (IsSslTcpStream) { - ASSERT(sslContext.has_value(), "SSL context must be present to upgrade the connection"); - return makeSslWsConnection( - boost::beast::get_lowest_layer(stream_).release_socket(), - std::move(ip_), - std::move(buffer_), - std::move(request_).value(), - sslContext.value(), - tagDecoratorFactory, - yield - ); - } else { - return makePlainWsConnection( - stream_.release_socket(), - std::move(ip_), - std::move(buffer_), - std::move(request_).value(), - tagDecoratorFactory, - yield - ); - } + return makeWsConnection( + std::move(stream_), + std::move(ip_), + std::move(buffer_), + std::move(request_).value(), + tagDecoratorFactory, + yield + ); } private: diff --git a/src/web/ng/impl/WsConnection.cpp b/src/web/ng/impl/WsConnection.cpp deleted file mode 100644 index 89c47ba05..000000000 --- a/src/web/ng/impl/WsConnection.cpp +++ /dev/null @@ -1,77 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of clio: https://github.com/XRPLF/clio - Copyright (c) 2024, 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 "web/ng/impl/WsConnection.hpp" - -#include "util/Taggable.hpp" -#include "web/ng/Error.hpp" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -namespace web::ng::impl { - -std::expected, Error> -makePlainWsConnection( - boost::asio::ip::tcp::socket socket, - std::string ip, - boost::beast::flat_buffer buffer, - boost::beast::http::request request, - util::TagDecoratorFactory const& tagDecoratorFactory, - boost::asio::yield_context yield -) -{ - auto connection = std::make_unique( - std::move(socket), std::move(ip), std::move(buffer), std::move(request), tagDecoratorFactory - ); - auto maybeError = connection->performHandshake(yield); - if (maybeError.has_value()) - return std::unexpected{maybeError.value()}; - return connection; -} - -std::expected, Error> -makeSslWsConnection( - boost::asio::ip::tcp::socket socket, - std::string ip, - boost::beast::flat_buffer buffer, - boost::beast::http::request request, - boost::asio::ssl::context& sslContext, - util::TagDecoratorFactory const& tagDecoratorFactory, - boost::asio::yield_context yield -) -{ - auto connection = std::make_unique( - std::move(socket), std::move(ip), std::move(buffer), sslContext, std::move(request), tagDecoratorFactory - ); - auto maybeError = connection->performHandshake(yield); - if (maybeError.has_value()) - return std::unexpected{maybeError.value()}; - return connection; -} - -} // namespace web::ng::impl diff --git a/src/web/ng/impl/WsConnection.hpp b/src/web/ng/impl/WsConnection.hpp index e13e51b66..9d48d392d 100644 --- a/src/web/ng/impl/WsConnection.hpp +++ b/src/web/ng/impl/WsConnection.hpp @@ -68,31 +68,14 @@ class WsConnection : public WsConnectionBase { public: WsConnection( - boost::asio::ip::tcp::socket socket, + StreamType&& stream, std::string ip, boost::beast::flat_buffer buffer, boost::beast::http::request initialRequest, util::TagDecoratorFactory const& tagDecoratorFactory ) - requires IsTcpStream : WsConnectionBase(std::move(ip), std::move(buffer), tagDecoratorFactory) - , stream_(std::move(socket)) - , initialRequest_(std::move(initialRequest)) - { - setupWsStream(); - } - - WsConnection( - boost::asio::ip::tcp::socket socket, - std::string ip, - boost::beast::flat_buffer buffer, - boost::asio::ssl::context& sslContext, - boost::beast::http::request initialRequest, - util::TagDecoratorFactory const& tagDecoratorFactory - ) - requires IsSslTcpStream - : WsConnectionBase(std::move(ip), std::move(buffer), tagDecoratorFactory) - , stream_(std::move(socket), sslContext) + , stream_(std::move(stream)) , initialRequest_(std::move(initialRequest)) { setupWsStream(); @@ -189,25 +172,24 @@ private: using PlainWsConnection = WsConnection; using SslWsConnection = WsConnection>; -std::expected, Error> -makePlainWsConnection( - boost::asio::ip::tcp::socket socket, +template +std::expected>, Error> +makeWsConnection( + StreamType&& stream, std::string ip, boost::beast::flat_buffer buffer, boost::beast::http::request request, util::TagDecoratorFactory const& tagDecoratorFactory, boost::asio::yield_context yield -); - -std::expected, Error> -makeSslWsConnection( - boost::asio::ip::tcp::socket socket, - std::string ip, - boost::beast::flat_buffer buffer, - boost::beast::http::request request, - boost::asio::ssl::context& sslContext, - util::TagDecoratorFactory const& tagDecoratorFactory, - boost::asio::yield_context yield -); +) +{ + auto connection = std::make_unique>( + std::forward(stream), std::move(ip), std::move(buffer), std::move(request), tagDecoratorFactory + ); + auto maybeError = connection->performHandshake(yield); + if (maybeError.has_value()) + return std::unexpected{maybeError.value()}; + return connection; +} } // namespace web::ng::impl diff --git a/tests/common/web/ng/impl/MockHttpConnection.hpp b/tests/common/web/ng/impl/MockHttpConnection.hpp index 8f4ab0885..7288a5f8a 100644 --- a/tests/common/web/ng/impl/MockHttpConnection.hpp +++ b/tests/common/web/ng/impl/MockHttpConnection.hpp @@ -67,9 +67,7 @@ struct MockHttpConnectionImpl : web::ng::impl::UpgradableConnection { MOCK_METHOD( UpgradeReturnType, upgrade, - (OptionalSslContext & sslContext, - util::TagDecoratorFactory const& tagDecoratorFactory, - boost::asio::yield_context yield), + (util::TagDecoratorFactory const& tagDecoratorFactory, boost::asio::yield_context yield), (override) ); }; diff --git a/tests/unit/web/ng/impl/HttpConnectionTests.cpp b/tests/unit/web/ng/impl/HttpConnectionTests.cpp index eb03f1ffd..4c6e5d4f4 100644 --- a/tests/unit/web/ng/impl/HttpConnectionTests.cpp +++ b/tests/unit/web/ng/impl/HttpConnectionTests.cpp @@ -300,8 +300,7 @@ TEST_F(HttpConnectionTests, Upgrade) [&]() { ASSERT_TRUE(expectedResult.has_value()) << expectedResult.error().message(); }(); [&]() { ASSERT_TRUE(expectedResult.value()); }(); - std::optional sslContext; - auto expectedWsConnection = connection.upgrade(sslContext, tagDecoratorFactory_, yield); + auto expectedWsConnection = connection.upgrade(tagDecoratorFactory_, yield); [&]() { ASSERT_TRUE(expectedWsConnection.has_value()) << expectedWsConnection.error().message(); }(); }); } diff --git a/tests/unit/web/ng/impl/WsConnectionTests.cpp b/tests/unit/web/ng/impl/WsConnectionTests.cpp index 122ad746e..b449919a4 100644 --- a/tests/unit/web/ng/impl/WsConnectionTests.cpp +++ b/tests/unit/web/ng/impl/WsConnectionTests.cpp @@ -74,8 +74,7 @@ struct WebWsConnectionTests : SyncAsioContextTest { ASSERT_TRUE(expectedTrue.value()) << "Expected upgrade request"; }(); - std::optional sslContext; - auto expectedWsConnection = httpConnection.upgrade(sslContext, tagDecoratorFactory_, yield); + auto expectedWsConnection = httpConnection.upgrade(tagDecoratorFactory_, yield); [&]() { ASSERT_TRUE(expectedWsConnection.has_value()) << expectedWsConnection.error().message(); }(); auto connection = std::move(expectedWsConnection).value(); auto wsConnectionPtr = dynamic_cast(connection.release());