GCC Code Coverage Report


Directory: ./
File: libs/http_proto/include/boost/http_proto/server/router_types.hpp
Date: 2025-12-25 12:14:37
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 42 BOOST_SYSTEM_CONSTEXPR route_cat_type()
124 42 : error_category(0x51c90d393754ecdf )
125 {
126 42 }
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 virtual resumer do_suspend();
171 virtual void do_resume(route_result const&) = 0;
172 };
173
174 1 suspender() = default;
175 suspender(suspender const&) = default;
176 suspender& operator=(suspender const&) = default;
177
178 explicit
179 suspender(
180 owner& who) noexcept
181 : p_(&who)
182 {
183 }
184
185 /** Suspend and invoke the given function
186
187 The function will be invoked with this equivalent signature:
188 @code
189 void( resumer );
190 @endcode
191
192 @return A @ref route_result equal to @ref route::suspend
193 */
194 template<class F>
195 route_result
196 operator()(F&& f);
197
198 private:
199 friend resumer;
200 // Clang doesn't consider uninstantiated templates
201 // when checking for unused private fields.
202 owner* p_
203 #if defined(__clang__)
204 __attribute__((unused))
205 #endif
206 = nullptr;
207 };
208
209 //------------------------------------------------
210
211 /** Function to resume a suspended route.
212
213 This holds a reference to an implementation which resumes the handler's
214 session. The resume function is typically obtained at the time the
215 route is suspended.
216 */
217 class resumer
218 {
219 public:
220 /** Constructor
221
222 Default constructed resume functions will
223 be empty. An exception is thrown when
224 attempting to invoke an empty object.
225 */
226 resumer() = default;
227
228 /** Constructor
229
230 Copies of resume functions behave the same
231 as the original
232 */
233 resumer(resumer const&) = default;
234
235 /** Assignment
236
237 Copies of resume functions behave the same
238 as the original
239 */
240 resumer& operator=(resumer const&) = default;
241
242 /** Constructor
243 */
244 explicit
245 resumer(
246 suspender::owner& who) noexcept
247 : p_(&who)
248 {
249 }
250
251 /** Resume the session
252
253 When a session is resumed, routing continues as if the handler
254 had returned the @ref route_result contained in @p rv.
255
256 @param ec The error code to resume with.
257
258 @throw std::invalid_argument If the object is empty.
259 */
260 void operator()(
261 route_result const& rv) const
262 {
263 if(! p_)
264 detail::throw_invalid_argument();
265 p_->do_resume(rv);
266 }
267
268 private:
269 suspender::owner* p_
270 #if defined(__clang__)
271 __attribute__((unused))
272 #endif
273 = nullptr;
274 };
275
276 template<class F>
277 auto
278 suspender::
279 operator()(F&& f) ->
280 route_result
281 {
282 if(! p_)
283 detail::throw_logic_error();
284 std::forward<F>(f)(p_->do_suspend());
285 return route::suspend;
286 }
287
288 //------------------------------------------------
289
290 namespace detail {
291 class any_router;
292 } // detail
293 template<class>
294 class basic_router;
295
296 /** Base class for request objects
297
298 This is a required public base for any `Request`
299 type used with @ref basic_router.
300 */
301 class route_params_base
302 {
303 public:
304 /** Return true if the request method matches `m`
305 */
306 2 bool is_method(
307 http_proto::method m) const noexcept
308 {
309 2 return verb_ == m;
310 }
311
312 /** Return true if the request method matches `s`
313 */
314 BOOST_HTTP_PROTO_DECL
315 bool is_method(
316 core::string_view s) const noexcept;
317
318 /** The mount path of the current router
319
320 This is the portion of the request path
321 which was matched to select the handler.
322 The remaining portion is available in
323 @ref path.
324 */
325 core::string_view base_path;
326
327 /** The current pathname, relative to the base path
328 */
329 core::string_view path;
330
331 private:
332 friend class /*detail::*/any_router;
333 template<class>
334 friend class basic_router;
335 struct match_result;
336 route_params_base& operator=(
337 route_params_base const&) = delete;
338
339 std::string verb_str_;
340 std::string decoded_path_;
341 system::error_code ec_;
342 std::exception_ptr ep_;
343 std::size_t pos_ = 0;
344 std::size_t resume_ = 0;
345 http_proto::method verb_ =
346 http_proto::method::unknown;
347 bool addedSlash_ = false;
348 bool case_sensitive = false;
349 bool strict = false;
350 };
351
352 } // http_proto
353 } // boost
354
355 #endif
356