22#include <boost/beast/version.hpp>
23#include <boost/uuid/string_generator.hpp>
24#include <boost/uuid/uuid_io.hpp>
25#include <fmt/chrono.h>
44 std::string_view path = [&]
47 size_t queryIndex = path.find(
'?');
48 if (queryIndex != std::string_view::npos)
49 path = path.substr(0, queryIndex);
53 context.
handler = [&]() -> HttpMethodHandlerMap::mapped_type
const*
55 switch (context.
request.method())
57 case boost::beast::http::verb::get:
58 case boost::beast::http::verb::head:
61 return itr !=
_getHandlers.end() ? &itr->second :
nullptr;
63 case boost::beast::http::verb::post:
76 context.
response.set(boost::beast::http::field::server, BOOST_BEAST_VERSION_STRING);
82 return context.
handler->
Func(std::move(session), context);
87 context.
response.result(boost::beast::http::status::bad_request);
93 context.
response.result(boost::beast::http::status::unauthorized);
99 context.
response.result(boost::beast::http::status::not_found);
111 case boost::beast::http::verb::get:
113 case boost::beast::http::verb::post:
117 std::string_view methodString =
ToStdStringView(boost::beast::http::to_string(method));
123 handlerMap[std::string(path)] = { .Func = std::move(handler), .Flags =
flags };
129 state->RemoteAddress = address;
135 while (state->Id.is_nil() ||
_sessions.contains(state->Id))
136 std::copy_n(Trinity::Crypto::GetRandomBytes<16>().begin(), 16, state->Id.begin());
138 TC_LOG_DEBUG(
_logger,
"Client at {} created new session {}", address, boost::uuids::to_string(state->Id));
171 std::shared_ptr<SessionState> state;
175 auto itr =
_sessions.find(boost::uuids::string_generator()(
id.begin(),
id.end()));
178 TC_LOG_DEBUG(
_logger,
"Client at {} attempted to use a session {} that was expired", address,
id);
185 if (state->RemoteAddress != address)
187 TC_LOG_ERROR(
_logger,
"Client at {} attempted to use a session {} that was last accessed from {}, denied access",
188 address,
id, state->RemoteAddress);
202 bool wasActive =
true;
214 itr->second->InactiveTimestamp = TimePoint::clock::now() +
Minutes(5);
222 std::set<boost::uuids::uuid> inactiveSessions;
231 std::size_t inactiveSessionsCount = inactiveSessions.size();
234 for (
auto itr = inactiveSessions.begin(); itr != inactiveSessions.end(); )
237 if (sessionItr ==
_sessions.end() || sessionItr->second->InactiveTimestamp < now)
240 itr = inactiveSessions.erase(itr);
246 TC_LOG_DEBUG(
_logger,
"Killed {} inactive sessions", inactiveSessionsCount - inactiveSessions.size());
252 for (
auto itr = inactiveSessions.begin(); itr != inactiveSessions.end(); )
254 auto node = inactiveSessions.extract(itr++);
#define STRING_VIEW_FMT_ARG(str)
std::chrono::system_clock::time_point SystemTimePoint
std::chrono::steady_clock::time_point TimePoint
time_point shorthand typedefs
std::chrono::minutes Minutes
Minutes shorthand typedef.
#define TC_LOG_DEBUG(filterType__, message__,...)
#define TC_LOG_ERROR(filterType__, message__,...)
#define TC_LOG_INFO(filterType__, message__,...)
#define TC_LOG_TRACE(filterType__, message__,...)
constexpr bool HasFlag(T flag) const
RequestHandlerResult HandleRequest(std::shared_ptr< AbstractSocket > session, RequestContext &context)
static RequestHandlerResult HandlePathNotFound(std::shared_ptr< AbstractSocket > session, RequestContext &context)
static RequestHandlerResult HandleUnauthorized(std::shared_ptr< AbstractSocket > session, RequestContext &context)
HttpMethodHandlerMap _getHandlers
HttpMethodHandlerMap _postHandlers
static RequestHandlerResult HandleBadRequest(std::shared_ptr< AbstractSocket > session, RequestContext &context)
void RegisterHandler(boost::beast::http::verb method, std::string_view path, std::function< RequestHandlerResult(std::shared_ptr< AbstractSocket > session, RequestContext &context)> handler, RequestHandlerFlag flags=RequestHandlerFlag::None)
std::map< std::string, RequestHandler, std::less<> > HttpMethodHandlerMap
std::map< boost::uuids::uuid, std::shared_ptr< SessionState > > _sessions
std::unique_ptr< Asio::DeadlineTimer > _inactiveSessionsKillTimer
std::set< boost::uuids::uuid > _inactiveSessions
void KillInactiveSessions()
std::shared_ptr< SessionState > FindAndRefreshSessionState(std::string_view id, boost::asio::ip::address const &address)
std::shared_mutex _sessionsMutex
void Start(Asio::IoContext &ioContext)
void InitAndStoreSessionState(std::shared_ptr< SessionState > state, boost::asio::ip::address const &address)
void MarkSessionInactive(boost::uuids::uuid const &id)
std::mutex _inactiveSessionsMutex
@ DoNotLogResponseContent
std::string_view ToStdStringView(boost::beast::string_view bsw)
TC_NETWORK_API bool CanLogResponseContent(RequestContext const &context)
TC_NETWORK_API bool CanLogRequestContent(RequestContext const &context)
Minutes GetSystemZoneOffsetAt(SystemTimePoint date)
std::string StringFormat(FormatString< Args... > fmt, Args &&... args) noexcept
Default TC string format function.
struct RequestHandler const * handler
std::function< RequestHandlerResult(std::shared_ptr< AbstractSocket > session, RequestContext &context)> Func
EnumFlag< RequestHandlerFlag > Flags