From 669a54a17b248de602ebccbab0eb4a02c8952971 Mon Sep 17 00:00:00 2001 From: Ryan Date: Fri, 7 Mar 2025 22:13:09 +0100 Subject: [PATCH 1/2] Implement virtual host routing --- seafire/routing/builder.cxx | 43 ++++++++ seafire/routing/builder.hxx | 42 ++++++++ seafire/routing/endpoint.cxx | 21 +++- seafire/routing/endpoint.hxx | 10 +- seafire/routing/flatten-route.cxx | 50 --------- seafire/routing/flatten-route.hxx | 28 ----- seafire/routing/flatten.cxx | 55 ++++++++++ seafire/routing/flatten.hxx | 32 ++++++ seafire/routing/host-parameter.hxx | 68 ++++++++++++ seafire/routing/match-path.hxx | 24 ----- seafire/routing/{match-path.cxx => match.cxx} | 17 ++- seafire/routing/match.hxx | 22 ++++ .../{route-parameters.cxx => parameters.cxx} | 16 +-- seafire/routing/parameters.hxx | 56 ++++++++++ seafire/routing/route-parameter.hxx | 2 +- seafire/routing/route-parameters.hxx | 30 ------ seafire/routing/route.cxx | 35 +++--- seafire/routing/route.hxx | 9 +- seafire/routing/router.cxx | 30 ++++-- seafire/routing/routing-table.cxx | 74 +++---------- seafire/routing/routing-table.hxx | 46 ++------ seafire/routing/virtual-host.cxx | 100 ++++++++++++++++++ seafire/routing/virtual-host.hxx | 65 ++++++++++++ 23 files changed, 593 insertions(+), 282 deletions(-) create mode 100644 seafire/routing/builder.cxx create mode 100644 seafire/routing/builder.hxx delete mode 100644 seafire/routing/flatten-route.cxx delete mode 100644 seafire/routing/flatten-route.hxx create mode 100644 seafire/routing/flatten.cxx create mode 100644 seafire/routing/flatten.hxx create mode 100644 seafire/routing/host-parameter.hxx delete mode 100644 seafire/routing/match-path.hxx rename seafire/routing/{match-path.cxx => match.cxx} (83%) create mode 100644 seafire/routing/match.hxx rename seafire/routing/{route-parameters.cxx => parameters.cxx} (54%) create mode 100644 seafire/routing/parameters.hxx delete mode 100644 seafire/routing/route-parameters.hxx create mode 100644 seafire/routing/virtual-host.cxx create mode 100644 seafire/routing/virtual-host.hxx diff --git a/seafire/routing/builder.cxx b/seafire/routing/builder.cxx new file mode 100644 index 0000000..a73db5f --- /dev/null +++ b/seafire/routing/builder.cxx @@ -0,0 +1,43 @@ +#include +#include + +#include + +namespace seafire::routing +{ + + builder_t:: + builder_t() + {} + + std::list const& + builder_t:: + virtual_hosts() const + { + return _vhosts; + } + + virtual_host_t& + builder_t:: + add_virtual_host(std::string vhost) + { + _vhosts.emplace_back(std::move(vhost)); + return _vhosts.back(); + } + + routing_table_t + builder_t:: + build() const + { + std::vector endpoints; + + for (auto const& vhost : _vhosts) { + for (auto const& r : vhost.routes()) { + flatten(endpoints, vhost.host(), vhost.middleware(), r); + } + } + + return routing_table_t{std::move(endpoints)}; + } + +} // namespace seafire::routing diff --git a/seafire/routing/builder.hxx b/seafire/routing/builder.hxx new file mode 100644 index 0000000..a3f3c57 --- /dev/null +++ b/seafire/routing/builder.hxx @@ -0,0 +1,42 @@ +#ifndef seafire__routing__builder_hxx_ +#define seafire__routing__builder_hxx_ + +#include +#include + +#include + +#include +#include + +namespace seafire::routing +{ + + class builder_t + { + public: + builder_t(); + + builder_t(builder_t const&) = delete; + builder_t(builder_t&&) = delete; + + std::list const& + virtual_hosts() const; + + virtual_host_t& + add_virtual_host(std::string); + + routing_table_t + build() const; + + builder_t& operator=(builder_t const&) = delete; + builder_t& operator=(builder_t&&) = delete; + + private: + std::list _vhosts; + + }; + +} // namespace seafire::routing + +#endif diff --git a/seafire/routing/endpoint.cxx b/seafire/routing/endpoint.cxx index e655619..6c6a6d9 100644 --- a/seafire/routing/endpoint.cxx +++ b/seafire/routing/endpoint.cxx @@ -4,15 +4,26 @@ namespace seafire::routing { endpoint_t:: - endpoint_t(std::string pattern, server::request_handler_t handler) - : pattern_{std::move(pattern)}, handler_{std::move(handler)} + endpoint_t(std::string host, + std::string path, + server::request_handler_t handler) + : host_{std::move(host)}, + path_{std::move(path)}, + handler_{std::move(handler)} {} std::string const& endpoint_t:: - pattern() const + host() const { - return pattern_; + return host_; + } + + std::string const& + endpoint_t:: + path() const + { + return path_; } server::request_handler_t const& @@ -25,7 +36,7 @@ namespace seafire::routing std::ostream& to_stream(std::ostream& o, endpoint_t const& ep) { - return o << ep.pattern(); + return o << ep.host() << ": " << ep.path(); } std::ostream& diff --git a/seafire/routing/endpoint.hxx b/seafire/routing/endpoint.hxx index 2d7f919..44d5fc4 100644 --- a/seafire/routing/endpoint.hxx +++ b/seafire/routing/endpoint.hxx @@ -12,16 +12,20 @@ namespace seafire::routing class endpoint_t { public: - endpoint_t(std::string, server::request_handler_t); + endpoint_t(std::string, std::string, server::request_handler_t); std::string const& - pattern() const; + host() const; + + std::string const& + path() const; server::request_handler_t const& handler() const; private: - std::string pattern_; + std::string host_; + std::string path_; server::request_handler_t handler_; }; diff --git a/seafire/routing/flatten-route.cxx b/seafire/routing/flatten-route.cxx deleted file mode 100644 index 87f85a8..0000000 --- a/seafire/routing/flatten-route.cxx +++ /dev/null @@ -1,50 +0,0 @@ -#include - -namespace seafire::routing -{ - - void - flatten_route(std::vector& endpoints, - std::vector middlewares, - route_t const& route, - std::string const& root) - { - auto const path = root + route.path(); - - // append any middlewares if we have any. - // - for (auto const& m : route.middleware()) { - middlewares.emplace_back(m); - } - - // generate an endpoint for this route if we have a handler. - // - if (auto const& h = route.handler()) { - endpoints.emplace_back(path, server::make_middleware(middlewares, *h)); - } - - // flatten any child routes. - // - for (auto const& child_route : route.children()) { - flatten_route(endpoints, - middlewares, - child_route, - route.path().empty() ? path : path + '/'); - } - } - - void - flatten_route(std::vector& endpoints, route_t const& r) - { - flatten_route(endpoints, {}, r, "/"); - } - - std::vector - flatten_route(route_t const& r) - { - std::vector endpoints; - flatten_route(endpoints, r); - return endpoints; - } - -} // namespace seafire::routing diff --git a/seafire/routing/flatten-route.hxx b/seafire/routing/flatten-route.hxx deleted file mode 100644 index ba6753c..0000000 --- a/seafire/routing/flatten-route.hxx +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef seafire__routing__flatten_route_hxx_ -#define seafire__routing__flatten_route_hxx_ - -#include -#include - -#include - -#include - -namespace seafire::routing -{ - - void - flatten_route(std::vector& endpoints, - std::vector, - route_t const& r, - std::string const& root); - - void - flatten_route(std::vector&, route_t const&); - - std::vector - flatten_route(route_t const&); - -} // namespace seafire::routing - -#endif diff --git a/seafire/routing/flatten.cxx b/seafire/routing/flatten.cxx new file mode 100644 index 0000000..fa24ec8 --- /dev/null +++ b/seafire/routing/flatten.cxx @@ -0,0 +1,55 @@ +#include + +namespace seafire::routing +{ + + void + flatten(std::vector& endpoints, + std::string const& vhost, + std::vector middlewares, + route_t const& route, + std::string const& root) + { + auto const path = root + route.path(); + + // append any middlewares if we have any. + // + for (auto const& m : route.middleware()) { + middlewares.emplace_back(m); + } + + // generate an endpoint for this route if we have a handler. + // + if (auto const& h = route.handler()) { + endpoints.emplace_back(vhost, path, server::make_middleware(middlewares, *h)); + } + + // flatten any child routes. + // + for (auto const& child_route : route.children()) { + flatten(endpoints, + vhost, + middlewares, + child_route, + route.path().empty() ? path : path + '/'); + } + } + + void + flatten(std::vector& endpoints, + std::string const& vhost, + std::vector middlewares, + route_t const& r) + { + flatten(endpoints, vhost, middlewares, r, "/"); + } + + std::vector + flatten(std::string const& vhost, route_t const& r) + { + std::vector endpoints; + flatten(endpoints, vhost, {}, r); + return endpoints; + } + +} // namespace seafire::routing diff --git a/seafire/routing/flatten.hxx b/seafire/routing/flatten.hxx new file mode 100644 index 0000000..ca77ca5 --- /dev/null +++ b/seafire/routing/flatten.hxx @@ -0,0 +1,32 @@ +#ifndef seafire__routing__flatten_route_hxx_ +#define seafire__routing__flatten_route_hxx_ + +#include +#include + +#include + +#include + +namespace seafire::routing +{ + + void + flatten(std::vector& endpoints, + std::string const&, + std::vector, + route_t const& r, + std::string const& root); + + void + flatten(std::vector&, + std::string const&, + std::vector, + route_t const&); + + std::vector + flatten(std::string const&, route_t const&); + +} // namespace seafire::routing + +#endif diff --git a/seafire/routing/host-parameter.hxx b/seafire/routing/host-parameter.hxx new file mode 100644 index 0000000..6cd87a7 --- /dev/null +++ b/seafire/routing/host-parameter.hxx @@ -0,0 +1,68 @@ +#ifndef seafire__routing__host_parameter_hxx_ +#define seafire__routing__host_parameter_hxx_ + +#include +#include + +#include + +#include + +namespace seafire::routing +{ + + template< + server::parameter_name_t Name, + typename ParameterType = server::string_parameter_t + > + class host_parameter_t + { + public: + using parameter_type = ParameterType; + using value_type = typename parameter_type::value_type; + + static + std::string const& + name() + { + static std::string const name{Name}; + return name; + } + + host_parameter_t(std::optional value) + : _value{std::move(value)} + {} + + std::optional const& + value() const + { + return _value; + } + + operator std::optional const&() const + { + return value(); + } + + std::optional const* + operator->() const + { + return &value(); + } + + static + host_parameter_t + fetch(server::request_t& req) + { + auto v = req.extensions().use().get(name()); + return parameter_type::try_parse(v); + } + + private: + std::optional _value; + + }; + +} // namespace seafire::routing + +#endif diff --git a/seafire/routing/match-path.hxx b/seafire/routing/match-path.hxx deleted file mode 100644 index 015f69a..0000000 --- a/seafire/routing/match-path.hxx +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef seafire__routing__match_path_hxx_ -#define seafire__routing__match_path_hxx_ - -#include - -#include - -#include - -namespace seafire::routing -{ - - bool - match_path(std::string const&, - std::string const&, - route_parameters_t&); - - std::string - render_path(std::string const&, - route_parameters_t&); - -} // namespace seafire::routing - -#endif diff --git a/seafire/routing/match-path.cxx b/seafire/routing/match.cxx similarity index 83% rename from seafire/routing/match-path.cxx rename to seafire/routing/match.cxx index c8cb625..20881ca 100644 --- a/seafire/routing/match-path.cxx +++ b/seafire/routing/match.cxx @@ -1,18 +1,18 @@ -#include +#include #include #include -#include namespace seafire::routing { bool - match_path(std::string const& pattern, - std::string const& subject, - route_parameters_t& params) + match(std::string const& subject, + std::string const& pattern, + char delim, + parameters_t& params) { - route_parameters_t tmp_params; + parameters_t tmp_params; // p/pend = pattern iterators. // @@ -46,7 +46,7 @@ namespace seafire::routing // v/vend = local subject iterators. // auto const v = s; - while (s != send && (greedy || '/' != *s)) { + while (s != send && (greedy || delim != *s)) { ++s; } auto const vend = s; @@ -83,8 +83,7 @@ namespace seafire::routing } std::string - render_path(std::string const& pattern, - route_parameters_t const& params) + render(std::string const& pattern, parameters_t& params) { std::stringstream str; diff --git a/seafire/routing/match.hxx b/seafire/routing/match.hxx new file mode 100644 index 0000000..a30ff8c --- /dev/null +++ b/seafire/routing/match.hxx @@ -0,0 +1,22 @@ +#ifndef seafire__routing__match_hxx_ +#define seafire__routing__match_hxx_ + +#include + +#include + +namespace seafire::routing +{ + + bool + match(std::string const&, + std::string const&, + char, + parameters_t&); + + std::string + render(std::string const&, parameters_t&); + +} // namespace seafire::routing + +#endif diff --git a/seafire/routing/route-parameters.cxx b/seafire/routing/parameters.cxx similarity index 54% rename from seafire/routing/route-parameters.cxx rename to seafire/routing/parameters.cxx index 696828f..bbe7d50 100644 --- a/seafire/routing/route-parameters.cxx +++ b/seafire/routing/parameters.cxx @@ -1,24 +1,24 @@ -#include +#include namespace seafire::routing { - std::map& - route_parameters_t:: + parameters_t::map_type& + parameters_t:: map() { - return kv_; + return _values; } - std::map const& - route_parameters_t:: + parameters_t::map_type const& + parameters_t:: map() const { - return kv_; + return _values; } std::optional - route_parameters_t:: + parameters_t:: get(std::string const& key) const { if (auto it = map().find(key); it != map().end()) diff --git a/seafire/routing/parameters.hxx b/seafire/routing/parameters.hxx new file mode 100644 index 0000000..77bb6dd --- /dev/null +++ b/seafire/routing/parameters.hxx @@ -0,0 +1,56 @@ +#ifndef seafire_routing__parameters_hxx_ +#define seafire_routing__parameters_hxx_ + +#include +#include +#include +#include + +namespace seafire::routing +{ + + class parameters_t + { + public: + using map_type = std::map; + + parameters_t() = default; + + parameters_t(map_type values) + : _values{std::move(values)} + {} + + map_type& + map(); + + map_type const& + map() const; + + std::optional + get(std::string const&) const; + + private: + map_type _values; + + }; + + class host_parameters_t + : public parameters_t + { + public: + using parameters_t::parameters_t; + + }; + + class route_parameters_t + : public parameters_t + { + public: + using parameters_t::parameters_t; + + }; + +} // namespace seafire::routing + + +#endif diff --git a/seafire/routing/route-parameter.hxx b/seafire/routing/route-parameter.hxx index 3c1c6ff..f91d036 100644 --- a/seafire/routing/route-parameter.hxx +++ b/seafire/routing/route-parameter.hxx @@ -4,7 +4,7 @@ #include #include -#include +#include #include diff --git a/seafire/routing/route-parameters.hxx b/seafire/routing/route-parameters.hxx deleted file mode 100644 index ac67cc3..0000000 --- a/seafire/routing/route-parameters.hxx +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef seafire__routing__route_parameters_hxx_ -#define seafire__routing__route_parameters_hxx_ - -#include -#include -#include - -namespace seafire::routing -{ - - class route_parameters_t - { - public: - std::map& - map(); - - std::map const& - map() const; - - std::optional - get(std::string const& key) const; - - private: - std::map kv_; - - }; - -} // namespace seafire::routing - -#endif diff --git a/seafire/routing/route.cxx b/seafire/routing/route.cxx index 1c7d55a..4a055e8 100644 --- a/seafire/routing/route.cxx +++ b/seafire/routing/route.cxx @@ -6,18 +6,21 @@ namespace seafire::routing { static - void - ensure_valid_path(std::string const& path) + std::string + validate_path(std::string path) { if (!path.empty()) { if (path.front() == '/') { - throw std::invalid_argument{"route path must not start with '/'"}; + throw std::invalid_argument{"route path must not begin with '/'"}; } if (path.back() == '/') { throw std::invalid_argument{"route path must not end with '/'"}; } } + + return path; + } route_t:: @@ -25,17 +28,13 @@ namespace seafire::routing route_t:: route_t(std::string path) - : path_{std::move(path)} - { - ensure_valid_path(path_); - } + : path_{validate_path(std::move(path))} + {} route_t:: route_t(std::string path, server::request_handler_t handler) - : path_{std::move(path)}, handler_{std::move(handler)} - { - ensure_valid_path(path_); - } + : path_{validate_path(std::move(path))}, handler_{std::move(handler)} + {} std::string const& route_t:: @@ -80,26 +79,20 @@ namespace seafire::routing return children_.back(); } - route_t& - route_t:: - add_route(route_t r) - { - children_.emplace_back(std::move(r)); - return children_.back(); - } - route_t& route_t:: add_route(std::string path) { - return add_route(route_t{std::move(path)}); + children_.emplace_back(std::move(path)); + return children_.back(); } route_t& route_t:: add_route(std::string path, server::request_handler_t handler) { - return add_route(route_t{std::move(path), std::move(handler)}); + children_.emplace_back(std::move(path), std::move(handler)); + return children_.back(); } std::ostream& diff --git a/seafire/routing/route.hxx b/seafire/routing/route.hxx index 6806ef4..86ea0f8 100644 --- a/seafire/routing/route.hxx +++ b/seafire/routing/route.hxx @@ -24,6 +24,9 @@ namespace seafire::routing route_t(std::string, server::request_handler_t); + route_t(route_t const&) = delete; + route_t(route_t&&) = delete; + std::string const& path() const; @@ -42,15 +45,15 @@ namespace seafire::routing route_t& add_route(); - route_t& - add_route(route_t); - route_t& add_route(std::string); route_t& add_route(std::string, server::request_handler_t); + route_t& operator=(route_t const&) = delete; + route_t& operator=(route_t&&) = delete; + private: std::string path_; std::vector middleware_; diff --git a/seafire/routing/router.cxx b/seafire/routing/router.cxx index 7b81552..4e03e03 100644 --- a/seafire/routing/router.cxx +++ b/seafire/routing/router.cxx @@ -1,6 +1,8 @@ #include #include +#include + namespace seafire::routing { @@ -58,11 +60,23 @@ namespace seafire::routing { trace() << "on_request(...)"; + auto host = get(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 for [" << path << "]"; + trace() << "locating endpoint:\n" + << " -> hostname: " << hostname << '\n' + << " -> path : " << path + ; - auto result = routing_table().find_route(path); + auto result = routing_table().find_route(hostname, path); if (!result) { trace() << "endpoint for [" << path << "] not found"; @@ -72,15 +86,19 @@ namespace seafire::routing auto trace_endpoint = [&result](common::diagnostics_t::proxy_t proxy) { - proxy << "endpoint found"; + proxy << "endpoint found!"; - for (auto const& j : result->params.map()) - proxy << "\n -> " << j.first << " = " << j.second << '\n'; + 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->params)); + req.extensions().extend(&res.memory().alloc(result->host_params)); + req.extensions().extend(&res.memory().alloc(result->route_params)); result->handler.invoke(req, res); } diff --git a/seafire/routing/routing-table.cxx b/seafire/routing/routing-table.cxx index 586d346..c80591f 100644 --- a/seafire/routing/routing-table.cxx +++ b/seafire/routing/routing-table.cxx @@ -1,7 +1,6 @@ #include -#include -#include +#include namespace seafire::routing { @@ -20,66 +19,27 @@ namespace seafire::routing std::optional routing_table_t:: - find_route(std::string const& path) const + find_route(std::string const& host, std::string const& path) const { for (auto const& e : endpoints()) { - route_parameters_t params; + host_parameters_t host_params; - if (match_path(e.pattern(), path, params)) - return find_result_t{e.handler(), std::move(params)}; + if (!match(host, e.host(), '.', host_params)) { + continue; + } + + route_parameters_t route_params; + + if (match(path, e.path(), '/', route_params)) { + return find_result_t{ + std::move(host_params), + std::move(route_params), + e.handler() + }; + } } - return {}; - } - - routing_table_t::builder_t:: - builder_t() = default; - - routing_table_t::builder_t:: - ~builder_t() noexcept = default; - - route_t& - routing_table_t::builder_t:: - add_route() - { - roots_.emplace_back(); - return roots_.back(); - } - - route_t& - routing_table_t::builder_t:: - add_route(route_t r) - { - roots_.emplace_back(std::move(r)); - return roots_.back(); - } - - route_t& - routing_table_t::builder_t:: - add_route(std::string path) - { - return add_route(route_t{std::move(path)}); - } - - route_t& - routing_table_t::builder_t:: - add_route(std::string path, - server::request_handler_t handler) - { - return add_route({std::move(path), std::move(handler)}); - } - - routing_table_t - routing_table_t::builder_t:: - build() const - { - std::vector endpoints; - - for (auto const& r : roots_) { - flatten_route(endpoints, r); - } - - return routing_table_t{std::move(endpoints)}; + return std::nullopt; } } // namespace seafire::routing diff --git a/seafire/routing/routing-table.hxx b/seafire/routing/routing-table.hxx index bb6463f..6d9e6f2 100644 --- a/seafire/routing/routing-table.hxx +++ b/seafire/routing/routing-table.hxx @@ -2,7 +2,7 @@ #define seafire__routing__routing_table_hxx_ #include -#include +#include #include #include @@ -18,12 +18,12 @@ namespace seafire::routing class routing_table_t { public: - class builder_t; - struct find_result_t { + host_parameters_t host_params; + route_parameters_t route_params; + server::request_handler_t const& handler; - route_parameters_t params; }; @@ -34,45 +34,17 @@ namespace seafire::routing endpoints() const; std::optional - find_route(std::string const&) const; + find_route(std::string const&, std::string const&) const; private: + static + bool + match_host(std::string const&, std::string const&); + std::vector endpoints_; }; - class routing_table_t::builder_t { - public: - builder_t(); - - builder_t(builder_t const&) = delete; - builder_t(builder_t&&) = delete; - - ~builder_t() noexcept; - - route_t& - add_route(); - - route_t& - add_route(route_t); - - route_t& - add_route(std::string); - - route_t& - add_route(std::string, server::request_handler_t); - - routing_table_t - build() const; - - builder_t& operator=(builder_t const&) = delete; - builder_t& operator=(builder_t&&) = delete; - - private: - std::list roots_; - - }; - } // namespace seafire::routing #endif diff --git a/seafire/routing/virtual-host.cxx b/seafire/routing/virtual-host.cxx new file mode 100644 index 0000000..ad86564 --- /dev/null +++ b/seafire/routing/virtual-host.cxx @@ -0,0 +1,100 @@ +#include + +namespace seafire::routing +{ + + static + std::string + validate_host(std::string host) + { + if (host.empty()) { + throw std::invalid_argument{"host must not be empty"}; + } + + if (host.front() == '.') { + throw std::invalid_argument{"host must not begin with '.'"}; + } + + if (host.back() == '.') { + throw std::invalid_argument{"host must not end with '.'"}; + } + + return host; + } + + virtual_host_t:: + virtual_host_t(std::string host) + : _host{validate_host(std::move(host))} + {} + + std::string const& + virtual_host_t:: + host() const + { + return _host; + } + + std::vector const& + virtual_host_t:: + middleware() const + { + return _middleware; + } + + std::list const& + virtual_host_t:: + routes() const + { + return _routes; + } + + void + virtual_host_t:: + use(server::middleware_t m) + { + _middleware.emplace_back(std::move(m)); + } + + route_t& + virtual_host_t:: + add_route() + { + _routes.emplace_back(); + return _routes.back(); + } + + route_t& + virtual_host_t:: + add_route(std::string path) + { + _routes.emplace_back(std::move(path)); + return _routes.back(); + } + + route_t& + virtual_host_t:: + add_route(std::string path, server::request_handler_t handler) + { + _routes.emplace_back(std::move(path), std::move(handler)); + return _routes.back(); + } + + std::ostream& + to_stream(std::ostream& o, virtual_host_t const& vhost) + { + o << " => " << vhost.host() << '\n'; + + for (auto const& r : vhost.routes()) { + to_stream(o, r, 2); + } + + return o; + } + + std::ostream& + operator<<(std::ostream& o, virtual_host_t const& vhost) + { + return to_stream(o, vhost); + } + +} // namespace seafire::routing diff --git a/seafire/routing/virtual-host.hxx b/seafire/routing/virtual-host.hxx new file mode 100644 index 0000000..abd3b4f --- /dev/null +++ b/seafire/routing/virtual-host.hxx @@ -0,0 +1,65 @@ +#ifndef seafire_routing__virtual_host_hxx_ +#define seafire_routing__virtual_host_hxx_ + +#include + +#include +#include + +#include +#include +#include +#include + +namespace seafire::routing +{ + + class virtual_host_t + { + public: + explicit + virtual_host_t(std::string); + + virtual_host_t(virtual_host_t const&) = delete; + virtual_host_t(virtual_host_t&&) = delete; + + std::string const& + host() const; + + std::vector const& + middleware() const; + + std::list const& + routes() const; + + void + use(server::middleware_t); + + route_t& + add_route(); + + route_t& + add_route(std::string); + + route_t& + add_route(std::string, server::request_handler_t); + + virtual_host_t& operator=(virtual_host_t const&) = delete; + virtual_host_t& operator=(virtual_host_t&&) = delete; + + private: + std::string _host; + std::vector _middleware; + std::list _routes; + + }; + + std::ostream& + to_stream(std::ostream&, virtual_host_t const&); + + std::ostream& + operator<<(std::ostream&, virtual_host_t const&); + +} // namespace seafire::routing + +#endif From 8bacfde0c1b4dd9a8369ba946ab1ba8e1df9e216 Mon Sep 17 00:00:00 2001 From: Ryan Date: Sun, 9 Mar 2025 15:56:08 +0100 Subject: [PATCH 2/2] Use named_parameter_t from Seafire::Server --- seafire/routing/host-parameter.hxx | 11 +++-------- seafire/routing/route-parameter.hxx | 11 +++-------- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/seafire/routing/host-parameter.hxx b/seafire/routing/host-parameter.hxx index 6cd87a7..5a79e1c 100644 --- a/seafire/routing/host-parameter.hxx +++ b/seafire/routing/host-parameter.hxx @@ -16,23 +16,18 @@ namespace seafire::routing typename ParameterType = server::string_parameter_t > class host_parameter_t + : public server::named_parameter_t { public: using parameter_type = ParameterType; using value_type = typename parameter_type::value_type; - static - std::string const& - name() - { - static std::string const name{Name}; - return name; - } - host_parameter_t(std::optional value) : _value{std::move(value)} {} + using server::named_parameter_t::name; + std::optional const& value() const { diff --git a/seafire/routing/route-parameter.hxx b/seafire/routing/route-parameter.hxx index f91d036..564742a 100644 --- a/seafire/routing/route-parameter.hxx +++ b/seafire/routing/route-parameter.hxx @@ -16,23 +16,18 @@ namespace seafire::routing typename ParameterType = server::string_parameter_t > class route_parameter_t + : public server::named_parameter_t { public: using parameter_type = ParameterType; using value_type = typename parameter_type::value_type; - static - std::string const& - name() - { - static std::string const name{Name}; - return name; - } - route_parameter_t(std::optional value) : _value{std::move(value)} {} + using server::named_parameter_t::name; + std::optional const& value() const {