RESTinio
traits.hpp
Go to the documentation of this file.
1 /*
2  restinio
3 */
4 
5 /*!
6  HTTP server traits.
7 */
8 
9 #pragma once
10 
11 #include <restinio/request_handler.hpp>
12 #include <restinio/asio_timer_manager.hpp>
13 #include <restinio/null_logger.hpp>
14 #include <restinio/connection_state_listener.hpp>
15 #include <restinio/ip_blocker.hpp>
16 #include <restinio/default_strands.hpp>
17 #include <restinio/connection_count_limiter.hpp>
18 
19 #include <restinio/utils/metaprogramming.hpp>
20 
21 namespace restinio
22 {
23 
24 namespace details
25 {
26 
28 {
29 
30 template< typename, typename, typename = restinio::utils::metaprogramming::void_t<> >
31 struct valid_handler_type : public std::false_type {};
32 
33 template< typename Handler, typename Extra_Data_Factory >
35  Handler,
39  std::is_same<
41  decltype(std::declval<Handler>()(
42  std::declval<
44  typename Extra_Data_Factory::data_t
45  >
46  >()))
47  >::value,
48  bool
49  >
50  >
51  > : public std::true_type
52 {};
53 
54 } /* namespace valid_request_handler_type_check */
55 
56 //
57 // autodetect_request_handler_type
58 //
59 /*!
60  * @brief A special type to be used as indicator that the type of
61  * a request handler should be automatically detected.
62  *
63  * In versions prior to 0.6.13 request-handlers in RESTinio have the
64  * same format. But since v.0.6.13 the actual type of request-handler
65  * is dependent on extra-data-factory type. It means that if a user
66  * defines own extra-data-factory for server's traits then user also
67  * has to define own request-handler type:
68  *
69  * @code
70  * struct my_extra_data_factory {...};
71  *
72  * struct my_traits : public restinio::default_traits_t {
73  * using extra_data_factory_t = my_extra_data_factory;
74  * using request_handler_t = std::function<
75  * restinio::request_handling_status_t(
76  * restinio::generic_request_handle_t<
77  * my_extra_data_factory::data_t>)
78  * >;
79  * };
80  * @endcode
81  *
82  * But this is a boring and error-prone task. So RESTinio allows a user
83  * to specify only `extra_data_factory_t` type and skip the definition
84  * of `request_handler_t`. That definition will be performed automatically.
85  *
86  * The actual detection of request-handler type is performed by
87  * using specialization of actual_request_handler_type_detector for
88  * autodetect_request_handler_type.
89  *
90  * @since v.0.6.13
91  */
93 
94 //
95 // actual_request_handler_type_detector
96 //
97 /*!
98  * @brief A metafunction for the detection of type of a request-handler.
99  *
100  * @since v.0.6.13
101  */
102 template<
103  typename Request_Handler,
104  typename Extra_Data_Factory >
106 {
107  static_assert(
111  >::value,
112  "Request_Handler should be invocable with "
113  "generic_request_handle_t<Extra_Data_Factory::data_t>" );
114 
115  using request_handler_t = Request_Handler;
116 };
117 
118 /*!
119  * @brief Special version of metafunction %actual_request_handler_type_detector
120  * for the case of %autodetect_request_handler_type.
121  *
122  * @since v.0.6.13
123  */
124 template< typename Extra_Data_Factory >
127  Extra_Data_Factory >
128 {
129  using request_handler_t = std::function<
132 };
133 
134 } /* namespace details */
135 
136 //
137 // traits_t
138 //
139 
140 template <
141  typename Timer_Manager,
142  typename Logger,
143  typename Request_Handler = details::autodetect_request_handler_type,
144  typename Strand = default_strand_t,
145  typename Socket = asio_ns::ip::tcp::socket >
146 struct traits_t
147 {
148  /*!
149  * @brief A type for HTTP methods mapping.
150  *
151  * If RESTinio is used with vanila version of http_parser then
152  * the default value of http_methods_mapper_t is enough. But if a user
153  * uses modified version of http_parser with support of additional,
154  * not-standard HTTP methods then the user should provide its
155  * http_methods_mapper. For example:
156  * \code
157  * // Definition for non-standard HTTP methods.
158  * // Note: values of HTTP_ENCODE and HTTP_DECODE are from modified
159  * // http_parser version.
160  * constexpr const restinio::http_method_id_t http_encode(HTTP_ENCODE, "ENCODE");
161  * constexpr const restinio::http_method_id_t http_decode(HTTP_DECODE, "DECODE");
162  *
163  * // Definition of non-standard http_method_mapper.
164  * struct my_http_method_mapper {
165  * inline constexpr restinio::http_method_id_t
166  * from_nodejs(int value) noexcept {
167  * switch(value) {
168  * case HTTP_ENCODE: return http_encode;
169  * case HTTP_DECODE: return http_decode;
170  * default: return restinio::default_http_methods_t::from_nodejs(value);
171  * }
172  * }
173  * };
174  * ...
175  * // Make a custom traits with non-standard http_method_mapper.
176  * struct my_server_traits : public restinio::default_traits_t {
177  * using http_methods_mapper_t = my_http_method_mapper;
178  * };
179  * \endcode
180  *
181  * @since v.0.5.0
182  */
184 
185  /*!
186  * @brief A type for connection state listener.
187  *
188  * By default RESTinio doesn't inform about changes with connection state.
189  * But if a user specify its type of connection state listener then
190  * RESTinio will call this listener object when the state of connection
191  * changes.
192  *
193  * An example:
194  * @code
195  * // Definition of user's state listener.
196  * class my_state_listener {
197  * ...
198  * public:
199  * ...
200  * void state_changed(const restinio::connection_state::notice_t & notice) noexcept {
201  * ... // some reaction to state change.
202  * }
203  * };
204  *
205  * // Definition of custom traits for HTTP server.
206  * struct my_server_traits : public restinio::default_traits_t {
207  * using connection_state_listener_t = my_state_listener;
208  * };
209  * @endcode
210  *
211  * @since v.0.5.1
212  */
214 
215  /*!
216  * @brief A type for IP-blocker.
217  *
218  * By default RESTinio's accepts all incoming connections.
219  * But since v.0.5.1 a user can specify IP-blocker object that
220  * will be called for every new connection. This IP-blocker can
221  * deny or allow a new connection.
222  *
223  * Type of that IP-blocker object is specified by typedef
224  * ip_blocker_t.
225  *
226  * An example:
227  * @code
228  * // Definition of user's IP-blocker.
229  * class my_ip_blocker {
230  * ...
231  * public:
232  * ...
233  * restinio::ip_blocker::inspection_result_t
234  * state_changed(const restinio::ip_blocker::incoming_info_t & info) noexcept {
235  * ... // some checking for new connection.
236  * }
237  * };
238  *
239  * // Definition of custom traits for HTTP server.
240  * struct my_server_traits : public restinio::default_traits_t {
241  * using ip_blocker_t = my_ip_blocker;
242  * };
243  * @endcode
244  *
245  * @since v.0.5.1
246  */
248 
249  using timer_manager_t = Timer_Manager;
250  using logger_t = Logger;
251  using request_handler_t = Request_Handler;
252  using strand_t = Strand;
253  using stream_socket_t = Socket;
254 
255  /*!
256  * @brief A flag that enables or disables the usage of connection count
257  * limiter.
258  *
259  * Since v.0.6.12 RESTinio allows to limit the number of active
260  * parallel connections to a server. But the usage of this limit
261  * should be turned on explicitly. For example:
262  * @code
263  * struct my_traits : public restinio::default_traits_t {
264  * static constexpr bool use_connection_count_limiter = true;
265  * };
266  * @endcode
267  * In that case there will be `max_parallel_connections` method
268  * in server_settings_t type. That method should be explicitly
269  * called to set a specific limit (by the default there is no
270  * limit at all):
271  * @code
272  * restinio::server_settings_t<my_traits> settings;
273  * settings.max_parallel_connections(1000u);
274  * @endcode
275  *
276  * @since v.0.6.12
277  */
278  static constexpr bool use_connection_count_limiter = false;
279 
280  /*!
281  * @brief The type of extra-data-factory.
282  *
283  * By the default RESTinio doesn't hold any additional data for a
284  * request object. But if a user has to store some user-specific
285  * data inside a request object the user has to do the following
286  * steps:
287  *
288  * The first one is the definition of factory type that should
289  * look like:
290  * @code
291  * class some_extra_data_factory {
292  * public:
293  * using data_t = ...;
294  *
295  * void make_within(restinio::extra_data_buffer_t<data_t> buf);
296  * };
297  * @endcode
298  * Where the name `data_t` should define a name of type to incorporated
299  * into request object.
300  * And the method `make_within` should call a placement new for
301  * type `data_t` to construct a new object of `data_t` inside the
302  * buffer `buf`:
303  * @code
304  * void some_extra_data_factory::make_within(
305  * restinio::extra_data_buffer_t<data_t> buf) {
306  * new(buf.get()) data_t{...};
307  * }
308  * @endcode
309  *
310  * The second step is the definition of extra-data-factory in server's traits:
311  * @code
312  * struct my_traits : public restinio::default_traits_t {
313  * using extra_data_factory_t = some_extra_data_factory;
314  * };
315  * @endcode
316  *
317  * The third step is the creation of the extra-data-factory instance and
318  * passing it to server settings:
319  * @code
320  * restino::run(on_thread_pool<my_traits>(16)
321  * .port(...)
322  * .address(...)
323  * .extra_data_factory(std::make_shared<some_extra_data_factory>(..))
324  * .request_handler(...)
325  * ...
326  * );
327  * @endcode
328  * Please note that the third step is not necessary if extra-data-factory
329  * type is DefaultConstructible. In that case an instance of
330  * extra-data-factory will be created automatically.
331  *
332  * Please note that if RESTinio's server is used with express-like or
333  * easy_parser-based routers then `request_handler_t` should be
334  * defined with the respect to extra-data-factory type:
335  * @code
336  * struct my_extra_data_factory {
337  * struct data_t {...};
338  *
339  * void make_within(restinio::extra_data_buffer_t<data_t> buf) {
340  * new(buf.get()) data_t{};
341  * }
342  * };
343  *
344  * using my_router = restinio::router::generic_express_router_t<
345  * restinio::router::std_regex_engine_t,
346  * my_extra_data_factory
347  * >;
348  *
349  * struct my_traits : public restinio::default_traits_t {
350  * using extra_data_factory_t = my_extra_data_factory;
351  * using request_handler_t = my_router;
352  * };
353  * @endcode
354  *
355  * @since v.0.6.13
356  */
358 };
359 
360 //
361 // request_handler_type_from_traits_t
362 //
363 /*!
364  * @brief A metafunction for extraction a request-handler type from
365  * server's traits.
366  *
367  * This metafunction is necessary because `request_handler_t` in
368  * Traits can be an alias for details::autodetect_request_handler_type.
369  * Because of that details::actual_request_handler_type_detector metafunction
370  * is invoked for the detection of request-handler type.
371  *
372  * @since v.0.6.13
373  */
374 template< typename Traits >
375 using request_handler_type_from_traits_t =
377  typename Traits::request_handler_t,
378  typename Traits::extra_data_factory_t
379  >::request_handler_t;
380 
381 //
382 // generic_request_type_from_traits_t
383 //
384 /*!
385  * @brief A metafunction for the detection of actual type of request-object
386  * from server's traits.
387  *
388  * The actual type of request-object depends from extra-data-factory.
389  * This metafunction detect the actual type with the respect to the
390  * definition of `extra_data_factory_t` inside Traits.
391  *
392  * @since v.0.6.13
393  */
394 template< typename Traits >
397 
398 //
399 // single_thread_traits_t
400 //
401 
402 template <
403  typename Timer_Manager,
404  typename Logger,
408 
409 //
410 // default_traits_t
411 //
412 
414 
415 /*!
416  * \brief Default traits for single-threaded HTTP-server.
417  *
418  * Uses default timer manager. And null logger.
419  *
420  * Usage example:
421  * \code
422  * struct my_traits : public restinio::default_single_thread_traits_t {
423  * using logger_t = my_special_single_threaded_logger_type;
424  * };
425  * \endcode
426  *
427  * \since
428  * v.0.4.0
429  */
433 
434 } /* namespace restinio */
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
static constexpr bool use_connection_count_limiter
A flag that enables or disables the usage of connection count limiter.
Definition: traits.hpp:278
A special type to be used as indicator that the type of a request handler should be automatically det...
Definition: traits.hpp:92