Line data Source code
1 : //
2 : // Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot com)
3 : //
4 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 : //
7 : // Official repository: https://github.com/cppalliance/beast2
8 : //
9 :
10 : #ifndef BOOST_BEAST2_SERVER_DETAIL_ANY_ROUTER_HPP
11 : #define BOOST_BEAST2_SERVER_DETAIL_ANY_ROUTER_HPP
12 :
13 : #include <boost/beast2/detail/config.hpp>
14 : #include <boost/beast2/detail/call_traits.hpp>
15 : #include <boost/beast2/detail/type_traits.hpp>
16 : #include <boost/beast2/server/route_handler.hpp>
17 : #include <boost/http_proto/method.hpp>
18 : #include <boost/url/segments_encoded_view.hpp>
19 : #include <boost/core/detail/string_view.hpp>
20 : #include <type_traits>
21 :
22 : namespace boost {
23 : namespace beast2 {
24 :
25 : struct route_state;
26 :
27 : //------------------------------------------------
28 :
29 : namespace detail {
30 :
31 : class any_router;
32 :
33 : // handler kind constants
34 : // 0 = unrecognized
35 : // 1 = regular
36 : // 2 = router
37 : // 3 = error
38 :
39 : template<class T,
40 : class Req, class Res, class = void>
41 : struct get_handler_kind
42 : : std::integral_constant<int, 0>
43 : {
44 : };
45 :
46 : // route_result( Req&, Res& )
47 : template<class T, class Req, class Res>
48 : struct get_handler_kind<T, Req, Res,
49 : typename std::enable_if<detail::is_invocable<
50 : T, route_result, Req&, Res&>::value>::type>
51 : : std::integral_constant<int, 1>
52 : {
53 : };
54 :
55 : // route_result( Req&, Res&, route_state& )
56 : template<class T, class Req, class Res>
57 : struct get_handler_kind<T, Req, Res,
58 : typename std::enable_if<detail::derived_from<
59 : T, any_router>::value>::type>
60 : : std::integral_constant<int, 2>
61 : {
62 : };
63 :
64 : // route_result( Req&, Res&, system::error_code&
65 : template<class T, class Req, class Res>
66 : struct get_handler_kind<T, Req, Res,
67 : typename std::enable_if<detail::is_invocable<
68 : T, route_result, Req&, Res&,
69 : system::error_code&>::value>::type>
70 : : std::integral_constant<int, 3>
71 : {
72 : };
73 :
74 : //------------------------------------------------
75 :
76 : // implementation for all routers
77 : class any_router
78 : {
79 : protected:
80 : struct layer;
81 : struct impl;
82 : struct any_handler;
83 :
84 : struct req_info
85 : {
86 : core::string_view& base_path;
87 : core::string_view& path;
88 : };
89 :
90 : using handler_ptr = std::unique_ptr<any_handler>;
91 :
92 : template<class, class, class>
93 : struct handler_impl;
94 :
95 : any_router() = default;
96 :
97 : BOOST_BEAST2_DECL ~any_router();
98 : BOOST_BEAST2_DECL any_router(any_router&&) noexcept;
99 : BOOST_BEAST2_DECL any_router(any_router const&) noexcept;
100 : BOOST_BEAST2_DECL any_router& operator=(any_router&&) noexcept;
101 : BOOST_BEAST2_DECL any_router& operator=(any_router const&) noexcept;
102 : BOOST_BEAST2_DECL any_router(req_info(*)(void*));
103 : BOOST_BEAST2_DECL std::size_t count() const noexcept;
104 : BOOST_BEAST2_DECL route_result dispatch_impl(http_proto::method,
105 : urls::url_view const&, void*, void*, route_state& st) const;
106 : BOOST_BEAST2_DECL route_result dispatch_impl(
107 : void*, void*, route_state&) const;
108 : BOOST_BEAST2_DECL route_result resume(
109 : void*, void*, route_state&, route_result const& ec) const;
110 : BOOST_BEAST2_DECL void append(bool, http_proto::method,
111 : core::string_view, handler_ptr);
112 : BOOST_BEAST2_DECL void append(core::string_view, any_router&);
113 : void append(bool, http_proto::method, core::string_view) {}
114 :
115 : impl* impl_ = nullptr;
116 : };
117 :
118 : //------------------------------------------------
119 :
120 : struct BOOST_SYMBOL_VISIBLE
121 : any_router::any_handler
122 : {
123 : BOOST_BEAST2_DECL virtual ~any_handler();
124 : BOOST_BEAST2_DECL virtual
125 : std::size_t count() const noexcept = 0 ;
126 : virtual route_result invoke(
127 : void*, void*, route_state&,
128 : system::error_code*) const = 0;
129 : };
130 :
131 : // wrapper for route handlers
132 : template<class Req, class Res, class H>
133 : struct any_router::
134 : handler_impl : any_handler
135 : {
136 : typename std::decay<H>::type h;
137 :
138 : template<class... Args>
139 9 : handler_impl(Args&&... args)
140 9 : : h(std::forward<Args>(args)...)
141 : {
142 9 : }
143 :
144 : std::size_t
145 0 : count() const noexcept override
146 : {
147 0 : return count(get_handler_kind<
148 0 : decltype(h), Req, Res>{});
149 : }
150 :
151 : route_result
152 7 : invoke(
153 : void* req, void* res,
154 : route_state& st,
155 : system::error_code* pec) const override
156 : {
157 14 : return invoke(
158 : *reinterpret_cast<Req*>(req),
159 : *reinterpret_cast<Res*>(res),
160 : st, pec, get_handler_kind<
161 7 : decltype(h), Req, Res>{});
162 : }
163 :
164 : private:
165 : std::size_t count(
166 : std::integral_constant<int, 0>) const = delete;
167 :
168 0 : std::size_t count(
169 : std::integral_constant<int, 1>) const noexcept
170 : {
171 0 : return 1;
172 : }
173 :
174 : std::size_t count(
175 : std::integral_constant<int, 2>) const noexcept
176 : {
177 : return h.count();
178 : }
179 :
180 : std::size_t count(
181 : std::integral_constant<int, 3>) const noexcept
182 : {
183 : return 1;
184 : }
185 :
186 : route_result
187 : invoke(Req&, Res&, route_state&,
188 : system::error_code*,
189 : std::integral_constant<int, 0>) const = delete;
190 :
191 : route_result
192 7 : invoke(Req& req, Res& res, route_state&,
193 : system::error_code* pec,
194 : std::integral_constant<int, 1>) const
195 : {
196 7 : if(! pec)
197 7 : return h(req, res);
198 0 : return route::next;
199 : }
200 :
201 : route_result
202 : invoke(Req& req, Res& res, route_state& st,
203 : system::error_code* pec,
204 : std::integral_constant<int, 2>) const
205 : {
206 : if(! pec)
207 : return h.dispatch(&req, &res, st);
208 : return route::next;
209 : }
210 :
211 : route_result
212 : invoke(Req& req, Res& res, route_state&,
213 : system::error_code* pec,
214 : std::integral_constant<int, 3>) const
215 : {
216 : if(pec != nullptr)
217 : return h(req, res, *pec);
218 : return route::next;
219 : }
220 : };
221 :
222 : } // detail
223 : } // beast2
224 : } // boost
225 :
226 : #endif
|