From c394535d715cd5e3b0843448afa981c8701d062b Mon Sep 17 00:00:00 2001 From: Ryan Date: Thu, 15 Jan 2026 08:46:12 +0100 Subject: [PATCH] Add support for parameter validators --- art/seafire/routing/match.cxx | 71 ++++++++++++++++++++++++--- art/seafire/routing/match.hxx | 7 +++ art/seafire/routing/router.cxx | 15 ++++-- art/seafire/routing/router.hxx | 7 ++- art/seafire/routing/routing-table.cxx | 10 ++-- art/seafire/routing/routing-table.hxx | 3 +- 6 files changed, 96 insertions(+), 17 deletions(-) diff --git a/art/seafire/routing/match.cxx b/art/seafire/routing/match.cxx index a726a03..e9a8481 100644 --- a/art/seafire/routing/match.cxx +++ b/art/seafire/routing/match.cxx @@ -1,14 +1,31 @@ #include #include +#include #include namespace art::seafire::routing { + static + std::vector + split(std::string const& str, char delim) + { + std::vector strings; + + std::stringstream input{str}; + + for (std::string line; std::getline(input, line, delim);) { + strings.emplace_back(std::move(line)); + } + + return strings; + } + bool match(std::string const& subject, std::string const& pattern, + validator_map_t const& validators, char delim, parameters_t& params) { @@ -24,7 +41,7 @@ namespace art::seafire::routing auto s = subject.begin(); auto const send = subject.end(); - auto match_param = [&]() + auto match_param = [&]() -> bool { // k/kend = local pattern iterators. // @@ -35,10 +52,6 @@ namespace art::seafire::routing auto const kend = p; ++p; - if (k == kend) { - throw std::invalid_argument{"empty parameter name"}; - } - // a greedy parameter will eat the rest of the subject. // bool const greedy{'*' == *k && 1 == std::distance(k, kend)}; @@ -51,13 +64,57 @@ namespace art::seafire::routing } auto const vend = s; - tmp_params.map().emplace(std::string{k, kend}, std::string{v, vend}); + std::string key{k, kend}; + std::string type; + + auto parts = split(key, ':'); + + if (parts.size() == 1) { + key = parts[0]; + } + else if (parts.size() == 2) { + key = parts[0]; + type = parts[1]; + + if (type.size() == 0) { + return false; + } + } + else { + return false; + } + + if (key.size() == 0) { + return false; + } + + std::string value{v, vend}; + + if (type.size() > 0) { + auto validator = validators.find(type); + + if (validator == validators.end()) { + return false; + } + + if (!validator->second(value)) { + return false; + } + } + + tmp_params.map().emplace(std::move(key), std::move(value)); + + return true; }; while (p != pend) { if (*p == '{') { ++p; - match_param(); + + if (!match_param()) { + return false; + } + continue; } diff --git a/art/seafire/routing/match.hxx b/art/seafire/routing/match.hxx index 625ae25..534ccac 100644 --- a/art/seafire/routing/match.hxx +++ b/art/seafire/routing/match.hxx @@ -3,14 +3,21 @@ #include +#include +#include #include namespace art::seafire::routing { + using validator_t = std::function; + + using validator_map_t = std::map; + bool match(std::string const&, std::string const&, + validator_map_t const&, char, parameters_t&); diff --git a/art/seafire/routing/router.cxx b/art/seafire/routing/router.cxx index 565f636..f71c0d5 100644 --- a/art/seafire/routing/router.cxx +++ b/art/seafire/routing/router.cxx @@ -43,10 +43,19 @@ namespace art::seafire::routing } router_t:: - router_t(common::diagnostics_t& diagnostics, routing_table_t table) - : diagnostics_{diagnostics}, rt_{std::move(table)} + router_t(common::diagnostics_t& diagnostics, + validator_map_t validators, + routing_table_t table) + : diagnostics_{diagnostics}, validators_{std::move(validators)}, rt_{std::move(table)} {} + validator_map_t const& + router_t:: + validators() const + { + return validators_; + } + routing_table_t const& router_t:: routing_table() const @@ -76,7 +85,7 @@ namespace art::seafire::routing << " -> path : " << path ; - auto result = routing_table().find_route(hostname, path); + auto result = routing_table().find_route(hostname, path, validators()); if (!result) { trace() << "endpoint for [" << path << "] not found"; diff --git a/art/seafire/routing/router.hxx b/art/seafire/routing/router.hxx index 8570459..f45d949 100644 --- a/art/seafire/routing/router.hxx +++ b/art/seafire/routing/router.hxx @@ -2,6 +2,7 @@ #define art__seafire__routing__router_hxx_ #include +#include #include #include @@ -15,7 +16,10 @@ namespace art::seafire::routing class router_t { public: - router_t(common::diagnostics_t&, routing_table_t); + router_t(common::diagnostics_t&, validator_map_t, routing_table_t); + + validator_map_t const& + validators() const; routing_table_t const& routing_table() const; @@ -31,6 +35,7 @@ namespace art::seafire::routing trace() const; common::diagnostics_t& diagnostics_; + validator_map_t validators_; routing_table_t rt_; }; diff --git a/art/seafire/routing/routing-table.cxx b/art/seafire/routing/routing-table.cxx index 994674b..5e542be 100644 --- a/art/seafire/routing/routing-table.cxx +++ b/art/seafire/routing/routing-table.cxx @@ -1,7 +1,5 @@ #include -#include - namespace art::seafire::routing { @@ -19,18 +17,20 @@ namespace art::seafire::routing std::optional routing_table_t:: - find_route(std::string const& host, std::string const& path) const + find_route(std::string const& host, + std::string const& path, + validator_map_t const& validators) const { for (auto const& e : endpoints()) { host_parameters_t host_params; - if (!match(host, e.host(), '.', host_params)) { + if (!match(host, e.host(), validators, '.', host_params)) { continue; } route_parameters_t route_params; - if (match(path, e.path(), '/', route_params)) { + if (match(path, e.path(), validators, '/', route_params)) { return find_result_t{ std::move(host_params), std::move(route_params), diff --git a/art/seafire/routing/routing-table.hxx b/art/seafire/routing/routing-table.hxx index 48a3f07..fff4e58 100644 --- a/art/seafire/routing/routing-table.hxx +++ b/art/seafire/routing/routing-table.hxx @@ -2,6 +2,7 @@ #define art__seafire__routing__routing_table_hxx_ #include +#include #include #include @@ -34,7 +35,7 @@ namespace art::seafire::routing endpoints() const; std::optional - find_route(std::string const&, std::string const&) const; + find_route(std::string const&, std::string const&, validator_map_t const&) const; private: static