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