Merge branch 'feature/virtual-hosts'
This commit is contained in:
commit
53d43dfea6
43
seafire/routing/builder.cxx
Normal file
43
seafire/routing/builder.cxx
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#include <seafire/routing/builder.hxx>
|
||||||
|
#include <seafire/routing/flatten.hxx>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace seafire::routing
|
||||||
|
{
|
||||||
|
|
||||||
|
builder_t::
|
||||||
|
builder_t()
|
||||||
|
{}
|
||||||
|
|
||||||
|
std::list<virtual_host_t> 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<endpoint_t> 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
|
42
seafire/routing/builder.hxx
Normal file
42
seafire/routing/builder.hxx
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#ifndef seafire__routing__builder_hxx_
|
||||||
|
#define seafire__routing__builder_hxx_
|
||||||
|
|
||||||
|
#include <seafire/routing/routing-table.hxx>
|
||||||
|
#include <seafire/routing/virtual-host.hxx>
|
||||||
|
|
||||||
|
#include <seafire/server/request-handler.hxx>
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace seafire::routing
|
||||||
|
{
|
||||||
|
|
||||||
|
class builder_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
builder_t();
|
||||||
|
|
||||||
|
builder_t(builder_t const&) = delete;
|
||||||
|
builder_t(builder_t&&) = delete;
|
||||||
|
|
||||||
|
std::list<virtual_host_t> 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<virtual_host_t> _vhosts;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace seafire::routing
|
||||||
|
|
||||||
|
#endif
|
@ -4,15 +4,26 @@ namespace seafire::routing
|
|||||||
{
|
{
|
||||||
|
|
||||||
endpoint_t::
|
endpoint_t::
|
||||||
endpoint_t(std::string pattern, server::request_handler_t handler)
|
endpoint_t(std::string host,
|
||||||
: pattern_{std::move(pattern)}, handler_{std::move(handler)}
|
std::string path,
|
||||||
|
server::request_handler_t handler)
|
||||||
|
: host_{std::move(host)},
|
||||||
|
path_{std::move(path)},
|
||||||
|
handler_{std::move(handler)}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
std::string const&
|
std::string const&
|
||||||
endpoint_t::
|
endpoint_t::
|
||||||
pattern() const
|
host() const
|
||||||
{
|
{
|
||||||
return pattern_;
|
return host_;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string const&
|
||||||
|
endpoint_t::
|
||||||
|
path() const
|
||||||
|
{
|
||||||
|
return path_;
|
||||||
}
|
}
|
||||||
|
|
||||||
server::request_handler_t const&
|
server::request_handler_t const&
|
||||||
@ -25,7 +36,7 @@ namespace seafire::routing
|
|||||||
std::ostream&
|
std::ostream&
|
||||||
to_stream(std::ostream& o, endpoint_t const& ep)
|
to_stream(std::ostream& o, endpoint_t const& ep)
|
||||||
{
|
{
|
||||||
return o << ep.pattern();
|
return o << ep.host() << ": " << ep.path();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream&
|
std::ostream&
|
||||||
|
@ -12,16 +12,20 @@ namespace seafire::routing
|
|||||||
class endpoint_t
|
class endpoint_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
endpoint_t(std::string, server::request_handler_t);
|
endpoint_t(std::string, std::string, server::request_handler_t);
|
||||||
|
|
||||||
std::string const&
|
std::string const&
|
||||||
pattern() const;
|
host() const;
|
||||||
|
|
||||||
|
std::string const&
|
||||||
|
path() const;
|
||||||
|
|
||||||
server::request_handler_t const&
|
server::request_handler_t const&
|
||||||
handler() const;
|
handler() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string pattern_;
|
std::string host_;
|
||||||
|
std::string path_;
|
||||||
server::request_handler_t handler_;
|
server::request_handler_t handler_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -1,50 +0,0 @@
|
|||||||
#include <seafire/routing/flatten-route.hxx>
|
|
||||||
|
|
||||||
namespace seafire::routing
|
|
||||||
{
|
|
||||||
|
|
||||||
void
|
|
||||||
flatten_route(std::vector<endpoint_t>& endpoints,
|
|
||||||
std::vector<server::middleware_t> 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<endpoint_t>& endpoints, route_t const& r)
|
|
||||||
{
|
|
||||||
flatten_route(endpoints, {}, r, "/");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<endpoint_t>
|
|
||||||
flatten_route(route_t const& r)
|
|
||||||
{
|
|
||||||
std::vector<endpoint_t> endpoints;
|
|
||||||
flatten_route(endpoints, r);
|
|
||||||
return endpoints;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace seafire::routing
|
|
@ -1,28 +0,0 @@
|
|||||||
#ifndef seafire__routing__flatten_route_hxx_
|
|
||||||
#define seafire__routing__flatten_route_hxx_
|
|
||||||
|
|
||||||
#include <seafire/routing/endpoint.hxx>
|
|
||||||
#include <seafire/routing/route.hxx>
|
|
||||||
|
|
||||||
#include <seafire/server/middleware.hxx>
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace seafire::routing
|
|
||||||
{
|
|
||||||
|
|
||||||
void
|
|
||||||
flatten_route(std::vector<endpoint_t>& endpoints,
|
|
||||||
std::vector<server::middleware_t>,
|
|
||||||
route_t const& r,
|
|
||||||
std::string const& root);
|
|
||||||
|
|
||||||
void
|
|
||||||
flatten_route(std::vector<endpoint_t>&, route_t const&);
|
|
||||||
|
|
||||||
std::vector<endpoint_t>
|
|
||||||
flatten_route(route_t const&);
|
|
||||||
|
|
||||||
} // namespace seafire::routing
|
|
||||||
|
|
||||||
#endif
|
|
55
seafire/routing/flatten.cxx
Normal file
55
seafire/routing/flatten.cxx
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#include <seafire/routing/flatten.hxx>
|
||||||
|
|
||||||
|
namespace seafire::routing
|
||||||
|
{
|
||||||
|
|
||||||
|
void
|
||||||
|
flatten(std::vector<endpoint_t>& endpoints,
|
||||||
|
std::string const& vhost,
|
||||||
|
std::vector<server::middleware_t> 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<endpoint_t>& endpoints,
|
||||||
|
std::string const& vhost,
|
||||||
|
std::vector<server::middleware_t> middlewares,
|
||||||
|
route_t const& r)
|
||||||
|
{
|
||||||
|
flatten(endpoints, vhost, middlewares, r, "/");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<endpoint_t>
|
||||||
|
flatten(std::string const& vhost, route_t const& r)
|
||||||
|
{
|
||||||
|
std::vector<endpoint_t> endpoints;
|
||||||
|
flatten(endpoints, vhost, {}, r);
|
||||||
|
return endpoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace seafire::routing
|
32
seafire/routing/flatten.hxx
Normal file
32
seafire/routing/flatten.hxx
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#ifndef seafire__routing__flatten_route_hxx_
|
||||||
|
#define seafire__routing__flatten_route_hxx_
|
||||||
|
|
||||||
|
#include <seafire/routing/endpoint.hxx>
|
||||||
|
#include <seafire/routing/route.hxx>
|
||||||
|
|
||||||
|
#include <seafire/server/middleware.hxx>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace seafire::routing
|
||||||
|
{
|
||||||
|
|
||||||
|
void
|
||||||
|
flatten(std::vector<endpoint_t>& endpoints,
|
||||||
|
std::string const&,
|
||||||
|
std::vector<server::middleware_t>,
|
||||||
|
route_t const& r,
|
||||||
|
std::string const& root);
|
||||||
|
|
||||||
|
void
|
||||||
|
flatten(std::vector<endpoint_t>&,
|
||||||
|
std::string const&,
|
||||||
|
std::vector<server::middleware_t>,
|
||||||
|
route_t const&);
|
||||||
|
|
||||||
|
std::vector<endpoint_t>
|
||||||
|
flatten(std::string const&, route_t const&);
|
||||||
|
|
||||||
|
} // namespace seafire::routing
|
||||||
|
|
||||||
|
#endif
|
63
seafire/routing/host-parameter.hxx
Normal file
63
seafire/routing/host-parameter.hxx
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
#ifndef seafire__routing__host_parameter_hxx_
|
||||||
|
#define seafire__routing__host_parameter_hxx_
|
||||||
|
|
||||||
|
#include <seafire/server/parameters.hxx>
|
||||||
|
#include <seafire/server/request.hxx>
|
||||||
|
|
||||||
|
#include <seafire/routing/parameters.hxx>
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
namespace seafire::routing
|
||||||
|
{
|
||||||
|
|
||||||
|
template<
|
||||||
|
server::parameter_name_t Name,
|
||||||
|
typename ParameterType = server::string_parameter_t
|
||||||
|
>
|
||||||
|
class host_parameter_t
|
||||||
|
: public server::named_parameter_t<Name>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using parameter_type = ParameterType;
|
||||||
|
using value_type = typename parameter_type::value_type;
|
||||||
|
|
||||||
|
host_parameter_t(std::optional<value_type> value)
|
||||||
|
: _value{std::move(value)}
|
||||||
|
{}
|
||||||
|
|
||||||
|
using server::named_parameter_t<Name>::name;
|
||||||
|
|
||||||
|
std::optional<value_type> const&
|
||||||
|
value() const
|
||||||
|
{
|
||||||
|
return _value;
|
||||||
|
}
|
||||||
|
|
||||||
|
operator std::optional<value_type> const&() const
|
||||||
|
{
|
||||||
|
return value();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<value_type> const*
|
||||||
|
operator->() const
|
||||||
|
{
|
||||||
|
return &value();
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
host_parameter_t<Name, ParameterType>
|
||||||
|
fetch(server::request_t& req)
|
||||||
|
{
|
||||||
|
auto v = req.extensions().use<host_parameters_t>().get(name());
|
||||||
|
return parameter_type::try_parse(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::optional<value_type> _value;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace seafire::routing
|
||||||
|
|
||||||
|
#endif
|
@ -1,24 +0,0 @@
|
|||||||
#ifndef seafire__routing__match_path_hxx_
|
|
||||||
#define seafire__routing__match_path_hxx_
|
|
||||||
|
|
||||||
#include <seafire/routing/route-parameters.hxx>
|
|
||||||
|
|
||||||
#include <code/uri/uri.hxx>
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
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
|
|
@ -1,18 +1,18 @@
|
|||||||
#include <seafire/routing/match-path.hxx>
|
#include <seafire/routing/match.hxx>
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
namespace seafire::routing
|
namespace seafire::routing
|
||||||
{
|
{
|
||||||
|
|
||||||
bool
|
bool
|
||||||
match_path(std::string const& pattern,
|
match(std::string const& subject,
|
||||||
std::string const& subject,
|
std::string const& pattern,
|
||||||
route_parameters_t& params)
|
char delim,
|
||||||
|
parameters_t& params)
|
||||||
{
|
{
|
||||||
route_parameters_t tmp_params;
|
parameters_t tmp_params;
|
||||||
|
|
||||||
// p/pend = pattern iterators.
|
// p/pend = pattern iterators.
|
||||||
//
|
//
|
||||||
@ -46,7 +46,7 @@ namespace seafire::routing
|
|||||||
// v/vend = local subject iterators.
|
// v/vend = local subject iterators.
|
||||||
//
|
//
|
||||||
auto const v = s;
|
auto const v = s;
|
||||||
while (s != send && (greedy || '/' != *s)) {
|
while (s != send && (greedy || delim != *s)) {
|
||||||
++s;
|
++s;
|
||||||
}
|
}
|
||||||
auto const vend = s;
|
auto const vend = s;
|
||||||
@ -83,8 +83,7 @@ namespace seafire::routing
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
render_path(std::string const& pattern,
|
render(std::string const& pattern, parameters_t& params)
|
||||||
route_parameters_t const& params)
|
|
||||||
{
|
{
|
||||||
std::stringstream str;
|
std::stringstream str;
|
||||||
|
|
22
seafire/routing/match.hxx
Normal file
22
seafire/routing/match.hxx
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#ifndef seafire__routing__match_hxx_
|
||||||
|
#define seafire__routing__match_hxx_
|
||||||
|
|
||||||
|
#include <seafire/routing/parameters.hxx>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
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
|
@ -1,24 +1,24 @@
|
|||||||
#include <seafire/routing/route-parameters.hxx>
|
#include <seafire/routing/parameters.hxx>
|
||||||
|
|
||||||
namespace seafire::routing
|
namespace seafire::routing
|
||||||
{
|
{
|
||||||
|
|
||||||
std::map<std::string, std::string>&
|
parameters_t::map_type&
|
||||||
route_parameters_t::
|
parameters_t::
|
||||||
map()
|
map()
|
||||||
{
|
{
|
||||||
return kv_;
|
return _values;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::string, std::string> const&
|
parameters_t::map_type const&
|
||||||
route_parameters_t::
|
parameters_t::
|
||||||
map() const
|
map() const
|
||||||
{
|
{
|
||||||
return kv_;
|
return _values;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::string>
|
std::optional<std::string>
|
||||||
route_parameters_t::
|
parameters_t::
|
||||||
get(std::string const& key) const
|
get(std::string const& key) const
|
||||||
{
|
{
|
||||||
if (auto it = map().find(key); it != map().end())
|
if (auto it = map().find(key); it != map().end())
|
56
seafire/routing/parameters.hxx
Normal file
56
seafire/routing/parameters.hxx
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
#ifndef seafire_routing__parameters_hxx_
|
||||||
|
#define seafire_routing__parameters_hxx_
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace seafire::routing
|
||||||
|
{
|
||||||
|
|
||||||
|
class parameters_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using map_type = std::map<std::string, std::string>;
|
||||||
|
|
||||||
|
parameters_t() = default;
|
||||||
|
|
||||||
|
parameters_t(map_type values)
|
||||||
|
: _values{std::move(values)}
|
||||||
|
{}
|
||||||
|
|
||||||
|
map_type&
|
||||||
|
map();
|
||||||
|
|
||||||
|
map_type const&
|
||||||
|
map() const;
|
||||||
|
|
||||||
|
std::optional<std::string>
|
||||||
|
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
|
@ -4,7 +4,7 @@
|
|||||||
#include <seafire/server/parameters.hxx>
|
#include <seafire/server/parameters.hxx>
|
||||||
#include <seafire/server/request.hxx>
|
#include <seafire/server/request.hxx>
|
||||||
|
|
||||||
#include <seafire/routing/route-parameters.hxx>
|
#include <seafire/routing/parameters.hxx>
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
@ -16,23 +16,18 @@ namespace seafire::routing
|
|||||||
typename ParameterType = server::string_parameter_t
|
typename ParameterType = server::string_parameter_t
|
||||||
>
|
>
|
||||||
class route_parameter_t
|
class route_parameter_t
|
||||||
|
: public server::named_parameter_t<Name>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using parameter_type = ParameterType;
|
using parameter_type = ParameterType;
|
||||||
using value_type = typename parameter_type::value_type;
|
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_type> value)
|
route_parameter_t(std::optional<value_type> value)
|
||||||
: _value{std::move(value)}
|
: _value{std::move(value)}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
using server::named_parameter_t<Name>::name;
|
||||||
|
|
||||||
std::optional<value_type> const&
|
std::optional<value_type> const&
|
||||||
value() const
|
value() const
|
||||||
{
|
{
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
#ifndef seafire__routing__route_parameters_hxx_
|
|
||||||
#define seafire__routing__route_parameters_hxx_
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include <optional>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace seafire::routing
|
|
||||||
{
|
|
||||||
|
|
||||||
class route_parameters_t
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
std::map<std::string, std::string>&
|
|
||||||
map();
|
|
||||||
|
|
||||||
std::map<std::string, std::string> const&
|
|
||||||
map() const;
|
|
||||||
|
|
||||||
std::optional<std::string>
|
|
||||||
get(std::string const& key) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::map<std::string, std::string> kv_;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace seafire::routing
|
|
||||||
|
|
||||||
#endif
|
|
@ -6,18 +6,21 @@ namespace seafire::routing
|
|||||||
{
|
{
|
||||||
|
|
||||||
static
|
static
|
||||||
void
|
std::string
|
||||||
ensure_valid_path(std::string const& path)
|
validate_path(std::string path)
|
||||||
{
|
{
|
||||||
if (!path.empty()) {
|
if (!path.empty()) {
|
||||||
if (path.front() == '/') {
|
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() == '/') {
|
if (path.back() == '/') {
|
||||||
throw std::invalid_argument{"route path must not end with '/'"};
|
throw std::invalid_argument{"route path must not end with '/'"};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
route_t::
|
route_t::
|
||||||
@ -25,17 +28,13 @@ namespace seafire::routing
|
|||||||
|
|
||||||
route_t::
|
route_t::
|
||||||
route_t(std::string path)
|
route_t(std::string path)
|
||||||
: path_{std::move(path)}
|
: path_{validate_path(std::move(path))}
|
||||||
{
|
{}
|
||||||
ensure_valid_path(path_);
|
|
||||||
}
|
|
||||||
|
|
||||||
route_t::
|
route_t::
|
||||||
route_t(std::string path, server::request_handler_t handler)
|
route_t(std::string path, server::request_handler_t handler)
|
||||||
: path_{std::move(path)}, handler_{std::move(handler)}
|
: path_{validate_path(std::move(path))}, handler_{std::move(handler)}
|
||||||
{
|
{}
|
||||||
ensure_valid_path(path_);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string const&
|
std::string const&
|
||||||
route_t::
|
route_t::
|
||||||
@ -80,26 +79,20 @@ namespace seafire::routing
|
|||||||
return children_.back();
|
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&
|
||||||
route_t::
|
route_t::
|
||||||
add_route(std::string path)
|
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&
|
||||||
route_t::
|
route_t::
|
||||||
add_route(std::string path, server::request_handler_t handler)
|
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&
|
std::ostream&
|
||||||
|
@ -24,6 +24,9 @@ namespace seafire::routing
|
|||||||
|
|
||||||
route_t(std::string, server::request_handler_t);
|
route_t(std::string, server::request_handler_t);
|
||||||
|
|
||||||
|
route_t(route_t const&) = delete;
|
||||||
|
route_t(route_t&&) = delete;
|
||||||
|
|
||||||
std::string const&
|
std::string const&
|
||||||
path() const;
|
path() const;
|
||||||
|
|
||||||
@ -42,15 +45,15 @@ namespace seafire::routing
|
|||||||
route_t&
|
route_t&
|
||||||
add_route();
|
add_route();
|
||||||
|
|
||||||
route_t&
|
|
||||||
add_route(route_t);
|
|
||||||
|
|
||||||
route_t&
|
route_t&
|
||||||
add_route(std::string);
|
add_route(std::string);
|
||||||
|
|
||||||
route_t&
|
route_t&
|
||||||
add_route(std::string, server::request_handler_t);
|
add_route(std::string, server::request_handler_t);
|
||||||
|
|
||||||
|
route_t& operator=(route_t const&) = delete;
|
||||||
|
route_t& operator=(route_t&&) = delete;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string path_;
|
std::string path_;
|
||||||
std::vector<server::middleware_t> middleware_;
|
std::vector<server::middleware_t> middleware_;
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#include <seafire/routing/router.hxx>
|
#include <seafire/routing/router.hxx>
|
||||||
#include <seafire/routing/diagnostics.hxx>
|
#include <seafire/routing/diagnostics.hxx>
|
||||||
|
|
||||||
|
#include <seafire/protocol/rfc7230/host.hxx>
|
||||||
|
|
||||||
namespace seafire::routing
|
namespace seafire::routing
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -58,11 +60,23 @@ namespace seafire::routing
|
|||||||
{
|
{
|
||||||
trace() << "on_request(...)";
|
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());
|
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) {
|
if (!result) {
|
||||||
trace() << "endpoint for [" << path << "] not found";
|
trace() << "endpoint for [" << path << "] not found";
|
||||||
@ -72,15 +86,19 @@ namespace seafire::routing
|
|||||||
|
|
||||||
auto trace_endpoint = [&result](common::diagnostics_t::proxy_t proxy)
|
auto trace_endpoint = [&result](common::diagnostics_t::proxy_t proxy)
|
||||||
{
|
{
|
||||||
proxy << "endpoint found";
|
proxy << "endpoint found!";
|
||||||
|
|
||||||
for (auto const& j : result->params.map())
|
for (auto const& j : result->host_params.map())
|
||||||
proxy << "\n -> " << j.first << " = " << j.second << '\n';
|
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());
|
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);
|
result->handler.invoke(req, res);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#include <seafire/routing/routing-table.hxx>
|
#include <seafire/routing/routing-table.hxx>
|
||||||
|
|
||||||
#include <seafire/routing/match-path.hxx>
|
#include <seafire/routing/match.hxx>
|
||||||
#include <seafire/routing/flatten-route.hxx>
|
|
||||||
|
|
||||||
namespace seafire::routing
|
namespace seafire::routing
|
||||||
{
|
{
|
||||||
@ -20,66 +19,27 @@ namespace seafire::routing
|
|||||||
|
|
||||||
std::optional<routing_table_t::find_result_t>
|
std::optional<routing_table_t::find_result_t>
|
||||||
routing_table_t::
|
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()) {
|
for (auto const& e : endpoints()) {
|
||||||
route_parameters_t params;
|
host_parameters_t host_params;
|
||||||
|
|
||||||
if (match_path(e.pattern(), path, params))
|
if (!match(host, e.host(), '.', host_params)) {
|
||||||
return find_result_t{e.handler(), std::move(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 {};
|
return std::nullopt;
|
||||||
}
|
|
||||||
|
|
||||||
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<endpoint_t> endpoints;
|
|
||||||
|
|
||||||
for (auto const& r : roots_) {
|
|
||||||
flatten_route(endpoints, r);
|
|
||||||
}
|
|
||||||
|
|
||||||
return routing_table_t{std::move(endpoints)};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace seafire::routing
|
} // namespace seafire::routing
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#define seafire__routing__routing_table_hxx_
|
#define seafire__routing__routing_table_hxx_
|
||||||
|
|
||||||
#include <seafire/routing/endpoint.hxx>
|
#include <seafire/routing/endpoint.hxx>
|
||||||
#include <seafire/routing/route-parameters.hxx>
|
#include <seafire/routing/parameters.hxx>
|
||||||
#include <seafire/routing/route.hxx>
|
#include <seafire/routing/route.hxx>
|
||||||
|
|
||||||
#include <seafire/server/request-handler.hxx>
|
#include <seafire/server/request-handler.hxx>
|
||||||
@ -18,12 +18,12 @@ namespace seafire::routing
|
|||||||
class routing_table_t
|
class routing_table_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
class builder_t;
|
|
||||||
|
|
||||||
struct find_result_t
|
struct find_result_t
|
||||||
{
|
{
|
||||||
|
host_parameters_t host_params;
|
||||||
|
route_parameters_t route_params;
|
||||||
|
|
||||||
server::request_handler_t const& handler;
|
server::request_handler_t const& handler;
|
||||||
route_parameters_t params;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -34,45 +34,17 @@ namespace seafire::routing
|
|||||||
endpoints() const;
|
endpoints() const;
|
||||||
|
|
||||||
std::optional<find_result_t>
|
std::optional<find_result_t>
|
||||||
find_route(std::string const&) const;
|
find_route(std::string const&, std::string const&) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static
|
||||||
|
bool
|
||||||
|
match_host(std::string const&, std::string const&);
|
||||||
|
|
||||||
std::vector<endpoint_t> endpoints_;
|
std::vector<endpoint_t> 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<route_t> roots_;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace seafire::routing
|
} // namespace seafire::routing
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
100
seafire/routing/virtual-host.cxx
Normal file
100
seafire/routing/virtual-host.cxx
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
#include <seafire/routing/virtual-host.hxx>
|
||||||
|
|
||||||
|
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<server::middleware_t> const&
|
||||||
|
virtual_host_t::
|
||||||
|
middleware() const
|
||||||
|
{
|
||||||
|
return _middleware;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list<route_t> 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
|
65
seafire/routing/virtual-host.hxx
Normal file
65
seafire/routing/virtual-host.hxx
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
#ifndef seafire_routing__virtual_host_hxx_
|
||||||
|
#define seafire_routing__virtual_host_hxx_
|
||||||
|
|
||||||
|
#include <seafire/routing/route.hxx>
|
||||||
|
|
||||||
|
#include <seafire/server/middleware.hxx>
|
||||||
|
#include <seafire/server/request-handler.hxx>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <list>
|
||||||
|
#include <optional>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
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<server::middleware_t> const&
|
||||||
|
middleware() const;
|
||||||
|
|
||||||
|
std::list<route_t> 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<server::middleware_t> _middleware;
|
||||||
|
std::list<route_t> _routes;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
std::ostream&
|
||||||
|
to_stream(std::ostream&, virtual_host_t const&);
|
||||||
|
|
||||||
|
std::ostream&
|
||||||
|
operator<<(std::ostream&, virtual_host_t const&);
|
||||||
|
|
||||||
|
} // namespace seafire::routing
|
||||||
|
|
||||||
|
#endif
|
Loading…
x
Reference in New Issue
Block a user