RESTinio
Loading...
Searching...
No Matches
growable_size.hpp
Go to the documentation of this file.
1/*
2 * RESTinio
3 */
4
5/*!
6 * @file
7 * @brief Stuff related to growable-size chain of async request-headers.
8 *
9 * @since v.0.7.0
10 */
11
12#pragma once
13
14#include <restinio/async_chain/common.hpp>
15
16#include <vector>
17
18namespace restinio::async_chain
19{
20
21//
22// growable_size_chain_t
23//
24/*!
25 * @brief A holder of variable-size chain of asynchronous handlers.
26 *
27 * @note
28 * Once a list of schedulers is filled and an instance of growable_size_chain_t
29 * is created that instance can't be changed: a new scheduler can't be added, and
30 * an old scheduler can be removed. The creation of growable_size_chain_t
31 * instance is performed by the help of growable_size_chain_t::builder_t
32 * class.
33 *
34 * Usage example for the case when there is no extra-data in a request object
35 * (please note that this is simplified example without actual asynchronous code,
36 * all schedulers work as synchronous handlers):
37 * @code
38 * struct my_traits : public restinio::default_traits_t {
39 * using request_handler_t = restinio::async_chain::growable_size_chain_t;
40 * };
41 *
42 * // The first handler in the chain.
43 * restinio::async_chain::schedule_result_t headers_checker(
44 * restinio::async_chain::unique_async_handling_controller_t<> controller )
45 * {
46 * ... // Checks values of HTTP-fields and rejects invalid requests.
47 *
48 * // Activation of the next handler.
49 * next( std::move(controller) );
50 *
51 * return restinio::async_chain::ok();
52 * }
53 *
54 * // The second handler in the chain.
55 * restinio::async_chain::schedule_result_t authentificator(
56 * restinio::async_chain::unique_async_handling_controller_t<> controller )
57 * {
58 * ... // Checks user's credentials and rejects requests from
59 * // non-authentificated users.
60 *
61 * // Activation of the next handler.
62 * next( std::move(controller) );
63 *
64 * return restinio::async_chain::ok();
65 * }
66 *
67 * // The last handler in the chain.
68 * restinio::async_chain::schedule_result_t actual_handler(
69 * restinio::async_chain::unique_async_handling_controller_t<> controller )
70 * {
71 * ... // Actual processing.
72 *
73 * return restinio::async_chain::ok();
74 * }
75 *
76 * // Building of a chain.
77 * restinio::async_chain::growable_size_chain_t<>::builder_t builder;
78 * if(config.force_headers_checking())
79 * builder.add(headers_checker);
80 * if(config.force_user_authentification())
81 * builder.add(authentificator);
82 * builder.add(actual_handler);
83 *
84 * restinio::run(
85 * on_thread_pool<my_traits>(16)
86 * .address(...)
87 * .port(...)
88 * .request_handler(builder.release())
89 * );
90 * @endcode
91 *
92 * Usage example for the case when some extra-data is incorporated into
93 * a request object:
94 * (please note that this is simplified example without actual asynchronous code,
95 * all schedulers work as synchronous handlers):
96 * @code
97 * struct my_extra_data_factory {
98 * // A data formed by checker of HTTP-fields.
99 * struct request_specific_fields_t {...};
100 *
101 * // A data formed by user-authentificator.
102 * struct user_info_t {...};
103 *
104 * // A data to be incorporated into a request object.
105 * using data_t = std::tuple<
106 * std::optional<request_specific_fields_t>,
107 * std::optional<user_info_t>>;
108 *
109 * void make_within(restinio::extra_data_buffer_t<data_t> buf) {
110 * new(buf.get()) data_t{};
111 * }
112 * };
113 *
114 * struct my_traits : public restinio::default_traits_t {
115 * using extra_data_factory_t = my_extra_data_factory;
116 * using request_handler_t = restinio::async_chain::growable_size_chain_t<
117 * extra_data_factory>;
118 * };
119 *
120 * using my_unique_controller_t =
121 * restinio::async_chain::unique_async_handling_controller_t<my_extra_data_factory>;
122 * using my_request_handle_t = my_unique_controller_t::actual_request_handle_t;
123 *
124 * // The first handler in the chain.
125 * restinio::async_chain::schedule_result_t headers_checker(
126 * my_unique_controller_t controller )
127 * {
128 * const my_request_handle_t req = acceptor->request_handle();
129 * ... // Checks values of HTTP-fields and rejects invalid requests.
130 * ...
131 * next( std::move(controller) );
132 * return restinio::async_chain::ok();
133 * }
134 *
135 * // The second handler in the chain.
136 * restinio::async_chain::schedule_result_t authentificator(
137 * my_unique_controller_t controller )
138 * {
139 * const my_request_handle_t req = acceptor->request_handle();
140 * ... // Checks user's credentials and rejects requests from
141 * // non-authentificated users.
142 * ...
143 * next( std::move(controller) );
144 * return restinio::async_chain::ok();
145 * }
146 *
147 * // The last handler in the chain.
148 * restinio::async_chain::schedule_result_t actual_handler(
149 * my_unique_controller_t controller )
150 * {
151 * const my_request_handle_t req = acceptor->request_handle();
152 * auto & field_values = std::get<my_extra_data_factory::request_specific_fields_t>(req->extra_data());
153 * auto & user_info = std::get<my_extra_data_factory::user_info_t>(req->extra_data());
154 * ... // Actual processing.
155 * return restinio::async_chain::ok();
156 * }
157 *
158 * // Building of a chain.
159 * restinio::sync_chain::growable_size_chain_t::builder_t builder;
160 * if(config.force_headers_checking())
161 * builder.add(headers_checker);
162 * if(config.force_user_authentification())
163 * builder.add(authentificator);
164 * builder.add(actual_handler);
165 *
166 * restinio::run(
167 * on_thread_pool<my_traits>(16)
168 * .address(...)
169 * .port(...)
170 * .request_handler(builder.release())
171 * );
172 * @endcode
173 *
174 * @tparam Extra_Data_Factory The type of extra-data-factory specified in
175 * the server's traits.
176 *
177 * @since v.0.7.0
178 */
179template< typename Extra_Data_Factory = no_extra_data_factory_t >
181{
182 // Helper class to allow the creation of growable_size_chain_t only
183 // for the friends of growable_size_chain_t.
185
186 //! Short alias for a handling controller.
188
189 //! Short alias for a scheduler.
191
192 //! Short alias for a vector of schedulers.
194
195 //! Short alias to a smart pointer to the source request.
197 typename async_handling_controller_t< Extra_Data_Factory >::actual_request_handle_t;
198
199 //! Short alias for the result of controller's on_next method.
201 typename async_handling_controller_t< Extra_Data_Factory >::actual_on_next_result_t;
202
203 /*!
204 * @brief Actual implementation of the controller interface.
205 *
206 * @note
207 * Object of this type holds a copy of the source vector of schedulers.
208 */
209 class actual_controller_t final
210 : public async_handling_controller_t< Extra_Data_Factory >
211 {
212 //! The source request.
214 //! Request schedulers.
216 //! Index of the current scheduler to be used.
217 /*!
218 * @note
219 * May be equal to or greater than m_schedulers.size() in the case
220 * when all schedulers are already processed.
221 */
222 std::size_t m_current{};
223
224 public:
225 //! Initializing constructor.
228 const schedulers_vector_t & schedulers )
229 : m_request{ request }
231 {}
232
233 [[nodiscard]]
235 request_handle() const noexcept override { return m_request; }
236
237 private:
238 [[nodiscard]]
240 on_next() override
241 {
242 const auto index_to_use = m_current;
243 ++m_current;
244
245 if( index_to_use >= m_schedulers.size() )
246 {
247 return { no_more_schedulers_t{} };
248 }
249 else
250 {
251 return { m_schedulers[ index_to_use ] };
252 }
253 }
254 };
255
256public:
257 friend class builder_t;
258
259 /*!
260 * @brief A builder of an instance of growable_size_chain.
261 *
262 * Creates an empty instance of growable_size_chain_t in the constructor.
263 * That instance can be obtained by release() method.
264 *
265 * @note
266 * New schedulers can be added to the chain by add() method until
267 * release() is called.
268 *
269 * @attention
270 * An instance of builder works like an unique_ptr: it will hold
271 * a nullptr after a call of release() method.
272 *
273 * @since v.0.7.0
274 */
276 {
277 public:
281
282 /*!
283 * @brief Stop adding of new schedulers and acquire the chain instance.
284 *
285 * @note
286 * The builder object should not be used after the calling of
287 * that method.
288 */
289 [[nodiscard]]
291 release() noexcept
292 {
293 return { std::move(m_chain) };
294 }
295
296 /*!
297 * @brief Add a new scheduler to the chain.
298 */
299 template< typename Scheduler >
300 void
301 add( Scheduler && scheduler )
302 {
303 if( !m_chain )
304 throw exception_t{ "an attempt to add a scheduler to "
305 "a growable-size-chain builder that already "
306 "released"
307 };
308 m_chain->m_schedulers.push_back(
309 growable_size_chain_t::scheduler_holder_t{
310 std::forward<Scheduler>(scheduler)
311 } );
312 }
313
314 private:
316 };
317
318private:
319 //! The vector of schedulers.
321
322 /*!
323 * @brief The main constructor.
324 *
325 * It has that form because the default constructor is public and
326 * marked as deleted.
327 */
329
330public:
331 /*!
332 * @note
333 * The default constructor is disable because an instance of
334 * that class should be created and filled by using builder_t.
335 */
337
338 /*!
339 * Initiates execution of the first scheduler in the chain.
340 *
341 * @note
342 * Always returns request_handling_status_t::accepted.
343 */
344 [[nodiscard]]
346 operator()( const actual_request_handle_t & req ) const
347 {
348 unique_controller_t controller =
349 std::make_unique< actual_controller_t >(
350 req,
351 m_schedulers );
352 next( std::move(controller) );
353
354 return request_accepted();
355 }
356};
357
358} /* namespace restinio::async_chain */
Interface of a controller of an async chan.
Definition common.hpp:146
actual_on_next_result_t on_next() override
Command to try find a next scheduler to be invoked.
std::size_t m_current
Index of the current scheduler to be used.
const actual_request_handle_t & request_handle() const noexcept override
Get reference to the source request.
actual_controller_t(actual_request_handle_t request, const schedulers_vector_t &schedulers)
Initializing constructor.
const actual_request_handle_t m_request
The source request.
A builder of an instance of growable_size_chain.
std::unique_ptr< growable_size_chain_t > release() noexcept
Stop adding of new schedulers and acquire the chain instance.
std::unique_ptr< growable_size_chain_t > m_chain
void add(Scheduler &&scheduler)
Add a new scheduler to the chain.
A holder of variable-size chain of asynchronous handlers.
typename async_handling_controller_t< Extra_Data_Factory >::actual_request_handle_t actual_request_handle_t
Short alias to a smart pointer to the source request.
typename async_handling_controller_t< Extra_Data_Factory >::actual_on_next_result_t actual_on_next_result_t
Short alias for the result of controller's on_next method.
schedulers_vector_t m_schedulers
The vector of schedulers.
request_handling_status_t operator()(const actual_request_handle_t &req) const
growable_size_chain_t(creation_token_t)
The main constructor.
Exception class for all exceptions thrown by RESTinio.
Definition exception.hpp:26
exception_t(const char *err)
Definition exception.hpp:29
constexpr request_handling_status_t request_accepted() noexcept
request_handling_status_t
Request handling status.
Special type to be used as an indicator that there are no more schedulers in an async chain.
Definition common.hpp:106
The default extra-data-factory to be used in server's traits if a user doesn't specify own one.