1515#include < boost/beast2/detail/call_traits.hpp>
1616#include < boost/beast2/detail/type_traits.hpp>
1717#include < boost/http_proto/method.hpp>
18- #include < boost/url/segments_encoded_view .hpp>
18+ #include < boost/url/url_view .hpp>
1919#include < boost/core/detail/string_view.hpp>
2020#include < type_traits>
2121
@@ -26,17 +26,21 @@ struct route_state
2626{
2727private:
2828 friend class detail ::any_router;
29- template <class Res , class Req >
29+ template <class , class >
3030 friend class basic_router ;
3131
3232 std::size_t pos = 0 ;
3333 std::size_t resume = 0 ;
34- system::error_code ec;
34+ route_result ec;
35+ http_proto::method verb;
36+ core::string_view verb_str;
37+ std::string decoded_path;
3538};
3639
3740// ------------------------------------------------
3841
3942/* * A container for HTTP route handlers
43+
4044 The basic_router class template is used to
4145 store and invoke route handlers based on
4246 the request method and path.
@@ -46,99 +50,154 @@ struct route_state
4650 Handlers are invoked by calling the
4751 function call operator with a request
4852 and response object.
49- @tparam Request The type of request object.
50- @tparam Response The type of 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+
5158 @par Example
5259 @code
53- using router_type = basic_router<Request, Response >;
60+ using router_type = basic_router<Req, Res >;
5461 router_type router;
5562 router.get("/hello",
56- [](Request & req, Response & res)
63+ [](Req & req, Res & res)
5764 {
5865 res.status(http_proto::status::ok);
5966 res.set_body("Hello, world!");
6067 return system::error_code{};
6168 });
6269 @endcode
70+
71+ @tparam Req The type of request object.
72+ @tparam Res The type of response object.
6373*/
64- template <class Request , class Response >
74+ template <class Req , class Res >
6575class basic_router : public detail ::any_router
6676{
67- static constexpr http_proto::method all_methods =
68- http_proto::method::unknown;
77+ static constexpr http_proto::method
78+ middleware = http_proto::method::unknown;
6979
7080public:
7181 /* * The type of request object used in handlers
7282
7383 Route handlers must have this invocable signature
7484 @code
75- system::error_code(Request &, Response &)
85+ system::error_code(Req &, Res &)
7686 @endcode
7787 */
78- using request_type = Request ;
88+ using request_type = Req ;
7989
8090 /* * The type of response object used in handlers
8191
8292 Route handlers must have this invocable signature
8393 @code
84- system::error_code(Request &, Response &)
94+ system::error_code(Req &, Res &)
8595 @endcode
8696 */
87- using response_type = Response ;
97+ using response_type = Res ;
8898
8999 /* * Constructor
90100 */
91101 basic_router ()
92102 : any_router(
93103 [](void * preq) -> req_info
94104 {
95- auto & req = *reinterpret_cast <Request*>(preq);
96- req_info ri;
97- ri.method = req.method ;
98- ri.base_path = &req.base_path ;
99- ri.suffix_path = &req.suffix_path ;
100- ri.path = &req.path ;
101- return ri;
105+ auto & req = *reinterpret_cast <Req*>(preq);
106+ return req_info{ req.base_path , req.path };
102107 })
103108 {
104109 }
105110
106111 /* * Constructor
107112 */
108113 template <
109- class DerivedRequest , class DerivedResponse ,
114+ class OtherReq , class OtherRes ,
110115 class = typename std::enable_if<
111- detail::derived_from<Request, DerivedRequest >::value &&
112- detail::derived_from<Response, DerivedResponse >::value>::type
116+ detail::derived_from<Req, OtherReq >::value &&
117+ detail::derived_from<Res, OtherRes >::value>::type
113118 >
114119 basic_router (
115- basic_router<DerivedRequest, DerivedResponse > const & other)
120+ basic_router<OtherReq, OtherRes > const & other)
116121 : any_router(other)
117122 {
118123 }
119124
120- /* * Add a global middleware
121- The handler will run for every request.
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
122136 */
123- template <class H0 , class ... HN
124- , class = typename std::enable_if<
125- ! std::is_convertible<H0 , core::string_view>::value>::type
137+ template <class H1 , class ... HN
138+ , class = typename std::enable_if<! std::is_convertible <
139+ H1 , core::string_view>::value>::type
126140 >
127- void use (H0 && h0 , HN&&... hn)
141+ void use (H1 && h1 , HN&&... hn)
128142 {
129- append (true , all_methods, " " ,
130- std::forward<H0>(h0),
131- std::forward<HN>(hn)...);
143+ use (" /" , std::forward<H1>(h1), std::forward<HN>(hn)...);
132144 }
133145
134- /* * Add a mounted middleware
135- The handler will run for every request matching the given prefix.
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)
136192 */
137193 template <class H0 , class ... HN>
138- void use (core::string_view pattern,
194+ void use (
195+ core::string_view pattern,
139196 H0&& h0, HN... hn)
140197 {
141- append (true , all_methods, pattern,
198+ if (pattern.empty ())
199+ pattern = " /" ;
200+ append (false , middleware, pattern,
142201 std::forward<H0>(h0),
143202 std::forward<HN>(hn)...);
144203 }
@@ -173,7 +232,7 @@ class basic_router : public detail::any_router
173232 core::string_view pattern,
174233 H0&& h0, HN&&... hn)
175234 {
176- return add (all_methods , pattern,
235+ return add (middleware , pattern,
177236 std::forward<H0>(h0), std::forward<HN>(hn)...);
178237 }
179238
@@ -197,32 +256,39 @@ class basic_router : public detail::any_router
197256 std::forward<H0>(h0), std::forward<HN>(hn)...);
198257 }
199258
200- auto
201- operator ()(
202- Request& req,
203- Response& res,
204- route_state& st) const ->
205- system::error_code
259+ auto dispatch (
260+ http_proto::method method,
261+ urls::url_view const & url,
262+ Req& req, Res& res, route_state& st) ->
263+ route_result
206264 {
207- return invoke (&req, &res, st);
265+ return dispatch_impl (
266+ method, url, &req, &res, st);
208267 }
209268
210269 auto
211270 resume (
212- Request & req,
213- Response & res,
214- system::error_code const & ec,
271+ Req & req,
272+ Res & res,
273+ route_result const & ec,
215274 route_state& st) const ->
216- system::error_code
275+ route_result
217276 {
218277 st.pos = 0 ;
219278 st.ec = ec;
220- return invoke (&req, &res, st);
279+ return dispatch_impl (&req, &res, st);
221280 }
222281
223282private:
283+ template <class H >
284+ handler_ptr make_handler (H&& h)
285+ {
286+ return handler_ptr (new handler_impl<
287+ Req, Res, H>(std::forward<H>(h)));
288+ }
289+
224290 void append (bool , http_proto::method,
225- core::string_view ) const noexcept
291+ core::string_view) const noexcept
226292 {
227293 }
228294
@@ -231,24 +297,17 @@ class basic_router : public detail::any_router
231297 core::string_view pat, H0&& h, HN&&... hn)
232298 {
233299 any_router::append (prefix, method, pat,
234- handler_ptr (new handler_impl<Request, Response, H0>(
235- std::forward<H0>(h))));
300+ make_handler<H0>(std::forward<H0>(h)));
236301 append (prefix, method, pat, std::forward<HN>(hn)...);
237302 }
238303
239- void append_err () const noexcept
240- {
241- }
242-
243304 template <class H0 , class ... HN>
244305 void append_err (H0&& h, HN&&... hn)
245306 {
246- any_router::append_err (errfn_ptr (new
247- errfn_impl<Request, Response, H0>(
248- std::forward<H0>(h))));
249- append_err (std::forward<HN>(hn)...);
307+ append (true , middleware, {},
308+ std::forward<H0>(h),
309+ std::forward<HN>(hn)...);
250310 }
251-
252311};
253312
254313} // beast2
0 commit comments