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 request-headers.
8  *
9  * @since v.0.6.13
10  */
11 
12 #pragma once
13 
14 #include <restinio/request_handler.hpp>
15 
16 #include <vector>
17 
18 namespace restinio
19 {
20 
21 namespace sync_chain
22 {
23 
24 //
25 // growable_size_chain_t
26 //
27 /*!
28  * @brief A holder of variable-size chain of synchronous handlers.
29  *
30  * @note
31  * Once a list of handler is filled and an instance of growable_size_chain_t
32  * is created that instance can't be changed: a new handler can't be added, and
33  * an old handler can be removed. The creation of growable_size_chain_t
34  * instance is performed by the help of growable_size_chain_t::builder_t
35  * class.
36  *
37  * Usage example for the case when there is no extra-data in a request object.
38  * @code
39  * struct my_traits : public restinio::default_traits_t {
40  * using request_handler_t = restinio::sync_chain::growable_size_chain_t;
41  * };
42  *
43  * // The first handler in the chain.
44  * restinio::request_handling_status_t headers_checker(
45  * const restinio::request_handle_t & req )
46  * {
47  * ... // Checks values of HTTP-fields and rejects invalid requests.
48  * }
49  *
50  * // The second handler in the chain.
51  * restinio::request_handling_status_t authentificator(
52  * const restinio::request_handle_t & req )
53  * {
54  * ... // Checks user's credentials and rejects requests from
55  * // non-authentificated users.
56  * }
57  *
58  * // The last handler in the chain.
59  * restinio::request_handling_status_t actual_handler(
60  * const restinio::request_handle_t & req )
61  * {
62  * ... // Actual processing.
63  * }
64  *
65  * // Building of a chain.
66  * restinio::sync_chain::growable_size_chain_t::builder_t builder;
67  * if(config.force_headers_checking())
68  * builder.add(headers_checker);
69  * if(config.force_user_authentification())
70  * builder.add(authentificator);
71  * builder.add(actual_handler);
72  *
73  * restinio::run(
74  * on_thread_pool<my_traits>(16)
75  * .address(...)
76  * .port(...)
77  * .request_handler(builder.release())
78  * );
79  * @endcode
80  *
81  * Usage example for the case when some extra-data is incorporated into
82  * a request object.
83  * @code
84  * struct my_extra_data_factory {
85  * // A data formed by checker of HTTP-fields.
86  * struct request_specific_fields_t {...};
87  *
88  * // A data formed by user-authentificator.
89  * struct user_info_t {...};
90  *
91  * // A data to be incorporated into a request object.
92  * using data_t = std::tuple<
93  * std::optional<request_specific_fields_t>,
94  * std::optional<user_info_t>>;
95  *
96  * void make_within(restinio::extra_data_buffer_t<data_t> buf) {
97  * new(buf.get()) data_t{};
98  * }
99  * };
100  *
101  * struct my_traits : public restinio::default_traits_t {
102  * using extra_data_factory_t = my_extra_data_factory;
103  * using request_handler_t = restinio::sync_chain::growable_size_chain_t<
104  * extra_data_factory>;
105  * };
106  *
107  * using my_request_handle_t =
108  * restinio::generic_request_handle_t<my_extra_data_factory::data_t>;
109  *
110  * // The first handler in the chain.
111  * restinio::request_handling_status_t headers_checker(
112  * const my_request_handle_t & req )
113  * {
114  * ... // Checks values of HTTP-fields and rejects invalid requests.
115  * }
116  *
117  * // The second handler in the chain.
118  * restinio::request_handling_status_t authentificator(
119  * const my_request_handle_t & req )
120  * {
121  * ... // Checks user's credentials and rejects requests from
122  * // non-authentificated users.
123  * }
124  *
125  * // The last handler in the chain.
126  * restinio::request_handling_status_t actual_handler(
127  * const my_request_handle_t & req )
128  * {
129  * auto & field_values = std::get<
130  * std::optional<my_extra_data_factory::request_specific_fields_t>>(req->extra_data());
131  * auto & user_info = std::get<
132  * std::optional<my_extra_data_factory::user_info_t>>(req->extra_data());
133  * ... // Actual processing.
134  * }
135  *
136  * // Building of a chain.
137  * restinio::sync_chain::growable_size_chain_t::builder_t builder;
138  * if(config.force_headers_checking())
139  * builder.add(headers_checker);
140  * if(config.force_user_authentification())
141  * builder.add(authentificator);
142  * builder.add(actual_handler);
143  *
144  * restinio::run(
145  * on_thread_pool<my_traits>(16)
146  * .address(...)
147  * .port(...)
148  * .request_handler(builder.release())
149  * );
150  * @endcode
151  *
152  * @tparam Extra_Data_Factory The type of extra-data-factory specified in
153  * the server's traits.
154  *
155  * @since v.0.6.13
156  */
157 template< typename Extra_Data_Factory = no_extra_data_factory_t >
159 {
160  // Helper class to allow the creation of growable_size_chain_t only
161  // for the friends of growable_size_chain_t.
162  struct creation_token_t {};
163 
164 public:
165  friend class builder_t;
166 
167  /*!
168  * @brief A builder of an instance of growable_size_chain.
169  *
170  * Creates an empty instance of growable_size_chain_t in the constructor.
171  * That instance can be obtained by release() method.
172  *
173  * @note
174  * New handlers can be added to the chain by add() method until
175  * release() is called.
176  *
177  * @attention
178  * An instance of builder works like an unique_ptr: it will hold
179  * a nullptr after a call of release() method.
180  *
181  * @since v.0.6.13
182  */
183  class builder_t
184  {
185  public:
188  {}
189 
190  /*!
191  * @brief Stop adding of new handlers and acquire the chain instance.
192  *
193  * @note
194  * The builder object should not be used after the calling of
195  * that method.
196  */
199  release() noexcept
200  {
201  return { std::move(m_chain) };
202  }
203 
204  /*!
205  * @brief Add a new handler to the chain.
206  */
207  template< typename Handler >
208  void
210  {
211  if( !m_chain )
212  throw exception_t{ "an attempt to add a handler to "
213  "a growable-size-chain builder that already "
214  "released"
215  };
219  } );
220  }
221 
222  private:
224  };
225 
226 private:
229 
230  using handler_holder_t = std::function<
232  >;
233 
235 
236  /*!
237  * @brief The main constructor.
238  *
239  * It has that form because the default constructor is public and
240  * marked as deleted.
241  */
243 
244 public:
245  /*!
246  * @note
247  * The default constructor is disable because an instance of
248  * that class should be created and filled by using builder_t.
249  */
250  growable_size_chain_t() = delete;
251 
252  RESTINIO_NODISCARD
253  request_handling_status_t
255  {
256  for( auto & h : m_handlers )
257  {
259 
260  switch( result )
261  {
264  // There is no need to try next handler.
265  return result;
266 
268  // Nothing to do. The next handler should be tried.
269  break;
270  }
271  }
272 
273  return request_not_handled();
274  }
275 };
276 
277 } /* namespace sync_chain */
278 
279 } /* namespace restinio */
std::vector< handler_holder_t > m_handlers
void add(Handler &&handler)
Add a new handler to the chain.
RESTINIO_NODISCARD request_handling_status_t operator()(const actual_request_handle_t &req) const
std::enable_if< std::is_same< Parameter_Container, query_string_params_t >::value||std::is_same< Parameter_Container, router::route_params_t >::value, optional_t< Value_Type > >::type opt_value(const Parameter_Container &params, string_view_t key)
Gets the value of a parameter specified by key wrapped in optional_t<Value_Type> if parameter exists ...
Definition: value_or.hpp:64
growable_size_chain_t(creation_token_t)
The main constructor.