diff options
| author | Shauren <shauren.trinity@gmail.com> | 2025-04-08 19:15:16 +0200 |
|---|---|---|
| committer | Ovahlord <dreadkiller@gmx.de> | 2025-04-08 19:57:45 +0200 |
| commit | 4aa991e7e4450232df4ceda0b2f439bccce1d260 (patch) | |
| tree | 6ba65344105e100dd29da50cb667a53c465252a7 /src/server/bnetserver/REST/LoginHttpSession.cpp | |
| parent | a28b2999b1b500185aeecf343c3b1e14a39c26cf (diff) | |
Core/Network: Socket refactors
* Devirtualize calls to Read and Update by marking concrete implementations as final
* Removed derived class template argument
* Specialize boost::asio::basic_stream_socket for boost::asio::io_context instead of type-erased any_io_executor
* Make socket initialization easier composable (before entering Read loop)
* Remove use of deprecated boost::asio::null_buffers and boost::beast::ssl_stream
(cherry picked from commit e8b2be3527c7683e8bfca70ed7706fc20da566fd)
Diffstat (limited to 'src/server/bnetserver/REST/LoginHttpSession.cpp')
| -rw-r--r-- | src/server/bnetserver/REST/LoginHttpSession.cpp | 169 |
1 files changed, 80 insertions, 89 deletions
diff --git a/src/server/bnetserver/REST/LoginHttpSession.cpp b/src/server/bnetserver/REST/LoginHttpSession.cpp index aff579de7f9..23a317d3726 100644 --- a/src/server/bnetserver/REST/LoginHttpSession.cpp +++ b/src/server/bnetserver/REST/LoginHttpSession.cpp @@ -17,126 +17,117 @@ #include "LoginHttpSession.h" #include "DatabaseEnv.h" +#include "HttpSocket.h" +#include "HttpSslSocket.h" +#include "IpBanCheckConnectionInitializer.h" #include "LoginRESTService.h" #include "SslContext.h" #include "Util.h" +#include <boost/container/static_vector.hpp> -namespace Battlenet -{ -template<template<typename> typename SocketImpl> -LoginHttpSession<SocketImpl>::LoginHttpSession(boost::asio::ip::tcp::socket&& socket, LoginHttpSessionWrapper& owner) - : BaseSocket(std::move(socket), SslContext::instance()), _owner(owner) -{ -} - -template<template<typename> typename SocketImpl> -LoginHttpSession<SocketImpl>::~LoginHttpSession() = default; - -template<template<typename> typename SocketImpl> -void LoginHttpSession<SocketImpl>::Start() -{ - std::string ip_address = this->GetRemoteIpAddress().to_string(); - TC_LOG_TRACE("server.http.session", "{} Accepted connection", this->GetClientInfo()); - - // Verify that this IP is not in the ip_banned table - LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS)); - - LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_INFO); - stmt->setString(0, ip_address); - - this->_queryProcessor.AddCallback(LoginDatabase.AsyncQuery(stmt) - .WithPreparedCallback([sess = this->shared_from_this()](PreparedQueryResult result) { sess->CheckIpCallback(std::move(result)); })); -} - -template<template<typename> typename SocketImpl> -void LoginHttpSession<SocketImpl>::CheckIpCallback(PreparedQueryResult result) -{ - if (result) - { - bool banned = false; - do - { - Field* fields = result->Fetch(); - if (fields[0].GetUInt64() != 0) - banned = true; - - } while (result->NextRow()); - - if (banned) - { - TC_LOG_DEBUG("server.http.session", "{} tries to log in using banned IP!", this->GetClientInfo()); - this->CloseSocket(); - return; - } - } - - if constexpr (std::is_same_v<BaseSocket, Trinity::Net::Http::SslSocket<LoginHttpSession<Trinity::Net::Http::SslSocket>>>) - { - this->AsyncHandshake(); - } - else - { - this->ResetHttpParser(); - this->AsyncRead(); - } -} - -template<template<typename> typename SocketImpl> -Trinity::Net::Http::RequestHandlerResult LoginHttpSession<SocketImpl>::RequestHandler(Trinity::Net::Http::RequestContext& context) +namespace { - return sLoginService.HandleRequest(_owner.shared_from_this(), context); -} - std::shared_ptr<Trinity::Net::Http::SessionState> ObtainSessionState(Trinity::Net::Http::RequestContext& context, boost::asio::ip::address const& remoteAddress) { using namespace std::string_literals; - std::shared_ptr<Trinity::Net::Http::SessionState> state; - auto cookieItr = context.request.find(boost::beast::http::field::cookie); if (cookieItr != context.request.end()) { std::vector<std::string_view> cookies = Trinity::Tokenize(Trinity::Net::Http::ToStdStringView(cookieItr->value()), ';', false); - std::size_t eq = 0; - auto sessionIdItr = std::find_if(cookies.begin(), cookies.end(), [&](std::string_view cookie) + auto sessionIdItr = std::ranges::find_if(cookies, [](std::string_view const& cookie) { - std::string_view name = cookie; - eq = cookie.find('='); - if (eq != std::string_view::npos) - name = cookie.substr(0, eq); - - return name == LoginHttpSessionWrapper::SESSION_ID_COOKIE; + return cookie.length() > Battlenet::LoginHttpSession::SESSION_ID_COOKIE.length() + && cookie.starts_with(Battlenet::LoginHttpSession::SESSION_ID_COOKIE); }); if (sessionIdItr != cookies.end()) { - std::string_view value = sessionIdItr->substr(eq + 1); - state = sLoginService.FindAndRefreshSessionState(value, remoteAddress); + sessionIdItr->remove_prefix(Battlenet::LoginHttpSession::SESSION_ID_COOKIE.length()); + state = sLoginService.FindAndRefreshSessionState(*sessionIdItr, remoteAddress); } } - if (!state) { state = sLoginService.CreateNewSessionState(remoteAddress); std::string_view host = Trinity::Net::Http::ToStdStringView(context.request[boost::beast::http::field::host]); - if (std::size_t port = host.find(':'); port != std::string_view::npos) + if (size_t port = host.find(':'); port != std::string_view::npos) host.remove_suffix(host.length() - port); - context.response.insert(boost::beast::http::field::set_cookie, Trinity::StringFormat("{}={}; Path=/bnetserver; Domain={}; Secure; HttpOnly; SameSite=None", - LoginHttpSessionWrapper::SESSION_ID_COOKIE, boost::uuids::to_string(state->Id), host)); + context.response.insert(boost::beast::http::field::set_cookie, Trinity::StringFormat("{}{}; Path=/bnetserver; Domain={}; Secure; HttpOnly; SameSite=None", + Battlenet::LoginHttpSession::SESSION_ID_COOKIE, boost::uuids::to_string(state->Id), host)); } - return state; } -template class LoginHttpSession<Trinity::Net::Http::SslSocket>; -template class LoginHttpSession<Trinity::Net::Http::Socket>; +template<typename SocketImpl> +class LoginHttpSocketImpl final : public SocketImpl +{ +public: + using BaseSocket = SocketImpl; + + explicit LoginHttpSocketImpl(Trinity::Net::IoContextTcpSocket&& socket, Battlenet::LoginHttpSession& owner) + : BaseSocket(std::move(socket)), _owner(owner) + { + } + + LoginHttpSocketImpl(LoginHttpSocketImpl const&) = delete; + LoginHttpSocketImpl(LoginHttpSocketImpl&&) = delete; + LoginHttpSocketImpl& operator=(LoginHttpSocketImpl const&) = delete; + LoginHttpSocketImpl& operator=(LoginHttpSocketImpl&&) = delete; + + ~LoginHttpSocketImpl() = default; + + void Start() override + { + // build initializer chain + boost::container::static_vector<std::shared_ptr<Trinity::Net::SocketConnectionInitializer>, 4> initializers; + + initializers.stable_emplace_back(std::make_shared<Trinity::Net::IpBanCheckConnectionInitializer<BaseSocket>>(this)); + + if constexpr (std::is_same_v<BaseSocket, Trinity::Net::Http::SslSocket>) + initializers.stable_emplace_back(std::make_shared<Trinity::Net::SslHandshakeConnectionInitializer<BaseSocket>>(this)); + + initializers.stable_emplace_back(std::make_shared<Trinity::Net::Http::HttpConnectionInitializer<BaseSocket>>(this)); + initializers.stable_emplace_back(std::make_shared<Trinity::Net::ReadConnectionInitializer<BaseSocket>>(this)); + + Trinity::Net::SocketConnectionInitializer::SetupChain(std::span(initializers.data(), initializers.size()))->Start(); + } + + Trinity::Net::Http::RequestHandlerResult RequestHandler(Trinity::Net::Http::RequestContext& context) override + { + return sLoginService.HandleRequest(_owner.shared_from_this(), context); + } + +protected: + std::shared_ptr<Trinity::Net::Http::SessionState> ObtainSessionState(Trinity::Net::Http::RequestContext& context) const override + { + return ::ObtainSessionState(context, this->GetRemoteIpAddress()); + } + + Battlenet::LoginHttpSession& _owner; +}; + +template<> +LoginHttpSocketImpl<Trinity::Net::Http::SslSocket>::LoginHttpSocketImpl(Trinity::Net::IoContextTcpSocket&& socket, Battlenet::LoginHttpSession& owner) + : BaseSocket(std::move(socket), Battlenet::SslContext::instance()), _owner(owner) +{ +} +} + +namespace Battlenet +{ +LoginHttpSession::LoginHttpSession(Trinity::Net::IoContextTcpSocket&& socket) + : _socket(!SslContext::UsesDevWildcardCertificate() + ? std::shared_ptr<AbstractSocket>(std::make_shared<LoginHttpSocketImpl<Trinity::Net::Http::SslSocket>>(std::move(socket), *this)) + : std::shared_ptr<AbstractSocket>(std::make_shared<LoginHttpSocketImpl<Trinity::Net::Http::Socket>>(std::move(socket), *this))) +{ +} -LoginHttpSessionWrapper::LoginHttpSessionWrapper(boost::asio::ip::tcp::socket&& socket) +void LoginHttpSession::Start() { - if (!SslContext::UsesDevWildcardCertificate()) - _socket = std::make_shared<LoginHttpSession<Trinity::Net::Http::SslSocket>>(std::move(socket), *this); - else - _socket = std::make_shared<LoginHttpSession<Trinity::Net::Http::Socket>>(std::move(socket), *this); + TC_LOG_TRACE("server.http.session", "{} Accepted connection", GetClientInfo()); + + return _socket->Start(); } } |
