RESTinio
Loading...
Searching...
No Matches
easy_parser_router.hpp
Go to the documentation of this file.
1/*
2 * RESTinio
3 */
4
12#pragma once
13
17
19
20#include <vector>
21
22namespace restinio
23{
24
25namespace router
26{
27
28namespace easy_parser_router
29{
30
31namespace impl
32{
33
35namespace ep = restinio::easy_parser;
36
38
44struct no_match_t {};
45
54template< typename Extra_Data >
76
85template< typename Extra_Data >
87 std::unique_ptr< router_entry_t< Extra_Data > >;
88
89//
90// actual_router_entry_t
91//
105template< typename Extra_Data, typename Producer, typename Handler >
106class actual_router_entry_t : public router_entry_t< Extra_Data >
107{
110
113
116
117public:
120
121 template<
122 typename Method_Matcher,
123 typename Producer_Arg,
124 typename Handler_Arg >
127 Producer_Arg && producer,
129 : m_producer{ std::forward<Producer_Arg>(producer) }
131 {
132 assign( m_method_matcher, std::forward<Method_Matcher>(method_matcher) );
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 {
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//
165template< typename Unescape_Traits >
168{
169 using input_type = std::string;
170
171 [[nodiscard]]
174 {
175 return restinio::utils::unescape_percent_encoding< Unescape_Traits >(
176 input );
177 }
178};
179
180//
181// special_produce_tuple_item_clause_t
182//
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{
195 using consumer_t = ep::impl::tuple_item_consumer_t<Index>;
196
197 using base_type_t = ep::impl::consume_value_clause_t<
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
206 {
207 return { std::forward<Producer_Arg>(producer) };
208 }
209
210public:
211 template< typename Producer_Arg >
217};
218
219//
220// special_exact_fixed_size_fragment_clause_t
221//
232template< std::size_t Size >
234 : public ep::impl::consume_value_clause_t<
235 ep::impl::exact_fixed_size_fragment_producer_t<Size>,
236 ep::impl::any_value_skipper_t >
237{
238 using producer_t = ep::impl::exact_fixed_size_fragment_producer_t<Size>;
239 using consumer_t = ep::impl::any_value_skipper_t;
240
241 using base_type_t = ep::impl::consume_value_clause_t<
243 consumer_t >;
244
245public:
247 const char (&fragment)[Size] )
248 : base_type_t{ producer_t{ fragment }, consumer_t{} }
249 {}
250};
251
252//
253// special_exact_fragment_clause_t
254//
266 : public ep::impl::consume_value_clause_t<
267 ep::impl::exact_fragment_producer_t,
268 ep::impl::any_value_skipper_t >
269{
270 using producer_t = ep::impl::exact_fragment_producer_t;
271 using consumer_t = ep::impl::any_value_skipper_t;
272
273 using base_type_t = ep::impl::consume_value_clause_t<
275 consumer_t >;
276
277public:
279 : base_type_t{ producer_t{ std::move(value) }, consumer_t{} }
280 {}
281
283 : base_type_t{
284 producer_t{ std::string{ value.data(), value.size() } },
285 consumer_t{} }
286 {}
287};
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 >
301{
302 using type = To<Results...>;
303};
304
305template<
306 typename H,
307 template<class...> class To,
308 typename... Results >
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 >
331{
332 using type = typename result_tuple_detector<
334 typename add_type_if_necessary<
336 To< Results... > >::type
337 >::type;
338};
339
340template<
341 template<class...> class From,
342 template<class...> class To,
343 typename... 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<
357 std::tuple >;
358};
359
360template< typename Args_Type_List >
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 >
385
386template< std::size_t 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 >
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 >
421{
422private:
424
426 head_type,
427 ep::impl::is_producer_v<head_type>,
429
430public:
431 using type = typename clauses_type_maker<
434 one_clause_type::next_index >::type;
435};
436
437template<
438 template<class...> class From,
439 template<class...> class To,
440 typename... Results,
441 std::size_t 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<
456 0u >::type,
457 std::tuple >;
458};
459
460template< typename Args_Type_List >
462
463//
464// special_decay
465//
480template< typename T >
482{
483private:
484 using U = std::remove_reference_t<T>;
485
486public:
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//
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//
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:
545 using base_type_t::base_type_t;
546
547 template< typename Extra_Data, typename Handler >
548 [[nodiscard]]
549 static auto
552 Handler && handler,
553 typename base_type_t::result_type & type )
554 {
555 return handler( req, type );
556 }
557};
558
559namespace path_to_params_details
560{
561
562template<
563 typename F,
564 typename Extra_Data,
565 typename Tuple,
566 std::size_t... Indexes >
567decltype(auto)
569 F && what,
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//
589template< typename F, typename Extra_Data, typename Tuple >
590decltype(auto)
592 F && what,
594 Tuple && params )
595{
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//
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:
628 using base_type_t::base_type_t;
629
630 template< typename User_Type, typename Handler >
631 [[nodiscard]]
632 static auto
635 Handler && handler,
636 typename base_type_t::result_type & type )
637 {
639 }
640};
641
642} /* namespace impl */
643
644using namespace restinio::easy_parser;
645
646//
647// path_to_tuple
648//
688template< typename... Args >
689[[nodiscard]]
690auto
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
700
701 return producer_type{
702 subclauses_tuple_type{ std::forward<Args>(args)... }
703 };
704}
705
706//
707// path_to_params
708//
742template< typename... Args >
743[[nodiscard]]
744auto
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
754
755 return producer_type{
756 subclauses_tuple_type{ std::forward<Args>(args)... }
757 };
758}
759
800[[nodiscard]]
801inline auto
803{
805 repeat( 1, N,
807}
808
855template< typename Unescape_Traits =
857[[nodiscard]]
858auto
863
864} /* namespace easy_parser_router */
865
866//
867// generic_easy_parser_router_t
868//
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]]
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.
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
993 return request_not_handled();
994 }
995
996 template<
997 typename Method_Matcher,
998 typename Route_Producer,
999 typename Handler >
1000 void
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<
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
1023 template< typename Route_Producer, typename Handler >
1024 void
1027 Handler && handler )
1028 {
1029 this->add_handler(
1031 std::forward<Route_Producer>(route),
1032 std::forward<Handler>(handler) );
1033 }
1034
1036 template< typename Route_Producer, typename Handler >
1037 void
1040 Handler && handler )
1041 {
1042 this->add_handler(
1044 std::forward<Route_Producer>(route),
1045 std::forward<Handler>(handler) );
1046 }
1047
1049 template< typename Route_Producer, typename Handler >
1050 void
1053 Handler && handler )
1054 {
1055 this->add_handler(
1057 std::forward<Route_Producer>(route),
1058 std::forward<Handler>(handler) );
1059 }
1060
1062 template< typename Route_Producer, typename Handler >
1063 void
1066 Handler && handler )
1067 {
1068 this->add_handler(
1070 std::forward<Route_Producer>(route),
1071 std::forward<Handler>(handler) );
1072 }
1073
1075 template< typename Route_Producer, typename Handler >
1076 void
1079 Handler && handler )
1080 {
1081 this->add_handler(
1083 std::forward<Route_Producer>(route),
1084 std::forward<Handler>(handler) );
1085 }
1086
1088 void
1094
1095private:
1096 using entries_container_t = std::vector<
1098 >;
1099
1101
1105};
1106
1107//
1108// easy_parser_router_t
1109//
1172
1173} /* namespace router */
1174
1175} /* namespace restinio */
1176
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
generic_request_handle_t< Extra_Data > actual_request_handle_t
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
std::vector< easy_parser_router::impl::router_entry_unique_ptr_t< extra_data_t > > entries_container_t
generic_request_handle_t< extra_data_t > actual_request_handle_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.
An very small, simple and somewhat limited implementation of recursive-descent parser.
Stuff related to method_matchers.
auto to_container()
A factory function to create a to_container_consumer.
expected_t< typename Producer::result_type, parse_error_t > try_parse(string_view_t from, Producer producer)
Perform the parsing of the specified content by using specified value producer.
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.
auto repeat(std::size_t min_occurences, std::size_t max_occurences, Clauses &&... clauses)
A factory function to create repetitor of subclauses.
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.
std::unique_ptr< router_entry_t< Extra_Data > > router_entry_unique_ptr_t
An alias for unique_ptr of router_entry.
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.
std::function< request_handling_status_t(generic_request_handle_t< Extra_Data >) > generic_non_matched_request_handler_t
A generic type of handler for non-matched requests.
typename impl::head_of< L... >::type head_of_t
Metafunction to get the first item from a list of types.
typename impl::transform< Transform_F, From, type_list<> >::type transform_t
Applies a specified meta-function to every item from a specified type-list and return a new type-list...
typename impl::rename< From, To >::type rename_t
Allows to pass all template arguments from one type to another.
typename impl::tail_of< L... >::type tail_of_t
Metafunction to get the tail of a list of types in a form of type_list.
std::shared_ptr< generic_request_t< Extra_Data > > generic_request_handle_t
An alias for shared-pointer to incoming request.
run_on_this_thread_settings_t< Traits > on_this_thread()
A special marker for the case when http_server must be run on the context of the current thread.
std::string_view string_view_t
constexpr request_handling_status_t request_not_handled() noexcept
request_handling_status_t
Request handling status.
nonstd::expected< T, E > expected_t
Definition expected.hpp:18
The definition of the non_matched_request_handler type.
A special base class to be used with transformers.
typename clauses_type_maker< meta::tail_of_t< Sources... >, To< Results..., typename one_clause_type::clause_type >, one_clause_type::next_index >::type type
meta::rename_t< typename result_tuple_detector< Args_Type_List, meta::type_list<> >::type, std::tuple > type
meta::rename_t< typename clauses_type_maker< Args_Type_List, meta::type_list<>, 0u >::type, std::tuple > type
typename result_tuple_detector< meta::tail_of_t< Sources... >, typename add_type_if_necessary< meta::head_of_t< Sources... >, To< Results... > >::type >::type type
A special analog of std::decay meta-function that is handles array differently.
typename std::conditional< std::is_array< U >::value, U, std::remove_cv_t< U > >::type type
The main meta-function for processing route DSL.
meta::transform_t< dsl_details::special_decay, meta::type_list< Args... > > arg_types
dsl_details::make_clauses_types_t< arg_types > clauses_tuple
dsl_details::detect_result_tuple_t< arg_types > result_tuple
Helper type to indicate a negative match attempt.
A transformer that performs percent-unescaping of an input string.
virtual bool match(const http_method_id_t &method) const noexcept=0
Is the specified method can be applied to a route?
The basic building block: a type for representation of a type list.
The default traits for escaping and unexcaping symbols in a query string.
Implementation of target_path_holder helper class.