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/http_proto
8 : //
9 :
10 : #ifndef BOOST_HTTP_PROTO_SERVER_ROUTER_TYPES_HPP
11 : #define BOOST_HTTP_PROTO_SERVER_ROUTER_TYPES_HPP
12 :
13 : #include <boost/http_proto/detail/config.hpp>
14 : #include <boost/http_proto/method.hpp>
15 : #include <boost/http_proto/detail/except.hpp>
16 : #include <boost/core/detail/string_view.hpp>
17 : #include <boost/system/error_code.hpp>
18 : #include <exception>
19 : #include <string>
20 : #include <boost/http_proto/detail/config.hpp>
21 : #include <type_traits>
22 :
23 : namespace boost {
24 : namespace http_proto {
25 :
26 : /** The result type returned by a route handler.
27 :
28 : Route handlers use this type to report errors that prevent
29 : normal processing. A handler must never return a non-failing
30 : (i.e. `ec.failed() == false`) value. Returning a default-constructed
31 : `system::error_code` is disallowed; handlers that complete
32 : successfully must instead return a valid @ref route result.
33 : */
34 : using route_result = system::error_code;
35 :
36 : /** Route handler return values
37 :
38 : These values determine how the caller proceeds after invoking
39 : a route handler. Each enumerator represents a distinct control
40 : action—whether the request was handled, should continue to the
41 : next route, transfers ownership of the session, or signals that
42 : the connection should be closed.
43 : */
44 : enum class route
45 : {
46 : /** The handler requests that the connection be closed.
47 :
48 : No further requests will be processed. The caller should
49 : close the connection once the current response, if any,
50 : has been sent.
51 : */
52 : close = 1,
53 :
54 : /** The handler completed the request.
55 :
56 : The response has been fully transmitted, and no further
57 : handlers or routes will be invoked. The caller should continue
58 : by either reading the next request on a persistent connection
59 : or closing the session if it is not keep-alive.
60 : */
61 : complete,
62 :
63 : /** The handler detached from the session.
64 :
65 : Ownership of the session or stream has been transferred to
66 : the handler. The caller will not perform further I/O or manage
67 : the connection after this return value.
68 : */
69 : detach,
70 :
71 : /** The handler declined to process the request.
72 :
73 : The handler chose not to generate a response. The caller
74 : continues invoking the remaining handlers in the same route
75 : until one returns @ref send. If none do, the caller proceeds
76 : to evaluate the next matching route.
77 :
78 : This value is returned by @ref basic_router::dispatch if no
79 : handlers in any route handle the request.
80 : */
81 : next,
82 :
83 : /** The handler declined the current route.
84 :
85 : The handler wishes to skip any remaining handlers in the
86 : current route and move on to the next matching route. The
87 : caller stops invoking handlers in this route and resumes
88 : evaluation with the next candidate route.
89 : */
90 : next_route,
91 :
92 : /** The request was handled.
93 :
94 : The route handler processed the request and prepared
95 : the response serializer. The caller will send the response
96 : before reading the next request or closing the connection.
97 : */
98 : send
99 : };
100 :
101 : //------------------------------------------------
102 :
103 : } // http_proto
104 : namespace system {
105 : template<>
106 : struct is_error_code_enum<
107 : ::boost::http_proto::route>
108 : {
109 : static bool const value = true;
110 : };
111 : } // system
112 : namespace http_proto {
113 :
114 : namespace detail {
115 : struct BOOST_SYMBOL_VISIBLE route_cat_type
116 : : system::error_category
117 : {
118 : BOOST_HTTP_PROTO_DECL const char* name() const noexcept override;
119 : BOOST_HTTP_PROTO_DECL std::string message(int) const override;
120 : BOOST_HTTP_PROTO_DECL char const* message(
121 : int, char*, std::size_t) const noexcept override;
122 47 : BOOST_SYSTEM_CONSTEXPR route_cat_type()
123 47 : : error_category(0x51c90d393754ecdf )
124 : {
125 47 : }
126 : };
127 : BOOST_HTTP_PROTO_DECL extern route_cat_type route_cat;
128 : } // detail
129 :
130 : inline
131 : BOOST_SYSTEM_CONSTEXPR
132 : system::error_code
133 2337 : make_error_code(route ev) noexcept
134 : {
135 : return system::error_code{static_cast<
136 : std::underlying_type<route>::type>(ev),
137 2337 : detail::route_cat};
138 : }
139 :
140 : /** Return true if `rv` is a route result.
141 :
142 : A @ref route_result can hold any error code,
143 : and this function returns `true` only if `rv`
144 : holds a value from the @ref route enumeration.
145 : */
146 222 : inline bool is_route_result(
147 : route_result rv) noexcept
148 : {
149 222 : return &rv.category() == &detail::route_cat;
150 : }
151 :
152 : //------------------------------------------------
153 :
154 : class resumer;
155 :
156 : /** Function to detach a route handler from its session
157 :
158 : This holds an reference to an implementation
159 : which detaches the handler from its session.
160 : */
161 : class BOOST_HTTP_PROTO_DECL detacher
162 : {
163 : public:
164 : /** Base class of the implementation
165 : */
166 : struct BOOST_SYMBOL_VISIBLE
167 : owner
168 : {
169 : BOOST_HTTP_PROTO_DECL virtual resumer do_detach();
170 : virtual void do_resume(route_result const&) = 0;
171 : };
172 :
173 1 : detacher() = default;
174 : detacher(detacher const&) = default;
175 : detacher& operator=(detacher const&) = default;
176 :
177 : explicit
178 : detacher(
179 : owner& who) noexcept
180 : : p_(&who)
181 : {
182 : }
183 :
184 : /** Detach and invoke the given function
185 :
186 : The function will be invoked with this equivalent signature:
187 : @code
188 : void( resumer );
189 : @endcode
190 :
191 : @return A @ref route_result equal to @ref route::detach
192 : */
193 : template<class F>
194 : route_result
195 : operator()(F&& f);
196 :
197 : private:
198 : friend resumer;
199 : // Clang doesn't consider uninstantiated templates
200 : // when checking for unused private fields.
201 : owner* p_
202 : #if defined(__clang__)
203 : __attribute__((unused))
204 : #endif
205 : = nullptr;
206 : };
207 :
208 : //------------------------------------------------
209 :
210 : /** Function to resume a route handler's session
211 :
212 : This holds a reference to an implementation
213 : which resumes the handler's session. The resume
214 : function is returned by calling @ref detach.
215 : */
216 : class resumer
217 : {
218 : public:
219 : /** Constructor
220 :
221 : Default constructed resume functions will
222 : be empty. An exception is thrown when
223 : attempting to invoke an empty object.
224 : */
225 : resumer() = default;
226 :
227 : /** Constructor
228 :
229 : Copies of resume functions behave the same
230 : as the original
231 : */
232 : resumer(resumer const&) = default;
233 :
234 : /** Assignment
235 :
236 : Copies of resume functions behave the same
237 : as the original
238 : */
239 : resumer& operator=(resumer const&) = default;
240 :
241 : /** Constructor
242 : */
243 : explicit
244 : resumer(
245 : detacher::owner& who) noexcept
246 : : p_(&who)
247 : {
248 : }
249 :
250 : /** Resume the session
251 :
252 : A session is resumed as if the detached
253 : handler returned the route result in @p rv.
254 :
255 : @param ec The error code to resume with.
256 :
257 : @throw std::invalid_argument If the object is empty.
258 : */
259 : void operator()(
260 : route_result const& rv) const
261 : {
262 : if(! p_)
263 : detail::throw_invalid_argument();
264 : p_->do_resume(rv);
265 : }
266 :
267 : private:
268 : detacher::owner* p_
269 : #if defined(__clang__)
270 : __attribute__((unused))
271 : #endif
272 : = nullptr;
273 : };
274 :
275 : template<class F>
276 : auto
277 : detacher::
278 : operator()(F&& f) ->
279 : route_result
280 : {
281 : if(! p_)
282 : detail::throw_logic_error();
283 : std::forward<F>(f)(p_->do_detach());
284 : return route::detach;
285 : }
286 :
287 : //------------------------------------------------
288 :
289 : namespace detail {
290 : class any_router;
291 : } // detail
292 : template<class>
293 : class basic_router;
294 :
295 : BOOST_HTTP_PROTO_MSVC_WARNING_PUSH
296 : BOOST_HTTP_PROTO_MSVC_DISABLE_4251_4275
297 :
298 : /** Base class for request objects
299 :
300 : This is a required public base for any `Request`
301 : type used with @ref basic_router.
302 : */
303 : class BOOST_HTTP_PROTO_DECL route_params_base
304 : {
305 : public:
306 : /** The mount path of the current router
307 :
308 : This is the portion of the request path
309 : which was matched to select the handler.
310 : The remaining portion is available in
311 : @ref path.
312 : */
313 : core::string_view base_path;
314 :
315 : /** The current pathname, relative to the base path
316 : */
317 : core::string_view path;
318 :
319 : private:
320 : friend class /*detail::*/any_router;
321 : template<class>
322 : friend class basic_router;
323 : struct match_result;
324 : route_params_base& operator=(
325 : route_params_base const&) = delete;
326 :
327 : std::string verb_str_;
328 : std::string decoded_path_;
329 : system::error_code ec_;
330 : std::exception_ptr ep_;
331 : std::size_t pos_ = 0;
332 : std::size_t resume_ = 0;
333 : http_proto::method verb_ =
334 : http_proto::method::unknown;
335 : bool addedSlash_ = false;
336 : bool case_sensitive = false;
337 : bool strict = false;
338 : };
339 :
340 :
341 : BOOST_HTTP_PROTO_MSVC_WARNING_POP
342 :
343 : } // http_proto
344 : } // boost
345 :
346 : #endif
|