RESTinio
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 
18 namespace restinio
19 {
20 
21 namespace 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::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  */
160 template<
161  std::size_t Size,
162  typename Extra_Data_Factory = no_extra_data_factory_t >
164 {
167 
168  using handler_holder_t = std::function<
170  >;
171 
173 
174  template< std::size_t >
175  void
176  store_to() noexcept {}
177 
178  template<
179  std::size_t Index,
180  typename Head,
181  typename... Tail >
182  void
183  store_to( Head && head, Tail && ...tail )
184  {
185  m_handlers[ Index ] =
186  [handler = std::move(head)]
188  {
189  return handler( req );
190  };
191 
192  store_to< Index + 1u >( std::forward<Tail>(tail)... );
193  }
194 
195 public:
196  /*!
197  * @attention
198  * The default constructor is disabled. It's because a chain should
199  * be initialized by handlers at the creation time. Because of that
200  * fixed_size_chain_t isn't a DefaultConstructible type.
201  */
202  fixed_size_chain_t() = delete;
203 
204  /*!
205  * @brief Initializing constructor.
206  *
207  * @note
208  * The number of parameters should match the value of @a Size
209  * template parameter.
210  */
211  template< typename... Handlers >
212  fixed_size_chain_t( Handlers && ...handlers )
213  {
214  static_assert( Size == sizeof...(handlers),
215  "Wrong number of parameters for the constructor of "
216  "fixed_size_chain_t<Size>. Exact `Size` parameters expected" );
217 
218  store_to< 0u >( std::forward<Handlers>(handlers)... );
219  }
220 
221  RESTINIO_NODISCARD
222  request_handling_status_t
224  {
225  for( auto & h : m_handlers )
226  {
228 
229  switch( result )
230  {
233  // There is no need to try next handler.
234  return result;
235 
237  // Nothing to do. The next handler should be tried.
238  break;
239  }
240  }
241 
242  return request_not_handled();
243  }
244 };
245 
246 } /* namespace sync_chain */
247 
248 } /* namespace restinio */
RESTINIO_NODISCARD request_handling_status_t operator()(const actual_request_handle_t &req) const
Definition: fixed_size.hpp:223
std::array< handler_holder_t, Size > m_handlers
Definition: fixed_size.hpp:172
fixed_size_chain_t(Handlers &&...handlers)
Initializing constructor.
Definition: fixed_size.hpp:212
void store_to(Head &&head, Tail &&...tail)
Definition: fixed_size.hpp:183
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