Skip to content

Commit 83dc972

Browse files
committed
chore: routing refactor
1 parent 1d80534 commit 83dc972

File tree

15 files changed

+1068
-681
lines changed

15 files changed

+1068
-681
lines changed

example/server/main.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ int server_main( int argc, char* argv[] )
6868
std::atoi(argv[4]));
6969

7070
//srv.wwwroot.use("/log", serve_log_admin(app));
71+
srv.wwwroot.use("/alt", serve_static( argv[3] ));
7172
srv.wwwroot.use("/", serve_static( argv[3] ));
7273

7374
app.start();

example/server/serve_detached.hpp

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,17 +42,20 @@ class serve_detached
4242
Request&,
4343
Response& res) const
4444
{
45-
auto resume = res.detach();
46-
asio::post(*tp_,
47-
[&, resume]()
45+
return res.detach(
46+
[&](resumer resume)
4847
{
49-
// Simulate some asynchronous work
50-
std::this_thread::sleep_for(std::chrono::seconds(1));
51-
res.status(http_proto::status::ok);
52-
res.set_body("Hello from serve_detached!\n");
53-
resume(error::success);
48+
asio::post(*tp_,
49+
[&, resume]()
50+
{
51+
// Simulate some asynchronous work
52+
std::this_thread::sleep_for(std::chrono::seconds(1));
53+
res.status(http_proto::status::ok);
54+
res.set_body("Hello from serve_detached!\n");
55+
resume(route::send);
56+
// resume( res.send("Hello from serve_detached!\n") );
57+
});
5458
});
55-
return error::detach;
5659
}
5760

5861
private:

include/boost/beast2/error.hpp

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,20 +24,6 @@ namespace beast2 {
2424
enum class error
2525
{
2626
success = 0,
27-
28-
// Routing
29-
30-
/** The route handler did not satisfy the request
31-
*/
32-
next,
33-
34-
/** The route handler is detaching from the session
35-
*/
36-
detach,
37-
38-
/** The route handler wants to close the connection
39-
*/
40-
close
4127
};
4228

4329
} // beast2

include/boost/beast2/server/basic_router.hpp

Lines changed: 122 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
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
{
2727
private:
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>
6575
class 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

7080
public:
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

223282
private:
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

Comments
 (0)