121 lines
2.7 KiB
C++

#include <seafire/routing/router.hxx>
#include <seafire/routing/diagnostics.hxx>
#include <seafire/protocol/rfc7230/host.hxx>
namespace seafire::routing
{
static
std::string
normalize_path(std::string const& path)
{
std::stringstream ipath{path};
std::vector<std::string> segments;
for (std::string segment; std::getline(ipath, segment, '/');) {
if (segment.empty()) {
continue;
}
if (segment == ".") {
continue;
}
if (segment == "..") {
if (!segments.empty()) {
segments.pop_back();
}
continue;
}
segments.push_back(segment);
}
std::string normalized;
for (auto const& j : segments) {
normalized += '/';
normalized += j;
}
return normalized.empty() ? "/" : normalized;
}
router_t::
router_t(common::diagnostics_t& diagnostics, routing_table_t table)
: diagnostics_{diagnostics}, rt_{std::move(table)}
{}
routing_table_t const&
router_t::
routing_table() const
{
return rt_;
}
void
router_t::
on_request(server::request_t& req, server::response_t& res) const
{
trace() << "on_request(...)";
auto host = get<seafire::protocol::rfc7230::host_t>(req);
if (!host) {
trace() << "host not present on request!";
res.send(server::common_error_t::not_found);
return;
}
auto hostname = host->hostname();
auto path = normalize_path(req.get_message().target_uri().path_str());
trace() << "locating endpoint:\n"
<< " -> hostname: " << hostname << '\n'
<< " -> path : " << path
;
auto result = routing_table().find_route(hostname, path);
if (!result) {
trace() << "endpoint for [" << path << "] not found";
res.send(server::common_error_t::not_found);
return;
}
auto trace_endpoint = [&result](common::diagnostics_t::proxy_t proxy)
{
proxy << "endpoint found!";
for (auto const& j : result->host_params.map())
proxy << "\n -> host param : " << j.first << " = " << j.second << '\n';
for (auto const& j : result->route_params.map())
proxy << "\n -> route param: " << j.first << " = " << j.second << '\n';
};
trace_endpoint(trace());
req.extensions().extend(&res.memory().alloc(result->host_params));
req.extensions().extend(&res.memory().alloc(result->route_params));
result->handler.invoke(req, res);
}
void
router_t::
operator()(server::request_t& req, server::response_t& res) const
{
on_request(req, res);
}
common::diagnostics_t::proxy_t
router_t::
trace() const
{
return diagnostics_ << routing_category();
}
} // namespace seafire::routing