RESTinio
Loading...
Searching...
No Matches
express.hpp
Go to the documentation of this file.
1/*
2 restinio
3*/
4
9#pragma once
10
13
14#include <restinio/optional.hpp>
15
17
20
23
24#include <map>
25#include <vector>
26
27namespace restinio
28{
29
30namespace router
31{
32
33namespace impl
34{
35
37
38} /* namespace impl */
39
40//
41// route_params_t
42//
43
45
57class route_params_t final
58{
59 public:
61 std::vector< std::pair< string_view_t, string_view_t > >;
63 std::vector< string_view_t >;
64
65 private:
67
68 void
70 std::unique_ptr< char[] > request_target,
71 std::shared_ptr< std::string > key_names_buffer,
73 named_parameters_container_t named_parameters,
74 indexed_parameters_container_t indexed_parameters )
75 {
76 m_request_target = std::move( request_target );
77 m_key_names_buffer = std::move( key_names_buffer );
78 m_match = match;
79 m_named_parameters = std::move( named_parameters );
80 m_indexed_parameters = std::move( indexed_parameters );
81 }
82
83 public:
84 route_params_t() = default;
85
88
89 route_params_t( const route_params_t & ) = delete;
91
93 string_view_t match() const noexcept { return m_match; }
94
98 {
99 return find_named_parameter_with_check( key ).second;
100 }
101
103 bool
104 has( string_view_t key ) const noexcept
105 {
106 return m_named_parameters.end() != find_named_parameter( key );
107 }
108
112 get_param( string_view_t key ) const noexcept
113 {
114 const auto it = find_named_parameter( key );
115
116 return m_named_parameters.end() != it ?
117 optional_t< string_view_t >{ it->second } :
119 }
120
123 operator [] ( std::size_t i ) const
124 {
125 if( i >= m_indexed_parameters.size() )
126 throw exception_t{
127 fmt::format(
128 RESTINIO_FMT_FORMAT_STRING( "invalid parameter index: {}" ),
129 i )
130 };
131
132 return m_indexed_parameters.at( i );
133 }
134
137 auto named_parameters_size() const noexcept { return m_named_parameters.size(); }
138 auto indexed_parameters_size() const noexcept { return m_indexed_parameters.size(); }
140
141 private:
142 named_parameters_container_t::const_iterator
144 {
145 return
146 std::find_if(
147 m_named_parameters.begin(),
148 m_named_parameters.end(),
149 [&]( const auto p ){
150 return key == p.first;
151 } );
152 }
153
154 named_parameters_container_t::const_reference
156 {
157 auto it = find_named_parameter( key );
158
159 if( m_named_parameters.end() == it )
160 throw exception_t{
161 fmt::format(
162 RESTINIO_FMT_FORMAT_STRING( "invalid parameter name: {}" ),
163 std::string{ key.data(), key.size() } ) };
164
165 return *it;
166 }
167
169
180 std::unique_ptr< char[] > m_request_target;
181
183 std::shared_ptr< std::string > m_key_names_buffer;
184
187
190
193};
194
195namespace impl
196{
197
198//
199// route_params_accessor_t
200//
201
204{
206 static void
208 route_params_t & rp,
209 std::unique_ptr< char[] > request_target,
210 std::shared_ptr< std::string > key_names_buffer,
211 string_view_t match_,
214 {
215 rp.match(
216 std::move( request_target ),
217 std::move( key_names_buffer ),
218 match_,
219 std::move( named_parameters ),
220 std::move( indexed_parameters ) );
221 }
222
225 static const auto &
226 named_parameters( const route_params_t & rp ) noexcept
227 {
228 return rp.m_named_parameters;
229 }
230
231 static const auto &
232 indexed_parameters( const route_params_t & rp ) noexcept
233 {
234 return rp.m_indexed_parameters;
235 }
237};
238
239//
240// route_params_appender_t
241//
242
245{
246 public:
250 : m_named_parameters{ named_parameters }
251 , m_indexed_parameters{ indexed_parameters }
252 {}
253
258
259 void
261 {
262 m_named_parameters.emplace_back( key, value );
263 }
264
265 void
267 {
268 m_indexed_parameters.emplace_back( value );
269 }
270
271 private:
274};
275
278
279//
280// route_matcher_t
281//
282
284template < typename Regex_Engine = std_regex_engine_t >
286{
287 public:
288 using regex_t = typename Regex_Engine::compiled_regex_t;
289 using match_results_t = typename Regex_Engine::match_results_t;
290
293 http_method_id_t method,
294 regex_t route_regex,
295 std::shared_ptr< std::string > named_params_buffer,
296 param_appender_sequence_t param_appender_sequence )
297 : m_route_regex{ std::move( route_regex ) }
298 , m_named_params_buffer{ std::move( named_params_buffer ) }
299 , m_param_appender_sequence{ std::move( param_appender_sequence ) }
300 {
301 assign( m_method_matcher, std::move(method) );
302 }
303
312 template< typename Method_Matcher >
314 Method_Matcher && method_matcher,
315 regex_t route_regex,
316 std::shared_ptr< std::string > named_params_buffer,
317 param_appender_sequence_t param_appender_sequence )
318 : m_route_regex{ std::move( route_regex ) }
319 , m_named_params_buffer{ std::move( named_params_buffer ) }
320 , m_param_appender_sequence{ std::move( param_appender_sequence ) }
321 {
322 assign(
324 std::forward<Method_Matcher>(method_matcher) );
325 }
326
327 route_matcher_t() = default;
329
331 bool
333 target_path_holder_t & target_path,
334 route_params_t & parameters ) const
335 {
336 match_results_t matches;
337 if( Regex_Engine::try_match(
338 target_path.view(),
340 matches ) )
341 {
342 assert( m_param_appender_sequence.size() + 1 >= matches.size() );
343
344 // Data for route_params_t initialization.
345
346 auto captured_params = target_path.giveout_data();
347
348 const string_view_t match{
349 captured_params.get() + Regex_Engine::submatch_begin_pos( matches[0] ),
350 Regex_Engine::submatch_end_pos( matches[0] ) -
351 Regex_Engine::submatch_begin_pos( matches[0] ) } ;
352
355
356 route_params_appender_t param_appender{ named_parameters, indexed_parameters };
357
358 // Std regex and pcre engines handle
359 // trailing groups with empty values differently.
360 // Std despite they are empty includes them in the list of match results;
361 // Pcre on the other hand does not.
362 // So the second for is for pushing empty values
363 std::size_t i = 1;
364 for( ; i < matches.size(); ++i )
365 {
366 const auto & m = matches[ i ];
368 param_appender,
370 captured_params.get() + Regex_Engine::submatch_begin_pos( m ),
371 Regex_Engine::submatch_end_pos( m ) -
372 Regex_Engine::submatch_begin_pos( m ) } );
373 }
374
375 for( ; i < m_param_appender_sequence.size() + 1; ++i )
376 {
378 param_appender,
379 string_view_t{ captured_params.get(), 0 } );
380 }
381
382 // Init route parameters.
384 parameters,
385 std::move( captured_params ),
386 m_named_params_buffer, // Do not move (it is used on each match).
387 std::move( match ),
388 std::move( named_parameters ),
389 std::move( indexed_parameters ) );
390
391 return true;
392 }
393
394 return false;
395 }
396
397 inline bool
399 const http_request_header_t & h,
400 target_path_holder_t & target_path,
401 route_params_t & parameters ) const
402 {
403 return m_method_matcher->match( h.method() ) &&
404 match_route( target_path, parameters );
405 }
406
407 private:
410
413
415 std::shared_ptr< std::string > m_named_params_buffer;
416
419};
420
421} /* namespace impl */
422
423//
424// generic_express_request_handler_t
425//
442template< typename Extra_Data >
447 >;
448
449//
450// express_request_handler_t
451//
462
463//
464// generic_express_route_entry_t
465//
466
468
473template<
474 typename Regex_Engine,
475 typename Extra_Data_Factory >
477{
478 public:
480 typename Extra_Data_Factory::data_t
481 >;
483 typename Extra_Data_Factory::data_t
484 >;
485
486 private:
490 Regex_Engine >;
491
492 template< typename Method_Matcher >
494 Method_Matcher && method_matcher,
495 matcher_init_data_t matcher_data,
497 : m_matcher{
498 std::forward<Method_Matcher>( method_matcher ),
499 std::move( matcher_data.m_regex ),
500 std::move( matcher_data.m_named_params_buffer ),
501 std::move( matcher_data.m_param_appender_sequence ) }
502 , m_handler{ std::move( handler ) }
503 {}
504
505 public:
507 const generic_express_route_entry_t & ) = delete;
509 const generic_express_route_entry_t & ) = delete;
510
513 generic_express_route_entry_t && ) = default;
514
517
518 template< typename Method_Matcher >
520 Method_Matcher && method_matcher,
521 string_view_t route_path,
522 const path2regex::options_t & options,
525 std::forward<Method_Matcher>( method_matcher ),
526 path2regex::path2regex< impl::route_params_appender_t, Regex_Engine >(
527 route_path,
528 options ),
529 std::move( handler ) }
530 {}
531
532 template< typename Method_Matcher >
534 Method_Matcher && method_matcher,
535 string_view_t route_path,
538 std::forward<Method_Matcher>( method_matcher ),
539 route_path,
540 path2regex::options_t{},
541 std::move( handler ) }
542 {}
543
547 bool
549 const http_request_header_t & h,
550 impl::target_path_holder_t & target_path,
551 route_params_t & params ) const
552 {
553 return m_matcher( h, target_path, params );
554 }
555
560 {
561 return m_handler( std::move( rh ), std::move( rp ) );
562 }
563
564 private:
567};
568
569//
570// express_route_entry_t
571//
578template<
579 typename Regex_Engine = std_regex_engine_t >
581 Regex_Engine,
583
584//
585// generic_express_router_t
586//
587
589
612template<
613 typename Regex_Engine,
614 typename Extra_Data_Factory >
616{
617 public:
622 Regex_Engine,
623 Extra_Data_Factory
627 typename Extra_Data_Factory::data_t
628 >;
629
632
636 {
637 impl::target_path_holder_t target_path{ req->header().path() };
638 route_params_t params;
639 for( const auto & entry : m_handlers )
640 {
641 if( entry.match( req->header(), target_path, params ) )
642 {
643 return entry.handle( std::move( req ), std::move( params ) );
644 }
645 }
646
647 // Here: none of the routes matches this handler.
648
650 {
651 // If non matched request handler is set
652 // then call it.
653 return m_non_matched_request_handler( std::move( req ) );
654 }
655
656 return request_not_handled();
657 }
658
661 template< typename Method_Matcher >
662 void
664 Method_Matcher && method_matcher,
665 string_view_t route_path,
667 {
669 std::forward<Method_Matcher>(method_matcher),
670 route_path,
672 std::move( handler ) );
673 }
674
675 template< typename Method_Matcher >
676 void
678 Method_Matcher && method_matcher,
679 string_view_t route_path,
680 const path2regex::options_t & options,
682 {
683 m_handlers.emplace_back(
684 std::forward<Method_Matcher>(method_matcher),
685 route_path,
686 options,
687 std::move( handler ) );
688 }
689
690 void
692 string_view_t route_path,
694 {
696 http_method_delete(),
697 route_path,
698 std::move( handler ) );
699 }
700
701 void
703 string_view_t route_path,
704 const path2regex::options_t & options,
706 {
708 http_method_delete(),
709 route_path,
710 options,
711 std::move( handler ) );
712 }
713
714 void
716 string_view_t route_path,
718 {
720 http_method_get(),
721 route_path,
722 std::move( handler ) );
723 }
724
725 void
727 string_view_t route_path,
728 const path2regex::options_t & options,
730 {
732 http_method_get(),
733 route_path,
734 options,
735 std::move( handler ) );
736 }
737
738 void
740 string_view_t route_path,
742 {
744 http_method_head(),
745 route_path,
746 std::move( handler ) );
747 }
748
749 void
751 string_view_t route_path,
752 const path2regex::options_t & options,
754 {
756 http_method_head(),
757 route_path,
758 options,
759 std::move( handler ) );
760 }
761
762 void
764 string_view_t route_path,
766 {
768 http_method_post(),
769 route_path,
770 std::move( handler ) );
771 }
772
773 void
775 string_view_t route_path,
776 const path2regex::options_t & options,
778 {
780 http_method_post(),
781 route_path,
782 options,
783 std::move( handler ) );
784 }
785
786 void
788 string_view_t route_path,
790 {
792 http_method_put(),
793 route_path,
794 std::move( handler ) );
795 }
796
797 void
799 string_view_t route_path,
800 const path2regex::options_t & options,
802 {
804 http_method_put(),
805 route_path,
806 options,
807 std::move( handler ) );
808 }
810
812 void
814 {
815 m_non_matched_request_handler = std::move( nmrh );
816 }
817
818 private:
820 Regex_Engine,
821 Extra_Data_Factory
822 >;
823
825 std::vector< route_entry_t > m_handlers;
826
829};
830
831//
832// express_router_t
833//
843template<
844 typename Regex_Engine = std_regex_engine_t >
846 Regex_Engine,
848
849} /* namespace router */
850
852template < typename Value_Type >
853Value_Type
855{
856 return get< Value_Type >( params[ key ] );
857}
858
860template < typename Value_Type >
861Value_Type
862get( const router::route_params_t & params, std::size_t index )
863{
864 return get< Value_Type >( params[ index ] );
865}
866
867} /* namespace restinio */
Exception class for all exceptions thrown by RESTinio.
Definition: exception.hpp:26
A type for representation of HTTP method ID.
Options for matching routes.
Definition: path2regex.hpp:92
A single generic express route entry.
Definition: express.hpp:477
RESTINIO_NODISCARD bool match(const http_request_header_t &h, impl::target_path_holder_t &target_path, route_params_t &params) const
Checks if request header matches entry, and if so, set route params.
Definition: express.hpp:548
generic_express_route_entry_t(Method_Matcher &&method_matcher, matcher_init_data_t matcher_data, actual_request_handler_t handler)
Definition: express.hpp:493
generic_express_request_handler_t< typename Extra_Data_Factory::data_t > actual_request_handler_t
Definition: express.hpp:481
generic_express_route_entry_t & operator=(const generic_express_route_entry_t &)=delete
RESTINIO_NODISCARD request_handling_status_t handle(actual_request_handle_t rh, route_params_t rp) const
Calls a handler of given request with given params.
Definition: express.hpp:559
generic_express_route_entry_t(Method_Matcher &&method_matcher, string_view_t route_path, const path2regex::options_t &options, actual_request_handler_t handler)
Definition: express.hpp:519
generic_express_route_entry_t(generic_express_route_entry_t &&)=default
generic_request_handle_t< typename Extra_Data_Factory::data_t > actual_request_handle_t
Definition: express.hpp:484
generic_express_route_entry_t(Method_Matcher &&method_matcher, string_view_t route_path, actual_request_handler_t handler)
Definition: express.hpp:533
generic_express_route_entry_t & operator=(generic_express_route_entry_t &&)=default
actual_request_handler_t m_handler
Definition: express.hpp:566
generic_express_route_entry_t()=default
generic_express_route_entry_t(const generic_express_route_entry_t &)=delete
impl::route_matcher_t< Regex_Engine > m_matcher
Definition: express.hpp:565
Generic Express.js style router.
Definition: express.hpp:616
void http_post(string_view_t route_path, const path2regex::options_t &options, actual_request_handler_t handler)
Definition: express.hpp:774
void http_get(string_view_t route_path, actual_request_handler_t handler)
Definition: express.hpp:715
void http_put(string_view_t route_path, const path2regex::options_t &options, actual_request_handler_t handler)
Definition: express.hpp:798
generic_non_matched_request_handler_t< typename Extra_Data_Factory::data_t > non_matched_handler_t
Definition: express.hpp:628
void non_matched_request_handler(non_matched_handler_t nmrh)
Set handler for requests that don't match any route.
Definition: express.hpp:813
RESTINIO_NODISCARD request_handling_status_t operator()(actual_request_handle_t req) const
Definition: express.hpp:635
non_matched_handler_t m_non_matched_request_handler
Handler that is called for requests that don't match any route.
Definition: express.hpp:828
void http_head(string_view_t route_path, const path2regex::options_t &options, actual_request_handler_t handler)
Definition: express.hpp:750
void http_delete(string_view_t route_path, const path2regex::options_t &options, actual_request_handler_t handler)
Definition: express.hpp:702
generic_request_handle_t< typename Extra_Data_Factory::data_t > actual_request_handle_t
Definition: express.hpp:619
void http_delete(string_view_t route_path, actual_request_handler_t handler)
Definition: express.hpp:691
std::vector< route_entry_t > m_handlers
A list of existing routes.
Definition: express.hpp:825
void add_handler(Method_Matcher &&method_matcher, string_view_t route_path, const path2regex::options_t &options, actual_request_handler_t handler)
Definition: express.hpp:677
void http_put(string_view_t route_path, actual_request_handler_t handler)
Definition: express.hpp:787
void http_head(string_view_t route_path, actual_request_handler_t handler)
Definition: express.hpp:739
void http_post(string_view_t route_path, actual_request_handler_t handler)
Definition: express.hpp:763
void http_get(string_view_t route_path, const path2regex::options_t &options, actual_request_handler_t handler)
Definition: express.hpp:726
void add_handler(Method_Matcher &&method_matcher, string_view_t route_path, actual_request_handler_t handler)
Add handlers.
Definition: express.hpp:663
generic_express_router_t(generic_express_router_t &&)=default
typename generic_express_route_entry_t< Regex_Engine, Extra_Data_Factory >::actual_request_handler_t actual_request_handler_t
Definition: express.hpp:624
A special class that allows to hold a copy of small-size method_matchers or a pointer to dynamically ...
A matcher for a given path.
Definition: express.hpp:286
route_matcher_t(Method_Matcher &&method_matcher, regex_t route_regex, std::shared_ptr< std::string > named_params_buffer, param_appender_sequence_t param_appender_sequence)
Definition: express.hpp:313
buffered_matcher_holder_t m_method_matcher
HTTP method to match.
Definition: express.hpp:409
regex_t m_route_regex
Regex of a given route.
Definition: express.hpp:412
param_appender_sequence_t m_param_appender_sequence
Parameters values.
Definition: express.hpp:418
bool match_route(target_path_holder_t &target_path, route_params_t &parameters) const
Try to match a given request target with this route.
Definition: express.hpp:332
typename Regex_Engine::match_results_t match_results_t
Definition: express.hpp:289
bool operator()(const http_request_header_t &h, target_path_holder_t &target_path, route_params_t &parameters) const
Definition: express.hpp:398
std::shared_ptr< std::string > m_named_params_buffer
Buffer for named parameters names string views.
Definition: express.hpp:415
typename Regex_Engine::compiled_regex_t regex_t
Definition: express.hpp:288
route_matcher_t(route_matcher_t &&)=default
route_matcher_t(http_method_id_t method, regex_t route_regex, std::shared_ptr< std::string > named_params_buffer, param_appender_sequence_t param_appender_sequence)
Creates matcher with a given parameters.
Definition: express.hpp:292
Helper class for gthering parameters from route.
Definition: express.hpp:245
route_params_t::indexed_parameters_container_t & m_indexed_parameters
Definition: express.hpp:273
void add_indexed_param(string_view_t value)
Definition: express.hpp:266
void add_named_param(string_view_t key, string_view_t value)
Definition: express.hpp:260
route_params_t::named_parameters_container_t & m_named_parameters
Definition: express.hpp:272
route_params_appender_t(route_params_appender_t &&)=delete
route_params_appender_t & operator=(const route_params_appender_t &)=delete
route_params_appender_t(const route_params_appender_t &)=delete
route_params_appender_t(route_params_t::named_parameters_container_t &named_parameters, route_params_t::indexed_parameters_container_t &indexed_parameters)
Definition: express.hpp:247
Helper class for holding a unique instance of char array with target_path value.
RESTINIO_NODISCARD string_view_t view() const noexcept
Get access to the value of target_path.
RESTINIO_NODISCARD data_t giveout_data() noexcept
Give out the value from holder.
Parameters extracted from route.
Definition: express.hpp:58
named_parameters_container_t::const_reference find_named_parameter_with_check(string_view_t key) const
Definition: express.hpp:155
auto indexed_parameters_size() const noexcept
Definition: express.hpp:138
optional_t< string_view_t > get_param(string_view_t key) const noexcept
Get the value of a parameter if it exists.
Definition: express.hpp:112
bool has(string_view_t key) const noexcept
Check parameter.
Definition: express.hpp:104
std::vector< string_view_t > indexed_parameters_container_t
Definition: express.hpp:63
void match(std::unique_ptr< char[] > request_target, std::shared_ptr< std::string > key_names_buffer, string_view_t match, named_parameters_container_t named_parameters, indexed_parameters_container_t indexed_parameters)
Definition: express.hpp:69
route_params_t(const route_params_t &)=delete
std::unique_ptr< char[] > m_request_target
A raw request target.
Definition: express.hpp:180
std::vector< std::pair< string_view_t, string_view_t > > named_parameters_container_t
Definition: express.hpp:61
string_view_t match() const noexcept
Matched route.
Definition: express.hpp:93
named_parameters_container_t m_named_parameters
Named params.
Definition: express.hpp:189
route_params_t & operator=(route_params_t &&)=default
auto named_parameters_size() const noexcept
Get number of parameters.
Definition: express.hpp:137
indexed_parameters_container_t m_indexed_parameters
Indexed params.
Definition: express.hpp:192
route_params_t(route_params_t &&)=default
string_view_t operator[](string_view_t key) const
Get named parameter.
Definition: express.hpp:97
named_parameters_container_t::const_iterator find_named_parameter(string_view_t key) const noexcept
Definition: express.hpp:143
string_view_t m_match
Matched pattern.
Definition: express.hpp:186
std::shared_ptr< std::string > m_key_names_buffer
Shared buffer for string_view of named parameterts names.
Definition: express.hpp:183
#define RESTINIO_NODISCARD
#define RESTINIO_FMT_FORMAT_STRING(s)
Stuff related to method_matchers.
std::vector< param_appender_t< Route_Param_Appender > > param_appender_sequence_t
A sequence of appenders for submatches.
Definition: path2regex.hpp:272
path2regex::param_appender_sequence_t< route_params_appender_t > param_appender_sequence_t
Definition: express.hpp:277
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.
std::function< request_handling_status_t(generic_request_handle_t< Extra_Data >, route_params_t) > generic_express_request_handler_t
Type of generic handler for one route.
Definition: express.hpp:447
generic_express_request_handler_t< no_extra_data_factory_t::data_t > express_request_handler_t
Type of a handler for one route in the case when there is no extra-data in request object.
Definition: express.hpp:461
RESTINIO_NODISCARD constexpr request_handling_status_t request_not_handled() noexcept
nonstd::string_view string_view_t
Definition: string_view.hpp:19
std::shared_ptr< generic_request_t< Extra_Data > > generic_request_handle_t
An alias for shared-pointer to incoming request.
request_handling_status_t
Request handling status.
Value_Type get(const router::route_params_t &params, string_view_t key)
Cast named parameter value to a given type.
Definition: express.hpp:854
STL namespace.
The definition of the non_matched_request_handler type.
http_method_id_t method() const noexcept
The default extra-data-factory to be used in server's traits if a user doesn't specify own one.
Resulting regex and param extraction for a specific route.
Definition: path2regex.hpp:752
Route params private internals accessor.
Definition: express.hpp:204
static const auto & named_parameters(const route_params_t &rp) noexcept
Get values containers for all parameters (used in unit tests).
Definition: express.hpp:226
static const auto & indexed_parameters(const route_params_t &rp) noexcept
Definition: express.hpp:232
static void match(route_params_t &rp, std::unique_ptr< char[] > request_target, std::shared_ptr< std::string > key_names_buffer, string_view_t match_, route_params_t::named_parameters_container_t named_parameters, route_params_t::indexed_parameters_container_t indexed_parameters)
Init parameters with a matched route params.
Definition: express.hpp:207
virtual RESTINIO_NODISCARD bool match(const http_method_id_t &method) const noexcept=0
Is the specified method can be applied to a route?
Regex engine implementation for using with standard regex implementation.
Implementation of target_path_holder helper class.
#define const
Definition: zconf.h:230