VWeb/Source/Router.cpp

97 lines
2.6 KiB
C++

#include "StringUtils.h"
#include <VWeb.h>
#include <type_traits>
namespace VWeb {
template <typename E> constexpr auto to_underlying(E e) noexcept {
return static_cast<std::underlying_type_t<E>>(e);
}
class ErrorRoute : public Route {
public:
bool Execute(const Request &request, Response &response) override {
response.Reset();
response << "Unhandled Error: Status "
<< std::to_string(to_underlying(response.Status));
response.SetType("text/plain");
return true;
}
};
Router::Router() { m_Routes["@"] = CreateRef<ErrorRoute>(); }
void Router::AddRoute(const std::string &name, const Ref<Route> &route) {
m_Routes[name] = route;
}
Ref<Route> &Router::GetRoute(const std::string &name) { return m_Routes[name]; }
void Router::DeleteRoute(const std::string &name) {
if (m_Routes.contains(name)) {
m_Routes.erase(name);
}
}
Ref<Response> Router::HandleRoute(Ref<Request> &request) {
auto response = CreateRef<Response>();
auto route = FindRoute(request);
response->CookieData = request->CookieData;
response->Method = request->Method;
if (!route) {
response->SetStatus(HttpStatusCode::NotFound);
m_Routes["@"]->Execute(*request, *response);
return response;
}
if (!route->IsAllowed(*request)) {
response->SetStatus(HttpStatusCode::Forbidden);
m_Routes["@"]->Execute(*request, *response);
return response;
}
if (!route->Execute(*request, *response)) {
std::string rKey = "@" + std::to_string(to_underlying(response->Status));
m_Routes.contains(rKey) ? m_Routes[rKey]->Execute(*request, *response)
: m_Routes["@"]->Execute(*request, *response);
}
return response;
}
Ref<Route> Router::FindRoute(Ref<Request> &request) {
auto &url = request->URI;
if (m_Routes.contains(url.data())) {
auto &route = m_Routes.at(url.data());
if (route->SupportsMethod(*request))
return route;
}
if (url.starts_with("@"))
return nullptr;
auto split = String::Split(url.data(), "/");
if (split.size() > 1) {
AddToArgs(request, split);
while (split.size() > 1) {
std::string nUrl = String::Join(split, "/");
if (m_Routes.contains(nUrl)) {
auto &route = m_Routes[nUrl];
if (route->SupportsMethod(*request))
return route;
}
AddToArgs(request, split);
}
}
if (m_Routes.contains("/")) {
auto &route = m_Routes["/"];
if (route->SupportsMethod(*request))
return route;
}
return nullptr;
}
void Router::AddToArgs(Ref<Request> &request, Vector<std::string> &items) {
request->URLParameters.push_back(items[items.size() - 1]);
items.pop_back();
}
} // namespace VWeb