#include "StringUtils.h" #include #include namespace VWeb { template constexpr auto to_underlying(E e) noexcept { return static_cast>(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(); } void Router::AddRoute(const std::string &name, const Ref &route) { m_Routes[name] = route; } Ref &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 Router::HandleRoute(Ref &request) { auto response = CreateRef(); 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 Router::FindRoute(Ref &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, Vector &items) { request->URLParameters.push_back(items[items.size() - 1]); items.pop_back(); } } // namespace VWeb