Files
UpAndDown/src/endpoints_handlers/RootExecutor.h
T
2025-10-04 15:25:55 +03:00

157 lines
5.1 KiB
C++

#include "IExecutor.h"
#include "IController.h"
#include "Controller.h"
#include "AuthRegistrationExecutor.h"
#include "./../helpers/helpers.h"
namespace uad
{
template <class Body, class Allocator, class ResponseType, class Send>
class RootExecutor
{
using IRouteExecutor = IExecutor<Body, Allocator, boost::beast::http::string_body>;
using RouteAuthRegistrationExecutor = AuthRegistrationExecutor<
Body, Allocator, boost::beast::http::string_body>;
using IRouteController = IController<Body, Allocator, boost::beast::http::string_body>;
using RouteController = Controller<Body, Allocator, boost::beast::http::string_body>;
using RoutesPathes = std::unordered_map<std::string, std::unique_ptr<IRouteController>>;
using Request = boost::beast::http::request<Body, boost::beast::http::basic_fields<Allocator>>;
using StringResponse = boost::beast::http::response<boost::beast::http::string_body>;
using EmptyResponse = boost::beast::http::response<boost::beast::http::empty_body>;
using FileResponse = boost::beast::http::response<boost::beast::http::file_body>;
private:
RoutesPathes routes_pathes_;
public:
RootExecutor()
{
routes_pathes_["/api/v1/Auth/Register"] = std::make_unique<RouteController>(
typename RouteController::HTTPMethodsToExecutors{
{boost::beast::http::verb::get, std::make_shared<RouteAuthRegistrationExecutor>()}
}
);
}
void operator ()(
boost::beast::string_view doc_root,
Request&& req,
Send&& send
)
{
const std::string& route = req.target();
const bool is_match_route = routes_pathes_.count(route);
if (is_match_route)
{
std::optional<std::shared_ptr<IRouteExecutor>> maybe_executor_ptr = routes_pathes_
.at(route)
->FindExecutor(req.method());
if (maybe_executor_ptr.has_value())
{
IRouteExecutor& executor = *maybe_executor_ptr.value();
return send(executor(std::move(req)));
}
}
if (req.method() != boost::beast::http::verb::get &&
req.method() != boost::beast::http::verb::head)
return send(SendBadRequest(std::move(req), "Unknown boost::beast::HTTP-method"));
if (req.target().empty() || req.target()[0] != '/' ||
req.target().find("..") != boost::beast::string_view::npos)
return send(SendBadRequest(std::move(req), "Illegal request-target"));
std::string path = PathCat(doc_root, req.target());
if (req.target().back() == '/')
path.append("index.html");
boost::beast::error_code ec;
boost::beast::http::file_body::value_type body;
body.open(path.c_str(), boost::beast::file_mode::scan, ec);
if (ec == boost::beast::errc::no_such_file_or_directory)
return send(SendNotFound(std::move(req),req.target()));
if (ec)
return send(SendServerError(std::move(req), ec.message()));
auto const size = body.size();
if (req.method() == boost::beast::http::verb::head)
{
EmptyResponse res{
boost::beast::http::status::ok,
req.version()
};
res.set(boost::beast::http::field::server, BOOST_BEAST_VERSION_STRING);
res.set(boost::beast::http::field::content_type, MimeType(path));
res.content_length(size);
res.keep_alive(req.keep_alive());
return send(std::move(res));
}
FileResponse res{
std::piecewise_construct, std::make_tuple(std::move(body)),
std::make_tuple(boost::beast::http::status::ok, req.version())
};
res.set(boost::beast::http::field::server, BOOST_BEAST_VERSION_STRING);
res.set(boost::beast::http::field::content_type, MimeType(path));
res.content_length(size);
res.keep_alive(req.keep_alive());
return send(std::move(res));
}
private:
StringResponse SendBadRequest(
Request&& req,
boost::beast::string_view why
)
{
StringResponse res{
boost::beast::http::status::bad_request, req.version()
};
res.set(boost::beast::http::field::server, BOOST_BEAST_VERSION_STRING);
res.set(boost::beast::http::field::content_type, "text/html");
res.keep_alive(req.keep_alive());
res.body() = std::string(why);
res.prepare_payload();
return res;
}
StringResponse SendNotFound(
Request&& req,
boost::beast::string_view target
)
{
StringResponse res{
boost::beast::http::status::not_found, req.version()
};
res.set(boost::beast::http::field::server, BOOST_BEAST_VERSION_STRING);
res.set(boost::beast::http::field::content_type, "text/html");
res.keep_alive(req.keep_alive());
res.body() = "The resource '" + std::string(target) + "' was not found.";
res.prepare_payload();
return res;
}
StringResponse SendServerError(
Request&& req,
boost::beast::string_view what
)
{
StringResponse res{
boost::beast::http::status::internal_server_error, req.version()
};
res.set(boost::beast::http::field::server, BOOST_BEAST_VERSION_STRING);
res.set(boost::beast::http::field::content_type, "text/html");
res.keep_alive(req.keep_alive());
res.body() = "An error occurred: '" + std::string(what) + "'";
res.prepare_payload();
return res;
}
};
}