2016-03-27 01:05:17 +01:00
package main
import (
"errors"
2016-08-05 20:42:45 +02:00
"fmt"
2016-10-14 16:04:09 +02:00
"github.com/BurntSushi/ty/fun"
2016-06-03 17:58:33 +02:00
"github.com/containous/mux"
2016-10-14 16:04:09 +02:00
"github.com/containous/traefik/types"
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-10-14 16:04:09 +02:00
if types . CanonicalDomain ( reqHost ) == types . CanonicalDomain ( 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 {
2016-10-14 16:04:09 +02:00
router . Host ( types . CanonicalDomain ( host ) )
2016-04-06 13:06:31 +02:00
}
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 {
2016-10-14 16:04:09 +02:00
router . Path ( types . CanonicalDomain ( path ) )
2016-04-06 13:06:31 +02:00
}
return r . route . route
}
func ( r * Rules ) pathPrefix ( paths ... string ) * mux . Route {
router := r . route . route . Subrouter ( )
for _ , path := range paths {
2016-10-14 16:04:09 +02:00
router . PathPrefix ( types . CanonicalDomain ( path ) )
2016-04-06 13:06:31 +02:00
}
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 {
2016-10-14 16:04:09 +02:00
router . Path ( types . CanonicalDomain ( path ) )
2016-04-06 13:06:31 +02:00
}
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 {
2016-10-14 16:04:09 +02:00
router . PathPrefix ( types . CanonicalDomain ( path ) )
2016-04-06 13:06:31 +02:00
}
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 ... )
}
2016-08-05 20:42:45 +02:00
func ( r * Rules ) parseRules ( expression string , onRule func ( functionName string , function interface { } , arguments [ ] string ) error ) error {
2016-03-27 01:05:17 +01:00
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 ,
}
2016-06-22 22:07:02 +02:00
if len ( expression ) == 0 {
2016-08-05 20:42:45 +02:00
return errors . New ( "Empty rule" )
2016-06-22 22:07:02 +02:00
}
2016-03-27 01:05:17 +01:00
f := func ( c rune ) bool {
2016-04-06 13:06:31 +02:00
return c == ':'
2016-03-27 01:05:17 +01:00
}
2016-06-06 09:21:00 +02:00
// Allow multiple rules separated by ;
splitRule := func ( c rune ) bool {
return c == ';'
2016-03-27 01:05:17 +01:00
}
2016-06-06 09:21:00 +02:00
parsedRules := strings . FieldsFunc ( expression , splitRule )
for _ , rule := range parsedRules {
// get function
parsedFunctions := strings . FieldsFunc ( rule , f )
if len ( parsedFunctions ) == 0 {
2016-08-05 20:42:45 +02:00
return errors . New ( "Error parsing rule: '" + rule + "'" )
2016-06-06 09:21:00 +02:00
}
2016-08-05 20:42:45 +02:00
functionName := strings . TrimSpace ( parsedFunctions [ 0 ] )
parsedFunction , ok := functions [ functionName ]
2016-06-06 09:21:00 +02:00
if ! ok {
2016-08-05 20:42:45 +02:00
return errors . New ( "Error parsing rule: '" + rule + "'. Unknown function: '" + parsedFunctions [ 0 ] + "'" )
2016-04-07 15:01:04 +02:00
}
2016-06-06 09:21:00 +02:00
parsedFunctions = append ( parsedFunctions [ : 0 ] , parsedFunctions [ 1 : ] ... )
fargs := func ( c rune ) bool {
return c == ','
}
// get function
parsedArgs := strings . FieldsFunc ( strings . Join ( parsedFunctions , ":" ) , fargs )
if len ( parsedArgs ) == 0 {
2016-08-05 20:42:45 +02:00
return errors . New ( "Error parsing args from rule: '" + rule + "'" )
2016-06-06 09:21:00 +02:00
}
for i := range parsedArgs {
2016-08-05 20:42:45 +02:00
parsedArgs [ i ] = strings . TrimSpace ( parsedArgs [ i ] )
2016-06-06 09:21:00 +02:00
}
2016-08-05 20:42:45 +02:00
err := onRule ( functionName , parsedFunction , parsedArgs )
if err != nil {
2016-09-23 18:27:01 +02:00
return fmt . Errorf ( "Parsing error on rule: %v" , err )
2016-08-05 20:42:45 +02:00
}
}
return nil
}
// Parse parses rules expressions
func ( r * Rules ) Parse ( expression string ) ( * mux . Route , error ) {
var resultRoute * mux . Route
err := r . parseRules ( expression , func ( functionName string , function interface { } , arguments [ ] string ) error {
inputs := make ( [ ] reflect . Value , len ( arguments ) )
for i := range arguments {
inputs [ i ] = reflect . ValueOf ( arguments [ i ] )
}
method := reflect . ValueOf ( function )
2016-06-06 09:21:00 +02:00
if method . IsValid ( ) {
resultRoute = method . Call ( inputs ) [ 0 ] . Interface ( ) . ( * mux . Route )
if r . err != nil {
2016-08-05 20:42:45 +02:00
return r . err
2016-06-06 09:21:00 +02:00
}
if resultRoute . GetError ( ) != nil {
2016-08-05 20:42:45 +02:00
return resultRoute . GetError ( )
2016-06-06 09:21:00 +02:00
}
} else {
2016-08-05 20:42:45 +02:00
return errors . New ( "Method not found: '" + functionName + "'" )
2016-04-06 13:06:31 +02:00
}
2016-08-05 20:42:45 +02:00
return nil
} )
if err != nil {
2016-09-23 18:27:01 +02:00
return nil , fmt . Errorf ( "Error parsing rule: %v" , err )
2016-03-27 01:05:17 +01:00
}
2016-06-06 09:21:00 +02:00
return resultRoute , nil
2016-03-27 01:05:17 +01:00
}
2016-08-05 20:42:45 +02:00
// ParseDomains parses rules expressions and returns domains
func ( r * Rules ) ParseDomains ( expression string ) ( [ ] string , error ) {
domains := [ ] string { }
err := r . parseRules ( expression , func ( functionName string , function interface { } , arguments [ ] string ) error {
if functionName == "Host" {
domains = append ( domains , arguments ... )
}
return nil
} )
if err != nil {
2016-09-23 18:27:01 +02:00
return nil , fmt . Errorf ( "Error parsing domains: %v" , err )
2016-08-05 20:42:45 +02:00
}
2016-10-14 16:04:09 +02:00
return fun . Map ( types . CanonicalDomain , domains ) . ( [ ] string ) , nil
2016-08-05 20:42:45 +02:00
}