RESTinio
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 
18 namespace 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  */
179 template< 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.
184  struct creation_token_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.
198 
199  //! Short alias for the result of controller's on_next method.
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  */
223 
224  public:
225  //! Initializing constructor.
227  actual_request_handle_t request,
228  const schedulers_vector_t & schedulers )
229  : m_request{ request }
230  , m_schedulers{ schedulers }
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 
256 public:
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  */
275  class builder_t
276  {
277  public:
280  {}
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  };
311  } );
312  }
313 
314  private:
316  };
317 
318 private:
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 
330 public:
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  */
336  growable_size_chain_t() = delete;
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]]
347  {
350  req,
351  m_schedulers );
352  next( std::move(controller) );
353 
354  return request_accepted();
355  }
356 };
357 
358 } /* namespace restinio::async_chain */
std::unique_ptr< growable_size_chain_t > m_chain
std::unique_ptr< growable_size_chain_t > release() noexcept
Stop adding of new schedulers and acquire the chain instance.
A holder of variable-size chain of asynchronous handlers.
std::size_t m_current
Index of the current scheduler to be used.
std::enable_if< std::is_same< Parameter_Container, query_string_params_t >::value||std::is_same< Parameter_Container, router::route_params_t >::value, std::optional< Value_Type > >::type opt_value(const Parameter_Container &params, string_view_t key)
Gets the value of a parameter specified by key wrapped in std::optional<Value_Type> if parameter exis...
Definition: value_or.hpp:64
A builder of an instance of growable_size_chain.
request_handling_status_t operator()(const actual_request_handle_t &req) const
const actual_request_handle_t & request_handle() const noexcept override
Get reference to the source request.
void add(Scheduler &&scheduler)
Add a new scheduler to the chain.
actual_on_next_result_t on_next() override
Command to try find a next scheduler to be invoked.
growable_size_chain_t(creation_token_t)
The main constructor.
const actual_request_handle_t m_request
The source request.
schedulers_vector_t m_schedulers
The vector of schedulers.
actual_controller_t(actual_request_handle_t request, const schedulers_vector_t &schedulers)
Initializing constructor.