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  */
70  [[nodiscard]]
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  //! HTTP method to match.
110 
111  //! Parser of a route and producer of argument(s) for request handler.
112  Producer m_producer;
113 
114  //! Request handler to be used.
115  Handler m_handler;
116 
117 public:
118  using actual_request_handle_t =
119  typename router_entry_t<Extra_Data>::actual_request_handle_t;
120 
121  template<
122  typename Method_Matcher,
123  typename Producer_Arg,
124  typename Handler_Arg >
126  Method_Matcher && method_matcher,
127  Producer_Arg && producer,
128  Handler_Arg && handler )
131  {
133  }
134 
135  [[nodiscard]]
139  target_path_holder_t & target_path ) const override
140  {
141  if( m_method_matcher->match( req->header().method() ) )
142  {
144  target_path.view(),
145  m_producer );
146  if( parse_result )
147  {
149  }
150  }
151 
152  return make_unexpected( no_match_t{} );
153  }
154 };
155 
156 //
157 // unescape_transformer_t
158 //
159 /*!
160  * @brief A transformer that performs percent-unescaping of
161  * an input string.
162  *
163  * @since v.0.6.6
164  */
165 template< typename Unescape_Traits >
168 {
170 
171  [[nodiscard]]
174  {
176  input );
177  }
178 };
179 
180 //
181 // special_produce_tuple_item_clause_t
182 //
183 /*!
184  * @brief A special case of produce-consume clause where the produced
185  * value is stored into a tuple.
186  *
187  * @since v.0.6.6
188  */
189 template< typename Producer, std::size_t Index >
191  : public ep::impl::consume_value_clause_t<
192  Producer,
194 {
196 
198  Producer,
200 
201  // NOTE: this is just a workaround for VS2017.
202  template< typename Producer_Arg >
203  [[nodiscard]]
204  static Producer
205  make_producer( Producer_Arg && producer )
206  {
207  return { std::forward<Producer_Arg>(producer) };
208  }
209 
210 public:
211  template< typename Producer_Arg >
212  special_produce_tuple_item_clause_t( Producer_Arg && producer )
213  : base_type_t{
215  consumer_t{} }
216  {}
217 };
218 
219 //
220 // special_exact_fixed_size_fragment_clause_t
221 //
222 /*!
223  * @brief A special clause type for case when
224  * exact_fixed_size_fragment_producer should be used without storing
225  * its value.
226  *
227  * This type is an equivalent of `exact_p() >> skip()`, but it can be
228  * used where a type is required.
229  *
230  * @since v.0.6.6
231  */
232 template< std::size_t Size >
234  : public ep::impl::consume_value_clause_t<
237 {
240 
242  producer_t,
244 
245 public:
247  const char (&fragment)[Size] )
249  {}
250 };
251 
252 //
253 // special_exact_fragment_clause_t
254 //
255 /*!
256  * @brief A special clause type for case when
257  * exact_fragment_producer should be used without storing
258  * its value.
259  *
260  * This type is an equivalent of `exact_p() >> skip()`, but it can be
261  * used where a type is required.
262  *
263  * @since v.0.6.6
264  */
266  : public ep::impl::consume_value_clause_t<
269 {
272 
274  producer_t,
276 
277 public:
278  special_exact_fragment_clause_t( std::string value )
280  {}
281 
282  special_exact_fragment_clause_t( string_view_t value )
283  : base_type_t{
284  producer_t{ std::string{ value.data(), value.size() } },
285  consumer_t{} }
286  {}
287 };
288 
289 namespace dsl_details
290 {
291 
292 // Adds type H to type list R if Is_Producer is true.
293 template< typename H, typename R, bool Is_Producer >
294 struct add_type_if_necessary_impl;
295 
296 template<
297  typename H,
298  template<class...> class To,
299  typename... Results >
300 struct add_type_if_necessary_impl< H, To<Results...>, false >
301 {
302  using type = To<Results...>;
303 };
304 
305 template<
306  typename H,
307  template<class...> class To,
308  typename... Results >
309 struct add_type_if_necessary_impl< H, To<Results...>, true >
310 {
311  using type = To<Results..., typename H::result_type>;
312 };
313 
314 // Adds type H to type list R if H is a producer.
315 template< typename H, typename R >
318 {};
319 
320 // Produces a type-list of producers from type-list From.
321 template< typename From, typename To >
322 struct result_tuple_detector;
323 
324 // Adds a type from Sources to Results only if this type is a producer.
325 template<
326  template<class...> class From,
327  typename... Sources,
328  template<class...> class To,
329  typename... Results >
330 struct result_tuple_detector< From<Sources...>, To<Results...> >
331 {
332  using type = typename result_tuple_detector<
333  meta::tail_of_t< Sources... >,
334  typename add_type_if_necessary<
335  meta::head_of_t< Sources... >,
336  To< Results... > >::type
337  >::type;
338 };
339 
340 template<
341  template<class...> class From,
342  template<class...> class To,
343  typename... Results >
344 struct result_tuple_detector< From<>, To<Results...> >
345 {
346  using type = To<Results...>;
347 };
348 
349 // Produces a type of std::tuple of producers from type-list Args_Type_List.
350 template< typename Args_Type_List >
352 {
353  using type = meta::rename_t<
354  typename result_tuple_detector<
356  meta::type_list<> >::type,
357  std::tuple >;
358 };
359 
360 template< typename Args_Type_List >
361 using detect_result_tuple_t = typename detect_result_tuple<Args_Type_List>::type;
362 
363 // Detects an appropriate type of clause for T.
364 // If T is a producer then there will be a new clause that
365 // consumes a value T produces.
366 // In that case Current_Index will also be incremented.
367 //
368 // If T is not a producer then Current_Index will be kept.
369 //
370 // If T is a string literal, or std::string, or string_view
371 // then T will be replaced by a special clause.
372 template< typename T, bool Is_Producer, std::size_t Current_Index >
374 {
375  using clause_type = T;
376  static constexpr std::size_t next_index = Current_Index;
377 };
378 
379 template< std::size_t Size, std::size_t Current_Index >
380 struct one_clause_type_processor<const char[Size], false, Current_Index>
381 {
383  static constexpr std::size_t next_index = Current_Index;
384 };
385 
386 template< std::size_t Current_Index >
388 {
390  static constexpr std::size_t next_index = Current_Index;
391 };
392 
393 template< std::size_t Current_Index >
395 {
397  static constexpr std::size_t next_index = Current_Index;
398 };
399 
400 template< typename T, std::size_t Current_Index >
401 struct one_clause_type_processor<T, true, Current_Index>
402 {
403  using clause_type = special_produce_tuple_item_clause_t< T, Current_Index >;
404  static constexpr std::size_t next_index = Current_Index + 1u;
405 };
406 
407 // Takes a type-list of user-specified types From and produces a
408 // typelist of actual clauses types To.
409 //
410 // The Current_Index should be 0 at the first invocation.
411 template< typename From, typename To, std::size_t Current_Index >
412 struct clauses_type_maker;
413 
414 template<
415  template<class...> class From,
416  typename... Sources,
417  template<class...> class To,
418  typename... Results,
419  std::size_t Current_Index >
420 struct clauses_type_maker< From<Sources...>, To<Results...>, Current_Index >
421 {
422 private:
423  using head_type = meta::head_of_t< Sources... >;
424 
425  using one_clause_type = one_clause_type_processor<
426  head_type,
427  ep::impl::is_producer_v<head_type>,
428  Current_Index >;
429 
430 public:
431  using type = typename clauses_type_maker<
432  meta::tail_of_t< Sources... >,
433  To< Results..., typename one_clause_type::clause_type >,
434  one_clause_type::next_index >::type;
435 };
436 
437 template<
438  template<class...> class From,
439  template<class...> class To,
440  typename... Results,
441  std::size_t Current_Index >
442 struct clauses_type_maker< From<>, To<Results...>, Current_Index >
443 {
444  using type = To< Results... >;
445 };
446 
447 // Takes a type-list of user-specified types Args_Type_List and produces a
448 // typelist of actual clauses types to be used for parsing.
449 template< typename Args_Type_List >
451 {
452  using type = meta::rename_t<
453  typename clauses_type_maker<
455  meta::type_list<>,
456  0u >::type,
457  std::tuple >;
458 };
459 
460 template< typename Args_Type_List >
461 using make_clauses_types_t = typename make_clauses_types<Args_Type_List>::type;
462 
463 //
464 // special_decay
465 //
466 /*!
467  * @brief A special analog of std::decay meta-function that is
468  * handles array differently.
469  *
470  * The std::decay converts `char[]` into `char*` and that is not
471  * appropriate because `const char[]` is handled by
472  * exact_fixed_size_fragment_producer.
473  *
474  * The special_decay keeps the type of arrays and do not handles
475  * function pointers (it's because function pointers is not used
476  * by easy-parser).
477  *
478  * @since v.0.6.6
479  */
480 template< typename T >
482 {
483 private:
485 
486 public:
487  using type = typename std::conditional<
488  std::is_array<U>::value,
489  U,
490  std::remove_cv_t<U>
491  >::type;
492 };
493 
494 } /* namespace dsl_details */
495 
496 //
497 // dsl_processor
498 //
499 /*!
500  * @brief The main meta-function for processing route DSL.
501  *
502  * It takes types of user-supplied clauses/produces and makes
503  * two types:
504  *
505  * - result_tuple. This is a type of std::tuple for holding all values produced
506  * by producers from Args. This tuple can be an empty tuple.
507  * - clauses_tuple. This a type of std::tuple with clauses for parsing of a
508  * user's route.
509  *
510  * @since v.0.6.6
511  */
512 template< typename... Args >
514 {
515  static_assert( 0u != sizeof...(Args), "Args can't be an empty list" );
516 
517  using arg_types = meta::transform_t<
519 
521 
523 };
524 
525 //
526 // path_to_tuple_producer_t
527 //
528 /*!
529  * @brief An implementation of a producer for path_to_tuple case.
530  *
531  * This implementation produces a tuple and provides a way to call a
532  * request-handler with passing that tuple as a single argument.
533  *
534  * @since v.0.6.6
535  */
536 template<
537  typename Target_Type,
538  typename Subitems_Tuple >
541 {
543 
544 public:
545  using base_type_t::base_type_t;
546 
547  template< typename Extra_Data, typename Handler >
548  [[nodiscard]]
549  static auto
551  const generic_request_handle_t< Extra_Data > & req,
552  Handler && handler,
553  typename base_type_t::result_type & type )
554  {
555  return handler( req, type );
556  }
557 };
558 
560 {
561 
562 template<
563  typename F,
564  typename Extra_Data,
565  typename Tuple,
566  std::size_t... Indexes >
567 decltype(auto)
569  F && what,
570  const generic_request_handle_t< Extra_Data > & req,
571  Tuple && params,
572  std::index_sequence<Indexes...> )
573 {
574  return std::forward<F>(what)(
575  req,
576  std::get<Indexes>(std::forward<Tuple>(params))... );
577 }
578 
579 //
580 // call_with_tuple
581 //
582 /*!
583  * @brief A helper function to call a request-handler with a tuple.
584  *
585  * This helper passes every item of a tuple as a separate parameter.
586  *
587  * @since v.0.6.6
588  */
589 template< typename F, typename Extra_Data, typename Tuple >
590 decltype(auto)
592  F && what,
593  const generic_request_handle_t< Extra_Data > & req,
594  Tuple && params )
595 {
596  return call_with_tuple_impl(
597  std::forward<F>(what),
598  req,
599  std::forward<Tuple>(params),
600  std::make_index_sequence<
601  std::tuple_size< std::remove_reference_t<Tuple> >::value
602  >{} );
603 }
604 
605 } /* namespace path_to_params_details */
606 
607 //
608 // path_to_params_producer_t
609 //
610 /*!
611  * @brief An implementation of a producer for path_to_params case.
612  *
613  * This implementation produces a tuple and provides a way to call a
614  * request-handler with passing that tuple as a set of separate
615  * parameters.
616  *
617  * @since v.0.6.6
618  */
619 template<
620  typename Target_Type,
621  typename Subitems_Tuple >
624 {
626 
627 public:
628  using base_type_t::base_type_t;
629 
630  template< typename User_Type, typename Handler >
631  [[nodiscard]]
632  static auto
634  const generic_request_handle_t< User_Type > & req,
635  Handler && handler,
636  typename base_type_t::result_type & type )
637  {
638  return path_to_params_details::call_with_tuple( handler, req, type );
639  }
640 };
641 
642 } /* namespace impl */
643 
644 using namespace restinio::easy_parser;
645 
646 //
647 // path_to_tuple
648 //
649 /*!
650  * @brief Describe a route for a handler that accepts params from the
651  * route in form of a tuple.
652  *
653  * Usage example:
654  * @code
655  * router->add_handler(http_method_get(),
656  * path_to_tuple("/api/v1/users/", user_id_parser),
657  * [](const auto & req, const auto & params) {
658  * auto uid = std::get<0>(params);
659  * ...
660  * });
661  *
662  * router->add_handler(http_method_get(),
663  * path_to_tuple(
664  * "/api/v1/books/", book_id_parser,
665  * "/versions/", version_id_parser),
666  * [](const auto & req, const auto & params) {
667  * auto book_id = std::get<0>(params);
668  * auto ver_id = std::get<1>(params);
669  * ...
670  * });
671  * @endcode
672  *
673  * Please note that a route can contain no params at all. In that case
674  * an empty tuple will be passed as an argument to the request handler:
675  * @code
676  * router->add_handler(http_method_get(),
677  * path_to_tuple("/api/v1/books"),
678  * [](const auto & req, auto params) {
679  * static_assert(
680  * std::is_same<std::tuple<>, decltype(params)>::value,
681  * "type std::tuple<> is expected");
682  * ...
683  * });
684  * @endcode
685  *
686  * @since v.0.6.6
687  */
688 template< typename... Args >
689 [[nodiscard]]
690 auto
691 path_to_tuple( Args && ...args )
692 {
693  using dsl_processor = impl::dsl_processor< Args... >;
694  using result_tuple_type = typename dsl_processor::result_tuple;
695  using subclauses_tuple_type = typename dsl_processor::clauses_tuple;
696 
697  using producer_type = impl::path_to_tuple_producer_t<
698  result_tuple_type,
699  subclauses_tuple_type >;
700 
701  return producer_type{
702  subclauses_tuple_type{ std::forward<Args>(args)... }
703  };
704 }
705 
706 //
707 // path_to_params
708 //
709 /*!
710  * @brief Describe a route for a handler that accepts params from the
711  * route in form of a list of separate arguments.
712  *
713  * Usage example:
714  * @code
715  * router->add_handler(http_method_get(),
716  * path_to_params("/api/v1/users/", user_id_parser),
717  * [](const auto & req, const auto & uid) {
718  * ...
719  * });
720  *
721  * router->add_handler(http_method_get(),
722  * path_to_params(
723  * "/api/v1/books/", book_id_parser,
724  * "/versions/", version_id_parser),
725  * [](const auto & req, const auto & book_id, const auto & ver_id) {
726  * ...
727  * });
728  * @endcode
729  *
730  * Please note that a route can contain no params at all. In that case
731  * the request handler will receive just one parameter: a requst_handle.
732  * @code
733  * router->add_handler(http_method_get(),
734  * path_to_params("/api/v1/books"),
735  * [](const auto & req) {
736  * ...
737  * });
738  * @endcode
739  *
740  * @since v.0.6.6
741  */
742 template< typename... Args >
743 [[nodiscard]]
744 auto
745 path_to_params( Args && ...args )
746 {
747  using dsl_processor = impl::dsl_processor< Args... >;
748  using result_tuple_type = typename dsl_processor::result_tuple;
749  using subclauses_tuple_type = typename dsl_processor::clauses_tuple;
750 
751  using producer_type = impl::path_to_params_producer_t<
752  result_tuple_type,
753  subclauses_tuple_type >;
754 
755  return producer_type{
756  subclauses_tuple_type{ std::forward<Args>(args)... }
757  };
758 }
759 
760 /*!
761  * @brief A factory that creates a string-producer that extracts a
762  * sequence on symbols until the separator will be found.
763  *
764  * Usage example:
765  * @code
766  * namespace epr = restinio::router::easy_parser_router;
767  *
768  * router->add_handler(http_method_get(),
769  * // Route for '/film/:author/:title'
770  * path_to_params(
771  * "/film/",
772  * epr::path_fragment_p(),
773  * "/",
774  * epr::path_fragment_p()
775  * ),
776  * [](const restinio::request_handle_t & req,
777  * const std::string & author,
778  * const std::string & title) {...});
779  * @endcode
780  *
781  * By default the separator is '/', by it can be changed by @a separator
782  * argument:
783  * @code
784  * namespace epr = restinio::router::easy_parser_router;
785  *
786  * router->add_handler(http_method_get(),
787  * // Route for '/user-group'
788  * path_to_params(
789  * "/",
790  * epr::path_fragment_p('-'),
791  * epr::path_fragment_p()
792  * ),
793  * [](const restinio::request_handle_t & req,
794  * const std::string & user,
795  * const std::string & group) {...});
796  * @endcode
797  *
798  * @since v.0.6.6
799  */
800 [[nodiscard]]
801 inline auto
802 path_fragment_p( char separator = '/' )
803 {
804  return produce< std::string >(
805  repeat( 1, N,
806  any_symbol_if_not_p( separator ) >> to_container() ) );
807 }
808 
809 /*!
810  * @brief A factory for unescape_transformer.
811  *
812  * The unescape_transformer performs unescaping of percent-encoded
813  * string.
814  *
815  * Usage example:
816  * @code
817  * namespace epr = restinio::router::easy_parser_router;
818  *
819  * router->add_handler(http_method_get(),
820  * // Route for '/film/:author/:title'
821  * path_to_params(
822  * "/film/",
823  * epr::path_fragment_p() >> epr::unescape(),
824  * "/",
825  * epr::path_fragment_p() >> epr::unescape()
826  * ),
827  * [](const restinio::request_handle_t & req,
828  * const std::string & author,
829  * const std::string & title) {...});
830  * @endcode
831  *
832  * @note
833  * This function can be parametrized by Unescape_Traits type:
834  * @code
835  * namespace epr = restinio::router::easy_parser_router;
836  *
837  * struct film_by_athor_and_title { std::string author, title };
838  * router->add_handler(http_method_get(),
839  * // Route for '/film/:author/:title'
840  * path_to_params(
841  * "/film/",
842  * epr::path_fragment_p()
843  * >> epr::unescape<restinio::utils::javascript_compatible_unescape_traits>(),
844  * "/",
845  * epr::path_fragment_p()
846  * >> epr::unescape<restinio::utils::javascript_compatible_unescape_traits>()
847  * ),
848  * [](const restinio::request_handle_t & req,
849  * const std::string & author,
850  * const std::string & title) {...});
851  * @endcode
852  *
853  * @since v.0.6.6
854  */
855 template< typename Unescape_Traits =
857 [[nodiscard]]
858 auto
860 {
861  return impl::unescape_transformer_t< Unescape_Traits >{};
862 }
863 
864 } /* namespace easy_parser_router */
865 
866 //
867 // generic_easy_parser_router_t
868 //
869 /*!
870  * @brief A generic request router that uses easy_parser for matching requests
871  * with handlers.
872  *
873  * @note
874  * That type is intended to be used when extra-data-factory for server traits
875  * is not the default one. If your server uses the default extra-data-factory
876  * then easy_parser_router_t should be used for the simplicity.
877  *
878  * Usage example:
879  * @code
880  * struct my_extra_data_factory {
881  * // Type of data to be incorporated into request object.
882  * struct data_t {...};
883  *
884  * // Factory function for data_t.
885  * void make_within( restinio::extra_data_buffer_t<data_t> buf ) {
886  * new(buf.get()) data_t{...};
887  * }
888  * };
889  *
890  * using router_t = restinio::router::generic_easy_parser_router_t<
891  * my_extra_data_factory >;
892  * namespace epr = restinio::router::easy_parser_router;
893  *
894  * auto make_router(...) {
895  * auto router = std::make_unique<router_t>();
896  * ...
897  * router->http_get(epr::path_to_params(...),
898  * [](const auto & req, ...) {...});
899  * router->http_post(epr::path_to_params(...),
900  * [](const auto & req, ...) {...});
901  * router->http_delete(epr::path_to_params(...),
902  * [](const auto & req, ...) {...});
903  *
904  * router->add_handler(
905  * restinio::http_method_lock(),
906  * epr::path_to_params(...),
907  * [](const auto & req, ...) {...});
908  *
909  * router->add_handler(
910  * restinio::router::any_of_methods(
911  * restinio::http_method_get(),
912  * restinio::http_method_delete(),
913  * restinio::http_method_post()),
914  * epr::path_to_params(...),
915  * [](const auto & req, ...) {...});
916  *
917  * router->add_handler(
918  * restinio::router::none_of_methods(
919  * restinio::http_method_get(),
920  * restinio::http_method_delete(),
921  * restinio::http_method_post()),
922  * epr::path_to_params(...),
923  * [](const auto & req, ...) {...});
924  *
925  * return router;
926  * }
927  * ...
928  * struct traits_t : public restinio::default_traits_t {
929  * using extra_data_factory_t = my_extra_data_factory;
930  * using request_handler_t = router_t;
931  * }
932  * ...
933  * restinio::run(
934  * restinio::on_this_thread<traits_t>()
935  * .request_handler(make_router)
936  * ...
937  * );
938  * @endcode
939  *
940  * @tparam Extra_Data_Factory The type of user-type-factory. This type should
941  * be the same as the `traits::user_type_factory_t` type for the server.
942  *
943  * @since v.0.6.6, v.0.6.13
944  */
945 template< typename Extra_Data_Factory >
947 {
948  using extra_data_t = typename Extra_Data_Factory::data_t;
949 
950 public:
952 
953  generic_easy_parser_router_t() = default;
954 
956  const generic_easy_parser_router_t & ) = delete;
958  operator=( const generic_easy_parser_router_t & ) = delete;
959 
962  operator=( generic_easy_parser_router_t && ) = default;
963 
964  [[nodiscard]]
967  {
968  using namespace easy_parser_router::impl;
969 
970  // Take care of an optional trailing slash.
972  if( path_to_inspect.size() > 1u && '/' == path_to_inspect.back() )
974 
976  for( const auto & entry : m_entries )
977  {
978  const auto r = entry->try_handle( req, target_path );
979  if( r )
980  {
981  return *r;
982  }
983  }
984 
985  // Here: none of the routes matches this handler.
987  {
988  // If non matched request handler is set
989  // then call it.
991  }
992 
993  return request_not_handled();
994  }
995 
996  template<
997  typename Method_Matcher,
998  typename Route_Producer,
999  typename Handler >
1000  void
1002  Method_Matcher && method_matcher,
1003  Route_Producer && route,
1004  Handler && handler )
1005  {
1006  using namespace easy_parser_router::impl;
1007 
1009  using handler_type = std::decay_t< Handler >;
1010 
1013 
1017  std::forward<Handler>(handler) );
1018 
1020  }
1021 
1022  //! Set handler for HTTP GET request.
1023  template< typename Route_Producer, typename Handler >
1024  void
1026  Route_Producer && route,
1027  Handler && handler )
1028  {
1029  this->add_handler(
1030  http_method_get(),
1032  std::forward<Handler>(handler) );
1033  }
1034 
1035  //! Set handler for HTTP DELETE request.
1036  template< typename Route_Producer, typename Handler >
1037  void
1039  Route_Producer && route,
1040  Handler && handler )
1041  {
1042  this->add_handler(
1045  std::forward<Handler>(handler) );
1046  }
1047 
1048  //! Set handler for HTTP HEAD request.
1049  template< typename Route_Producer, typename Handler >
1050  void
1052  Route_Producer && route,
1053  Handler && handler )
1054  {
1055  this->add_handler(
1056  http_method_head(),
1058  std::forward<Handler>(handler) );
1059  }
1060 
1061  //! Set handler for HTTP POST request.
1062  template< typename Route_Producer, typename Handler >
1063  void
1065  Route_Producer && route,
1066  Handler && handler )
1067  {
1068  this->add_handler(
1069  http_method_post(),
1071  std::forward<Handler>(handler) );
1072  }
1073 
1074  //! Set handler for HTTP PUT request.
1075  template< typename Route_Producer, typename Handler >
1076  void
1078  Route_Producer && route,
1079  Handler && handler )
1080  {
1081  this->add_handler(
1082  http_method_put(),
1084  std::forward<Handler>(handler) );
1085  }
1086 
1087  //! Set handler for requests that don't match any route.
1088  void
1090  generic_non_matched_request_handler_t< extra_data_t > nmrh )
1091  {
1093  }
1094 
1095 private:
1096  using entries_container_t = std::vector<
1098  >;
1099 
1101 
1102  //! Handler that is called for requests that don't match any route.
1105 };
1106 
1107 //
1108 // easy_parser_router_t
1109 //
1110 /*!
1111  * @brief A request router that uses easy_parser for matching requests
1112  * with handlers.
1113  *
1114  * @note
1115  * That type is intended to be used when the default extra-data-factory is
1116  * specified in you server's traits.
1117  *
1118  * Usage example:
1119  * @code
1120  * using router_t = restinio::router::easy_parser_router_t;
1121  * namespace epr = restinio::router::easy_parser_router;
1122  *
1123  * auto make_router(...) {
1124  * auto router = std::make_unique<router_t>();
1125  * ...
1126  * router->http_get(epr::path_to_params(...),
1127  * [](const auto & req, ...) {...});
1128  * router->http_post(epr::path_to_params(...),
1129  * [](const auto & req, ...) {...});
1130  * router->http_delete(epr::path_to_params(...),
1131  * [](const auto & req, ...) {...});
1132  *
1133  * router->add_handler(
1134  * restinio::http_method_lock(),
1135  * epr::path_to_params(...),
1136  * [](const auto & req, ...) {...});
1137  *
1138  * router->add_handler(
1139  * restinio::router::any_of_methods(
1140  * restinio::http_method_get(),
1141  * restinio::http_method_delete(),
1142  * restinio::http_method_post()),
1143  * epr::path_to_params(...),
1144  * [](const auto & req, ...) {...});
1145  *
1146  * router->add_handler(
1147  * restinio::router::none_of_methods(
1148  * restinio::http_method_get(),
1149  * restinio::http_method_delete(),
1150  * restinio::http_method_post()),
1151  * epr::path_to_params(...),
1152  * [](const auto & req, ...) {...});
1153  *
1154  * return router;
1155  * }
1156  * ...
1157  * struct traits_t : public restinio::default_traits_t {
1158  * using request_handler_t = router_t;
1159  * }
1160  * ...
1161  * restinio::run(
1162  * restinio::on_this_thread<traits_t>()
1163  * .request_handler(make_router)
1164  * ...
1165  * );
1166  * @endcode
1167  *
1168  * @since v.0.6.6
1169  */
1170 using easy_parser_router_t =
1172 
1173 } /* namespace router */
1174 
1175 } /* namespace restinio */
virtual 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.
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.
void http_put(Route_Producer &&route, Handler &&handler)
Set handler for HTTP PUT request.
generic_easy_parser_router_t & operator=(const generic_easy_parser_router_t &)=delete
void http_head(Route_Producer &&route, Handler &&handler)
Set handler for HTTP HEAD request.
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.
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.
static auto invoke_handler(const generic_request_handle_t< Extra_Data > &req, Handler &&handler, typename base_type_t::result_type &type)
Helper type to indicate a negative match attempt.
An implementation of a producer for path_to_tuple case.
void http_delete(Route_Producer &&route, Handler &&handler)
Set handler for HTTP DELETE request.
A special analog of std::decay meta-function that is handles array differently.
auto unescape()
A factory for unescape_transformer.
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
request_handling_status_t operator()(actual_request_handle_t req) const
A generic request router that uses easy_parser for matching requests with handlers.
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...
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.
void http_get(Route_Producer &&route, Handler &&handler)
Set handler for HTTP GET request.
A special case of produce-consume clause where the produced value is stored into a tuple...
A special clause type for case when exact_fixed_size_fragment_producer should be used without storing...
An interface for one entry of easy_parser-based router.
generic_easy_parser_router_t(const generic_easy_parser_router_t &)=delete
void add_handler(Method_Matcher &&method_matcher, Route_Producer &&route, Handler &&handler)
static auto invoke_handler(const generic_request_handle_t< User_Type > &req, Handler &&handler, typename base_type_t::result_type &type)
decltype(auto) call_with_tuple_impl(F &&what, const generic_request_handle_t< Extra_Data > &req, Tuple &&params, std::index_sequence< Indexes... >)
An actual implementation of router_entry interface.
A transformer that performs percent-unescaping of an input string.
An implementation of a producer for path_to_params case.
void http_post(Route_Producer &&route, Handler &&handler)
Set handler for HTTP POST request.
auto path_fragment_p(char separator='/')
A factory that creates a string-producer that extracts a sequence on symbols until the separator will...
auto path_to_params(Args &&...args)
Describe a route for a handler that accepts params from the route in form of a list of separate argum...
auto path_to_tuple(Args &&...args)
Describe a route for a handler that accepts params from the route in form of a tuple.
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.