RESTinio
Loading...
Searching...
No Matches
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
22namespace restinio
23{
24
25namespace router
26{
27
29{
30
31namespace impl
32{
33
34namespace meta = restinio::utils::metaprogramming;
35namespace 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 */
44struct 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 */
54template< typename Extra_Data >
56{
57public:
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]]
73 const actual_request_handle_t & req,
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 */
85template< 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 */
105template< typename Extra_Data, typename Producer, typename Handler >
106class 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
117public:
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 )
129 : m_producer{ std::forward<Producer_Arg>(producer) }
130 , m_handler{ std::forward<Handler_Arg>(handler) }
131 {
132 assign( m_method_matcher, std::forward<Method_Matcher>(method_matcher) );
133 }
134
135 [[nodiscard]]
138 const actual_request_handle_t & req,
139 target_path_holder_t & target_path ) const override
140 {
141 if( m_method_matcher->match( req->header().method() ) )
142 {
143 auto parse_result = easy_parser::try_parse(
144 target_path.view(),
145 m_producer );
146 if( parse_result )
147 {
148 return Producer::invoke_handler( req, m_handler, *parse_result );
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 */
165template< typename Unescape_Traits >
168{
169 using input_type = std::string;
170
171 [[nodiscard]]
173 transform( input_type && input ) const
174 {
175 return restinio::utils::unescape_percent_encoding< Unescape_Traits >(
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 */
189template< typename Producer, std::size_t Index >
191 : public ep::impl::consume_value_clause_t<
192 Producer,
193 ep::impl::tuple_item_consumer_t<Index> >
194{
196
198 Producer,
199 consumer_t >;
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
210public:
211 template< typename Producer_Arg >
212 special_produce_tuple_item_clause_t( Producer_Arg && producer )
213 : base_type_t{
214 make_producer( std::forward<Producer_Arg>(producer) ),
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 */
232template< std::size_t Size >
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 */
288
289namespace dsl_details
290{
291
292// Adds type H to type list R if Is_Producer is true.
293template< typename H, typename R, bool Is_Producer >
295
296template<
297 typename H,
298 template<class...> class To,
299 typename... Results >
300struct add_type_if_necessary_impl< H, To<Results...>, false >
301{
302 using type = To<Results...>;
303};
304
305template<
306 typename H,
307 template<class...> class To,
308 typename... Results >
309struct 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.
315template< typename H, typename R >
317 : add_type_if_necessary_impl< H, R, ep::impl::is_producer_v<H> >
318{};
319
320// Produces a type-list of producers from type-list From.
321template< typename From, typename To >
323
324// Adds a type from Sources to Results only if this type is a producer.
325template<
326 template<class...> class From,
327 typename... Sources,
328 template<class...> class To,
329 typename... Results >
330struct 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
340template<
341 template<class...> class From,
342 template<class...> class To,
343 typename... Results >
344struct 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.
350template< typename Args_Type_List >
352{
354 typename result_tuple_detector<
356 meta::type_list<> >::type,
357 std::tuple >;
358};
359
360template< typename Args_Type_List >
361using 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.
372template< 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
379template< std::size_t Size, std::size_t Current_Index >
380struct one_clause_type_processor<const char[Size], false, Current_Index>
381{
383 static constexpr std::size_t next_index = Current_Index;
384};
385
386template< std::size_t Current_Index >
387struct one_clause_type_processor<std::string, false, Current_Index>
388{
390 static constexpr std::size_t next_index = Current_Index;
391};
392
393template< std::size_t Current_Index >
399
400template< typename T, std::size_t Current_Index >
401struct one_clause_type_processor<T, true, Current_Index>
402{
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.
411template< typename From, typename To, std::size_t Current_Index >
413
414template<
415 template<class...> class From,
416 typename... Sources,
417 template<class...> class To,
418 typename... Results,
419 std::size_t Current_Index >
420struct clauses_type_maker< From<Sources...>, To<Results...>, Current_Index >
421{
422private:
424
426 head_type,
429
430public:
431 using type = typename clauses_type_maker<
432 meta::tail_of_t< Sources... >,
433 To< Results..., typename one_clause_type::clause_type >,
435};
436
437template<
438 template<class...> class From,
439 template<class...> class To,
440 typename... Results,
441 std::size_t Current_Index >
442struct 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.
449template< typename Args_Type_List >
451{
453 typename clauses_type_maker<
455 meta::type_list<>,
456 0u >::type,
457 std::tuple >;
458};
459
460template< typename Args_Type_List >
461using 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 */
480template< typename T >
482{
483private:
485
486public:
487 using type = typename std::conditional<
488 std::is_array<U>::value,
489 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 */
512template< typename... Args >
514{
515 static_assert( 0u != sizeof...(Args), "Args can't be an empty list" );
516
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 */
536template<
537 typename Target_Type,
538 typename Subitems_Tuple >
540 : public ep::impl::produce_t< Target_Type, Subitems_Tuple >
541{
542 using base_type_t = ep::impl::produce_t< Target_Type, Subitems_Tuple >;
543
544public:
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
562template<
563 typename F,
564 typename Extra_Data,
565 typename Tuple,
566 std::size_t... Indexes >
567decltype(auto)
569 F && what,
570 const generic_request_handle_t< Extra_Data > & req,
571 Tuple && params,
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 */
589template< typename F, typename Extra_Data, typename Tuple >
590decltype(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 */
619template<
620 typename Target_Type,
621 typename Subitems_Tuple >
623 : public ep::impl::produce_t< Target_Type, Subitems_Tuple >
624{
625 using base_type_t = ep::impl::produce_t< Target_Type, Subitems_Tuple >;
626
627public:
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
644using 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 */
688template< typename... Args >
689[[nodiscard]]
690auto
691path_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 */
742template< typename... Args >
743[[nodiscard]]
744auto
745path_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]]
801inline auto
802path_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 */
855template< typename Unescape_Traits =
857[[nodiscard]]
858auto
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 */
945template< typename Extra_Data_Factory >
947{
948 using extra_data_t = typename Extra_Data_Factory::data_t;
949
950public:
952
954
956 const generic_easy_parser_router_t & ) = delete;
959
963
964 [[nodiscard]]
966 operator()( actual_request_handle_t req ) const
967 {
968 using namespace easy_parser_router::impl;
969
970 // Take care of an optional trailing slash.
971 string_view_t path_to_inspect{ req->header().path() };
972 if( path_to_inspect.size() > 1u && '/' == path_to_inspect.back() )
973 path_to_inspect.remove_suffix( 1u );
974
975 target_path_holder_t target_path{ path_to_inspect };
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.
986 if( m_non_matched_request_handler )
987 {
988 // If non matched request handler is set
989 // then call it.
990 return m_non_matched_request_handler( std::move( req ) );
991 }
992
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
1008 using producer_type = std::decay_t< Route_Producer >;
1009 using handler_type = std::decay_t< Handler >;
1010
1011 using actual_entry_type = actual_router_entry_t<
1012 extra_data_t, producer_type, handler_type >;
1013
1014 auto entry = std::make_unique< actual_entry_type >(
1015 std::forward<Method_Matcher>(method_matcher),
1016 std::forward<Route_Producer>(route),
1017 std::forward<Handler>(handler) );
1018
1019 m_entries.push_back( std::move(entry) );
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(),
1031 std::forward<Route_Producer>(route),
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(
1043 http_method_delete(),
1044 std::forward<Route_Producer>(route),
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(),
1057 std::forward<Route_Producer>(route),
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(),
1070 std::forward<Route_Producer>(route),
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(),
1083 std::forward<Route_Producer>(route),
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 {
1092 m_non_matched_request_handler= std::move( nmrh );
1093 }
1094
1095private:
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 */
1172
1173} /* namespace router */
1174
1175} /* namespace restinio */
A template for a clause that binds a value producer with value consumer.
A producer that expects a fragment in the input and produces boolean value if that fragment is found.
A producer that expects a fragment in the input and produces boolean value if that fragment is found.
A template for producing a value of specific type of a sequence of entities from the input stream.
An actual implementation of router_entry interface.
Producer m_producer
Parser of a route and producer of argument(s) for request handler.
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.
actual_router_entry_t(Method_Matcher &&method_matcher, Producer_Arg &&producer, Handler_Arg &&handler)
typename router_entry_t< Extra_Data >::actual_request_handle_t actual_request_handle_t
Handler m_handler
Request handler to be used.
restinio::router::impl::buffered_matcher_holder_t m_method_matcher
HTTP method to match.
An implementation of a producer for path_to_params case.
ep::impl::produce_t< Target_Type, Subitems_Tuple > base_type_t
static auto invoke_handler(const generic_request_handle_t< User_Type > &req, Handler &&handler, typename base_type_t::result_type &type)
An implementation of a producer for path_to_tuple case.
ep::impl::produce_t< Target_Type, Subitems_Tuple > base_type_t
static auto invoke_handler(const generic_request_handle_t< Extra_Data > &req, Handler &&handler, typename base_type_t::result_type &type)
An interface for one entry of easy_parser-based router.
virtual ~router_entry_t()=default
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.
A special clause type for case when exact_fixed_size_fragment_producer should be used without storing...
A special clause type for case when exact_fragment_producer should be used without storing its value.
ep::impl::consume_value_clause_t< producer_t, consumer_t > base_type_t
A special case of produce-consume clause where the produced value is stored into a tuple.
ep::impl::consume_value_clause_t< Producer, consumer_t > base_type_t
A generic request router that uses easy_parser for matching requests with handlers.
void add_handler(Method_Matcher &&method_matcher, Route_Producer &&route, Handler &&handler)
typename Extra_Data_Factory::data_t extra_data_t
generic_easy_parser_router_t & operator=(generic_easy_parser_router_t &&)=default
void http_get(Route_Producer &&route, Handler &&handler)
Set handler for HTTP GET request.
void http_head(Route_Producer &&route, Handler &&handler)
Set handler for HTTP HEAD request.
void non_matched_request_handler(generic_non_matched_request_handler_t< extra_data_t > nmrh)
Set handler for requests that don't match any route.
generic_easy_parser_router_t & operator=(const generic_easy_parser_router_t &)=delete
generic_non_matched_request_handler_t< extra_data_t > m_non_matched_request_handler
Handler that is called for requests that don't match any route.
void http_delete(Route_Producer &&route, Handler &&handler)
Set handler for HTTP DELETE request.
request_handling_status_t operator()(actual_request_handle_t req) const
generic_easy_parser_router_t(generic_easy_parser_router_t &&)=default
void http_post(Route_Producer &&route, Handler &&handler)
Set handler for HTTP POST request.
generic_easy_parser_router_t(const generic_easy_parser_router_t &)=delete
void http_put(Route_Producer &&route, Handler &&handler)
Set handler for HTTP PUT request.
A special class that allows to hold a copy of small-size method_matchers or a pointer to dynamically ...
Helper class for holding a unique instance of char array with target_path value.
auto to_container()
A factory function to create a to_container_consumer.
auto any_symbol_if_not_p(char sentinel) noexcept
A factory function to create a any_symbol_if_not_producer.
constexpr std::size_t N
A special marker that means infinite repetitions.
typename detect_result_tuple< Args_Type_List >::type detect_result_tuple_t
typename make_clauses_types< Args_Type_List >::type make_clauses_types_t
decltype(auto) call_with_tuple_impl(F &&what, const generic_request_handle_t< Extra_Data > &req, Tuple &&params, std::index_sequence< Indexes... >)
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.
restinio::router::impl::target_path_holder_t target_path_holder_t
auto path_to_tuple(Args &&...args)
Describe a route for a handler that accepts params from the route in form of a tuple.
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_fragment_p(char separator='/')
A factory that creates a string-producer that extracts a sequence on symbols until the separator will...
auto unescape()
A factory for unescape_transformer.
generic_easy_parser_router_t< no_extra_data_factory_t > easy_parser_router_t
A request router that uses easy_parser for matching requests with handlers.
constexpr request_handling_status_t request_not_handled() noexcept
request_handling_status_t
Request handling status.
A special consumer that simply throws any value away.
A consumer that stores a result value at the specified index in the result tuple.
The default extra-data-factory to be used in server's traits if a user doesn't specify own one.
A special analog of std::decay meta-function that is handles array differently.
The main meta-function for processing route DSL.
Helper type to indicate a negative match attempt.
A transformer that performs percent-unescaping of an input string.
The default traits for escaping and unexcaping symbols in a query string.