2014-04-02 16:38:08 +00:00
# pragma once
# include <cstdint>
2014-04-02 20:31:32 +00:00
# include <utility>
# include <tuple>
2014-04-10 16:43:33 +00:00
# include <unordered_map>
2014-04-13 02:24:06 +00:00
# include <memory>
# include <boost/lexical_cast.hpp>
2014-04-02 16:38:08 +00:00
2014-04-14 15:31:51 +00:00
# include "common.h"
2014-04-09 23:17:08 +00:00
# include "http_response.h"
2014-04-14 18:02:48 +00:00
# include "http_request.h"
# include "utility.h"
2014-07-08 09:28:38 +00:00
# include "logging.h"
2014-04-02 16:38:08 +00:00
2014-04-26 17:19:59 +00:00
namespace crow
2014-04-02 16:38:08 +00:00
{
2014-04-13 02:24:06 +00:00
class BaseRule
2014-04-02 16:38:08 +00:00
{
2014-04-09 23:17:08 +00:00
public :
2014-04-13 02:24:06 +00:00
virtual ~ BaseRule ( )
{
}
2014-04-15 13:46:28 +00:00
virtual void validate ( ) = 0 ;
2014-04-14 15:31:51 +00:00
2014-08-05 18:54:38 +00:00
virtual void handle ( const request & , response & , const routing_params & ) = 0 ;
2014-04-13 02:24:06 +00:00
2014-10-07 12:51:24 +00:00
uint32_t methods ( )
{
return methods_ ;
}
2014-04-20 08:45:10 +00:00
2014-10-07 12:51:24 +00:00
protected :
uint32_t methods_ { 1 < < ( int ) HTTPMethod : : GET } ;
2014-04-13 02:24:06 +00:00
} ;
template < typename . . . Args >
class TaggedRule : public BaseRule
{
2014-04-14 15:31:51 +00:00
private :
2014-08-05 13:38:51 +00:00
template < typename H1 , typename H2 , typename H3 >
2014-04-20 08:45:10 +00:00
struct call_params
{
H1 & handler ;
H2 & handler_with_req ;
2014-08-05 13:38:51 +00:00
H3 & handler_with_req_res ;
2014-04-20 08:45:10 +00:00
const routing_params & params ;
const request & req ;
2014-08-05 18:54:38 +00:00
response & res ;
2014-04-20 08:45:10 +00:00
} ;
template < typename F , int NInt , int NUint , int NDouble , int NString , typename S1 , typename S2 >
struct call
2014-04-14 15:31:51 +00:00
{
} ;
template < typename F , int NInt , int NUint , int NDouble , int NString , typename . . . Args1 , typename . . . Args2 >
struct call < F , NInt , NUint , NDouble , NString , black_magic : : S < int64_t , Args1 . . . > , black_magic : : S < Args2 . . . > >
{
2014-08-05 18:54:38 +00:00
void operator ( ) ( F cparams )
2014-04-14 15:31:51 +00:00
{
using pushed = typename black_magic : : S < Args2 . . . > : : template push_back < call_pair < int64_t , NInt > > ;
2014-08-05 18:54:38 +00:00
call < F , NInt + 1 , NUint , NDouble , NString ,
black_magic : : S < Args1 . . . > , pushed > ( ) ( cparams ) ;
2014-04-14 15:31:51 +00:00
}
} ;
2014-04-15 13:46:28 +00:00
template < typename F , int NInt , int NUint , int NDouble , int NString , typename . . . Args1 , typename . . . Args2 >
struct call < F , NInt , NUint , NDouble , NString , black_magic : : S < uint64_t , Args1 . . . > , black_magic : : S < Args2 . . . > >
{
2014-08-05 18:54:38 +00:00
void operator ( ) ( F cparams )
2014-04-15 13:46:28 +00:00
{
2014-04-15 17:57:18 +00:00
using pushed = typename black_magic : : S < Args2 . . . > : : template push_back < call_pair < uint64_t , NUint > > ;
2014-08-05 18:54:38 +00:00
call < F , NInt , NUint + 1 , NDouble , NString ,
black_magic : : S < Args1 . . . > , pushed > ( ) ( cparams ) ;
2014-04-15 13:46:28 +00:00
}
} ;
template < typename F , int NInt , int NUint , int NDouble , int NString , typename . . . Args1 , typename . . . Args2 >
struct call < F , NInt , NUint , NDouble , NString , black_magic : : S < double , Args1 . . . > , black_magic : : S < Args2 . . . > >
{
2014-08-05 18:54:38 +00:00
void operator ( ) ( F cparams )
2014-04-15 13:46:28 +00:00
{
2014-04-15 17:57:18 +00:00
using pushed = typename black_magic : : S < Args2 . . . > : : template push_back < call_pair < double , NDouble > > ;
2014-08-05 18:54:38 +00:00
call < F , NInt , NUint , NDouble + 1 , NString ,
black_magic : : S < Args1 . . . > , pushed > ( ) ( cparams ) ;
2014-04-15 13:46:28 +00:00
}
} ;
template < typename F , int NInt , int NUint , int NDouble , int NString , typename . . . Args1 , typename . . . Args2 >
struct call < F , NInt , NUint , NDouble , NString , black_magic : : S < std : : string , Args1 . . . > , black_magic : : S < Args2 . . . > >
{
2014-08-05 18:54:38 +00:00
void operator ( ) ( F cparams )
2014-04-15 13:46:28 +00:00
{
2014-04-15 17:57:18 +00:00
using pushed = typename black_magic : : S < Args2 . . . > : : template push_back < call_pair < std : : string , NString > > ;
2014-08-05 18:54:38 +00:00
call < F , NInt , NUint , NDouble , NString + 1 ,
black_magic : : S < Args1 . . . > , pushed > ( ) ( cparams ) ;
2014-04-15 13:46:28 +00:00
}
} ;
2014-04-14 15:31:51 +00:00
template < typename F , int NInt , int NUint , int NDouble , int NString , typename . . . Args1 >
struct call < F , NInt , NUint , NDouble , NString , black_magic : : S < > , black_magic : : S < Args1 . . . > >
{
2014-08-05 18:54:38 +00:00
void operator ( ) ( F cparams )
2014-04-14 15:31:51 +00:00
{
2014-04-20 08:45:10 +00:00
if ( cparams . handler )
2014-08-05 18:54:38 +00:00
{
cparams . res = cparams . handler (
2014-04-20 08:45:10 +00:00
cparams . params . template get < typename Args1 : : type > ( Args1 : : pos ) . . .
) ;
2014-08-05 18:54:38 +00:00
cparams . res . end ( ) ;
return ;
}
2014-04-20 08:45:10 +00:00
if ( cparams . handler_with_req )
2014-08-05 18:54:38 +00:00
{
cparams . res = cparams . handler_with_req (
2014-04-20 08:45:10 +00:00
cparams . req ,
cparams . params . template get < typename Args1 : : type > ( Args1 : : pos ) . . .
) ;
2014-08-05 18:54:38 +00:00
cparams . res . end ( ) ;
return ;
}
2014-08-05 13:38:51 +00:00
if ( cparams . handler_with_req_res )
{
cparams . handler_with_req_res (
cparams . req ,
2014-08-05 18:54:38 +00:00
cparams . res ,
2014-08-05 13:38:51 +00:00
cparams . params . template get < typename Args1 : : type > ( Args1 : : pos ) . . .
) ;
2014-08-05 18:54:38 +00:00
return ;
2014-08-05 13:38:51 +00:00
}
2014-08-16 03:44:43 +00:00
CROW_LOG_DEBUG < < " ERROR cannot find handler " ;
2014-08-16 02:55:26 +00:00
2014-08-05 18:54:38 +00:00
// we already found matched url; this is server error
cparams . res = response ( 500 ) ;
2014-04-14 15:31:51 +00:00
}
} ;
2014-04-13 02:24:06 +00:00
public :
2014-04-26 17:19:59 +00:00
using self_t = TaggedRule < Args . . . > ;
2014-04-13 02:24:06 +00:00
TaggedRule ( std : : string rule )
2014-04-26 17:19:59 +00:00
: rule_ ( std : : move ( rule ) )
2014-04-13 02:24:06 +00:00
{
}
2014-04-26 17:19:59 +00:00
self_t & name ( std : : string name ) noexcept
2014-04-02 20:31:32 +00:00
{
2014-04-10 16:43:33 +00:00
name_ = std : : move ( name ) ;
2014-04-09 23:17:08 +00:00
return * this ;
2014-04-02 20:31:32 +00:00
}
2014-04-10 16:43:33 +00:00
2014-04-26 17:19:59 +00:00
self_t & methods ( HTTPMethod method )
{
methods_ = 1 < < ( int ) method ;
2014-10-07 12:51:24 +00:00
return * this ;
2014-04-26 17:19:59 +00:00
}
template < typename . . . MethodArgs >
self_t & methods ( HTTPMethod method , MethodArgs . . . args_method )
{
methods ( args_method . . . ) ;
methods_ | = 1 < < ( int ) method ;
2014-10-07 12:51:24 +00:00
return * this ;
2014-04-26 17:19:59 +00:00
}
2014-04-15 13:46:28 +00:00
void validate ( )
{
2014-08-05 13:38:51 +00:00
if ( ! handler_ & & ! handler_with_req_ & & ! handler_with_req_res_ )
2014-04-21 18:27:53 +00:00
{
throw std : : runtime_error ( name_ + ( ! name_ . empty ( ) ? " : " : " " ) + " no handler for url " + rule_ ) ;
}
2014-04-15 13:46:28 +00:00
}
2014-04-13 02:24:06 +00:00
template < typename Func >
2014-04-20 08:45:10 +00:00
typename std : : enable_if < black_magic : : CallHelper < Func , black_magic : : S < Args . . . > > : : value , void > : : type
operator ( ) ( Func & & f )
2014-04-02 20:31:32 +00:00
{
2014-04-20 08:45:10 +00:00
static_assert ( black_magic : : CallHelper < Func , black_magic : : S < Args . . . > > : : value | |
2014-08-05 13:38:51 +00:00
black_magic : : CallHelper < Func , black_magic : : S < crow : : request , Args . . . > > : : value ,
2014-04-13 02:24:06 +00:00
" Handler type is mismatched with URL paramters " ) ;
2014-04-15 17:57:18 +00:00
static_assert ( ! std : : is_same < void , decltype ( f ( std : : declval < Args > ( ) . . . ) ) > : : value ,
2014-04-26 17:19:59 +00:00
" Handler function cannot have void return type; valid return types: string, int, crow::resposne, crow::json::wvalue " ) ;
2014-04-20 08:45:10 +00:00
handler_ = [ f = std : : move ( f ) ] ( Args . . . args ) {
return response ( f ( args . . . ) ) ;
} ;
2014-04-21 18:27:53 +00:00
handler_with_req_ = nullptr ;
2014-08-05 13:38:51 +00:00
handler_with_req_res_ = nullptr ;
2014-04-13 02:24:06 +00:00
}
template < typename Func >
2014-08-05 13:38:51 +00:00
typename std : : enable_if <
! black_magic : : CallHelper < Func , black_magic : : S < Args . . . > > : : value & &
black_magic : : CallHelper < Func , black_magic : : S < crow : : request , Args . . . > > : : value ,
void > : : type
2014-04-20 08:45:10 +00:00
operator ( ) ( Func & & f )
2014-04-13 02:24:06 +00:00
{
2014-04-20 08:45:10 +00:00
static_assert ( black_magic : : CallHelper < Func , black_magic : : S < Args . . . > > : : value | |
2014-08-05 13:38:51 +00:00
black_magic : : CallHelper < Func , black_magic : : S < crow : : request , Args . . . > > : : value ,
2014-04-13 02:24:06 +00:00
" Handler type is mismatched with URL paramters " ) ;
2014-04-26 17:19:59 +00:00
static_assert ( ! std : : is_same < void , decltype ( f ( std : : declval < crow : : request > ( ) , std : : declval < Args > ( ) . . . ) ) > : : value ,
" Handler function cannot have void return type; valid return types: string, int, crow::resposne, crow::json::wvalue " ) ;
2014-04-20 08:45:10 +00:00
2014-08-05 13:38:51 +00:00
handler_with_req_ = [ f = std : : move ( f ) ] ( const crow : : request & req , Args . . . args ) {
return response ( f ( req , args . . . ) ) ;
2014-04-20 08:45:10 +00:00
} ;
2014-04-21 18:27:53 +00:00
handler_ = nullptr ;
2014-08-05 13:38:51 +00:00
handler_with_req_res_ = nullptr ;
}
template < typename Func >
typename std : : enable_if <
! black_magic : : CallHelper < Func , black_magic : : S < Args . . . > > : : value & &
! black_magic : : CallHelper < Func , black_magic : : S < crow : : request , Args . . . > > : : value ,
void > : : type
operator ( ) ( Func & & f )
{
static_assert ( black_magic : : CallHelper < Func , black_magic : : S < Args . . . > > : : value | |
black_magic : : CallHelper < Func , black_magic : : S < crow : : request , Args . . . > > : : value | |
black_magic : : CallHelper < Func , black_magic : : S < crow : : request , crow : : response & , Args . . . > > : : value
,
" Handler type is mismatched with URL paramters " ) ;
static_assert ( std : : is_same < void , decltype ( f ( std : : declval < crow : : request > ( ) , std : : declval < crow : : response & > ( ) , std : : declval < Args > ( ) . . . ) ) > : : value ,
" Handler function with response argument should have void return type " ) ;
handler_with_req_res_ = std : : move ( f ) ;
//[f = std::move(f)](const crow::request& req, crow::response& res, Args ... args){
// f(req, response, args...);
//};
handler_ = nullptr ;
handler_with_req_ = nullptr ;
2014-04-20 08:45:10 +00:00
}
template < typename Func >
void operator ( ) ( std : : string name , Func & & f )
{
2014-04-13 02:24:06 +00:00
name_ = std : : move ( name ) ;
2014-07-08 10:14:21 +00:00
( * this ) . template operator ( ) < Func > ( std : : forward ( f ) ) ;
2014-04-09 23:17:08 +00:00
}
2014-04-02 20:31:32 +00:00
2014-08-05 18:54:38 +00:00
void handle ( const request & req , response & res , const routing_params & params ) override
{
call <
call_params <
decltype ( handler_ ) ,
decltype ( handler_with_req_ ) ,
decltype ( handler_with_req_res_ ) > ,
0 , 0 , 0 , 0 ,
black_magic : : S < Args . . . > ,
black_magic : : S < >
> ( ) (
call_params <
decltype ( handler_ ) ,
decltype ( handler_with_req_ ) ,
decltype ( handler_with_req_res_ ) >
{ handler_ , handler_with_req_ , handler_with_req_res_ , params , req , res }
) ;
2014-04-02 20:31:32 +00:00
}
2014-04-09 23:17:08 +00:00
private :
2014-04-13 02:24:06 +00:00
std : : function < response ( Args . . . ) > handler_ ;
2014-08-05 13:38:51 +00:00
std : : function < response ( const crow : : request & , Args . . . ) > handler_with_req_ ;
std : : function < void ( const crow : : request & , crow : : response & , Args . . . ) > handler_with_req_res_ ;
2014-04-26 17:19:59 +00:00
std : : string rule_ ;
std : : string name_ ;
2014-04-14 15:31:51 +00:00
template < typename T , int Pos >
struct call_pair
{
using type = T ;
static const int pos = Pos ;
} ;
2014-05-02 05:17:49 +00:00
friend class Router ;
2014-04-09 23:17:08 +00:00
} ;
2014-04-02 16:38:08 +00:00
2014-04-10 16:43:33 +00:00
class Trie
{
public :
struct Node
{
2014-04-14 15:31:51 +00:00
unsigned rule_index { } ;
std : : array < unsigned , ( int ) ParamType : : MAX > param_childrens { } ;
2014-04-15 17:57:18 +00:00
std : : unordered_map < std : : string , unsigned > children ;
2014-08-06 21:18:21 +00:00
bool IsSimpleNode ( ) const
{
return
! rule_index & &
std : : all_of (
std : : begin ( param_childrens ) ,
std : : end ( param_childrens ) ,
[ ] ( unsigned x ) { return ! x ; } ) ;
}
2014-04-10 16:43:33 +00:00
} ;
2014-08-06 21:18:21 +00:00
Trie ( ) : nodes_ ( 1 )
{
}
2014-04-15 13:46:28 +00:00
2014-08-06 21:18:21 +00:00
private :
void optimizeNode ( Node * node )
{
for ( auto x : node - > param_childrens )
{
if ( ! x )
continue ;
Node * child = & nodes_ [ x ] ;
optimizeNode ( child ) ;
}
if ( node - > children . empty ( ) )
return ;
bool mergeWithChild = true ;
for ( auto & kv : node - > children )
{
Node * child = & nodes_ [ kv . second ] ;
if ( ! child - > IsSimpleNode ( ) )
{
mergeWithChild = false ;
break ;
}
}
if ( mergeWithChild )
{
decltype ( node - > children ) merged ;
for ( auto & kv : node - > children )
{
Node * child = & nodes_ [ kv . second ] ;
for ( auto & child_kv : child - > children )
{
merged [ kv . first + child_kv . first ] = child_kv . second ;
}
}
node - > children = std : : move ( merged ) ;
optimizeNode ( node ) ;
}
else
{
for ( auto & kv : node - > children )
{
Node * child = & nodes_ [ kv . second ] ;
optimizeNode ( child ) ;
}
}
}
void optimize ( )
{
optimizeNode ( head ( ) ) ;
}
2014-04-15 13:46:28 +00:00
2014-08-06 21:18:21 +00:00
public :
void validate ( )
{
if ( ! head ( ) - > IsSimpleNode ( ) )
throw std : : runtime_error ( " Internal error: Trie header should be simple! " ) ;
optimize ( ) ;
}
2014-04-10 16:43:33 +00:00
2014-09-15 16:28:15 +00:00
std : : pair < unsigned , routing_params > find ( const std : : string & req_url , const Node * node = nullptr , unsigned pos = 0 , routing_params * params = nullptr ) const
2014-08-06 21:18:21 +00:00
{
routing_params empty ;
if ( params = = nullptr )
params = & empty ;
2014-04-10 16:43:33 +00:00
2014-08-06 21:18:21 +00:00
unsigned found { } ;
routing_params match_params ;
2014-04-10 16:43:33 +00:00
2014-08-06 21:18:21 +00:00
if ( node = = nullptr )
node = head ( ) ;
2014-09-15 16:28:15 +00:00
if ( pos = = req_url . size ( ) )
2014-08-06 21:18:21 +00:00
return { node - > rule_index , * params } ;
auto update_found = [ & found , & match_params ] ( std : : pair < unsigned , routing_params > & ret )
{
if ( ret . first & & ( ! found | | found > ret . first ) )
{
found = ret . first ;
match_params = std : : move ( ret . second ) ;
}
} ;
if ( node - > param_childrens [ ( int ) ParamType : : INT ] )
{
2014-09-15 16:28:15 +00:00
char c = req_url [ pos ] ;
2014-08-06 21:18:21 +00:00
if ( ( c > = ' 0 ' & & c < = ' 9 ' ) | | c = = ' + ' | | c = = ' - ' )
{
char * eptr ;
errno = 0 ;
2014-09-15 16:28:15 +00:00
long long int value = strtoll ( req_url . data ( ) + pos , & eptr , 10 ) ;
if ( errno ! = ERANGE & & eptr ! = req_url . data ( ) + pos )
2014-08-06 21:18:21 +00:00
{
params - > int_params . push_back ( value ) ;
2014-09-15 16:28:15 +00:00
auto ret = find ( req_url , & nodes_ [ node - > param_childrens [ ( int ) ParamType : : INT ] ] , eptr - req_url . data ( ) , params ) ;
2014-08-06 21:18:21 +00:00
update_found ( ret ) ;
params - > int_params . pop_back ( ) ;
}
}
}
if ( node - > param_childrens [ ( int ) ParamType : : UINT ] )
{
2014-09-15 16:28:15 +00:00
char c = req_url [ pos ] ;
2014-08-06 21:18:21 +00:00
if ( ( c > = ' 0 ' & & c < = ' 9 ' ) | | c = = ' + ' )
{
char * eptr ;
errno = 0 ;
2014-09-15 16:28:15 +00:00
unsigned long long int value = strtoull ( req_url . data ( ) + pos , & eptr , 10 ) ;
if ( errno ! = ERANGE & & eptr ! = req_url . data ( ) + pos )
2014-08-06 21:18:21 +00:00
{
params - > uint_params . push_back ( value ) ;
2014-09-15 16:28:15 +00:00
auto ret = find ( req_url , & nodes_ [ node - > param_childrens [ ( int ) ParamType : : UINT ] ] , eptr - req_url . data ( ) , params ) ;
2014-08-06 21:18:21 +00:00
update_found ( ret ) ;
params - > uint_params . pop_back ( ) ;
}
}
}
if ( node - > param_childrens [ ( int ) ParamType : : DOUBLE ] )
{
2014-09-15 16:28:15 +00:00
char c = req_url [ pos ] ;
2014-08-06 21:18:21 +00:00
if ( ( c > = ' 0 ' & & c < = ' 9 ' ) | | c = = ' + ' | | c = = ' - ' | | c = = ' . ' )
{
char * eptr ;
errno = 0 ;
2014-09-15 16:28:15 +00:00
double value = strtod ( req_url . data ( ) + pos , & eptr ) ;
if ( errno ! = ERANGE & & eptr ! = req_url . data ( ) + pos )
2014-08-06 21:18:21 +00:00
{
params - > double_params . push_back ( value ) ;
2014-09-15 16:28:15 +00:00
auto ret = find ( req_url , & nodes_ [ node - > param_childrens [ ( int ) ParamType : : DOUBLE ] ] , eptr - req_url . data ( ) , params ) ;
2014-08-06 21:18:21 +00:00
update_found ( ret ) ;
params - > double_params . pop_back ( ) ;
}
}
}
if ( node - > param_childrens [ ( int ) ParamType : : STRING ] )
{
size_t epos = pos ;
2014-09-15 16:28:15 +00:00
for ( ; epos < req_url . size ( ) ; epos + + )
2014-08-06 21:18:21 +00:00
{
2014-09-15 16:28:15 +00:00
if ( req_url [ epos ] = = ' / ' )
2014-08-06 21:18:21 +00:00
break ;
}
if ( epos ! = pos )
{
2014-09-15 16:28:15 +00:00
params - > string_params . push_back ( req_url . substr ( pos , epos - pos ) ) ;
auto ret = find ( req_url , & nodes_ [ node - > param_childrens [ ( int ) ParamType : : STRING ] ] , epos , params ) ;
2014-08-06 21:18:21 +00:00
update_found ( ret ) ;
params - > string_params . pop_back ( ) ;
}
}
if ( node - > param_childrens [ ( int ) ParamType : : PATH ] )
{
2014-09-15 16:28:15 +00:00
size_t epos = req_url . size ( ) ;
2014-08-06 21:18:21 +00:00
if ( epos ! = pos )
{
2014-09-15 16:28:15 +00:00
params - > string_params . push_back ( req_url . substr ( pos , epos - pos ) ) ;
auto ret = find ( req_url , & nodes_ [ node - > param_childrens [ ( int ) ParamType : : PATH ] ] , epos , params ) ;
2014-08-06 21:18:21 +00:00
update_found ( ret ) ;
params - > string_params . pop_back ( ) ;
}
}
2014-04-15 17:57:18 +00:00
2014-08-06 21:18:21 +00:00
for ( auto & kv : node - > children )
{
const std : : string & fragment = kv . first ;
const Node * child = & nodes_ [ kv . second ] ;
2014-04-10 16:43:33 +00:00
2014-09-15 16:28:15 +00:00
if ( req_url . compare ( pos , fragment . size ( ) , fragment ) = = 0 )
2014-08-06 21:18:21 +00:00
{
2014-09-15 16:28:15 +00:00
auto ret = find ( req_url , child , pos + fragment . size ( ) , params ) ;
2014-08-06 21:18:21 +00:00
update_found ( ret ) ;
}
}
2014-04-10 16:43:33 +00:00
2014-08-06 21:18:21 +00:00
return { found , match_params } ;
}
void add ( const std : : string & url , unsigned rule_index )
{
unsigned idx { 0 } ;
for ( unsigned i = 0 ; i < url . size ( ) ; i + + )
{
char c = url [ i ] ;
if ( c = = ' < ' )
{
static struct ParamTraits
{
ParamType type ;
std : : string name ;
} paramTraits [ ] =
{
{ ParamType : : INT , " <int> " } ,
{ ParamType : : UINT , " <uint> " } ,
{ ParamType : : DOUBLE , " <float> " } ,
{ ParamType : : DOUBLE , " <double> " } ,
{ ParamType : : STRING , " <str> " } ,
{ ParamType : : STRING , " <string> " } ,
{ ParamType : : PATH , " <path> " } ,
} ;
for ( auto & x : paramTraits )
{
if ( url . compare ( i , x . name . size ( ) , x . name ) = = 0 )
{
if ( ! nodes_ [ idx ] . param_childrens [ ( int ) x . type ] )
{
auto new_node_idx = new_node ( ) ;
nodes_ [ idx ] . param_childrens [ ( int ) x . type ] = new_node_idx ;
}
idx = nodes_ [ idx ] . param_childrens [ ( int ) x . type ] ;
i + = x . name . size ( ) ;
break ;
}
}
i - - ;
}
else
{
std : : string piece ( & c , 1 ) ;
if ( ! nodes_ [ idx ] . children . count ( piece ) )
{
auto new_node_idx = new_node ( ) ;
nodes_ [ idx ] . children . emplace ( piece , new_node_idx ) ;
}
idx = nodes_ [ idx ] . children [ piece ] ;
}
}
if ( nodes_ [ idx ] . rule_index )
throw std : : runtime_error ( " handler already exists for " + url ) ;
nodes_ [ idx ] . rule_index = rule_index ;
}
private :
void debug_node_print ( Node * n , int level )
{
for ( int i = 0 ; i < ( int ) ParamType : : MAX ; i + + )
{
if ( n - > param_childrens [ i ] )
{
CROW_LOG_DEBUG < < std : : string ( 2 * level , ' ' ) /*<< "("<<n->param_childrens[i]<<") "*/ ;
switch ( ( ParamType ) i )
{
case ParamType : : INT :
CROW_LOG_DEBUG < < " <int> " ;
break ;
case ParamType : : UINT :
CROW_LOG_DEBUG < < " <uint> " ;
break ;
case ParamType : : DOUBLE :
CROW_LOG_DEBUG < < " <float> " ;
break ;
case ParamType : : STRING :
CROW_LOG_DEBUG < < " <str> " ;
break ;
case ParamType : : PATH :
CROW_LOG_DEBUG < < " <path> " ;
break ;
default :
CROW_LOG_DEBUG < < " <ERROR> " ;
break ;
}
debug_node_print ( & nodes_ [ n - > param_childrens [ i ] ] , level + 1 ) ;
}
}
for ( auto & kv : n - > children )
{
CROW_LOG_DEBUG < < std : : string ( 2 * level , ' ' ) /*<< "(" << kv.second << ") "*/ < < kv . first ;
debug_node_print ( & nodes_ [ kv . second ] , level + 1 ) ;
}
}
public :
void debug_print ( )
{
debug_node_print ( head ( ) , 0 ) ;
}
2014-04-10 16:43:33 +00:00
2014-08-06 20:25:18 +00:00
private :
2014-08-06 21:18:21 +00:00
const Node * head ( ) const
{
return & nodes_ . front ( ) ;
}
Node * head ( )
{
return & nodes_ . front ( ) ;
}
unsigned new_node ( )
{
nodes_ . resize ( nodes_ . size ( ) + 1 ) ;
return nodes_ . size ( ) - 1 ;
}
2014-04-10 16:43:33 +00:00
std : : vector < Node > nodes_ ;
} ;
2014-04-02 16:38:08 +00:00
class Router
{
public :
2014-08-06 21:18:21 +00:00
Router ( ) : rules_ ( 1 ) { }
2014-04-13 02:24:06 +00:00
template < uint64_t N >
typename black_magic : : arguments < N > : : type : : template rebind < TaggedRule > & new_rule_tagged ( const std : : string & rule )
{
using RuleT = typename black_magic : : arguments < N > : : type : : template rebind < TaggedRule > ;
auto ruleObject = new RuleT ( rule ) ;
rules_ . emplace_back ( ruleObject ) ;
trie_ . add ( rule , rules_ . size ( ) - 1 ) ;
return * ruleObject ;
}
2014-08-06 21:18:21 +00:00
void validate ( )
{
trie_ . validate ( ) ;
for ( auto & rule : rules_ )
{
if ( rule )
rule - > validate ( ) ;
}
}
2014-04-10 16:43:33 +00:00
2014-08-06 21:18:21 +00:00
void handle ( const request & req , response & res )
{
2014-10-14 08:48:35 +00:00
auto found = trie_ . find ( req . url ) ;
2014-08-06 21:18:21 +00:00
unsigned rule_index = found . first ;
if ( ! rule_index )
{
2014-10-14 08:48:35 +00:00
CROW_LOG_DEBUG < < " Cannot match rules " < < req . url ;
2014-08-06 21:18:21 +00:00
res = response ( 404 ) ;
res . end ( ) ;
return ;
}
if ( rule_index > = rules_ . size ( ) )
throw std : : runtime_error ( " Trie internal structure corrupted! " ) ;
2014-10-07 12:51:24 +00:00
if ( ( rules_ [ rule_index ] - > methods ( ) & ( 1 < < ( uint32_t ) req . method ) ) = = 0 )
{
2014-10-14 17:25:22 +00:00
CROW_LOG_DEBUG < < " Rule found but method mismatch: " < < req . url < < " with " < < method_name ( req . method ) < < " ( " < < ( uint32_t ) req . method < < " ) / " < < rules_ [ rule_index ] - > methods ( ) ;
2014-10-07 12:51:24 +00:00
res = response ( 404 ) ;
res . end ( ) ;
return ;
}
CROW_LOG_DEBUG < < " Matched rule ' " < < ( ( TaggedRule < > * ) rules_ [ rule_index ] . get ( ) ) - > rule_ < < " ' " < < ( uint32_t ) req . method < < " / " < < rules_ [ rule_index ] - > methods ( ) ;
2014-08-06 21:18:21 +00:00
rules_ [ rule_index ] - > handle ( req , res , found . second ) ;
}
void debug_print ( )
{
trie_ . debug_print ( ) ;
}
2014-04-15 17:57:18 +00:00
2014-04-02 20:31:32 +00:00
private :
2014-04-13 02:24:06 +00:00
std : : vector < std : : unique_ptr < BaseRule > > rules_ ;
2014-04-10 16:43:33 +00:00
Trie trie_ ;
2014-04-02 16:38:08 +00:00
} ;
}