RESTinio
Loading...
Searching...
No Matches
fixed_size.hpp
Go to the documentation of this file.
1/*
2 * RESTinio
3 */
4
5/*!
6 * @file
7 * @brief Stuff related to fixed-size chain of request-headers.
8 *
9 * @since v.0.6.13
10 */
11
12#pragma once
13
14#include <restinio/request_handler.hpp>
15
16#include <array>
17
18namespace restinio
19{
20
21namespace sync_chain
22{
23
24//
25// fixed_size_chain_t
26//
27/*!
28 * @brief A holder of fixed-size chain of synchronous handlers.
29 *
30 * @note
31 * An instance of that type is intended to be filled with actual handlers
32 * at the creation time. After that new handlers can't be added to the chain,
33 * and old handlers can't be removed from the chain.
34 *
35 * Usage example for the case when there is no extra-data in a request object.
36 * @code
37 * struct my_traits : public restinio::default_traits_t {
38 * using request_handler_t = restinio::sync_chain::fixed_size_chain_t<3>;
39 * };
40 *
41 * // The first handler in the chain.
42 * restinio::request_handling_status_t headers_checker(
43 * const restinio::request_handle_t & req )
44 * {
45 * ... // Checks values of HTTP-fields and rejects invalid requests.
46 * }
47 *
48 * // The second handler in the chain.
49 * restinio::request_handling_status_t authentificator(
50 * const restinio::request_handle_t & req )
51 * {
52 * ... // Checks user's credentials and rejects requests from
53 * // non-authentificated users.
54 * }
55 *
56 * // The last handler in the chain.
57 * restinio::request_handling_status_t actual_handler(
58 * const restinio::request_handle_t & req )
59 * {
60 * ... // Actual processing.
61 * }
62 *
63 * restinio::run(
64 * on_thread_pool<my_traits>(16)
65 * .address(...)
66 * .port(...)
67 * .request_handler(
68 * // Just enumerate all handlers.
69 * headers_checker,
70 * authentificator,
71 * actual_handler )
72 * );
73 * @endcode
74 *
75 * An instance of `fixed_size_chain_t` can also be created manually and
76 * passed to server's settings by `unique_ptr`:
77 * @code
78 * auto chain = std::make_unique<restinio::sync_chain::fixed_size_chain_t<3>>(
79 * headers_checker, authentificator, actual_handler);
80 * ...
81 * restinio::run(
82 * on_thread_pool<my_traits>(16)
83 * .address(...)
84 * .port(...)
85 * .request_handler(std::move(chain))
86 * );
87 * @endcode
88 *
89 * Usage example for the case when some extra-data is incorporated into
90 * a request object.
91 * @code
92 * struct my_extra_data_factory {
93 * // A data formed by checker of HTTP-fields.
94 * struct request_specific_fields_t {...};
95 *
96 * // A data formed by user-authentificator.
97 * struct user_info_t {...};
98 *
99 * // A data to be incorporated into a request object.
100 * using data_t = std::tuple<request_specific_fields_t, user_info_t>;
101 *
102 * void make_within(restinio::extra_data_buffer_t<data_t> buf) {
103 * new(buf.get()) data_t{};
104 * }
105 * };
106 *
107 * struct my_traits : public restinio::default_traits_t {
108 * using extra_data_factory_t = my_extra_data_factory;
109 * using request_handler_t = restinio::sync_chain::fixed_size_chain_t<
110 * 3,
111 * extra_data_factory>;
112 * };
113 *
114 * using my_request_handle_t =
115 * restinio::generic_request_handle_t<my_extra_data_factory::data_t>;
116 *
117 * // The first handler in the chain.
118 * restinio::request_handling_status_t headers_checker(
119 * const my_request_handle_t & req )
120 * {
121 * ... // Checks values of HTTP-fields and rejects invalid requests.
122 * }
123 *
124 * // The second handler in the chain.
125 * restinio::request_handling_status_t authentificator(
126 * const my_request_handle_t & req )
127 * {
128 * ... // Checks user's credentials and rejects requests from
129 * // non-authentificated users.
130 * }
131 *
132 * // The last handler in the chain.
133 * restinio::request_handling_status_t actual_handler(
134 * const my_request_handle_t & req )
135 * {
136 * auto & field_values = std::get<my_extra_data_factory::request_specific_fields_t>(req->extra_data());
137 * auto & user_info = std::get<my_extra_data_factory::user_info_t>(req->extra_data());
138 * ... // Actual processing.
139 * }
140 *
141 * restinio::run(
142 * on_thread_pool<my_traits>(16)
143 * .address(...)
144 * .port(...)
145 * .request_handler(
146 * // Just enumerate all handlers.
147 * headers_checker,
148 * authentificator,
149 * actual_handler )
150 * );
151 * @endcode
152 *
153 * @tparam Size The exact number of handlers in the chain.
154 *
155 * @tparam Extra_Data_Factory The type of extra-data-factory specified in
156 * the server's traits.
157 *
158 * @since v.0.6.13
159 */
160template<
161 std::size_t Size,
162 typename Extra_Data_Factory = no_extra_data_factory_t >
164{
167
168 using handler_holder_t = std::function<
169 request_handling_status_t(const actual_request_handle_t &)
170 >;
171
172 std::array< handler_holder_t, Size > m_handlers;
173
174 template<
175 typename Head,
176 typename... Tail >
177 void
178 store_to( std::size_t index, Head && head, Tail && ...tail )
179 {
180 m_handlers[ index ] =
181 [handler = std::move(head)]
182 ( const actual_request_handle_t & req ) -> request_handling_status_t
183 {
184 return handler( req );
185 };
186
187 if constexpr( 0u != sizeof...(tail) )
188 store_to( index + 1u, std::forward<Tail>(tail)... );
189 }
190
191public:
192 /*!
193 * @attention
194 * The default constructor is disabled. It's because a chain should
195 * be initialized by handlers at the creation time. Because of that
196 * fixed_size_chain_t isn't a DefaultConstructible type.
197 */
199
200 /*!
201 * @brief Initializing constructor.
202 *
203 * @note
204 * The number of parameters should match the value of @a Size
205 * template parameter.
206 */
207 template< typename... Handlers >
208 fixed_size_chain_t( Handlers && ...handlers )
209 {
210 static_assert( Size == sizeof...(handlers),
211 "Wrong number of parameters for the constructor of "
212 "fixed_size_chain_t<Size>. Exact `Size` parameters expected" );
213
214 store_to( 0u, std::forward<Handlers>(handlers)... );
215 }
216
217 [[nodiscard]]
219 operator()( const actual_request_handle_t & req ) const
220 {
221 for( auto & h : m_handlers )
222 {
223 const request_handling_status_t result = h( req );
224
225 switch( result )
226 {
229 // There is no need to try next handler.
230 return result;
231
233 // Nothing to do. The next handler should be tried.
234 break;
235 }
236 }
237
239 }
240};
241
242} /* namespace sync_chain */
243
244} /* namespace restinio */
A holder of fixed-size chain of synchronous handlers.
std::array< handler_holder_t, Size > m_handlers
void store_to(std::size_t index, Head &&head, Tail &&...tail)
fixed_size_chain_t(Handlers &&...handlers)
Initializing constructor.
std::function< request_handling_status_t(const actual_request_handle_t &) > handler_holder_t
request_handling_status_t operator()(const actual_request_handle_t &req) const
constexpr request_handling_status_t request_not_handled() noexcept
request_handling_status_t
Request handling status.
@ accepted
Request accepted for handling.
@ not_handled
The request wasn't handled. If there is another handler to be tried it should be tried....
@ rejected
Request wasn't accepted for handling.
The default extra-data-factory to be used in server's traits if a user doesn't specify own one.