GCC Code Coverage Report


Directory: ./
File: libs/http/include/boost/http/server/router_types.hpp
Date: 2026-01-20 00:11:35
Exec Total Coverage
Lines: 15 15 100.0%
Functions: 3 3 100.0%
Branches: 5 6 83.3%

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
8 //
9
10 #ifndef BOOST_HTTP_SERVER_ROUTER_TYPES_HPP
11 #define BOOST_HTTP_SERVER_ROUTER_TYPES_HPP
12
13 #include <boost/http/detail/config.hpp>
14 #include <boost/http/method.hpp>
15 #include <boost/http/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 {
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 declined to process the request.
46
47 The handler chose not to generate a response. The caller
48 continues invoking the remaining handlers in the same route
49 until one returns @ref send. If none do, the caller proceeds
50 to evaluate the next matching route.
51
52 This value is returned by @ref router::dispatch if no
53 handlers in any route handle the request.
54 */
55 next,
56
57 /** The handler declined the current route.
58
59 The handler wishes to skip any remaining handlers in the
60 current route and move on to the next matching route. The
61 caller stops invoking handlers in this route and resumes
62 evaluation with the next candidate route.
63 */
64 next_route
65 };
66
67 //------------------------------------------------
68
69 } // http
70 namespace system {
71 template<>
72 struct is_error_code_enum<
73 ::boost::http::route>
74 {
75 static bool const value = true;
76 };
77 } // system
78 namespace http {
79
80 namespace detail {
81 struct BOOST_HTTP_SYMBOL_VISIBLE route_cat_type
82 : system::error_category
83 {
84 BOOST_HTTP_DECL const char* name() const noexcept override;
85 BOOST_HTTP_DECL std::string message(int) const override;
86 BOOST_HTTP_DECL char const* message(
87 int, char*, std::size_t) const noexcept override;
88 BOOST_SYSTEM_CONSTEXPR route_cat_type()
89 : error_category(0x51c90d393754ecdf )
90 {
91 }
92 };
93 BOOST_HTTP_DECL extern route_cat_type route_cat;
94 } // detail
95
96 inline
97 BOOST_SYSTEM_CONSTEXPR
98 system::error_code
99 155 make_error_code(route ev) noexcept
100 {
101 return system::error_code{static_cast<
102 std::underlying_type<route>::type>(ev),
103 155 detail::route_cat};
104 }
105
106 /** Return true if `rv` is a route result.
107
108 A @ref route_result can hold any error code,
109 and this function returns `true` only if `rv`
110 holds a value from the @ref route enumeration.
111 */
112 inline bool is_route_result(
113 route_result rv) noexcept
114 {
115 return &rv.category() == &detail::route_cat;
116 }
117
118 //------------------------------------------------
119
120 namespace detail {
121 class router_base;
122 } // detail
123 template<class> class router;
124
125 struct route_params_base_privates
126 {
127 struct match_result;
128
129 std::string verb_str_;
130 std::string decoded_path_;
131 system::error_code ec_;
132 std::exception_ptr ep_;
133 std::size_t pos_ = 0;
134 std::size_t resume_ = 0;
135 http::method verb_ =
136 http::method::unknown;
137 bool addedSlash_ = false;
138 bool case_sensitive = false;
139 bool strict = false;
140 char kind_ = 0; // dispatch mode, initialized by flat_router::dispatch()
141 };
142
143 /** Base class for request objects
144
145 This is a required public base for any `Request`
146 type used with @ref router.
147 */
148 class route_params_base : public route_params_base_privates
149 {
150 public:
151 /** Return true if the request method matches `m`
152 */
153 bool is_method(
154 http::method m) const noexcept
155 {
156 return verb_ == m;
157 }
158
159 /** Return true if the request method matches `s`
160 */
161 BOOST_HTTP_DECL
162 bool is_method(
163 core::string_view s) const noexcept;
164
165 /** The mount path of the current router
166
167 This is the portion of the request path
168 which was matched to select the handler.
169 The remaining portion is available in
170 @ref path.
171 */
172 core::string_view base_path;
173
174 /** The current pathname, relative to the base path
175 */
176 core::string_view path;
177
178 struct match_result;
179
180 private:
181 template<class>
182 friend class router;
183 friend struct route_params_access;
184
185 route_params_base& operator=(
186 route_params_base const&) = delete;
187 };
188
189 struct route_params_base::
190 match_result
191 {
192 73 void adjust_path(
193 route_params_base& p,
194 std::size_t n)
195 {
196 73 n_ = n;
197
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 34 times.
73 if(n_ == 0)
198 39 return;
199 34 p.base_path = {
200 p.base_path.data(),
201 34 p.base_path.size() + n_ };
202
2/2
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 21 times.
34 if(n_ < p.path.size())
203 {
204 13 p.path.remove_prefix(n_);
205 }
206 else
207 {
208 // append a soft slash
209 21 p.path = { p.decoded_path_.data() +
210 21 p.decoded_path_.size() - 1, 1};
211
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
21 BOOST_ASSERT(p.path == "/");
212 }
213 }
214
215 void restore_path(
216 route_params_base& p)
217 {
218 if( n_ > 0 &&
219 p.addedSlash_ &&
220 p.path.data() ==
221 p.decoded_path_.data() +
222 p.decoded_path_.size() - 1)
223 {
224 // remove soft slash
225 p.path = {
226 p.base_path.data() +
227 p.base_path.size(), 0 };
228 }
229 p.base_path.remove_suffix(n_);
230 p.path = {
231 p.path.data() - n_,
232 p.path.size() + n_ };
233 }
234
235 private:
236 std::size_t n_ = 0; // chars moved from path to base_path
237 };
238
239
240 namespace detail {
241
242 struct route_params_access
243 {
244 route_params_base& rp;
245
246 24 route_params_base_privates* operator->() const noexcept
247 {
248 24 return &rp;
249 }
250 };
251
252 } // detail
253
254 } // http
255 } // boost
256
257 #endif
258