2
3
6
7
8
9
20#include <restinio/impl/include_fmtlib.hpp>
22#include <restinio/exception.hpp>
23#include <restinio/string_view.hpp>
43 result.reserve( group.size() + group.size() / 2 );
45 for(
const char c : group )
47 if(
'=' == c ||
'!' == c ||
':' == c ||
48 '$' == c ||
'/' == c ||
'(' == c ||
')' == c )
66 result.reserve( group.size() + group.size() / 2 );
68 for(
const char c : group )
70 if(
'.' == c ||
'+' == c ||
'*' == c ||
71 '?' == c ||
'=' == c ||
'^' == c ||
72 ':' == c ||
'$' == c ||
'{' == c ||
73 '}' == c ||
'(' == c ||
')' == c ||
74 '[' == c ||
']' == c ||
'|' == c ||
75 '\\' == c ||
'/' == c )
154 m_delimiter = std::move( p );
161 return std::move(
this->delimiter( std::move( p ) ) );
173 std::string result{ std::move( d ) };
184 m_delimiters = std::move( p );
191 return std::move(
this->delimiters( std::move( p ) ) );
203 m_ends_with = std::move( p );
210 return std::move(
this->ends_with( std::move( p ) ) );
224 for(
const auto & e : m_ends_with )
228 result += impl::escape_string( e ) +
"|";
262template <
typename Route_Param_Appender >
264 std::function<
void ( Route_Param_Appender &,
string_view_t ) >;
279template <
typename Route_Param_Appender >
285 Route_Param_Appender & parameters,
286 string_view_t value ){
287 parameters.add_named_param( key, value );
292template <
typename Route_Param_Appender >
297 []( Route_Param_Appender & parameters, string_view_t value ){
298 parameters.add_indexed_param( value );
310template <
typename Container >
311class string_view_buffer_storage_appender_t
final
318 assert(
m_buffer.capacity() >= reserve_size );
326 const auto n = name.size();
332 throw exception_t{ "unable to insert data into names buffer" };
336 const auto prev_size =
m_buffer.size();
338 std::copy( name.data(), name.data() + n, std::back_inserter(
m_buffer ) );
339 return string_view_t{ m_buffer.data() + prev_size, n };
357 R"((\\.)|(?:\:(\w+)(?:\(((?:\\.|[^\\()])+)\))?|\(((?:\\.|[^\\()])+)\))([+*?])?)";
370template <
typename Route_Param_Appender >
382 param_appender_sequence_t< Route_Param_Appender > & param_appender_sequence,
403template <
typename Route_Param_Appender >
404class plain_string_token_t
final :
public token_t< Route_Param_Appender >
415 param_appender_sequence_t< Route_Param_Appender > &,
418 route += m_escaped_path;
426 return std::string::npos != delimiters.find( m_last_char );
435template <
typename Route_Param_Appender >
439 using token_t = plain_string_token_t< Route_Param_Appender >;
440 return std::make_unique< token_t >( std::move( path ) );
448template <
typename Route_Param_Appender,
typename Name >
449class parameter_token_t
final :
public token_t< Route_Param_Appender >
457 const std::string & prefix,
458 std::string delimiter,
462 std::string pattern )
463 :
m_name{ std::move( name ) }
475 param_appender_sequence_t< Route_Param_Appender > & param_appender_sequence,
479 auto capture =
"(?:" + m_pattern +
")";
484 capture +=
"(?:" + m_escaped_prefix + capture +
")*";
492 capture =
"(?:" + m_escaped_prefix +
"(" + capture +
"))?";
496 capture = m_escaped_prefix +
"(" + capture +
")?";
502 capture = m_escaped_prefix +
"(" + capture +
")";
507 param_appender_sequence.push_back(
508 make_param_setter< Route_Param_Appender >(
509 names_buffer_appender.append_name(
m_name ) ) );
529template <
typename Route_Param_Appender,
typename Name >
534 std::string delimiter,
538 std::string pattern )
540 return std::make_unique< parameter_token_t< Route_Param_Appender, Name > >(
543 std::move( delimiter ),
547 std::move( pattern ) );
564 auto pos = strv.find(
'(' );
565 if( std::string::npos != pos )
570 "non-escaped bracket '(' at pos {}: may be unmatched group start" ),
574 pos = strv.find(
')' );
575 if( std::string::npos != pos )
580 "non-escaped bracket ')' at pos {}: may be unmatched group finish" ),
584 return std::string{ strv.data(), strv.size() };
592template <
typename Route_Param_Appender,
typename MATCH >
599 token_list_t< Route_Param_Appender > & result )
601 std::string prefix{
"" };
602 if( !path_escaped && !path.empty() )
604 const auto k = path.size() - 1;
606 if( std::string::npos != options.delimiters().find( path[k] ) )
608 prefix = path.substr( k, 1 );
609 path = path.substr( 0, k );
616 result.push_back( create_token< Route_Param_Appender >( std::move( path ) ) );
617 path_escaped =
false;
620 const auto next = match.suffix().str().substr( 0, 1 );
622 std::string name{ match[ group_name_idx ].str() };
623 const std::string modifier{ match[ group_modifier_idx ].str() };
625 const bool partial = !prefix.empty() && !next.empty() && prefix != next;
627 const bool optional = modifier ==
"?" || modifier ==
"*";
628 const bool repeat = modifier ==
"+" || modifier ==
"*";
629 std::string delimiter = options.make_delimiter( prefix );
631 auto create_pattern = [ delimiter ](
auto pattern ){
632 if( !pattern.empty() )
634 pattern = escape_group( pattern );
638 pattern =
"[^" + escape_string( delimiter ) +
"]+?";
647 create_token< Route_Param_Appender >(
650 std::move( delimiter ),
660 create_token< Route_Param_Appender >(
663 std::move( delimiter ),
676template <
typename Route_Param_Appender >
680 token_list_t< Route_Param_Appender > result;
684 bool path_escaped =
false;
686 std::cregex_iterator token_it{
688 route_sv.data() + route_sv.size(),
691 std::cregex_iterator token_end{};
693 if( token_it == token_end )
696 path = check_no_unescaped_brackets( route_sv, 0 );
699 while( token_it != token_end )
701 const auto & match = *token_it;
703 assert( 6 == match.size() );
705 const string_view_t prefix{
706 match.prefix().first,
707 static_cast<std::size_t>( match.prefix().length() ) };
709 path += check_no_unescaped_brackets( prefix,
710 static_cast<std::size_t>(match.position()) - prefix.size() );
713 if( !escaped.empty() )
715 assert( 2 == escaped.size() );
716 path += escaped[ 1 ];
721 handle_param_token( options, match, path, path_escaped, result );
724 auto next_it = token_it;
725 std::advance( next_it, 1 );
727 if( next_it == token_end )
729 const std::string suffix{ match.suffix() };
731 check_no_unescaped_brackets(
733 static_cast<std::size_t>(match.position() + match.length()) );
740 result.push_back( create_token< Route_Param_Appender >( std::move( path ) ) );
750template <
typename Route_Param_Appender,
typename Regex_Engine >
780template <
typename Route_Param_Appender,
typename Regex_Engine >
784 const token_list_t< Route_Param_Appender > & tokens,
790 result.m_named_params_buffer = std::make_shared< std::string >();
792 names_buffer_appender{ path.size(), *result.m_named_params_buffer };
795 auto & param_appender_sequence = result.m_param_appender_sequence;
799 std::size_t captured_groups_count = 1 ;
801 for(
const auto & t : tokens )
803 const auto appended_token_type =
804 t->append_self_to( route, param_appender_sequence, names_buffer_appender );
806 if( token_type_t::capturing_token == appended_token_type )
807 ++captured_groups_count;
810 if( Regex_Engine::max_capture_groups() < captured_groups_count )
816 "too many parameter to capture from route: {}, while {} "
818 captured_groups_count,
819 Regex_Engine::max_capture_groups() ) };
822 const auto & delimiter = escape_string( options.delimiter() );
823 const auto & ends_with = options.make_ends_with();
829 route +=
"(?:" + delimiter +
")?";
832 if( ends_with ==
"$" )
835 route +=
"(?=" + ends_with +
")";
840 route +=
"(?:" + delimiter +
"(?=" + ends_with +
"))?";
842 if( !tokens.empty() &&
844 route +=
"(?=" + delimiter +
"|" + ends_with +
")";
847 result.m_regex = Regex_Engine::compile_regex(
"^" + route, options
.sensitive() );
849 catch(
const std::exception & ex )
867template <
typename Route_Param_Appender,
typename Regex_Engine >
873 return impl::tokens2regexp< Route_Param_Appender, Regex_Engine >(
875 impl::parse< Route_Param_Appender >( path, options ),
Exception class for all exceptions thrown by RESTinio.
exception_t(const char *err)
parameter_token_t(const parameter_token_t &)=delete
const std::string m_escaped_prefix
const std::string m_pattern
parameter_token_t(Name name, const std::string &prefix, std::string delimiter, bool optional, bool repeat, bool partial, std::string pattern)
parameter_token_t(parameter_token_t &&)=delete
const std::string m_delimiter
virtual token_type_t append_self_to(std::string &route, param_appender_sequence_t< Route_Param_Appender > ¶m_appender_sequence, names_buffer_appender_t &names_buffer_appender) const override
const std::string m_escaped_path
Already escaped piece of the route.
virtual token_type_t append_self_to(std::string &route, param_appender_sequence_t< Route_Param_Appender > &, names_buffer_appender_t &) const override
virtual bool is_end_delimited(const std::string &delimiters) const noexcept override
plain_string_token_t(const std::string &path)
string_view_t append_name(const std::string &name)
Appends a given name to buffer, and returns a string view object within the context of a buffer.
std::size_t append_name(std::size_t i) const
A stub for indexed paramaters.
string_view_buffer_storage_appender_t(std::size_t reserve_size, Container &buffer)
Base class for token variants.
virtual bool is_end_delimited(const std::string &) const noexcept
virtual token_type_t append_self_to(std::string &route, param_appender_sequence_t< Route_Param_Appender > ¶m_appender_sequence, names_buffer_appender_t &names_buffer_appender) const =0
token_t(token_t &&)=delete
token_t(const token_t &)=delete
virtual ~token_t()=default
Options for matching routes.
options_t & ends_with(std::vector< std::string > p) &
const std::vector< std::string > & ends_with() const
options_t && delimiter(std::string p) &&
bool m_strict
When false the trailing slash is optional.
const std::string & delimiter() const
options_t && delimiters(std::string p) &&
std::string make_ends_with() const
options_t & strict(bool p) &
options_t & sensitive(bool s) &
options_t && ending(bool p) &&
std::string m_delimiters
Path delimiters.
bool m_sensitive
When true the route will be case sensitive.
std::vector< std::string > m_ends_with
Path delimiter.
bool m_ending
When false the path will match at the beginning.
options_t & delimiters(std::string p) &
const std::string & delimiters() const
options_t & delimiter(std::string p) &
std::string make_delimiter(std::string d) const
options_t & ending(bool p) &
options_t && ends_with(std::vector< std::string > p) &&
options_t && sensitive(bool s) &&
options_t && strict(bool p) &&
std::string m_delimiter
Path delimiter.
#define RESTINIO_FMT_FORMAT_STRING(s)
constexpr std::size_t group_escaped_idx
Indexes for different groups in matched result (used when extracting tokens from initial route).
auto escape_string(const std::string &group)
Excape regex control chars.
string_view_buffer_storage_appender_t< std::string > names_buffer_appender_t
auto tokens2regexp(string_view_t path, const token_list_t< Route_Param_Appender > &tokens, const options_t &options)
Makes route regex matcher out of path tokens.
constexpr std::size_t group_capture_idx
token_unique_ptr_t< Route_Param_Appender > create_token(std::string path)
auto escape_group(const std::string &group)
Escapes not allowed symbols in a sub-match group assigned to a parameter.
constexpr std::size_t group_modifier_idx
constexpr std::size_t group_name_idx
std::string check_no_unescaped_brackets(string_view_t strv, std::size_t base_pos)
Checks that string doesn't contain non-excaped brackets.
constexpr auto path_regex_str
The main path matching expression.
constexpr std::size_t group_group_idx
void handle_param_token(const options_t &options, const MATCH &match, std::string &path, bool &path_escaped, token_list_t< Route_Param_Appender > &result)
Handling of a parameterized token.
token_list_t< Route_Param_Appender > parse(string_view_t route_sv, const options_t &options)
Parse a string for the raw tokens.
token_unique_ptr_t< Route_Param_Appender > create_token(Name name, std::string prefix, std::string delimiter, bool optional, bool repeat, bool partial, std::string pattern)
Creates tokent for specific parameter.
auto path2regex(string_view_t path, const options_t &options)
The main path matching regexp.
param_appender_t< Route_Param_Appender > make_param_setter(std::size_t)
Create default appender indexed parameter.
param_appender_t< Route_Param_Appender > make_param_setter(string_view_t key)
Create default appender for named parameter.
std::function< void(Route_Param_Appender &, string_view_t) > param_appender_t
Appends sub-match as a request parameter to specified container.
Resulting regex and param extraction for a specific route.
std::shared_ptr< std::string > m_named_params_buffer
Char buffer for holding named paramaters.
param_appender_sequence_t< Route_Param_Appender > m_param_appender_sequence
Appenders for captured values (names/indexed groups).
typename Regex_Engine::compiled_regex_t regex_t
route_regex_matcher_data_t(route_regex_matcher_data_t &&)=default
route_regex_matcher_data_t & operator=(route_regex_matcher_data_t &&)=delete
route_regex_matcher_data_t()=default
route_regex_matcher_data_t & operator=(const route_regex_matcher_data_t &)=delete
route_regex_matcher_data_t(const route_regex_matcher_data_t &)=delete