//SPDX-FileCopyrightText: 2023 Yury Gubich //SPDX-License-Identifier: GPL-3.0-or-later #include "router.h" #include "request/redirect.h" Router::Router(): get(), post() {} void Router::addRoute(Handler handler) { std::pair::const_iterator, bool> result; switch (handler->method) { case Request::Method::get: result = get.emplace(handler->path, std::move(handler)); break; case Request::Method::post: result = post.emplace(handler->path, std::move(handler)); break; default: throw std::runtime_error("An attempt to register handler with unsupported method type: " + std::to_string((int)handler->method)); } if (!result.second) throw std::runtime_error("could'not add route " + handler->path + " to the routing table"); } void Router::route(std::unique_ptr request) { std::map::const_iterator itr, end; switch (request->method()) { case Request::Method::get: itr = get.find(request->getPath()); end = get.end(); break; case Request::Method::post: itr = post.find(request->getPath()); end = post.end(); break; default: return handleMethodNotAllowed(std::move(request)); } if (itr == end) return handleNotFound(std::move(request)); try { itr->second->handle(*request.get()); if (request->currentState() != Request::State::responded) handleInternalError(std::runtime_error("handler failed to handle the request"), std::move(request)); } catch (const Redirect& redirect) { redirect.destination->accept(std::move(request)); } catch (const std::exception& e) { handleInternalError(e, std::move(request)); } } void Router::handleNotFound(std::unique_ptr request) { Response& notFound = request->createResponse(Response::Status::notFound); std::string path = request->getPath(); notFound.setBody(std::string("Path \"") + path + "\" was not found"); notFound.send(); std::cerr << notFound.statusCode() << '\t' << request->methodName() << '\t' << path << std::endl; } void Router::handleInternalError(const std::exception& exception, std::unique_ptr request) { Response& error = request->createResponse(Response::Status::internalError); error.setBody(std::string(exception.what())); error.send(); std::cerr << error.statusCode() << '\t' << request->methodName() << '\t' << request->getPath() << std::endl; } void Router::handleMethodNotAllowed(std::unique_ptr request) { Response& error = request->createResponse(Response::Status::methodNotAllowed); error.setBody(std::string("Method not allowed")); error.send(); std::cerr << error.statusCode() << '\t' << request->methodName() << '\t' << request->getPath() << std::endl; }