Line data Source code
1 : //
2 : // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
3 : //
4 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 : //
7 : // Official repository: https://github.com/cppalliance/http
8 : //
9 :
10 : #ifndef BOOST_HTTP_SERVER_DETAIL_ROUTER_BASE_HPP
11 : #define BOOST_HTTP_SERVER_DETAIL_ROUTER_BASE_HPP
12 :
13 : #include <boost/http/detail/config.hpp>
14 : #include <boost/http/server/route_handler.hpp>
15 : #include <boost/http/method.hpp>
16 : #include <boost/url/url_view.hpp>
17 : #include <boost/mp11/algorithm.hpp>
18 : #include <boost/assert.hpp>
19 : #include <exception>
20 : #include <memory>
21 : #include <string_view>
22 : #include <type_traits>
23 :
24 : namespace boost {
25 : namespace http {
26 : namespace detail {
27 :
28 : template<class> class router;
29 :
30 : /** Non-template base class for all routers.
31 :
32 : Holds a shared reference to an internal routing table
33 : that is built incrementally as routes are added. The routing
34 : table uses contiguous flat arrays for cache-friendly dispatch.
35 :
36 : Copies share the same underlying routing data. Modifying
37 : a router after it has been copied is not permitted and
38 : results in undefined behavior.
39 :
40 : @par Thread Safety
41 :
42 : `dispatch` may be called concurrently on routers that share
43 : the same data. Modification through `router` is not
44 : thread-safe and must not be performed concurrently with any
45 : other operation.
46 :
47 : @see router
48 : */
49 : class BOOST_HTTP_DECL
50 : router_base
51 : {
52 : struct impl;
53 : std::shared_ptr<impl> impl_;
54 :
55 : template<class, class> friend class http::router;
56 :
57 : protected:
58 : using opt_flags = unsigned int;
59 :
60 : enum
61 : {
62 : is_invalid = 0,
63 : is_plain = 1,
64 : is_error = 2,
65 : is_exception = 8
66 : };
67 :
68 : struct BOOST_HTTP_DECL
69 : handler
70 : {
71 : char const kind;
72 227 : explicit handler(char kind_) noexcept : kind(kind_) {}
73 227 : virtual ~handler() = default;
74 : virtual auto invoke(route_params&) const ->
75 : route_task = 0;
76 : };
77 :
78 : using handler_ptr = std::unique_ptr<handler>;
79 :
80 : struct handlers
81 : {
82 : std::size_t n;
83 : handler_ptr* p;
84 : };
85 :
86 : struct BOOST_HTTP_DECL
87 : options_handler
88 : {
89 224 : virtual ~options_handler() = default;
90 : virtual route_task invoke(
91 : route_params&,
92 : std::string_view allow) const = 0;
93 : };
94 :
95 : using options_handler_ptr = std::unique_ptr<options_handler>;
96 :
97 : protected:
98 : using match_result = route_params::match_result;
99 : struct matcher;
100 : struct entry;
101 :
102 : // Construct with options
103 : explicit router_base(opt_flags);
104 :
105 : // Registration helpers
106 : void add_middleware(std::string_view pattern, handlers hn);
107 : void inline_router(std::string_view pattern, router_base&& sub);
108 : std::size_t new_route(std::string_view pattern);
109 : void add_to_route(std::size_t idx, http::method verb, handlers hn);
110 : void add_to_route(std::size_t idx, std::string_view verb, handlers hn);
111 : void finalize_pending();
112 : void set_options_handler_impl(options_handler_ptr p);
113 :
114 : public:
115 : /** Default constructor.
116 :
117 : Creates a router in an empty state. The only valid
118 : operations on a default-constructed router are
119 : assignment, destruction, and copying.
120 : */
121 : router_base() = default;
122 :
123 75 : router_base(router_base const&) = default;
124 72 : router_base(router_base&&) noexcept = default;
125 2 : router_base& operator=(router_base const&) = default;
126 : router_base& operator=(router_base&&) noexcept = default;
127 369 : ~router_base() = default;
128 :
129 : /** Dispatch a request using a known HTTP method.
130 :
131 : @param verb The HTTP method to match. Must not be
132 : @ref http::method::unknown.
133 :
134 : @param url The full request target used for route matching.
135 :
136 : @param p The params to pass to handlers.
137 :
138 : @return A task yielding the @ref route_result describing
139 : how routing completed.
140 :
141 : @throws std::invalid_argument If @p verb is
142 : @ref http::method::unknown.
143 : */
144 : route_task
145 : dispatch(
146 : http::method verb,
147 : urls::url_view const& url,
148 : route_params& p) const;
149 :
150 : /** Dispatch a request using a method string.
151 :
152 : @param verb The HTTP method string to match. Must not be empty.
153 :
154 : @param url The full request target used for route matching.
155 :
156 : @param p The params to pass to handlers.
157 :
158 : @return A task yielding the @ref route_result describing
159 : how routing completed.
160 :
161 : @throws std::invalid_argument If @p verb is empty.
162 : */
163 : route_task
164 : dispatch(
165 : std::string_view verb,
166 : urls::url_view const& url,
167 : route_params& p) const;
168 :
169 : /** Maximum nesting depth for routers.
170 :
171 : This limit applies to nested routers added via use().
172 : Exceeding this limit throws std::length_error at
173 : insertion time.
174 : */
175 : static constexpr std::size_t max_path_depth = 16;
176 : };
177 :
178 : } // detail
179 : } // http
180 : } // boost
181 :
182 : #endif
|