2017-04-17 22:47:53 +02:00
package server
2016-03-27 01:05:17 +01:00
import (
"errors"
2016-08-05 20:42:45 +02:00
"fmt"
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"
2017-04-17 22:47:53 +02:00
"github.com/BurntSushi/ty/fun"
"github.com/containous/mux"
"github.com/containous/traefik/types"
2016-03-27 01:05:17 +01:00
)
// 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-11-17 09:36:10 -05:00
router . Path ( strings . TrimSpace ( 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-11-17 09:36:10 -05:00
router . PathPrefix ( strings . TrimSpace ( 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-11-17 09:36:10 -05:00
router . Path ( strings . TrimSpace ( path ) )
2016-04-06 13:06:31 +02:00
}
return r . route . route
2016-03-27 01:05:17 +01:00
}
2017-03-24 12:07:59 +01:00
func ( r * Rules ) pathStripRegex ( paths ... string ) * mux . Route {
sort . Sort ( bySize ( paths ) )
r . route . stripPrefixesRegex = paths
router := r . route . route . Subrouter ( )
for _ , path := range paths {
router . Path ( strings . TrimSpace ( path ) )
}
return r . route . route
}
2017-04-25 11:13:39 -07:00
func ( r * Rules ) replacePath ( paths ... string ) * mux . Route {
for _ , path := range paths {
r . route . replacePath = path
}
return r . route . route
}
2016-12-02 13:40:18 +01:00
func ( r * Rules ) addPrefix ( paths ... string ) * mux . Route {
for _ , path := range paths {
r . route . addPrefix = path
}
return r . route . route
}
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-11-17 09:36:10 -05:00
router . PathPrefix ( strings . TrimSpace ( path ) )
2016-04-06 13:06:31 +02:00
}
return r . route . route
2016-03-27 01:05:17 +01:00
}
2017-03-24 12:07:59 +01:00
func ( r * Rules ) pathPrefixStripRegex ( paths ... string ) * mux . Route {
sort . Sort ( bySize ( paths ) )
r . route . stripPrefixesRegex = 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 ... )
}
2017-08-24 19:28:03 +01:00
func ( r * Rules ) query ( query ... string ) * mux . Route {
var queries [ ] string
for _ , elem := range query {
queries = append ( queries , strings . Split ( elem , "=" ) ... )
}
return r . route . route . Queries ( queries ... )
}
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 { } {
2017-03-24 12:07:59 +01:00
"Host" : r . host ,
"HostRegexp" : r . hostRegexp ,
"Path" : r . path ,
"PathStrip" : r . pathStrip ,
"PathStripRegex" : r . pathStripRegex ,
"PathPrefix" : r . pathPrefix ,
"PathPrefixStrip" : r . pathPrefixStrip ,
"PathPrefixStripRegex" : r . pathPrefixStripRegex ,
"Method" : r . methods ,
"Headers" : r . headers ,
"HeadersRegexp" : r . headersRegexp ,
"AddPrefix" : r . addPrefix ,
"ReplacePath" : r . replacePath ,
2017-08-24 19:28:03 +01:00
"Query" : r . query ,
2016-03-27 01:05:17 +01:00
}
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 {
2017-05-26 17:03:14 +02:00
return fmt . Errorf ( "error parsing rule: '%s'" , 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 {
2017-05-26 17:03:14 +02:00
return fmt . Errorf ( "error parsing rule: '%s'. Unknown function: '%s'" , rule , 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 {
2017-05-26 17:03:14 +02:00
return fmt . Errorf ( "error parsing args from rule: '%s'" , 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 {
2017-05-26 17:03:14 +02:00
return fmt . Errorf ( "Method not found: '%s'" , functionName )
2016-04-06 13:06:31 +02:00
}
2016-08-05 20:42:45 +02:00
return nil
} )
if err != nil {
2017-05-26 17:03:14 +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 {
2017-05-26 17:03:14 +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
}