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