2018-02-26 15:34:04 +01:00
package rules
2016-03-27 01:05:17 +01:00
import (
2016-08-05 20:42:45 +02:00
"fmt"
2016-04-06 13:06:31 +02:00
"net/http"
2016-03-27 01:05:17 +01:00
"strings"
2017-04-17 22:47:53 +02:00
2019-08-03 03:58:23 +02:00
"github.com/gorilla/mux"
2020-09-16 15:46:04 +02:00
"github.com/traefik/traefik/v2/pkg/log"
"github.com/traefik/traefik/v2/pkg/middlewares/requestdecorator"
2019-01-30 16:24:07 +01:00
"github.com/vulcand/predicate"
2016-03-27 01:05:17 +01:00
)
2019-01-30 16:24:07 +01:00
var funcs = map [ string ] func ( * mux . Route , ... string ) error {
2020-07-13 17:58:03 +02:00
"Host" : host ,
2020-07-08 12:18:03 +02:00
"HostHeader" : host ,
2019-01-30 16:24:07 +01:00
"HostRegexp" : hostRegexp ,
"Path" : path ,
"PathPrefix" : pathPrefix ,
"Method" : methods ,
"Headers" : headers ,
"HeadersRegexp" : headersRegexp ,
"Query" : query ,
2016-03-27 01:05:17 +01:00
}
2020-05-11 12:06:07 +02:00
// Router handle routing with rules.
2019-01-30 16:24:07 +01:00
type Router struct {
* mux . Router
parser predicate . Parser
2016-03-27 01:05:17 +01:00
}
2019-01-30 16:24:07 +01:00
// NewRouter returns a new router instance.
func NewRouter ( ) ( * Router , error ) {
parser , err := newParser ( )
if err != nil {
return nil , err
2016-04-06 13:06:31 +02:00
}
2019-01-30 16:24:07 +01:00
return & Router {
Router : mux . NewRouter ( ) . SkipClean ( true ) ,
parser : parser ,
} , nil
2016-03-27 01:05:17 +01:00
}
2019-01-30 16:24:07 +01:00
// AddRoute add a new route to the router.
func ( r * Router ) AddRoute ( rule string , priority int , handler http . Handler ) error {
parse , err := r . parser . Parse ( rule )
if err != nil {
2020-05-11 12:06:07 +02:00
return fmt . Errorf ( "error while parsing rule %s: %w" , rule , err )
2016-04-06 13:06:31 +02:00
}
2019-01-30 16:24:07 +01:00
buildTree , ok := parse . ( treeBuilder )
if ! ok {
return fmt . Errorf ( "error while parsing rule %s" , rule )
2016-04-06 13:06:31 +02:00
}
2016-03-27 01:05:17 +01:00
2019-01-30 16:24:07 +01:00
if priority == 0 {
priority = len ( rule )
2017-12-19 17:00:12 +01:00
}
2019-01-30 16:24:07 +01:00
route := r . NewRoute ( ) . Handler ( handler ) . Priority ( priority )
2020-12-17 10:06:03 +01:00
err = addRuleOnRoute ( route , buildTree ( ) )
if err != nil {
route . BuildOnly ( )
return err
}
return nil
2017-12-19 17:00:12 +01:00
}
2019-01-30 16:24:07 +01:00
type tree struct {
matcher string
value [ ] string
ruleLeft * tree
ruleRight * tree
2017-12-19 17:00:12 +01:00
}
2019-01-30 16:24:07 +01:00
func path ( route * mux . Route , paths ... string ) error {
rt := route . Subrouter ( )
2016-04-06 13:06:31 +02:00
for _ , path := range paths {
2019-01-30 16:24:07 +01:00
tmpRt := rt . Path ( path )
if tmpRt . GetError ( ) != nil {
return tmpRt . GetError ( )
}
2016-04-06 13:06:31 +02:00
}
2019-01-30 16:24:07 +01:00
return nil
2016-03-27 01:05:17 +01:00
}
2019-01-30 16:24:07 +01:00
func pathPrefix ( route * mux . Route , paths ... string ) error {
rt := route . Subrouter ( )
2017-03-24 12:07:59 +01:00
2017-04-25 11:13:39 -07:00
for _ , path := range paths {
2019-01-30 16:24:07 +01:00
tmpRt := rt . PathPrefix ( path )
if tmpRt . GetError ( ) != nil {
return tmpRt . GetError ( )
}
2017-04-25 11:13:39 -07:00
}
2019-01-30 16:24:07 +01:00
return nil
2017-04-25 11:13:39 -07:00
}
2019-01-30 16:24:07 +01:00
func host ( route * mux . Route , hosts ... string ) error {
for i , host := range hosts {
hosts [ i ] = strings . ToLower ( host )
2017-10-30 19:54:03 +08:00
}
2019-01-30 16:24:07 +01:00
route . MatcherFunc ( func ( req * http . Request , _ * mux . RouteMatch ) bool {
2020-07-13 17:58:03 +02:00
reqHost := requestdecorator . GetCanonizedHost ( req . Context ( ) )
if len ( reqHost ) == 0 {
log . FromContext ( req . Context ( ) ) . Warnf ( "Could not retrieve CanonizedHost, rejecting %s" , req . Host )
return false
2019-01-30 16:24:07 +01:00
}
2020-07-13 17:58:03 +02:00
flatH := requestdecorator . GetCNAMEFlatten ( req . Context ( ) )
if len ( flatH ) > 0 {
for _ , host := range hosts {
if strings . EqualFold ( reqHost , host ) || strings . EqualFold ( flatH , host ) {
return true
}
log . FromContext ( req . Context ( ) ) . Debugf ( "CNAMEFlattening: request %s which resolved to %s, is not matched to route %s" , reqHost , flatH , host )
2020-07-08 12:18:03 +02:00
}
2020-07-13 17:58:03 +02:00
return false
2020-07-08 12:18:03 +02:00
}
2020-07-13 17:58:03 +02:00
for _ , host := range hosts {
if reqHost == host {
2019-01-30 16:24:07 +01:00
return true
}
2019-05-06 08:16:03 -07:00
2020-07-13 17:58:03 +02:00
// Check for match on trailing period on host
if last := len ( host ) - 1 ; last >= 0 && host [ last ] == '.' {
h := host [ : last ]
if reqHost == h {
return true
}
2019-05-06 08:16:03 -07:00
}
2020-07-13 17:58:03 +02:00
// Check for match on trailing period on request
if last := len ( reqHost ) - 1 ; last >= 0 && reqHost [ last ] == '.' {
h := reqHost [ : last ]
if h == host {
return true
}
2019-05-06 08:16:03 -07:00
}
2019-01-30 16:24:07 +01:00
}
return false
} )
return nil
2016-03-27 01:05:17 +01:00
}
2019-01-30 16:24:07 +01:00
func hostRegexp ( route * mux . Route , hosts ... string ) error {
router := route . Subrouter ( )
for _ , host := range hosts {
tmpRt := router . Host ( host )
if tmpRt . GetError ( ) != nil {
return tmpRt . GetError ( )
}
2017-03-24 12:07:59 +01:00
}
2019-01-30 16:24:07 +01:00
return nil
2017-03-24 12:07:59 +01:00
}
2019-01-30 16:24:07 +01:00
func methods ( route * mux . Route , methods ... string ) error {
return route . Methods ( methods ... ) . GetError ( )
2016-03-27 01:05:17 +01:00
}
2019-01-30 16:24:07 +01:00
func headers ( route * mux . Route , headers ... string ) error {
return route . Headers ( headers ... ) . GetError ( )
2016-03-27 01:05:17 +01:00
}
2019-01-30 16:24:07 +01:00
func headersRegexp ( route * mux . Route , headers ... string ) error {
return route . HeadersRegexp ( headers ... ) . GetError ( )
2016-03-27 01:05:17 +01:00
}
2019-01-30 16:24:07 +01:00
func query ( route * mux . Route , query ... string ) error {
2017-08-24 19:28:03 +01:00
var queries [ ] string
for _ , elem := range query {
queries = append ( queries , strings . Split ( elem , "=" ) ... )
}
2019-01-30 16:24:07 +01:00
route . Queries ( queries ... )
// Queries can return nil so we can't chain the GetError()
return route . GetError ( )
2017-08-24 19:28:03 +01:00
}
2019-01-30 16:24:07 +01:00
func addRuleOnRouter ( router * mux . Router , rule * tree ) error {
switch rule . matcher {
case "and" :
route := router . NewRoute ( )
err := addRuleOnRoute ( route , rule . ruleLeft )
if err != nil {
return err
2016-06-06 09:21:00 +02:00
}
2018-03-23 13:30:03 +01:00
2019-01-30 16:24:07 +01:00
return addRuleOnRoute ( route , rule . ruleRight )
case "or" :
err := addRuleOnRouter ( router , rule . ruleLeft )
if err != nil {
return err
2016-04-07 15:01:04 +02:00
}
2018-03-23 13:30:03 +01:00
2019-01-30 16:24:07 +01:00
return addRuleOnRouter ( router , rule . ruleRight )
default :
err := checkRule ( rule )
if err != nil {
return err
2016-06-06 09:21:00 +02:00
}
2019-01-30 16:24:07 +01:00
return funcs [ rule . matcher ] ( router . NewRoute ( ) , rule . value ... )
}
}
2016-08-05 20:42:45 +02:00
2019-01-30 16:24:07 +01:00
func addRuleOnRoute ( route * mux . Route , rule * tree ) error {
switch rule . matcher {
case "and" :
err := addRuleOnRoute ( route , rule . ruleLeft )
2016-08-05 20:42:45 +02:00
if err != nil {
2019-01-30 16:24:07 +01:00
return err
2016-08-05 20:42:45 +02:00
}
2019-01-30 16:24:07 +01:00
return addRuleOnRoute ( route , rule . ruleRight )
case "or" :
subRouter := route . Subrouter ( )
2018-03-23 13:30:03 +01:00
2019-01-30 16:24:07 +01:00
err := addRuleOnRouter ( subRouter , rule . ruleLeft )
if err != nil {
return err
2016-08-05 20:42:45 +02:00
}
2019-01-30 16:24:07 +01:00
return addRuleOnRouter ( subRouter , rule . ruleRight )
default :
err := checkRule ( rule )
if err != nil {
return err
2016-04-06 13:06:31 +02:00
}
2018-03-23 13:30:03 +01:00
2019-01-30 16:24:07 +01:00
return funcs [ rule . matcher ] ( route , rule . value ... )
}
2016-03-27 01:05:17 +01:00
}
2016-08-05 20:42:45 +02:00
2019-01-30 16:24:07 +01:00
func checkRule ( rule * tree ) error {
if len ( rule . value ) == 0 {
return fmt . Errorf ( "no args for matcher %s" , rule . matcher )
2016-08-05 20:42:45 +02:00
}
2018-03-23 13:30:03 +01:00
2019-01-30 16:24:07 +01:00
for _ , v := range rule . value {
if len ( v ) == 0 {
return fmt . Errorf ( "empty args for matcher %s, %v" , rule . matcher , rule . value )
2018-09-04 17:14:04 +02:00
}
}
2019-01-30 16:24:07 +01:00
return nil
2016-08-05 20:42:45 +02:00
}