2016-03-27 01:05:17 +01:00
package main
import (
"errors"
"github.com/gorilla/mux"
2016-04-07 15:01:04 +02:00
"net"
2016-04-06 13:06:31 +02:00
"net/http"
2016-03-27 01:05:17 +01:00
"reflect"
2016-04-06 13:06:31 +02:00
"sort"
2016-03-27 01:05:17 +01:00
"strings"
)
// Rules holds rule parsing and configuration
type Rules struct {
route * serverRoute
2016-04-07 15:01:04 +02:00
err error
2016-03-27 01:05:17 +01:00
}
2016-04-06 13:06:31 +02:00
func ( r * Rules ) host ( hosts ... string ) * mux . Route {
return r . route . route . MatcherFunc ( func ( req * http . Request , route * mux . RouteMatch ) bool {
2016-04-07 15:01:04 +02:00
reqHost , _ , err := net . SplitHostPort ( req . Host )
if err != nil {
reqHost = req . Host
}
2016-04-06 13:06:31 +02:00
for _ , host := range hosts {
2016-04-07 15:01:04 +02:00
if reqHost == strings . TrimSpace ( host ) {
2016-04-06 13:06:31 +02:00
return true
}
}
return false
} )
2016-03-27 01:05:17 +01:00
}
2016-04-06 13:06:31 +02:00
func ( r * Rules ) hostRegexp ( hosts ... string ) * mux . Route {
router := r . route . route . Subrouter ( )
for _ , host := range hosts {
router . Host ( strings . TrimSpace ( host ) )
}
return r . route . route
2016-03-27 01:05:17 +01:00
}
2016-04-06 13:06:31 +02:00
func ( r * Rules ) path ( paths ... string ) * mux . Route {
router := r . route . route . Subrouter ( )
for _ , path := range paths {
router . Path ( strings . TrimSpace ( path ) )
}
return r . route . route
}
func ( r * Rules ) pathPrefix ( paths ... string ) * mux . Route {
router := r . route . route . Subrouter ( )
for _ , path := range paths {
router . PathPrefix ( strings . TrimSpace ( path ) )
}
return r . route . route
2016-03-27 01:05:17 +01:00
}
2016-04-06 13:06:31 +02:00
type bySize [ ] string
func ( a bySize ) Len ( ) int { return len ( a ) }
func ( a bySize ) Swap ( i , j int ) { a [ i ] , a [ j ] = a [ j ] , a [ i ] }
func ( a bySize ) Less ( i , j int ) bool { return len ( a [ i ] ) > len ( a [ j ] ) }
func ( r * Rules ) pathStrip ( paths ... string ) * mux . Route {
sort . Sort ( bySize ( paths ) )
r . route . stripPrefixes = paths
router := r . route . route . Subrouter ( )
for _ , path := range paths {
router . Path ( strings . TrimSpace ( path ) )
}
return r . route . route
2016-03-27 01:05:17 +01:00
}
2016-04-06 13:06:31 +02:00
func ( r * Rules ) pathPrefixStrip ( paths ... string ) * mux . Route {
sort . Sort ( bySize ( paths ) )
r . route . stripPrefixes = paths
router := r . route . route . Subrouter ( )
for _ , path := range paths {
router . PathPrefix ( strings . TrimSpace ( path ) )
}
return r . route . route
2016-03-27 01:05:17 +01:00
}
func ( r * Rules ) methods ( methods ... string ) * mux . Route {
return r . route . route . Methods ( methods ... )
}
func ( r * Rules ) headers ( headers ... string ) * mux . Route {
return r . route . route . Headers ( headers ... )
}
func ( r * Rules ) headersRegexp ( headers ... string ) * mux . Route {
return r . route . route . HeadersRegexp ( headers ... )
}
// Parse parses rules expressions
func ( r * Rules ) Parse ( expression string ) ( * mux . Route , error ) {
functions := map [ string ] interface { } {
"Host" : r . host ,
2016-04-06 13:06:31 +02:00
"HostRegexp" : r . hostRegexp ,
2016-03-27 01:05:17 +01:00
"Path" : r . path ,
"PathStrip" : r . pathStrip ,
"PathPrefix" : r . pathPrefix ,
"PathPrefixStrip" : r . pathPrefixStrip ,
2016-04-06 13:06:31 +02:00
"Method" : r . methods ,
2016-03-27 01:05:17 +01:00
"Headers" : r . headers ,
"HeadersRegexp" : r . headersRegexp ,
}
f := func ( c rune ) bool {
2016-04-06 13:06:31 +02:00
return c == ':'
2016-03-27 01:05:17 +01:00
}
// get function
parsedFunctions := strings . FieldsFunc ( expression , f )
2016-04-06 13:06:31 +02:00
if len ( parsedFunctions ) == 0 {
2016-03-27 01:05:17 +01:00
return nil , errors . New ( "Error parsing rule: " + expression )
}
parsedFunction , ok := functions [ parsedFunctions [ 0 ] ]
if ! ok {
2016-04-21 23:38:44 +01:00
return nil , errors . New ( "Error parsing rule: " + expression + ". Unknown function: " + parsedFunctions [ 0 ] )
2016-03-27 01:05:17 +01:00
}
2016-04-06 13:06:31 +02:00
parsedFunctions = append ( parsedFunctions [ : 0 ] , parsedFunctions [ 1 : ] ... )
2016-03-27 01:05:17 +01:00
fargs := func ( c rune ) bool {
return c == ',' || c == ';'
}
// get function
2016-04-06 13:06:31 +02:00
parsedArgs := strings . FieldsFunc ( strings . Join ( parsedFunctions , ":" ) , fargs )
2016-03-27 01:05:17 +01:00
if len ( parsedArgs ) == 0 {
return nil , errors . New ( "Error parsing args from rule: " + expression )
}
inputs := make ( [ ] reflect . Value , len ( parsedArgs ) )
for i := range parsedArgs {
inputs [ i ] = reflect . ValueOf ( parsedArgs [ i ] )
}
method := reflect . ValueOf ( parsedFunction )
if method . IsValid ( ) {
2016-04-06 13:06:31 +02:00
resultRoute := method . Call ( inputs ) [ 0 ] . Interface ( ) . ( * mux . Route )
2016-04-07 15:01:04 +02:00
if r . err != nil {
return nil , r . err
}
2016-04-06 13:06:31 +02:00
if resultRoute . GetError ( ) != nil {
return nil , resultRoute . GetError ( )
}
return resultRoute , nil
2016-03-27 01:05:17 +01:00
}
return nil , errors . New ( "Method not found: " + parsedFunctions [ 0 ] )
}