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 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
18namespace restinio
19{
20
21namespace 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 */
157template< 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.
163
164public:
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 */
184 {
185 public:
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 */
197 [[nodiscard]]
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
209 add( Handler && handler )
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 };
216 m_chain->m_handlers.push_back(
217 growable_size_chain_t::handler_holder_t{
218 std::forward<Handler>(handler)
219 } );
220 }
221
222 private:
224 };
225
226private:
229
230 using handler_holder_t = std::function<
231 request_handling_status_t(const actual_request_handle_t &)
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
244public:
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 */
251
252 [[nodiscard]]
254 operator()( const actual_request_handle_t & req ) const
255 {
256 for( auto & h : m_handlers )
257 {
258 const request_handling_status_t result = h( req );
259
260 switch( result )
261 {
262 case request_handling_status_t::accepted:
263 case request_handling_status_t::rejected:
264 // There is no need to try next handler.
265 return result;
266
267 case request_handling_status_t::not_handled:
268 // Nothing to do. The next handler should be tried.
269 break;
270 }
271 }
272
274 }
275};
276
277} /* namespace sync_chain */
278
279} /* namespace restinio */
Exception class for all exceptions thrown by RESTinio.
Definition exception.hpp:26
exception_t(const char *err)
Definition exception.hpp:29
A builder of an instance of growable_size_chain.
std::unique_ptr< growable_size_chain_t > m_chain
void add(Handler &&handler)
Add a new handler to the chain.
std::unique_ptr< growable_size_chain_t > release() noexcept
Stop adding of new handlers and acquire the chain instance.
A holder of variable-size chain of synchronous handlers.
request_handling_status_t operator()(const actual_request_handle_t &req) const
growable_size_chain_t(creation_token_t)
The main constructor.
std::function< request_handling_status_t(const actual_request_handle_t &) > handler_holder_t
std::vector< handler_holder_t > m_handlers
constexpr request_handling_status_t request_not_handled() noexcept
request_handling_status_t
Request handling status.
The default extra-data-factory to be used in server's traits if a user doesn't specify own one.