GCC Code Coverage Report


Directory: ./
File: libs/http_proto/include/boost/http_proto/server/router_types.hpp
Date: 2025-12-30 20:59:34
Exec Total Coverage
Lines: 10 10 100.0%
Functions: 5 5 100.0%
Branches: 0 0 -%

Line Branch Exec Source
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 is suspending the route.
63
64 When the handler returns this value, the router is placed into
65 a suspended state which can later be reactivated by invoking
66 @ref basic_router::resume. Depending on the implementation,
67 this might detach the handler from the session until it is
68 resumed.
69 */
70 suspend,
71
72 /** The handler declined to process the request.
73
74 The handler chose not to generate a response. The caller
75 continues invoking the remaining handlers in the same route
76 until one returns @ref send. If none do, the caller proceeds
77 to evaluate the next matching route.
78
79 This value is returned by @ref basic_router::dispatch if no
80 handlers in any route handle the request.
81 */
82 next,
83
84 /** The handler declined the current route.
85
86 The handler wishes to skip any remaining handlers in the
87 current route and move on to the next matching route. The
88 caller stops invoking handlers in this route and resumes
89 evaluation with the next candidate route.
90 */
91 next_route,
92
93 /** The request was handled.
94
95 The route handler processed the request and prepared
96 the response serializer. The caller will send the response
97 before reading the next request or closing the connection.
98 */
99 send
100 };
101
102 //------------------------------------------------
103
104 } // http_proto
105 namespace system {
106 template<>
107 struct is_error_code_enum<
108 ::boost::http_proto::route>
109 {
110 static bool const value = true;
111 };
112 } // system
113 namespace http_proto {
114
115 namespace detail {
116 struct BOOST_HTTP_PROTO_SYMBOL_VISIBLE route_cat_type
117 : system::error_category
118 {
119 BOOST_HTTP_PROTO_DECL const char* name() const noexcept override;
120 BOOST_HTTP_PROTO_DECL std::string message(int) const override;
121 BOOST_HTTP_PROTO_DECL char const* message(
122 int, char*, std::size_t) const noexcept override;
123 43 BOOST_SYSTEM_CONSTEXPR route_cat_type()
124 43 : error_category(0x51c90d393754ecdf )
125 {
126 43 }
127 };
128 BOOST_HTTP_PROTO_DECL extern route_cat_type route_cat;
129 } // detail
130
131 inline
132 BOOST_SYSTEM_CONSTEXPR
133 system::error_code
134 2357 make_error_code(route ev) noexcept
135 {
136 return system::error_code{static_cast<
137 std::underlying_type<route>::type>(ev),
138 2357 detail::route_cat};
139 }
140
141 /** Return true if `rv` is a route result.
142
143 A @ref route_result can hold any error code,
144 and this function returns `true` only if `rv`
145 holds a value from the @ref route enumeration.
146 */
147 223 inline bool is_route_result(
148 route_result rv) noexcept
149 {
150 223 return &rv.category() == &detail::route_cat;
151 }
152
153 //------------------------------------------------
154
155 class resumer;
156
157 /** Function to suspend a route handler from its session
158
159 This holds an reference to an implementation
160 which suspends the router which dispatched the handler.
161 */
162 class suspender
163 {
164 public:
165 /** Base class of the implementation
166 */
167 struct BOOST_HTTP_PROTO_SYMBOL_VISIBLE
168 owner
169 {
170 BOOST_HTTP_PROTO_DECL
171 virtual resumer do_suspend();
172 virtual void do_resume(route_result const&) = 0;
173 virtual void do_resume(std::exception_ptr) = 0;
174 };
175
176 1 suspender() = default;
177 suspender(suspender const&) = default;
178 suspender& operator=(suspender const&) = default;
179
180 explicit
181 suspender(
182 owner& who) noexcept
183 : p_(&who)
184 {
185 }
186
187 /** Suspend and invoke the given function
188
189 The function will be invoked with this equivalent signature:
190 @code
191 void( resumer );
192 @endcode
193
194 @return A @ref route_result equal to @ref route::suspend
195 */
196 template<class F>
197 route_result
198 operator()(F&& f);
199
200 private:
201 friend resumer;
202 // Clang doesn't consider uninstantiated templates
203 // when checking for unused private fields.
204 owner* p_
205 #if defined(__clang__)
206 __attribute__((unused))
207 #endif
208 = nullptr;
209 };
210
211 //------------------------------------------------
212
213 /** Function to resume a suspended route.
214
215 This holds a reference to an implementation which resumes the handler's
216 session. The resume function is typically obtained at the time the
217 route is suspended.
218 */
219 class resumer
220 {
221 public:
222 /** Constructor
223
224 Default constructed resume functions will
225 be empty. An exception is thrown when
226 attempting to invoke an empty object.
227 */
228 resumer() = default;
229
230 /** Constructor
231
232 Copies of resume functions behave the same
233 as the original
234 */
235 resumer(resumer const&) = default;
236
237 /** Assignment
238
239 Copies of resume functions behave the same
240 as the original
241 */
242 resumer& operator=(resumer const&) = default;
243
244 /** Constructor
245 */
246 explicit
247 resumer(
248 suspender::owner& who) noexcept
249 : p_(&who)
250 {
251 }
252
253 /** Resume the session
254
255 When a session is resumed, routing continues as if the handler
256 had returned the @ref route_result contained in @p rv.
257
258 @param rv The route result to resume with.
259
260 @throw std::invalid_argument If the object is empty.
261 */
262 void operator()(
263 route_result const& rv) const
264 {
265 if(! p_)
266 detail::throw_invalid_argument();
267 p_->do_resume(rv);
268 }
269
270 /** Resume the session with an exception
271
272 When a session is resumed with an exception, the exception
273 is propagated through the router's error handling mechanism.
274
275 @param ep The exception to propagate.
276
277 @throw std::invalid_argument If the object is empty.
278 */
279 void operator()(
280 std::exception_ptr ep) const
281 {
282 if(! p_)
283 detail::throw_invalid_argument();
284 p_->do_resume(ep);
285 }
286
287 private:
288 suspender::owner* p_
289 #if defined(__clang__)
290 __attribute__((unused))
291 #endif
292 = nullptr;
293 };
294
295 template<class F>
296 auto
297 suspender::
298 operator()(F&& f) ->
299 route_result
300 {
301 if(! p_)
302 detail::throw_logic_error();
303 std::forward<F>(f)(p_->do_suspend());
304 return route::suspend;
305 }
306
307 //------------------------------------------------
308
309 namespace detail {
310 class any_router;
311 } // detail
312 template<class>
313 class basic_router;
314
315 /** Base class for request objects
316
317 This is a required public base for any `Request`
318 type used with @ref basic_router.
319 */
320 class route_params_base
321 {
322 public:
323 /** Return true if the request method matches `m`
324 */
325 2 bool is_method(
326 http_proto::method m) const noexcept
327 {
328 2 return verb_ == m;
329 }
330
331 /** Return true if the request method matches `s`
332 */
333 BOOST_HTTP_PROTO_DECL
334 bool is_method(
335 core::string_view s) const noexcept;
336
337 /** The mount path of the current router
338
339 This is the portion of the request path
340 which was matched to select the handler.
341 The remaining portion is available in
342 @ref path.
343 */
344 core::string_view base_path;
345
346 /** The current pathname, relative to the base path
347 */
348 core::string_view path;
349
350 private:
351 friend class /*detail::*/any_router;
352 template<class>
353 friend class basic_router;
354 struct match_result;
355 route_params_base& operator=(
356 route_params_base const&) = delete;
357
358 std::string verb_str_;
359 std::string decoded_path_;
360 system::error_code ec_;
361 std::exception_ptr ep_;
362 std::size_t pos_ = 0;
363 std::size_t resume_ = 0;
364 http_proto::method verb_ =
365 http_proto::method::unknown;
366 bool addedSlash_ = false;
367 bool case_sensitive = false;
368 bool strict = false;
369 };
370
371 } // http_proto
372 } // boost
373
374 #endif
375