2023-12-10 23:23:15 +00:00
|
|
|
// SPDX-FileCopyrightText: 2023 Yury Gubich <blue@macaw.me>
|
|
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
|
2023-11-23 19:57:32 +00:00
|
|
|
#include "router.h"
|
|
|
|
|
2023-12-28 20:26:08 +00:00
|
|
|
#include "request/redirect.h"
|
|
|
|
|
2023-11-23 19:57:32 +00:00
|
|
|
Router::Router():
|
2023-12-13 20:33:11 +00:00
|
|
|
get(),
|
|
|
|
post()
|
|
|
|
{}
|
2023-11-23 19:57:32 +00:00
|
|
|
|
2023-12-13 20:33:11 +00:00
|
|
|
void Router::addRoute(Handler handler) {
|
|
|
|
std::pair<std::map<std::string, Handler>::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));
|
|
|
|
}
|
2023-11-23 19:57:32 +00:00
|
|
|
|
|
|
|
if (!result.second)
|
2023-12-13 20:33:11 +00:00
|
|
|
throw std::runtime_error("could'not add route " + handler->path + " to the routing table");
|
2023-11-23 19:57:32 +00:00
|
|
|
}
|
|
|
|
|
2023-12-28 20:26:08 +00:00
|
|
|
void Router::route(std::unique_ptr<Request> request) {
|
2023-12-13 20:33:11 +00:00
|
|
|
std::map<std::string, Handler>::const_iterator itr, end;
|
|
|
|
switch (request->method()) {
|
|
|
|
case Request::Method::get:
|
2023-12-28 20:26:08 +00:00
|
|
|
itr = get.find(request->getPath());
|
2023-12-13 20:33:11 +00:00
|
|
|
end = get.end();
|
|
|
|
break;
|
|
|
|
case Request::Method::post:
|
2023-12-28 20:26:08 +00:00
|
|
|
itr = post.find(request->getPath());
|
2023-12-13 20:33:11 +00:00
|
|
|
end = post.end();
|
|
|
|
break;
|
|
|
|
default:
|
2023-12-28 20:26:08 +00:00
|
|
|
return handleMethodNotAllowed(std::move(request));
|
2023-12-13 20:33:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (itr == end)
|
2023-12-28 20:26:08 +00:00
|
|
|
return handleNotFound(std::move(request));
|
2023-11-23 19:57:32 +00:00
|
|
|
|
|
|
|
try {
|
2023-12-13 20:33:11 +00:00
|
|
|
itr->second->handle(*request.get());
|
|
|
|
|
|
|
|
if (request->currentState() != Request::State::responded)
|
2023-12-28 20:26:08 +00:00
|
|
|
handleInternalError(std::runtime_error("handler failed to handle the request"), std::move(request));
|
|
|
|
} catch (const Redirect& redirect) {
|
|
|
|
redirect.destination->accept(std::move(request));
|
2023-11-23 19:57:32 +00:00
|
|
|
} catch (const std::exception& e) {
|
2023-12-28 20:26:08 +00:00
|
|
|
handleInternalError(e, std::move(request));
|
2023-11-23 19:57:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-28 20:26:08 +00:00
|
|
|
void Router::handleNotFound(std::unique_ptr<Request> request) {
|
2023-12-22 23:25:20 +00:00
|
|
|
Response& notFound = request->createResponse(Response::Status::notFound);
|
2023-12-28 20:26:08 +00:00
|
|
|
std::string path = request->getPath();
|
2023-11-23 19:57:32 +00:00
|
|
|
notFound.setBody(std::string("Path \"") + path + "\" was not found");
|
2023-12-13 20:33:11 +00:00
|
|
|
notFound.send();
|
2023-12-22 23:25:20 +00:00
|
|
|
std::cerr << notFound.statusCode() << '\t' << request->methodName() << '\t' << path << std::endl;
|
2023-11-23 19:57:32 +00:00
|
|
|
}
|
|
|
|
|
2023-12-28 20:26:08 +00:00
|
|
|
void Router::handleInternalError(const std::exception& exception, std::unique_ptr<Request> request) {
|
2023-12-22 23:25:20 +00:00
|
|
|
Response& error = request->createResponse(Response::Status::internalError);
|
2023-11-23 19:57:32 +00:00
|
|
|
error.setBody(std::string(exception.what()));
|
2023-12-13 20:33:11 +00:00
|
|
|
error.send();
|
2023-12-28 20:26:08 +00:00
|
|
|
std::cerr << error.statusCode() << '\t' << request->methodName() << '\t' << request->getPath() << std::endl;
|
2023-12-13 20:33:11 +00:00
|
|
|
}
|
|
|
|
|
2023-12-28 20:26:08 +00:00
|
|
|
void Router::handleMethodNotAllowed(std::unique_ptr<Request> request) {
|
2023-12-22 23:25:20 +00:00
|
|
|
Response& error = request->createResponse(Response::Status::methodNotAllowed);
|
2023-12-13 20:33:11 +00:00
|
|
|
error.setBody(std::string("Method not allowed"));
|
|
|
|
error.send();
|
2023-12-28 20:26:08 +00:00
|
|
|
std::cerr << error.statusCode() << '\t' << request->methodName() << '\t' << request->getPath() << std::endl;
|
2023-11-23 19:57:32 +00:00
|
|
|
}
|