RESTinio
easy_parser_router.hpp
Go to the documentation of this file.
1 /*
2  * RESTinio
3  */
4 
5 /*!
6  * @file
7  * @brief A router based on easy_parser.
8  *
9  * @since v.0.6.6
10  */
11 
12 #pragma once
13 
14 #include <restinio/router/impl/target_path_holder.hpp>
15 #include <restinio/router/non_matched_request_handler.hpp>
16 #include <restinio/router/method_matcher.hpp>
17 
18 #include <restinio/helpers/easy_parser.hpp>
19 
20 #include <vector>
21 
22 namespace restinio
23 {
24 
25 namespace router
26 {
27 
29 {
30 
31 namespace impl
32 {
33 
34 namespace meta = restinio::utils::metaprogramming;
35 namespace ep = restinio::easy_parser;
36 
38 
39 /*!
40  * @brief Helper type to indicate a negative match attempt.
41  *
42  * @since v.0.6.6
43  */
44 struct no_match_t {};
45 
46 /*!
47  * @brief An interface for one entry of easy_parser-based router.
48  *
49  * @tparam Extra_Data The type of extra-data incorporated into a request object.
50  * This type is added to router_entry_t in v.0.6.13.
51  *
52  * @since v.0.6.6
53  */
54 template< typename Extra_Data >
56 {
57 public:
59 
60  virtual ~router_entry_t() = default;
61 
62  //! An attempt to match a request against the route.
63  /*!
64  * If match successed the corresponding request handler is called
65  * and its return value is returned in form of
66  * request_handling_status_t value.
67  *
68  * If match failed then an instance of no_match_t is returned.
69  */
72  try_handle(
74  target_path_holder_t & target_path ) const = 0;
75 };
76 
77 /*!
78  * @brief An alias for unique_ptr of router_entry.
79  *
80  * @tparam Extra_Data The type of extra-data incorporated into a request object.
81  * This type is added to router_entry_unique_ptr_t in v.0.6.13.
82  *
83  * @since v.0.6.6
84  */
85 template< typename Extra_Data >
88 
89 //
90 // actual_router_entry_t
91 //
92 /*!
93  * @brief An actual implementation of router_entry interface.
94  *
95  * @tparam Producer A type of producer that parses a route and produces
96  * a value to be used as argument(s) for request handler.
97  *
98  * @tparam Extra_Data The type of extra-data incorporated into a request object.
99  * This type is added to actual_router_entry_t in v.0.6.13.
100  *
101  * @tparam Handle A type of request handler.
102  *
103  * @since v.0.6.6
104  */
105 template< typename Extra_Data, typename Producer, typename Handler >
106 class actual_router_entry_t : public router_entry_t< Extra_Data >
107 {
108  //FIXME: compatibility between Extra_Data and Handler should be
109  //checked by static_assert. If it's possible.
110 
111  //! HTTP method to match.
113 
114  //! Parser of a route and producer of argument(s) for request handler.
115  Producer m_producer;
116 
117  //! Request handler to be used.
118  Handler m_handler;
119 
120 public:
121  using actual_request_handle_t =
122  typename router_entry_t<Extra_Data>::actual_request_handle_t;
123 
124  template<
125  typename Method_Matcher,
126  typename Producer_Arg,
127  typename Handler_Arg >
129  Method_Matcher && method_matcher,
130  Producer_Arg && producer,
131  Handler_Arg && handler )
134  {
136  }
137 
138  RESTINIO_NODISCARD
143  {
144  if( m_method_matcher->match( req->header().method() ) )
145  {
147  target_path.view(),
148  m_producer );
149  if( parse_result )
150  {
152  }
153  }
154 
155  return make_unexpected( no_match_t{} );
156  }
157 };
158 
159 //
160 // unescape_transformer_t
161 //
162 /*!
163  * @brief A transformer that performs percent-unescaping of
164  * an input string.
165  *
166  * @since v.0.6.6
167  */
168 template< typename Unescape_Traits >
171 {
173 
174  RESTINIO_NODISCARD
175  result_type
177  {
179  input );
180  }
181 };
182 
183 //
184 // special_produce_tuple_item_clause_t
185 //
186 /*!
187  * @brief A special case of produce-consume clause where the produced
188  * value is stored into a tuple.
189  *
190  * @since v.0.6.6
191  */
192 template< typename Producer, std::size_t Index >
194  : public ep::impl::consume_value_clause_t<
195  Producer,
197 {
199 
201  Producer,
203 
204  // NOTE: this is just a workaround for VS2017.
205  template< typename Producer_Arg >
207  static Producer
209  {
210  return { std::forward<Producer_Arg>(producer) };
211  }
212 
213 public:
214  template< typename Producer_Arg >
216  : base_type_t{
218  consumer_t{} }
219  {}
220 };
221 
222 //
223 // special_exact_fixed_size_fragment_clause_t
224 //
225 /*!
226  * @brief A special clause type for case when
227  * exact_fixed_size_fragment_producer should be used without storing
228  * its value.
229  *
230  * This type is an equivalent of `exact_p() >> skip()`, but it can be
231  * used where a type is required.
232  *
233  * @since v.0.6.6
234  */
235 template< std::size_t Size >
237  : public ep::impl::consume_value_clause_t<
240 {
243 
245  producer_t,
247 
248 public:
250  const char (&fragment)[Size] )
252  {}
253 };
254 
255 //
256 // special_exact_fragment_clause_t
257 //
258 /*!
259  * @brief A special clause type for case when
260  * exact_fragment_producer should be used without storing
261  * its value.
262  *
263  * This type is an equivalent of `exact_p() >> skip()`, but it can be
264  * used where a type is required.
265  *
266  * @since v.0.6.6
267  */
269  : public ep::impl::consume_value_clause_t<
272 {
275 
277  producer_t,
279 
280 public:
281  special_exact_fragment_clause_t( std::string value )
283  {}
284 
285  special_exact_fragment_clause_t( string_view_t value )
286  : base_type_t{
287  producer_t{ std::string{ value.data(), value.size() } },
288  consumer_t{} }
289  {}
290 };
291 
292 namespace dsl_details
293 {
294 
295 // Adds type H to type list R if Is_Producer is true.
296 template< typename H, typename R, bool Is_Producer >
297 struct add_type_if_necessary_impl;
298 
299 template<
300  typename H,
301  template<class...> class To,
302  typename... Results >
303 struct add_type_if_necessary_impl< H, To<Results...>, false >
304 {
305  using type = To<Results...>;
306 };
307 
308 template<
309  typename H,
310  template<class...> class To,
311  typename... Results >
312 struct add_type_if_necessary_impl< H, To<Results...>, true >
313 {
314  using type = To<Results..., typename H::result_type>;
315 };
316 
317 // Adds type H to type list R if H is a producer.
318 template< typename H, typename R >
321 {};
322 
323 // Produces a type-list of producers from type-list From.
324 template< typename From, typename To >
325 struct result_tuple_detector;
326 
327 // Adds a type from Sources to Results only if this type is a producer.
328 template<
329  template<class...> class From,
330  typename... Sources,
331  template<class...> class To,
332  typename... Results >
333 struct result_tuple_detector< From<Sources...>, To<Results...> >
334 {
335  using type = typename result_tuple_detector<
336  meta::tail_of_t< Sources... >,
337  typename add_type_if_necessary<
338  meta::head_of_t< Sources... >,
339  To< Results... > >::type
340  >::type;
341 };
342 
343 template<
344  template<class...> class From,
345  template<class...> class To,
346  typename... Results >
347 struct result_tuple_detector< From<>, To<Results...> >
348 {
349  using type = To<Results...>;
350 };
351 
352 // Produces a type of std::tuple of producers from type-list Args_Type_List.
353 template< typename Args_Type_List >
355 {
356  using type = meta::rename_t<
357  typename result_tuple_detector<
359  meta::type_list<> >::type,
360  std::tuple >;
361 };
362 
363 template< typename Args_Type_List >
364 using detect_result_tuple_t = typename detect_result_tuple<Args_Type_List>::type;
365 
366 // Detects an appropriate type of clause for T.
367 // If T is a producer then there will be a new clause that
368 // consumes a value T produces.
369 // In that case Current_Index will also be incremented.
370 //
371 // If T is not a producer then Current_Index will be kept.
372 //
373 // If T is a string literal, or std::string, or string_view
374 // then T will be replaced by a special clause.
375 template< typename T, bool Is_Producer, std::size_t Current_Index >
377 {
378  using clause_type = T;
379  static constexpr std::size_t next_index = Current_Index;
380 };
381 
382 template< std::size_t Size, std::size_t Current_Index >
383 struct one_clause_type_processor<const char[Size], false, Current_Index>
384 {
386  static constexpr std::size_t next_index = Current_Index;
387 };
388 
389 template< std::size_t Current_Index >
391 {
393  static constexpr std::size_t next_index = Current_Index;
394 };
395 
396 template< std::size_t Current_Index >
398 {
400  static constexpr std::size_t next_index = Current_Index;
401 };
402 
403 template< typename T, std::size_t Current_Index >
404 struct one_clause_type_processor<T, true, Current_Index>
405 {
406  using clause_type = special_produce_tuple_item_clause_t< T, Current_Index >;
407  static constexpr std::size_t next_index = Current_Index + 1u;
408 };
409 
410 // Takes a type-list of user-specified types From and produces a
411 // typelist of actual clauses types To.
412 //
413 // The Current_Index should 0 at the first invocation.
414 template< typename From, typename To, std::size_t Current_Index >
415 struct clauses_type_maker;
416 
417 template<
418  template<class...> class From,
419  typename... Sources,
420  template<class...> class To,
421  typename... Results,
422  std::size_t Current_Index >
423 struct clauses_type_maker< From<Sources...>, To<Results...>, Current_Index >
424 {
425 private:
426  using head_type = meta::head_of_t< Sources... >;
427 
428  using one_clause_type = one_clause_type_processor<
429  head_type,
430  ep::impl::is_producer_v<head_type>,
431  Current_Index >;
432 
433 public:
434  using type = typename clauses_type_maker<
435  meta::tail_of_t< Sources... >,
436  To< Results..., typename one_clause_type::clause_type >,
437  one_clause_type::next_index >::type;
438 };
439 
440 template<
441  template<class...> class From,
442  template<class...> class To,
443  typename... Results,
444  std::size_t Current_Index >
445 struct clauses_type_maker< From<>, To<Results...>, Current_Index >
446 {
447  using type = To< Results... >;
448 };
449 
450 // Takes a type-list of user-specified types Args_Type_List and produces a
451 // typelist of actual clauses types to be used for parsing.
452 template< typename Args_Type_List >
454 {
455  using type = meta::rename_t<
456  typename clauses_type_maker<
458  meta::type_list<>,
459  0u >::type,
460  std::tuple >;
461 };
462 
463 template< typename Args_Type_List >
464 using make_clauses_types_t = typename make_clauses_types<Args_Type_List>::type;
465 
466 //
467 // special_decay
468 //
469 /*!
470  * @brief A special analog of std::decay meta-function that is
471  * handles array differently.
472  *
473  * The std::decay converts `char[]` into `char*` and that is not
474  * appropriate because `const char[]` is handled by
475  * exact_fixed_size_fragment_producer.
476  *
477  * The special_decay keeps the type of arrays and do not handles
478  * function pointers (it's because function pointers is not used
479  * by easy-parser).
480  *
481  * @since v.0.6.6
482  */
483 template< typename T >
485 {
486 private:
488 
489 public:
490  using type = typename std::conditional<
491  std::is_array<U>::value,
492  U,
493  std::remove_cv_t<U>
494  >::type;
495 };
496 
497 } /* namespace dsl_details */
498 
499 //
500 // dsl_processor
501 //
502 /*!
503  * @brief The main meta-function for processing route DSL.
504  *
505  * It takes types of user-supplied clauses/produces and makes
506  * two types:
507  *
508  * - result_tuple. This is a type of std::tuple for holding all values produced
509  * by producers from Args. This tuple can be an empty tuple.
510  * - clauses_tuple. This a type of std::tuple with clauses for parsing of a
511  * user's route.
512  *
513  * @since v.0.6.6
514  */
515 template< typename... Args >
517 {
518  static_assert( 0u != sizeof...(Args), "Args can't be an empty list" );
519 
520  using arg_types = meta::transform_t<
522 
524 
526 };
527 
528 //
529 // path_to_tuple_producer_t
530 //
531 /*!
532  * @brief An implementation of a producer for path_to_tuple case.
533  *
534  * This implementation produces a tuple and provides a way to call a
535  * request-handler with passing that tuple as a single argument.
536  *
537  * @since v.0.6.6
538  */
539 template<
540  typename Target_Type,
541  typename Subitems_Tuple >
544 {
546 
547 public:
548  using base_type_t::base_type_t;
549 
550  template< typename Extra_Data, typename Handler >
552  static auto
555  Handler && handler,
556  typename base_type_t::result_type & type )
557  {
558  return handler( req, type );
559  }
560 };
561 
563 {
564 
565 template<
566  typename F,
567  typename Extra_Data,
568  typename Tuple,
569  std::size_t... Indexes >
570 decltype(auto)
572  F && what,
573  const generic_request_handle_t< Extra_Data > & req,
574  Tuple && params,
575  std::index_sequence<Indexes...> )
576 {
577  return std::forward<F>(what)(
578  req,
579  std::get<Indexes>(std::forward<Tuple>(params))... );
580 }
581 
582 //
583 // call_with_tuple
584 //
585 /*!
586  * @brief A helper function to call a request-handler with a tuple.
587  *
588  * This helper passes every item of a tuple as a separate parameter.
589  *
590  * @since v.0.6.6
591  */
592 template< typename F, typename Extra_Data, typename Tuple >
593 decltype(auto)
595  F && what,
596  const generic_request_handle_t< Extra_Data > & req,
597  Tuple && params )
598 {
599  return call_with_tuple_impl(
600  std::forward<F>(what),
601  req,
602  std::forward<Tuple>(params),
603  std::make_index_sequence<
604  std::tuple_size< std::remove_reference_t<Tuple> >::value
605  >{} );
606 }
607 
608 } /* namespace path_to_params_details */
609 
610 //
611 // path_to_params_producer_t
612 //
613 /*!
614  * @brief An implementation of a producer for path_to_params case.
615  *
616  * This implementation produces a tuple and provides a way to call a
617  * request-handler with passing that tuple as a set of separate
618  * parameters.
619  *
620  * @since v.0.6.6
621  */
622 template<
623  typename Target_Type,
624  typename Subitems_Tuple >
627 {
629 
630 public:
631  using base_type_t::base_type_t;
632 
633  template< typename User_Type, typename Handler >
635  static auto
638  Handler && handler,
639  typename base_type_t::result_type & type )
640  {
642  }
643 };
644 
645 } /* namespace impl */
646 
647 using namespace restinio::easy_parser;
648 
649 //
650 // path_to_tuple
651 //
652 /*!
653  * @brief Describe a route for a handler that accepts params from the
654  * route in form of a tuple.
655  *
656  * Usage example:
657  * @code
658  * router->add_handler(http_method_get(),
659  * path_to_tuple("/api/v1/users/", user_id_parser),
660  * [](const auto & req, const auto & params) {
661  * auto uid = std::get<0>(params);
662  * ...
663  * });
664  *
665  * router->add_handler(http_method_get(),
666  * path_to_tuple(
667  * "/api/v1/books/", book_id_parser,
668  * "/versions/", version_id_parser),
669  * [](const auto & req, const auto & params) {
670  * auto book_id = std::get<0>(params);
671  * auto ver_id = std::get<1>(params);
672  * ...
673  * });
674  * @endcode
675  *
676  * Please note that a route can contain no params at all. In that case
677  * an empty tuple will be passed as an argument to the request handler:
678  * @code
679  * router->add_handler(http_method_get(),
680  * path_to_tuple("/api/v1/books"),
681  * [](const auto & req, auto params) {
682  * static_assert(
683  * std::is_same<std::tuple<>, decltype(params)>::value,
684  * "type std::tuple<> is expected");
685  * ...
686  * });
687  * @endcode
688  *
689  * @since v.0.6.6
690  */
691 template< typename... Args >
693 auto
695 {
696  using dsl_processor = impl::dsl_processor< Args... >;
697  using result_tuple_type = typename dsl_processor::result_tuple;
699 
703 
704  return producer_type{
706  };
707 }
708 
709 //
710 // path_to_params
711 //
712 /*!
713  * @brief Describe a route for a handler that accepts params from the
714  * route in form of a list of separate arguments.
715  *
716  * Usage example:
717  * @code
718  * router->add_handler(http_method_get(),
719  * path_to_params("/api/v1/users/", user_id_parser),
720  * [](const auto & req, const auto & uid) {
721  * ...
722  * });
723  *
724  * router->add_handler(http_method_get(),
725  * path_to_params(
726  * "/api/v1/books/", book_id_parser,
727  * "/versions/", version_id_parser),
728  * [](const auto & req, const auto & book_id, const auto & ver_id) {
729  * ...
730  * });
731  * @endcode
732  *
733  * Please note that a route can contain no params at all. In that case
734  * the request handler will receive just one parameter: a requst_handle.
735  * @code
736  * router->add_handler(http_method_get(),
737  * path_to_params("/api/v1/books"),
738  * [](const auto & req) {
739  * ...
740  * });
741  * @endcode
742  *
743  * @since v.0.6.6
744  */
745 template< typename... Args >
747 auto
749 {
750  using dsl_processor = impl::dsl_processor< Args... >;
751  using result_tuple_type = typename dsl_processor::result_tuple;
753 
757 
758  return producer_type{
760  };
761 }
762 
763 /*!
764  * @brief A factory that creates a string-producer that extracts a
765  * sequence on symbols until the separator will be found.
766  *
767  * Usage example:
768  * @code
769  * namespace epr = restinio::router::easy_parser_router;
770  *
771  * router->add_handler(http_method_get(),
772  * // Route for '/film/:author/:title'
773  * path_to_params(
774  * "/film/",
775  * epr::path_fragment_p(),
776  * "/",
777  * epr::path_fragment_p()
778  * ),
779  * [](const restinio::request_handle_t & req,
780  * const std::string & author,
781  * const std::string & title) {...});
782  * @endcode
783  *
784  * By default the separator is '/', by it can be changed by @a separator
785  * argument:
786  * @code
787  * namespace epr = restinio::router::easy_parser_router;
788  *
789  * router->add_handler(http_method_get(),
790  * // Route for '/user-group'
791  * path_to_params(
792  * "/",
793  * epr::path_fragment_p('-'),
794  * epr::path_fragment_p()
795  * ),
796  * [](const restinio::request_handle_t & req,
797  * const std::string & user,
798  * const std::string & group) {...});
799  * @endcode
800  *
801  * @since v.0.6.6
802  */
804 inline auto
806 {
807  return produce< std::string >(
808  repeat( 1, N,
810 }
811 
812 /*!
813  * @brief A factory for unescape_transformer.
814  *
815  * The unescape_transformer performs unescaping of percent-encoded
816  * string.
817  *
818  * Usage example:
819  * @code
820  * namespace epr = restinio::router::easy_parser_router;
821  *
822  * router->add_handler(http_method_get(),
823  * // Route for '/film/:author/:title'
824  * path_to_params(
825  * "/film/",
826  * epr::path_fragment_p() >> epr::unescape(),
827  * "/",
828  * epr::path_fragment_p() >> epr::unescape()
829  * ),
830  * [](const restinio::request_handle_t & req,
831  * const std::string & author,
832  * const std::string & title) {...});
833  * @endcode
834  *
835  * @note
836  * This function can be parametrized by Unescape_Traits type:
837  * @code
838  * namespace epr = restinio::router::easy_parser_router;
839  *
840  * struct film_by_athor_and_title { std::string author, title };
841  * router->add_handler(http_method_get(),
842  * // Route for '/film/:author/:title'
843  * path_to_params(
844  * "/film/",
845  * epr::path_fragment_p()
846  * >> epr::unescape<restinio::utils::javascript_compatible_unescape_traits>(),
847  * "/",
848  * epr::path_fragment_p()
849  * >> epr::unescape<restinio::utils::javascript_compatible_unescape_traits>()
850  * ),
851  * [](const restinio::request_handle_t & req,
852  * const std::string & author,
853  * const std::string & title) {...});
854  * @endcode
855  *
856  * @since v.0.6.6
857  */
858 template< typename Unescape_Traits =
861 auto
863 {
865 }
866 
867 } /* namespace easy_parser_router */
868 
869 //
870 // generic_easy_parser_router_t
871 //
872 /*!
873  * @brief A generic request router that uses easy_parser for matching requests
874  * with handlers.
875  *
876  * @note
877  * That type is intended to be used when extra-data-factory for server traits
878  * is not the default one. If your server uses the default extra-data-factory
879  * then easy_parser_router_t should be used for the simplicity.
880  *
881  * Usage example:
882  * @code
883  * struct my_extra_data_factory {
884  * // Type of data to be incorporated into request object.
885  * struct data_t {...};
886  *
887  * // Factory function for data_t.
888  * void make_within( restinio::extra_data_buffer_t<data_t> buf ) {
889  * new(buf.get()) data_t{...};
890  * }
891  * };
892  *
893  * using router_t = restinio::router::generic_easy_parser_router_t<
894  * my_extra_data_factory >;
895  * namespace epr = restinio::router::easy_parser_router;
896  *
897  * auto make_router(...) {
898  * auto router = std::make_unique<router_t>();
899  * ...
900  * router->http_get(epr::path_to_params(...),
901  * [](const auto & req, ...) {...});
902  * router->http_post(epr::path_to_params(...),
903  * [](const auto & req, ...) {...});
904  * router->http_delete(epr::path_to_params(...),
905  * [](const auto & req, ...) {...});
906  *
907  * router->add_handler(
908  * restinio::http_method_lock(),
909  * epr::path_to_params(...),
910  * [](const auto & req, ...) {...});
911  *
912  * router->add_handler(
913  * restinio::router::any_of_methods(
914  * restinio::http_method_get(),
915  * restinio::http_method_delete(),
916  * restinio::http_method_post()),
917  * epr::path_to_params(...),
918  * [](const auto & req, ...) {...});
919  *
920  * router->add_handler(
921  * restinio::router::none_of_methods(
922  * restinio::http_method_get(),
923  * restinio::http_method_delete(),
924  * restinio::http_method_post()),
925  * epr::path_to_params(...),
926  * [](const auto & req, ...) {...});
927  *
928  * return router;
929  * }
930  * ...
931  * struct traits_t : public restinio::default_traits_t {
932  * using extra_data_factory_t = my_extra_data_factory;
933  * using request_handler_t = router_t;
934  * }
935  * ...
936  * restinio::run(
937  * restinio::on_this_thread<traits_t>()
938  * .request_handler(make_router)
939  * ...
940  * );
941  * @endcode
942  *
943  * @tparam Extra_Data_Factory The type of user-type-factory. This type should
944  * be the same as the `traits::user_type_factory_t` type for the server.
945  *
946  * @since v.0.6.6, v.0.6.13
947  */
948 template< typename Extra_Data_Factory >
950 {
951  using extra_data_t = typename Extra_Data_Factory::data_t;
952 
953 public:
955 
956  generic_easy_parser_router_t() = default;
957 
959  const generic_easy_parser_router_t & ) = delete;
961  operator=( const generic_easy_parser_router_t & ) = delete;
962 
965  operator=( generic_easy_parser_router_t && ) = default;
966 
967  RESTINIO_NODISCARD
968  request_handling_status_t
970  {
971  using namespace easy_parser_router::impl;
972 
973  // Take care of an optional trailing slash.
975  if( path_to_inspect.size() > 1u && '/' == path_to_inspect.back() )
977 
979  for( const auto & entry : m_entries )
980  {
981  const auto r = entry->try_handle( req, target_path );
982  if( r )
983  {
984  return *r;
985  }
986  }
987 
988  // Here: none of the routes matches this handler.
990  {
991  // If non matched request handler is set
992  // then call it.
994  }
995 
996  return request_not_handled();
997  }
998 
999  template<
1000  typename Method_Matcher,
1001  typename Route_Producer,
1002  typename Handler >
1003  void
1006  Route_Producer && route,
1007  Handler && handler )
1008  {
1009  using namespace easy_parser_router::impl;
1010 
1012  using handler_type = std::decay_t< Handler >;
1013 
1016 
1020  std::forward<Handler>(handler) );
1021 
1023  }
1024 
1025  //! Set handler for HTTP GET request.
1026  template< typename Route_Producer, typename Handler >
1027  void
1029  Route_Producer && route,
1030  Handler && handler )
1031  {
1032  this->add_handler(
1033  http_method_get(),
1035  std::forward<Handler>(handler) );
1036  }
1037 
1038  //! Set handler for HTTP DELETE request.
1039  template< typename Route_Producer, typename Handler >
1040  void
1042  Route_Producer && route,
1043  Handler && handler )
1044  {
1045  this->add_handler(
1048  std::forward<Handler>(handler) );
1049  }
1050 
1051  //! Set handler for HTTP HEAD request.
1052  template< typename Route_Producer, typename Handler >
1053  void
1055  Route_Producer && route,
1056  Handler && handler )
1057  {
1058  this->add_handler(
1059  http_method_head(),
1061  std::forward<Handler>(handler) );
1062  }
1063 
1064  //! Set handler for HTTP POST request.
1065  template< typename Route_Producer, typename Handler >
1066  void
1068  Route_Producer && route,
1069  Handler && handler )
1070  {
1071  this->add_handler(
1072  http_method_post(),
1074  std::forward<Handler>(handler) );
1075  }
1076 
1077  //! Set handler for HTTP PUT request.
1078  template< typename Route_Producer, typename Handler >
1079  void
1081  Route_Producer && route,
1082  Handler && handler )
1083  {
1084  this->add_handler(
1085  http_method_put(),
1087  std::forward<Handler>(handler) );
1088  }
1089 
1090  //! Set handler for requests that don't match any route.
1091  void
1094  {
1096  }
1097 
1098 private:
1099  using entries_container_t = std::vector<
1101  >;
1102 
1104 
1105  //! Handler that is called for requests that don't match any route.
1108 };
1109 
1110 //
1111 // easy_parser_router_t
1112 //
1113 /*!
1114  * @brief A request router that uses easy_parser for matching requests
1115  * with handlers.
1116  *
1117  * @note
1118  * That type is intended to be used when the default extra-data-factory is
1119  * specified in you server's traits.
1120  *
1121  * Usage example:
1122  * @code
1123  * using router_t = restinio::router::easy_parser_router_t;
1124  * namespace epr = restinio::router::easy_parser_router;
1125  *
1126  * auto make_router(...) {
1127  * auto router = std::make_unique<router_t>();
1128  * ...
1129  * router->http_get(epr::path_to_params(...),
1130  * [](const auto & req, ...) {...});
1131  * router->http_post(epr::path_to_params(...),
1132  * [](const auto & req, ...) {...});
1133  * router->http_delete(epr::path_to_params(...),
1134  * [](const auto & req, ...) {...});
1135  *
1136  * router->add_handler(
1137  * restinio::http_method_lock(),
1138  * epr::path_to_params(...),
1139  * [](const auto & req, ...) {...});
1140  *
1141  * router->add_handler(
1142  * restinio::router::any_of_methods(
1143  * restinio::http_method_get(),
1144  * restinio::http_method_delete(),
1145  * restinio::http_method_post()),
1146  * epr::path_to_params(...),
1147  * [](const auto & req, ...) {...});
1148  *
1149  * router->add_handler(
1150  * restinio::router::none_of_methods(
1151  * restinio::http_method_get(),
1152  * restinio::http_method_delete(),
1153  * restinio::http_method_post()),
1154  * epr::path_to_params(...),
1155  * [](const auto & req, ...) {...});
1156  *
1157  * return router;
1158  * }
1159  * ...
1160  * struct traits_t : public restinio::default_traits_t {
1161  * using request_handler_t = router_t;
1162  * }
1163  * ...
1164  * restinio::run(
1165  * restinio::on_this_thread<traits_t>()
1166  * .request_handler(make_router)
1167  * ...
1168  * );
1169  * @endcode
1170  *
1171  * @since v.0.6.6
1172  */
1173 using easy_parser_router_t =
1175 
1176 } /* namespace router */
1177 
1178 } /* namespace restinio */
void non_matched_request_handler(generic_non_matched_request_handler_t< extra_data_t > nmrh)
Set handler for requests that don&#39;t match any route.
generic_easy_parser_router_t & operator=(const generic_easy_parser_router_t &)=delete
decltype(auto) call_with_tuple(F &&what, const generic_request_handle_t< Extra_Data > &req, Tuple &&params)
A helper function to call a request-handler with a tuple.
static RESTINIO_NODISCARD auto invoke_handler(const generic_request_handle_t< Extra_Data > &req, Handler &&handler, typename base_type_t::result_type &type)
static RESTINIO_NODISCARD auto invoke_handler(const generic_request_handle_t< User_Type > &req, Handler &&handler, typename base_type_t::result_type &type)
Helper type to indicate a negative match attempt.
A special analog of std::decay meta-function that is handles array differently.
generic_easy_parser_router_t(generic_easy_parser_router_t &&)=default
A special clause type for case when exact_fragment_producer should be used without storing its value...
virtual RESTINIO_NODISCARD expected_t< request_handling_status_t, no_match_t > try_handle(const actual_request_handle_t &req, target_path_holder_t &target_path) const =0
An attempt to match a request against the route.
Producer m_producer
Parser of a route and producer of argument(s) for request handler.
actual_router_entry_t(Method_Matcher &&method_matcher, Producer_Arg &&producer, Handler_Arg &&handler)
Handler m_handler
Request handler to be used.
restinio::router::impl::buffered_matcher_holder_t m_method_matcher
HTTP method to match.
The main meta-function for processing route DSL.
A special clause type for case when exact_fixed_size_fragment_producer should be used without storing...
RESTINIO_NODISCARD auto unescape()
A factory for unescape_transformer.
RESTINIO_NODISCARD result_type transform(input_type &&input) const
generic_easy_parser_router_t(const generic_easy_parser_router_t &)=delete
decltype(auto) call_with_tuple_impl(F &&what, const generic_request_handle_t< Extra_Data > &req, Tuple &&params, std::index_sequence< Indexes... >)
RESTINIO_NODISCARD expected_t< request_handling_status_t, no_match_t > try_handle(const actual_request_handle_t &req, target_path_holder_t &target_path) const override
An attempt to match a request against the route.
virtual ~router_entry_t()=default
generic_easy_parser_router_t & operator=(generic_easy_parser_router_t &&)=default
generic_non_matched_request_handler_t< extra_data_t > m_non_matched_request_handler
Handler that is called for requests that don&#39;t match any route.
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