GCC Code Coverage Report


Directory: libs/beast2/
File: include/boost/beast2/server/basic_router.hpp
Date: 2025-11-13 15:50:44
Exec Total Coverage
Lines: 25 30 83.3%
Functions: 11 15 73.3%
Branches: 5 10 50.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/beast2
8 //
9
10 #ifndef BOOST_BEAST2_SERVER_BASIC_ROUTER_HPP
11 #define BOOST_BEAST2_SERVER_BASIC_ROUTER_HPP
12
13 #include <boost/beast2/detail/config.hpp>
14 #include <boost/beast2/server/detail/any_router.hpp>
15 #include <boost/beast2/detail/call_traits.hpp>
16 #include <boost/beast2/detail/type_traits.hpp>
17 #include <boost/http_proto/method.hpp>
18 #include <boost/url/url_view.hpp>
19 #include <boost/core/detail/string_view.hpp>
20 #include <type_traits>
21
22 namespace boost {
23 namespace beast2 {
24
25 struct route_state
26 {
27 private:
28 friend class detail::any_router;
29 template<class, class>
30 friend class basic_router;
31
32 std::size_t pos = 0;
33 std::size_t resume = 0;
34 route_result ec;
35 http_proto::method verb;
36 core::string_view verb_str;
37 std::string decoded_path;
38 };
39
40 //------------------------------------------------
41
42 /** A container for HTTP route handlers
43
44 The basic_router class template is used to
45 store and invoke route handlers based on
46 the request method and path.
47 Handlers are added to the router using
48 the member functions such as @ref get,
49 @ref post, and @ref all.
50 Handlers are invoked by calling the
51 function call operator with a request
52 and response object.
53
54 Express treats all route definitions as decoded path patterns, not raw URL-encoded ones.
55 So a literal %2F in the pattern string is indistinguishable from a literal / once Express builds the layer.
56 Therefore "/x%2Fz" is the same as "/x/z"
57
58 @par Example
59 @code
60 using router_type = basic_router<Req, Res>;
61 router_type router;
62 router.get("/hello",
63 [](Req& req, Res& res)
64 {
65 res.status(http_proto::status::ok);
66 res.set_body("Hello, world!");
67 return system::error_code{};
68 });
69 @endcode
70
71 @tparam Req The type of request object.
72 @tparam Res The type of response object.
73 */
74 template<class Req, class Res>
75 class basic_router : public detail::any_router
76 {
77 static constexpr http_proto::method
78 middleware = http_proto::method::unknown;
79
80 public:
81 /** The type of request object used in handlers
82
83 Route handlers must have this invocable signature
84 @code
85 system::error_code(Req&, Res&)
86 @endcode
87 */
88 using request_type = Req;
89
90 /** The type of response object used in handlers
91
92 Route handlers must have this invocable signature
93 @code
94 system::error_code(Req&, Res&)
95 @endcode
96 */
97 using response_type = Res;
98
99 /** Constructor
100 */
101 7 basic_router()
102 : any_router(
103 21 [](void* preq) -> req_info
104 {
105 14 auto& req = *reinterpret_cast<Req*>(preq);
106 14 return req_info{ req.base_path, req.path };
107
1/2
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
7 })
108 {
109 7 }
110
111 /** Constructor
112 */
113 template<
114 class OtherReq, class OtherRes,
115 class = typename std::enable_if<
116 detail::derived_from<Req, OtherReq>::value &&
117 detail::derived_from<Res, OtherRes>::value>::type
118 >
119 basic_router(
120 basic_router<OtherReq, OtherRes> const& other)
121 : any_router(other)
122 {
123 }
124
125 /** Add one or more global middleware handlers.
126
127 Each handler registered with this function runs for every incoming
128 request, regardless of its HTTP method or path. Handlers execute in
129 the order they were added, and may call `next()` to transfer control
130 to the subsequent handler in the chain.
131
132 This is equivalent to writing
133 @code
134 use( "/", h1, hn... );
135 @endcode
136 */
137 template<class H1, class... HN
138 , class = typename std::enable_if<! std::is_convertible<
139 H1, core::string_view>::value>::type
140 >
141 1 void use(H1&& h1, HN&&... hn)
142 {
143
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 use("/", std::forward<H1>(h1), std::forward<HN>(hn)...);
144 1 }
145
146 /** Add one or more middleware handlers for a path prefix.
147
148 Each handler registered with this function runs for every request
149 whose path begins with the specified prefix, regardless of the
150 request method. The prefix match is not strict: middleware attached
151 to `"/api"` will also match `"/api/users"` and `"/api/data"`.
152 Handlers execute in the order they were added, and may call `next()`
153 to transfer control to the subsequent handler.
154
155 This function behaves analogously to `app.use(path, ...)` in
156 Express.js. The registered middleware executes for requests matching
157 the prefix, and when registered before route handlers for the same
158 prefix, runs prior to those routes.
159
160 @par Example
161 @code
162 router.use("/api",
163 [](Request& req, Response& res)
164 {
165 if(!authenticate(req))
166 return res.setStatus(401), res.end("Unauthorized");
167 return res.next();
168 },
169 [](Request&, Response& res)
170 {
171 res.setHeader("X-Powered-By", "MyServer");
172 });
173 @endcode
174
175 @par Constraints
176 - `pattern` must be a valid path prefix; it may be empty to indicate
177 the root scope.
178 - Each handler must be callable with the signature
179 `void(Request&, Response&, NextHandler)`.
180 - Each handler must be copy- or move-constructible, depending on how
181 it is passed.
182
183 @throws Any exception thrown by a handler during execution.
184
185 @param pattern The path prefix to match. Middleware runs for any
186 request whose path begins with this prefix.
187 @param h0 The first middleware handler to install.
188 @param hn Additional middleware handlers to install, executed in
189 declaration order.
190
191 @return (none)
192 */
193 template<class H0, class... HN>
194 18 void use(
195 core::string_view pattern,
196 H0&& h0, HN... hn)
197 {
198
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
18 if(pattern.empty())
199 pattern = "/";
200 18 append(false, middleware, pattern,
201 std::forward<H0>(h0),
202 std::forward<HN>(hn)...);
203 18 }
204
205 template<class H0, class... HN>
206 void add(
207 http_proto::method method,
208 core::string_view pattern,
209 H0&& h0, HN&&... hn)
210 {
211 append(false, method, pattern,
212 std::forward<H0>(h0),
213 std::forward<HN>(hn)...);
214 }
215
216 /** Add an error handler
217 */
218 template<class H0, class... HN>
219 void err(
220 H0&& h0, HN&&... hn)
221 {
222 append_err(
223 std::forward<H0>(h0),
224 std::forward<HN>(hn)...);
225 }
226
227 /** Add a route handler matching all methods and the given pattern
228 The handler will run for every request matching the entire pattern.
229 */
230 template<class H0, class... HN>
231 void all(
232 core::string_view pattern,
233 H0&& h0, HN&&... hn)
234 {
235 return add(middleware, pattern,
236 std::forward<H0>(h0), std::forward<HN>(hn)...);
237 }
238
239 /** Add a GET handler
240 */
241 template<class H0, class... HN>
242 void get(
243 core::string_view pattern,
244 H0&& h0, HN&&... hn)
245 {
246 add(http_proto::method::get, pattern,
247 std::forward<H0>(h0), std::forward<HN>(hn)...);
248 }
249
250 template<class H0, class... HN>
251 void post(
252 core::string_view pattern,
253 H0&& h0, HN&&... hn)
254 {
255 add(http_proto::method::post, pattern,
256 std::forward<H0>(h0), std::forward<HN>(hn)...);
257 }
258
259 7 auto dispatch(
260 http_proto::method method,
261 urls::url_view const& url,
262 Req& req, Res& res, route_state& st) ->
263 route_result
264 {
265 7 return dispatch_impl(
266 7 method, url, &req, &res, st);
267 }
268
269 auto
270 resume(
271 Req& req,
272 Res& res,
273 route_result const& ec,
274 route_state& st) const ->
275 route_result
276 {
277 st.pos = 0;
278 st.ec = ec;
279 return dispatch_impl(&req, &res, st);
280 }
281
282 private:
283 template<class H>
284 18 handler_ptr make_handler(H&& h)
285 {
286 36 return handler_ptr(new handler_impl<
287 36 Req, Res, H>(std::forward<H>(h)));
288 }
289
290 9 void append(bool, http_proto::method,
291 core::string_view) const noexcept
292 {
293 9 }
294
295 template<class H0, class... HN>
296 18 void append(bool prefix, http_proto::method method,
297 core::string_view pat, H0&& h, HN&&... hn)
298 {
299
2/4
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 9 times.
✗ Branch 6 not taken.
18 any_router::append(prefix, method, pat,
300 make_handler<H0>(std::forward<H0>(h)));
301 18 append(prefix, method, pat, std::forward<HN>(hn)...);
302 18 }
303
304 template<class H0, class... HN>
305 void append_err(H0&& h, HN&&... hn)
306 {
307 append(true, middleware, {},
308 std::forward<H0>(h),
309 std::forward<HN>(hn)...);
310 }
311 };
312
313 } // beast2
314 } // boost
315
316 #endif
317