1  
//
1  
//
2  
// Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
2  
// Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
3  
//
3  
//
4  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
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)
5  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6  
//
6  
//
7  
// Official repository: https://github.com/cppalliance/http
7  
// Official repository: https://github.com/cppalliance/http
8  
//
8  
//
9  

9  

10  
#ifndef BOOST_HTTP_SERVER_ROUTER_HPP
10  
#ifndef BOOST_HTTP_SERVER_ROUTER_HPP
11  
#define BOOST_HTTP_SERVER_ROUTER_HPP
11  
#define BOOST_HTTP_SERVER_ROUTER_HPP
12  

12  

13  
#include <boost/http/detail/config.hpp>
13  
#include <boost/http/detail/config.hpp>
14  
#include <boost/http/server/route_handler.hpp>
14  
#include <boost/http/server/route_handler.hpp>
15  
#include <boost/http/server/detail/router_base.hpp>
15  
#include <boost/http/server/detail/router_base.hpp>
 
16 +
#include <boost/http/field.hpp>
16  
#include <boost/http/method.hpp>
17  
#include <boost/http/method.hpp>
 
18 +
#include <boost/http/status.hpp>
17  
#include <boost/url/url_view.hpp>
19  
#include <boost/url/url_view.hpp>
18  
#include <boost/mp11/algorithm.hpp>
20  
#include <boost/mp11/algorithm.hpp>
19  
#include <boost/assert.hpp>
21  
#include <boost/assert.hpp>
20  
#include <exception>
22  
#include <exception>
21  
#include <string_view>
23  
#include <string_view>
22  
#include <type_traits>
24  
#include <type_traits>
23  

25  

24  
namespace boost {
26  
namespace boost {
25  
namespace http {
27  
namespace http {
26  

28  

27  
template<class, class> class router;
29  
template<class, class> class router;
28  

30  

29  
/** Configuration options for HTTP routers.
31  
/** Configuration options for HTTP routers.
30  
*/
32  
*/
31  
struct router_options
33  
struct router_options
32  
{
34  
{
33  
    /** Constructor.
35  
    /** Constructor.
34  

36  

35  
        Routers constructed with default options inherit the values of
37  
        Routers constructed with default options inherit the values of
36  
        @ref case_sensitive and @ref strict from the parent router.
38  
        @ref case_sensitive and @ref strict from the parent router.
37  
        If there is no parent, both default to `false`.
39  
        If there is no parent, both default to `false`.
38  
        The value of @ref merge_params always defaults to `false`
40  
        The value of @ref merge_params always defaults to `false`
39  
        and is never inherited.
41  
        and is never inherited.
40  
    */
42  
    */
41  
    router_options() = default;
43  
    router_options() = default;
42  

44  

43  
    /** Set whether to merge parameters from parent routers.
45  
    /** Set whether to merge parameters from parent routers.
44  

46  

45  
        This setting controls whether route parameters defined on parent
47  
        This setting controls whether route parameters defined on parent
46  
        routers are made available in nested routers. It is not inherited
48  
        routers are made available in nested routers. It is not inherited
47  
        and always defaults to `false`.
49  
        and always defaults to `false`.
48  

50  

49  
        @par Example
51  
        @par Example
50  
        @code
52  
        @code
51  
        router r( router_options()
53  
        router r( router_options()
52  
            .merge_params( true )
54  
            .merge_params( true )
53  
            .case_sensitive( true )
55  
            .case_sensitive( true )
54  
            .strict( false ) );
56  
            .strict( false ) );
55  
        @endcode
57  
        @endcode
56  

58  

57  
        @param value `true` to merge parameters from parent routers.
59  
        @param value `true` to merge parameters from parent routers.
58  

60  

59  
        @return A reference to `*this` for chaining.
61  
        @return A reference to `*this` for chaining.
60  
    */
62  
    */
61  
    router_options&
63  
    router_options&
62  
    merge_params(
64  
    merge_params(
63  
        bool value) noexcept
65  
        bool value) noexcept
64  
    {
66  
    {
65  
        v_ = (v_ & ~1) | (value ? 1 : 0);
67  
        v_ = (v_ & ~1) | (value ? 1 : 0);
66  
        return *this;
68  
        return *this;
67  
    }
69  
    }
68  

70  

69  
    /** Set whether pattern matching is case-sensitive.
71  
    /** Set whether pattern matching is case-sensitive.
70  

72  

71  
        When this option is not set explicitly, the value is inherited
73  
        When this option is not set explicitly, the value is inherited
72  
        from the parent router or defaults to `false` if there is no parent.
74  
        from the parent router or defaults to `false` if there is no parent.
73  

75  

74  
        @par Example
76  
        @par Example
75  
        @code
77  
        @code
76  
        router r( router_options()
78  
        router r( router_options()
77  
            .case_sensitive( true )
79  
            .case_sensitive( true )
78  
            .strict( true ) );
80  
            .strict( true ) );
79  
        @endcode
81  
        @endcode
80  

82  

81  
        @param value `true` to perform case-sensitive path matching.
83  
        @param value `true` to perform case-sensitive path matching.
82  

84  

83  
        @return A reference to `*this` for chaining.
85  
        @return A reference to `*this` for chaining.
84  
    */
86  
    */
85  
    router_options&
87  
    router_options&
86  
    case_sensitive(
88  
    case_sensitive(
87  
        bool value) noexcept
89  
        bool value) noexcept
88  
    {
90  
    {
89  
        if(value)
91  
        if(value)
90  
            v_ = (v_ & ~6) | 2;
92  
            v_ = (v_ & ~6) | 2;
91  
        else
93  
        else
92  
            v_ = (v_ & ~6) | 4;
94  
            v_ = (v_ & ~6) | 4;
93  
        return *this;
95  
        return *this;
94  
    }
96  
    }
95  

97  

96  
    /** Set whether pattern matching is strict.
98  
    /** Set whether pattern matching is strict.
97  

99  

98  
        When this option is not set explicitly, the value is inherited
100  
        When this option is not set explicitly, the value is inherited
99  
        from the parent router or defaults to `false` if there is no parent.
101  
        from the parent router or defaults to `false` if there is no parent.
100  
        Strict matching treats a trailing slash as significant:
102  
        Strict matching treats a trailing slash as significant:
101  
        the pattern `"/api"` matches `"/api"` but not `"/api/"`.
103  
        the pattern `"/api"` matches `"/api"` but not `"/api/"`.
102  
        When strict matching is disabled, these paths are treated
104  
        When strict matching is disabled, these paths are treated
103  
        as equivalent.
105  
        as equivalent.
104  

106  

105  
        @par Example
107  
        @par Example
106  
        @code
108  
        @code
107  
        router r( router_options()
109  
        router r( router_options()
108  
            .strict( true )
110  
            .strict( true )
109  
            .case_sensitive( false ) );
111  
            .case_sensitive( false ) );
110  
        @endcode
112  
        @endcode
111  

113  

112  
        @param value `true` to enable strict path matching.
114  
        @param value `true` to enable strict path matching.
113  

115  

114  
        @return A reference to `*this` for chaining.
116  
        @return A reference to `*this` for chaining.
115  
    */
117  
    */
116  
    router_options&
118  
    router_options&
117  
    strict(
119  
    strict(
118  
        bool value) noexcept
120  
        bool value) noexcept
119  
    {
121  
    {
120  
        if(value)
122  
        if(value)
121  
            v_ = (v_ & ~24) | 8;
123  
            v_ = (v_ & ~24) | 8;
122  
        else
124  
        else
123  
            v_ = (v_ & ~24) | 16;
125  
            v_ = (v_ & ~24) | 16;
124  
        return *this;
126  
        return *this;
125  
    }
127  
    }
126  

128  

127  
private:
129  
private:
128  
    template<class, class> friend class router;
130  
    template<class, class> friend class router;
129  
    unsigned int v_ = 0;
131  
    unsigned int v_ = 0;
130  
};
132  
};
131  

133  

132  
//-----------------------------------------------
134  
//-----------------------------------------------
133  

135  

134  
/** The default handler transform.
136  
/** The default handler transform.
135  

137  

136  
    Passes each handler through unchanged. This is the
138  
    Passes each handler through unchanged. This is the
137  
    default value of the `HT` template parameter on
139  
    default value of the `HT` template parameter on
138  
    @ref router.
140  
    @ref router.
139  
*/
141  
*/
140  
struct identity
142  
struct identity
141  
{
143  
{
142  
    template< class T >
144  
    template< class T >
143  
    T operator()( T&& t ) const
145  
    T operator()( T&& t ) const
144  
    {
146  
    {
145  
        return std::forward<T>(t);
147  
        return std::forward<T>(t);
146  
    }
148  
    }
147  
};
149  
};
148  

150  

149  
/** A container for HTTP route handlers.
151  
/** A container for HTTP route handlers.
150  

152  

151  
    `router` objects store and dispatch route handlers based on the
153  
    `router` objects store and dispatch route handlers based on the
152  
    HTTP method and path of an incoming request. Routes are added with a
154  
    HTTP method and path of an incoming request. Routes are added with a
153  
    path pattern, method, and an associated handler, and the router is then
155  
    path pattern, method, and an associated handler, and the router is then
154  
    used to dispatch the appropriate handler.
156  
    used to dispatch the appropriate handler.
155  

157  

156  
    Routes are flattened into contiguous arrays as they are added, so
158  
    Routes are flattened into contiguous arrays as they are added, so
157  
    dispatch is always cache-friendly regardless of nesting depth.
159  
    dispatch is always cache-friendly regardless of nesting depth.
158  

160  

159  
    Patterns used to create route definitions have percent-decoding applied
161  
    Patterns used to create route definitions have percent-decoding applied
160  
    when handlers are mounted. A literal "%2F" in the pattern string is
162  
    when handlers are mounted. A literal "%2F" in the pattern string is
161  
    indistinguishable from a literal '/'. For example, "/x%2Fz" is the
163  
    indistinguishable from a literal '/'. For example, "/x%2Fz" is the
162  
    same as "/x/z" when used as a pattern.
164  
    same as "/x/z" when used as a pattern.
163  

165  

164  
    @par Example
166  
    @par Example
165  
    @code
167  
    @code
166  
    router<route_params> r;
168  
    router<route_params> r;
167  
    r.get( "/hello",
169  
    r.get( "/hello",
168  
        []( route_params& p )
170  
        []( route_params& p )
169  
        {
171  
        {
170  
            p.res.status( status::ok );
172  
            p.res.status( status::ok );
171  
            p.res.set_body( "Hello, world!" );
173  
            p.res.set_body( "Hello, world!" );
172  
            return route_done;
174  
            return route_done;
173  
        } );
175  
        } );
174  
    @endcode
176  
    @endcode
175  

177  

176  
    Router objects use shared ownership via `shared_ptr`. Copies refer
178  
    Router objects use shared ownership via `shared_ptr`. Copies refer
177  
    to the same underlying data. Modifying a router after it has been
179  
    to the same underlying data. Modifying a router after it has been
178  
    copied is not permitted and results in undefined behavior.
180  
    copied is not permitted and results in undefined behavior.
179  

181  

180  
    @par Path Pattern Syntax
182  
    @par Path Pattern Syntax
181  

183  

182  
    Route patterns define which request paths match a route. Patterns
184  
    Route patterns define which request paths match a route. Patterns
183  
    support literal text, named parameters, wildcards, and optional
185  
    support literal text, named parameters, wildcards, and optional
184  
    groups. The syntax is inspired by Express.js path-to-regexp.
186  
    groups. The syntax is inspired by Express.js path-to-regexp.
185  

187  

186  
    @code
188  
    @code
187  
    path       = *token
189  
    path       = *token
188  
    token      = text / param / wildcard / group
190  
    token      = text / param / wildcard / group
189  
    text       = 1*( char / escaped )     ; literal characters
191  
    text       = 1*( char / escaped )     ; literal characters
190  
    param      = ":" name                 ; captures segment until '/'
192  
    param      = ":" name                 ; captures segment until '/'
191  
    wildcard   = "*" name                 ; captures everything to end
193  
    wildcard   = "*" name                 ; captures everything to end
192  
    group      = "{" *token "}"           ; optional section
194  
    group      = "{" *token "}"           ; optional section
193  
    name       = identifier / quoted      ; plain or quoted name
195  
    name       = identifier / quoted      ; plain or quoted name
194  
    identifier = ( "$" / "_" / ALPHA ) *( "$" / "_" / ALNUM )
196  
    identifier = ( "$" / "_" / ALPHA ) *( "$" / "_" / ALNUM )
195  
    quoted     = DQUOTE 1*qchar DQUOTE    ; allows spaces, punctuation
197  
    quoted     = DQUOTE 1*qchar DQUOTE    ; allows spaces, punctuation
196  
    escaped    = "\" CHAR                 ; literal special character
198  
    escaped    = "\" CHAR                 ; literal special character
197  
    @endcode
199  
    @endcode
198  

200  

199  
    Named parameters capture path segments. A parameter matches any
201  
    Named parameters capture path segments. A parameter matches any
200  
    characters except `/` and must capture at least one character:
202  
    characters except `/` and must capture at least one character:
201  

203  

202  
    - `/users/:id` matches `/users/42`, capturing `id = "42"`
204  
    - `/users/:id` matches `/users/42`, capturing `id = "42"`
203  
    - `/users/:userId/posts/:postId` matches `/users/5/posts/99`
205  
    - `/users/:userId/posts/:postId` matches `/users/5/posts/99`
204  
    - `/:from-:to` matches `/LAX-JFK`, capturing `from = "LAX"`, `to = "JFK"`
206  
    - `/:from-:to` matches `/LAX-JFK`, capturing `from = "LAX"`, `to = "JFK"`
205  

207  

206  
    Wildcards capture everything from their position to the end of
208  
    Wildcards capture everything from their position to the end of
207  
    the path, including `/` characters. Optional groups match
209  
    the path, including `/` characters. Optional groups match
208  
    all-or-nothing:
210  
    all-or-nothing:
209  

211  

210  
    - `/api{/v:version}` matches both `/api` and `/api/v2`
212  
    - `/api{/v:version}` matches both `/api` and `/api/v2`
211  
    - `/file{.:ext}` matches `/file` and `/file.json`
213  
    - `/file{.:ext}` matches `/file` and `/file.json`
212  

214  

213  
    Reserved characters `( ) [ ] + ? !` are not allowed in patterns.
215  
    Reserved characters `( ) [ ] + ? !` are not allowed in patterns.
214  
    For wildcards, escaping, and quoted names, see the Route Patterns
216  
    For wildcards, escaping, and quoted names, see the Route Patterns
215  
    documentation.
217  
    documentation.
216  

218  

217  
    @par Handlers
219  
    @par Handlers
218  

220  

219  
    Regular handlers are invoked for matching routes and have this
221  
    Regular handlers are invoked for matching routes and have this
220  
    equivalent signature:
222  
    equivalent signature:
221  
    @code
223  
    @code
222  
    route_result handler( Params& p )
224  
    route_result handler( Params& p )
223  
    @endcode
225  
    @endcode
224  

226  

225  
    The return value is a @ref route_result used to indicate the desired
227  
    The return value is a @ref route_result used to indicate the desired
226  
    action through @ref route enum values, or to indicate that a failure
228  
    action through @ref route enum values, or to indicate that a failure
227  
    occurred. Failures are represented by error codes for which
229  
    occurred. Failures are represented by error codes for which
228  
    `system::error_code::failed()` returns `true`.
230  
    `system::error_code::failed()` returns `true`.
229  

231  

230  
    When a failing error code is produced and remains unhandled, the
232  
    When a failing error code is produced and remains unhandled, the
231  
    router enters error-dispatching mode. In this mode, only error
233  
    router enters error-dispatching mode. In this mode, only error
232  
    handlers are invoked. Error handlers are registered globally or
234  
    handlers are invoked. Error handlers are registered globally or
233  
    for specific paths and execute in the order of registration whenever
235  
    for specific paths and execute in the order of registration whenever
234  
    a failing error code is present in the response.
236  
    a failing error code is present in the response.
235  

237  

236  
    Error handlers have this equivalent signature:
238  
    Error handlers have this equivalent signature:
237  
    @code
239  
    @code
238  
    route_result error_handler( Params& p, system::error_code ec )
240  
    route_result error_handler( Params& p, system::error_code ec )
239  
    @endcode
241  
    @endcode
240  

242  

241  
    Each error handler may return any failing @ref system::error_code,
243  
    Each error handler may return any failing @ref system::error_code,
242  
    which is equivalent to calling:
244  
    which is equivalent to calling:
243  
    @code
245  
    @code
244  
    p.next( ec ); // with ec == true
246  
    p.next( ec ); // with ec == true
245  
    @endcode
247  
    @endcode
246  

248  

247  
    Returning @ref route_next indicates that control should proceed to
249  
    Returning @ref route_next indicates that control should proceed to
248  
    the next matching error handler. Returning a different failing code
250  
    the next matching error handler. Returning a different failing code
249  
    replaces the current error and continues dispatch in error mode using
251  
    replaces the current error and continues dispatch in error mode using
250  
    that new code. Error handlers are invoked until one returns a result
252  
    that new code. Error handlers are invoked until one returns a result
251  
    other than @ref route_next.
253  
    other than @ref route_next.
252  

254  

253  
    Exception handlers have this equivalent signature:
255  
    Exception handlers have this equivalent signature:
254  
    @code
256  
    @code
255  
    route_result exception_handler( Params& p, E ex )
257  
    route_result exception_handler( Params& p, E ex )
256  
    @endcode
258  
    @endcode
257  

259  

258  
    Where `E` is the type of exception caught. Handlers installed for an
260  
    Where `E` is the type of exception caught. Handlers installed for an
259  
    exception of type `E` will also be called when the exception type is
261  
    exception of type `E` will also be called when the exception type is
260  
    a derived class of `E`. Exception handlers are invoked in the order
262  
    a derived class of `E`. Exception handlers are invoked in the order
261  
    of registration whenever an exception is present in the request.
263  
    of registration whenever an exception is present in the request.
262  

264  

263  
    The prefix match is not strict: middleware attached to `"/api"`
265  
    The prefix match is not strict: middleware attached to `"/api"`
264  
    will also match `"/api/users"` and `"/api/data"`. When registered
266  
    will also match `"/api/users"` and `"/api/data"`. When registered
265  
    before route handlers for the same prefix, middleware runs before
267  
    before route handlers for the same prefix, middleware runs before
266  
    those routes. This is analogous to `app.use( path, ... )` in
268  
    those routes. This is analogous to `app.use( path, ... )` in
267  
    Express.js.
269  
    Express.js.
268  

270  

269  
    @par Handler Transforms
271  
    @par Handler Transforms
270  

272  

271  
    The second template parameter `HT` is a <em>handler transform</em>.
273  
    The second template parameter `HT` is a <em>handler transform</em>.
272  
    A handler transform is a callable object that the router applies to
274  
    A handler transform is a callable object that the router applies to
273  
    each plain handler at registration time, producing a new callable
275  
    each plain handler at registration time, producing a new callable
274  
    with the canonical signature `route_task(Params&)`.
276  
    with the canonical signature `route_task(Params&)`.
275  

277  

276  
    When a handler is registered that does not directly satisfy
278  
    When a handler is registered that does not directly satisfy
277  
    `route_task(Params&)`, the router applies `ht(handler)` to adapt
279  
    `route_task(Params&)`, the router applies `ht(handler)` to adapt
278  
    it. The transform is invoked <em>once</em> at registration time;
280  
    it. The transform is invoked <em>once</em> at registration time;
279  
    the returned callable is stored and invoked each time the route
281  
    the returned callable is stored and invoked each time the route
280  
    matches at dispatch time.
282  
    matches at dispatch time.
281  

283  

282  
    Error handlers and exception handlers are never transformed.
284  
    Error handlers and exception handlers are never transformed.
283  
    Only plain route handlers pass through the transform.
285  
    Only plain route handlers pass through the transform.
284  

286  

285  
    The default transform is @ref identity, which passes handlers
287  
    The default transform is @ref identity, which passes handlers
286  
    through unchanged.
288  
    through unchanged.
287  

289  

288  
    A transform `HT` must satisfy the following contract: for any
290  
    A transform `HT` must satisfy the following contract: for any
289  
    handler `h` passed to the router, the expression `ht(h)` must
291  
    handler `h` passed to the router, the expression `ht(h)` must
290  
    return a callable `g` such that `g(Params&)` returns
292  
    return a callable `g` such that `g(Params&)` returns
291  
    @ref route_task.
293  
    @ref route_task.
292  

294  

293  
    @par Example: Logging Transform
295  
    @par Example: Logging Transform
294  
    @code
296  
    @code
295  
    struct log_transform
297  
    struct log_transform
296  
    {
298  
    {
297  
        template<class Handler>
299  
        template<class Handler>
298  
        auto operator()(Handler h) const
300  
        auto operator()(Handler h) const
299  
        {
301  
        {
300  
            struct wrapper
302  
            struct wrapper
301  
            {
303  
            {
302  
                Handler h_;
304  
                Handler h_;
303  

305  

304  
                route_task operator()(route_params& p) const
306  
                route_task operator()(route_params& p) const
305  
                {
307  
                {
306  
                    auto t0 = steady_clock::now();
308  
                    auto t0 = steady_clock::now();
307  
                    auto rv = co_await h_(p);
309  
                    auto rv = co_await h_(p);
308  
                    log_elapsed(steady_clock::now() - t0);
310  
                    log_elapsed(steady_clock::now() - t0);
309  
                    co_return rv;
311  
                    co_return rv;
310  
                }
312  
                }
311  
            };
313  
            };
312  
            return wrapper{ std::move(h) };
314  
            return wrapper{ std::move(h) };
313  
        }
315  
        }
314  
    };
316  
    };
315  

317  

316  
    router<route_params> base;
318  
    router<route_params> base;
317  
    auto r = base.with_transform( log_transform{} );
319  
    auto r = base.with_transform( log_transform{} );
318  

320  

319  
    // The lambda is wrapped by log_transform at registration.
321  
    // The lambda is wrapped by log_transform at registration.
320  
    // At dispatch, log_transform::wrapper::operator() runs,
322  
    // At dispatch, log_transform::wrapper::operator() runs,
321  
    // which invokes the original lambda and logs elapsed time.
323  
    // which invokes the original lambda and logs elapsed time.
322  
    r.get( "/hello", []( route_params& p ) -> route_task {
324  
    r.get( "/hello", []( route_params& p ) -> route_task {
323  
        co_return route_done;
325  
        co_return route_done;
324  
    });
326  
    });
325  
    @endcode
327  
    @endcode
326  

328  

327  
    @par Example: Dependency Injection Transform
329  
    @par Example: Dependency Injection Transform
328  

330  

329  
    A transform can adapt handlers whose parameters are not
331  
    A transform can adapt handlers whose parameters are not
330  
    `Params&` at all. The transform resolves each parameter
332  
    `Params&` at all. The transform resolves each parameter
331  
    from a service container at dispatch time:
333  
    from a service container at dispatch time:
332  

334  

333  
    @code
335  
    @code
334  
    struct inject_transform
336  
    struct inject_transform
335  
    {
337  
    {
336  
        template<class Handler>
338  
        template<class Handler>
337  
        auto operator()(Handler h) const
339  
        auto operator()(Handler h) const
338  
        {
340  
        {
339  
            struct wrapper
341  
            struct wrapper
340  
            {
342  
            {
341  
                Handler h_;
343  
                Handler h_;
342  

344  

343  
                route_task operator()(route_params& p) const
345  
                route_task operator()(route_params& p) const
344  
                {
346  
                {
345  
                    // Look up each of h_'s parameter types
347  
                    // Look up each of h_'s parameter types
346  
                    // in p.route_data. Return route_next if
348  
                    // in p.route_data. Return route_next if
347  
                    // any are missing.
349  
                    // any are missing.
348  
                    co_return dynamic_invoke(p.route_data, h_);
350  
                    co_return dynamic_invoke(p.route_data, h_);
349  
                }
351  
                }
350  
            };
352  
            };
351  
            return wrapper{ std::move(h) };
353  
            return wrapper{ std::move(h) };
352  
        }
354  
        }
353  
    };
355  
    };
354  

356  

355  
    router<route_params> base;
357  
    router<route_params> base;
356  
    auto r = base.with_transform( inject_transform{} );
358  
    auto r = base.with_transform( inject_transform{} );
357  

359  

358  
    // Parameters are resolved from p.route_data automatically.
360  
    // Parameters are resolved from p.route_data automatically.
359  
    // If UserService or Config are not in route_data, the
361  
    // If UserService or Config are not in route_data, the
360  
    // handler is skipped and route_next is returned.
362  
    // handler is skipped and route_next is returned.
361  
    r.get( "/users", [](
363  
    r.get( "/users", [](
362  
        UserService& svc,
364  
        UserService& svc,
363  
        Config const& cfg) -> route_result
365  
        Config const& cfg) -> route_result
364  
    {
366  
    {
365  
        // use svc and cfg...
367  
        // use svc and cfg...
366  
        return route_done;
368  
        return route_done;
367  
    });
369  
    });
368  
    @endcode
370  
    @endcode
369  

371  

370  
    @par Thread Safety
372  
    @par Thread Safety
371  

373  

372  
    Member functions marked `const` such as @ref dispatch
374  
    Member functions marked `const` such as @ref dispatch
373  
    may be called concurrently on routers that refer to the same data.
375  
    may be called concurrently on routers that refer to the same data.
374  
    Modification of routers through calls to non-`const` member functions
376  
    Modification of routers through calls to non-`const` member functions
375  
    is not thread-safe and must not be performed concurrently with any
377  
    is not thread-safe and must not be performed concurrently with any
376  
    other member function.
378  
    other member function.
377  

379  

378  
    @par Nesting Depth
380  
    @par Nesting Depth
379  

381  

380  
    Routers may be nested to a maximum depth of `max_path_depth` (16 levels).
382  
    Routers may be nested to a maximum depth of `max_path_depth` (16 levels).
381  
    Exceeding this limit throws `std::length_error` when the nested router
383  
    Exceeding this limit throws `std::length_error` when the nested router
382  
    is added via @ref use. This limit ensures that dispatch never overflows
384  
    is added via @ref use. This limit ensures that dispatch never overflows
383  
    its fixed-size tracking arrays.
385  
    its fixed-size tracking arrays.
384  

386  

385  
    @par Constraints
387  
    @par Constraints
386  

388  

387  
    `Params` must be publicly derived from @ref route_params.
389  
    `Params` must be publicly derived from @ref route_params.
388  

390  

389  
    @tparam Params The type of the parameters object passed to handlers.
391  
    @tparam Params The type of the parameters object passed to handlers.
390  
*/
392  
*/
391  
template<class P = route_params, class HT = identity>
393  
template<class P = route_params, class HT = identity>
392  
class router : public detail::router_base
394  
class router : public detail::router_base
393  
{
395  
{
394  
    template<class, class> friend class router;
396  
    template<class, class> friend class router;
395  

397  

396  
    HT ht_{};
398  
    HT ht_{};
397  

399  

398  
    static_assert(std::derived_from<P, route_params>);
400  
    static_assert(std::derived_from<P, route_params>);
399  

401  

400  
    template<class T>
402  
    template<class T>
401  
    static inline constexpr char handler_kind =
403  
    static inline constexpr char handler_kind =
402  
        []() -> char
404  
        []() -> char
403  
        {
405  
        {
404  
            if constexpr (detail::returns_route_task<
406  
            if constexpr (detail::returns_route_task<
405  
                T, P&, system::error_code>)
407  
                T, P&, system::error_code>)
406  
            {
408  
            {
407  
                return is_error;
409  
                return is_error;
408  
            }
410  
            }
409  
            else if constexpr (detail::returns_route_task<
411  
            else if constexpr (detail::returns_route_task<
410  
                T, P&, std::exception_ptr>)
412  
                T, P&, std::exception_ptr>)
411  
            {
413  
            {
412  
                return is_exception;
414  
                return is_exception;
413  
            }
415  
            }
414  
            else if constexpr (detail::returns_route_task<T, P&>)
416  
            else if constexpr (detail::returns_route_task<T, P&>)
415  
            {
417  
            {
416  
                return is_plain;
418  
                return is_plain;
417  
            }
419  
            }
418  
            else if constexpr (
420  
            else if constexpr (
419  
                std::is_invocable_v<HT const&, T> &&
421  
                std::is_invocable_v<HT const&, T> &&
420  
                detail::returns_route_task<
422  
                detail::returns_route_task<
421  
                    std::invoke_result_t<HT const&, T>, P&>)
423  
                    std::invoke_result_t<HT const&, T>, P&>)
422  
            {
424  
            {
423  
                return is_plain;
425  
                return is_plain;
424  
            }
426  
            }
425  
            else
427  
            else
426  
            {
428  
            {
427  
                return is_invalid;
429  
                return is_invalid;
428  
            }
430  
            }
429  
        }();
431  
        }();
430  

432  

431  
    template<class T>
433  
    template<class T>
432  
    static inline constexpr bool is_sub_router =
434  
    static inline constexpr bool is_sub_router =
433  
        std::is_base_of_v<detail::router_base, std::decay_t<T>> &&
435  
        std::is_base_of_v<detail::router_base, std::decay_t<T>> &&
434  
        std::is_convertible_v<std::decay_t<T> const volatile*,
436  
        std::is_convertible_v<std::decay_t<T> const volatile*,
435  
            detail::router_base const volatile*>;
437  
            detail::router_base const volatile*>;
436  

438  

437  
    template<class... Ts>
439  
    template<class... Ts>
438  
    static inline constexpr bool handler_crvals =
440  
    static inline constexpr bool handler_crvals =
439  
        ((!std::is_lvalue_reference_v<Ts> || 
441  
        ((!std::is_lvalue_reference_v<Ts> || 
440  
        std::is_const_v<std::remove_reference_t<Ts>> ||
442  
        std::is_const_v<std::remove_reference_t<Ts>> ||
441  
        std::is_function_v<std::remove_reference_t<Ts>>) && ...);
443  
        std::is_function_v<std::remove_reference_t<Ts>>) && ...);
442  
        
444  
        
443  
    template<char Mask, class... Ts>
445  
    template<char Mask, class... Ts>
444  
    static inline constexpr bool handler_check = 
446  
    static inline constexpr bool handler_check = 
445  
        (((handler_kind<Ts> & Mask) != 0) && ...);
447  
        (((handler_kind<Ts> & Mask) != 0) && ...);
446  

448  

447  
    template<class H>
449  
    template<class H>
448  
    struct handler_impl : handler
450  
    struct handler_impl : handler
449  
    {  
451  
    {  
450  
        std::decay_t<H> h;
452  
        std::decay_t<H> h;
451  

453  

452  
        template<class H_>
454  
        template<class H_>
453  
        explicit handler_impl(H_ h_)
455  
        explicit handler_impl(H_ h_)
454  
            : handler(handler_kind<H>)
456  
            : handler(handler_kind<H>)
455  
            , h(std::forward<H_>(h_))
457  
            , h(std::forward<H_>(h_))
456  
        {
458  
        {
457  
        }
459  
        }
458  
    
460  
    
459  
        auto invoke(route_params& rp) const ->
461  
        auto invoke(route_params& rp) const ->
460  
            route_task override
462  
            route_task override
461  
        {
463  
        {
462  
            if constexpr (detail::returns_route_task<H, P&>)
464  
            if constexpr (detail::returns_route_task<H, P&>)
463  
            {
465  
            {
464  
                return h(static_cast<P&>(rp));
466  
                return h(static_cast<P&>(rp));
465  
            }
467  
            }
466  
            else if constexpr (detail::returns_route_task<
468  
            else if constexpr (detail::returns_route_task<
467  
                H, P&, system::error_code>)
469  
                H, P&, system::error_code>)
468  
            {
470  
            {
469  
                return h(static_cast<P&>(rp), rp.priv_.ec_);
471  
                return h(static_cast<P&>(rp), rp.priv_.ec_);
470  
            }
472  
            }
471  
            else if constexpr (detail::returns_route_task<
473  
            else if constexpr (detail::returns_route_task<
472  
                H, P&, std::exception_ptr>)
474  
                H, P&, std::exception_ptr>)
473  
            {
475  
            {
474  
                return h(static_cast<P&>(rp), rp.priv_.ep_);
476  
                return h(static_cast<P&>(rp), rp.priv_.ep_);
475  
            }
477  
            }
476  
            else
478  
            else
477  
            {
479  
            {
478  
                std::terminate();
480  
                std::terminate();
479  
            }
481  
            }
480  
        }
482  
        }
481  
    };
483  
    };
482  

484  

483  
    template<class H>
485  
    template<class H>
484  
    static handler_ptr make_handler(H&& h)
486  
    static handler_ptr make_handler(H&& h)
485  
    {
487  
    {
486  
        return std::make_unique<handler_impl<H>>(std::forward<H>(h));
488  
        return std::make_unique<handler_impl<H>>(std::forward<H>(h));
487  
    }
489  
    }
488  

490  

489  
    template<class H>
491  
    template<class H>
490  
    struct options_handler_impl : options_handler
492  
    struct options_handler_impl : options_handler
491  
    {
493  
    {
492  
        std::decay_t<H> h;
494  
        std::decay_t<H> h;
493  

495  

494  
        template<class H_>
496  
        template<class H_>
495  
        explicit options_handler_impl(H_&& h_)
497  
        explicit options_handler_impl(H_&& h_)
496  
            : h(std::forward<H_>(h_))
498  
            : h(std::forward<H_>(h_))
497  
        {
499  
        {
498  
        }
500  
        }
499  

501  

500  
        route_task invoke(
502  
        route_task invoke(
501  
            route_params& rp,
503  
            route_params& rp,
502  
            std::string_view allow) const override
504  
            std::string_view allow) const override
503  
        {
505  
        {
504  
            return h(static_cast<P&>(rp), allow);
506  
            return h(static_cast<P&>(rp), allow);
505  
        }
507  
        }
506  
    };
508  
    };
507  

509  

508  
    template<class T, std::size_t N>
510  
    template<class T, std::size_t N>
509  
    struct handlers_impl : handlers
511  
    struct handlers_impl : handlers
510  
    {
512  
    {
511  
        T const& ht;
513  
        T const& ht;
512  
        handler_ptr v[N];
514  
        handler_ptr v[N];
513  

515  

514  
        template<class... HN>
516  
        template<class... HN>
515  
        explicit handlers_impl(T const& ht_, HN&&... hn)
517  
        explicit handlers_impl(T const& ht_, HN&&... hn)
516  
            : ht(ht_)
518  
            : ht(ht_)
517  
        {
519  
        {
518  
            p = v;
520  
            p = v;
519  
            n = sizeof...(HN);
521  
            n = sizeof...(HN);
520  
            assign<0>(std::forward<HN>(hn)...);
522  
            assign<0>(std::forward<HN>(hn)...);
521  
        }
523  
        }
522  

524  

523  
    private:
525  
    private:
524  
        template<std::size_t I, class H1, class... HN>
526  
        template<std::size_t I, class H1, class... HN>
525  
        void assign(H1&& h1, HN&&... hn)
527  
        void assign(H1&& h1, HN&&... hn)
526  
        {
528  
        {
527  
            if constexpr (
529  
            if constexpr (
528  
                detail::returns_route_task<
530  
                detail::returns_route_task<
529  
                    H1, P&, system::error_code> ||
531  
                    H1, P&, system::error_code> ||
530  
                detail::returns_route_task<
532  
                detail::returns_route_task<
531  
                    H1, P&, std::exception_ptr>)
533  
                    H1, P&, std::exception_ptr>)
532  
            {
534  
            {
533  
                v[I] = make_handler(std::forward<H1>(h1));
535  
                v[I] = make_handler(std::forward<H1>(h1));
534  
            }
536  
            }
535  
            else if constexpr (detail::returns_route_task<
537  
            else if constexpr (detail::returns_route_task<
536  
                decltype(std::declval<T const&>()(std::declval<H1>())), P&>)
538  
                decltype(std::declval<T const&>()(std::declval<H1>())), P&>)
537  
            {
539  
            {
538  
                v[I] = make_handler(ht(std::forward<H1>(h1)));
540  
                v[I] = make_handler(ht(std::forward<H1>(h1)));
539  
            }
541  
            }
540  
            assign<I+1>(std::forward<HN>(hn)...);
542  
            assign<I+1>(std::forward<HN>(hn)...);
541  
        }
543  
        }
542  

544  

543  
        template<std::size_t>
545  
        template<std::size_t>
544  
        void assign(int = 0)
546  
        void assign(int = 0)
545  
        {
547  
        {
546  
        }
548  
        }
547  
    };
549  
    };
548  

550  

549  
    template<class T, class... HN>
551  
    template<class T, class... HN>
550  
    static auto make_handlers(T const& ht, HN&&... hn)
552  
    static auto make_handlers(T const& ht, HN&&... hn)
551  
    {
553  
    {
552  
        return handlers_impl<T, sizeof...(HN)>(ht,
554  
        return handlers_impl<T, sizeof...(HN)>(ht,
553  
            std::forward<HN>(hn)...);
555  
            std::forward<HN>(hn)...);
554  
    }
556  
    }
555  

557  

556  
public:
558  
public:
557  
    /** The type of params used in handlers.
559  
    /** The type of params used in handlers.
558  
    */
560  
    */
559  
    using params_type = P;
561  
    using params_type = P;
560  

562  

561  
    /** A fluent interface for defining handlers on a specific route.
563  
    /** A fluent interface for defining handlers on a specific route.
562  

564  

563  
        This type represents a single route within the router and
565  
        This type represents a single route within the router and
564  
        provides a chainable API for registering handlers associated
566  
        provides a chainable API for registering handlers associated
565  
        with particular HTTP methods or for all methods collectively.
567  
        with particular HTTP methods or for all methods collectively.
566  

568  

567  
        Typical usage registers one or more handlers for a route:
569  
        Typical usage registers one or more handlers for a route:
568  
        @code
570  
        @code
569  
        r.route( "/users/:id" )
571  
        r.route( "/users/:id" )
570  
            .get( show_user )
572  
            .get( show_user )
571  
            .put( update_user )
573  
            .put( update_user )
572  
            .all( log_access );
574  
            .all( log_access );
573  
        @endcode
575  
        @endcode
574  

576  

575  
        Each call appends handlers in registration order.
577  
        Each call appends handlers in registration order.
576  
    */
578  
    */
577  
    class fluent_route;
579  
    class fluent_route;
578  

580  

579  
    router(router const&) = default;
581  
    router(router const&) = default;
580  
    router& operator=(router const&) = default;
582  
    router& operator=(router const&) = default;
581  
    router(router&&) = default;
583  
    router(router&&) = default;
582  
    router& operator=(router&&) = default;
584  
    router& operator=(router&&) = default;
583  

585  

584  
    /** Constructor.
586  
    /** Constructor.
585  

587  

586  
        Creates an empty router with the specified configuration.
588  
        Creates an empty router with the specified configuration.
587  
        Routers constructed with default options inherit the values
589  
        Routers constructed with default options inherit the values
588  
        of @ref router_options::case_sensitive and
590  
        of @ref router_options::case_sensitive and
589  
        @ref router_options::strict from the parent router, or default
591  
        @ref router_options::strict from the parent router, or default
590  
        to `false` if there is no parent. The value of
592  
        to `false` if there is no parent. The value of
591  
        @ref router_options::merge_params defaults to `false` and
593  
        @ref router_options::merge_params defaults to `false` and
592  
        is never inherited.
594  
        is never inherited.
593  

595  

594  
        @param options The configuration options to use.
596  
        @param options The configuration options to use.
595  
    */
597  
    */
596  
    explicit
598  
    explicit
597  
    router(
599  
    router(
598  
        router_options options = {})
600  
        router_options options = {})
599  
        : detail::router_base(options.v_)
601  
        : detail::router_base(options.v_)
600  
    {
602  
    {
 
603 +
        set_options_handler(
 
604 +
            [](P& rp, std::string_view allow) -> route_task {
 
605 +
                rp.status(status::no_content);
 
606 +
                rp.res.set(field::allow, allow);
 
607 +
                (void)(co_await rp.send());
 
608 +
                co_return route_done;
 
609 +
            });
601  
    }
610  
    }
602  

611  

603  
    /** Construct a router from another router with compatible types.
612  
    /** Construct a router from another router with compatible types.
604  

613  

605  
        This constructs a router that shares the same underlying routing
614  
        This constructs a router that shares the same underlying routing
606  
        state as another router whose params and handler transform types
615  
        state as another router whose params and handler transform types
607  
        may differ.
616  
        may differ.
608  

617  

609  
        The handler transform is initialized as follows:
618  
        The handler transform is initialized as follows:
610  
        - If `HT` is constructible from `OtherHT`, the transform is
619  
        - If `HT` is constructible from `OtherHT`, the transform is
611  
          move-constructed from the source router's transform.
620  
          move-constructed from the source router's transform.
612  
        - Otherwise, if `HT` is default-constructible, the transform
621  
        - Otherwise, if `HT` is default-constructible, the transform
613  
          is value-initialized.
622  
          is value-initialized.
614  

623  

615  
        @par Constraints
624  
        @par Constraints
616  

625  

617  
        `OtherParams` must be derived from `Params`, and `HT` must be
626  
        `OtherParams` must be derived from `Params`, and `HT` must be
618  
        either constructible from `OtherHT` or default-constructible.
627  
        either constructible from `OtherHT` or default-constructible.
619  

628  

620  
        @param other The router to construct from.
629  
        @param other The router to construct from.
621  

630  

622  
        @tparam OtherParams The params type of the source router.
631  
        @tparam OtherParams The params type of the source router.
623  

632  

624  
        @tparam OtherHT The handler transform type of the source router.
633  
        @tparam OtherHT The handler transform type of the source router.
625  
    */
634  
    */
626  
    template<class OtherP, class OtherHT>
635  
    template<class OtherP, class OtherHT>
627  
        requires std::derived_from<OtherP, P> &&
636  
        requires std::derived_from<OtherP, P> &&
628  
            std::constructible_from<HT, OtherHT>
637  
            std::constructible_from<HT, OtherHT>
629  
    router(
638  
    router(
630  
        router<OtherP, OtherHT>&& other) noexcept
639  
        router<OtherP, OtherHT>&& other) noexcept
631  
        : detail::router_base(std::move(other))
640  
        : detail::router_base(std::move(other))
632  
        , ht_(std::move(other.ht_))
641  
        , ht_(std::move(other.ht_))
633  
    {
642  
    {
634  
    }
643  
    }
635  

644  

636  
    /// @copydoc router(router<OtherP,OtherHT>&&)
645  
    /// @copydoc router(router<OtherP,OtherHT>&&)
637  
    template<class OtherP, class OtherHT>
646  
    template<class OtherP, class OtherHT>
638  
        requires std::derived_from<OtherP, P> &&
647  
        requires std::derived_from<OtherP, P> &&
639  
            (!std::constructible_from<HT, OtherHT>) &&
648  
            (!std::constructible_from<HT, OtherHT>) &&
640  
            std::default_initializable<HT>
649  
            std::default_initializable<HT>
641  
    router(
650  
    router(
642  
        router<OtherP, OtherHT>&& other) noexcept
651  
        router<OtherP, OtherHT>&& other) noexcept
643  
        : detail::router_base(std::move(other))
652  
        : detail::router_base(std::move(other))
644  
    {
653  
    {
645  
    }
654  
    }
646  

655  

647  
    /** Construct a router with a handler transform.
656  
    /** Construct a router with a handler transform.
648  

657  

649  
        Creates a router that shares the routing state of @p other
658  
        Creates a router that shares the routing state of @p other
650  
        but applies @p ht to each plain handler before installation.
659  
        but applies @p ht to each plain handler before installation.
651  

660  

652  
        @param other The router whose routing state to share.
661  
        @param other The router whose routing state to share.
653  

662  

654  
        @param ht The handler transform to apply.
663  
        @param ht The handler transform to apply.
655  
    */
664  
    */
656  
    template<class OtherHT>
665  
    template<class OtherHT>
657  
    router(router<P, OtherHT> const& other, HT ht)
666  
    router(router<P, OtherHT> const& other, HT ht)
658  
        : detail::router_base(other)
667  
        : detail::router_base(other)
659  
        , ht_(std::move(ht))
668  
        , ht_(std::move(ht))
660  
    {
669  
    {
661  
    }
670  
    }
662  

671  

663  
    /** Return a router that applies a transform to plain handlers.
672  
    /** Return a router that applies a transform to plain handlers.
664  

673  

665  
        Creates a new router that shares the same underlying routing
674  
        Creates a new router that shares the same underlying routing
666  
        table but applies @p f to each plain handler before it is
675  
        table but applies @p f to each plain handler before it is
667  
        stored. Error and exception handlers are not affected by
676  
        stored. Error and exception handlers are not affected by
668  
        the transform.
677  
        the transform.
669  

678  

670  
        The transform is invoked once at handler registration time.
679  
        The transform is invoked once at handler registration time.
671  
        For each plain handler `h` passed to the returned router,
680  
        For each plain handler `h` passed to the returned router,
672  
        `f(h)` must produce a callable `g` such that `g(Params&)`
681  
        `f(h)` must produce a callable `g` such that `g(Params&)`
673  
        returns @ref route_task. The callable `g` is what gets
682  
        returns @ref route_task. The callable `g` is what gets
674  
        stored and invoked at dispatch time.
683  
        stored and invoked at dispatch time.
675  

684  

676  
        @par Shared State
685  
        @par Shared State
677  

686  

678  
        The returned router shares the same routing table as
687  
        The returned router shares the same routing table as
679  
        `*this`. Routes added through either router are visible
688  
        `*this`. Routes added through either router are visible
680  
        during dispatch from both. The transform only controls
689  
        during dispatch from both. The transform only controls
681  
        how new handlers are wrapped when they are registered
690  
        how new handlers are wrapped when they are registered
682  
        through the returned router.
691  
        through the returned router.
683  

692  

684  
        @par Example: Simple Transform
693  
        @par Example: Simple Transform
685  
        @code
694  
        @code
686  
        // A transform that logs before each handler runs
695  
        // A transform that logs before each handler runs
687  
        auto r = base.with_transform(
696  
        auto r = base.with_transform(
688  
            []( auto handler )
697  
            []( auto handler )
689  
            {
698  
            {
690  
                struct wrapper
699  
                struct wrapper
691  
                {
700  
                {
692  
                    decltype(handler) h_;
701  
                    decltype(handler) h_;
693  
                    route_task operator()(route_params& p) const
702  
                    route_task operator()(route_params& p) const
694  
                    {
703  
                    {
695  
                        std::cout << "dispatching\n";
704  
                        std::cout << "dispatching\n";
696  
                        co_return co_await h_(p);
705  
                        co_return co_await h_(p);
697  
                    }
706  
                    }
698  
                };
707  
                };
699  
                return wrapper{ std::move(handler) };
708  
                return wrapper{ std::move(handler) };
700  
            });
709  
            });
701  
        @endcode
710  
        @endcode
702  

711  

703  
        @par Example: Chaining Transforms
712  
        @par Example: Chaining Transforms
704  
        @code
713  
        @code
705  
        auto r1 = base.with_transform( first_transform{} );
714  
        auto r1 = base.with_transform( first_transform{} );
706  
        auto r2 = base.with_transform( second_transform{} );
715  
        auto r2 = base.with_transform( second_transform{} );
707  

716  

708  
        // r1 applies first_transform to its handlers
717  
        // r1 applies first_transform to its handlers
709  
        // r2 applies second_transform to its handlers
718  
        // r2 applies second_transform to its handlers
710  
        // Both share the same routing table
719  
        // Both share the same routing table
711  
        @endcode
720  
        @endcode
712  

721  

713  
        @par Constraints
722  
        @par Constraints
714  

723  

715  
        `f(handler)` must return a callable `g` where
724  
        `f(handler)` must return a callable `g` where
716  
        `g(Params&)` returns @ref route_task.
725  
        `g(Params&)` returns @ref route_task.
717  

726  

718  
        @param f The handler transform to apply.
727  
        @param f The handler transform to apply.
719  

728  

720  
        @return A router with the transform applied.
729  
        @return A router with the transform applied.
721  
    */
730  
    */
722  
    template<class F>
731  
    template<class F>
723  
    auto with_transform(F&& f) const ->
732  
    auto with_transform(F&& f) const ->
724  
        router<P, std::decay_t<F>>
733  
        router<P, std::decay_t<F>>
725  
    {
734  
    {
726  
        return router<P, std::decay_t<F>>(
735  
        return router<P, std::decay_t<F>>(
727  
            *this, std::forward<F>(f));
736  
            *this, std::forward<F>(f));
728  
    }
737  
    }
729  

738  

730  
    /** Dispatch a request using a known HTTP method.
739  
    /** Dispatch a request using a known HTTP method.
731  

740  

732  
        @param verb The HTTP method to match. Must not be
741  
        @param verb The HTTP method to match. Must not be
733  
        @ref http::method::unknown.
742  
        @ref http::method::unknown.
734  

743  

735  
        @param url The full request target used for route matching.
744  
        @param url The full request target used for route matching.
736  

745  

737  
        @param p The typed params to pass to handlers.
746  
        @param p The typed params to pass to handlers.
738  

747  

739  
        @return A task yielding the @ref route_result describing
748  
        @return A task yielding the @ref route_result describing
740  
        how routing completed.
749  
        how routing completed.
741  

750  

742  
        @throws std::invalid_argument If @p verb is
751  
        @throws std::invalid_argument If @p verb is
743  
        @ref http::method::unknown.
752  
        @ref http::method::unknown.
744  
    */
753  
    */
745  
    route_task
754  
    route_task
746  
    dispatch(
755  
    dispatch(
747  
        http::method verb,
756  
        http::method verb,
748  
        urls::url_view const& url,
757  
        urls::url_view const& url,
749  
        P& p) const
758  
        P& p) const
750  
    {
759  
    {
751  
        return detail::router_base::dispatch(
760  
        return detail::router_base::dispatch(
752  
            verb, url, static_cast<route_params&>(p));
761  
            verb, url, static_cast<route_params&>(p));
753  
    }
762  
    }
754  

763  

755  
    /** Dispatch a request using a method string.
764  
    /** Dispatch a request using a method string.
756  

765  

757  
        @param verb The HTTP method string to match. Must not be empty.
766  
        @param verb The HTTP method string to match. Must not be empty.
758  

767  

759  
        @param url The full request target used for route matching.
768  
        @param url The full request target used for route matching.
760  

769  

761  
        @param p The typed params to pass to handlers.
770  
        @param p The typed params to pass to handlers.
762  

771  

763  
        @return A task yielding the @ref route_result describing
772  
        @return A task yielding the @ref route_result describing
764  
        how routing completed.
773  
        how routing completed.
765  

774  

766  
        @throws std::invalid_argument If @p verb is empty.
775  
        @throws std::invalid_argument If @p verb is empty.
767  
    */
776  
    */
768  
    route_task
777  
    route_task
769  
    dispatch(
778  
    dispatch(
770  
        std::string_view verb,
779  
        std::string_view verb,
771  
        urls::url_view const& url,
780  
        urls::url_view const& url,
772  
        P& p) const
781  
        P& p) const
773  
    {
782  
    {
774  
        return detail::router_base::dispatch(
783  
        return detail::router_base::dispatch(
775  
            verb, url, static_cast<route_params&>(p));
784  
            verb, url, static_cast<route_params&>(p));
776  
    }
785  
    }
777  

786  

778  
    /** Add middleware handlers for a path prefix.
787  
    /** Add middleware handlers for a path prefix.
779  

788  

780  
        Each handler registered with this function participates in the
789  
        Each handler registered with this function participates in the
781  
        routing and error-dispatch process for requests whose path begins
790  
        routing and error-dispatch process for requests whose path begins
782  
        with the specified prefix, as described in the @ref router
791  
        with the specified prefix, as described in the @ref router
783  
        class documentation. Handlers execute in the order they are added
792  
        class documentation. Handlers execute in the order they are added
784  
        and may return @ref route_next to transfer control to the
793  
        and may return @ref route_next to transfer control to the
785  
        subsequent handler in the chain.
794  
        subsequent handler in the chain.
786  

795  

787  
        @par Example
796  
        @par Example
788  
        @code
797  
        @code
789  
        r.use( "/api",
798  
        r.use( "/api",
790  
            []( route_params& p )
799  
            []( route_params& p )
791  
            {
800  
            {
792  
                if( ! authenticate( p ) )
801  
                if( ! authenticate( p ) )
793  
                {
802  
                {
794  
                    p.res.status( 401 );
803  
                    p.res.status( 401 );
795  
                    p.res.set_body( "Unauthorized" );
804  
                    p.res.set_body( "Unauthorized" );
796  
                    return route_done;
805  
                    return route_done;
797  
                }
806  
                }
798  
                return route_next;
807  
                return route_next;
799  
            },
808  
            },
800  
            []( route_params& p )
809  
            []( route_params& p )
801  
            {
810  
            {
802  
                p.res.set_header( "X-Powered-By", "MyServer" );
811  
                p.res.set_header( "X-Powered-By", "MyServer" );
803  
                return route_next;
812  
                return route_next;
804  
            } );
813  
            } );
805  
        @endcode
814  
        @endcode
806  

815  

807  
        @par Preconditions
816  
        @par Preconditions
808  

817  

809  
        @p pattern must be a valid path prefix; it may be empty to
818  
        @p pattern must be a valid path prefix; it may be empty to
810  
        indicate the root scope.
819  
        indicate the root scope.
811  

820  

812  
        @param pattern The pattern to match.
821  
        @param pattern The pattern to match.
813  

822  

814  
        @param h1 The first handler to add.
823  
        @param h1 The first handler to add.
815  

824  

816  
        @param hn Additional handlers to add, invoked after @p h1 in
825  
        @param hn Additional handlers to add, invoked after @p h1 in
817  
        registration order.
826  
        registration order.
818  
    */
827  
    */
819  
    template<class H1, class... HN>
828  
    template<class H1, class... HN>
820  
    void use(
829  
    void use(
821  
        std::string_view pattern,
830  
        std::string_view pattern,
822  
        H1&& h1, HN&&... hn)
831  
        H1&& h1, HN&&... hn)
823  
    {
832  
    {
824  
        // Single sub-router case
833  
        // Single sub-router case
825  
        if constexpr(sizeof...(HN) == 0 && is_sub_router<H1>)
834  
        if constexpr(sizeof...(HN) == 0 && is_sub_router<H1>)
826  
        {
835  
        {
827  
            static_assert(!std::is_lvalue_reference_v<H1>,
836  
            static_assert(!std::is_lvalue_reference_v<H1>,
828  
                "pass sub-routers by value or std::move()");
837  
                "pass sub-routers by value or std::move()");
829  
            this->inline_router(pattern,
838  
            this->inline_router(pattern,
830  
                std::forward<H1>(h1));
839  
                std::forward<H1>(h1));
831  
        }
840  
        }
832  
        else
841  
        else
833  
        {
842  
        {
834  
            static_assert(handler_crvals<H1, HN...>,
843  
            static_assert(handler_crvals<H1, HN...>,
835  
                "pass handlers by value or std::move()");
844  
                "pass handlers by value or std::move()");
836  
            static_assert(! handler_check<8, H1, HN...>,
845  
            static_assert(! handler_check<8, H1, HN...>,
837  
                "cannot use exception handlers here");
846  
                "cannot use exception handlers here");
838  
            static_assert(handler_check<3, H1, HN...>,
847  
            static_assert(handler_check<3, H1, HN...>,
839  
                "invalid handler signature");
848  
                "invalid handler signature");
840  
            this->add_middleware(pattern, make_handlers(ht_,
849  
            this->add_middleware(pattern, make_handlers(ht_,
841  
                std::forward<H1>(h1), std::forward<HN>(hn)...));
850  
                std::forward<H1>(h1), std::forward<HN>(hn)...));
842  
        }
851  
        }
843  
    }
852  
    }
844  

853  

845  
    /** Add global middleware handlers.
854  
    /** Add global middleware handlers.
846  

855  

847  
        Each handler registered with this function participates in the
856  
        Each handler registered with this function participates in the
848  
        routing and error-dispatch process as described in the
857  
        routing and error-dispatch process as described in the
849  
        @ref router class documentation. Handlers execute in the
858  
        @ref router class documentation. Handlers execute in the
850  
        order they are added and may return @ref route_next to transfer
859  
        order they are added and may return @ref route_next to transfer
851  
        control to the next handler in the chain.
860  
        control to the next handler in the chain.
852  

861  

853  
        This is equivalent to writing:
862  
        This is equivalent to writing:
854  
        @code
863  
        @code
855  
        use( "/", h1, hn... );
864  
        use( "/", h1, hn... );
856  
        @endcode
865  
        @endcode
857  

866  

858  
        @par Example
867  
        @par Example
859  
        @code
868  
        @code
860  
        r.use(
869  
        r.use(
861  
            []( Params& p )
870  
            []( Params& p )
862  
            {
871  
            {
863  
                p.res.erase( "X-Powered-By" );
872  
                p.res.erase( "X-Powered-By" );
864  
                return route_next;
873  
                return route_next;
865  
            } );
874  
            } );
866  
        @endcode
875  
        @endcode
867  

876  

868  
        @par Constraints
877  
        @par Constraints
869  

878  

870  
        @p h1 must not be convertible to @ref std::string_view.
879  
        @p h1 must not be convertible to @ref std::string_view.
871  

880  

872  
        @param h1 The first handler to add.
881  
        @param h1 The first handler to add.
873  

882  

874  
        @param hn Additional handlers to add, invoked after @p h1 in
883  
        @param hn Additional handlers to add, invoked after @p h1 in
875  
        registration order.
884  
        registration order.
876  
    */
885  
    */
877  
    template<class H1, class... HN>
886  
    template<class H1, class... HN>
878  
    void use(H1&& h1, HN&&... hn)
887  
    void use(H1&& h1, HN&&... hn)
879  
        requires (!std::convertible_to<H1, std::string_view>)
888  
        requires (!std::convertible_to<H1, std::string_view>)
880  
    {
889  
    {
881  
        use(std::string_view(),
890  
        use(std::string_view(),
882  
            std::forward<H1>(h1), std::forward<HN>(hn)...);
891  
            std::forward<H1>(h1), std::forward<HN>(hn)...);
883  
    }
892  
    }
884  

893  

885  
    /** Add exception handlers for a route pattern.
894  
    /** Add exception handlers for a route pattern.
886  

895  

887  
        Registers one or more exception handlers that will be invoked
896  
        Registers one or more exception handlers that will be invoked
888  
        when an exception is thrown during request processing for routes
897  
        when an exception is thrown during request processing for routes
889  
        matching the specified pattern.
898  
        matching the specified pattern.
890  

899  

891  
        Handlers are invoked in the order provided until one handles
900  
        Handlers are invoked in the order provided until one handles
892  
        the exception.
901  
        the exception.
893  

902  

894  
        @par Example
903  
        @par Example
895  
        @code
904  
        @code
896  
        app.except( "/api*",
905  
        app.except( "/api*",
897  
            []( route_params& p, std::exception const& ex )
906  
            []( route_params& p, std::exception const& ex )
898  
            {
907  
            {
899  
                p.res.set_status( 500 );
908  
                p.res.set_status( 500 );
900  
                return route_done;
909  
                return route_done;
901  
            } );
910  
            } );
902  
        @endcode
911  
        @endcode
903  

912  

904  
        @param pattern The route pattern to match, or empty to match
913  
        @param pattern The route pattern to match, or empty to match
905  
        all routes.
914  
        all routes.
906  

915  

907  
        @param h1 The first exception handler.
916  
        @param h1 The first exception handler.
908  

917  

909  
        @param hn Additional exception handlers.
918  
        @param hn Additional exception handlers.
910  
    */
919  
    */
911  
    template<class H1, class... HN>
920  
    template<class H1, class... HN>
912  
    void except(
921  
    void except(
913  
        std::string_view pattern,
922  
        std::string_view pattern,
914  
        H1&& h1, HN&&... hn)
923  
        H1&& h1, HN&&... hn)
915  
    {
924  
    {
916  
        static_assert(handler_crvals<H1, HN...>,
925  
        static_assert(handler_crvals<H1, HN...>,
917  
            "pass handlers by value or std::move()");
926  
            "pass handlers by value or std::move()");
918  
        static_assert(handler_check<8, H1, HN...>,
927  
        static_assert(handler_check<8, H1, HN...>,
919  
            "only exception handlers are allowed here");
928  
            "only exception handlers are allowed here");
920  
        this->add_middleware(pattern, make_handlers(ht_,
929  
        this->add_middleware(pattern, make_handlers(ht_,
921  
            std::forward<H1>(h1), std::forward<HN>(hn)...));
930  
            std::forward<H1>(h1), std::forward<HN>(hn)...));
922  
    }
931  
    }
923  

932  

924  
    /** Add global exception handlers.
933  
    /** Add global exception handlers.
925  

934  

926  
        Registers one or more exception handlers that will be invoked
935  
        Registers one or more exception handlers that will be invoked
927  
        when an exception is thrown during request processing for any
936  
        when an exception is thrown during request processing for any
928  
        route.
937  
        route.
929  

938  

930  
        Equivalent to calling `except( "", h1, hn... )`.
939  
        Equivalent to calling `except( "", h1, hn... )`.
931  

940  

932  
        @par Example
941  
        @par Example
933  
        @code
942  
        @code
934  
        app.except(
943  
        app.except(
935  
            []( route_params& p, std::exception const& ex )
944  
            []( route_params& p, std::exception const& ex )
936  
            {
945  
            {
937  
                p.res.set_status( 500 );
946  
                p.res.set_status( 500 );
938  
                return route_done;
947  
                return route_done;
939  
            } );
948  
            } );
940  
        @endcode
949  
        @endcode
941  

950  

942  
        @param h1 The first exception handler.
951  
        @param h1 The first exception handler.
943  

952  

944  
        @param hn Additional exception handlers.
953  
        @param hn Additional exception handlers.
945  
    */
954  
    */
946  
    template<class H1, class... HN>
955  
    template<class H1, class... HN>
947  
    void except(H1&& h1, HN&&... hn)
956  
    void except(H1&& h1, HN&&... hn)
948  
        requires (!std::convertible_to<H1, std::string_view>)
957  
        requires (!std::convertible_to<H1, std::string_view>)
949  
    {
958  
    {
950  
        static_assert(handler_crvals<H1, HN...>,
959  
        static_assert(handler_crvals<H1, HN...>,
951  
            "pass handlers by value or std::move()");
960  
            "pass handlers by value or std::move()");
952  
        static_assert(handler_check<8, H1, HN...>,
961  
        static_assert(handler_check<8, H1, HN...>,
953  
            "only exception handlers are allowed here");
962  
            "only exception handlers are allowed here");
954  
        except(std::string_view(),
963  
        except(std::string_view(),
955  
            std::forward<H1>(h1), std::forward<HN>(hn)...);
964  
            std::forward<H1>(h1), std::forward<HN>(hn)...);
956  
    }
965  
    }
957  

966  

958  
    /** Add handlers for all HTTP methods matching a path pattern.
967  
    /** Add handlers for all HTTP methods matching a path pattern.
959  

968  

960  
        This registers regular handlers for the specified path pattern,
969  
        This registers regular handlers for the specified path pattern,
961  
        participating in dispatch as described in the @ref router
970  
        participating in dispatch as described in the @ref router
962  
        class documentation. Handlers run when the route matches,
971  
        class documentation. Handlers run when the route matches,
963  
        regardless of HTTP method, and execute in registration order.
972  
        regardless of HTTP method, and execute in registration order.
964  
        Error handlers and routers cannot be passed here. A new route
973  
        Error handlers and routers cannot be passed here. A new route
965  
        object is created even if the pattern already exists.
974  
        object is created even if the pattern already exists.
966  

975  

967  
        @par Example
976  
        @par Example
968  
        @code
977  
        @code
969  
        r.route( "/status" )
978  
        r.route( "/status" )
970  
            .add( method::head, check_headers )
979  
            .add( method::head, check_headers )
971  
            .add( method::get, send_status )
980  
            .add( method::get, send_status )
972  
            .all( log_access );
981  
            .all( log_access );
973  
        @endcode
982  
        @endcode
974  

983  

975  
        @par Preconditions
984  
        @par Preconditions
976  

985  

977  
        @p pattern must be a valid path pattern; it must not be empty.
986  
        @p pattern must be a valid path pattern; it must not be empty.
978  

987  

979  
        @param pattern The path pattern to match.
988  
        @param pattern The path pattern to match.
980  

989  

981  
        @param h1 The first handler to add.
990  
        @param h1 The first handler to add.
982  

991  

983  
        @param hn Additional handlers to add, invoked after @p h1 in
992  
        @param hn Additional handlers to add, invoked after @p h1 in
984  
        registration order.
993  
        registration order.
985  
    */
994  
    */
986  
    template<class H1, class... HN>
995  
    template<class H1, class... HN>
987  
    void all(
996  
    void all(
988  
        std::string_view pattern,
997  
        std::string_view pattern,
989  
        H1&& h1, HN&&... hn)
998  
        H1&& h1, HN&&... hn)
990  
    {
999  
    {
991  
        static_assert(handler_crvals<H1, HN...>,
1000  
        static_assert(handler_crvals<H1, HN...>,
992  
            "pass handlers by value or std::move()");
1001  
            "pass handlers by value or std::move()");
993  
        static_assert(handler_check<1, H1, HN...>,
1002  
        static_assert(handler_check<1, H1, HN...>,
994  
            "only normal route handlers are allowed here");
1003  
            "only normal route handlers are allowed here");
995  
        this->route(pattern).all(
1004  
        this->route(pattern).all(
996  
            std::forward<H1>(h1), std::forward<HN>(hn)...);
1005  
            std::forward<H1>(h1), std::forward<HN>(hn)...);
997  
    }
1006  
    }
998  

1007  

999  
    /** Add route handlers for a method and pattern.
1008  
    /** Add route handlers for a method and pattern.
1000  

1009  

1001  
        This registers regular handlers for the specified HTTP verb and
1010  
        This registers regular handlers for the specified HTTP verb and
1002  
        path pattern, participating in dispatch as described in the
1011  
        path pattern, participating in dispatch as described in the
1003  
        @ref router class documentation. Error handlers and
1012  
        @ref router class documentation. Error handlers and
1004  
        routers cannot be passed here.
1013  
        routers cannot be passed here.
1005  

1014  

1006  
        @param verb The known HTTP method to match.
1015  
        @param verb The known HTTP method to match.
1007  

1016  

1008  
        @param pattern The path pattern to match.
1017  
        @param pattern The path pattern to match.
1009  

1018  

1010  
        @param h1 The first handler to add.
1019  
        @param h1 The first handler to add.
1011  

1020  

1012  
        @param hn Additional handlers to add, invoked after @p h1 in
1021  
        @param hn Additional handlers to add, invoked after @p h1 in
1013  
        registration order.
1022  
        registration order.
1014  
    */
1023  
    */
1015  
    template<class H1, class... HN>
1024  
    template<class H1, class... HN>
1016  
    void add(
1025  
    void add(
1017  
        http::method verb,
1026  
        http::method verb,
1018  
        std::string_view pattern,
1027  
        std::string_view pattern,
1019  
        H1&& h1, HN&&... hn)
1028  
        H1&& h1, HN&&... hn)
1020  
    {
1029  
    {
1021  
        static_assert(handler_crvals<H1, HN...>,
1030  
        static_assert(handler_crvals<H1, HN...>,
1022  
            "pass handlers by value or std::move()");
1031  
            "pass handlers by value or std::move()");
1023  
        static_assert(handler_check<1, H1, HN...>,
1032  
        static_assert(handler_check<1, H1, HN...>,
1024  
            "only normal route handlers are allowed here");
1033  
            "only normal route handlers are allowed here");
1025  
        this->route(pattern).add(verb,
1034  
        this->route(pattern).add(verb,
1026  
            std::forward<H1>(h1), std::forward<HN>(hn)...);
1035  
            std::forward<H1>(h1), std::forward<HN>(hn)...);
1027  
    }
1036  
    }
1028  

1037  

1029  
    /** Add route handlers for a method string and pattern.
1038  
    /** Add route handlers for a method string and pattern.
1030  

1039  

1031  
        This registers regular handlers for the specified HTTP verb and
1040  
        This registers regular handlers for the specified HTTP verb and
1032  
        path pattern, participating in dispatch as described in the
1041  
        path pattern, participating in dispatch as described in the
1033  
        @ref router class documentation. Error handlers and
1042  
        @ref router class documentation. Error handlers and
1034  
        routers cannot be passed here.
1043  
        routers cannot be passed here.
1035  

1044  

1036  
        @param verb The HTTP method string to match.
1045  
        @param verb The HTTP method string to match.
1037  

1046  

1038  
        @param pattern The path pattern to match.
1047  
        @param pattern The path pattern to match.
1039  

1048  

1040  
        @param h1 The first handler to add.
1049  
        @param h1 The first handler to add.
1041  

1050  

1042  
        @param hn Additional handlers to add, invoked after @p h1 in
1051  
        @param hn Additional handlers to add, invoked after @p h1 in
1043  
        registration order.
1052  
        registration order.
1044  
    */
1053  
    */
1045  
    template<class H1, class... HN>
1054  
    template<class H1, class... HN>
1046  
    void add(
1055  
    void add(
1047  
        std::string_view verb,
1056  
        std::string_view verb,
1048  
        std::string_view pattern,
1057  
        std::string_view pattern,
1049  
        H1&& h1, HN&&... hn)
1058  
        H1&& h1, HN&&... hn)
1050  
    {
1059  
    {
1051  
        static_assert(handler_crvals<H1, HN...>,
1060  
        static_assert(handler_crvals<H1, HN...>,
1052  
            "pass handlers by value or std::move()");
1061  
            "pass handlers by value or std::move()");
1053  
        static_assert(handler_check<1, H1, HN...>,
1062  
        static_assert(handler_check<1, H1, HN...>,
1054  
            "only normal route handlers are allowed here");
1063  
            "only normal route handlers are allowed here");
1055  
        this->route(pattern).add(verb,
1064  
        this->route(pattern).add(verb,
1056  
            std::forward<H1>(h1), std::forward<HN>(hn)...);
1065  
            std::forward<H1>(h1), std::forward<HN>(hn)...);
1057  
    }
1066  
    }
1058  

1067  

1059  
    /** Return a fluent route for the specified path pattern.
1068  
    /** Return a fluent route for the specified path pattern.
1060  

1069  

1061  
        Adds a new route to the router for the given pattern.
1070  
        Adds a new route to the router for the given pattern.
1062  
        A new route object is always created, even if another
1071  
        A new route object is always created, even if another
1063  
        route with the same pattern already exists. The returned
1072  
        route with the same pattern already exists. The returned
1064  
        @ref fluent_route reference allows method-specific handler
1073  
        @ref fluent_route reference allows method-specific handler
1065  
        registration (such as GET or POST) or catch-all handlers
1074  
        registration (such as GET or POST) or catch-all handlers
1066  
        with @ref fluent_route::all.
1075  
        with @ref fluent_route::all.
1067  

1076  

1068  
        @param pattern The path expression to match against request
1077  
        @param pattern The path expression to match against request
1069  
        targets. This may include parameters or wildcards following
1078  
        targets. This may include parameters or wildcards following
1070  
        the router's pattern syntax. May not be empty.
1079  
        the router's pattern syntax. May not be empty.
1071  

1080  

1072  
        @return A fluent route interface for chaining handler
1081  
        @return A fluent route interface for chaining handler
1073  
        registrations.
1082  
        registrations.
1074  
    */
1083  
    */
1075  
    auto
1084  
    auto
1076  
    route(
1085  
    route(
1077  
        std::string_view pattern) -> fluent_route
1086  
        std::string_view pattern) -> fluent_route
1078  
    {
1087  
    {
1079  
        return fluent_route(*this, pattern);
1088  
        return fluent_route(*this, pattern);
1080  
    }
1089  
    }
1081  

1090  

1082  
    /** Set the handler for automatic OPTIONS responses.
1091  
    /** Set the handler for automatic OPTIONS responses.
1083  

1092  

1084  
        When an OPTIONS request matches a route but no explicit OPTIONS
1093  
        When an OPTIONS request matches a route but no explicit OPTIONS
1085  
        handler is registered, this handler is invoked with the pre-built
1094  
        handler is registered, this handler is invoked with the pre-built
1086  
        Allow header value. This follows Express.js semantics where
1095  
        Allow header value. This follows Express.js semantics where
1087  
        explicit OPTIONS handlers take priority.
1096  
        explicit OPTIONS handlers take priority.
1088  

1097  

1089  
        @param h A callable with signature `route_task(P&, std::string_view)`
1098  
        @param h A callable with signature `route_task(P&, std::string_view)`
1090  
        where the string_view contains the pre-built Allow header value.
1099  
        where the string_view contains the pre-built Allow header value.
1091  
    */
1100  
    */
1092  
    template<class H>
1101  
    template<class H>
1093  
    void set_options_handler(H&& h)
1102  
    void set_options_handler(H&& h)
1094  
    {
1103  
    {
1095  
        static_assert(
1104  
        static_assert(
1096  
            std::is_invocable_r_v<route_task, const std::decay_t<H>&, P&, std::string_view>,
1105  
            std::is_invocable_r_v<route_task, const std::decay_t<H>&, P&, std::string_view>,
1097  
            "Handler must have signature: route_task(P&, std::string_view)");
1106  
            "Handler must have signature: route_task(P&, std::string_view)");
1098  
        this->set_options_handler_impl(
1107  
        this->set_options_handler_impl(
1099  
            std::make_unique<options_handler_impl<H>>(
1108  
            std::make_unique<options_handler_impl<H>>(
1100  
                std::forward<H>(h)));
1109  
                std::forward<H>(h)));
1101  
    }
1110  
    }
1102  
};
1111  
};
1103  

1112  

1104  
template<class P, class HT>
1113  
template<class P, class HT>
1105  
class router<P, HT>::
1114  
class router<P, HT>::
1106  
    fluent_route
1115  
    fluent_route
1107  
{
1116  
{
1108  
public:
1117  
public:
1109  
    fluent_route(fluent_route const&) = default;
1118  
    fluent_route(fluent_route const&) = default;
1110  

1119  

1111  
    /** Add handlers that apply to all HTTP methods.
1120  
    /** Add handlers that apply to all HTTP methods.
1112  

1121  

1113  
        This registers regular handlers that run for any request matching
1122  
        This registers regular handlers that run for any request matching
1114  
        the route's pattern, regardless of HTTP method. Handlers are
1123  
        the route's pattern, regardless of HTTP method. Handlers are
1115  
        appended to the route's handler sequence and are invoked in
1124  
        appended to the route's handler sequence and are invoked in
1116  
        registration order whenever a preceding handler returns
1125  
        registration order whenever a preceding handler returns
1117  
        @ref route_next. Error handlers and routers cannot be passed here.
1126  
        @ref route_next. Error handlers and routers cannot be passed here.
1118  

1127  

1119  
        This function returns a @ref fluent_route, allowing additional
1128  
        This function returns a @ref fluent_route, allowing additional
1120  
        method registrations to be chained. For example:
1129  
        method registrations to be chained. For example:
1121  
        @code
1130  
        @code
1122  
        r.route( "/resource" )
1131  
        r.route( "/resource" )
1123  
            .all( log_request )
1132  
            .all( log_request )
1124  
            .add( method::get, show_resource )
1133  
            .add( method::get, show_resource )
1125  
            .add( method::post, update_resource );
1134  
            .add( method::post, update_resource );
1126  
        @endcode
1135  
        @endcode
1127  

1136  

1128  
        @param h1 The first handler to add.
1137  
        @param h1 The first handler to add.
1129  

1138  

1130  
        @param hn Additional handlers to add, invoked after @p h1 in
1139  
        @param hn Additional handlers to add, invoked after @p h1 in
1131  
        registration order.
1140  
        registration order.
1132  

1141  

1133  
        @return A reference to `*this` for chained registrations.
1142  
        @return A reference to `*this` for chained registrations.
1134  
    */
1143  
    */
1135  
    template<class H1, class... HN>
1144  
    template<class H1, class... HN>
1136  
    auto all(
1145  
    auto all(
1137  
        H1&& h1, HN&&... hn) ->
1146  
        H1&& h1, HN&&... hn) ->
1138  
            fluent_route
1147  
            fluent_route
1139  
    {
1148  
    {
1140  
        static_assert(handler_check<1, H1, HN...>);
1149  
        static_assert(handler_check<1, H1, HN...>);
1141  
        owner_.add_to_route(route_idx_, std::string_view{},
1150  
        owner_.add_to_route(route_idx_, std::string_view{},
1142  
            owner_.make_handlers(owner_.ht_,
1151  
            owner_.make_handlers(owner_.ht_,
1143  
                std::forward<H1>(h1), std::forward<HN>(hn)...));
1152  
                std::forward<H1>(h1), std::forward<HN>(hn)...));
1144  
        return *this;
1153  
        return *this;
1145  
    }
1154  
    }
1146  

1155  

1147  
    /** Add handlers for a specific HTTP method.
1156  
    /** Add handlers for a specific HTTP method.
1148  

1157  

1149  
        This registers regular handlers for the given method on the
1158  
        This registers regular handlers for the given method on the
1150  
        current route, participating in dispatch as described in the
1159  
        current route, participating in dispatch as described in the
1151  
        @ref router class documentation. Handlers are appended
1160  
        @ref router class documentation. Handlers are appended
1152  
        to the route's handler sequence and invoked in registration
1161  
        to the route's handler sequence and invoked in registration
1153  
        order whenever a preceding handler returns @ref route_next.
1162  
        order whenever a preceding handler returns @ref route_next.
1154  
        Error handlers and routers cannot be passed here.
1163  
        Error handlers and routers cannot be passed here.
1155  

1164  

1156  
        @param verb The HTTP method to match.
1165  
        @param verb The HTTP method to match.
1157  

1166  

1158  
        @param h1 The first handler to add.
1167  
        @param h1 The first handler to add.
1159  

1168  

1160  
        @param hn Additional handlers to add, invoked after @p h1 in
1169  
        @param hn Additional handlers to add, invoked after @p h1 in
1161  
        registration order.
1170  
        registration order.
1162  

1171  

1163  
        @return A reference to `*this` for chained registrations.
1172  
        @return A reference to `*this` for chained registrations.
1164  
    */
1173  
    */
1165  
    template<class H1, class... HN>
1174  
    template<class H1, class... HN>
1166  
    auto add(
1175  
    auto add(
1167  
        http::method verb,
1176  
        http::method verb,
1168  
        H1&& h1, HN&&... hn) ->
1177  
        H1&& h1, HN&&... hn) ->
1169  
            fluent_route
1178  
            fluent_route
1170  
    {
1179  
    {
1171  
        static_assert(handler_check<1, H1, HN...>);
1180  
        static_assert(handler_check<1, H1, HN...>);
1172  
        owner_.add_to_route(route_idx_, verb,
1181  
        owner_.add_to_route(route_idx_, verb,
1173  
            owner_.make_handlers(owner_.ht_,
1182  
            owner_.make_handlers(owner_.ht_,
1174  
                std::forward<H1>(h1), std::forward<HN>(hn)...));
1183  
                std::forward<H1>(h1), std::forward<HN>(hn)...));
1175  
        return *this;
1184  
        return *this;
1176  
    }
1185  
    }
1177  

1186  

1178  
    /** Add handlers for a method string.
1187  
    /** Add handlers for a method string.
1179  

1188  

1180  
        This registers regular handlers for the given HTTP method string
1189  
        This registers regular handlers for the given HTTP method string
1181  
        on the current route, participating in dispatch as described in
1190  
        on the current route, participating in dispatch as described in
1182  
        the @ref router class documentation. This overload is
1191  
        the @ref router class documentation. This overload is
1183  
        intended for methods not represented by @ref http::method.
1192  
        intended for methods not represented by @ref http::method.
1184  
        Handlers are appended to the route's handler sequence and invoked
1193  
        Handlers are appended to the route's handler sequence and invoked
1185  
        in registration order whenever a preceding handler returns
1194  
        in registration order whenever a preceding handler returns
1186  
        @ref route_next. Error handlers and routers cannot be passed here.
1195  
        @ref route_next. Error handlers and routers cannot be passed here.
1187  

1196  

1188  
        @param verb The HTTP method string to match.
1197  
        @param verb The HTTP method string to match.
1189  

1198  

1190  
        @param h1 The first handler to add.
1199  
        @param h1 The first handler to add.
1191  

1200  

1192  
        @param hn Additional handlers to add, invoked after @p h1 in
1201  
        @param hn Additional handlers to add, invoked after @p h1 in
1193  
        registration order.
1202  
        registration order.
1194  

1203  

1195  
        @return A reference to `*this` for chained registrations.
1204  
        @return A reference to `*this` for chained registrations.
1196  
    */
1205  
    */
1197  
    template<class H1, class... HN>
1206  
    template<class H1, class... HN>
1198  
    auto add(
1207  
    auto add(
1199  
        std::string_view verb,
1208  
        std::string_view verb,
1200  
        H1&& h1, HN&&... hn) ->
1209  
        H1&& h1, HN&&... hn) ->
1201  
            fluent_route
1210  
            fluent_route
1202  
    {
1211  
    {
1203  
        static_assert(handler_check<1, H1, HN...>);
1212  
        static_assert(handler_check<1, H1, HN...>);
1204  
        owner_.add_to_route(route_idx_, verb,
1213  
        owner_.add_to_route(route_idx_, verb,
1205  
            owner_.make_handlers(owner_.ht_,
1214  
            owner_.make_handlers(owner_.ht_,
1206  
                std::forward<H1>(h1), std::forward<HN>(hn)...));
1215  
                std::forward<H1>(h1), std::forward<HN>(hn)...));
1207  
        return *this;
1216  
        return *this;
1208  
    }
1217  
    }
1209  

1218  

1210  
private:
1219  
private:
1211  
    friend class router;
1220  
    friend class router;
1212  
    fluent_route(
1221  
    fluent_route(
1213  
        router& owner,
1222  
        router& owner,
1214  
        std::string_view pattern)
1223  
        std::string_view pattern)
1215  
        : route_idx_(owner.new_route(pattern))
1224  
        : route_idx_(owner.new_route(pattern))
1216  
        , owner_(owner)
1225  
        , owner_(owner)
1217  
    {
1226  
    {
1218  
    }
1227  
    }
1219  

1228  

1220  
    std::size_t route_idx_;
1229  
    std::size_t route_idx_;
1221  
    router& owner_;
1230  
    router& owner_;
1222  
};
1231  
};
1223  

1232  

1224  
} // http
1233  
} // http
1225  
} // boost
1234  
} // boost
1226  

1235  

1227  
#endif
1236  
#endif